Commit b0f7eb29 authored by Rusty Russell's avatar Rusty Russell

Dependency checking (make sure .o files exist, prereq to building)

parent 54299958
......@@ -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)
......
......@@ -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
......
......@@ -25,18 +25,21 @@
#include <string.h>
#include <err.h>
#include <ctype.h>
#include <ccan/talloc/talloc.h>
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 <dirname>]\n"
fprintf(stderr, "Usage: %s [-s] [-n] [-v] [-d <dirname>]\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;
}
......@@ -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 */
......@@ -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';
......
#include <tools/ccanlint/ccanlint.h>
#include <tools/tools.h>
#include <ccan/talloc/talloc.h>
#include <ccan/str/str.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <string.h>
#include <ctype.h>
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);
......@@ -6,6 +6,7 @@
#include <err.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
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;
}
......@@ -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)
......
......@@ -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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment