]> git.neil.brown.name Git - history.git/commitdiff
kbuild: Make dependencies at compile time
authorKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
Wed, 5 Jun 2002 07:31:30 +0000 (02:31 -0500)
committerKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
Wed, 5 Jun 2002 07:31:30 +0000 (02:31 -0500)
Making dependencies once up front is not ideal. For one, you don't need
them initially, since when you don't have the .o file, you bet you have
to build it no matter what the dependencies say - dependencies are about
deciding when to *re*build.

There's more reasons, like:
o you don't even know which files you'll build, so you have to go over
  all files (even over drivers/{sbus,s390,...} on i386)
o generated files don't exist yet, so you cannot pick up dependencies
  on them
o even if dependencies are right initially, they change when you work on
  your tree or patch it, and nobody will notice unless you run "make dep"
  explicitly again

Anyway, gcc knows hows to emit a correct dependency list, so we just use
that. Well, a little bit of hacking is necessary to remove the dependency
on autoconf.h and put in individual CONFIG_WHAT_EVER dependencies instead,
since otherwise changing one config option would cause everything to be
rebuilt.

I should add that I didn't come up with this all by myself, most work
is actually done in gcc and there were discussions about using -MD on
kbuild-devel way back, so I should mention Keith Owens and Michael
Elizabeth Chastain, and probably others that I forgot, so I apologize
just in case.

Makefile
Rules.make
scripts/Makefile
scripts/fixdep.c [new file with mode: 0644]
scripts/mkdep.c [deleted file]

index bbe5a0758ceb1ee274d24889732a7bd7ddb2c425..a0f626123002859a01393b2d21364c615f177d64 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -300,39 +300,41 @@ include/linux/version.h: Makefile
 # Helpers built in scripts/
 # ---------------------------------------------------------------------------
 
-scripts/mkdep scripts/split-include : scripts ;
+scripts/fixdep scripts/split-include : scripts ;
 
 .PHONY: scripts
 scripts:
        @$(MAKE) -C scripts
 
-# Generate dependencies
+# Generate module versions
 # ---------------------------------------------------------------------------
 
-#      In the same pass, generate module versions, that's why it's
-#      all mixed up here.
+#      The targets are still named depend / dep for traditional
+#      reasons, but the only thing we do here is generating
+#      the module version checksums.
+#      FIXME: For now, we are also calling "archdep" from here,
+#      which should be replaced by a more sensible solution.
 
 .PHONY: depend dep $(patsubst %,_sfdep_%,$(SUBDIRS))
 
 depend dep: .hdepend
 
-#      .hdepend is missing prerequisites - in fact dependencies need
-#      to be redone basically each time anything changed - since
-#      that's too expensive, we traditionally rely on the user to
-#      run "make dep" manually whenever necessary. In this case,
-#      we make "FORCE" a prequisite, to force redoing the
-#      dependencies. Yeah, that's ugly, and it'll go away soon.
+ifdef CONFIG_MODVERSIONS
+
+#      Before descending for the actual build, we need module
+#      versions done. - Still using the old, illogical name
+#      .hdepend
 
-quiet_cmd_depend = Making dependencies (include)
-cmd_depend       = scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > $@
+#      .hdepend only indicates if we have generated module
+#      version checksums before now. For now, if they've
+#      been generated once, no rechecking will be done unless
+#      explicitly asked for using "make dep".
 
-.hdepend: scripts/mkdep include/linux/version.h include/asm \
+.hdepend: scripts/fixdep include/linux/version.h include/asm \
          $(if $(filter dep depend,$(MAKECMDGOALS)),FORCE)
-       $(call cmd,cmd_depend)
+       touch $@
        @$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS))
-ifdef CONFIG_MODVERSIONS
        @$(MAKE) include/linux/modversions.h
-endif
        @$(MAKE) archdep
 
 $(patsubst %,_sfdep_%,$(SUBDIRS)): FORCE
@@ -358,6 +360,15 @@ include/linux/modversions.h: FORCE
                mv -f $@.tmp $@; \
        fi
 
+else # !CONFIG_MODVERSIONS
+
+.hdepend: include/linux/version.h include/asm \
+         $(if $(filter dep depend,$(MAKECMDGOALS)),FORCE)
+       touch $@
+       @$(MAKE) archdep
+
+endif # CONFIG_MODVERSIONS
+
 # ---------------------------------------------------------------------------
 # Modules
 
@@ -592,8 +603,8 @@ MRPROPER_FILES += \
        scripts/lxdialog/*.o scripts/lxdialog/lxdialog \
        .menuconfig.log \
        include/asm \
-       .hdepend scripts/mkdep scripts/split-include scripts/docproc \
-       $(TOPDIR)/include/linux/modversions.h \
+       .hdepend scripts/split-include scripts/docproc \
+       scripts/fixdep $(TOPDIR)/include/linux/modversions.h \
        tags TAGS kernel.spec \
 
 #      directories removed with 'make mrproper'
@@ -607,7 +618,8 @@ include arch/$(ARCH)/Makefile
 
 clean: archclean
        @echo 'Cleaning up'
-       @find . \( -name \*.[oas] -o -name core -o -name .\*.cmd \) -type f -print \
+       @find . \( -name \*.[oas] -o -name core -o -name .\*.cmd -o \
+                  -name .\*.tmp -o -name .\*.d \) -type f -print \
                | grep -v lxdialog/ | xargs rm -f
        @rm -f $(CLEAN_FILES)
        @rm -rf $(CLEAN_DIRS)
index 26903c9f6a1dd509d01ec7c33627f9e45caa4b9a..16109267367264c8be3ef0f4e49d6afbfe0b9424 100644 (file)
@@ -96,7 +96,7 @@ first_rule: vmlinux $(if $(BUILD_MODULES),$(obj-m))
 # Compile C sources (.c)
 # ---------------------------------------------------------------------------
 
-# FIXME: if we don't know if built-in or modular, assume built-in.
+# If we don't know if built-in or modular, assume built-in.
 # Only happens in Makefiles which override the default first_rule:
 modkern_cflags := $(CFLAGS_KERNEL)
 
@@ -120,25 +120,25 @@ quiet_cmd_cc_s_c = CC     $(RELDIR)/$@
 cmd_cc_s_c       = $(CC) $(c_flags) -S -o $@ $< 
 
 %.s: %.c FORCE
-       $(call if_changed,cmd_cc_s_c)
+       $(call cmd,cmd_cc_s_c)
 
 quiet_cmd_cc_i_c = CPP    $(RELDIR)/$@
 cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<
 
 %.i: %.c FORCE
-       $(call if_changed,cmd_cc_i_c)
+       $(call cmd,cmd_cc_i_c)
 
 quiet_cmd_cc_o_c = CC     $(RELDIR)/$@
-cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
+cmd_cc_o_c       = $(CC) -Wp,-MD,.$(subst /,_,$@).d $(c_flags) -c -o $@ $<
 
 %.o: %.c FORCE
-       $(call if_changed,cmd_cc_o_c)
+       $(call if_changed_dep,cc_o_c)
 
 quiet_cmd_cc_lst_c = Generating $(RELDIR)/$@
 cmd_cc_lst_c     = $(CC) $(c_flags) -g -c -o $*.o $< && $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP) > $@
 
 %.lst: %.c FORCE
-       $(call if_changed,cmd_cc_lst_c)
+       $(call cmd,cmd_cc_lst_c)
 
 # Compile assembler sources (.S)
 # ---------------------------------------------------------------------------
@@ -158,13 +158,13 @@ quiet_cmd_as_s_S = CPP    $(RELDIR)/$@
 cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 
 
 %.s: %.S FORCE
-       $(call if_changed,cmd_as_s_S)
+       $(call cmd,cmd_as_s_S)
 
 quiet_cmd_as_o_S = AS     $(RELDIR)/$@
-cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<
+cmd_as_o_S       = $(CC) -Wp,-MD,.$(subst /,_,$@).d $(a_flags) -c -o $@ $<
 
 %.o: %.S FORCE
-       $(call if_changed,cmd_as_o_S)
+       $(call if_changed_dep,as_o_S)
 
 # If a Makefile does define neither O_TARGET nor L_TARGET,
 # use a standard O_TARGET named "built-in.o"
@@ -226,14 +226,10 @@ $(multi-used-m) : %.o: $(multi-objs-m) FORCE
        $(call if_changed,cmd_link_multi)
 
 #
-# This make dependencies quickly
+# This makes module versions
 #
 
-quiet_cmd_fastdep = Making dependencies ($(RELDIR))
-cmd_fastdep       = $(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS) -- $(wildcard *.[chS]) > .depend
-
 fastdep: FORCE
-       $(call cmd,cmd_fastdep)
 ifdef ALL_SUB_DIRS
        @$(MAKE) $(patsubst %,_sfdep_%,$(ALL_SUB_DIRS)) _FASTDEP_ALL_SUB_DIRS="$(ALL_SUB_DIRS)"
 endif
@@ -287,7 +283,9 @@ modules_install: _modinst__ $(patsubst %,_modinst_%,$(MOD_SUB_DIRS))
 
 # Add FORCE to the prequisites of a target to force it to be always rebuilt.
 # ---------------------------------------------------------------------------
+
 .PHONY: FORCE
+
 FORCE:
 
 #
@@ -301,7 +299,6 @@ script:
 # Separate the object into "normal" objects and "exporting" objects
 # Exporting objects are: all objects that define symbol tables
 #
-ifdef CONFIG_MODULES
 
 ifdef CONFIG_MODVERSIONS
 ifneq "$(strip $(export-objs))" ""
@@ -323,16 +320,17 @@ endif
 # We don't track dependencies for .ver files, so we FORCE to check
 # them always (i.e. always at "make dep" time).
 
+quiet_cmd_create_ver = Creating $@
 cmd_create_ver = $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< | \
                 $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp
 
 $(MODINCL)/$(MODPREFIX)%.ver: %.c FORCE
        @echo $(cmd_create_ver)
-       @$(cmd_create_ver)
+       @$(call cmd,cmd_create_ver)
        @if [ -r $@ ] && cmp -s $@ $@.tmp; then \
          echo $@ is unchanged; rm -f $@.tmp; \
        else \
-         echo mv $@.tmp $@; mv -f $@.tmp $@; \
+         mv -f $@.tmp $@; \
        fi
 
 # updates .ver files but not modversions.h
@@ -340,30 +338,8 @@ fastdep: $(addprefix $(MODINCL)/$(MODPREFIX),$(export-objs:.o=.ver))
 
 endif # export-objs 
 
-# make dep cannot correctly figure out the dependency on the generated
-# modversions.h, so we list them here:
-# o files which export symbols and are compiled into the kernel include
-#   it (to generate a correct symbol table)
-# o all modules get compiled with -include modversions.h
-
-$(filter $(export-objs),$(real-objs-y)): $(TOPDIR)/include/linux/modversions.h
-$(real-objs-m): $(TOPDIR)/include/linux/modversions.h
-
 endif # CONFIG_MODVERSIONS
 
-endif # CONFIG_MODULES
-
-#
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
-
-ifneq ($(wildcard $(TOPDIR)/.hdepend),)
-include $(TOPDIR)/.hdepend
-endif
-
 # ---------------------------------------------------------------------------
 # Check if command line has changed
 
@@ -395,7 +371,7 @@ endif
 #   which is saved in .<target>.o, to the current command line using
 #   the two filter-out commands)
 
-# read all saved command lines
+# read all saved command lines and dependencies
 
 cmd_files := $(wildcard .*.cmd)
 ifneq ($(cmd_files),)
@@ -409,6 +385,20 @@ if_changed = $(if $(strip $? \
                          $(filter-out $(cmd_$(@F)),$($(1)))),\
               @$(if $($(quiet)$(1)),echo '  $($(quiet)$(1))' &&) $($(1)) && echo 'cmd_$@ := $($(1))' > $(@D)/.$(@F).cmd)
 
+
+# execute the command and also postprocess generated .d dependencies
+# file
+
+if_changed_dep = $(if $(strip $? \
+                         $(filter-out $(cmd_$(1)),$(cmd_$@))\
+                         $(filter-out $(cmd_$@),$(cmd_$(1)))),\
+       @set -e; \
+       $(if $($(quiet)cmd_$(1)),echo '$($(quiet)cmd_$(1))';) \
+       $(cmd_$(1)); \
+       $(TOPDIR)/scripts/fixdep $(subst /,_,$@) $(TOPDIR) '$(cmd_$(1))' > .$(subst /,_,$@).tmp; \
+       rm -f .$(subst /,_,$@).d; \
+       mv -f .$(subst /,_,$@).tmp .$(subst /,_,$@).cmd )
+
 # If quiet is set, only print short version of command
 
 cmd = @$(if $($(quiet)$(1)),echo '  $($(quiet)$(1))' &&) $($(1))
index c4c86002e7624a5de302c1ea22c83f30f525fa2c..83f72fb047b4980e8360593c449318560d954510 100644 (file)
@@ -7,9 +7,9 @@
 # can't do it
 CHMOD_FILES := docgen gen-all-syms kernel-doc mkcompile_h mkversion_h makelst
 
-all: mkdep split-include $(CHMOD_FILES)
+all: fixdep split-include $(CHMOD_FILES)
 
-mkdep: mkdep.c
+fixdep: fixdep.c
        $(HOSTCC) $(HOSTCFLAGS) -o $@ $<
 
 split-include: split-include.c
diff --git a/scripts/fixdep.c b/scripts/fixdep.c
new file mode 100644 (file)
index 0000000..07c927c
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD 
+ * for the kernel build
+ * ===========================================================================
+ *
+ * Author       Kai Germaschewski
+ * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ *
+ * Introduction:
+ * 
+ * gcc produces a very nice and correct list of dependencies which
+ * tells make when to remake a file.
+ *
+ * To use this list as-is however has the drawback that virtually
+ * every file in the kernel includes <linux/config.h> which then again
+ * includes <linux/autoconf.h>
+ *
+ * If the user re-runs make *config, linux/autoconf.h will be
+ * regenerated.  make notices that and will rebuild every file which
+ * includes autconf.h, i.e. basically all files. This is extremely
+ * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
+ * 
+ * So we play the same trick that "mkdep" played before. We replace
+ * the dependency on linux/autoconf.h by a dependency on every config
+ * option which is mentioned in any of the listed prequisites.
+ *  
+ * To be exact, split-include populates a tree in include/config/,
+ * e.g. include/config/his/driver.h, which contains the #define/#undef
+ * for the CONFIG_HIS_DRIVER option.
+ *
+ * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
+ * which depend on "include/linux/config/his/driver.h" will be rebuilt,
+ * so most likely only his driver ;-) 
+ *
+ * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
+ * 
+ * So to get dependencies right, there two issues:
+ * o if any of the files the compiler read changed, we need to rebuild
+ * o if the command line given to the compile the file changed, we
+ *   better rebuild as well.
+ *
+ * The former is handled by using the -MD output, the later by saving
+ * the command line used to compile the old object and comparing it
+ * to the one we would now use.
+ *
+ * Again, also this idea is pretty old and has been discussed on
+ * kbuild-devel a long time ago. I don't have a sensibly working
+ * internet connection right now, so I rather don't mention names
+ * without double checking.
+ *
+ * This code here has been based partially based on mkdep.c, which
+ * says the following about its history:
+ *
+ *   Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
+ *   This is a C version of syncdep.pl by Werner Almesberger.
+ *
+ *
+ * It is invoked as
+ *
+ *   fixdep <target> <topdir> <cmdline>
+ *
+ * and will read the dependency file ".<target>.d".
+ *
+ * The transformed dependency snipped is written to stdout.
+ *
+ * It first generates a line
+ *
+ *   cmd_<target> = <cmdline>
+ *
+ * and then basically copies the .<target>.d file to stdout, in the
+ * process filtering out the dependency on linux/autconf.h and adding
+ * dependencies on include/config/my/option.h for every
+ * CONFIG_MY_OPTION encountered in any of the prequisites.
+ *
+ * It will also filter out all the dependencies on *.ver. We need
+ * to make sure that the generated version checksum are globally up
+ * to date before even starting the recursive build, so it's too late
+ * at this point anyway.
+ *
+ * The algorithm to grep for "CONFIG_..." is bit unusual, but should
+ * be fast ;-) We don't even try to really parse the header files, but
+ * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
+ * be picked up as well. It's not a problem with respect to
+ * correctness, since that can only give too many dependencies, thus
+ * we cannot miss a rebuild. Since people tend to not mention totally
+ * unrelated CONFIG_ options all over the place, it's not an
+ * efficiency problem either.
+ * 
+ * (Note: it'd be easy to port over the complete mkdep state machine,
+ *  but I don't think the added complexity is worth it)
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <netinet/in.h>
+
+#define INT_CONF ntohl(0x434f4e46)
+#define INT_ONFI ntohl(0x4f4e4649)
+#define INT_NFIG ntohl(0x4e464947)
+#define INT_FIG_ ntohl(0x4649475f)
+
+char *topdir;
+
+void usage(void)
+
+{
+       fprintf(stderr, "Usage: fixdep <target> <topdir> <cmdline>\n");
+       exit(1);
+}
+
+void print_cmdline(char *target, char *cmdline)
+{
+       char *s = strdup(target);
+       char *p = s;
+
+       if (!s) {
+               fprintf(stderr, "no mem!\n");
+               exit(2);
+       }
+       while ((p = strchr(p,'/')))
+               *p = '_';
+
+       printf("cmd_%s := %s\n\n", s, cmdline);
+
+       free(s);
+}
+
+char * str_config  = NULL;
+int    size_config = 0;
+int    len_config  = 0;
+
+/*
+ * Grow the configuration string to a desired length.
+ * Usually the first growth is plenty.
+ */
+void grow_config(int len)
+{
+       while (len_config + len > size_config) {
+               if (size_config == 0)
+                       size_config = 2048;
+               str_config = realloc(str_config, size_config *= 2);
+               if (str_config == NULL)
+                       { perror("malloc"); exit(1); }
+       }
+}
+
+
+
+/*
+ * Lookup a value in the configuration string.
+ */
+int is_defined_config(const char * name, int len)
+{
+       const char * pconfig;
+       const char * plast = str_config + len_config - len;
+       for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
+               if (pconfig[ -1] == '\n'
+               &&  pconfig[len] == '\n'
+               &&  !memcmp(pconfig, name, len))
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * Add a new value to the configuration string.
+ */
+void define_config(const char * name, int len)
+{
+       grow_config(len + 1);
+
+       memcpy(str_config+len_config, name, len);
+       len_config += len;
+       str_config[len_config++] = '\n';
+}
+
+/*
+ * Clear the set of configuration strings.
+ */
+void clear_config(void)
+{
+       len_config = 0;
+       define_config("", 0);
+}
+
+/*
+ * Record the use of a CONFIG_* word.
+ */
+void use_config(char *m, int slen)
+{
+       char s[PATH_MAX];
+       char *p;
+
+       if (is_defined_config(m, slen))
+           return;
+
+       define_config(m, slen);
+
+       memcpy(s, m, slen); s[slen] = 0;
+
+       for (p = s; p < s + slen; p++) {
+               if (*p == '_')
+                       *p = '/';
+               else
+                       *p = tolower(*p);
+       }
+       printf("    $(wildcard %s/include/config/%s.h) \\\n", topdir, s);
+}
+
+void parse_config_file(char *map, size_t len)
+{
+       int *end = (int *) (map + len);
+       // start at +1, so that p can never be < map
+       int *m   = (int *) map + 1;
+       char *p, *q;
+
+       for (; m < end; m++) {
+               if (*m == INT_CONF) { p = (char *) m  ; goto conf; }
+               if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
+               if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
+               if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
+               continue;
+       conf:
+               if (p > map + len - 7)
+                       continue;
+               if (memcmp(p, "CONFIG_", 7))
+                       continue;
+               for (q = p + 7; q < map + len; q++) {
+                       if (!(isalnum(*q)))
+                               goto found;
+               }
+               continue;
+
+       found: 
+               use_config(p+7, q-p-7);
+       }
+}
+
+/* test is s ends in sub */
+int strrcmp(char *s, char *sub)
+{
+       int slen = strlen(s);
+       int sublen = strlen(sub);
+  
+       if (sublen > slen)
+               return 1;
+       
+       return memcmp(s + slen - sublen, sub, sublen);
+}
+
+void do_config_file(char *filename)
+{
+       struct stat st;
+       int fd;
+       void *map;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               perror(filename);
+               exit(2);
+       }
+       fstat(fd, &st);
+       if (st.st_size == 0) {
+               close(fd);
+               return;
+       }
+       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if ((long) map == -1) {
+               perror("mmap");
+               close(fd);
+               return;
+       }
+       
+       parse_config_file(map, st.st_size);
+
+       munmap(map, st.st_size);
+}
+
+void parse_dep_file(void *map, size_t len)
+{
+       char *m = map;
+       char *end = map + len;
+       char *p;
+       char s[PATH_MAX];
+
+       p = strchr(m, ':');
+       if (!p) {
+               fprintf(stderr, "parse error at %d", __LINE__);
+               exit(1);
+       }
+       memcpy(s, m, p-m); s[p-m] = 0;
+       printf("%s: \\\n", s);
+       m = p+1;
+
+       clear_config();
+
+       while (m < end) {
+               while (*m == ' ' || *m == '\\' || *m == '\n')
+                       m++;
+
+               p = strchr(m, ' ');
+               if (!p) {
+                       p = end;
+                       while (!isalpha(*p)) p--;
+                       p++;
+               }
+               memcpy(s, m, p-m); s[p-m] = 0;
+               if (strrcmp(s, "include/linux/autoconf.h") &&
+                   strrcmp(s, ".ver")) {
+                       printf("  %s \\\n", s);
+                       do_config_file(s);
+               }
+               m = p + 1;
+       }
+       printf("\n");
+}
+
+void print_deps(char *target)
+{
+       char filename[PATH_MAX];
+       struct stat st;
+       int fd;
+       void *map;
+
+       sprintf(filename, ".%s.d", target);
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               perror(filename);
+               exit(2);
+       }
+       fstat(fd, &st);
+       if (st.st_size == 0) {
+               fprintf(stderr,"%s is empty\n",filename);
+               close(fd);
+               return;
+       }
+       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if ((long) map == -1) {
+               perror("mmap");
+               close(fd);
+               return;
+       }
+       
+       parse_dep_file(map, st.st_size);
+
+       munmap(map, st.st_size);
+}
+
+void traps(void)
+{
+       char *test = "CONF";
+
+       if (*(int *)test != INT_CONF) {
+               fprintf(stderr, "sizeof(int) != 4 or wrong endianess? %#x\n",
+                       *(int *)test);
+               exit(2);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       char *target, *cmdline;
+       
+       traps();
+
+       if (argc != 4)
+               usage();
+               
+       target = argv[1];
+       topdir = argv[2];
+       cmdline = argv[3];
+
+       print_cmdline(target, cmdline);
+       print_deps(target);
+
+       return 0;
+}
diff --git a/scripts/mkdep.c b/scripts/mkdep.c
deleted file mode 100644 (file)
index 01386ea..0000000
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * Originally by Linus Torvalds.
- * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
- *
- * Usage: mkdep cflags -- file ...
- * 
- * Read source files and output makefile dependency lines for them.
- * I make simple dependency lines for #include <*.h> and #include "*.h".
- * I also find instances of CONFIG_FOO and generate dependencies
- *    like include/config/foo.h.
- *
- * 1 August 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Keith Owens reported a bug in smart config processing.  There used
- *   to be an optimization for "#define CONFIG_FOO ... #ifdef CONFIG_FOO",
- *   so that the file would not depend on CONFIG_FOO because the file defines
- *   this symbol itself.  But this optimization is bogus!  Consider this code:
- *   "#if 0 \n #define CONFIG_FOO \n #endif ... #ifdef CONFIG_FOO".  Here
- *   the definition is inactivated, but I still used it.  It turns out this
- *   actually happens a few times in the kernel source.  The simple way to
- *   fix this problem is to remove this particular optimization.
- *
- * 2.3.99-pre1, Andrew Morton <andrewm@uow.edu.au>
- * - Changed so that 'filename.o' depends upon 'filename.[cS]'.  This is so that
- *   missing source files are noticed, rather than silently ignored.
- *
- * 2.4.2-pre3, Keith Owens <kaos@ocs.com.au>
- * - Accept cflags followed by '--' followed by filenames.  mkdep extracts -I
- *   options from cflags and looks in the specified directories as well as the
- *   defaults.   Only -I is supported, no attempt is made to handle -idirafter,
- *   -isystem, -I- etc.
- */
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-
-
-char __depname[512] = "\n\t@touch ";
-#define depname (__depname+9)
-int hasdep;
-
-struct path_struct {
-       int len;
-       char *buffer;
-};
-struct path_struct *path_array;
-int paths;
-
-
-/* Current input file */
-static const char *g_filename;
-
-/*
- * This records all the configuration options seen.
- * In perl this would be a hash, but here it's a long string
- * of values separated by newlines.  This is simple and
- * extremely fast.
- */
-char * str_config  = NULL;
-int    size_config = 0;
-int    len_config  = 0;
-
-static void
-do_depname(void)
-{
-       if (!hasdep) {
-               hasdep = 1;
-               printf("%s:", depname);
-               if (g_filename)
-                       printf(" %s", g_filename);
-       }
-}
-
-/*
- * Grow the configuration string to a desired length.
- * Usually the first growth is plenty.
- */
-void grow_config(int len)
-{
-       while (len_config + len > size_config) {
-               if (size_config == 0)
-                       size_config = 2048;
-               str_config = realloc(str_config, size_config *= 2);
-               if (str_config == NULL)
-                       { perror("malloc config"); exit(1); }
-       }
-}
-
-
-
-/*
- * Lookup a value in the configuration string.
- */
-int is_defined_config(const char * name, int len)
-{
-       const char * pconfig;
-       const char * plast = str_config + len_config - len;
-       for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
-               if (pconfig[ -1] == '\n'
-               &&  pconfig[len] == '\n'
-               &&  !memcmp(pconfig, name, len))
-                       return 1;
-       }
-       return 0;
-}
-
-
-
-/*
- * Add a new value to the configuration string.
- */
-void define_config(const char * name, int len)
-{
-       grow_config(len + 1);
-
-       memcpy(str_config+len_config, name, len);
-       len_config += len;
-       str_config[len_config++] = '\n';
-}
-
-
-
-/*
- * Clear the set of configuration strings.
- */
-void clear_config(void)
-{
-       len_config = 0;
-       define_config("", 0);
-}
-
-
-
-/*
- * This records all the precious .h filenames.  No need for a hash,
- * it's a long string of values enclosed in tab and newline.
- */
-char * str_precious  = NULL;
-int    size_precious = 0;
-int    len_precious  = 0;
-
-
-
-/*
- * Grow the precious string to a desired length.
- * Usually the first growth is plenty.
- */
-void grow_precious(int len)
-{
-       while (len_precious + len > size_precious) {
-               if (size_precious == 0)
-                       size_precious = 2048;
-               str_precious = realloc(str_precious, size_precious *= 2);
-               if (str_precious == NULL)
-                       { perror("malloc"); exit(1); }
-       }
-}
-
-
-
-/*
- * Add a new value to the precious string.
- */
-void define_precious(const char * filename)
-{
-       int len = strlen(filename);
-       grow_precious(len + 4);
-       *(str_precious+len_precious++) = '\t';
-       memcpy(str_precious+len_precious, filename, len);
-       len_precious += len;
-       memcpy(str_precious+len_precious, " \\\n", 3);
-       len_precious += 3;
-}
-
-
-
-/*
- * Handle an #include line.
- */
-void handle_include(int start, const char * name, int len)
-{
-       struct path_struct *path;
-       int i;
-
-       if (len == 14 && !memcmp(name, "linux/config.h", len))
-               return;
-
-       if (len >= 7 && !memcmp(name, "config/", 7))
-               define_config(name+7, len-7-2);
-
-       for (i = start, path = path_array+start; i < paths; ++i, ++path) {
-               memcpy(path->buffer+path->len, name, len);
-               path->buffer[path->len+len] = '\0';
-               if (access(path->buffer, F_OK) == 0) {
-                       do_depname();
-                       printf(" \\\n   %s", path->buffer);
-                       return;
-               }
-       }
-
-}
-
-
-
-/*
- * Add a path to the list of include paths.
- */
-void add_path(const char * name)
-{
-       struct path_struct *path;
-       char resolved_path[PATH_MAX+1];
-       const char *name2;
-
-       if (strcmp(name, ".")) {
-               name2 = realpath(name, resolved_path);
-               if (!name2) {
-                       fprintf(stderr, "realpath(%s) failed, %m\n", name);
-                       exit(1);
-               }
-       }
-       else {
-               name2 = "";
-       }
-
-       path_array = realloc(path_array, (++paths)*sizeof(*path_array));
-       if (!path_array) {
-               fprintf(stderr, "cannot expand path_arry\n");
-               exit(1);
-       }
-
-       path = path_array+paths-1;
-       path->len = strlen(name2);
-       path->buffer = malloc(path->len+1+256+1);
-       if (!path->buffer) {
-               fprintf(stderr, "cannot allocate path buffer\n");
-               exit(1);
-       }
-       strcpy(path->buffer, name2);
-       if (path->len && *(path->buffer+path->len-1) != '/') {
-               *(path->buffer+path->len) = '/';
-               *(path->buffer+(++(path->len))) = '\0';
-       }
-}
-
-
-
-/*
- * Record the use of a CONFIG_* word.
- */
-void use_config(const char * name, int len)
-{
-       char *pc;
-       int i;
-
-       pc = path_array[paths-1].buffer + path_array[paths-1].len;
-       memcpy(pc, "config/", 7);
-       pc += 7;
-
-       for (i = 0; i < len; i++) {
-           int c = (unsigned char) name[i];
-           if (isupper(c)) c = tolower(c);
-           if (c == '_')   c = '/';
-           pc[i] = c;
-       }
-       pc[len] = '\0';
-
-       if (is_defined_config(pc, len))
-           return;
-
-       define_config(pc, len);
-
-       do_depname();
-       printf(" \\\n   $(wildcard %s.h)", path_array[paths-1].buffer);
-}
-
-
-
-/*
- * Macros for stunningly fast map-based character access.
- * __buf is a register which holds the current word of the input.
- * Thus, there is one memory access per sizeof(unsigned long) characters.
- */
-
-#if defined(__alpha__) || defined(__i386__) || defined(__ia64__)  || defined(__x86_64__) || defined(__MIPSEL__)        \
-    || defined(__arm__)
-#define LE_MACHINE
-#endif
-
-#ifdef LE_MACHINE
-#define next_byte(x) (x >>= 8)
-#define current ((unsigned char) __buf)
-#else
-#define next_byte(x) (x <<= 8)
-#define current (__buf >> 8*(sizeof(unsigned long)-1))
-#endif
-
-#define GETNEXT { \
-       next_byte(__buf); \
-       if ((unsigned long) next % sizeof(unsigned long) == 0) { \
-               if (next >= end) \
-                       break; \
-               __buf = * (unsigned long *) next; \
-       } \
-       next++; \
-}
-
-/*
- * State machine macros.
- */
-#define CASE(c,label) if (current == c) goto label
-#define NOTCASE(c,label) if (current != c) goto label
-
-/*
- * Yet another state machine speedup.
- */
-#define MAX2(a,b) ((a)>(b)?(a):(b))
-#define MIN2(a,b) ((a)<(b)?(a):(b))
-#define MAX5(a,b,c,d,e) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,e)))))
-#define MIN5(a,b,c,d,e) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,e)))))
-
-
-
-/*
- * The state machine looks for (approximately) these Perl regular expressions:
- *
- *    m|\/\*.*?\*\/|
- *    m|\/\/.*|
- *    m|'.*?'|
- *    m|".*?"|
- *    m|#\s*include\s*"(.*?)"|
- *    m|#\s*include\s*<(.*?>"|
- *    m|#\s*(?define|undef)\s*CONFIG_(\w*)|
- *    m|(?!\w)CONFIG_|
- *
- * About 98% of the CPU time is spent here, and most of that is in
- * the 'start' paragraph.  Because the current characters are
- * in a register, the start loop usually eats 4 or 8 characters
- * per memory read.  The MAX5 and MIN5 tests dispose of most
- * input characters with 1 or 2 comparisons.
- */
-void state_machine(const char * map, const char * end)
-{
-       const char * next = map;
-       const char * map_dot;
-       unsigned long __buf = 0;
-
-       for (;;) {
-start:
-       GETNEXT
-__start:
-       if (current > MAX5('/','\'','"','#','C')) goto start;
-       if (current < MIN5('/','\'','"','#','C')) goto start;
-       CASE('/',  slash);
-       CASE('\'', squote);
-       CASE('"',  dquote);
-       CASE('#',  pound);
-       CASE('C',  cee);
-       goto start;
-
-/* // */
-slash_slash:
-       GETNEXT
-       CASE('\n', start);
-       NOTCASE('\\', slash_slash);
-       GETNEXT
-       goto slash_slash;
-
-/* / */
-slash:
-       GETNEXT
-       CASE('/',  slash_slash);
-       NOTCASE('*', __start);
-slash_star_dot_star:
-       GETNEXT
-__slash_star_dot_star:
-       NOTCASE('*', slash_star_dot_star);
-       GETNEXT
-       NOTCASE('/', __slash_star_dot_star);
-       goto start;
-
-/* '.*?' */
-squote:
-       GETNEXT
-       CASE('\'', start);
-       NOTCASE('\\', squote);
-       GETNEXT
-       goto squote;
-
-/* ".*?" */
-dquote:
-       GETNEXT
-       CASE('"', start);
-       NOTCASE('\\', dquote);
-       GETNEXT
-       goto dquote;
-
-/* #\s* */
-pound:
-       GETNEXT
-       CASE(' ',  pound);
-       CASE('\t', pound);
-       CASE('i',  pound_i);
-       CASE('d',  pound_d);
-       CASE('u',  pound_u);
-       goto __start;
-
-/* #\s*i */
-pound_i:
-       GETNEXT NOTCASE('n', __start);
-       GETNEXT NOTCASE('c', __start);
-       GETNEXT NOTCASE('l', __start);
-       GETNEXT NOTCASE('u', __start);
-       GETNEXT NOTCASE('d', __start);
-       GETNEXT NOTCASE('e', __start);
-       goto pound_include;
-
-/* #\s*include\s* */
-pound_include:
-       GETNEXT
-       CASE(' ',  pound_include);
-       CASE('\t', pound_include);
-       map_dot = next;
-       CASE('"',  pound_include_dquote);
-       CASE('<',  pound_include_langle);
-       goto __start;
-
-/* #\s*include\s*"(.*)" */
-pound_include_dquote:
-       GETNEXT
-       CASE('\n', start);
-       NOTCASE('"', pound_include_dquote);
-       handle_include(0, map_dot, next - map_dot - 1);
-       goto start;
-
-/* #\s*include\s*<(.*)> */
-pound_include_langle:
-       GETNEXT
-       CASE('\n', start);
-       NOTCASE('>', pound_include_langle);
-       handle_include(1, map_dot, next - map_dot - 1);
-       goto start;
-
-/* #\s*d */
-pound_d:
-       GETNEXT NOTCASE('e', __start);
-       GETNEXT NOTCASE('f', __start);
-       GETNEXT NOTCASE('i', __start);
-       GETNEXT NOTCASE('n', __start);
-       GETNEXT NOTCASE('e', __start);
-       goto pound_define_undef;
-
-/* #\s*u */
-pound_u:
-       GETNEXT NOTCASE('n', __start);
-       GETNEXT NOTCASE('d', __start);
-       GETNEXT NOTCASE('e', __start);
-       GETNEXT NOTCASE('f', __start);
-       goto pound_define_undef;
-
-/*
- * #\s*(define|undef)\s*CONFIG_(\w*)
- *
- * this does not define the word, because it could be inside another
- * conditional (#if 0).  But I do parse the word so that this instance
- * does not count as a use.  -- mec
- */
-pound_define_undef:
-       GETNEXT
-       CASE(' ',  pound_define_undef);
-       CASE('\t', pound_define_undef);
-
-               NOTCASE('C', __start);
-       GETNEXT NOTCASE('O', __start);
-       GETNEXT NOTCASE('N', __start);
-       GETNEXT NOTCASE('F', __start);
-       GETNEXT NOTCASE('I', __start);
-       GETNEXT NOTCASE('G', __start);
-       GETNEXT NOTCASE('_', __start);
-
-       map_dot = next;
-pound_define_undef_CONFIG_word:
-       GETNEXT
-       if (isalnum(current) || current == '_')
-               goto pound_define_undef_CONFIG_word;
-       goto __start;
-
-/* \<CONFIG_(\w*) */
-cee:
-       if (next >= map+2 && (isalnum(next[-2]) || next[-2] == '_'))
-               goto start;
-       GETNEXT NOTCASE('O', __start);
-       GETNEXT NOTCASE('N', __start);
-       GETNEXT NOTCASE('F', __start);
-       GETNEXT NOTCASE('I', __start);
-       GETNEXT NOTCASE('G', __start);
-       GETNEXT NOTCASE('_', __start);
-
-       map_dot = next;
-cee_CONFIG_word:
-       GETNEXT
-       if (isalnum(current) || current == '_')
-               goto cee_CONFIG_word;
-       use_config(map_dot, next - map_dot - 1);
-       goto __start;
-    }
-}
-
-
-
-/*
- * Generate dependencies for one file.
- */
-void do_depend(const char * filename, const char * command)
-{
-       int mapsize;
-       int pagesizem1 = getpagesize()-1;
-       int fd;
-       struct stat st;
-       char * map;
-
-       fd = open(filename, O_RDONLY);
-       if (fd < 0) {
-               perror(filename);
-               return;
-       }
-
-       fstat(fd, &st);
-       if (st.st_size == 0) {
-               fprintf(stderr,"%s is empty\n",filename);
-               close(fd);
-               return;
-       }
-
-       mapsize = st.st_size;
-       mapsize = (mapsize+pagesizem1) & ~pagesizem1;
-       map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
-       if ((long) map == -1) {
-               perror("mkdep: mmap");
-               close(fd);
-               return;
-       }
-       if ((unsigned long) map % sizeof(unsigned long) != 0)
-       {
-               fprintf(stderr, "do_depend: map not aligned\n");
-               exit(1);
-       }
-
-       hasdep = 0;
-       clear_config();
-       state_machine(map, map+st.st_size);
-       if (hasdep) {
-               puts(command);
-               if (*command)
-                       define_precious(filename);
-       }
-
-       munmap(map, mapsize);
-       close(fd);
-}
-
-
-
-/*
- * Generate dependencies for all files.
- */
-int main(int argc, char **argv)
-{
-       int len;
-       const char *hpath;
-
-       hpath = getenv("HPATH");
-       if (!hpath) {
-               fputs("mkdep: HPATH not set in environment.  "
-                     "Don't bypass the top level Makefile.\n", stderr);
-               return 1;
-       }
-
-       add_path(".");          /* for #include "..." */
-
-       while (++argv, --argc > 0) {
-               if (strncmp(*argv, "-I", 2) == 0) {
-                       if (*((*argv)+2)) {
-                               add_path((*argv)+2);
-                       }
-                       else {
-                               ++argv;
-                               --argc;
-                               add_path(*argv);
-                       }
-               }
-               else if (strcmp(*argv, "--") == 0) {
-                       break;
-               }
-       }
-
-       add_path(hpath);        /* must be last entry, for config files */
-
-       while (--argc > 0) {
-               const char * filename = *++argv;
-               const char * command  = __depname;
-               g_filename = 0;
-               len = strlen(filename);
-               memcpy(depname, filename, len+1);
-               if (len > 2 && filename[len-2] == '.') {
-                       if (filename[len-1] == 'c' || filename[len-1] == 'S') {
-                           depname[len-1] = 'o';
-                           g_filename = filename;
-                           command = "";
-                       }
-               }
-               do_depend(filename, command);
-       }
-       if (len_precious) {
-               *(str_precious+len_precious) = '\0';
-               printf(".PRECIOUS:%s\n", str_precious);
-       }
-       return 0;
-}