From: Rusty Russell Date: Tue, 8 Sep 2009 11:42:03 +0000 (+0930) Subject: Dependency checking (make sure .o files exist, prereq to building) X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=b0f7eb297643941bd96eb209f35fbe223cd24e10 Dependency checking (make sure .o files exist, prereq to building) --- diff --git a/tools/ccan_depends.c b/tools/ccan_depends.c index 0c46173f..1baff828 100644 --- a/tools/ccan_depends.c +++ b/tools/ccan_depends.c @@ -12,6 +12,7 @@ int main(int argc, char *argv[]) bool compile = false; bool recurse = true; bool ccan = true; + char *dirname, *basename; if (argv[1] && streq(argv[1], "--direct")) { argv++; @@ -36,11 +37,15 @@ int main(int argc, char *argv[]) if (!ccan && !compile) errx(1, "--non-ccan needs --compile"); + dirname = talloc_dirname(NULL, argv[1]); + basename = talloc_basename(NULL, argv[1]); + if (compile) - deps = get_deps(talloc_autofree_context(), argv[1], recurse); + deps = get_deps(talloc_autofree_context(), + dirname, basename, recurse); else - deps = get_safe_ccan_deps(talloc_autofree_context(), argv[1], - recurse); + deps = get_safe_ccan_deps(talloc_autofree_context(), + dirname, basename, recurse); for (i = 0; deps[i]; i++) if (strstarts(deps[i], "ccan/") == ccan) diff --git a/tools/ccanlint/Makefile b/tools/ccanlint/Makefile index 16c4bfd2..e40b59de 100644 --- a/tools/ccanlint/Makefile +++ b/tools/ccanlint/Makefile @@ -5,6 +5,7 @@ TEST_OBJS := $(TEST_CFILES:.c=.o) CORE_OBJS := tools/ccanlint/ccanlint.o \ tools/ccanlint/file_analysis.o \ tools/doc_extract-core.o \ + tools/depends.o \ ccan/str_talloc/str_talloc.o ccan/grab_file/grab_file.o \ ccan/talloc/talloc.o ccan/noerr/noerr.o diff --git a/tools/ccanlint/ccanlint.c b/tools/ccanlint/ccanlint.c index 1164c314..9b252735 100644 --- a/tools/ccanlint/ccanlint.c +++ b/tools/ccanlint/ccanlint.c @@ -25,18 +25,21 @@ #include #include #include +#include static unsigned int verbose = 0; static LIST_HEAD(compulsory_tests); static LIST_HEAD(normal_tests); static LIST_HEAD(finished_tests); +bool safe_mode = false; static void usage(const char *name) { - fprintf(stderr, "Usage: %s [-s] [-v] [-d ]\n" + fprintf(stderr, "Usage: %s [-s] [-n] [-v] [-d ]\n" " -v: verbose mode\n" " -s: simply give one line per FAIL and total score\n" - " -d: use this directory instead of the current one\n", + " -d: use this directory instead of the current one\n" + " -n: do not compile anything\n", name); exit(1); } @@ -208,7 +211,7 @@ int main(int argc, char *argv[]) /* I'd love to use long options, but that's not standard. */ /* FIXME: getopt_long ccan package? */ - while ((c = getopt(argc, argv, "sd:v")) != -1) { + while ((c = getopt(argc, argv, "sd:vn")) != -1) { switch (c) { case 'd': if (chdir(optarg) != 0) @@ -220,6 +223,9 @@ int main(int argc, char *argv[]) case 'v': verbose++; break; + case 'n': + safe_mode = true; + break; default: usage(argv[0]); } @@ -228,7 +234,7 @@ int main(int argc, char *argv[]) if (optind < argc) usage(argv[0]); - m = get_manifest(); + m = get_manifest(talloc_autofree_context()); init_tests(); @@ -249,6 +255,5 @@ int main(int argc, char *argv[]) run_test(i, summary, &score, &total_score, m); } printf("Total score: %u/%u\n", score, total_score); - return 0; } diff --git a/tools/ccanlint/ccanlint.h b/tools/ccanlint/ccanlint.h index ee12ce04..9644185f 100644 --- a/tools/ccanlint/ccanlint.h +++ b/tools/ccanlint/ccanlint.h @@ -11,6 +11,7 @@ #define REGISTER_TEST(name, ...) struct manifest { + /* The module name, ie. final element of dir name */ char *basename; struct ccan_file *info_file; @@ -24,9 +25,12 @@ struct manifest { struct list_head other_test_files; struct list_head other_files; + + /* From tests/check_depends.c */ + struct list_head dep_obj_files; }; -struct manifest *get_manifest(void); +struct manifest *get_manifest(const void *ctx); struct ccanlint { struct list_node list; @@ -113,6 +117,9 @@ struct ccan_file { struct list_head *doc_sections; }; +/* A new ccan_file, with the given name (talloc_steal onto returned value). */ +struct ccan_file *new_ccan_file(const void *ctx, char *name); + /* Use this rather than accessing f->lines directly: loads on demand. */ char **get_ccan_file_lines(struct ccan_file *f); @@ -155,4 +162,7 @@ struct dependent { struct ccanlint *dependent; }; +/* Are we happy to compile stuff, or just non-intrusive tests? */ +extern bool safe_mode; + #endif /* CCAN_LINT_H */ diff --git a/tools/ccanlint/file_analysis.c b/tools/ccanlint/file_analysis.c index 2a66a545..3c8930f3 100644 --- a/tools/ccanlint/file_analysis.c +++ b/tools/ccanlint/file_analysis.c @@ -32,6 +32,18 @@ struct list_head *get_ccan_file_docs(struct ccan_file *f) return f->doc_sections; } +struct ccan_file *new_ccan_file(const void *ctx, char *name) +{ + struct ccan_file *f; + + f = talloc(ctx, struct ccan_file); + f->lines = NULL; + f->line_info = NULL; + f->doc_sections = NULL; + f->name = talloc_steal(f, name); + return f; +} + static void add_files(struct manifest *m, const char *dir) { DIR *d; @@ -53,11 +65,8 @@ static void add_files(struct manifest *m, const char *dir) if (ent->d_name[0] == '.') continue; - f = talloc(m, struct ccan_file); - f->lines = NULL; - f->line_info = NULL; - f->doc_sections = NULL; - f->name = talloc_asprintf(f, "%s%s", dir, ent->d_name); + f = new_ccan_file(m, talloc_asprintf(m, "%s%s", + dir, ent->d_name)); if (lstat(f->name, &st) != 0) err(1, "lstat %s", f->name); @@ -141,9 +150,9 @@ char *report_on_lines(struct list_head *files, return sofar; } -struct manifest *get_manifest(void) +struct manifest *get_manifest(const void *ctx) { - struct manifest *m = talloc(NULL, struct manifest); + struct manifest *m = talloc(ctx, struct manifest); unsigned int len; m->info_file = NULL; @@ -156,15 +165,9 @@ struct manifest *get_manifest(void) list_head_init(&m->other_test_files); list_head_init(&m->other_files); - /* *This* is why people hate C. */ - len = 32; - m->basename = talloc_array(m, char, len); - while (!getcwd(m->basename, len)) { - if (errno != ERANGE) - err(1, "Getting current directory"); - m->basename = talloc_realloc(m, m->basename, char, len *= 2); - } - + m->basename = talloc_getcwd(m); + if (!m->basename) + err(1, "Getting current directory"); len = strlen(m->basename); while (len && m->basename[len-1] == '/') m->basename[--len] = '\0'; diff --git a/tools/ccanlint/tests/check_depends.c b/tools/ccanlint/tests/check_depends.c new file mode 100644 index 00000000..fecce0b6 --- /dev/null +++ b/tools/ccanlint/tests/check_depends.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool expect_obj_file(const char *dir) +{ + char *olddir; + struct manifest *dep_man; + bool has_c_files; + + olddir = talloc_getcwd(dir); + if (!olddir) + err(1, "Getting current directory"); + + /* We will fail below if this doesn't exist. */ + if (chdir(dir) != 0) + return false; + + dep_man = get_manifest(dir); + if (chdir(olddir) != 0) + err(1, "Returning to original directory '%s'", olddir); + talloc_free(olddir); + + /* 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; +} + +/* FIXME: recursive ccanlint if they ask for it. */ +static char *add_dep(char *sofar, struct manifest *m, const char *dep) +{ + char *file, *dir; + struct stat st; + bool need_obj; + + dir = talloc_asprintf(m, "../%s", dep); + need_obj = expect_obj_file(dir); + + if (need_obj) { + file = talloc_asprintf(m, "../%s.o", dep); + if (stat(file, &st) == 0) { + struct ccan_file *f = new_ccan_file(m, file); + list_add_tail(&m->dep_obj_files, &f->list); + return sofar; + } + } + + if (stat(dir, &st) == 0) { + if (!need_obj) + return sofar; + + return talloc_asprintf_append(sofar, + "ccan/%s: isn't built (no %s)\n", + dep, file); + } + + return talloc_asprintf_append(sofar, + "ccan/%s: could not find directory %s\n", + dep, dir); +} + +static void *check_depends(struct manifest *m) +{ + unsigned int i; + char *report = NULL; + char **deps; + + if (safe_mode) + deps = get_safe_ccan_deps(m, "..", m->basename, true); + else + deps = get_deps(m, "..", m->basename, true); + + for (i = 0; deps[i]; i++) { + if (!strstarts(deps[i], "ccan/")) + continue; + + report = add_dep(report, m, deps[i] + strlen("ccan/")); + } + return report; +} + +static const char *describe_depends(struct manifest *m, void *check_result) +{ + return talloc_asprintf(check_result, + "The following dependencies are needed:\n" + "%s\n", (char *)check_result); +} + +struct ccanlint depends = { + .name = "CCAN dependencies are built", + .total_score = 1, + .check = check_depends, + .describe = describe_depends, +}; + +REGISTER_TEST(depends, NULL); diff --git a/tools/depends.c b/tools/depends.c index c9cf8816..1360cc39 100644 --- a/tools/depends.c +++ b/tools/depends.c @@ -6,6 +6,7 @@ #include #include #include +#include static char ** __attribute__((format(printf, 3, 4))) lines_from_cmd(const void *ctx, unsigned int *num, char *format, ...) @@ -37,11 +38,12 @@ static int unlink_info(char *infofile) } /* Be careful about trying to compile over running programs (parallel make) */ -static char *compile_info(const void *ctx, const char *dir) +static char *compile_info(const void *ctx, const char *dir, const char *name) { char *infofile = talloc_asprintf(ctx, "%s/info.%u", dir, getpid()); - char *cmd = talloc_asprintf(ctx, "cc " CFLAGS " -o %s -x c %s/_info", - infofile, dir); + char *cmd = talloc_asprintf(ctx, "cc " CFLAGS + " -o %s -x c %s/%s/_info", + infofile, dir, name); talloc_set_destructor(infofile, unlink_info); if (system(cmd) != 0) return NULL; @@ -49,13 +51,14 @@ static char *compile_info(const void *ctx, const char *dir) return infofile; } -static char **get_one_deps(const void *ctx, const char *dir, unsigned int *num) +static char **get_one_deps(const void *ctx, const char *dir, + const char *name, unsigned int *num) { char **deps, *cmd, *infofile; - infofile = compile_info(ctx, dir); + infofile = compile_info(ctx, dir, name); if (!infofile) - errx(1, "Could not compile _info for '%s'", dir); + errx(1, "Could not compile _info for '%s'", name); cmd = talloc_asprintf(ctx, "%s depends", infofile); deps = lines_from_cmd(cmd, num, "%s", cmd); @@ -93,12 +96,13 @@ static char *replace(const void *ctx, const char *src, /* This is a terrible hack. We scan for ccan/ strings. */ static char **get_one_safe_deps(const void *ctx, - const char *dir, unsigned int *num) + const char *dir, const char *name, + unsigned int *num) { char **deps, **lines, *raw, *fname; unsigned int i, n = 0; - fname = talloc_asprintf(ctx, "%s/_info", dir); + fname = talloc_asprintf(ctx, "%s/%s/_info", dir, name); raw = grab_file(fname, fname, NULL); if (!raw) errx(1, "Could not open %s", fname); @@ -150,13 +154,14 @@ static bool have_dep(char **deps, unsigned int num, const char *dep) /* Gets all the dependencies, recursively. */ static char ** -get_all_deps(const void *ctx, const char *dir, - char **(*get_one)(const void *, const char *, unsigned int *)) +get_all_deps(const void *ctx, const char *dir, const char *name, + char **(*get_one)(const void *, const char *, const char *, + unsigned int *)) { char **deps; unsigned int i, num; - deps = get_one(ctx, dir, &num); + deps = get_one(ctx, dir, name, &num); for (i = 0; i < num; i++) { char **newdeps; unsigned int j, newnum; @@ -164,7 +169,8 @@ get_all_deps(const void *ctx, const char *dir, if (!strstarts(deps[i], "ccan/")) continue; - newdeps = get_one(ctx, deps[i], &newnum); + newdeps = get_one(ctx, dir, deps[i] + strlen("ccan/"), + &newnum); /* Should be short, so brute-force out dups. */ for (j = 0; j < newnum; j++) { @@ -179,21 +185,59 @@ get_all_deps(const void *ctx, const char *dir, return deps; } -char **get_deps(const void *ctx, const char *dir, bool recurse) +char **get_deps(const void *ctx, const char *dir, const char *name, + bool recurse) { if (!recurse) { unsigned int num; - return get_one_deps(ctx, dir, &num); + return get_one_deps(ctx, dir, name, &num); } - return get_all_deps(ctx, dir, get_one_deps); + return get_all_deps(ctx, dir, name, get_one_deps); } -char **get_safe_ccan_deps(const void *ctx, const char *dir, bool recurse) +char **get_safe_ccan_deps(const void *ctx, const char *dir, + const char *name, bool recurse) { if (!recurse) { unsigned int num; - return get_one_safe_deps(ctx, dir, &num); + return get_one_safe_deps(ctx, dir, name, &num); } - return get_all_deps(ctx, dir, get_one_safe_deps); + return get_all_deps(ctx, dir, name, get_one_safe_deps); } +char *talloc_basename(const void *ctx, const char *dir) +{ + char *p = strrchr(dir, '/'); + + if (!p) + return (char *)dir; + return talloc_strdup(ctx, p+1); +} + +char *talloc_dirname(const void *ctx, const char *dir) +{ + char *p = strrchr(dir, '/'); + + if (!p) + return talloc_strdup(ctx, "."); + return talloc_strndup(ctx, dir, p - dir); +} + +char *talloc_getcwd(const void *ctx) +{ + unsigned int len; + char *cwd; + + /* *This* is why people hate C. */ + len = 32; + cwd = talloc_array(ctx, char, len); + while (!getcwd(cwd, len)) { + if (errno != ERANGE) { + talloc_free(cwd); + return NULL; + } + cwd = talloc_realloc(ctx, cwd, char, len *= 2); + } + return cwd; +} + diff --git a/tools/namespacize.c b/tools/namespacize.c index 0ed36aa6..2e6dcbfb 100644 --- a/tools/namespacize.c +++ b/tools/namespacize.c @@ -102,15 +102,6 @@ static void add_replace_tok(struct replace **repl, const char *s) *repl = new; } -static char *basename(const void *ctx, const char *dir) -{ - char *p = strrchr(dir, '/'); - - if (!p) - return (char *)dir; - return talloc_strdup(ctx, p+1); -} - static void look_for_macros(char *contents, struct replace **repl) { char *p; @@ -269,7 +260,7 @@ static void analyze_headers(const char *dir, struct replace **repl) char *hdr, *contents; /* Get hold of header, assume that's it. */ - hdr = talloc_asprintf(dir, "%s/%s.h", dir, basename(dir, dir)); + hdr = talloc_asprintf(dir, "%s/%s.h", dir, talloc_basename(dir, dir)); contents = grab_file(dir, hdr, NULL); if (!contents) err(1, "Reading %s", hdr); @@ -459,27 +450,16 @@ static struct replace *read_replacement_file(const char *depdir) return repl; } -static char *parent_dir(const void *ctx, const char *dir) -{ - char *parent, *slash; - - parent = talloc_strdup(ctx, dir); - slash = strrchr(parent, '/'); - if (slash) - *slash = '\0'; - else - parent = talloc_strdup(ctx, "."); - return parent; -} - static void adjust_dir(const char *dir) { - char *parent = parent_dir(talloc_autofree_context(), dir); + char *parent = talloc_dirname(talloc_autofree_context(), dir); char **deps; verbose("Adjusting %s\n", dir); verbose_indent(); - for (deps = get_deps(parent, dir, false); *deps; deps++) { + for (deps = get_deps(parent, parent, talloc_basename(parent, dir), + false); + *deps; deps++) { char *depdir; struct adjusted *adj = NULL; struct replace *repl; @@ -500,8 +480,8 @@ static void adjust_dir(const char *dir) static void adjust_dependents(const char *dir) { - char *parent = parent_dir(NULL, dir); - char *base = basename(parent, dir); + char *parent = talloc_dirname(NULL, dir); + char *base = talloc_basename(parent, dir); char **file; verbose("Looking for dependents in %s\n", parent); @@ -510,15 +490,19 @@ static void adjust_dependents(const char *dir) char *info, **deps; bool isdep = false; - if (basename(*file, *file)[0] == '.') + if (talloc_basename(*file, *file)[0] == '.') continue; info = talloc_asprintf(*file, "%s/_info", *file); if (access(info, R_OK) != 0) continue; - for (deps = get_deps(*file, *file, false); *deps; deps++) { - if (streq(*deps, base)) + for (deps = get_deps(*file, talloc_dirname(*file, *file), + talloc_basename(*file, *file), false); + *deps; deps++) { + if (!strstarts(*deps, "ccan/")) + continue; + if (streq(*deps + strlen("ccan/"), base)) isdep = true; } if (isdep) diff --git a/tools/tools.h b/tools/tools.h index 4bdb8077..6ac4e66f 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -8,13 +8,18 @@ #define SPACE_CHARS " \f\n\r\t\v" -#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -Iccan/ -I." +/* FIXME: Remove some -I */ +#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -Iccan/ -I. -I../.." /* This actually compiles and runs the info file to get dependencies. */ -char **get_deps(const void *ctx, const char *dir, bool recurse); +char **get_deps(const void *ctx, const char *dir, const char *name, + bool recurse); /* This is safer: just looks for ccan/ strings in info */ -char **get_safe_ccan_deps(const void *ctx, const char *dir, bool recurse); +char **get_safe_ccan_deps(const void *ctx, const char *dir, const char *name, + bool recurse); +char *talloc_basename(const void *ctx, const char *dir); +char *talloc_dirname(const void *ctx, const char *dir); +char *talloc_getcwd(const void *ctx); #endif /* CCAN_TOOLS_H */ -