aboutsummaryrefslogtreecommitdiffstats
path: root/src/build.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/build.c')
-rw-r--r--src/build.c126
1 files changed, 62 insertions, 64 deletions
diff --git a/src/build.c b/src/build.c
index 18ead3f..677f7b9 100644
--- a/src/build.c
+++ b/src/build.c
@@ -36,7 +36,7 @@ static char **parse_shebang(char *target, char *dofile, char *temp_output);
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 int write_dep_hash(const char *target, unsigned char *old_hash);
static int handle_c(const char *target);
struct do_attr {
@@ -48,15 +48,16 @@ struct do_attr {
/* Build given target, using it's do-file. */
int build_target(const char *target) {
+ int retval = 1;
/* get the do-file which we are going to execute */
struct do_attr *dofiles = get_dofiles(target);
if (!dofiles->chosen) {
if (fexists(target)) {
/* if our target file has no do file associated but exists,
then we treat it as a source */
- write_dep_hash(target);
+ write_dep_hash(target, NULL);
free_do_attr(dofiles);
- return 1;
+ return retval;
}
die("%s couldn't be built as no suitable do-file exists\n", target);
@@ -66,8 +67,23 @@ int build_target(const char *target) {
printf("redo %s\n", reltarget);
free(reltarget);
- /* remove old dependency file */
+ /* get the old hash (if any) */
+ unsigned char old_hash[HASHSIZE];
char *dep_file = get_dep_path(target);
+ FILE *fp = fopen(dep_file, "rb");
+ if (!fp) {
+ if (errno != ENOENT)
+ fatal("redo: failed to open %s\n", dep_file);
+ memset(old_hash, 0, HASHSIZE); // FIXME
+ } else {
+ if (!fseek(fp, sizeof(unsigned), SEEK_SET))
+ fatal("redo: fseek() failed");
+ if (fread(old_hash, 1, HASHSIZE, fp) < HASHSIZE)
+ fatal("redo: failed to read stuff");
+ fclose(fp);
+ }
+
+ /* remove old dependency file */
if (remove(dep_file))
if (errno != ENOENT)
fatal("redo: failed to remove %s", dep_file);
@@ -118,26 +134,32 @@ int build_target(const char *target) {
fatal("waitpid() failed: ");
bool remove_temp = true;
+ /* check how our child exited */
if (WIFEXITED(status)) {
- if (WEXITSTATUS(status)) {
+ if (WEXITSTATUS(status))
die("redo: invoked do-file %s failed: %d\n", dofiles->chosen,
WEXITSTATUS(status));
- } else {
- /* successful */
-
- /* if the file is 0 bytes long we delete it */
- if (fsize(temp_output) > 0)
- remove_temp = false;
- }
} else {
/* something very wrong happened with the child */
die("redo: invoked do-file did not terminate correctly\n");
}
+ /* check if our output file is > 0 bytes long */
+ if (fsize(temp_output) > 0) {
+ if (rename(temp_output, target))
+ fatal("redo: failed to rename %s to %s", temp_output, target);
+
+ retval = write_dep_hash(target, old_hash);
+ } else {
+ if (remove(temp_output))
+ if (errno != ENOENT)
+ fatal("redo: failed to remove %s", temp_output);
+ }
+
/* depend on the do-file */
char *temp = get_dep_path(dofiles->chosen);
if (!fexists(temp))
- write_dep_hash(dofiles->chosen);
+ write_dep_hash(dofiles->chosen, NULL);
free(temp);
add_dep(dofiles->chosen, target, 'c');
@@ -146,21 +168,10 @@ int build_target(const char *target) {
if (dofiles->general == dofiles->chosen)
add_dep(dofiles->specific, target, 'e');
- if (remove_temp) {
- if (remove(temp_output))
- if (errno != ENOENT)
- fatal("redo: failed to remove %s", temp_output);
- } else {
- if (rename(temp_output, target))
- fatal("redo: failed to rename %s to %s", temp_output, target);
-
- write_dep_hash(target);
- }
-
free(temp_output);
free_do_attr(dofiles);
- return 1;
+ return retval;
}
/* Read and parse shebang and return an argv-like pointer array containing the
@@ -257,7 +268,6 @@ static struct do_attr *get_dofiles(const char *target) {
return dofiles;
}
-
/* Free the do_attr struct. */
static void free_do_attr(struct do_attr *thing) {
free(thing->specific);
@@ -363,14 +373,16 @@ static void hash_file(const char *target, unsigned char *hash) {
fclose(in);
}
-/* Calculate and store the hash of target in the right dependency file. */
-static void write_dep_hash(const char *target) {
+/* Calculate and store the hash of target in the right dependency file. Returns
+ a nonzero value if the hash changed or zero otherwise. */
+static int write_dep_hash(const char *target, unsigned char *old_hash) {
unsigned char hash[HASHSIZE];
unsigned magic = atoi(getenv("REDO_MAGIC"));
hash_file(target, hash);
char *dep_path = get_dep_path(target);
+
int out = open(dep_path, O_WRONLY | O_CREAT, 0644);
if (out < 0)
fatal("redo: failed to open %s", dep_path);
@@ -383,22 +395,24 @@ static void write_dep_hash(const char *target) {
if (close(out))
fatal("redo: failed to close %s", dep_path);
+
free(dep_path);
+
+ if (old_hash)
+ return memcmp(hash, old_hash, HASHSIZE);
+ else
+ return 1;
+
}
int update_target(const char *target, int ident) {
switch(ident) {
case 'a':
- debug("%s is not up-to-date: always rebuild\n", target);
- build_target(target);
- return 1;
+ return build_target(target);
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;
- }
+ if (fexists(target))
+ return build_target(target);
+
return 0;
case 'c':
return handle_c(target);
@@ -408,12 +422,8 @@ int update_target(const char *target, int ident) {
}
static int handle_c(const char *target) {
- 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;
- }
+ if (!fexists(target))
+ return build_target(target);
char *dep_path = get_dep_path(target);
@@ -421,11 +431,8 @@ static int handle_c(const char *target) {
if (!fp) {
if (errno == ENOENT) {
/* dependency file does not exist */
- debug("%s is not up-to-date: dependency file (%s) doesn't exist\n",
- target, dep_path);
- build_target(target);
free(dep_path);
- return 1;
+ return build_target(target);
} else {
fatal("redo: failed to open %s", dep_path);
}
@@ -446,11 +453,8 @@ static int handle_c(const char *target) {
bool rebuild = false;
unsigned char hash[HASHSIZE];
hash_file(target, hash);
- if (memcmp(hash, buf+sizeof(unsigned), HASHSIZE)) {
- debug("%s is not-up-to-date: hashes don't match\n", target);
- build_target(target);
- return 1;
- }
+ if (memcmp(hash, buf+sizeof(unsigned), HASHSIZE))
+ return build_target(target);
char *ptr;
@@ -468,18 +472,13 @@ static int handle_c(const char *target) {
/* 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);
+ if (update_target(abs, ptr[0]))
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]);
+ if (update_target(&ptr[1], ptr[0]))
rebuild = true;
- }
}
ptr = &buf[i+1];
}
@@ -493,9 +492,8 @@ static int handle_c(const char *target) {
}
fclose(fp);
- if (rebuild) {
- build_target(target);
- return 1;
- }
+ if (rebuild)
+ return build_target(target);
+
return 0;
}