diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 19 | ||||
| -rwxr-xr-x | bootstrap.sh | 2 | ||||
| -rw-r--r-- | tool/depgen.c | 153 |
4 files changed, 170 insertions, 5 deletions
@@ -12,3 +12,4 @@ compile_commands.json .gdb_history *.o a.out +tool/depgen @@ -16,6 +16,14 @@ BINDIR=$(PREFIX)/bin -include config.mk +HOSTCC ?= $(CC) + +ifdef V + V= +else + V=@ +endif + all: CFLAGS += -g -Og all: $(OUT) @@ -26,19 +34,22 @@ dbg: CFLAGS += -g -fsanitize=address,undefined dbg: CC:=clang dbg: $(OUT) -$(OUT): $(OBJ) +tool/depgen: tool/depgen.c + $(CC) -Wall -g -o $@ $< + +$(OUT): tool/depgen $(OBJ) $(CC) $(CFLAGS) -o $@ $(OBJ) hostconfig.h: ./configure $(BUILDDIR)/%.o: %.c hostconfig.h - @mkdir -p `dirname $@` - @cc $(CFLAGS) -w -MMD -MP -fsyntax-only -MF $(BUILDDIR)/$*.d -MT $@ $< #depfiles + $Vmkdir -p `dirname $@` + $Vtool/depgen -MP -MF $(BUILDDIR)/$*.d -MT $@ $< $(CC) $(CFLAGS) -c -o $@ $< clean: - $(RM) -r -- $(BUILDDIR)/ test/build/ $(OUT) *.o a.out + $(RM) -r -- $(BUILDDIR)/ test/build/ $(OUT) *.o a.out tool/depgen clean-config: clean $(RM) -r config.mk hostconfig.h diff --git a/bootstrap.sh b/bootstrap.sh index b2f3fa9..8a2cd64 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -12,7 +12,7 @@ test -n "$cflags" || : ${cflags:="-std=c11"} if test -n "$V"; then opt="$opt -v" fi -src=$(grep -o '\([_A-Za-z0-9/]\)\+\.c' < Makefile) +src=$(head -n 15 Makefile | grep -o '\([_A-Za-z0-9/]\)\+\.c') X() { echo "> $@" | (test -n "$V" && cat || sed -s 's/\([^ ]\+\.c \?\)\{10\}$/.../') $@ diff --git a/tool/depgen.c b/tool/depgen.c new file mode 100644 index 0000000..0291859 --- /dev/null +++ b/tool/depgen.c @@ -0,0 +1,153 @@ +#define USAGE "depgen [-MP | -MT target | -MF output] <file>" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static char * +alloc1(size_t n) +{ + static char mem[64*1<<10], *pmem = mem; + assert(mem+sizeof mem - pmem >= n && "oom"); + pmem += n; + return pmem - n; +} + +static char * +sdup(const char *s, size_t n) +{ + return memcpy(alloc1(n+1), s, n); +} + +static char * +catpath(const char *s1, const char *s2) +{ + if (!s1) return strcpy(alloc1(strlen(s2)+1), s2); + size_t n1 = strlen(s1), n2 = strlen(s2), n; + char *x = alloc1(n = n1+1+n2+1); + memcpy(x, s1, n1); + x[n1] = '/'; + memcpy(x+n1+1, s2, n2); + x[n1+n2+1] = 0; + for (char *p = x+1; *p; ++p) { + if (!memcmp(p, "/../", 4)) { + char *next = p+4, *q; + for (q = p - 1; q > x && *q != '/'; --q); + if (q == x) x = p = next; + else { + memmove(q+1, next, strlen(next)+1); + p = q-1; + } + } + } + return x; +} + +static const char * +fileext(const char *path) +{ + assert(path && *path && "empty"); + const char *dot = NULL; + for (++path; *path; ++path) { + if (*path == '.') dot = path; + } + return dot ? dot+1 : ""; +} + +static const char * +withext(const char *path, const char *ext) +{ + const char *oext, *file = path; + assert(*file && "no filename"); + oext = fileext(file); + size_t len; + if (!*oext) + len = strlen(file); + else + len = oext - file - 1; + char *res = memcpy(alloc1(len + 1 + (ext ? strlen(ext) + 1 : 0)), file, len); + if (ext) { + res[len] = '.'; + memcpy(res + len + 1, ext, strlen(ext)); + } + return res; +} + +static char * +dirname(const char *path) +{ + const char *end = path + strlen(path); + while (end > path && *end != '/') --end; + return end == path ? NULL : sdup(path, end - path); +} + +static FILE *out; + +enum { MAXFILES = 200, MAXLINE = 2048 }; +static const char *files[MAXFILES]; +static int nfiles; +static int +dofile(const char *f) +{ + int ret = 0; + assert(nfiles < MAXFILES); + files[nfiles++] = f; + FILE *fp = fopen(f, "r"); + if (!fp) { + perror(f); + return 1; + } + char line[MAXLINE], hdr[MAXLINE]; + while (fgets(line, sizeof line, fp)) { + if (sscanf(line, " # include \"%[^\"]\"", hdr) == 1) { + const char *abspath = catpath(dirname(f), hdr); + for (int i = 0; files[i] && i < MAXFILES; ++i) { + if (!strcmp(files[i], abspath)) goto Skip; + } + fprintf(out, " %s", abspath); + ret |= dofile(abspath); + } + Skip:; + } + if (ferror(fp)) perror(f); + fclose(fp); + return ret; +} + +int +main(int argc, char **argv) +{ +#define DIE(...) return fprintf(stderr, "? "__VA_ARGS__), fputc('\n', stderr), 1 + const char *src = NULL, *targ = NULL, *mf = NULL; + int mp = 0; + for (int i = 1; i < argc; ++i) { + if (*argv[i] != '-') { + if (src) DIE("too many input files"); + else src = argv[i]; + } else if (!strcmp(argv[i], "-MT")) { + if (!(targ = argv[++i])) DIE("-MT missing arg"); + } else if (!strcmp(argv[i], "-MF")) { + if (mf) DIE("too many output files\n"); + if (!(mf = argv[++i])) DIE("-MF missing arg"); + } else if (!strcmp(argv[i], "-MP")) { + mp = 1; + } else { + DIE("invalid arg '%s'", argv[i]); + } + } + if (!src) return fprintf(stderr, "Usage: "USAGE"\n"), 1; + if (mf && !(out = fopen(mf, "w"))) return perror(mf), 1; + else if (!out) out = stdout; + fprintf(out, "%s: %s", targ ? targ : withext(src, "o"), src); + int ret = dofile(src); + if (mp) for (int i = 1; files[i]; ++i) { + fprintf(out, "\n%s:", files[i]); + } + fputc('\n', out); + if (ferror(out)) ret += 4; + fclose(out); + return ret; +} + +/* vim:set ts=3 sw=3 expandtab: */ |