djones@megatest.UUCP (Dave Jones) (12/23/87)
The problem with make -- well ONE of the problems with make -- is that it requires the user to specify the dependencies. What you really want is something that keeps up with the dependencies automatically as they change. You want to use a data-base, but the Makefile IS its own data-base. HEY! THAT'S IT! Let's cause the Makefile to update itself each time a dependency might have changed. We will need a program which removes dependency spec's from a Makefile, and one which creates new dependency spec's. In Sun-3 land, cc -M will make the new dependencies. It's quite easy to write a little program to do it, if your cc doesn't have the feature. If you have the source to cpp, just hack that. I've done so, and it's easy. Let's call the one which removes dependencies "remove_depends". (One follows at the end of this letter, in C++. Absolutely free.) Again easy. If you speak sed or awk, (I don't), you can probably write it in a line or two. The here is a paradigm for your Makefile: # Is this self-modifying code? If so, sue me. ################################################## FILES = foo.o bar.o foobar.o foozle.o libFoo.a: $(FILES) ar cru libFoo.a $(FILES) ranlib libFoo.a .c.o: remove_depends $*.o < Makefile > NewMakefile cc -M $(CFLAGS) $< >> NewMakefile mv NewMakefile Makefile $(CC) $(CFLAGS) -.o $< # dependency specs will magically appear below /* This can be used as "remove_depends" */ #include <stream.h> #include <string.h> /* This program filters out all lines prefixed by argv[1]. ** */ void maybe_quit() { if(cin.rdstate() != _good) exit(cin.rdstate() == _eof ? 0 : -1); } main(int argc, char** argv) { if(argc == 1) { cerr << "Need a parameter\n"; exit(1); } const int name_len = strlen(argv[1]) + 1; char* name = new char[name_len]; strcpy(name,argv[1]); char* prefix = new char[name_len]; while(1) { cin.get(prefix, name_len); maybe_quit(); const int compares = ( strcmp(name, prefix) == 0 ); /* flush prefix */ if(!compares) cout << prefix; /* flush remainder of line */ char ch; do { cin.get(ch); maybe_quit(); if( !compares ) cout.put(ch); } while( ch != '\n'); } }
djones@megatest.UUCP (Dave Jones) (12/23/87)
in article <176@goofy.megatest.UUCP>, djones@megatest.UUCP (Dave Jones) says: > > > > The problem with make -- well ONE of the problems with make -- is that it > requires the user to specify the dependencies. What you really want [...] Oops. In translating from a C++ makefile into a C one, I dropped the ball. The flag -.o in the $(CC) line should be -c. Sorry. Dave Jones Megatest Corp. 880 Fox Lane San Jose, CA. 95131 (408) 437-9700 Ext 3227 UUCP: ucbvax!sun!megatest!djones ARPA: megatest!djones@riacs.ARPA
chris@mimsy.UUCP (Chris Torek) (12/24/87)
In article <176@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: >... What you really want is something that keeps up with the >dependencies automatically as they change. ... Let's cause the >Makefile to update itself each time a dependency might have changed. We already have something like this in 4.3BSD. A number of the makefiles in /usr/src support the command `make depend'. Admittedly this requires manual intervention---one has to decide that it is time to update the dependency lists---but it works and is relatively simple. The makefiles distributed with 4.3BSD do this in an ugly way. Each makefile has something like this: depend: for i in ${SUBDIR}; do (cd $$i; make ${MFLAGS} depend); done for i in ${STD} ${NSTD} ${SETUID}; do \ cc -M $$i.c | sed 's/\.o//' | \ awk ' { if ($$1 != prev) \ { if (rec != "") print rec; rec = $$0; prev = $$1; } \ else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ else rec = rec " " $$2 } } \ END { print rec } '; done >makedep echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep echo '$$r makedep' >>eddep echo 'w' >>eddep cp Makefile Makefile.bak ed - Makefile < eddep rm eddep makedep echo '# DEPENDENCIES MUST END AT END OF FILE' >>Makefile echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>Makefile echo '# see make depend above' >>Makefile # DO NOT DELETE THIS LINE -- make depend uses it foo: foo.c /usr/include/stdio.h /usr/include/signal.h foo.h # DEPENDENCIES MUST END AT END OF FILE [etc] As it happens, all the ugliness can be, should be, and as of a number of months ago, has been, encapsulated in a program. This program is called `mkdep'; it is really just a shell script that runs cc -M. It has two options, `-f' (specify the name of the makefile) and `-p' (producing programs: do the sed command shown above, so that x depends on x.c and incl.h; otherwise x.o depends on x.c and incl.h). I am not sure I should post the script itself, but it is trivial, since everything you need do is shown above. Instead of the for loop, mkdep assumes you are naming .c files, so the Makefile entry now looks like this: depend: ldepend for i in ${SUBDIR}; do (cd $$i; make ${MFLAGS} depend); done ldepend: mkdep -p ${CFLAGS} ${CSRCS} # DO NOT DELETE THIS LINE -- mkdep uses it # DEPENDENCIES MUST END ... [etc] (Here `depend' has been split to provide a `change local dependencies only' target. `make depend' in an upper-level source directory such as /usr/src/ucb is time consuming, and deadly boring; `make ldepend' confines dependency generation to the current directory.) Disliking having to list both source files *and* programs (it seems inelegant and error prone), I created two small scripts called `addsuf' and `chgsuf', so that the `ldepend' target becomes ldepend: mkdep -p ${CFLAGS} `addsuf .c ${STD} ${NSTD}` or ldepend: mkdep ${CFLAGS} `chgsuf .o .c ${OBJS}` Since I wrote them, I know I can post them. Here are addsuf and chgsuf in their entirety: #! /bin/sh # # addsuf - add suffix to each argument # assumes no embedded spaces in arguments case $# in 0) echo "usage: addsuf suffix files" 1>&2; exit 1;; esac suf="$1" shift echo ${1+"$@"} | sed -e "s/ /$suf /g" -e "s/$/$suf/" #! /bin/sh # # chgsuf - change suffix in each argument # assumes no embedded spaces in arguments # oldsuf is a string, not an R.E. case $# in 0|1) echo "usage: chgsuf oldsuf newsuf files" 1>&2; exit 1;; esac sed="sed -e s/[/.^[\*]/\\\\&/g" oldsuf="`echo \"$1\" | $sed`" newsuf="`echo \"$2\" | $sed`" shift; shift echo ${1+"$@"} | sed -e "s/$oldsuf /$newsuf /g" -e "s/$oldsuf$/$newsuf/" Of course, there is still a problem for those for whom `cc -M' produces nothing useful. Fortunately, some time ago I wrote a shell script for use on our Suns, which then did not support a -M option for cc. Not long ago I moved it to our Pyramid, which still does not support cc -M (we run OSx release 2.5, as we have some trouble getting current sources). Here is that version: #! /bin/sh # # getdep - get dependency lists. # find cpp cpp=/lib/cpp # handle arguments incl= for i do case "$i" in -I*) incl="$incl $i";; -O|-c|-M|-D*|-U*) ;; *) # assume source file # put '$dep' in front of dependencies dep=`echo "$i" | sed -e 's,/,\\\\/,g' -e 's/\.c$/.o/'` # Find includes, remove leading numerics, remove ./, # remove double quotes, and remove trailing numerics. # Sort that, discarding duplicates, and add '$dep'. $cpp $incl "$i" | grep "^#" | sed -e 's/# [0-9]* //' -e 's,"./,",' -e 's/"\(.*\)"/\1/' \ -e 's/ [ 0-9]*$//' | sort -u | sed -e "s/^/$dep: /";; esac done -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
ljz@fxgrp.UUCP (Lloyd Zusman, Master Byte Software) (12/24/87)
In article <176@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: >The problem with make -- well ONE of the problems with make -- is that it >requires the user to specify the dependencies. What you really want >is something that keeps up with the dependencies automatically as they >change. > ... >We will need a program which removes dependency spec's from a Makefile, >and one which creates new dependency spec's. > ... There already is a program that lets you do this. It is called "mkmf" and I have mentioned it in an earlier posting. I have determined that it indeed is in the public domain. After mentioning it here I got such an overwhelming number of requests for it that yesterday I mailed it to the moderators of comp.sources.misc and comp.sources.unix ... I'm hoping it will be posted in one or the other of these newsgroups in the near future. This program takes a makefile as input and produces a new one as output. It automatically recalculates all the dependencies every time it is run, removes the old dependencies from the makefile, and writes the new ones therein. We use it that way here at our installation and we are quite pleased with it. Look for it soon in comp.sources.unix or comp.sources.misc. ------------------------------------------------------------------------- Lloyd Zusman Master Byte Software Los Gatos, California Internet: fxgrp!ljz@ames.arpa "We take things well in hand." UUCP: ...!ames!fxgrp!ljz
djones@megatest.UUCP (Dave Jones) (12/25/87)
in article <9942@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) says: > > In article <176@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: >>... What you really want is something that keeps up with the >>dependencies automatically as they change. ... Let's cause the >>Makefile to update itself each time a dependency might have changed. > > We already have something like this in 4.3BSD. A number of the > makefiles in /usr/src support the command `make depend'. Admittedly > this requires manual intervention---one has to decide that it is > time to update the dependency lists---but it works and is relatively > simple. > I guess I forgot to say, "I know about 'depend', but it requires manual intervention." By the way, the "make" of my dreams would keep in its data-base not only the a record of what the source files were the last time the object was made, but also the modification dates, and the METHOD which was used to make the object. It would then remake the object if any file had been modified, or if the method to make the object had changed. For example, maybe you have added something to CFLAGS. About three years ago, I wrote just such a program for our customers. Called it "compile_files". Now it's used exclusively for Pascal programs and extensively for C programs. It is not general, however. The methods for making Pascal and C programs are "hard-coded" into it, rather than coded in the makefile. "Knows too much for its own good", you might say. So now that we have C++, it needs to be fiddled with.
djones@megatest.UUCP (Dave Jones) (12/26/87)
in article <190@fxgrp.UUCP>, ljz@fxgrp.UUCP (Lloyd Zusman, Master Byte Software) says: > > In article <176@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: > >>The problem with make -- well ONE of the problems with make -- is that it >>requires the user to specify the dependencies. What you really want >>is something that keeps up with the dependencies automatically as they >>change. >> ... >>We will need a program which removes dependency spec's from a Makefile, >>and one which creates new dependency spec's. >> ... > > There already is a program that lets you do this. It is called "mkmf" > and I have mentioned it in an earlier posting. I have determined that > it indeed is in the public domain. [...] > This program takes a makefile as input and produces a new one as > output. It automatically recalculates all the dependencies every time > it is run ... Com'on guys!! Read the posting! The little program and Makefile paradigm I posted automatically recalculates the dependancies on a file-by-file basis, ONLY when a file is remade. "mkmf", as you described it, goes through ALL files every time ONE changes. That was the point. I don't make it out to be profound, but when you are working on one file in a large archive, it is fast and foolproof. The "depend" which somebody posted earlier also reads through all files, and requires manual intervention. That's enough "Bah-Humbug". Merry Christmas. X X X X X X X X X X X X