Path: utzoo!attcan!uunet!samsung!uakari.primate.wisc.edu!uflorida!haven!ncifcrf!lhc!mimsy!chris From: chris@mimsy.umd.edu (Chris Torek) Newsgroups: comp.lang.c Subject: Re: C + Make Message-ID: <26567@mimsy.umd.edu> Date: 16 Sep 90 15:30:30 GMT References: <0949@sheol.UUCP> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 87 I wrote: >>I have two recommendations ... 1. Put the dependency-making in a >>separate program. In article <0949@sheol.UUCP> throopw@sheol.UUCP (Wayne Throop) writes: >Much as I am aware of the dangers of disagreeing with somebody as >usually-correct as Chris, I disagree slightly here. My experience >says that packing all the dependency-making into a single step >seperated from the construction step is very bad for information >hiding, and makes for monolithic, hard-to-maintain, hard-to-enhance >dependency "expert systems". Hmm, well, would you prefer `in separate programs'? I.e., `mkdep-C' extracts information on C source files, `mkdep-EP' extracts Extended Pascal information (cannot do ANSI Standard Pascal since it has no inclusion mechanism!), `mkdep-KCL' extracts Kyoto Common Lisp information, and so forth. In the case of the Berkeley source tree, the C-only mkdep handles at least 95% of the job, i.e., it is `good enough'. >In fact, Chris' second rule: >> Do not make `mkdep' edit the makefile. [.. instead ..] >> make -f Makefile -f .depend >... obliquely illustrates part of the problem with the first rule. >The dependency occurs in a single massive step before the "real" >work of construction begins. Thus, any source that is generated >"on the fly" (like yacc or lex, but more complicated... for example >computing a perfect hash literal array, or whatever) must be >treated as a stylized special case in the dependency check. The >natural way of computing the dependencies of the output files >using the method of an existing subcase won't work because the >files don't exist yet. True. In the case of lex and yacc files, one cheats: since the output from both these programs is a C file (which has not expanded any `#include's---that is, if foo.y yaccs to foo.c and foo.y `#include's foo.h, then foo.o depends on foo.c and foo.h, but foo.c does not depend on foo.h) one adds the C files to the list of `things for mkdep' and makes the `depend' rule depend on the .c files themselves. I.e.: # Makefile for foo, built from foo.y->foo.c->foo.o and aux.c->aux.o CSRCS= foo.c aux.c OBJS= foo.o aux.o all: foo foo: ${OBJS} ${CC} ${LDFLAGS} -o $@ ${OBJS} clean: rm -f ${OBJS} foo a.out core depend: ${CSRCS} mkdep ${CSRCS} Note that foo.y need not be mentioned at all: `make' keys off its existence, plus make's implicit rule for `.y' -> `.c'. >Not that this problem is insoluable. I've seen it solved. It's just >that the solution, while effective, seems not to have an audience. > >( The basic notion of the solution is that the construction engine must > construct the dependency graph on the fly... quite doable, trust me. ) Indeed. Unfortunately, this requires the construction engine (`make') to have access to the actual dependency information, which means either pushing all those rules from mkdep-* into `make' itself, or else an incestuous relationship between the compiler(s) and `make'. The latter is certainly more maintainable (what else but the program that creates an output file knows for certain what inputs were used?), and can be quite efficient---the dependency information for any one source is correct if and only if the corresponding output file exists, and if not that output needs rebuilding anyway---but, unfortunately, this is MUCH more work to add to a system that does not already have it. (Too, it has the drawback of requiring that there be room in every output file for the information needed by `make', or else that output files come in pairs: foo.o and .depend.foo.o, or some such. Which is `better' is to some extent a matter of taste. One can argue that every `object' file should in fact be a directory: foo.o/text, foo.o/data, foo.o/symbols, foo.o/debug, foo.o/depend.... Let the file system work for you.) In any case, it is important that a makefile---even one as minimal as a source list (`bill of materials', as it were) for a system like the one above---not be altered by the dependency-update step, because such a file *is* a source file, just as much as any C program. If you are using a revision control system, you will not want revisions made merely to reflect automatically-derived changes. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris