Browse Source

ccanlint: build depends if necessary

Now it will build copies of other ccan deps if it can't find them.
Rusty Russell 15 years ago
parent
commit
451d97ad85

+ 6 - 1
tools/ccanlint/ccanlint.h

@@ -26,6 +26,11 @@ struct manifest {
 	char *basename;
 	struct ccan_file *info_file;
 
+	/* Linked off deps. */
+	struct list_node list;
+	/* Where our final compiled output is */
+	char *compiled;
+
 	struct list_head c_files;
 	struct list_head h_files;
 
@@ -41,7 +46,7 @@ struct manifest {
 	struct list_head mangled_examples;
 
 	/* From tests/check_depends_exist.c */
-	struct list_head dep_dirs;
+	struct list_head deps;
 };
 
 struct manifest *get_manifest(const void *ctx, const char *dir);

+ 19 - 10
tools/ccanlint/compulsory_tests/build.c

@@ -13,6 +13,7 @@
 #include <err.h>
 #include <string.h>
 #include <ctype.h>
+#include "build.h"
 
 static const char *can_build(struct manifest *m)
 {
@@ -33,12 +34,27 @@ static char *obj_list(const struct manifest *m)
 	return list;
 }
 
+char *build_module(struct manifest *m, bool keep, char **errstr)
+{
+	char *name = link_objects(m, m->basename, false, obj_list(m), errstr);
+	if (name) {
+		if (keep) {
+			char *realname = talloc_asprintf(m, "%s.o", m->dir);
+			/* We leave this object file around, all built. */
+			if (!move_file(name, realname))
+				err(1, "Renaming %s to %s", name, realname);
+			name = realname;
+		}
+	}
+	return name;
+}
+
 static void do_build(struct manifest *m,
 		     bool keep,
 		     unsigned int *timeleft,
 		     struct score *score)
 {
-	char *filename, *errstr;
+	char *errstr;
 
 	if (list_empty(&m->c_files)) {
 		/* No files?  No score, but we "pass". */
@@ -47,19 +63,12 @@ static void do_build(struct manifest *m,
 		return;
 	}
 
-	filename = link_objects(m, m->basename, false, obj_list(m), &errstr);
-	if (!filename) {
-		score->error = "The object file didn't build";
+	m->compiled = build_module(m, keep, &errstr);
+	if (!m->compiled) {
 		score_file_error(score, NULL, 0, errstr);
 		return;
 	}
 
-	if (keep) {
-		char *realname = talloc_asprintf(m, "%s.o", m->dir);
-		/* We leave this object file around, all built. */
-		if (!move_file(filename, realname))
-			err(1, "Renaming %s to %s", filename, realname);
-	}
 	score->pass = true;
 	score->score = score->total;
 }

+ 4 - 0
tools/ccanlint/compulsory_tests/build.h

@@ -0,0 +1,4 @@
+#ifndef CCANLINT_BUILD_H
+#define CCANLINT_BUILD_H
+char *build_module(struct manifest *m, bool keep, char **errstr);
+#endif /* CCANLINT_BUILD_H */

+ 4 - 3
tools/ccanlint/compulsory_tests/check_build.c

@@ -24,12 +24,13 @@ static const char *can_build(struct manifest *m)
 static char *obj_list(const struct manifest *m)
 {
 	char *list = talloc_strdup(m, "");
-	struct ccan_file *i;
+	struct manifest *i;
 
 	/* Other CCAN deps. */
-	list_for_each(&m->dep_dirs, i, list) {
+	list_for_each(&m->deps, i, list) {
 		if (i->compiled)
-			list = talloc_asprintf_append(list, "%s ", i->compiled);
+			list = talloc_asprintf_append(list, "%s ",
+						      i->compiled);
 	}
 	return list;
 }

+ 44 - 30
tools/ccanlint/compulsory_tests/check_depends_built.c

@@ -13,6 +13,7 @@
 #include <err.h>
 #include <string.h>
 #include <ctype.h>
+#include "build.h"
 
 static const char *can_build(struct manifest *m)
 {
@@ -21,50 +22,63 @@ static const char *can_build(struct manifest *m)
 	return NULL;
 }
 
-/* FIXME: recursive ccanlint if they ask for it. */
-static bool expect_obj_file(const char *dir)
+static bool expect_obj_file(struct manifest *m)
 {
-	struct manifest *dep_man;
-	bool has_c_files;
+	/* If it has C files, we expect an object file built from them. */
+	return !list_empty(&m->c_files);
+}
 
-	dep_man = get_manifest(dir, dir);
+static char *build_subdir_objs(struct manifest *m)
+{
+	struct ccan_file *i;
 
-	/* If it has C files, we expect an object file built from them. */
-	has_c_files = !list_empty(&dep_man->c_files);
-	talloc_free(dep_man);
-	return has_c_files;
+	list_for_each(&m->c_files, i, list) {
+		char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
+		char *output;
+
+		i->compiled = maybe_temp_file(m, "", false, fullfile);
+		if (!compile_object(m, fullfile, ccan_dir, "", i->compiled,
+				    &output)) {
+			talloc_free(i->compiled);
+			i->compiled = NULL;
+			return talloc_asprintf(m,
+					       "Dependency %s"
+					       " did not build:\n%s",
+					       m->basename, output);
+		}
+	}
+	return NULL;
 }
 
 static void check_depends_built(struct manifest *m,
 				bool keep,
 				unsigned int *timeleft, struct score *score)
 {
-	struct ccan_file *i;
+	struct manifest *i;
 	struct stat st;
 
-	list_for_each(&m->dep_dirs, i, list) {
-		if (!expect_obj_file(i->fullname))
+	list_for_each(&m->deps, i, list) {
+		char *errstr;
+		if (!expect_obj_file(i))
 			continue;
 
-		i->compiled = talloc_asprintf(i, "%s.o", i->fullname);
-		if (stat(i->compiled, &st) != 0) {
-			score->error = "Dependencies are not built";
-			score_file_error(score, i, 0,
-					 talloc_asprintf(score,
-							"object file %s",
-							 i->compiled));
-			i->compiled = NULL;
-		}			
-	}
+		i->compiled = talloc_asprintf(i, "%s.o", i->dir);
+		if (stat(i->compiled, &st) == 0)
+			continue;
 
-	/* We may need libtap for testing, unless we're "tap" */
-	if (!streq(m->basename, "tap")
-	    && (!list_empty(&m->run_tests) || !list_empty(&m->api_tests))) {
-		char *tapobj = talloc_asprintf(m, "%s/ccan/tap.o", ccan_dir);
-		if (stat(tapobj, &st) != 0) {
+		if (verbose >= 2)
+			printf("  Building dependency %s\n", i->dir);
+		score->error = build_subdir_objs(i);
+		if (score->error)
+			return;
+		i->compiled = build_module(i, keep, &errstr);
+		if (!i->compiled) {
 			score->error = talloc_asprintf(score,
-					       "tap object file not built");
-		}
+						       "Dependency %s"
+						       " did not build:\n%s",
+						       i->basename, errstr);
+			return;
+		}			
 	}
 
 	if (!score->error) {
@@ -75,7 +89,7 @@ static void check_depends_built(struct manifest *m,
 
 struct ccanlint depends_built = {
 	.key = "depends-built",
-	.name = "Module's CCAN dependencies are already built",
+	.name = "Module's CCAN dependencies can be found or built",
 	.check = check_depends_built,
 	.can_run = can_build,
 };

+ 25 - 12
tools/ccanlint/compulsory_tests/check_depends_exist.c

@@ -14,17 +14,23 @@
 #include <string.h>
 #include <ctype.h>
 
-static void add_dep(struct manifest *m, const char *dep, struct score *score)
+static bool add_dep(struct manifest *m, const char *dep, struct score *score)
 {
 	struct stat st;
-	struct ccan_file *f;
+	struct manifest *subm;
+	char *dir = talloc_asprintf(m, "%s/%s", ccan_dir, dep);
 
-	f = new_ccan_file(m, ccan_dir, talloc_strdup(m, dep));
-	if (stat(f->fullname, &st) != 0) {
-		score->error = "Depends don't exist";
-		score_file_error(score, f, 0, "could not stat");
-	} else
-		list_add_tail(&m->dep_dirs, &f->list);
+	/* FIXME: get_manifest has a tendency to exit. */
+	if (stat(dir, &st) != 0) {
+		score->error
+			= talloc_asprintf(m,
+					  "Could not stat dependency %s: %s",
+					  dir, strerror(errno));
+		return false;
+	}
+	subm = get_manifest(m, dir);
+	list_add_tail(&m->deps, &subm->list);
+	return true;
 }
 
 static void check_depends_exist(struct manifest *m,
@@ -47,12 +53,19 @@ static void check_depends_exist(struct manifest *m,
 		if (!strstarts(deps[i], "ccan/"))
 			continue;
 
-		add_dep(m, deps[i], score);
+		if (!add_dep(m, deps[i], score))
+			return;
 	}
-	if (!score->error) {
-		score->pass = true;
-		score->score = score->total;
+
+	/* We may need libtap for testing, unless we're "tap" */
+	if (!streq(m->basename, "tap")
+	    && (!list_empty(&m->run_tests) || !list_empty(&m->api_tests))) {
+		if (!add_dep(m, "ccan/tap", score))
+			return;
 	}
+
+	score->pass = true;
+	score->score = score->total;
 }
 
 struct ccanlint depends_exist = {

+ 2 - 1
tools/ccanlint/file_analysis.c

@@ -173,6 +173,7 @@ struct manifest *get_manifest(const void *ctx, const char *dir)
 	struct list_head *list;
 
 	m->info_file = NULL;
+	m->compiled = NULL;
 	list_head_init(&m->c_files);
 	list_head_init(&m->h_files);
 	list_head_init(&m->api_tests);
@@ -184,7 +185,7 @@ struct manifest *get_manifest(const void *ctx, const char *dir)
 	list_head_init(&m->other_files);
 	list_head_init(&m->examples);
 	list_head_init(&m->mangled_examples);
-	list_head_init(&m->dep_dirs);
+	list_head_init(&m->deps);
 
 	olddir = talloc_getcwd(NULL);
 	if (!olddir)

+ 7 - 10
tools/ccanlint/tests/build-coverage.c

@@ -50,16 +50,12 @@ static bool build_module_objs_with_coverage(struct manifest *m, bool keep,
 	return true;
 }
 
+/* FIXME: Merge this into one place. */
 static char *obj_list(const struct manifest *m, const char *modobjs)
 {
-	char *list;
+	char *list = talloc_strdup(m, "");
 	struct ccan_file *i;
-
-	/* We expect to be linked with tap, unless that's us. */
-	if (!streq(m->basename, "tap"))
-		list = talloc_asprintf(m, "%s/ccan/tap.o", ccan_dir);
-	else
-		list = talloc_strdup(m, "");
+	struct manifest *subm;
 
 	/* Objects from any other C files. */
 	list_for_each(&m->other_test_c_files, i, list)
@@ -69,9 +65,10 @@ static char *obj_list(const struct manifest *m, const char *modobjs)
 		list = talloc_append_string(list, modobjs);
 
 	/* Other ccan modules (don't need coverage versions of those). */
-	list_for_each(&m->dep_dirs, i, list) {
-		if (i->compiled)
-			list = talloc_asprintf_append(list, " %s", i->compiled);
+	list_for_each(&m->deps, subm, list) {
+		if (subm->compiled)
+			list = talloc_asprintf_append(list, " %s",
+						      subm->compiled);
 	}
 
 	return list;

+ 7 - 10
tools/ccanlint/tests/compile_tests.c

@@ -22,16 +22,12 @@ static const char *can_build(struct manifest *m)
 	return NULL;
 }
 
+/* FIXME: Merge this into one place. */
 static char *obj_list(const struct manifest *m, bool link_with_module)
 {
-	char *list;
+	char *list = talloc_strdup(m, "");
 	struct ccan_file *i;
-
-	/* We expect to be linked with tap, unless that's us. */
-	if (!streq(m->basename, "tap"))
-		list = talloc_asprintf(m, "%s/ccan/tap.o", ccan_dir);
-	else
-		list = talloc_strdup(m, "");
+	struct manifest *subm;
 
 	/* Objects from any other C files. */
 	list_for_each(&m->other_test_c_files, i, list)
@@ -43,9 +39,10 @@ static char *obj_list(const struct manifest *m, bool link_with_module)
 			list = talloc_asprintf_append(list, " %s", i->compiled);
 
 	/* Other ccan modules. */
-	list_for_each(&m->dep_dirs, i, list) {
-		if (i->compiled)
-			list = talloc_asprintf_append(list, " %s", i->compiled);
+	list_for_each(&m->deps, subm, list) {
+		if (subm->compiled)
+			list = talloc_asprintf_append(list, " %s",
+						      subm->compiled);
 	}
 
 	return list;

+ 7 - 14
tools/ccanlint/tests/depends_accurate.c

@@ -28,19 +28,16 @@ static char *strip_spaces(const void *ctx, char *line)
 	return p;
 }
 
-static bool has_dep(struct manifest *m, const char *depname, bool tap_ok)
+static bool has_dep(struct manifest *m, const char *depname)
 {
-	struct ccan_file *f;
-
-	if (tap_ok && streq(depname, "ccan/tap"))
-		return true;
+	struct manifest *i;
 
 	/* We can include ourselves, of course. */
-	if (streq(depname + strlen("ccan/"), m->basename))
+	if (streq(depname, m->basename))
 		return true;
 
-	list_for_each(&m->dep_dirs, f, list) {
-		if (streq(f->name, depname))
+	list_for_each(&m->deps, i, list) {
+		if (streq(i->basename, depname))
 			return true;
 	}
 	return false;
@@ -57,10 +54,6 @@ static void check_depends_accurate(struct manifest *m,
 		    &m->compile_ok_tests, &m->compile_fail_tests,
 		    &m->other_test_c_files) {
 		struct ccan_file *f;
-		bool tap_ok;
-
-		/* Including ccan/tap is fine for tests. */
-		tap_ok = (list != &m->c_files && list != &m->h_files);
 
 		list_for_each(list, f, list) {
 			unsigned int i;
@@ -74,11 +67,11 @@ static void check_depends_accurate(struct manifest *m,
 				if (!strstarts(p, "#include<ccan/")
 				    && !strstarts(p, "#include\"ccan/"))
 					continue;
-				p += strlen("#include\"");
+				p += strlen("#include\"ccan/");
 				if (!strchr(strchr(p, '/') + 1, '/'))
 					continue;
 				*strchr(strchr(p, '/') + 1, '/') = '\0';
-				if (has_dep(m, p, tap_ok))
+				if (has_dep(m, p))
 					continue;
 				score->error = "Includes a ccan module"
 					" not listed in _info";

+ 6 - 3
tools/ccanlint/tests/examples_compile.c

@@ -67,10 +67,12 @@ static char *add_dep(const struct manifest *m, char *list, const char *mod)
 	return list;
 }
 
+/* FIXME: Merge this into one place. */
 static char *obj_list(const struct manifest *m, struct ccan_file *f)
 {
 	char *list = talloc_strdup(m, "");
 	struct ccan_file *i;
+	struct manifest *subm;
 	char **lines;
 
 	/* Object files for this module. */
@@ -78,9 +80,10 @@ static char *obj_list(const struct manifest *m, struct ccan_file *f)
 		list = talloc_asprintf_append(list, " %s", i->compiled);
 
 	/* Other ccan modules we depend on. */
-	list_for_each(&m->dep_dirs, i, list) {
-		if (i->compiled)
-			list = talloc_asprintf_append(list, " %s", i->compiled);
+	list_for_each(&m->deps, subm, list) {
+		if (subm->compiled)
+			list = talloc_asprintf_append(list, " %s",
+						      subm->compiled);
 	}
 
 	/* Other modules implied by includes. */