diff options
author | Tharre <tharre3@gmail.com> | 2014-11-16 17:30:35 +0100 |
---|---|---|
committer | Tharre <tharre3@gmail.com> | 2014-11-16 17:30:35 +0100 |
commit | b4c1b2145d6a0b1ec4219847dc26877046f84e8b (patch) | |
tree | 6bb3bc8b35afc7a76bf53d93227b07e91501b807 | |
parent | 19cba89127381d9dc06d1e823b123231496e9a3d (diff) | |
download | redo-b4c1b2145d6a0b1ec4219847dc26877046f84e8b.tar.gz redo-b4c1b2145d6a0b1ec4219847dc26877046f84e8b.tar.xz redo-b4c1b2145d6a0b1ec4219847dc26877046f84e8b.zip |
Change the way redo updates targets.
It's done a lot more efficiently now, as we are no longer checking if a
target is out-of-date before we rebuild it, but instead rebuild
subtargets directly when they are checked.
We also now correctly depend on .do files.
-rw-r--r-- | src/build.c | 116 | ||||
-rw-r--r-- | src/build.h | 2 | ||||
-rw-r--r-- | src/redo-always.c | 2 | ||||
-rw-r--r-- | src/redo-ifchange.c | 12 | ||||
-rw-r--r-- | src/redo-ifcreate.c | 3 | ||||
-rw-r--r-- | src/redo.c | 4 |
6 files changed, 81 insertions, 58 deletions
diff --git a/src/build.c b/src/build.c index 8b0ed94..c002cc8 100644 --- a/src/build.c +++ b/src/build.c @@ -36,7 +36,6 @@ static char **parsecmd(char *cmd, size_t *i, size_t keep_free); static char *get_relpath(const char *target); static char *get_dep_path(const char *target); static void write_dep_hash(const char *target); -static bool dependencies_changed(char buf[], size_t read); struct do_attr { char *specific; @@ -139,8 +138,13 @@ int build_target(const char *target) { } /* depend on the do-file */ + char *temp = get_dep_path(dofiles->chosen); + if (!fexists(temp)) { + write_dep_hash(dofiles->chosen); + } + free(temp); + add_dep(dofiles->chosen, target, 'c'); - write_dep_hash(dofiles->chosen); /* redo-ifcreate on specific if general was chosen */ if (dofiles->general == dofiles->chosen) @@ -203,8 +207,16 @@ static struct do_attr *get_dofiles(const char *target) { struct do_attr *dofiles = safe_malloc(sizeof(struct do_attr)); dofiles->specific = concat(2, target, ".do"); - dofiles->general = concat(3, "default", take_extension(target), ".do"); - dofiles->redofile = safe_strdup("Redofile"); + if (!is_absolute(target)) { + dofiles->general = concat(3, "default", take_extension(target), ".do"); + dofiles->redofile = safe_strdup("Redofile"); + } else { + char *dirc = safe_strdup(target); + char *dt = dirname(dirc); + + dofiles->general = concat(4, dt, "/default", take_extension(target), ".do"); + dofiles->redofile = concat(2, dt, "/Redofile"); + } if (fexists(dofiles->specific)) dofiles->chosen = dofiles->specific; @@ -392,40 +404,27 @@ static void write_dep_hash(const char *target) { free(dep_path); } -/* Parse the dependency information from the dependency record and check if - those are up-to-date. */ -static bool dependencies_changed(char buf[], size_t read) { - char *root = getenv("REDO_ROOT"); - char *ptr = buf; - - for (size_t i = 0; i < read; ++i) { - if (buf[i]) - continue; - if (is_absolute(&ptr[1])) { - if (has_changed(&ptr[1], ptr[0], true)) - return true; - } else { - char *abs = concat(3, root, "/", &ptr[1]); - if (has_changed(abs, ptr[0], true)) { - free(abs); - return true; - } - free(abs); - } - ptr = &buf[i+1]; - } - return false; -} - -/* Checks if a target should be rebuild, given it's identifier. */ -bool has_changed(const char *target, int ident, bool is_sub_dependency) { +int update_target(const char *target, int ident) { switch(ident) { - case 'a': return true; - case 'e': return fexists(target); + case 'a': + debug("%s is not up-to-date: always rebuild\n", target); + build_target(target); + return 1; + case 'e': + if (fexists(target)) { + debug("%s is not up-to-date: target exist and e ident was chosen\n", target); + build_target(target); + return 1; + } + return 0; case 'c': #define HEADERSIZE HASHSIZE + sizeof(unsigned) - if (!fexists(target)) - return true; + if (!fexists(target)) { + /* target does not exist */ + debug("%s is not up-to-date: target doesn't exist\n", target); + build_target(target); + return 1; + } char *dep_path = get_dep_path(target); @@ -433,7 +432,10 @@ bool has_changed(const char *target, int ident, bool is_sub_dependency) { if (!fp) { if (errno == ENOENT) { /* dependency file does not exist */ - return true; + debug("%s is not up-to-date: dependency file (%s) doesn't exist\n", + target, dep_path); + build_target(target); + return 1; } else { fatal(ERRM_FOPEN, dep_path); } @@ -446,29 +448,57 @@ bool has_changed(const char *target, int ident, bool is_sub_dependency) { free(dep_path); if (*(unsigned *) buf == (unsigned) atoi(getenv("REDO_MAGIC"))) - return is_sub_dependency; + /* magic number matches */ + return 1; + char *root = getenv("REDO_ROOT"); + bool rebuild = false; unsigned char hash[HASHSIZE]; hash_file(target, hash); if (memcmp(hash, buf+sizeof(unsigned), HASHSIZE)) { - /*debug("Hash doesn't match for %s\n", target);*/ - return true; + debug("%s is not-up-to-date: hashes don't match\n", target); + build_target(target); + return 1; } + /* FIXME: this doesn't work properly if we actually read beyond 8096 bytes */ while (!feof(fp)) { size_t read = fread(buf, 1, sizeof buf, fp); if (ferror(fp)) fatal("redo: failed to read %zu bytes from file descriptor", sizeof buf); - if (dependencies_changed(buf, read)) { - fclose(fp); - return true; + char *ptr = buf; + for (size_t i = 0; i < read; ++i) { + if (buf[i]) + continue; + if (!is_absolute(&ptr[1])) { + /* if our path is relative we need to prefix it with the + root project directory or the path will be invalid */ + char *abs = concat(3, root, "/", &ptr[1]); + if (update_target(abs, ptr[0])) { + debug("%s is not up-to-date: subdependency %s is out-of-date\n", + target, abs); + rebuild = true; + } + free(abs); + } else { + if (update_target(&ptr[1], ptr[0])) { + debug("%s is not up-to-date: subdependency %s is out-of-date\n", + target, &ptr[1]); + rebuild = true; + } + } + ptr = &buf[i+1]; } } fclose(fp); - return false; + if (rebuild) { + build_target(target); + return 1; + } + return 0; default: log_err("Unknown identifier '%c'\n", ident); diff --git a/src/build.h b/src/build.h index 8a5f072..e4ef626 100644 --- a/src/build.h +++ b/src/build.h @@ -12,7 +12,7 @@ #include <stdbool.h> extern void add_dep(const char *target, const char *parent, int ident); -extern bool has_changed(const char *target, int ident, bool is_sub_dependency); +extern int update_target(const char *target, int ident); extern int build_target(const char *target); extern bool environment_sane(); diff --git a/src/redo-always.c b/src/redo-always.c index 5f0c24c..0e1d849 100644 --- a/src/redo-always.c +++ b/src/redo-always.c @@ -12,7 +12,7 @@ int main(int argc, char *argv[]) { for (int i = 1; i < argc; ++i) { - build_target(argv[i]); + update_target(argv[i], 'a'); add_dep(argv[i], NULL, 'a'); } } diff --git a/src/redo-ifchange.c b/src/redo-ifchange.c index cfc017b..d7b4af0 100644 --- a/src/redo-ifchange.c +++ b/src/redo-ifchange.c @@ -14,19 +14,13 @@ int main(int argc, char *argv[]) { if (!environment_sane()) { - fprintf(stderr, "redo: environment variables are missing, \ - please use %s only in do scripts.\n", argv[0]); + fprintf(stderr, "redo: environment variables are missing, " + "please use %s only in do scripts.\n", argv[0]); exit(1); } for (int i = 1; i < argc; ++i) { - /*debug("Testing if %s is up-to-date ...\n", argv[i]);*/ - if (has_changed(argv[i], 'c', false)) { - /*printf("=> no\n");*/ - build_target(argv[i]); - } else { - /*printf("=> yes\n");*/ - } + update_target(argv[i], 'c'); add_dep(argv[i], NULL, 'c'); } diff --git a/src/redo-ifcreate.c b/src/redo-ifcreate.c index eba1c6b..77e51cc 100644 --- a/src/redo-ifcreate.c +++ b/src/redo-ifcreate.c @@ -12,8 +12,7 @@ int main(int argc, char *argv[]) { for (int i = 1; i < argc; ++i) { - if (has_changed(argv[i], 'e', false)) - build_target(argv[i]); + update_target(argv[i], 'e'); add_dep(argv[i], NULL, 'e'); } } @@ -51,11 +51,11 @@ int main(int argc, char *argv[]) { prepare_env(); if (argc < 2) { - build_target("all"); + update_target("all", 'a'); } else { int i; for (i = 1; i < argc; ++i) { - build_target(argv[i]); + update_target(argv[i], 'a'); } } } |