From: Rusty Russell Date: Sat, 12 Sep 2009 01:27:44 +0000 (+0930) Subject: Build tests for ccan. X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=61088f5c752c555172e2ab6cf93a7967f79f3f2c Build tests for ccan. More sophisticated skipping: skip dependencies when one fails as well. Allow tests to change their total_score; only access it after running (other than to check it's non-zero). --- diff --git a/tools/Makefile b/tools/Makefile index 173355ab..f3575b3d 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -3,13 +3,13 @@ ALL_TOOLS = tools/ccan_depends tools/run_tests tools/doc_extract tools/namespaci .PHONY: tools tools: $(ALL_TOOLS) -tools/ccan_depends: tools/ccan_depends.o tools/depends.o ccan/str_talloc/str_talloc.o ccan/grab_file/grab_file.o ccan/talloc/talloc.o ccan/noerr/noerr.o +tools/ccan_depends: tools/ccan_depends.o tools/depends.o tools/tools.o ccan/str_talloc/str_talloc.o ccan/grab_file/grab_file.o ccan/talloc/talloc.o ccan/noerr/noerr.o tools/run_tests: tools/run_tests.o tools/depends.o ccan/str_talloc/str_talloc.o ccan/grab_file/grab_file.o ccan/tap/tap.o ccan/noerr/noerr.o ccan/talloc/talloc.o tools/doc_extract: tools/doc_extract.o tools/doc_extract-core.o ccan/str_talloc/str_talloc.o ccan/grab_file/grab_file.o ccan/noerr/noerr.o ccan/talloc/talloc.o -tools/namespacize: tools/namespacize.o tools/depends.o ccan/str_talloc/str_talloc.o ccan/grab_file/grab_file.o ccan/noerr/noerr.o ccan/talloc/talloc.o +tools/namespacize: tools/namespacize.o tools/depends.o tools/tools.o ccan/str_talloc/str_talloc.o ccan/grab_file/grab_file.o ccan/noerr/noerr.o ccan/talloc/talloc.o tools/run_tests.o tools/namespacize.o tools/depends.o: tools/tools.h diff --git a/tools/ccanlint/Makefile b/tools/ccanlint/Makefile index e40b59de..a99a6aeb 100644 --- a/tools/ccanlint/Makefile +++ b/tools/ccanlint/Makefile @@ -6,6 +6,7 @@ CORE_OBJS := tools/ccanlint/ccanlint.o \ tools/ccanlint/file_analysis.o \ tools/doc_extract-core.o \ tools/depends.o \ + tools/tools.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 f88b58dc..be6829c0 100644 --- a/tools/ccanlint/ccanlint.c +++ b/tools/ccanlint/ccanlint.c @@ -68,6 +68,19 @@ bool ask(const char *question) && toupper(reply[0]) == 'Y'; } +static const char *should_skip(struct manifest *m, struct ccanlint *i) +{ + if (i->skip_fail) + return "dependency failed"; + + if (i->skip) + return "dependency was skipped"; + + if (i->can_run) + return i->can_run(m); + return NULL; +} + static bool run_test(struct ccanlint *i, bool summary, unsigned int *score, @@ -77,18 +90,38 @@ static bool run_test(struct ccanlint *i, void *result; unsigned int this_score; const struct dependent *d; + const char *skip; - if (i->total_score) - *total_score += i->total_score; //one less test to run through list_for_each(&i->dependencies, d, node) d->dependent->num_depends--; + + skip = should_skip(m, i); + if (skip) { + if (verbose) + printf(" %s: skipped (%s)\n", i->name, skip); + + /* If we're skipping this because a prereq failed, we fail. */ + if (i->skip_fail) + *total_score += i->total_score; + + list_del(&i->list); + list_add_tail(&finished_tests, &i->list); + list_for_each(&i->dependencies, d, node) { + d->dependent->skip = true; + d->dependent->skip_fail = i->skip_fail; + } + return true; + } + result = i->check(m); if (!result) { if (verbose) printf(" %s: OK\n", i->name); - if (i->total_score) + if (i->total_score) { *score += i->total_score; + *total_score += i->total_score; + } list_del(&i->list); list_add_tail(&finished_tests, &i->list); @@ -103,6 +136,7 @@ static bool run_test(struct ccanlint *i, list_del(&i->list); list_add_tail(&finished_tests, &i->list); + *total_score += i->total_score; *score += this_score; if (summary) { printf("%s FAILED (%u/%u)\n", @@ -119,11 +153,8 @@ static bool run_test(struct ccanlint *i, /* Skip any tests which depend on this one. */ list_for_each(&i->dependencies, d, node) { - list_del(&d->dependent->list); - list_add(&finished_tests, &d->dependent->list); - if (verbose) - printf(" -> skipping %s\n", d->dependent->name); - *total_score += d->dependent->total_score; + d->dependent->skip = true; + d->dependent->skip_fail = true; } return false; diff --git a/tools/ccanlint/ccanlint.h b/tools/ccanlint/ccanlint.h index 9644185f..d832332d 100644 --- a/tools/ccanlint/ccanlint.h +++ b/tools/ccanlint/ccanlint.h @@ -26,8 +26,10 @@ struct manifest { struct list_head other_files; - /* From tests/check_depends.c */ - struct list_head dep_obj_files; + /* From tests/check_depends_exist.c */ + struct list_head dep_dirs; + /* From tests/check_depends_built.c */ + struct list_head dep_objs; }; struct manifest *get_manifest(const void *ctx); @@ -41,6 +43,9 @@ struct ccanlint { /* Total score that this test is worth. 0 means compulsory tests. */ unsigned int total_score; + /* Can we run this test? Return string explaining why, if not. */ + const char *(*can_run)(struct manifest *m); + /* If this returns non-NULL, it means the check failed. */ void *(*check)(struct manifest *m); @@ -60,6 +65,10 @@ struct ccanlint { struct list_head dependencies; /* How many things do we (still) depend on? */ unsigned int num_depends; + /* Did we skip a dependency? If so, must skip this, too. */ + bool skip; + /* Did we fail a dependency? If so, skip and mark as fail. */ + bool skip_fail; }; /* Ask the user a yes/no question: the answer is NO if there's an error. */ diff --git a/tools/ccanlint/file_analysis.c b/tools/ccanlint/file_analysis.c index 3c8930f3..44ea5c2d 100644 --- a/tools/ccanlint/file_analysis.c +++ b/tools/ccanlint/file_analysis.c @@ -164,6 +164,8 @@ struct manifest *get_manifest(const void *ctx) list_head_init(&m->compile_fail_tests); list_head_init(&m->other_test_files); list_head_init(&m->other_files); + list_head_init(&m->dep_dirs); + list_head_init(&m->dep_objs); m->basename = talloc_getcwd(m); if (!m->basename) diff --git a/tools/ccanlint/tests/build.c b/tools/ccanlint/tests/build.c new file mode 100644 index 00000000..c3b570e4 --- /dev/null +++ b/tools/ccanlint/tests/build.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *can_build(struct manifest *m) +{ + if (list_empty(&m->c_files)) + return "No C files in module"; + if (safe_mode) + return "Safe mode enabled"; + return NULL; +} + +static char *obj_list(const struct manifest *m) +{ + char *list = talloc_strdup(m, ""); + struct ccan_file *i; + + /* Object from all the C files. */ + list_for_each(&m->c_files, i, list) + list = talloc_asprintf_append(list, "%.*s.o ", + strlen(i->name) - 2, i->name); + + return list; +} + +/* We leave this object file around after ccanlint runs, all built. */ +static void *do_build(struct manifest *m) +{ + return run_command(m, "ld -r -o ../%s.o %s", m->basename, obj_list(m)); +} + +static const char *describe_build(struct manifest *m, void *check_result) +{ + return talloc_asprintf(check_result, + "The object file for the module didn't build:\n" + "%s", (char *)check_result); +} + +struct ccanlint build = { + .name = "Module can be built", + .total_score = 1, + .check = do_build, + .describe = describe_build, + .can_run = can_build, +}; + +REGISTER_TEST(build, &depends_built, NULL); diff --git a/tools/ccanlint/tests/build_objs.c b/tools/ccanlint/tests/build_objs.c new file mode 100644 index 00000000..199772ab --- /dev/null +++ b/tools/ccanlint/tests/build_objs.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *can_build(struct manifest *m) +{ + if (list_empty(&m->c_files)) + return "No C files in module"; + if (safe_mode) + return "Safe mode enabled"; + return NULL; +} + +static bool compile_obj(struct ccan_file *c_file, char *objfile, char **report) +{ + char *contents; + + contents = run_command(objfile, "cc " CFLAGS " -o %s -c %s", + objfile, c_file->name); + if (contents) { + if (*report) + *report = talloc_append_string(*report, contents); + else + *report = contents; + return false; + } + return true; +} + +static int cleanup_obj(char *objfile) +{ + unlink(objfile); + return 0; +} + +static void *check_objs_build(struct manifest *m) +{ + char *report = NULL; + struct ccan_file *i; + + /* One point for each obj file. */ + build_objs.total_score = 0; + list_for_each(&m->c_files, i, list) + build_objs.total_score++; + + list_for_each(&m->c_files, i, list) { + char *objfile = talloc_strdup(m, i->name); + objfile[strlen(objfile)-1] = 'o'; + + if (compile_obj(i, objfile, &report)) + talloc_set_destructor(objfile, cleanup_obj); + } + return report; +} + +static const char *describe_objs_build(struct manifest *m, void *check_result) +{ + return talloc_asprintf(check_result, + "%s", (char *)check_result); +} + +struct ccanlint build_objs = { + .name = "Module object files can be built", + .total_score = 1, + .check = check_objs_build, + .describe = describe_objs_build, + .can_run = can_build, +}; + +REGISTER_TEST(build_objs, &depends_exist, NULL); diff --git a/tools/ccanlint/tests/check_build.c b/tools/ccanlint/tests/check_build.c new file mode 100644 index 00000000..03e3233c --- /dev/null +++ b/tools/ccanlint/tests/check_build.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *can_build(struct manifest *m) +{ + if (safe_mode) + return "Safe mode enabled"; + return NULL; +} + +static int cleanup_testfile(char *testfile) +{ + unlink(testfile); + return 0; +} + +static char *obj_list(const struct manifest *m) +{ + char *list = talloc_strdup(m, ""); + struct ccan_file *i; + + /* Other CCAN deps. */ + list_for_each(&m->dep_objs, i, list) + list = talloc_asprintf_append(list, "%s ", i->name); + + return list; +} + +static char *lib_list(const struct manifest *m) +{ + unsigned int i, num; + char **libs = get_libs(m, ".", ".", &num); + char *ret = talloc_strdup(m, ""); + + for (i = 0; i < num; i++) + ret = talloc_asprintf_append(ret, "-l %s ", libs[i]); + return ret; +} + +static void *check_use_build(struct manifest *m) +{ + char *contents; + char *tmpfile, *outfile; + int fd; + + tmpfile = talloc_strdup(m, tempnam("/tmp", "ccanlint")); + talloc_set_destructor(tmpfile, cleanup_testfile); + outfile = talloc_strdup(m, tempnam("/tmp", "ccanlint")); + talloc_set_destructor(outfile, cleanup_testfile); + + fd = open(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) + return talloc_asprintf(m, "Creating temporary file: %s", + strerror(errno)); + + contents = talloc_asprintf(tmpfile, + "#include \n" + "int main(void)\n" + "{\n" + " return 0;\n" + "}\n", + m->basename, m->basename); + if (write(fd, contents, strlen(contents)) != strlen(contents)) { + close(fd); + return "Failure writing to temporary file"; + } + close(fd); + + return run_command(m, "cc " CFLAGS " -o %s -x c %s -x none %s %s", + outfile, tmpfile, obj_list(m), lib_list(m)); +} + +static const char *describe_use_build(struct manifest *m, void *check_result) +{ + return talloc_asprintf(check_result, + "Linking against module:\n" + "%s", (char *)check_result); +} + +struct ccanlint check_build = { + .name = "Module can be used", + .total_score = 1, + .check = check_use_build, + .describe = describe_use_build, + .can_run = can_build, +}; + +REGISTER_TEST(check_build, &build, NULL); diff --git a/tools/ccanlint/tests/check_depends.c b/tools/ccanlint/tests/check_depends.c deleted file mode 100644 index fecce0b6..00000000 --- a/tools/ccanlint/tests/check_depends.c +++ /dev/null @@ -1,109 +0,0 @@ -#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/ccanlint/tests/check_depends_built.c b/tools/ccanlint/tests/check_depends_built.c new file mode 100644 index 00000000..02fa83b8 --- /dev/null +++ b/tools/ccanlint/tests/check_depends_built.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *can_build(struct manifest *m) +{ + if (safe_mode) + return "Safe mode enabled"; + return NULL; +} + +/* FIXME: recursive ccanlint if they ask for it. */ +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; +} + +static void *check_depends_built(struct manifest *m) +{ + struct ccan_file *i; + char *report = NULL; + + list_for_each(&m->dep_dirs, i, list) { + char *objfile; + struct stat st; + + if (!expect_obj_file(i->name)) + continue; + + objfile = talloc_asprintf(m, "%s.o", i->name); + if (stat(objfile, &st) != 0) { + report = talloc_asprintf_append(report, + "object file %s\n", + objfile); + } else { + struct ccan_file *f = new_ccan_file(m, objfile); + list_add_tail(&m->dep_objs, &f->list); + } + + } + return talloc_steal(m, report); +} + +static const char *describe_depends_built(struct manifest *m, + void *check_result) +{ + return talloc_asprintf(check_result, + "The following dependencies are not built:\n" + "%s", (char *)check_result); +} + +struct ccanlint depends_built = { + .name = "CCAN dependencies are built", + .total_score = 1, + .check = check_depends_built, + .describe = describe_depends_built, + .can_run = can_build, +}; + +REGISTER_TEST(depends_built, &depends_exist, NULL); diff --git a/tools/ccanlint/tests/check_depends_exist.c b/tools/ccanlint/tests/check_depends_exist.c new file mode 100644 index 00000000..0978340f --- /dev/null +++ b/tools/ccanlint/tests/check_depends_exist.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *add_dep(char *sofar, struct manifest *m, const char *dep) +{ + char *dir; + struct stat st; + struct ccan_file *f; + + dir = talloc_asprintf(m, "../%s", dep); + if (stat(dir, &st) != 0) { + return talloc_asprintf_append(sofar, + "ccan/%s: expected it in" + " directory %s\n", + dep, dir); + } + + f = new_ccan_file(m, dir); + list_add_tail(&m->dep_dirs, &f->list); + return sofar; +} + +static void *check_depends_exist(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_exist(struct manifest *m, + void *check_result) +{ + return talloc_asprintf(check_result, + "The following dependencies are are expected:\n" + "%s", (char *)check_result); +} + +struct ccanlint depends_exist = { + .name = "CCAN dependencies are present", + .total_score = 1, + .check = check_depends_exist, + .describe = describe_depends_exist, +}; + +REGISTER_TEST(depends_exist, NULL); diff --git a/tools/ccanlint/tests/check_includes_build.c b/tools/ccanlint/tests/check_includes_build.c new file mode 100644 index 00000000..33668ed8 --- /dev/null +++ b/tools/ccanlint/tests/check_includes_build.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *can_build(struct manifest *m) +{ + if (safe_mode) + return "Safe mode enabled"; + return NULL; +} + +static int cleanup_testfile(char *testfile) +{ + unlink(testfile); + return 0; +} + +static void *check_includes_build(struct manifest *m) +{ + char *contents; + char *tmpfile, *objfile; + int fd; + + tmpfile = talloc_strdup(m, tempnam("/tmp", "ccanlint")); + talloc_set_destructor(tmpfile, cleanup_testfile); + objfile = talloc_strdup(m, tempnam("/tmp", "ccanlint")); + talloc_set_destructor(objfile, cleanup_testfile); + + fd = open(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) + return talloc_asprintf(m, "Creating temporary file: %s", + strerror(errno)); + + contents = talloc_asprintf(tmpfile, "#include \n", + m->basename, m->basename); + if (write(fd, contents, strlen(contents)) != strlen(contents)) { + close(fd); + return "Failure writing to temporary file"; + } + close(fd); + + return run_command(m, "cc " CFLAGS " -o %s -c -x c %s", + objfile, tmpfile); +} + +static const char *describe_includes_build(struct manifest *m, + void *check_result) +{ + return talloc_asprintf(check_result, + "#include of the main header file:\n" + "%s", (char *)check_result); +} + +struct ccanlint includes_build = { + .name = "Can compile against main header", + .total_score = 1, + .check = check_includes_build, + .describe = describe_includes_build, + .can_run = can_build, +}; + +REGISTER_TEST(includes_build, &depends_exist, NULL); diff --git a/tools/depends.c b/tools/depends.c index 1360cc39..203788fe 100644 --- a/tools/depends.c +++ b/tools/depends.c @@ -185,6 +185,22 @@ get_all_deps(const void *ctx, const char *dir, const char *name, return deps; } +char **get_libs(const void *ctx, const char *dir, + const char *name, unsigned int *num) +{ + char **libs, *cmd, *infofile; + + infofile = compile_info(ctx, dir, name); + if (!infofile) + errx(1, "Could not compile _info for '%s'", name); + + cmd = talloc_asprintf(ctx, "%s libs", infofile); + libs = lines_from_cmd(cmd, num, "%s", cmd); + if (!libs) + err(1, "Could not run '%s'", cmd); + return libs; +} + char **get_deps(const void *ctx, const char *dir, const char *name, bool recurse) { @@ -204,40 +220,3 @@ char **get_safe_ccan_deps(const void *ctx, const char *dir, } 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/tools.c b/tools/tools.c new file mode 100644 index 00000000..d50a67fd --- /dev/null +++ b/tools/tools.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include "tools.h" + +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; +} + +char *run_command(const void *ctx, const char *fmt, ...) +{ + va_list ap; + char *cmd, *contents; + FILE *pipe; + + va_start(ap, fmt); + cmd = talloc_vasprintf(ctx, fmt, ap); + va_end(ap); + + /* Ensure stderr gets to us too. */ + cmd = talloc_asprintf_append(cmd, " 2>&1"); + + pipe = popen(cmd, "r"); + if (!pipe) + return talloc_asprintf(ctx, "Failed to run '%s'", cmd); + + contents = grab_fd(cmd, fileno(pipe), NULL); + if (pclose(pipe) != 0) + return talloc_asprintf(ctx, "Running '%s':\n%s", + cmd, contents); + + talloc_free(cmd); + return NULL; +} diff --git a/tools/tools.h b/tools/tools.h index 6ac4e66f..9fd1e1f6 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -19,7 +19,13 @@ char **get_deps(const void *ctx, const char *dir, const char *name, char **get_safe_ccan_deps(const void *ctx, const char *dir, const char *name, bool recurse); +/* This also needs to compile the info file. */ +char **get_libs(const void *ctx, const char *dir, + const char *name, unsigned int *num); + +/* From tools.c */ char *talloc_basename(const void *ctx, const char *dir); char *talloc_dirname(const void *ctx, const char *dir); char *talloc_getcwd(const void *ctx); +char *run_command(const void *ctx, const char *fmt, ...); #endif /* CCAN_TOOLS_H */