kim@enea.UUCP (Kim Walden) (04/10/85)
In response to all requests for my dependency generating program, which uses only source files as basis for generation, (general method described in: K. Walden, "Automatic Generation of Make Dependencies", Softw. Pract. & Exper., vol. 14(6), 575-585, June 1984), I am now posting it to net.sources, in the two following parts. It was developed for 4.2bsd, and I did not pay any special attention to portability. System V users must do the usual name changes CFLAGS="-Dindex=strchar -Drindex=strrchar" etc. The program deals correctly with included generated files, provided that the include statements are recognizable in the corresponding source files, and standard suffix conventions are used. If conditional includes, like #ifdef KERNEL & !defined(LOCORE) #include "foo" #else #include "bar" appear in the files, it may sometimes be possible to extend the recognition part so that only the relevant include statements are extracted (the distributed program uses only grep), but in the general case, only the C preprocessor may resolve the conditions correctly, and therefore one may be forced to use the newly added -M option of cpp instead. But then again, cpp -M cannot handle included generated files correctly. -- Kim Walden ENEA DATA Sweden UUCP: {seismo,decvax,philabs}!{mcvax,ukc,unido}!enea!kim ARPA: decvax!mcvax!enea!kim@berkeley.arpa mcvax!enea!kim@seismo.arpa
kim@enea.UUCP (Kim Walden) (04/10/85)
# This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # tool # This archive created: Wed Apr 10 14:06:20 1985 mkdir tool chdir tool sed 's/^XX//' << \SHAR_EOF > READ_ME XX******************************************************************* XX** ** XX** This distribution implements the algorithm described in ** XX** ** XX** K. Walden, "Automatic Generation of Make Dependencies", ** XX** Softw. Practice & Exper., vol. 14, no. 6, June 1984 ** XX** ** XX** Copyright (c) 1983 Kim Walden ** XX** ENEA DATA, Sweden and ** XX** SYSLAB, Department of Computer Science, ** XX** University of Stockholm, Sweden. ** XX** ** XX** The software may be used and copied freely, ** XX** provided that proper credit is given to the originator ** XX** by including this text label in each copy. ** XX** ** XX******************************************************************* XX XX XX XXSOURCES FUNCTION XX XXMakefile Make script to build the programs. XXmakedep.c Main program for extracting include statements XX and pipe them to makenorm and depend. XXmakenorm.y Include statement normalizer. XXnormscan.l Scanner for the normalizer. XXdepend.y Main dependency generator. XXdepscan.l Scanner for the dependency generator. XXmpath.c File name path reduction routine. XXerror.c Error handling routine. XX XXman Manuals subdirectory XXtest Subdirectory structure with test files. XX XX XX XX XXThe programs should be built invoking the Makefile, and the tool XXdirectory added to the command search path, so the programs can be XXfound when running the test below. XX XXWhen make is invoked on the test directory test/proc, the test XXexample in the above SP & E paper is run, and the output should be XXthe same as the contents of the file Dep.mk. XX XXMakedep and makenorm extract and normalize include statements that XXare directed to the C preprocessor. XXThese programs must be modified if include statements of other XXlanguages are to be handled, unless the include syntax and semantics XXhappen to be the same, while depend can be used unchanged. XX XXA general recommendation for Berkeley UNIX users is to get hold of XXthe augmented version of make available under AT & T System III/V, XXwhich has an include facility. XXAll generated dependencies can then be put in a separate file, XXwhich is made part of the ordinary make dependency graph. XX XXPorting the augmented make to run under Berkeley UNIX is not very XXdifficult, and mostly has to do with different formats of archive XXfiles. SHAR_EOF if test 2713 -ne "`wc -c READ_ME`" then echo shar: error transmitting READ_ME '(should have been 2713 characters)' fi sed 's/^XX//' << \SHAR_EOF > Makefile XXCFLAGS= -O -s XX XXOBJ1= mpath.o XXOBJ2= error.o XX XXall: makedep makenorm depend XX XXmakedep: makedep.o $(OBJ2) XX $(CC) $(CFLAGS) $@.o $(OBJ2) -o $@ XX XXmakenorm: makenorm.o $(OBJ1) $(OBJ2) XX $(CC) $(CFLAGS) $@.o $(OBJ1) $(OBJ2) -ll -o $@ XX XXdepend: depend.o $(OBJ2) XX $(CC) $(CFLAGS) $@.o $(OBJ2) -ll -o $@ XX XXmakenorm.o: normscan.c XXdepend.o: depscan.c XX XXclean: XX rm *.o XX rm makedep XX rm makenorm makenorm.c normscan.c XX rm depend depend.c depscan.c XX rm man/*.man XX XX.y.o: XX $(YACC) $(YFLAGS) $< XX @mv -f y.tab.c $*.c XX $(CC) $(CFLAGS) -c $*.c XX XX.y.c: XX $(YACC) $(YFLAGS) $< XX @mv -f y.tab.c $@ XX XX.l.o: XX $(LEX) $(LFLAGS) $< XX @mv -f lex.yy.c $*.c XX $(CC) $(CFLAGS) -c $*.c XX XX.l.c: XX $(LEX) $(LFLAGS) $< XX @mv -f lex.yy.c $@ SHAR_EOF if test 688 -ne "`wc -c Makefile`" then echo shar: error transmitting Makefile '(should have been 688 characters)' fi sed 's/^XX//' << \SHAR_EOF > depend.y XX%{ XX/* -- Make include dependency generator XX * XX * $File: depend.y 1.13 1985-03-29 14:06:29 $ XX * XX * Copyright (c) 1983 Kim Walden XX * ENEA DATA, Sweden and XX * SYSLAB, Department of Computer Science, XX * University of Stockholm, Sweden. XX * XX * This software may be used and copied freely, XX * provided that proper credit is given to the originator XX * by including the above text in each copy. XX * XX * Descr: This program implements part of the algorithm described in XX * K. Walden, "Automatic Generation of Make Dependencies", XX * Softw. Practice & Exper., vol. 14, no. 6, June 1984 XX * XX * $Log: depend.y,v $ XX * XX * Revision 1.13 1985-03-29 14:06:29 kim XX * New source format XX * XX * Revision 1.12 1985-03-08 01:16:37 kim XX * Added support for parallell transfer rules. XX * Added -1 option to makedep and depend. XX * XX * Revision 1.11 1985-02-25 19:40:21 kim XX * Path reduction moved to earlier stage XX * XX * Revision 1.10 1985-02-19 11:19:59 kim XX * New default include rules XX * XX * Revision 1.9 1985-02-18 14:23:55 kim XX * New error handling XX * XX * Revision 1.8 1985-02-14 13:59:52 kim XX * Changed rules options to -r/-R XX * XX * Revision 1.7 1985-02-14 01:53:19 kim XX * Converted to RCS format XX * XX * Revision 1.4 1983-10-06 19:50:16 kim XX * Allow empty include line input XX * XX * Revision 1.3 1983-07-20 19:50:00 kim XX * Closer to algorithm in SYSLAB Report No. 19 (June 1983) XX * XX * Revision 1.2 1983-02-22 19:49:51 kim XX * First version with include rules XX * XX * Revision 1.1 1982-12-15 19:49:47 kim XX * Initial revision XX */ XX%} XX XX%token SPACE RULSEP INCSEP PATH SUFF XX%{ XX# define PREF struct pref XX# define SUF struct suf XX# define INCFILE struct incfile XX# define LHSFILE struct lhsfile XX# define NAME struct filename XX# define OUTSIZ 10 XX# define PATHSIZ 100 XX# define DIRSIZ 14 XX# define LINSIZ 256 XX# define PHASHL 503 XX# define LINE 80 XX# define INCLUDED 1 XX# define CNULL '\0' XX# define KOL ':' XX# define EQU '=' XX# define RULES ".o: .c .p .f; .c= .y .l .q; .h= .y" XX XX# include <stdio.h> XX# include <strings.h> XX XXstatic char usage[]= "Usage: depend [-1] [-rfile] [-Rrules]"; XX XX/* File name prefixes XX */ XXPREF XX{ XX PREF * nexthash; XX char path[PATHSIZ+1]; XX}; XX XX/* File name suffixes: XX * XX * If the suffix occurs in the rhs of a rule, XX * the output file suffix and rule type XX * (KOL or EQU) is recorded. XX */ XXSUF XX{ XX SUF * next, XX * out[OUTSIZ]; XX char name[DIRSIZ+1]; XX int top, XX rule; XX}; XX XX/* List of files included by a given file. XX */ XXINCFILE XX{ XX INCFILE * next; XX PREF * pf; XX SUF * sf; XX}; XX XX/* A node for each file found in the lhs of some include statement. XX * The transfer rules are successively applied to the suffix XX * before the file is inserted. XX * Reference to list of included files. XX */ XXLHSFILE XX{ XX LHSFILE * next; XX PREF * pf; XX SUF * sf; XX INCFILE * ic; XX int state; XX}; XX XXNAME XX{ XX PREF * pf; XX SUF * sf; XX}; XX XXstruct XX{ XX SUF * sf; XX LHSFILE * lf; XX} first; XX XX XXextern char * calloc(); XXvoid yyerror(); XX XXstatic NAME getname(), XX lhs, XX rhs; XXstatic LHSFILE * nodelf(), XX * thislf; XXstatic PREF * nodepf(), XX * phash[PHASHL]; XXstatic SUF * nodesf(), XX * lsuf, XX * rsuf; XXstatic char * alloc(), XX * rulstring, XX * yystring; XXstatic char line[LINSIZ]; XXstatic void printdep(), XX copyinc(), XX nodeic(); XXstatic int hash(), XX lineno, XX rule, XX onedep; XX XX# include "depscan.c" XX XXmain(argc, argv) XX int argc; XX char * argv[]; XX{ XX char rulbuf[LINSIZ]; XX XX setprogname(argv[0]); XX rulstring = rulbuf; XX strcpy(rulbuf, RULES); XX XX while (argc > 1 && argv[1][0] == '-') XX { XX switch (argv[1][1]) XX { XX case 'r': XX strcat(rulbuf, "; "); XX strcat(rulbuf, argv[1]+2); XX break; XX XX case 'R': XX rulstring = argv[1]+2; XX break; XX XX case '1': XX onedep++; XX break; XX XX default: XX fatal("unknown option %s", argv[1]); XX } XX XX argv++; XX argc--; XX } XX XX if (argc != 1) XX fatalmesg(usage); XX XX yystring = rulstring; XX BEGIN rules; XX XX first.lf = NULL; XX yyparse(); XX if (first.lf) XX printdep(); XX exit(0); XX} XX%} XX XX%% XX XXaccept : rules includes XX ; XXrules : rule XX | RULSEP rules XX | rules RULSEP XX | rules RULSEP rule XX ; XXrule : ':' SPACE XX { /* Lhs of inclusion rule, empty output suffix */ XX lsuf = nodesf(""); XX rule = KOL; XX } XX rhssuf XX | lhssuf ':' SPACE XX { /* Lhs of inclusion rule */ XX rule = KOL; XX } XX rhssuf XX | lhssuf '=' SPACE XX { /* Lhs of transfer rule */ XX rule = EQU; XX } XX rhssuf XX | rule SPACE rhssuf XX ; XXlhssuf : SUFF XX { /* Lhs of any rule */ XX lsuf = nodesf(yytext); XX } XX ; XXrhssuf : SUFF XX { /* Rhs of any rule */ XX rsuf = nodesf(yytext); XX if (rsuf->rule && (rsuf->rule != EQU || rule != EQU)) XX fatal("ambiguous rules %s", rulstring); XX rsuf->rule = rule; XX if (rsuf->top >= OUTSIZ) XX fatal("to many parallel transfers %s", rulstring); XX rsuf->out[rsuf->top++] = lsuf; XX } XX ; XXincludes: XX | includes INCSEP XX | includes INCSEP include XX ; XXinclude : PATH XX { /* Lhs of include statement: XX * Insert in lhsfile list. XX */ XX lhs = getname(yytext); XX thislf = nodelf(lhs.pf, lhs.sf); XX } XX SPACE '<' SPACE XX PATH XX { /* Rhs of include statement: XX * Append to include list of lhsfile. XX */ XX rhs = getname(yytext); XX nodeic(thislf, rhs.pf, rhs.sf); XX } XX ; XX XX%% XX XXvoid XXyyerror(s) XX char * s; XX{ XX if (yystring) XX fatal("%s rules: %s", s, rulstring); XX else XX fatal("%s near line %d: %s", s, lineno, line); XX} XX XX/* Go through lhsfile list and print implied Make dependencies. XX */ XXstatic void XXprintdep() XX{ XX LHSFILE * lf, XX * lf2; XX SUF * sf; XX INCFILE * ic; XX int i; XX XX /* Apply transfer rules to the LHS suffixes. XX * If there are more than one output suffix, XX * make a new LHS node with a copy of the include list for each of them. XX * XX * Since the new nodes are inserted at the end of the LHS list, XX * they will be dealt with again, later in the for-loop. XX */ XX for (lf = first.lf; lf; lf = lf->next) XX while (lf->sf->rule == EQU) XX { XX for (i = 1; i < lf->sf->top; i++) XX copyinc(lf, nodelf(lf->pf, lf->sf->out[i])); XX XX lf->sf = lf->sf->out[0]; XX } XX XX /* Construct Transitive Closure. XX */ XX for (lf = first.lf; lf; lf = lf->next) XX for (lf2 = first.lf; lf2; lf2 = lf2->next) XX for (ic = lf2->ic; ic; ic = ic->next) XX if (ic->pf == lf->pf && ic->sf == lf->sf) XX { XX lf->state = INCLUDED; XX copyinc(lf, lf2); XX break; XX } XX XX /* For each lhs file, apply inclusion rules XX * and generate Make dependencies. XX */ XX for (lf = first.lf; lf; lf = lf->next) XX { XX char lhsdep[PATHSIZ+1], rhsdep[PATHSIZ+1]; XX int brk = 0; XX XX /* If the file was included in some other file, XX * no separate output file will be generated for it. XX * The corresponding dependencies have thus already XX * been taken care of. XX */ XX if (lf->state == INCLUDED) XX continue; XX XX sf = lf->sf; XX XX /* If the file was not included in any other file, XX * and there is no inclusion rule for its suffix, XX * the file is discarded. XX */ XX if (sf->rule != KOL) XX continue; XX XX sprintf(lhsdep, "%s%s", lf->pf->path, sf->out[0]->name); XX sprintf(line, "%s:", lhsdep); XX XX for (ic = lf->ic; ic; ic = ic->next) XX { XX sprintf(rhsdep, "%s%s", ic->pf->path, ic->sf->name); XX XX if (strlen(line)+strlen(rhsdep)+1 > LINE || brk) XX { XX printf("%s\n", line); XX sprintf(line, "%s:", lhsdep); XX } XX strcat(line, " "); XX strcat(line, rhsdep); XX brk = onedep; XX } XX printf("%s\n", line); XX } XX} XX XX/* Copy entire include file list. XX * XX */ XXstatic void XXcopyinc(from, to) XX LHSFILE * from, XX * to; XX{ XX INCFILE * ic; XX XX for (ic = from->ic; ic; ic = ic->next) XX nodeic(to, ic->pf, ic->sf); XX} XX XX/* Return file name. XX * XX */ XXstatic NAME XXgetname(path) XX char * path; XX{ XX NAME nm; XX char * p; XX int c; XX XX if (strlen(path) > PATHSIZ) XX fatal("path too long: %s", path); XX XX if ((p = rindex(path, '/')) == NULL) XX p = path; XX XX if ((p = rindex(p, '.')) == NULL) XX p = path + strlen(path); XX XX nm.sf = nodesf(p); XX c = *p; XX *p = CNULL; XX nm.pf = nodepf(path); XX *p = c; XX XX return nm; XX} XX XX/* Return suffix node. XX * If the given suffix was not in the suffix list, XX * allocate a new node. XX */ XXstatic SUF * XXnodesf(name) XX char * name; XX{ XX SUF * node, XX * prev; XX XX for (prev = node = first.sf; node; prev = node, node = node->next) XX if (strcmp(name, node->name) == 0) XX return node; XX XX node = (SUF *) alloc(sizeof(SUF), name); XX strcpy(node->name, name); XX XX if (prev) XX prev->next = node; XX else XX first.sf = node; XX XX return node; XX} XX XX/* Return prefix node. XX * If the given (reduced) path was not in the prefix list, XX * allocate a new node. XX */ XXstatic PREF * XXnodepf(path) XX char * path; XX{ XX PREF * node, XX * prevhash; XX int h; XX XX h = hash(path, PHASHL); XX XX for (node = phash[h]; node; node = node->nexthash) XX if (strcmp(path, node->path) == 0) XX return node; XX else XX prevhash = node; XX XX node = (PREF *) alloc(sizeof(PREF), path); XX strcpy(node->path, path); XX XX if (phash[h]) XX prevhash->nexthash = node; XX else XX phash[h] = node; XX XX return node; XX} XX XX/* Return lhsfile node. XX * If the given lhsfile was not in the lhsfile list, XX * allocate a new node. XX */ XXstatic LHSFILE * XXnodelf(pf, sf) XX PREF * pf; XX SUF * sf; XX{ XX LHSFILE * node, XX * prev; XX XX for (prev = node = first.lf; node; prev = node, node = node->next) XX if (node->pf == pf && node->sf == sf) XX return node; XX XX node = (LHSFILE *) alloc(sizeof(LHSFILE), line); XX XX node->pf = pf; XX node->sf = sf; XX XX if (prev) XX prev->next = node; XX else XX first.lf = node; XX XX return node; XX} XX XX/* Add the given rhsfile to the include list XX * of the given lhsfile, XX * if it was not there already. XX */ XXstatic void XXnodeic(lf, pf, sf) XX LHSFILE * lf; XX PREF * pf; XX SUF * sf; XX{ XX INCFILE * node, XX * prev; XX XX if (sf->rule == EQU) XX /* Must follow the Suffix Convention for Included Files. XX */ XX fatal("bad include file suffix %s%s < %s%s", XX lf->pf->path, lf->sf->name, pf->path, sf->name); XX XX for (prev = node = lf->ic; node; prev = node, node = node->next) XX if (node->pf == pf && node->sf == sf) XX return; XX XX if (pf == lf->pf && sf == lf->sf) XX { XX error("infinite recursion on %s%s - dependency ignored", pf->path, sf->name); XX return; XX } XX XX node = (INCFILE *) alloc(sizeof(INCFILE), line); XX node->pf = pf; XX node->sf = sf; XX XX if (prev) XX prev->next = node; XX else XX lf->ic = node; XX} XX XX/* Allocate a zero initialized node. XX */ XXstatic char * XXalloc(size, obj) XX char * obj; XX{ XX char * node; XX XX if ((node = calloc(1, size)) == NULL) XX fatal("can't alloc: %s", obj); XX XX return node; XX} XX XX/* Hash a character string, and return the hash value XX * modulo the given hash length. XX */ XXstatic int XXhash(p, hashl) XX char * p; XX int hashl; XX{ XX register unsigned sum; XX register c; XX XX sum = 0; XX while ((c = *p++) != 0) XX { XX if (sum & 01) XX sum = (sum >> 1) + 0x8000; XX else XX sum >>= 1; XX sum += c; XX sum &= 0xFFFF; XX } XX return sum % hashl; XX} SHAR_EOF if test 10650 -ne "`wc -c depend.y`" then echo shar: error transmitting depend.y '(should have been 10650 characters)' fi sed 's/^XX//' << \SHAR_EOF > makenorm.y XX%{ XX/* -- Normalize include references XX * XX * $File: makenorm.y 1.8 1985-03-29 14:11:19 $ XX * XX * Copyright (c) 1983 Kim Walden XX * ENEA DATA, Sweden and XX * SYSLAB, Department of Computer Science, XX * University of Stockholm, Sweden. XX * XX * This software may be used and copied freely, XX * provided that proper credit is given to the originator XX * by including the above text in each copy. XX * XX * Descr: This program implements part of the algorithm described XX * in K. Walden, "Automatic Generation of Make Dependencies", XX * Softw. Practice & Exper., vol. 14, no. 6, June 1984 XX * XX * XX * $Log: makenorm.y,v $ XX * XX * Revision 1.8 1985-03-29 14:11:19 kim XX * New source format XX * XX * Revision 1.7 1985-03-21 09:31:11 kim XX * Use sprintf in a System V compatible way XX * XX * Revision 1.6 1985-03-08 01:18:35 kim XX * Added support for parallell transfer rules. XX * Added -1 option to makedep and depend. XX * XX * Revision 1.5 1985-02-25 19:41:56 kim XX * Added -a option for absolute directories XX * XX * Revision 1.4 1985-02-20 11:53:09 kim XX * Bug fix XX * XX * Revision 1.3 1985-02-19 11:21:23 kim XX * New default include rules XX * XX * Revision 1.2 1985-02-18 14:24:15 kim XX * New error handling XX * XX * Revision 1.1 1985-02-16 18:57:07 kim XX * Initial revision XX */ XX%} XX XX%token SPACE RULSEP INCSEP PATH SUFF INCL QUOTE LPAR RPAR XX%{ XX# define DIRLIST struct dirlist XX# define PREF struct pref XX# define SUF struct suf XX# define SOURCE struct source XX# define NAME struct filename XX# define PATHSIZ 100 XX# define DIRSIZ 14 XX# define LINSIZ 256 XX# define OUTSIZ 10 XX# define PHASHL 503 XX# define LINE 80 XX# define EXACT 0 XX# define DERIVED 1 XX# define FORCE 2 XX# define NOREDUCE 0 XX# define REDUCE 1 XX# define FALSE 0 XX# define TRUE 1 XX# define CNULL '\0' XX# define KOL ':' XX# define EQU '=' XX# define RULES ".o: .c; .c= .y .l .q; .h= .y" XX XX# include <stdio.h> XX# include <strings.h> XX# include <sys/types.h> XX# include <sys/stat.h> XX XXstatic char usage[]= XX"Usage: makenorm [-rfile] [-Rrules] [-Ilist] [-alist] [-i] makedir sourcefiles"; XX XX/* Directory lists XX */ XXDIRLIST XX{ XX DIRLIST * next; XX char path[PATHSIZ+1]; XX}; XX XX/* File name prefixes (including directory part) XX */ XXPREF XX{ XX PREF * nexthash; XX char path[PATHSIZ+1]; XX}; XX XX/* File name suffixes: XX * XX * If the suffix occurs in the rhs of a rule, XX * the output file suffix and rule type XX * (KOL or EQU) is recorded. XX */ XXSUF XX{ XX SUF * next, XX * out[OUTSIZ]; XX char name[DIRSIZ+1]; XX int top, XX rule; XX}; XX XX/* Declared sources: XX * XX * The transfer rules are successively applied XX * to the suffix before a file is inserted. XX */ XXSOURCE XX{ XX SOURCE * next; XX PREF * pf; XX SUF * sf; XX}; XX XX/* File names XX */ XXNAME XX{ XX PREF * pf; XX SUF * sf; XX}; XX XX XXstruct XX{ XX SOURCE * so; /* source list */ XX SUF * sf; /* suffix list */ XX DIRLIST * idir, /* list of include directories */ XX * adir; /* list of absolute directories */ XX} first; XX XXextern char * calloc(), XX * mpath(); XXvoid yyerror(); XXstatic PREF * nodepf(), XX * phash[PHASHL]; /* hash table for prefixes */ XXstatic SUF * nodesf(), XX * lsuf, XX * rsuf; XXstatic NAME getname(), XX lhs, XX rhs; XXstatic char * alloc(), XX * makedir, XX * rulstring, XX * yystring; XXstatic char line[LINSIZ]; XXstatic int derived(), XX hash(), XX findso(), XX printcond(), XX lineno, XX rule, XX remote, XX sysflag; XXstatic void getdirlist(), XX nodedl(), XX printnorm(); XX XX# include "normscan.c" XX XXmain(argc, argv) XX int argc; XX char * argv[]; XX{ XX char rulbuf[LINSIZ]; XX XX setprogname(argv[0]); XX rulstring = rulbuf; XX strcpy(rulbuf, RULES); XX nodedl("/usr/include", &first.adir); XX sysflag = 0; XX XX while (argc > 1 && argv[1][0] == '-') XX { XX switch (argv[1][1]) XX { XX case 'r': XX strcat(rulbuf, "; "); XX strcat(rulbuf, argv[1]+2); XX break; XX XX case 'R': XX rulstring = argv[1]+2; XX break; XX XX case 'i': XX sysflag++; XX break; XX XX case 'a': XX case 'I': XX getdirlist(argv[1]); XX break; XX XX default: XX error("unknown option %s", argv[1]); XX fatalmesg(usage); XX } XX XX argv++; XX argc--; XX } XX XX if (argc < 2) XX fatalmesg(usage); XX makedir = argv[1]; XX argv ++; XX argc --; XX XX if (argc < 2) XX fatal("no source files specified"); XX XX while (--argc) XX findso(getname(argv++[1], REDUCE), FORCE); XX XX yystring = rulstring; XX BEGIN rules; XX XX yyparse(); XX exit(0); XX} XX%} XX XX%% XX XXaccept : rules includes XX ; XXrules : rule XX | RULSEP rules XX | rules RULSEP XX | rules RULSEP rule XX ; XXrule : ':' SPACE XX { /* Lhs of inclusion rule, empty output suffix */ XX lsuf = nodesf(""); XX rule = KOL; XX } XX rhssuf XX | lhssuf ':' SPACE XX { /* Lhs of inclusion rule */ XX rule = KOL; XX } XX rhssuf XX | lhssuf '=' SPACE XX { /* Lhs of transfer rule */ XX rule = EQU; XX } XX rhssuf XX | rule SPACE rhssuf XX ; XXlhssuf : SUFF XX { /* Lhs of any rule */ XX lsuf = nodesf(yytext); XX } XX ; XXrhssuf : SUFF XX { /* Rhs of any rule */ XX rsuf = nodesf(yytext); XX if (rsuf->rule && (rsuf->rule != EQU || rule != EQU)) XX fatal("ambiguous rules %s", rulstring); XX rsuf->rule = rule; XX if (rsuf->top >= OUTSIZ) XX fatal("to many parallel transfers %s", rulstring); XX rsuf->out[rsuf->top++] = lsuf; XX } XX ; XXincludes: XX | includes INCSEP XX | includes INCSEP include XX ; XXinclude : lhs XX QUOTE XX { remote = 0; } XX rhs XX QUOTE XX { unput('#'); XX BEGIN comment; XX } XX | lhs XX LPAR XX { remote = 1; } XX rhs XX RPAR XX { unput('#'); XX BEGIN comment; XX } XX ; XXlhs : PATH XX { /* Lhs of include statement: XX * Reduce filename, and check that XX * file name was in the source list. XX */ XX lhs = getname(yytext, REDUCE); XX if (!findso(lhs, EXACT)) XX error("%s not in source list", XX yytext); XX } XX ':' INCL XX ; XXrhs : PATH XX { /* Rhs of include statement: XX * Resolve file reference and print XX * normalized include statement. XX */ XX rhs = getname(yytext, NOREDUCE); XX if (rhs.sf->rule == EQU) XX fatal("bad include file suffix: %s", XX line); XX printnorm(); XX } XX ; XX XX%% XX XXvoid XXyyerror(s) XX char * s; XX{ XX if (yystring) XX fatal("%s rules: %s", s, rulstring); XX else XX fatal("%s near line %d: %s", s, lineno, line); XX} XX XX/* Resolve current include file reference and print XX * the corresponding normalized include statement. XX */ XXstatic void XXprintnorm() XX{ XX DIRLIST * dl; XX char * p; XX char dir[PATHSIZ+1]; XX XX /* Try directory of left hand side file when XX * format: #include "file". XX */ XX if (!remote) XX { XX strcpy(dir, lhs.pf->path); XX XX if ((p = rindex(dir, '/')) == NULL) XX p = dir; XX XX *p = CNULL; XX XX if (printcond(dir)) XX return; XX } XX XX /* Try user include libraries */ XX XX for (dl = first.idir; dl; dl = dl->next) XX if (printcond(dl->path)) XX return; XX XX /* Try system include library */ XX XX if (printcond("/usr/include")) XX return; XX XX error("cannot resolve: %s", line); XX} XX XXstatic int XXprintcond(dir) XX char * dir; XX{ XX struct stat stbuf; XX NAME nm; XX char buf[PATHSIZ+1]; XX XX /* If include reference is not absolute, XX * prepend directory. XX */ XX XX if (strlen(dir) != 0 && rhs.pf->path[0] != '/') XX sprintf(buf, "%s/%s%s", dir, rhs.pf->path, rhs.sf->name); XX else XX sprintf(buf, "%s%s", rhs.pf->path, rhs.sf->name); XX XX nm = getname(buf, REDUCE); XX XX sprintf(buf, "%s%s", nm.pf->path, nm.sf->name); XX XX /* If the resulting file name path can be derived from a source, XX * accept include reference and print dependency. XX */ XX if (findso(nm, DERIVED)) XX { XX printf("%s%s < %s\n", lhs.pf->path, lhs.sf->name, buf); XX return TRUE; XX } XX XX /* Ignore system include references not specified as sources, XX * unless -i option was specified. XX */ XX if (strncmp(buf, "/usr/include/", strlen("/usr/include/")) == 0 XX && !sysflag && (stat(buf, &stbuf) == 0)) XX return TRUE; XX XX return FALSE; XX} XX XX XX/* Return file name, XX * reduced if flag == REDUCE. XX */ XXstatic NAME XXgetname(path, flag) XX char * path; XX int flag; XX{ XX NAME nm; XX DIRLIST * dl; XX char * mp, XX * p; XX char buf[PATHSIZ+1]; XX int c; XX XX mp = path; XX XX if (flag == REDUCE ) XX { XX int absdir = 0; XX XX /* Make reference absolute */ XX if (*path != '/') XX { XX sprintf(buf, "%s/%s", makedir, path); XX path = buf; XX } XX XX /* If the file name refers to one of the absolute directories, XX * it should be in absolute form. XX */ XX for (dl = first.adir; dl; dl = dl->next) XX { XX if ((mp = mpath(path, dl->path)) == NULL) XX fatal("can't reduce path"); XX XX if (strncmp(mp, "../", 3) != 0) XX { XX if (strlen(mp)+strlen(dl->path)+1 > PATHSIZ) XX fatal("path too long: %s/%s", XX dl->path, mp); XX XX absdir++; XX sprintf(buf, "%s/%s", dl->path, mp); XX mp = buf; XX break; XX } XX } XX XX /* If the file name does not refer to any of the XX * absolute directories, it should be in relative form. XX */ XX if (!absdir) XX { XX if ((mp = mpath(path, makedir)) == NULL) XX fatal("can't reduce path"); XX XX if (strlen(mp) > PATHSIZ) XX fatal("path too long: %s", mp); XX } XX } XX XX XX if ((p = rindex(mp, '/')) == NULL) XX p = mp; XX XX if ((p = rindex(p, '.')) == NULL) XX p = mp + strlen(mp); XX XX nm.sf = nodesf(p); XX c = *p; XX *p = CNULL; XX nm.pf = nodepf(mp); XX *p = c; XX XX return nm; XX} XX XXstatic char * XXgetword(p, buf) XX char * p, XX * buf; XX{ XX while (*p == ' ' || *p == '\t') XX p++; XX XX if (*p == CNULL) XX return NULL; XX XX while (*p != ' ' && *p != '\t' && *p != CNULL) XX *buf++ = *p++; XX XX *buf = CNULL; XX return p; XX} XX XXstatic void XXgetdirlist(arg) XX char * arg; XX{ XX DIRLIST ** head; XX char * s; XX char buf[PATHSIZ+1]; XX XX if (arg[1] == 'a') XX head = &first.adir; XX else XX head = &first.idir; XX XX s = arg; XX s += 2; XX while (s = getword(s, buf)) XX { XX if (arg[1] == 'a' && buf[0] != '/') XX fatal("directory list must be absolute: %s", arg); XX XX nodedl(buf, head); XX } XX} XX XX/* Return suffix node. XX * If the given suffix was not in the suffix list, XX * allocate a new node. XX */ XXstatic SUF * XXnodesf(name) XX char * name; XX{ XX SUF * node, XX * prev; XX XX for (prev = node = first.sf; node; prev = node, node = node->next) XX if (strcmp(name, node->name) == 0) XX return node; XX XX node = (SUF *) alloc(sizeof(SUF), name); XX strcpy(node->name, name); XX XX if (prev) XX prev->next = node; XX else XX first.sf = node; XX XX return node; XX} XX XX/* Return prefix node. XX * If the given (reduced) path was not in the prefix list, XX * allocate a new node. XX */ XXstatic PREF * XXnodepf(path) XX char * path; XX{ XX PREF * node, XX * prevhash; XX int h; XX XX h = hash(path, PHASHL); XX XX for (node = phash[h]; node; node = node->nexthash) XX if (strcmp(path, node->path) == 0) XX return node; XX else XX prevhash = node; XX XX node = (PREF *) alloc(sizeof(PREF), path); XX strcpy(node->path, path); XX XX if (phash[h]) XX prevhash->nexthash = node; XX else XX phash[h] = node; XX XX return node; XX} XX XX/* Search the source list for the given file name: XX * XX * 1. flag = EXACT Look for exact match. XX * Return TRUE if found, else FALSE XX * XX * 2. flag = FORCE Look for exact match. XX * If not found, allocate a new node. XX * Always return TRUE. XX * XX * 3. flag = DERIVED Return TRUE if a match can be found by applying XX * transfer rules to the file name suffixes in the XX * source list, else FALSE. XX */ XXstatic int XXfindso(nm, flag) XX NAME nm; XX int flag; XX{ XX SOURCE * node, XX * prev; XX XX for (prev = node = first.so; node; prev = node, node = node->next) XX if (node->pf == nm.pf XX && (node->sf == nm.sf || DERIVED && derived(nm.sf, node->sf))) XX return TRUE; XX XX if (flag == FORCE) XX { XX node = (SOURCE *) alloc(sizeof(SOURCE), line); XX XX node->pf = nm.pf; XX node->sf = nm.sf; XX XX if (prev) XX prev->next = node; XX else XX first.so = node; XX XX return TRUE; XX } XX else XX return FALSE; XX} XX XX/* If dsf is same as sf, or can be derived from it by applying XX * a number of transfer rules, return TRUE, else FALSE XX */ XXstatic int XXderived(dsf, sf) XX SUF * dsf, XX * sf; XX{ XX int i; XX XX if (dsf == sf) XX return TRUE; XX XX if (sf->rule != EQU) XX return FALSE; XX XX for (i = 0; i < sf->top; i++) XX if (derived(dsf, sf->out[i])) XX return TRUE; XX XX return FALSE; XX} XX XX/* Append directory to search list. XX */ XXstatic void XXnodedl(path, head) XX char * path; XX DIRLIST ** head; XX{ XX DIRLIST * node, XX * prev; XX XX for (prev = node = *head; node; prev = node, node = node->next) XX if (strcmp(path, node->path) == 0) XX return; XX XX node = (DIRLIST *) alloc(sizeof(DIRLIST), path); XX strcpy(node->path, path); XX XX if (prev) XX prev->next = node; XX else XX *head = node; XX XX return; XX} XX XX XX/* Allocate a zero initialized node. XX */ XXstatic char * XXalloc(size, obj) XX char * obj; XX{ XX char * node; XX XX if ((node = calloc(1, size)) == NULL) XX fatal("can't alloc %s", obj); XX XX return node; XX} XX XX/* Hash a character string, and return the hash value XX * modulo the given hash length. XX */ XXstatic int XXhash(p, hashl) XX char * p; XX int hashl; XX{ XX register unsigned sum; XX register c; XX XX sum = 0; XX while ((c = *p++) != 0) XX { XX if (sum & 01) XX sum = (sum >> 1) + 0x8000; XX else XX sum >>= 1; XX sum += c; XX sum &= 0xFFFF; XX } XX return sum % hashl; XX} SHAR_EOF if test 12659 -ne "`wc -c makenorm.y`" then echo shar: error transmitting makenorm.y '(should have been 12659 characters)' fi chdir .. # End of shell archive exit 0 -- Kim Walden ENEA DATA Sweden UUCP: {seismo,decvax,philabs}!{mcvax,ukc,unido}!enea!kim ARPA: decvax!mcvax!enea!kim@berkeley.arpa mcvax!enea!kim@seismo.arpa
kim@enea.UUCP (Kim Walden) (04/10/85)
# This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # tool # This archive created: Wed Apr 10 14:07:18 1985 mkdir tool chdir tool mkdir test chdir test mkdir h chdir h sed 's/^XX//' << \SHAR_EOF > cons.h XX# include "../proc/globs.h" SHAR_EOF if test 28 -ne "`wc -c cons.h`" then echo shar: error transmitting cons.h '(should have been 28 characters)' fi chdir .. mkdir proc chdir proc sed 's/^XX//' << \SHAR_EOF > Makefile XX# Makefile using automatic dependency generation. XX XXSRCS= convert.l error.h globs.h parser.y \ XX prog.c scanner.l tab.h ../h/cons.h XX XXdepend: XX @makedep $(SRCS) SHAR_EOF if test 162 -ne "`wc -c Makefile`" then echo shar: error transmitting Makefile '(should have been 162 characters)' fi sed 's/^XX//' << \SHAR_EOF > tab.h SHAR_EOF if test 0 -ne "`wc -c tab.h`" then echo shar: error transmitting tab.h '(should have been 0 characters)' fi sed 's/^XX//' << \SHAR_EOF > scanner.l XX# include "../h/cons.h" XX# include "error.h" SHAR_EOF if test 44 -ne "`wc -c scanner.l`" then echo shar: error transmitting scanner.l '(should have been 44 characters)' fi sed 's/^XX//' << \SHAR_EOF > prog.c XX# include "error.h" SHAR_EOF if test 20 -ne "`wc -c prog.c`" then echo shar: error transmitting prog.c '(should have been 20 characters)' fi sed 's/^XX//' << \SHAR_EOF > parser.y XX# include "scanner.c" XX#include "tab.h" SHAR_EOF if test 39 -ne "`wc -c parser.y`" then echo shar: error transmitting parser.y '(should have been 39 characters)' fi sed 's/^XX//' << \SHAR_EOF > globs.h XX SHAR_EOF if test 1 -ne "`wc -c globs.h`" then echo shar: error transmitting globs.h '(should have been 1 characters)' fi sed 's/^XX//' << \SHAR_EOF > error.h SHAR_EOF if test 0 -ne "`wc -c error.h`" then echo shar: error transmitting error.h '(should have been 0 characters)' fi sed 's/^XX//' << \SHAR_EOF > convert.l XX# include "../h/cons.h" SHAR_EOF if test 24 -ne "`wc -c convert.l`" then echo shar: error transmitting convert.l '(should have been 24 characters)' fi sed 's/^XX//' << \SHAR_EOF > Dep.mk XXconvert.o: ../h/cons.h globs.h XXparser.o: scanner.c tab.h ../h/cons.h error.h globs.h XXprog.o: error.h SHAR_EOF if test 101 -ne "`wc -c Dep.mk`" then echo shar: error transmitting Dep.mk '(should have been 101 characters)' fi chdir .. chdir .. sed 's/^XX//' << \SHAR_EOF > mpath.c XX/* -- Minimal file path XX * XX * $File: mpath.c 1.3 1985-03-29 14:12:00 $ XX * XX * Copyright (c) 1983 Kim Walden XX * ENEA DATA, Sweden and XX * SYSLAB, Department of Computer Science, XX * University of Stockholm, Sweden. XX * XX * This software may be used and copied freely, XX * provided that proper credit is given to the originator XX * by including the above Copyright lines in each copy. XX * XX * Usage: mpath(filename, currdir) XX * XX * A pointer to the minmal path of 'filename' XX * relative to directory 'currdir' is returned. XX * XX * If 'filename' is not given in absolute form, XX * it is taken to be relative to 'currdir'. XX * XX * 'currdir' must be given in absolute form. XX * XX * E.g.: XX * XX * 1. mpath("/usr/src/doc", "/usr/src/cmd") --> "../doc" XX * XX * 2. mpath("../../src/doc/csh/..", "/usr/src/cmd") --> "../doc" XX * XX * $Log: mpath.c,v $ XX * XX * Revision 1.3 1985-03-29 14:12:00 kim XX * New source format XX * XX * Revision 1.2 1985-02-18 14:24:24 kim XX * New error handling XX */ XX XX# define LINSIZ 256 XX# define MAXLEVEL 100 XX# define CNULL '\0' XX XX# include <stdio.h> XX XXchar * mpath(); XXint split(), XX reduce(); XX XXchar * XXmpath(filename, currdir) XX char * filename, XX * currdir; XX{ XX static char buf[LINSIZ]; XX char * nm[MAXLEVEL], XX * cd[MAXLEVEL]; XX int nmlen, XX cdlen, XX i, XX k; XX XX if (strlen(filename)+strlen(currdir) > LINSIZ-2) XX { XX error("too long path: %s/%s", currdir, filename); XX return NULL; XX } XX XX if (currdir[0] != '/') XX { XX error("directory not absolute: %s", currdir); XX return NULL; XX } XX XX /* Split the path strings of current directory and filename XX ** into arrays of characters pointers XX */ XX cdlen = split(currdir, cd, '/'); XX XX if (filename[0] != '/') XX sprintf(buf, "%s/%s", currdir, filename); XX else XX strcpy(buf, filename); XX XX nmlen = split(buf, nm, '/'); XX XX /* Remove "//", "/.", and "x/.." entries */ XX XX cdlen = reduce(cd, cdlen); XX nmlen = reduce(nm, nmlen); XX XX /* Both strings are now absolute and normalized, XX ** find out how far they match from root down XX */ XX for (i = 0; i < cdlen && i < nmlen; i++) XX if (strcmp(cd[i], nm[i]) != 0) XX break; XX XX /* Concatenate the required number of ".." references XX ** needed to reach the point of divergence. XX */ XX buf[0] = CNULL; XX XX for (k = 0; k < cdlen-i; k++) XX { XX if (buf[0] != CNULL) XX strcat(buf, "/"); XX strcat(buf, ".."); XX } XX XX /* Append the rest of the filename path */ XX XX for (k = 0; k < nmlen-i; k++) XX { XX if (buf[0] != CNULL) XX strcat(buf, "/"); XX strcat(buf, nm[i+k]); XX } XX XX /* Empty means "." reference */ XX XX if (strlen(buf) == 0) XX strcpy(buf, "."); XX XX return buf; XX} XX XXstatic int XXsplit(s, array, sep) XX char * s, XX * array[]; XX{ XX char * index(), XX * p; XX int n = 0; XX XX /* Split string on given separator into array. XX ** Works much like the split function of awk. XX */ XX if ((p = (char *) calloc(1, strlen(s)+1)) == NULL) XX { XX error("can't allocate: %s", s); XX return NULL; XX } XX XX strcpy(p, s); XX XX array[n++] = p; XX while ((p = index(p, sep)) != NULL) XX { XX *p++ = CNULL; XX array[n++] = p; XX } XX XX return n; XX} XX XX XXstatic int XXreduce(array, len) XX char * array[]; XX{ XX int af, XX bf; XX XX /* Remove ".", "..", and empty references from array, XX ** by shifting the cells. XX */ XX for (af = bf = 0; bf < len; bf++) XX { XX if (strlen(array[bf]) == 0 || XX strcmp(array[bf], ".") == 0) XX continue; XX XX if (strcmp(array[bf], "..") == 0) XX { XX if (af == 0) XX continue; XX XX af -= 1; XX } XX else XX array[af++] = array[bf]; XX } XX XX return af; XX} SHAR_EOF if test 3421 -ne "`wc -c mpath.c`" then echo shar: error transmitting mpath.c '(should have been 3421 characters)' fi sed 's/^XX//' << \SHAR_EOF > makedep.c XX/* -- Make dependency generator XX * XX * $File: makedep.c 1.3 1985-03-29 14:46:31 $ XX * XX * Copyright (c) 1983 Kim Walden XX * ENEA DATA, Sweden and XX * SYSLAB, Department of Computer Science, XX * University of Stockholm, Sweden. XX * XX * This software may be used and copied freely, XX * provided that proper credit is given to the originator XX * by including the above text in each copy. XX * XX * Descr: This program implements part of the algorithm described XX * in K. Walden, "Automatic Generation of Make Dependencies", XX * Softw. Practice & Exper., vol. 14, no. 6, June 1984 XX * $Log: makedep.c,v $ XX * XX * Revision 1.3 1985-03-29 14:46:31 kim XX * New source format XX * XX * Revision 1.3 1985-03-29 14:11:11 kim XX * New source format XX * XX * Revision 1.2 1985-03-08 01:18:53 kim XX * Added support for parallell transfer rules. XX * Added -1 option to makedep and depend. XX * XX * Revision 1.1 1985-02-25 19:37:39 kim XX * Initial revision XX */ XX XX# define CMDSIZ 10000 XX# define OPTSIZ 1000 XX# define CNULL '\0' XX XX# include <strings.h> XX XXstatic char usage[]= XX"Usage: makedep [-1] [-rfile] [-Rrules] [-Ilist] [-alist] [-i] sourcefiles"; XX XXmain(argc, argv) XX int argc; XX char * argv[]; XX{ XX char * n, XX * d, XX * s; XX char buf[CMDSIZ], XX srcs[CMDSIZ], XX norm[OPTSIZ], XX dep[OPTSIZ]; XX int vflag = 0; XX XX setprogname(argv[0]); XX XX s = srcs; XX n = norm; XX d = dep; XX *s = *n = *d = CNULL; XX XX while (argc > 1 && argv[1][0] == '-') XX { XX switch (argv[1][1]) XX { XX case 'v': XX vflag++; XX break; XX XX case 'r': XX case 'R': XX sprintf(d, "-%c\"%s\" ", argv[1][1], &argv[1][2]); XX d += strlen(d); XX case 'I': XX case 'a': XX sprintf(n, "-%c\"%s\" ", argv[1][1], &argv[1][2]); XX n += strlen(n); XX break; XX XX case '1': XX sprintf(d, "-%c ", argv[1][1]); XX d += strlen(d); XX break; XX XX case 'i': XX sprintf(n, "-%c ", argv[1][1]); XX n += strlen(n); XX break; XX XX default: XX error("unknown option %s", argv[1]); XX fatalmesg(usage); XX } XX XX argv++; XX argc--; XX } XX XX if (argc < 2) XX fatal("no source files specified"); XX XX while (--argc) XX { XX sprintf(s, "%s ", argv++[1]); XX s += strlen(s); XX } XX XX s = buf; XX sprintf(s, "grep '^#[ \t]*include' /dev/null %s | ", srcs); XX s += strlen(s); XX XX sprintf(s, "makenorm %s `pwd` %s %s | ", norm, srcs); XX s += strlen(s); XX XX sprintf(s, "depend %s\n", dep); XX XX if (vflag) XX printf("%s", buf); XX XX system(buf); XX} SHAR_EOF if test 2339 -ne "`wc -c makedep.c`" then echo shar: error transmitting makedep.c '(should have been 2339 characters)' fi sed 's/^XX//' << \SHAR_EOF > depscan.l XX%{ XX/* -- Scanner for depend XX * XX * $File: depscan.l 1.7 1985-03-29 14:10:37 $ XX * XX * Copyright (c) 1983 Kim Walden XX * ENEA DATA, Sweden and XX * SYSLAB, Department of Computer Science, XX * University of Stockholm, Sweden. XX * XX * This software may be used and copied freely, XX * provided that proper credit is given to the originator XX * by including the above text in each copy. XX * XX * Descr: This scanner is part of an implementation of the XX * algorithm described in K. Walden, "Automatic Generation XX * of Make Dependencies", XX * Softw. Practice & Exper., vol. 14, no. 6, June 1984 XX * XX * When yylex is first called, it is supposed to be in XX * state <rules>, and 'yystring' is supposed to point XX * to a string containing declared include rules. XX * The input is taken from this string through a XX * modified getc() routine. XX * XX * The scanner recognizes rules of the form: XX * XX * .o: .c .p .f XX * .c= .y .l .q XX * XX * where '\n' or ';' may be used as record separators. XX * XX * The rules string is scanned until it is exhausted, XX * (Lex considers '\0' to be EOF,) and then yywrap() XX * will switch to state <includes>. XX * XX * The scanner now recognizes include statements of the form: XX * XX * file1 < file2 XX * XX * and getc() starts reading from the Standard Input. XX * XX * XX * $Log: depscan.l,v $ XX * XX * Revision 1.7 1985-03-29 14:10:37 kim XX * New source format XX * XX * Revision 1.6 1985-03-08 01:18:45 kim XX * Added support for parallell transfer rules. XX * Added -1 option to makedep and depend. XX * XX * Revision 1.5 1985-02-14 01:44:06 kim XX * Converted to RCS format XX * XX * Revision 1.4 1984-08-21 19:50:58 kim XX * Change SYSLAB report reference to SP & E XX * XX * Revision 1.3 1983-10-31 19:50:54 kim XX * Include Copyright lines XX * XX * Revision 1.2 1983-07-20 19:50:50 kim XX * Closer to algorithm in SYSLAB Report No. 19 (June 1983) XX * XX * Revision 1.1 1983-02-22 19:50:47 kim XX * Initial revision XX */ XX XX# undef getc XX# undef YYLMAX XX# define YYLMAX 10000 XX XX%} XX XX%START rules includes XX XXDOT [.] XXW [ \t] XX XXSUF [!%+\-0-9?@A-Z\^_a-z~] XXPATH [!%+\-./0-9?@A-Z\^_a-z~] XX XX int nlfound; XX XX%% XX XX{W}+ { return(SPACE); XX } XX<rules>{DOT}{SUF}+ { return(SUFF); XX } XX<rules>{W}*[\n;]{W}* { return(RULSEP); XX } XX<includes>^.+$ { strcpy(line, yytext); XX lineno = nlfound; XX REJECT; XX } XX<includes>{W}*\n{W}* { nlfound++; XX return(INCSEP); XX } XX<includes>{PATH}+ { return(PATH); XX } XX. { return(yytext[0]); XX } XX%% XX XXint XXyywrap() XX{ XX if (yystring) XX { XX yystring = NULL; XX BEGIN includes; XX nlfound = 0; XX lineno = 0; XX unput('\n'); XX return(0); XX } XX else XX return(1); XX} XX XXint XXgetc(fp) XX FILE * fp; XX{ XX if (yystring) XX return(*yystring ? *yystring++ : 0); XX else XX return(fgetc(fp)); XX} SHAR_EOF if test 2702 -ne "`wc -c depscan.l`" then echo shar: error transmitting depscan.l '(should have been 2702 characters)' fi sed 's/^XX//' << \SHAR_EOF > error.c XX/* -- Error handling XX * XX * $File: error.c 1.3 1985-03-29 14:46:48 $ XX * XX * Usage: fatal(format, args) XX * fatalmesg(format, args) XX * XX * error(format, args) XX * errorc(format, args) XX * XX * mesg(format, args) XX * mesgc(format, args) XX * XX * setprogname(s) XX * XX * Descr: Setprogname copies a string to be used as error message XX * prefix into the external array 'progname'. Normally XX * this function is called once with argv[0] as argument XX * when a command begins execution. XX * XX * Mesg prints a message on stderr, followed by a newline. XX * Error is like mesg, but prints a prefix. XX * Fatal is like error, but exits. XX * Fatalmesg is like mesg, but exits. XX * XX * Mesgc and errorc suppress the newline, and errorc prints XX * the prefix only the first time it is called. XX * XX * If a UNIX system call has returned an error number XX * in the external variable 'errno', then the XX * corresponding system error string is also output, XX * enclosed in parentheses. XX * XX * $Log: error.c,v $ XX * XX * Revision 1.3 1985-03-29 14:46:48 kim XX * Removed system error printout XX * XX * Revision 1.3 1985-03-29 14:29:58 kim XX * removed system error printout XX * XX * Revision 1.2 1985-03-08 01:18:57 kim XX * Removed fatalc. XX * XX * Revision 1.1 1985-02-18 13:22:12 kim XX * Initial revision XX */ XX XX# include <stdio.h> XX XX# define ARGS format,a,b,c,d,e,f XX# define PROGNAMELEN 100 XX XXfatal(ARGS) { errpri(1, 0, 1, ARGS); } XXfatalmesg(ARGS) { errpri(0, 0, 1, ARGS); } XX XXerror(ARGS) { errpri(1, 0, 0, ARGS); } XXerrorc(ARGS) { errpri(1, 1, 0, ARGS); } XX XXmesg(ARGS) { errpri(0, 0, 0, ARGS); } XXmesgc(ARGS) { errpri(0, 1, 0, ARGS); } XX XXchar progname[PROGNAMELEN] = "NULL"; XX XXsetprogname(s) char *s; { strcpy(progname, s); } XX XXstatic errpri(prf, cont, ex, ARGS) XX int prf, XX cont, XX ex; XX{ XX static int prf_printed; XX XX if (prf && !prf_printed) XX { XX fprintf(stderr, "%s: ", progname); XX prf_printed++; XX } XX XX fprintf(stderr, ARGS); XX XX if (!cont) XX { XX fprintf(stderr, "\n"); XX prf_printed = 0; XX } XX XX if (ex) XX exit(1); XX} SHAR_EOF if test 1985 -ne "`wc -c error.c`" then echo shar: error transmitting error.c '(should have been 1985 characters)' fi sed 's/^XX//' << \SHAR_EOF > normscan.l XX%{ XX/* -- Scanner for makenorm XX * XX * $File: normscan.l 1.3 1985-03-29 14:12:33 $ XX * XX * Copyright (c) 1983 Kim Walden XX * ENEA DATA, Sweden and XX * SYSLAB, Department of Computer Science, XX * University of Stockholm, Sweden. XX * XX * This software may be used and copied freely, XX * provided that proper credit is given to the originator XX * by including the above text in each copy. XX * XX * Descr: This scanner is part of an implementation of the XX * algorithm described in K. Walden, "Automatic Generation XX * of Make Dependencies", XX * Softw. Practice & Exper., vol. 14, no. 6, June 1984 XX * XX * When yylex is first called, it is supposed to be in XX * state <rules>, and 'yystring' is supposed to point XX * to a string containing declared include rules. XX * The input is taken from this string through a XX * modified getc() routine. XX * XX * The scanner recognizes rules of the form: XX * XX * .o: .c .p .f XX * .c= .y .l .q XX * XX * where '\n' or ';' may be used as record separators. XX * XX * The rules string is scanned until it is exhausted, XX * (Lex considers '\0' to be EOF,) and then yywrap() XX * will switch to state <includes>. XX * XX * The scanner now recognizes include statements of the form: XX * XX * #include "file" or #include <file> XX * XX * with possible whitespace and trailing comments, XX * and getc() starts reading from the Standard Input. XX * XX * XX * $Log: normscan.l,v $ XX * XX * Revision 1.3 1985-03-29 14:12:33 kim XX * New source format XX * XX * Revision 1.2 1985-03-08 01:18:49 kim XX * Added support for parallell transfer rules. XX * Added -1 option to makedep and depend. XX * XX * Revision 1.1 1985-02-16 18:57:56 kim XX * Initial revision XX */ XX XX# undef getc XX# undef YYLMAX XX# define YYLMAX 10000 XX XX%} XX XX%START rules includes comment XX XXDOT [.] XXW [ \t] XX XXSUF [!%+\-0-9?@A-Z\^_a-z~] XXPATH [!%+\-./0-9?@A-Z\^_a-z~] XX XX int nlfound; XX XX%% XX XX<comment>.* { BEGIN includes; XX } XX{W}+ { return(SPACE); XX } XX<rules>{DOT}{SUF}+ { return(SUFF); XX } XX<rules>{W}*[\n;]{W}* { return(RULSEP); XX } XX<includes>^.+$ { strcpy(line, yytext); XX lineno = nlfound; XX REJECT; XX } XX<includes>{W}*#{W}*include{W}* { return(INCL); XX } XX<includes>{W}*\"{W}* { return(QUOTE); XX } XX<includes>{W}*"<"{W}* { return(LPAR); XX } XX<includes>{W}*">"{W}* { return(RPAR); XX } XX<includes>{W}*\n{W}* { nlfound++; XX return(INCSEP); XX } XX<includes>{PATH}+ { return(PATH); XX } XX. { return(yytext[0]); XX } XX%% XX XXyywrap() XX{ XX if (yystring) XX { XX yystring = NULL; XX BEGIN includes; XX nlfound = 0; XX lineno = 0; XX unput('\n'); XX return(0); XX } XX else XX return(1); XX} XX XXgetc(fp) XX FILE * fp; XX{ XX if (yystring) XX return(*yystring ? *yystring++ : 0); XX else XX return(fgetc(fp)); XX} SHAR_EOF if test 2680 -ne "`wc -c normscan.l`" then echo shar: error transmitting normscan.l '(should have been 2680 characters)' fi mkdir man chdir man sed 's/^XX//' << \SHAR_EOF > Makefile XXall: makedep.man makenorm.man depend.man XX XXROFF= nroff XX XX.1.man: XX $(ROFF) -man $< > $@ XX XX.SUFFIXES: .man .1 SHAR_EOF if test 105 -ne "`wc -c Makefile`" then echo shar: error transmitting Makefile '(should have been 105 characters)' fi sed 's/^XX//' << \SHAR_EOF > makedep.1 XX.so tmac.anx XX.TH MAKEDEP 1 "ENEA DATA March 1985" XX.SH NAME XXmakedep - make dependency generator XX.SH SYNOPSIS XX.B makedep XX.SP r rules ] XX.SP R rules ] XX.SP I list ] XX.SP a list ] XX.SF i XXsourcefiles XX.SH DESCRIPTION XX.I Makedep XXexamines the given source files, XXand extracts all C preprocessor include statements XXof the standard form XX.IP XX #include "file" XX.br XX #include <file> XX.P XXwith possible extra white space and trailing comments. XXThe include statements are piped to XX.I makenorm, XXwhich transforms them into the normal form XX.IP XX file1 < file2 XX.P XXWhen the top directory of a system is moved to a new position XXin a global file system, all XX.I make XXdependencies should still be valid. XXThe file names must therefore be expressed in a form XXthat is insensitive to relocation. XXIn most cases, XXfile references relative to the current XX.I make XXdirectory have this property. XXSome references, however, are global in nature. XXThe dependency XX.IP XX prog.o: ../../../../../../usr/include/time.h XX.P XXbecomes invalid when the system is moved downwards in XXa file system. XX.P XXTherefore, whenever a file name refers to an absolute directory, XXit is expressed in absolute form, XXotherwise it is made relative to the given XX.I make XXdirectory. XXThe directory XX.I /usr/include XXis always considered absolute, XXbut additional absolute directories may be specified. XX.P XXThe normalized include statements are, in turn, XXpiped to XX.I depend, XXwhich generates all XX.I make XXdependencies implied by the include statements. XX.P XXThe resulting dependencies are written to the standard output. XX.P XXInclude file references are normally interpreted by XXthe C preprocessor as relative to XXthe directory of the file in which the statement occurred. XXHowever, if the referenced file cannot be found, XXa user directory list is first searched, if specified, XXand then the system directory XX.I /usr/include. XXThe '#include <file>' form searches only the user list XXand the system directory. XX.P XXGenerated files may be missing or obsolete XXat the time of the XX.I make XXdependency generation, XXso include statements must extracted from source files. XXHowever, include statements may reference generated files, XXlike e.g. a XX.I lex XXgenerated 'scanner.c' which is included in a XX.I yacc XXfile. XXTherefore, a set of standard include suffix rules XXare used to deduce which files will be present at XXC compile time, XXand all implied XX.I make XXdependencies may thus be generated by examining XXthe source files XX(see the SP & E article below). XX.P XXSince include statements are sometimes propagated XXto more than one output file, XXparallell transfer rules are permitted. XXFor example, the XX.B -d XXoption to XX.I yacc XXproduces a definitions file, XXwhich may be referenced by other files. XX.P XXTo make automatic dependency generation possible, XX.I yacc XXoutput files must have the same base name as the XXinput file. XXThus, if the XX.I make XXdependencies and corresponding commands are written: XX.IP XX grammar.h grammar.c: grammar.y XX.br XX yacc -d grammar.y XX.br XX mv y.tab.c grammar.c XX.br XX mv y.tab.h grammar.h XX.P XXthe default parallell rules XX.IP XX .c= .y XX.br XX .h= .y XX.P XXwill be applicable. XX.P XXArguments: XX.A1 r rules The XXstandard include suffix rules XX.IP XX .o: .c .p .f XX.br XX .c= .y .l .q XX.br XX .h= .y XX.IP XXare augmented by the specified rules. XXThe argument is a string of rules, separated by semicolon. XX.A1 R rules The XXstandard include suffix rules are replaced by XXthe specified rules. XX.A1 I list Add XXthe specified directory to the XXuser include directory search list. XX.A1 a list Add XXthe specified directory to the XXabsolute directory list. XX.AR i Since XXit is often convenient to exclude XXdependencies to standard system include files, XXreferences that cannot be resolved by examining the explicit XX.I sourcefiles XXlist, XXare silently ignored if they are found in the XX.I /usr/include XXdirectory. XXThe XX.B -i XXoption forces system include references to be treated like XXany other references. XX.C1 sourcefiles The XXcomplete list of source files. XX.RE XX.P XXA standard Makefile using XX.I makedep XXmay contain XX.P XX.nf XX\&... XX XXSRCS= 'list of source files' XX XXdepend: XX makedep $(SRCS) > Dep.mk XX @echo "\tInclude dependencies generated." XX XXinclude Dep.mk XX XX\&... XX.fi XX.SH IDENTIFICATION XX.de VL XX\\$2 XX.. XXAuthor: Kim Walden, XXENEA DATA and University of Stockholm, Sweden. XX.sp 0 XXRevision Number: XX.VL $Revision: 2.2 $ XX; Release Date: XX.VL $Date: 1985-03-13 18:39:26 $ XX\h'-1'. XX.sp 0 XXCopyright \(co 1983. XX.SH "SEE ALSO" XXdepend(1), makenorm(1), make(1) XX.sp 0 XXK. Walden, "Automatic Generation of Make Dependencies", XX.IR "Softw. Practice & Exper." , XXvol. 14, no. 6, June 1984. XX.sp 0 XX.IR "Make - A Program for Maintaining Computer Programs" , XXby S. I. Feldman. XX.sp 0 XX.IR "An Augmented Version of Make" , XXby E. G. Bradford. SHAR_EOF if test 4650 -ne "`wc -c makedep.1`" then echo shar: error transmitting makedep.1 '(should have been 4650 characters)' fi sed 's/^XX//' << \SHAR_EOF > tmac.anx XX.tr ~ XX.nr f 0 XX.bd S B 3 XX.de SP XX.if n .ul XX\%[\fB\-\\$1\fR\\c XX.if n .ul 0 XX\\$2\\$3 XX.. XX.de SF XX.if n .ul XX\%[\fB\-\\$1\fR] XX.if n .ul 0 XX.. XX.de ZZ XX\fB.\|.\|.\fR XX.. XX.de AR XX.if \\nf \{ \ XX. RE XX. nr f 0 \} XX.PP XX.RS 5 XX.TP 15 XX\fB\-\\$1\\fR XX\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 XX.nr f 1 XX.. XX.de C1 XX.if \\nf \{ \ XX. RE XX. nr f 0 \} XX.PP XX.RS 5 XX.TP 15 XX\\$1 XX\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 XX.nr f 1 XX.. XX.de A1 XX.if \\nf \{ \ XX. RE XX. nr f 0 \} XX.PP XX.RS 5 XX.TP 15 XX\fB\-\\$1\fR[\fI\\$2\fR] XX\\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 XX.nr f 1 XX.. XX.de A2 XX.if \\nf \{ \ XX. RE XX. nr f 0 \} XX.PP XX.RS 5 XX.TP 15 XX\fB\-\\$1\fI\\$2\fR XX\\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 XX.nr f 1 XX.. XX.ds M) \fI\s-1MR\s+1\fR XX.ds R) \fI\s-1RELEASE NUMBER\s+1\fR XX.ds S) \s-1SCCS\s+1 XX.ds I) \s-1SID\s+1 XX.de F1 XX.if \\nf \{ \ XX. RE XX. nr f 0 \} XX.PP XX.RS 13 XX.TP 7 XX\fB\\$1\fI\\$2\fR XX\\$3 XX.nr f 1 XX.. XX.de F2 XX.if \\nf \{ \ XX. RE XX. nr f 0 \} XX.PP XX.RS 13 XX.TP 7 XX\fB\\$1[\fI\\$2\fR] XX\\$3 XX.nr f 1 XX.. XX.de GE XX.br XX.if \\w'\\n(.z' .ab "GE: diversion in effect" XX.nr m \\n(.v*2 XX.nr h 0\\$1 XX.if \\nm-\\nh .ab "GE: unscaled arg" XX.if \\nh-\\n(.t .bp XX.. SHAR_EOF if test 1098 -ne "`wc -c tmac.anx`" then echo shar: error transmitting tmac.anx '(should have been 1098 characters)' fi sed 's/^XX//' << \SHAR_EOF > makenorm.1 XX.so tmac.anx XX.TH MAKENORM 1 "ENEA DATA March 1985" XX.SH NAME XXmakenorm - include statement normalizer XX.SH SYNOPSIS XX.B makenorm XX.SP r rules ] XX.SP R rules ] XX.SP I list ] XX.SP a list ] XX.SF i XXmakedir XXsourcefiles XX.SH DESCRIPTION XX.I Makenorm XXaccepts C preprocessor include statements XXof the form XX.IP XX file1: #include "file" XX.br XX file2: #include <file> XX.P XXfrom the standard input XXwith possible extra white space and trailing comments, XXand writes them to the standard output in the normal form XX.IP XX file1 < file2 XX.P XXThis form is suitable for later processing by the XX.I depend XXcommand to generate XX.I make XXdependencies. XX.P XXWhen the top directory of a system is moved to a new position XXin a global file system, all XX.I make XXdependencies should still be valid. XXThe file names must therefore be expressed in a form XXthat is insensitive to relocation. XXIn most cases, XXfile references relative to the current XX.I make XXdirectory have this property. XXSome references, however, are global in nature. XXThe dependency XX.IP XX prog.o: ../../../../../../usr/include/time.h XX.P XXbecomes invalid when the system is moved downwards in XXa file system. XX.P XXTherefore, whenever a file name refers to an absolute directory, XXit is expressed in absolute form, XXotherwise it is made relative to the given XX.I make XXdirectory. XXThe directory XX.I /usr/include XXis always considered absolute, XXbut additional absolute directories may be specified. XX.P XXWhether a reference is absolute or not, XXit is always reduced to the shortest possible path XX(loops eliminated), XXso that file names can later be unambiguously identified by the XX.I depend XXcommand. XX.P XXInclude file references are normally interpreted by XXthe C preprocessor as relative to XXthe directory of the file in which the statement occurred. XXHowever, if the referenced file cannot be found, XXa user directory list is first searched, if specified, XXand then the system directory XX.I /usr/include. XXThe '#include <file>' form searches only the user list XXand the system directory. XX.P XXGenerated files may be missing or obsolete XXat the time of the XX.I make XXdependency generation, XXso include statements must extracted from source files. XXHowever, include statements may reference generated files, XXlike e.g. a XX.I lex XXgenerated 'scanner.c' which is included in a XX.I yacc XXfile. XXTherefore, a set of standard include suffix rules XXare used to deduce, XXfrom the given list of source files, XXwhich files will be present at C compile time XX(see the SP & E article below). XXInclude file references are thus resolved without requiring XXany of the files to be present when XX.I makenorm XXis run. XX.P XXArguments: XX.A1 r rules The XXstandard include suffix rules XX.IP XX .o: .c .p .f XX.br XX .c= .y .l .q XX.br XX .h= .y XX.IP XXare augmented by the specified rules. XXThe argument is a string of rules, separated by semicolon. XX.A1 R rules The XXstandard include suffix rules are replaced by XXthe specified rules. XX.A1 I list Add XXthe specified directories to the XXuser include directory search list. XX.A1 a list Add XXthe specified directories to the XXabsolute directory list. XX.AR i Since XXit is often convenient to exclude XXdependencies to standard system include files, XXreferences that cannot be resolved by examining the explicit XX.I sourcefiles XXlist, XXare silently ignored if they are found in the XX.I /usr/include XXdirectory. XXThe XX.B -i XXoption forces system include references to be treated like XXany other references. XX.C1 makedir The XXfull path name of the XX.I make XXdirectory. XXIt must be given in absolute form. XX.C1 sourcefiles The XXcomplete list of source files, XXfrom which the include statements were extracted. XXThis is needed to identify source files which do not XXcontain include statements. XX.SH IDENTIFICATION XX.de VL XX\\$2 XX.. XXAuthor: Kim Walden, XXENEA DATA and University of Stockholm, Sweden. XX.sp 0 XXRevision Number: XX.VL $Revision: 2.2 $ XX; Release Date: XX.VL $Date: 1985-03-13 18:39:30 $ XX\h'-1'. XX.sp 0 XXCopyright \(co 1983. XX.SH "SEE ALSO" XXdepend(1), makedep(1), make(1) XX.sp 0 XXK. Walden, "Automatic Generation of Make Dependencies", XX.IR "Softw. Practice & Exper." , XXvol. 14, no. 6, June 1984. XX.sp 0 XX.IR "Make - A Program for Maintaining Computer Programs" , XXby S. I. Feldman. XX.sp 0 XX.IR "An Augmented Version of Make" , XXby E. G. Bradford. SHAR_EOF if test 4167 -ne "`wc -c makenorm.1`" then echo shar: error transmitting makenorm.1 '(should have been 4167 characters)' fi sed 's/^XX//' << \SHAR_EOF > depend.1 XX.so tmac.anx XX.TH DEPEND 1 "ENEA DATA March 1985" XX.SH NAME XXdepend - make dependency generator XX.SH SYNOPSIS XX.B depend XX.SP r file ] XX.SP R rules ] XX.SF 1 XX.SH DESCRIPTION XX.I Depend XXaccepts lines of the form XX.IP XX file1 < file2 XX.P XXfrom the standard input. XXThe lines represent include statements XXextracted from source files. XXEach file name is assumed to be in normal form, XXi.e., shortest absolute path for files XXin absolute directories, XXand shortest path relative to the make directory XXfor all other files. XX.P XXThe XX.I make XXdependencies implied by these XXinclude statements XXare output in the form XX.nf XX.IP XX fileX1: fileX2 fileX3 fileX4 ... XX fileY1: fileY2 fileY3 fileY4 ... XX ... XX.fi XX.P XXto the standard output. XXIf a dependency line is longer than 80 characters, XXit is split into two lines, XXso the generated dependencies can be conveniently XXinspected from a crt terminal. XX.P XXArguments: XX.A1 r rules The XXstandard include suffix rules XX.IP XX .o: .c .p .f XX.br XX .c= .y .l .q XX.br XX .h= .y XX.IP XXare augmented by the specified rules. XXThe argument is a string of rules, separated by semicolon. XX.A1 R rules The XXstandard include suffix rules are replaced by XXthe specified rules. XX.AR 1 Only one dependency per output line. XXThis is useful for postprocessing, XXfor example, when object file dependencies are to be XXtransformed into object library member dependencies. XX.SH IDENTIFICATION XX.de VL XX\\$2 XX.. XXAuthor: Kim Walden, XXENEA DATA and University of Stockholm, Sweden. XX.sp 0 XXRevision Number: XX.VL $Revision: 2.1 $ XX; Release Date: XX.VL $Date: 1985-03-13 18:29:12 $ XX\h'-1'. XX.sp 0 XXCopyright \(co 1983. XX.SH "SEE ALSO" XXmakedep(1), makenorm(1), make(1) XX.sp 0 XXK. Walden, "Automatic Generation of Make Dependencies", XX.IR "Softw. Practice & Exper." , XXvol. 14, no. 6, June 1984. XX.sp 0 XX.IR "Make - A Program for Maintaining Computer Programs" , XXby S. I. Feldman. XX.sp 0 XX.IR "An Augmented Version of Make" , XXby E. G. Bradford. SHAR_EOF if test 1881 -ne "`wc -c depend.1`" then echo shar: error transmitting depend.1 '(should have been 1881 characters)' fi chdir .. chdir .. # End of shell archive exit 0 -- Kim Walden ENEA DATA Sweden UUCP: {seismo,decvax,philabs}!{mcvax,ukc,unido}!enea!kim ARPA: decvax!mcvax!enea!kim@berkeley.arpa mcvax!enea!kim@seismo.arpa