aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile19
-rwxr-xr-xbootstrap.sh2
-rw-r--r--tool/depgen.c153
4 files changed, 170 insertions, 5 deletions
diff --git a/.gitignore b/.gitignore
index 3b34cc8..fea4c6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ compile_commands.json
.gdb_history
*.o
a.out
+tool/depgen
diff --git a/Makefile b/Makefile
index 656cfab..c377d62 100644
--- a/Makefile
+++ b/Makefile
@@ -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: */