tools/namespacize
tools/run_tests
tools/ccanlint/ccanlint
-tools/ccanlint/generated-compulsory-tests
-tools/ccanlint/generated-normal-tests
+tools/ccanlint/generated-testlist
inter-depends
test-depends
lib-depends
-COMPULSORY_TEST_CFILES := $(wildcard tools/ccanlint/compulsory_tests/*.c)
-NORMAL_TEST_CFILES := $(wildcard tools/ccanlint/tests/*.c)
-TEST_OBJS := $(NORMAL_TEST_CFILES:.c=.o) $(COMPULSORY_TEST_CFILES:.c=.o)
+TEST_CFILES := $(wildcard tools/ccanlint/tests/*.c)
+TEST_OBJS := $(TEST_CFILES:.c=.o)
CORE_OBJS := \
ccan/asort/asort.o \
OBJS := $(CORE_OBJS) $(TEST_OBJS)
# FIXME: write a trivial C program to do this
-tools/ccanlint/generated-normal-tests: $(NORMAL_TEST_CFILES)
- cat $^ | grep ^REGISTER_TEST > $@
-tools/ccanlint/generated-compulsory-tests: $(COMPULSORY_TEST_CFILES)
+tools/ccanlint/generated-testlist: $(TEST_CFILES)
cat $^ | grep ^REGISTER_TEST > $@
-$(TEST_OBJS): tools/ccanlint/generated-normal-tests tools/ccanlint/generated-compulsory-tests
+$(TEST_OBJS): tools/ccanlint/generated-testlist
# Otherwise, ccanlint.c et al. may fail to build
-$(CORE_OBJS): tools/ccanlint/generated-normal-tests tools/ccanlint/generated-compulsory-tests config.h
+$(CORE_OBJS): tools/ccanlint/generated-testlist config.h
tools/ccanlint/ccanlint: $(OBJS)
ccanlint-clean:
- $(RM) tools/ccanlint/generated-compulsory-tests
- $(RM) tools/ccanlint/generated-normal-tests
+ $(RM) tools/ccanlint/generated-testlist
$(RM) tools/ccanlint/ccanlint
-
#include <ccan/foreach/foreach.h>
#include <ccan/grab_file/grab_file.h>
#include <ccan/cast/cast.h>
+#include <ccan/tlist/tlist.h>
+
+/* Defines struct tlist_ccanlint. */
+TLIST_TYPE(ccanlint, struct ccanlint);
int verbose = 0;
-static struct list_head compulsory_tests;
-static struct list_head normal_tests;
+static struct tlist_ccanlint tests = TLIST_INIT(tests);
bool safe_mode = false;
static struct btree *cmdline_exclude;
static struct btree *info_exclude;
return score->pass;
}
-static void register_test(struct list_head *h, struct ccanlint *test)
+static void register_test(struct ccanlint *test)
{
- list_add(h, &test->list);
+ tlist_add(&tests, test, list);
test->options = talloc_array(NULL, char *, 1);
test->options[0] = NULL;
test->skip = NULL;
/**
* get_next_test - retrieves the next test to be processed
**/
-static inline struct ccanlint *get_next_test(struct list_head *test)
+static inline struct ccanlint *get_next_test(void)
{
struct ccanlint *i;
- if (list_empty(test))
+ if (tlist_empty(&tests))
return NULL;
- list_for_each(test, i, list) {
+ tlist_for_each(&tests, i, list) {
if (i->num_depends == 0)
return i;
}
{
struct ccanlint *i;
- list_for_each(&compulsory_tests, i, list)
- if (streq(i->key, key))
- return i;
-
- list_for_each(&normal_tests, i, list)
+ tlist_for_each(&tests, i, list)
if (streq(i->key, key))
return i;
#undef REGISTER_TEST
#define REGISTER_TEST(name, ...) extern struct ccanlint name
-#include "generated-normal-tests"
-#include "generated-compulsory-tests"
+#include "generated-testlist"
static void init_tests(void)
{
struct ccanlint *c;
struct btree *keys, *names;
- struct list_head *list;
- list_head_init(&normal_tests);
- list_head_init(&compulsory_tests);
+ tlist_init(&tests);
#undef REGISTER_TEST
-#define REGISTER_TEST(name) register_test(&normal_tests, &name)
-#include "generated-normal-tests"
-#undef REGISTER_TEST
-#define REGISTER_TEST(name) register_test(&compulsory_tests, &name)
-#include "generated-compulsory-tests"
+#define REGISTER_TEST(name) register_test(&name)
+#include "generated-testlist"
/* Initialize dependency lists. */
- foreach_ptr(list, &compulsory_tests, &normal_tests) {
- list_for_each(list, c, list) {
- list_head_init(&c->dependencies);
- c->num_depends = 0;
- }
+ tlist_for_each(&tests, c, list) {
+ list_head_init(&c->dependencies);
+ c->num_depends = 0;
}
/* Resolve dependencies. */
- foreach_ptr(list, &compulsory_tests, &normal_tests) {
- list_for_each(list, c, list) {
- char **deps = strsplit(NULL, c->needs, " ");
- unsigned int i;
-
- for (i = 0; deps[i]; i++) {
- struct ccanlint *dep;
- struct dependent *dchild;
-
- dep = find_test(deps[i]);
- if (!dep)
- errx(1, "BUG: unknown dep '%s' for %s",
- deps[i], c->key);
- dchild = talloc(NULL, struct dependent);
- dchild->dependent = c;
- list_add_tail(&dep->dependencies,
- &dchild->node);
- c->num_depends++;
- }
- talloc_free(deps);
+ tlist_for_each(&tests, c, list) {
+ char **deps = strsplit(NULL, c->needs, " ");
+ unsigned int i;
+
+ for (i = 0; deps[i]; i++) {
+ struct ccanlint *dep;
+ struct dependent *dchild;
+
+ dep = find_test(deps[i]);
+ if (!dep)
+ errx(1, "BUG: unknown dep '%s' for %s",
+ deps[i], c->key);
+ dchild = talloc(NULL, struct dependent);
+ dchild->dependent = c;
+ list_add_tail(&dep->dependencies, &dchild->node);
+ c->num_depends++;
}
+ talloc_free(deps);
}
/* Self-consistency check: make sure no two tests
have the same key or name. */
keys = btree_new(btree_strcmp);
names = btree_new(btree_strcmp);
- foreach_ptr(list, &compulsory_tests, &normal_tests) {
- list_for_each(list, c, list) {
- if (!btree_insert(keys, c->key))
- errx(1, "BUG: Duplicate test key '%s'",
- c->key);
- if (!btree_insert(names, c->name))
- errx(1, "BUG: Duplicate test name '%s'",
- c->name);
- }
+ tlist_for_each(&tests, c, list) {
+ if (!btree_insert(keys, c->key))
+ errx(1, "BUG: Duplicate test key '%s'",
+ c->key);
+ if (!btree_insert(names, c->name))
+ errx(1, "BUG: Duplicate test name '%s'",
+ c->name);
}
+
btree_delete(keys);
btree_delete(names);
}
static void print_test_depends(void)
{
- struct list_head *list;
-
- foreach_ptr(list, &compulsory_tests, &normal_tests) {
- struct ccanlint *c;
- printf("\%s Tests\n",
- list == &compulsory_tests ? "Compulsory" : "Normal");
-
- list_for_each(list, c, list) {
- if (!list_empty(&c->dependencies)) {
- const struct dependent *d;
- printf("These depend on %s:\n", c->key);
- list_for_each(&c->dependencies, d, node)
- printf("\t%s\n", d->dependent->key);
- }
+ struct ccanlint *c;
+ printf("Tests:\n");
+
+ tlist_for_each(&tests, c, list) {
+ if (!list_empty(&c->dependencies)) {
+ const struct dependent *d;
+ printf("These depend on %s:\n", c->key);
+ list_for_each(&c->dependencies, d, node)
+ printf("\t%s\n", d->dependent->key);
}
}
}
init_tests();
if (streq(testname, "all")) {
- struct list_head *list;
- foreach_ptr(list, &compulsory_tests, &normal_tests) {
- list_for_each(list, i, list)
- i->keep_results = true;
- }
+ tlist_for_each(&tests, i, list)
+ i->keep_results = true;
} else {
i = find_test(testname);
if (!i)
return NULL;
}
-static void print_tests(struct list_head *tests, const char *type)
+static char *list_tests(void *arg)
{
struct ccanlint *i;
- printf("%s tests:\n", type);
+ init_tests();
+
+ printf("Tests:\n");
/* This makes them print in topological order. */
- while ((i = get_next_test(tests)) != NULL) {
+ while ((i = get_next_test()) != NULL) {
const struct dependent *d;
printf(" %-25s %s\n", i->key, i->name);
list_del(&i->list);
list_for_each(&i->dependencies, d, node)
d->dependent->num_depends--;
}
-}
-
-static char *list_tests(void *arg)
-{
- init_tests();
- print_tests(&compulsory_tests, "Compulsory");
- print_tests(&normal_tests, "Normal");
exit(0);
}
-static void test_dgraph_vertices(struct list_head *tests, const char *style)
+static void test_dgraph_vertices(const char *style)
{
const struct ccanlint *i;
- list_for_each(tests, i, list) {
+ tlist_for_each(&tests, i, list) {
/*
* todo: escape labels in case ccanlint test keys have
* characters interpreted as GraphViz syntax.
}
}
-static void test_dgraph_edges(struct list_head *tests)
+static void test_dgraph_edges(void)
{
const struct ccanlint *i;
const struct dependent *d;
- list_for_each(tests, i, list)
+ tlist_for_each(&tests, i, list)
list_for_each(&i->dependencies, d, node)
printf("\t\"%p\" -> \"%p\"\n", d->dependent, i);
}
init_tests();
puts("digraph G {");
- test_dgraph_vertices(&compulsory_tests, ", style=filled, fillcolor=yellow");
- test_dgraph_vertices(&normal_tests, "");
-
- test_dgraph_edges(&compulsory_tests);
- test_dgraph_edges(&normal_tests);
+ test_dgraph_vertices("");
+ test_dgraph_edges();
puts("}");
static void skip_unrelated_tests(struct ccanlint *target)
{
struct ccanlint *i;
- struct list_head *list;
- foreach_ptr(list, &compulsory_tests, &normal_tests)
- list_for_each(list, i, list)
- if (!depends_on(i, target))
- i->skip = "not relevant to target";
+ tlist_for_each(&tests, i, list)
+ if (!depends_on(i, target))
+ i->skip = "not relevant to target";
}
static char *demangle_string(char *string)
for (i = 1; i < argc; i++) {
unsigned int score, total_score;
+ bool added_info_options = false;
+
dir = argv[i];
if (dir[0] != '/')
if (symlink(talloc_asprintf(m, "%s/test", dir), testlink) != 0)
err(1, "Creating test symlink in %s", temp_dir(NULL));
- /* If you don't pass the compulsory tests, score is 0. */
score = total_score = 0;
- while ((t = get_next_test(&compulsory_tests)) != NULL) {
+ while ((t = get_next_test()) != NULL) {
if (!run_test(t, summary, &score, &total_score, m,
prefix)) {
- warnx("%s%s failed", prefix, t->name);
- printf("%sTotal score: 0/%u\n",
- prefix, total_score);
pass = false;
- goto next;
+ if (t->compulsory) {
+ warnx("%s%s failed", prefix, t->name);
+ printf("%sTotal score: 0/%u\n",
+ prefix, total_score);
+ goto next;
+ }
}
- }
- /* --target overrides known FAIL from _info */
- if (m->info_file)
- add_info_options(m->info_file, !target);
-
- while ((t = get_next_test(&normal_tests)) != NULL)
- pass &= run_test(t, summary, &score, &total_score, m,
- prefix);
+ /* --target overrides known FAIL from _info */
+ if (!added_info_options && m->info_file) {
+ add_info_options(m->info_file, !target);
+ added_info_options = true;
+ }
+ }
printf("%sTotal score: %u/%u\n", prefix, score, total_score);
next: ;
/* Can we run this test? Return string explaining why, if not. */
const char *(*can_run)(struct manifest *m);
+ /* Should we stop immediately if test fails? */
+ bool compulsory;
+
/* keep is set if you should keep the results.
* If timeleft is set to 0, means it timed out.
* score is the result, and a talloc context freed after all our
+++ /dev/null
-#ifndef CCANLINT_BUILD_H
-#define CCANLINT_BUILD_H
-char *build_module(struct manifest *m, bool keep, enum compile_type ctype,
- char **errstr);
-char *build_submodule(struct manifest *m, const char *flags,
- enum compile_type ctype);
-void build_objects(struct manifest *m,
- bool keep, struct score *score, const char *flags,
- enum compile_type ctype);
-#endif /* CCANLINT_BUILD_H */
+++ /dev/null
-#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 add_dep(struct manifest *m, const char *dep, struct score *score)
-{
- struct stat st;
- struct manifest *subm;
- char *dir = talloc_asprintf(m, "%s/%s", ccan_dir, dep);
-
- /* 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;
-}
-
-/* FIXME: check this is still true once we reduce features. */
-static void check_depends_exist(struct manifest *m,
- bool keep,
- unsigned int *timeleft, struct score *score)
-{
- unsigned int i;
- char **deps;
- char *updir = talloc_strdup(m, m->dir);
- bool needs_tap;
-
- if (strrchr(updir, '/'))
- *strrchr(updir, '/') = '\0';
-
- /* We may need libtap for testing, unless we're "tap" */
- if (streq(m->basename, "tap")) {
- needs_tap = false;
- } else if (list_empty(&m->run_tests) && list_empty(&m->api_tests)) {
- needs_tap = false;
- } else {
- needs_tap = true;
- }
-
- if (safe_mode)
- deps = get_safe_ccan_deps(m, m->dir, true);
- else
- deps = get_deps(m, m->dir, true,
- &m->info_file->compiled[COMPILE_NORMAL]);
-
- for (i = 0; deps[i]; i++) {
- if (!strstarts(deps[i], "ccan/"))
- continue;
-
- if (!add_dep(m, deps[i], score))
- return;
-
- if (streq(deps[i], "ccan/tap")) {
- needs_tap = false;
- }
- }
-
- if (needs_tap && !add_dep(m, "ccan/tap", score)) {
- return;
- }
-
- score->pass = true;
- score->score = score->total;
-}
-
-struct ccanlint depends_exist = {
- .key = "depends_exist",
- .name = "Module's CCAN dependencies can be found",
- .check = check_depends_exist,
- .needs = "info_exists"
-};
-
-REGISTER_TEST(depends_exist);
+++ /dev/null
-#include <tools/ccanlint/ccanlint.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 <ccan/noerr/noerr.h>
-#include <ccan/talloc/talloc.h>
-
-static void check_has_info(struct manifest *m,
- bool keep,
- unsigned int *timeleft,
- struct score *score)
-{
- if (m->info_file) {
- score->pass = true;
- score->score = score->total;
- } else {
- score->error = talloc_strdup(score,
- "You have no _info file.\n\n"
- "The file _info contains the metadata for a ccan package: things\n"
- "like the dependencies, the documentation for the package as a whole\n"
- "and license information.\n");
- }
-}
-
-static const char template[] =
- "#include <string.h>\n"
- "#include \"config.h\"\n"
- "\n"
- "/**\n"
- " * %s - YOUR-ONE-LINE-DESCRIPTION-HERE\n"
- " *\n"
- " * This code ... YOUR-BRIEF-SUMMARY-HERE\n"
- " *\n"
- " * Example:\n"
- " * FULLY-COMPILABLE-INDENTED-TRIVIAL-BUT-USEFUL-EXAMPLE-HERE\n"
- " */\n"
- "int main(int argc, char *argv[])\n"
- "{\n"
- " /* Expect exactly one argument */\n"
- " if (argc != 2)\n"
- " return 1;\n"
- "\n"
- " if (strcmp(argv[1], \"depends\") == 0) {\n"
- " PRINTF-CCAN-PACKAGES-YOU-NEED-ONE-PER-LINE-IF-ANY\n"
- " return 0;\n"
- " }\n"
- "\n"
- " return 1;\n"
- "}\n";
-
-static void create_info_template(struct manifest *m, struct score *score)
-{
- FILE *info;
- const char *filename;
-
- if (!ask("Should I create a template _info file for you?"))
- return;
-
- filename = talloc_asprintf(m, "%s/%s", m->dir, "_info");
- info = fopen(filename, "w");
- if (!info)
- err(1, "Trying to create a template _info in %s", filename);
-
- if (fprintf(info, template, m->basename) < 0) {
- unlink_noerr(filename);
- err(1, "Writing template into %s", filename);
- }
- fclose(info);
-}
-
-struct ccanlint info_exists = {
- .key = "info_exists",
- .name = "Module has _info file",
- .check = check_has_info,
- .handle = create_info_template,
- .needs = ""
-};
-
-REGISTER_TEST(info_exists);
+++ /dev/null
-#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>
-#include "build.h"
-
-static const char *can_build(struct manifest *m)
-{
- if (safe_mode)
- return "Safe mode enabled";
- return NULL;
-}
-
-static char *obj_list(const struct manifest *m, enum compile_type ctype)
-{
- char *list = talloc_strdup(m, "");
- struct ccan_file *i;
-
- /* Objects from all the C files. */
- list_for_each(&m->c_files, i, list)
- list = talloc_asprintf_append(list, "%s ",
- i->compiled[ctype]);
-
- return list;
-}
-
-char *build_module(struct manifest *m, bool keep,
- enum compile_type ctype, char **errstr)
-{
- char *name = link_objects(m, m->basename, false, obj_list(m, ctype),
- errstr);
- if (name) {
- if (keep) {
- char *realname = talloc_asprintf(m, "%s.o", m->dir);
- assert(ctype == COMPILE_NORMAL);
- /* 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 *errstr;
-
- if (list_empty(&m->c_files)) {
- /* No files? No score, but we "pass". */
- score->total = 0;
- score->pass = true;
- return;
- }
-
- m->compiled[COMPILE_NORMAL]
- = build_module(m, keep, COMPILE_NORMAL, &errstr);
- if (!m->compiled[COMPILE_NORMAL]) {
- score_file_error(score, NULL, 0, "%s", errstr);
- return;
- }
-
- score->pass = true;
- score->score = score->total;
-}
-
-struct ccanlint module_builds = {
- .key = "module_builds",
- .name = "Module can be built from object files",
- .check = do_build,
- .can_run = can_build,
- .needs = "objects_build"
-};
-
-REGISTER_TEST(module_builds);
-
+++ /dev/null
-#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>
-#include "build.h"
-
-static const char *can_build(struct manifest *m)
-{
- if (safe_mode)
- return "Safe mode enabled";
- return NULL;
-}
-
-void build_objects(struct manifest *m,
- bool keep, struct score *score, const char *flags,
- enum compile_type ctype)
-{
- struct ccan_file *i;
- bool errors = false, warnings = false;
-
- if (list_empty(&m->c_files))
- score->total = 0;
- else
- score->total = 2;
-
- list_for_each(&m->c_files, i, list) {
- char *output;
- char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
-
- i->compiled[ctype] = maybe_temp_file(m, "", keep, fullfile);
- if (!compile_object(score, fullfile, ccan_dir, compiler, flags,
- i->compiled[ctype], &output)) {
- talloc_free(i->compiled[ctype]);
- score_file_error(score, i, 0,
- "Compiling object files:\n%s",
- output);
- errors = true;
- } else if (!streq(output, "")) {
- score_file_error(score, i, 0,
- "Compiling object files gave"
- " warnings:\n%s",
- output);
- warnings = true;
- }
- }
-
- if (!errors) {
- score->pass = true;
- score->score = score->total - warnings;
- }
-}
-
-static void check_objs_build(struct manifest *m,
- bool keep,
- unsigned int *timeleft, struct score *score)
-{
- build_objects(m, keep, score, cflags, COMPILE_NORMAL);
-}
-
-struct ccanlint objects_build = {
- .key = "objects_build",
- .name = "Module object files can be built",
- .check = check_objs_build,
- .can_run = can_build,
- .needs = "depends_exist"
-};
-
-REGISTER_TEST(objects_build);
--- /dev/null
+#ifndef CCANLINT_BUILD_H
+#define CCANLINT_BUILD_H
+char *build_module(struct manifest *m, bool keep, enum compile_type ctype,
+ char **errstr);
+char *build_submodule(struct manifest *m, const char *flags,
+ enum compile_type ctype);
+void build_objects(struct manifest *m,
+ bool keep, struct score *score, const char *flags,
+ enum compile_type ctype);
+#endif /* CCANLINT_BUILD_H */
#include <err.h>
#include <string.h>
#include <ctype.h>
-#include "../compulsory_tests/build.h"
+#include "build.h"
static const char *can_build(struct manifest *m)
{
#include <string.h>
#include <ctype.h>
#include "reduce_features.h"
-#include "../compulsory_tests/build.h"
+#include "build.h"
static const char *can_build(struct manifest *m)
{
.name = "Module's CCAN dependencies can be found or built (reduced features)",
.check = check_depends_built_without_features,
.can_run = can_build,
- .needs = "depends_exist reduce_features"
+ .needs = "depends_build reduce_features"
};
REGISTER_TEST(depends_build_without_features);
--- /dev/null
+#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 add_dep(struct manifest *m, const char *dep, struct score *score)
+{
+ struct stat st;
+ struct manifest *subm;
+ char *dir = talloc_asprintf(m, "%s/%s", ccan_dir, dep);
+
+ /* 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;
+}
+
+/* FIXME: check this is still true once we reduce features. */
+static void check_depends_exist(struct manifest *m,
+ bool keep,
+ unsigned int *timeleft, struct score *score)
+{
+ unsigned int i;
+ char **deps;
+ char *updir = talloc_strdup(m, m->dir);
+ bool needs_tap;
+
+ if (strrchr(updir, '/'))
+ *strrchr(updir, '/') = '\0';
+
+ /* We may need libtap for testing, unless we're "tap" */
+ if (streq(m->basename, "tap")) {
+ needs_tap = false;
+ } else if (list_empty(&m->run_tests) && list_empty(&m->api_tests)) {
+ needs_tap = false;
+ } else {
+ needs_tap = true;
+ }
+
+ if (safe_mode)
+ deps = get_safe_ccan_deps(m, m->dir, true);
+ else
+ deps = get_deps(m, m->dir, true,
+ &m->info_file->compiled[COMPILE_NORMAL]);
+
+ for (i = 0; deps[i]; i++) {
+ if (!strstarts(deps[i], "ccan/"))
+ continue;
+
+ if (!add_dep(m, deps[i], score))
+ return;
+
+ if (streq(deps[i], "ccan/tap")) {
+ needs_tap = false;
+ }
+ }
+
+ if (needs_tap && !add_dep(m, "ccan/tap", score)) {
+ return;
+ }
+
+ score->pass = true;
+ score->score = score->total;
+}
+
+struct ccanlint depends_exist = {
+ .key = "depends_exist",
+ .name = "Module's CCAN dependencies can be found",
+ .compulsory = true,
+ .check = check_depends_exist,
+ .needs = "info_exists"
+};
+
+REGISTER_TEST(depends_exist);
#include <ctype.h>
#include <assert.h>
#include <err.h>
-#include "../compulsory_tests/build.h"
+#include "build.h"
static const char *can_run(struct manifest *m)
{
.key = "hash_if",
.name = "Features are checked with #if not #ifdef",
.check = check_hash_if,
- .needs = ""
+ .needs = "info_exists"
};
REGISTER_TEST(hash_if);
.name = "Module headers are #ifndef/#define wrapped",
.check = check_idempotent,
.handle = handle_idem,
- .needs = ""
+ .needs = "info_exists main_header_exists"
};
REGISTER_TEST(headers_idempotent);
--- /dev/null
+#include <tools/ccanlint/ccanlint.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 <ccan/noerr/noerr.h>
+#include <ccan/talloc/talloc.h>
+
+static void check_has_info(struct manifest *m,
+ bool keep,
+ unsigned int *timeleft,
+ struct score *score)
+{
+ if (m->info_file) {
+ score->pass = true;
+ score->score = score->total;
+ } else {
+ score->error = talloc_strdup(score,
+ "You have no _info file.\n\n"
+ "The file _info contains the metadata for a ccan package: things\n"
+ "like the dependencies, the documentation for the package as a whole\n"
+ "and license information.\n");
+ }
+}
+
+static const char template[] =
+ "#include <string.h>\n"
+ "#include \"config.h\"\n"
+ "\n"
+ "/**\n"
+ " * %s - YOUR-ONE-LINE-DESCRIPTION-HERE\n"
+ " *\n"
+ " * This code ... YOUR-BRIEF-SUMMARY-HERE\n"
+ " *\n"
+ " * Example:\n"
+ " * FULLY-COMPILABLE-INDENTED-TRIVIAL-BUT-USEFUL-EXAMPLE-HERE\n"
+ " */\n"
+ "int main(int argc, char *argv[])\n"
+ "{\n"
+ " /* Expect exactly one argument */\n"
+ " if (argc != 2)\n"
+ " return 1;\n"
+ "\n"
+ " if (strcmp(argv[1], \"depends\") == 0) {\n"
+ " PRINTF-CCAN-PACKAGES-YOU-NEED-ONE-PER-LINE-IF-ANY\n"
+ " return 0;\n"
+ " }\n"
+ "\n"
+ " return 1;\n"
+ "}\n";
+
+static void create_info_template(struct manifest *m, struct score *score)
+{
+ FILE *info;
+ const char *filename;
+
+ if (!ask("Should I create a template _info file for you?"))
+ return;
+
+ filename = talloc_asprintf(m, "%s/%s", m->dir, "_info");
+ info = fopen(filename, "w");
+ if (!info)
+ err(1, "Trying to create a template _info in %s", filename);
+
+ if (fprintf(info, template, m->basename) < 0) {
+ unlink_noerr(filename);
+ err(1, "Writing template into %s", filename);
+ }
+ fclose(info);
+}
+
+struct ccanlint info_exists = {
+ .key = "info_exists",
+ .name = "Module has _info file",
+ .compulsory = true,
+ .check = check_has_info,
+ .handle = create_info_template,
+ .needs = ""
+};
+
+REGISTER_TEST(info_exists);
--- /dev/null
+#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>
+#include "build.h"
+
+static const char *can_build(struct manifest *m)
+{
+ if (safe_mode)
+ return "Safe mode enabled";
+ return NULL;
+}
+
+static char *obj_list(const struct manifest *m, enum compile_type ctype)
+{
+ char *list = talloc_strdup(m, "");
+ struct ccan_file *i;
+
+ /* Objects from all the C files. */
+ list_for_each(&m->c_files, i, list)
+ list = talloc_asprintf_append(list, "%s ",
+ i->compiled[ctype]);
+
+ return list;
+}
+
+char *build_module(struct manifest *m, bool keep,
+ enum compile_type ctype, char **errstr)
+{
+ char *name = link_objects(m, m->basename, false, obj_list(m, ctype),
+ errstr);
+ if (name) {
+ if (keep) {
+ char *realname = talloc_asprintf(m, "%s.o", m->dir);
+ assert(ctype == COMPILE_NORMAL);
+ /* 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 *errstr;
+
+ if (list_empty(&m->c_files)) {
+ /* No files? No score, but we "pass". */
+ score->total = 0;
+ score->pass = true;
+ return;
+ }
+
+ m->compiled[COMPILE_NORMAL]
+ = build_module(m, keep, COMPILE_NORMAL, &errstr);
+ if (!m->compiled[COMPILE_NORMAL]) {
+ score_file_error(score, NULL, 0, "%s", errstr);
+ return;
+ }
+
+ score->pass = true;
+ score->score = score->total;
+}
+
+struct ccanlint module_builds = {
+ .key = "module_builds",
+ .name = "Module can be built from object files",
+ .compulsory = true,
+ .check = do_build,
+ .can_run = can_build,
+ .needs = "objects_build"
+};
+
+REGISTER_TEST(module_builds);
.key = "no_trailing_whitespace",
.name = "Module's source code has no trailing whitespace",
.check = check_trailing_whitespace,
- .needs = ""
+ .needs = "info_exists"
};
--- /dev/null
+#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>
+#include "build.h"
+
+static const char *can_build(struct manifest *m)
+{
+ if (safe_mode)
+ return "Safe mode enabled";
+ return NULL;
+}
+
+void build_objects(struct manifest *m,
+ bool keep, struct score *score, const char *flags,
+ enum compile_type ctype)
+{
+ struct ccan_file *i;
+ bool errors = false, warnings = false;
+
+ if (list_empty(&m->c_files))
+ score->total = 0;
+ else
+ score->total = 2;
+
+ list_for_each(&m->c_files, i, list) {
+ char *output;
+ char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
+
+ i->compiled[ctype] = maybe_temp_file(m, "", keep, fullfile);
+ if (!compile_object(score, fullfile, ccan_dir, compiler, flags,
+ i->compiled[ctype], &output)) {
+ talloc_free(i->compiled[ctype]);
+ score_file_error(score, i, 0,
+ "Compiling object files:\n%s",
+ output);
+ errors = true;
+ } else if (!streq(output, "")) {
+ score_file_error(score, i, 0,
+ "Compiling object files gave"
+ " warnings:\n%s",
+ output);
+ warnings = true;
+ }
+ }
+
+ if (!errors) {
+ score->pass = true;
+ score->score = score->total - warnings;
+ }
+}
+
+static void check_objs_build(struct manifest *m,
+ bool keep,
+ unsigned int *timeleft, struct score *score)
+{
+ build_objects(m, keep, score, cflags, COMPILE_NORMAL);
+}
+
+struct ccanlint objects_build = {
+ .key = "objects_build",
+ .name = "Module object files can be built",
+ .compulsory = true,
+ .check = check_objs_build,
+ .can_run = can_build,
+ .needs = "depends_exist"
+};
+
+REGISTER_TEST(objects_build);
#include <tools/ccanlint/ccanlint.h>
#include <ccan/talloc/talloc.h>
#include "reduce_features.h"
-#include "../compulsory_tests/build.h"
+#include "build.h"
static void check_objs_build_without_features(struct manifest *m,
bool keep,
.name = "Module tests compile (without features)",
.check = do_compile_tests_without_features,
.can_run = features_reduced,
- .needs = "tests_helpers_compile_without_features objects_build_without_features"
+ .needs = "module_builds tests_helpers_compile_without_features objects_build_without_features"
};
REGISTER_TEST(tests_compile_without_features);
#include <err.h>
#include <string.h>
#include <ctype.h>
-#include "../compulsory_tests/build.h"
+#include "build.h"
#include "tests_compile.h"
/* Note: we already test safe_mode in run_tests.c */
.key = "tests_exist",
.name = "Module has test directory with tests in it",
.check = check_tests_exist,
- .needs = ""
+ .needs = "info_exists"
};