about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChristian Neukirchen <chneukirchen@gmail.com>2015-09-01 14:17:45 +0200
committerChristian Neukirchen <chneukirchen@gmail.com>2015-09-01 14:17:45 +0200
commit02cd33f61a141767a907f4e37be06f8f1b244632 (patch)
treec4e4189fdf279d0fdd0fb970ac20760b0aa92b23
parentb99749f6d13a59ce0b6ff35ce0aea5a9e50b63bf (diff)
downloadredo-c-02cd33f61a141767a907f4e37be06f8f1b244632.tar.gz
redo-c-02cd33f61a141767a907f4e37be06f8f1b244632.tar.xz
redo-c-02cd33f61a141767a907f4e37be06f8f1b244632.zip
Support for building across directories, look upward for default*.do
Essentially we just chdir to the directory of each target before we do
things there.
-rw-r--r--redo.c105
1 files changed, 82 insertions, 23 deletions
diff --git a/redo.c b/redo.c
index db300a8..8e92218 100644
--- a/redo.c
+++ b/redo.c
@@ -180,6 +180,7 @@ static void sha256_update(struct sha256 *s, const void *m, unsigned long len)
 
 // ----------------------------------------------------------------------
 
+int dir_fd = -1;
 int dep_fd = -1;
 int poolwr_fd = -1;
 int poolrd_fd = -1;
@@ -203,6 +204,8 @@ check_dofile(char *fmt, ...)
 	vsnprintf(dofile, sizeof dofile, fmt, ap);
 	va_end(ap);
 
+	printf("CDOF %s\n", dofile);
+
 	if (access (dofile, F_OK) == 0) {
 		return strdup(dofile);
 	} else {
@@ -214,33 +217,56 @@ check_dofile(char *fmt, ...)
 /*
 dir/base.a.b
        will look for dir/base.a.b.do,
-       dir/default.a.b.do, dir/default.b.do, dir/default.do, default.a.b.do,
-       default.b.do, and default.do.
-
-	// TODO: also traverse up directory
-17:47:24    <@dalias> then yeah, just newfd=openat(dirfd, "..", O_RDONLY)
-17:47:47    <@dalias> stat both of them and see if they have the same
-         (st_dev,st_ino) pair
-
+       dir/default.a.b.do, dir/default.b.do, dir/default.do,
+       default.a.b.do, default.b.do, and default.do.
+this function assumes no / in target
 */
 static char *
 find_dofile(char *target)
 {
 	char *dofile;
+	char updir[1024];
+	char *u = updir;
+
+	dofile = check_dofile("./%s.do", target);
+	if (dofile)
+		return dofile;
 
-	dofile = check_dofile("%s.do", target);
-	if (dofile) return dofile;
+	*u++ = '.';
+	*u++ = '/';
+	*u = 0;
+
+	struct stat st = {0};
+	struct stat ost = {0};
 	
-	char *s = target;
-        
-        while (*s) {
-		if (*s++ == '.') {
-			dofile = check_dofile("default.%s.do", s);
-			if (dofile) return dofile;
+	while (1) {
+		ost = st;
+
+		if (stat(updir, &st) < 0)
+			return 0;;
+		if (ost.st_dev == st.st_dev && ost.st_ino == st.st_ino)
+			break;  // reached root dir, .. = .
+
+		char *s = target;
+		while (*s) {
+			if (*s++ == '.') {
+				dofile = check_dofile("%sdefault.%s.do", updir, s);
+				if (dofile)
+					return dofile;
+			}
 		}
-        }
 
-	return check_dofile("default.do");
+		dofile = check_dofile("%sdefault.do", updir);
+		if (dofile)
+			return dofile;
+
+		*u++ = '.';
+		*u++ = '.';
+		*u++ = '/';
+		*u = 0;
+	}
+
+	return 0;
 }
 
 static int
@@ -299,6 +325,25 @@ hashfile(int fd)
 	return asciihash;
 }
 
+static char *
+targetchdir(char *target) {
+	char *base = strrchr(target, '/');
+	if (base) {
+		int fd;
+		*base = 0;
+		fd = openat(dir_fd, target, O_RDONLY | O_DIRECTORY);
+		printf("CHDIR %s\n", target);
+		*base = '/';
+		fchdir(fd);
+		close(fd);
+		return base+1;
+	} else {
+		fchdir(dir_fd);
+		printf("CHDIR [.]\n");
+		return target;
+	}
+}
+
 static int
 check_deps(char *target)
 {
@@ -309,13 +354,15 @@ check_deps(char *target)
 
 	printf("checkdeps %s\n", target);
 
+	target = targetchdir(target);
+
 	if (access(target, F_OK) != 0)
 		return 0;
 
 	asprintf(&depfile, ".%s.dep", target);
 	f = fopen(depfile, "r");
 	if (!f)
-		ok = 0;
+		return 0;
 
 	while (ok && !feof(f)) {
 		char line[4096];
@@ -402,6 +449,9 @@ find_job(pid_t pid)
 static struct job *
 run_script(char *target, int implicit)
 {
+	char *orig_target = target;
+	target = targetchdir(target);
+
 	char *depfile;
 	asprintf(&depfile, ".%s.dep", target);
 	
@@ -478,7 +528,7 @@ djb-style default.o.do:
 		if (!job)
 			exit(-1);
 		job->pid = pid;
-		job->target = target;
+		job->target = orig_target;
 		job->temp_depfile = strdup(temp_depfile);
 		job->temp_target = strdup(temp_target);
 		job->implicit = implicit;
@@ -628,15 +678,18 @@ redo_ifchange(int targetc, char *targetv[])
 			remove(job->temp_target);
 		} else {
 			char *depfile;
-			asprintf(&depfile, ".%s.dep", job->target);
+
+			char *target = targetchdir(job->target);
+
+			asprintf(&depfile, ".%s.dep", target);
 			printf("renamed %s to %s.\n", job->temp_depfile, depfile);
 			rename(job->temp_depfile, depfile);
 
 			struct stat st;
 			if (stat(job->temp_target, &st) == 0 &&
 			    st.st_size > 0) {
-				printf("renamed %s to %s.\n", job->temp_target, job->target);
-				rename(job->temp_target, job->target);
+				printf("renamed %s to %s.\n", job->temp_target, target);
+				rename(job->temp_target, target);
 			}
 		}
 		
@@ -672,6 +725,12 @@ record_deps(int targetc, char *targetv[])
 int
 main(int argc, char *argv[])
 {
+	dir_fd = open(".", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+	if (dir_fd < 0) {
+		perror("dir open");
+		exit(-1);
+	}
+
 	dep_fd = envfd("REDO_DEP_FD");
 	printf("DEPFD %d\n", dep_fd);