diff options
-rw-r--r-- | build.c | 58 |
1 files changed, 50 insertions, 8 deletions
@@ -17,9 +17,10 @@ fprintf(stderr, __VA_ARGS__); } while(0); #define MAXBUF 1024 -#define MAXCMDS 32 /* Maximum number of commands across all files. */ #define MAXCMD 1024 +#define MAXCMDS 32 /* Maximum number of commands across all files. */ #define MAXDEP 1024 +#define MAXPATH 1024 #define MAXTGT 64 extern char *optarg; @@ -27,12 +28,13 @@ extern int optind; void cleandep(char **); void cleantgt(char **); +char *dirname(char *); char *nextdep(char **); int main(int argc, char *argv[]) { - char *b, buf[MAXBUF], *cmd[MAXCMDS], *d, *dep, *name, *tgt; + char *b, buf[MAXBUF], *cmd[MAXCMDS], *d, *dep, *name, *tgt, wd[MAXPATH]; FILE *fp; int c, dflag, fflag, i, icmd, j, s; struct stat sb, ssb; @@ -48,6 +50,13 @@ main(int argc, char *argv[]) tgt[0] = dep[0] = 0; + /* + * The original working directory is saved. (When acting on the + * build information in a file, the program temporarily moves into + * its directory.) + */ + getcwd(wd, MAXPATH); + /* Process command-line flags (debug, force). */ name = argv[0]; dflag = fflag = 0; @@ -72,8 +81,12 @@ main(int argc, char *argv[]) /* Process dependencies and commands in each file. */ for(i = icmd = 0; i < argc; i++, icmd = 0){ + + /* Return to original directory. */ + chdir(wd); + if(!(fp = fopen(argv[i], "r"))) - err(1, "fopen"); + err(1, "fopen(%s)", argv[i]); /* Read line by line, at most twenty. */ for(j = 0; j < 20 && fgets(buf, MAXBUF, fp); j++){ @@ -115,21 +128,33 @@ main(int argc, char *argv[]) } /* Build immediately if forced or no target found. */ - if(fflag || !*tgt) + if(fflag || !*tgt){ + chdir(dirname(argv[i])); goto build; + } /* Trim shell meta-characters and whitespace. */ cleantgt(&tgt); cleandep(&dep); - /* Build immediately if source is newer than target. */ dd("%s: target '%s'\n", argv[i], tgt); + + /* Get information about source. */ if(stat(argv[i], &sb)) - err(1, argv[i]); + err(1, "stat(%s)", argv[i]); + + /* + * Subsequent operations should take place inside the + * directory of the source, as command lines and dependency + * lines may refer to relative paths. + */ + chdir(dirname(argv[i])); + + /* Build immediately if source is newer than target. */ if(stat(tgt, &ssb)){ if(errno == ENOENT) goto build; - err(1, tgt); + err(1, "stat(%s)", tgt); } if(sb.st_mtime > ssb.st_mtime){ d("%s: %s is modified, building\n", @@ -154,7 +179,7 @@ main(int argc, char *argv[]) "does not exist\n", argv[i], d); continue; } - err(1, d); + err(1, "stat(%s)", d); } if(sb.st_mtime > ssb.st_mtime){ d("%s: %s is modified, building\n", argv[i], d); @@ -240,6 +265,23 @@ cleantgt(char **tgt) } char * +dirname(char *file) +{ + char *dir; + int i; + + if(!(dir = malloc(strlen(file)+1))) + err(1, "malloc"); + + for(i = strlen(file); i >= 0; i--) + if(file[i] == '/') break; + for(dir[i--] = 0; i >= 0; i--) + dir[i] = file[i]; + + return dir[0] ? dir : "."; +} + +char * nextdep(char **dep) { char *d; |