ccanlint: build depends if necessary
authorRusty Russell <rusty@rustcorp.com.au>
Tue, 23 Nov 2010 12:49:19 +0000 (23:19 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 23 Nov 2010 12:51:03 +0000 (23:21 +1030)
Now it will build copies of other ccan deps if it can't find them.

tools/ccanlint/ccanlint.h
tools/ccanlint/compulsory_tests/build.c
tools/ccanlint/compulsory_tests/build.h [new file with mode: 0644]
tools/ccanlint/compulsory_tests/check_build.c
tools/ccanlint/compulsory_tests/check_depends_built.c
tools/ccanlint/compulsory_tests/check_depends_exist.c
tools/ccanlint/file_analysis.c
tools/ccanlint/tests/build-coverage.c
tools/ccanlint/tests/compile_tests.c
tools/ccanlint/tests/depends_accurate.c
tools/ccanlint/tests/examples_compile.c

index f5f7b51d8bbb89078d83fa82aa356c305856da70..458bed54e6acae9ec4b653c3f2c22ad67efcb8d0 100644 (file)
@@ -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);
index 7c73f0d4f834c98519dc68ff18420cb935d4d6cc..5bea548c46814af97cb3afaf76ef673a2145eec0 100644 (file)
@@ -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;
 }
diff --git a/tools/ccanlint/compulsory_tests/build.h b/tools/ccanlint/compulsory_tests/build.h
new file mode 100644 (file)
index 0000000..64abca4
--- /dev/null
@@ -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 */
index 830ea91427d4faef8116d686287969ef5215f906..8cd9ed8649bd106e3a9a18db957cb8f05f5652b3 100644 (file)
@@ -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;
 }
index 41e5d8885e52aea5026d73d426c10eee9c592e99..3bd82f830971ff4ec7eefcde5b4bb342d31b1390 100644 (file)
@@ -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,
 };
index e2437083e018d2dc52d70e64e09971b406b06e1b..d1f33b6465fbf99e0e94103c1d9d7d10b603f58f 100644 (file)
 #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 = {
index d17940a5d494b7763b72c8c34fbbe99848de4f2b..59dd40fd9d4c04585b990fd1b0772c4b27d87352 100644 (file)
@@ -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)
index 9415647f8f46974705af95fc2c96eca7a0af964b..31bb7882fed96956da8677dfb9541989852a1b6a 100644 (file)
@@ -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;
index e95849b2b7eaf89b4636e1670baa6fe4517822be..80ebe913da7b227945d15e227225e16d609773c8 100644 (file)
@@ -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;
index 3ba19f60a3240e0385dd720b509887bd4e4b493e..943fa350e09b3a8d6bc8ffc10c990f3e12e4a8d7 100644 (file)
@@ -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";
index 31b0a3ae8b1bef0cb306537a99772b5158cc3ecb..7cee7795b7c8fef9cd532437e3d4977b6bce1fda 100644 (file)
@@ -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. */