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"
 };