Removing this assumption should allow nested modules.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/talloc/talloc.o \
ccan/time/time.o \
tools/read_config_header.o \
+ tools/ccan_dir.o \
tools/compile.o \
tools/depends.o \
tools/tools.o
#include <ccan/talloc/talloc.h>
+#include <ccan/err/err.h>
#include "tools.h"
#include <assert.h>
#include <string.h>
const char *find_ccan_dir(const char *base)
{
- unsigned int prefix = ccan_dir_prefix(base);
+ static char *ccan_dir;
- if (!prefix)
- return NULL;
-
- return talloc_strndup(NULL, base, prefix);
+ if (!ccan_dir) {
+ if (base[0] != '/') {
+ const char *tmpctx = talloc_getcwd(NULL);
+ find_ccan_dir(talloc_asprintf(tmpctx, "%s/%s",
+ tmpctx, base));
+ talloc_free(tmpctx);
+ } else {
+ unsigned int prefix = ccan_dir_prefix(base);
+ if (prefix)
+ ccan_dir = talloc_strndup(NULL, base, prefix);
+ }
+ }
+ return ccan_dir;
}
struct doc_section *d;
list_for_each(get_ccan_file_docs(m->info_file), d, list) {
- if (!streq(d->function, m->basename))
+ if (!streq(d->function, m->modname))
continue;
if (streq(d->type, "license"))
return d;
"#define using #DONT_USE_CPLUSPLUS_RESERVED_NAMES\n"
"#define virtual #DONT_USE_CPLUSPLUS_RESERVED_NAMES\n"
"#include <ccan/%s/%s.h>\n",
- m->basename, m->basename);
+ m->modname, m->basename);
if (write(fd, contents, strlen(contents)) != strlen(contents))
err(1, "writing to temporary file %s", tmpsrc);
close(fd);
unsigned int i;
/* We can include ourselves, of course. */
- if (streq(depname + strlen("ccan/"), m->basename))
+ if (streq(depname + strlen("ccan/"), m->modname))
return true;
for (i = 0; deps[i]; i++) {
char *mod;
if (!strreg(f, lines[i],
"^[ \t]*#[ \t]*include[ \t]*[<\"]"
- "(ccan/+[^/]+)/", &mod))
+ "(ccan/+.+)/+[^/]+.h", &mod))
continue;
if (has_dep(m, deps, used, mod))
return talloc_asprintf(m,
"Dependency %s"
" did not build:\n%s",
- m->basename, output);
+ m->modname, output);
}
}
return NULL;
"Dependency %s"
" did not"
" build:\n%s",
- i->basename,
+ i->modname,
errstr);
return;
}
"Dependency %s"
" did not"
" build:\n%s",
- i->basename,
+ i->modname,
errstr);
return;
}
struct manifest *i;
list_for_each(&m->deps, i, list)
- if (streq(i->basename, dep + strlen("ccan/")))
+ if (streq(i->modname, dep + strlen("ccan/")))
return true;
return false;
bool needs_tap;
/* We may need libtap for testing, unless we're "tap" */
- if (streq(m->basename, "tap")) {
+ if (streq(m->modname, "tap")) {
needs_tap = false;
} else if (list_empty(&m->run_tests) && list_empty(&m->api_tests)) {
needs_tap = false;
(*deps)[num] = m;
}
-static bool have_mod(struct manifest *deps[], const char *basename)
+static bool have_mod(struct manifest *deps[], const char *modname)
{
unsigned int i;
for (i = 0; i < talloc_get_size(deps) / sizeof(*deps); i++)
- if (strcmp(deps[i]->basename, basename) == 0)
+ if (strcmp(deps[i]->modname, modname) == 0)
return true;
return false;
}
-static void add_dep(struct manifest ***deps, const char *basename)
+static void add_dep(struct manifest ***deps, const char *modname)
{
unsigned int i;
struct manifest *m;
char *errstr;
- if (have_mod(*deps, basename))
+ if (have_mod(*deps, modname))
return;
m = get_manifest(*deps, talloc_asprintf(*deps, "%s/ccan/%s",
- ccan_dir, basename));
+ ccan_dir, modname));
errstr = build_submodule(m, cflags, COMPILE_NORMAL);
if (errstr)
errx(1, "%s", errstr);
struct manifest **deps = talloc_array(f, struct manifest *, 0);
/* This one for a start. */
- add_dep(&deps, m->basename);
+ add_dep(&deps, m->modname);
/* Other modules implied by includes. */
for (lines = get_ccan_file_lines(f); *lines; lines++) {
"#include <sys/stat.h>\n"
"#include <sys/types.h>\n"
"#include <unistd.h>\n",
- m->basename, m->basename);
+ m->modname, m->basename);
ret = talloc_asprintf_append(ret, "/* Useful dummy functions. */\n"
"extern int somefunc(void);\n"
/* Main header gets CCAN_FOO_H, others CCAN_FOO_XXX_H */
if (strstarts(e->file->name, m->basename)
|| strlen(e->file->name) == strlen(m->basename) + 2)
- name = talloc_asprintf(score, "CCAN_%s_H", m->basename);
+ name = talloc_asprintf(score, "CCAN_%s_H", m->modname);
else
name = talloc_asprintf(score, "CCAN_%s_%s",
- m->basename, e->file->name);
+ m->modname, e->file->name);
fix_name(name);
q = talloc_asprintf(score,
" *\n"
" * Followed by an Example: section with a standalone\n"
" * (trivial and usually useless) program\n"
- " */\n", m->basename, m->basename) < 0) {
+ " */\n", m->modname, m->basename) < 0) {
unlink_noerr("_info.new");
err(1, "Writing to _info.new to insert documentation");
}
score->pass = true;
list_for_each(infodocs, d, list) {
- if (!streq(d->function, m->basename))
+ if (!streq(d->function, m->modname))
continue;
if (streq(d->type, "summary"))
summary = true;
if (!info)
err(1, "Trying to create a template _info in %s", filename);
- if (fprintf(info, template, m->basename) < 0) {
+ if (fprintf(info, template, m->modname) < 0) {
unlink_noerr(filename);
err(1, "Writing template into %s", filename);
}
score_file_error(score, i->info_file, 0,
"Dependency ccan/%s has"
" incompatible license '%s'",
- i->basename,
+ i->modname,
licenses[i->license].name);
score->pass = false;
}
#include <ccan/talloc/talloc.h>
#include <ccan/str/str.h>
-static const char *expected_link(enum license license)
+/* We might need more ../ for nested modules. */
+static const char *link_prefix(struct manifest *m)
{
+ char *prefix = talloc_strdup(m, "../../");
+ unsigned int i;
+
+ for (i = 0; i < strcount(m->modname, "/"); i++)
+ prefix = talloc_append_string(prefix, "../");
+
+ return talloc_append_string(prefix, "licenses/");
+}
+
+static const char *expected_link(const char *prefix, enum license license)
+{
+ const char *shortname;
+
switch (license) {
case LICENSE_LGPLv2_PLUS:
case LICENSE_LGPLv2:
- return "../../licenses/LGPL-2.1";
+ shortname = "LGPL-2.1";
+ break;
case LICENSE_LGPLv3:
case LICENSE_LGPL:
- return "../../licenses/LGPL-3";
+ shortname = "LGPL-3";
+ break;
case LICENSE_GPLv2_PLUS:
case LICENSE_GPLv2:
- return "../../licenses/GPL-2";
+ shortname = "GPL-2";
+ break;
case LICENSE_GPLv3:
case LICENSE_GPL:
- return "../../licenses/GPL-3";
+ shortname = "GPL-3";
+ break;
case LICENSE_BSD:
- return "../../licenses/BSD-3CLAUSE";
+ shortname = "BSD-3CLAUSE";
+ break;
case LICENSE_MIT:
- return "../../licenses/BSD-MIT";
+ shortname = "BSD-MIT";
+ break;
case LICENSE_CC0:
- return "../../licenses/CC0";
+ shortname = "CC0";
+ break;
default:
return NULL;
}
+
+ return talloc_append_string(talloc_strdup(prefix, prefix), shortname);
}
static void handle_license_link(struct manifest *m, struct score *score)
{
struct doc_section *d = find_license_tag(m);
+ const char *prefix = link_prefix(m);
const char *link = talloc_asprintf(m, "%s/LICENSE", m->dir);
- const char *ldest = expected_link(m->license);
+ const char *ldest = expected_link(prefix, m->license);
char *q;
printf(
"Most modules want a copy of their license, so usually we create a\n"
- "LICENSE symlink into ../../licenses to avoid too many copies.\n");
+ "LICENSE symlink into %s to avoid too many copies.\n", prefix);
/* FIXME: make ask printf-like */
q = talloc_asprintf(m, "Set up link to %s (license is %s)?",
char *license = talloc_asprintf(m, "%s/LICENSE", m->dir);
const char *expected;
struct doc_section *d;
+ const char *prefix = link_prefix(m);
d = find_license_tag(m);
if (!d) {
/* If they have a license tag at all, we pass. */
score->pass = true;
- expected = expected_link(m->license);
+ expected = expected_link(prefix, m->license);
len = readlink(license, buf, sizeof(buf));
if (len < 0) {
buf[len] = '\0';
- if (!strstarts(buf, "../../licenses/")) {
+ if (!strstarts(buf, prefix)) {
score->error = talloc_asprintf(score,
- "Expected symlink to"
- " ../../licenses/..."
- " not %s", buf);
+ "Expected symlink into"
+ " %s not %s", prefix, buf);
return;
}
err(1, "Creating temporary file %s", tmpsrc);
contents = talloc_asprintf(tmpsrc, "#include <ccan/%s/%s.h>\n",
- m->basename, m->basename);
+ m->modname, m->basename);
if (write(fd, contents, strlen(contents)) != strlen(contents))
err(1, "writing to temporary file %s", tmpsrc);
close(fd);
"You have no %s/%s.h header file.\n\n"
"CCAN modules have a name, the same as the directory name. They're\n"
"expected to have an interface in the header of the same name.\n",
- m->basename, m->basename);
+ m->modname, m->basename);
}
struct ccanlint main_header_exists = {
{
char *contents;
char *tmpfile, *cmdout;
- char *basename = talloc_asprintf(m, "%s/example.c", m->dir);
int fd;
- tmpfile = temp_file(m, ".c", basename);
+ tmpfile = temp_file(m, ".c", "example.c");
fd = open(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0)
"{\n"
" return 0;\n"
"}\n",
- m->basename, m->basename);
+ m->modname, m->basename);
if (write(fd, contents, strlen(contents)) != strlen(contents))
err(1, "Failure writing to temporary file %s", tmpfile);
close(fd);
tmp = temp_file(score, ".c", i->fullname);
tmpfd = start_file(tmp);
line = talloc_asprintf(score, "#include <ccan/%s/%s.h>\n",
- m->basename, m->basename);
+ m->modname, m->basename);
write_str(tmpfd, line);
close(tmpfd);
test_compile(score, i, tmp, flags, &errors, &warnings);
if (!run)
err(1, "Trying to create a test/run.c");
- fprintf(run, "#include <ccan/%s/%s.h>\n", m->basename, m->basename);
+ fprintf(run, "#include <ccan/%s/%s.h>\n", m->modname, m->basename);
if (!list_empty(&m->c_files)) {
fputs("/* Include the C files directly. */\n", run);
list_for_each(&m->c_files, i, list)
fprintf(run, "#include <ccan/%s/%s>\n",
- m->basename, i->name);
+ m->modname, i->name);
}
fprintf(run, "%s",
"#include <ccan/tap/tap.h>\n\n"
* temp_file helps here. */
char *compile_info(const void *ctx, const char *dir)
{
- char *info_c_file, *info, *ccandir, *compiled, *output;
+ char *info_c_file, *info, *compiled, *output;
size_t len;
int fd;
if (close(fd) != 0)
return NULL;
- ccandir = talloc_dirname(ctx, dir);
- if (strrchr(ccandir, '/'))
- *strrchr(ccandir, '/') = '\0';
-
compiled = temp_file(ctx, "", "info");
- if (compile_and_link(ctx, info_c_file, ccandir, "",
+ if (compile_and_link(ctx, info_c_file, find_ccan_dir(dir), "",
CCAN_COMPILER, CCAN_CFLAGS " -I.", "",
compiled, &output))
return compiled;
continue;
subdir = talloc_asprintf(ctx, "%s/%s",
- talloc_dirname(ctx, dir),
- deps[i] + strlen("ccan/"));
+ find_ccan_dir(dir), deps[i]);
newdeps = get_one(ctx, subdir, "depends", get_info);
/* Should be short, so brute-force out dups. */
continue;
subdir = talloc_asprintf(ctx, "%s/%s",
- talloc_dirname(ctx, dir),
- deps[i] + strlen("ccan/"));
+ find_ccan_dir(dir), deps[i]);
newlibs = get_one_libs(ctx, subdir, get_info);
newlen = talloc_array_length(newlibs);
{
unsigned int id_len;
- id_len = strspn(line, IDENT_CHARS" ");
+ /* We allow /, because it can be in (nested) module names. */
+ id_len = strspn(line, IDENT_CHARS" /");
if (id_len == 0)
return 0;
if (strspn(line, " ") == id_len)
list_head_init(&m->deps);
list_head_init(&m->test_deps);
+ /* Trim trailing /. */
len = strlen(m->dir);
while (len && m->dir[len-1] == '/')
m->dir[--len] = '\0';
errx(1, "I don't expect to be run from the root directory");
m->basename++;
+ assert(strstarts(m->dir, find_ccan_dir(m->dir)));
+ m->modname = m->dir + strlen(find_ccan_dir(m->dir)) + strlen("ccan/");
+
add_files(m, "");
/* Nicer to run tests in a predictable order. */
struct manifest {
char *dir;
- /* The module name, ie. final element of dir name */
+ /* The name of the module, ie. elements of dir name after ccan/. */
+ char *modname;
+ /* The final element of dir name */
char *basename;
struct ccan_file *info_file;