config.h dependencies

Werner Almesberger (almesber@lrc.di.epfl.ch)
Thu, 2 Oct 1997 17:01:06 +0100 (MET)


Every once in a while, somebody posts an approach to get rid of that
annoying full rebuild after even the slightest configuration change.
I guess it's my turn again, so here it is.

It introduces pseudo header files (include/config/*.dep) which are
referenced in the dependencies generated by mkdep. A little Perl script
synchronizes them with whatever happens to autoconf.h.

In addition to that, "missing" .dep files are generated at the end of
each make dep (actually, all of them are touched. Too bad touch doesn't
have a --create-only option and I'm too lazy to do anything better ;-)

Note that mkdep has changed a bit: it now scans the whole source, not only
the preprocessor directives. The extra work makes it about 50% slower. It
also "detects" bogus configuration options like CONFIG_0 in some drivers.
I'm not sure what to do about those. Perhaps renaming them would be the
best solution.

I'm also not sure why the original mkdep checked for character constants,
so I'm ignoring them. I've verified that the "normal" (i.e. non-.dep)
dependencies generated by mkdep are the same with or without my changes.

All that stuff is for 2.1.57. I only did some minimal testing, so there
are probably a few holes left.

Enjoy,
- Werner

---------------------------------- cut here -----------------------------------

diff -urp --new-file linux/Makefile work/Makefile
--- linux/Makefile Sat Sep 20 23:54:48 1997
+++ work/Makefile Thu Oct 2 17:59:41 1997
@@ -204,17 +204,21 @@ symlinks:
oldconfig: symlinks
$(MAKE) -C drivers/sound mkscript
$(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
+ perl scripts/syncdep.pl

xconfig: symlinks
$(MAKE) -C scripts kconfig.tk
wish -f scripts/kconfig.tk
+ perl scripts/syncdep.pl

menuconfig: include/linux/version.h symlinks
$(MAKE) -C scripts/lxdialog all
$(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in
+ perl scripts/syncdep.pl

config: symlinks
$(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
+ perl scripts/syncdep.pl

linuxsubdirs: dummy
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
@@ -351,6 +355,7 @@ mrproper: clean
rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
rm -f .menuconfig .menuconfig.log
rm -f include/asm
+ rm -rf include/config
rm -f .depend `find . -name .depend -print`
rm -f .hdepend scripts/mkdep
rm -f $(TOPDIR)/include/linux/modversions.h
@@ -376,6 +381,9 @@ dep-files: scripts/mkdep archdep include
scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep; done
mv .tmpdepend .depend
+ [ -d include/config ] || mkdir include/config
+ cat .hdepend `find . -name .depend` | grep /include/config/ | \
+ awk '{print $2}' | xargs touch

MODVERFILE :=

diff -urp --new-file linux/Rules.make work/Rules.make
--- linux/Rules.make Tue Apr 15 01:28:05 1997
+++ work/Rules.make Thu Oct 2 17:59:58 1997
@@ -205,7 +205,7 @@ endif # CONFIG_MODULES


#
-# include dependency files they exist
+# include dependency files if they exist
#
ifeq (.depend,$(wildcard .depend))
include .depend
diff -urp --new-file linux/scripts/mkdep.c work/scripts/mkdep.c
--- linux/scripts/mkdep.c Tue Jun 17 01:36:02 1997
+++ work/scripts/mkdep.c Thu Oct 2 16:58:42 1997
@@ -10,6 +10,7 @@
#include <sys/mman.h>

char *filename, *command, __depname[256] = "\n\t@touch ";
+char *hpath;
int needsconfig, hasconfig, hasmodules, hasdep;

#define depname (__depname+9)
@@ -22,14 +23,66 @@ struct path_struct {
{ 0, "" }
};

-static void handle_include(int type, char *name, int len)
+struct tree {
+ const char *name;
+ int len;
+ struct tree *left,*right;
+} *tree;
+
+
+static int config_dep(const char *name, int len)
+{
+ struct tree **walk;
+
+ if (!len) return 0;
+ walk = &tree;
+ while (*walk) {
+ int comp_len,diff;
+
+ comp_len = (*walk)->len < len ? (*walk)->len : len;
+ diff = strncmp(name,(*walk)->name,comp_len);
+ if (!diff)
+ if ((*walk)->len == len) return 0;
+ else diff = len-(*walk)->len;
+ walk = diff > 0 ? &(*walk)->right : &(*walk)->left;
+ }
+ *walk = malloc(sizeof(struct tree));
+ if (!*walk) {
+ perror("malloc");
+ exit(1);
+ }
+ (*walk)->left = (*walk)->right = NULL;
+ (*walk)->len = len;
+ (*walk)->name = name;
+ return 1;
+}
+
+static void clear_dep(struct tree *tree)
+{
+ if (!tree) return;
+ clear_dep(tree->left);
+ clear_dep(tree->right);
+ free(tree);
+}
+
+static void need_dep(void)
+{
+ if (!hasdep) {
+ hasdep = 1;
+ printf("%s:", depname);
+ }
+}
+
+static void handle_include(int type, const char *name, int len)
{
int plen;
struct path_struct *path = path_array+type;

if (len == 14)
- if (!memcmp(name, "linux/config.h", len))
+ if (!memcmp(name, "linux/config.h", len)) {
hasconfig = 1;
+ return;
+ }
else if (!memcmp(name, "linux/module.h", len))
hasmodules = 1;

@@ -39,21 +92,29 @@ static void handle_include(int type, cha
path->buffer[len] = '\0';
if (access(path->buffer, F_OK))
return;
-
- if (!hasdep) {
- hasdep = 1;
- printf("%s:", depname);
- }
+ need_dep();
printf(" \\\n %s", path->buffer);
}

-static void handle_config(void)
+static void handle_config(const char *name, int len)
{
- needsconfig = 1;
- if (!hasconfig)
- fprintf(stderr,
- "%s needs config but has not included config file\n",
- filename);
+ if (config_dep(name,len)) {
+ char buffer[256],*walk;
+
+ need_dep();
+ for (walk = buffer; len; len--) {
+ *walk++ = isupper(*name) ? tolower(*name) : *name;
+ name++;
+ }
+ *walk = 0;
+ printf(" \\\n %s/config/%s.dep",hpath,buffer);
+ }
+ if (!needsconfig) {
+ needsconfig = 1;
+ if (!hasconfig)
+ fprintf(stderr, "%s needs config but has not included "
+ "config file\n", filename);
+ }
}

#if defined(__alpha__) || defined(__i386__)
@@ -84,91 +145,67 @@ static void state_machine(register char
for(;;) {
register unsigned long __buf = 0;
register unsigned long __nrbuf = 0;
+ const char *optname;

-normal:
+no_id:
GETNEXT
-__normal:
+ CASE('C',config);
+__no_id:
CASE('/',slash);
CASE('"',string);
- CASE('\'',char_const);
+ /* Linus also checked for ' here, but why ? */
CASE('#',preproc);
- goto normal;
+ if (!isalpha(current) && current != '_') goto no_id;
+id:
+ GETNEXT
+__id:
+ if (isalnum(current) || current == '_') goto id;
+ goto __no_id;

slash:
GETNEXT
CASE('*',comment);
- goto __normal;
+ goto __no_id;

string:
GETNEXT
- CASE('"',normal);
+ CASE('"',no_id);
NOTCASE('\\',string);
GETNEXT
goto string;

-char_const:
- GETNEXT
- CASE('\'',normal);
- NOTCASE('\\',char_const);
- GETNEXT
- goto char_const;
-
comment:
GETNEXT
__comment:
NOTCASE('*',comment);
GETNEXT
- CASE('/',normal);
+ CASE('/',no_id);
goto __comment;

preproc:
GETNEXT
- CASE('\n',normal);
+ CASE('\n',no_id);
CASE(' ',preproc);
CASE('\t',preproc);
- CASE('i',i_preproc);
- CASE('e',e_preproc);
- GETNEXT
-
-skippreproc:
- CASE('\n',normal);
- CASE('\\',skippreprocslash);
- GETNEXT
- goto skippreproc;
-
-skippreprocslash:
- GETNEXT;
- GETNEXT;
- goto skippreproc;
-
-e_preproc:
- GETNEXT
- NOTCASE('l',skippreproc);
+ NOTCASE('i',__no_id);
GETNEXT
- NOTCASE('i',skippreproc);
+ NOTCASE('n',__no_id);
GETNEXT
- CASE('f',if_line);
- goto skippreproc;
-
-i_preproc:
+ NOTCASE('c',__no_id);
GETNEXT
- CASE('f',if_line);
- NOTCASE('n',skippreproc);
+ NOTCASE('l',__no_id);
GETNEXT
- NOTCASE('c',skippreproc);
+ NOTCASE('u',__no_id);
GETNEXT
- NOTCASE('l',skippreproc);
+ NOTCASE('d',__no_id);
GETNEXT
- NOTCASE('u',skippreproc);
+ NOTCASE('e',__no_id);
GETNEXT
- NOTCASE('d',skippreproc);
- GETNEXT
- NOTCASE('e',skippreproc);

/* "# include" found */
include_line:
GETNEXT
- CASE('\n',normal);
+ CASE('\n',no_id);
CASE('<', std_include_file);
NOTCASE('"', include_line);

@@ -177,10 +214,10 @@ include_line:
char *incname = next;
local_include_name:
GETNEXT
- CASE('\n',normal);
+ CASE('\n',no_id);
NOTCASE('"', local_include_name);
handle_include(1, incname, next-incname-1);
- goto skippreproc;
+ goto no_id;
}

/* <std> include file */
@@ -189,50 +226,35 @@ std_include_file:
char *incname = next;
std_include_name:
GETNEXT
- CASE('\n',normal);
+ CASE('\n',no_id);
NOTCASE('>', std_include_name);
handle_include(0, incname, next-incname-1);
- goto skippreproc;
+ goto no_id;
}

-if_line:
- if (needsconfig)
- goto skippreproc;
-if_start:
- GETNEXT
- CASE('C', config);
- CASE('\n', normal);
- CASE('_', if_middle);
- if (current >= 'a' && current <= 'z')
- goto if_middle;
- if (current < 'A' || current > 'Z')
- goto if_start;
config:
GETNEXT
- NOTCASE('O', __if_middle);
+ NOTCASE('O', __id);
GETNEXT
- NOTCASE('N', __if_middle);
+ NOTCASE('N', __id);
GETNEXT
- NOTCASE('F', __if_middle);
+ NOTCASE('F', __id);
GETNEXT
- NOTCASE('I', __if_middle);
+ NOTCASE('I', __id);
GETNEXT
- NOTCASE('G', __if_middle);
+ NOTCASE('G', __id);
GETNEXT
- NOTCASE('_', __if_middle);
- handle_config();
- goto skippreproc;
-
-if_middle:
+ NOTCASE('_', __id);
+ optname = next;
+read_name:
GETNEXT
-__if_middle:
- CASE('\n', normal);
- CASE('_', if_middle);
- if (current >= 'a' && current <= 'z')
- goto if_middle;
- if (current < 'A' || current > 'Z')
- goto if_start;
- goto if_middle;
+ if (isalnum(current) || current == '_') goto read_name;
+ /*
+ * We don't handle options that end with EOF since it'd be kind of
+ * tricky to generate them in the first place ...
+ */
+ handle_config(optname,next-optname-1);
+ goto __no_id;
}
}

@@ -263,8 +285,10 @@ static void do_depend(void)
return;
}
close(fd);
+ tree = NULL;
state_machine(map);
munmap(map, mapsize);
+ clear_dep(tree);
if (hasdep)
puts(command);
}
@@ -272,7 +296,6 @@ static void do_depend(void)
int main(int argc, char **argv)
{
int len;
- char * hpath;

hpath = getenv("HPATH");
if (!hpath)
diff -urp --new-file linux/scripts/syncdep.pl work/scripts/syncdep.pl
--- linux/scripts/syncdep.pl Thu Jan 1 01:00:00 1970
+++ work/scripts/syncdep.pl Thu Oct 2 17:53:50 1997
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+$DEP_DIR = "include/config";
+$CFG_FILE = "include/linux/autoconf.h";
+
+mkdir($DEP_DIR,0755) unless -d $DEP_DIR;
+
+open(CFG,"$CFG_FILE") || die "open $CFG_FILE: $!";
+while (<CFG>) {
+ next unless /^#\S+\s+CONFIG_(\S*)/;
+ ($name = $1) =~ tr/A-Z/a-z/;
+ $path = "$DEP_DIR/$name.dep";
+ if (open(DEP,$path)) {
+ $line = <DEP>;
+ close DEP;
+ next if $line eq $_;
+ }
+ open(DEP,">$path") || die "creat $path: $!";
+ print DEP $_ || die "write $path: $!";
+ close DEP || die "close $path: $!";
+}
+close CFG;

-- 
  _________________________________________________________________________
 / Werner Almesberger, DI-LRC,EPFL,CH   werner.almesberger@lrc.di.epfl.ch /
/_IN_R_133__Tel_+41_21_693_6621__Fax_+41_21_693_6610_____________________/