Commit 10e5e329 authored by Rusty Russell's avatar Rusty Russell

tools: don't assume modules are immediately below ccan/ dir.

Removing this assumption should allow nested modules.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent a64257be
......@@ -11,6 +11,7 @@ DEP_OBJS = ccan/err/err.o \
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>
......@@ -22,10 +23,19 @@ static unsigned int ccan_dir_prefix(const char *fulldir)
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;
}
......@@ -208,7 +208,7 @@ struct doc_section *find_license_tag(const struct manifest *m)
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;
......
......@@ -85,7 +85,7 @@ static void check_headers_no_cpp(struct manifest *m,
"#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);
......
......@@ -22,7 +22,7 @@ static bool has_dep(struct manifest *m, char **deps, bool *used,
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++) {
......@@ -48,7 +48,7 @@ static bool check_dep_includes(struct manifest *m,
char *mod;
if (!strreg(f, lines[i],
"^[ \t]*#[ \t]*include[ \t]*[<\"]"
"(ccan/+[^/]+)/", &mod))
"(ccan/+.+)/+[^/]+.h", &mod))
continue;
if (has_dep(m, deps, used, mod))
......
......@@ -47,7 +47,7 @@ static char *build_subdir_objs(struct manifest *m,
return talloc_asprintf(m,
"Dependency %s"
" did not build:\n%s",
m->basename, output);
m->modname, output);
}
}
return NULL;
......@@ -94,7 +94,7 @@ static void check_depends_built(struct manifest *m,
"Dependency %s"
" did not"
" build:\n%s",
i->basename,
i->modname,
errstr);
return;
}
......
......@@ -45,7 +45,7 @@ static void check_depends_built_without_features(struct manifest *m,
"Dependency %s"
" did not"
" build:\n%s",
i->basename,
i->modname,
errstr);
return;
}
......
......@@ -19,7 +19,7 @@ static bool have_dep(struct manifest *m, const char *dep)
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;
......@@ -80,7 +80,7 @@ static void check_test_depends_exist(struct manifest *m,
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;
......
......@@ -30,27 +30,27 @@ static void add_mod(struct manifest ***deps, struct manifest *m)
(*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);
......@@ -79,7 +79,7 @@ static struct manifest **get_example_deps(struct manifest *m,
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++) {
......@@ -362,7 +362,7 @@ static char *mangle(struct manifest *m, char **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"
......
......@@ -46,10 +46,10 @@ static void handle_idem(struct manifest *m, struct score *score)
/* 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,
......
......@@ -47,7 +47,7 @@ static void create_info_template_doc(struct manifest *m, struct score *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");
}
......@@ -83,7 +83,7 @@ static void check_info_documentation_exists(struct manifest *m,
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;
......
......@@ -68,7 +68,7 @@ static void create_info_template(struct manifest *m, struct score *score)
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);
}
......
......@@ -36,7 +36,7 @@ static void check_license_depends_compat(struct manifest *m,
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;
}
......
......@@ -11,48 +11,72 @@
#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)?",
......@@ -73,6 +97,7 @@ static void check_has_license(struct manifest *m,
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) {
......@@ -93,7 +118,7 @@ static void check_has_license(struct manifest *m,
/* 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) {
......@@ -129,11 +154,10 @@ static void check_has_license(struct manifest *m,
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;
}
......
......@@ -51,7 +51,7 @@ static void check_includes_build(struct manifest *m,
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);
......
......@@ -29,7 +29,7 @@ static void check_has_main_header(struct manifest *m,
"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 = {
......
......@@ -58,10 +58,9 @@ static void check_use_build(struct manifest *m,
{
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)
......@@ -73,7 +72,7 @@ static void check_use_build(struct manifest *m,
"{\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);
......
......@@ -112,7 +112,7 @@ static void build_objects_with_stringchecks(struct manifest *m,
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);
......
......@@ -69,12 +69,12 @@ static void handle_no_tests(struct manifest *m, struct score *score)
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"
......
......@@ -40,7 +40,7 @@ lines_from_cmd(const void *ctx, const char *format, ...)
* 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;
......@@ -59,12 +59,8 @@ char *compile_info(const void *ctx, const char *dir)
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;
......@@ -209,8 +205,7 @@ get_all_deps(const void *ctx, const char *dir, const char *style,
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. */
......@@ -285,8 +280,7 @@ char **get_libs(const void *ctx, const char *dir, const char *style,
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);
......
......@@ -71,7 +71,8 @@ static unsigned int is_summary_line(const char *line)
{
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)
......
......@@ -239,6 +239,7 @@ struct manifest *get_manifest(const void *ctx, const char *dir)
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';
......@@ -248,6 +249,9 @@ struct manifest *get_manifest(const void *ctx, const char *dir)
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. */
......
......@@ -13,7 +13,9 @@ enum compile_type {
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment