andrewt@watnext.waterloo.edu (Andrew Thomas) (07/26/89)
I find myself in a position where I have to keep an archive up to date, where the files in the archive are the objecs produced by compiling all of the C files in the directory. The directory is very large, so I would like to compile all of the C files which need compiling first, and then perform the 'ar' command at the end, thereby saving the (significant) time spent calling ar over and over again. My incorrect solution goes something like this: ------------------------------------------------------ CC = gcc CFLAGS = -g -fwritable-strings TARGET = libutil.a files := $(basename $(wildcard *.c)) objects := $(patsubst %,$(TARGET)(%),$(addsuffix .o,$(files))) $(objects): libutil.a(%.o): %.c $(CC) $(CFLAGS) -c $? libutil.a: $(objects) $(AR) $(ARFLAGS) $@ $(patsubst $@(%),%,$?) ranlib $@ $(RM) $(patsubst $@(%),%,$?) ----------------------------------------------------- The problem here is that this makefile will recompile all of the objects correctly, but when it does the pattern substitution on $?, the value of $? is empty because there are in fact no members of the archive which are more recent than the archive itself. At this point, I would like to see a variable which is the value of all dependencies which were remade, as opposed to those whose dates are newer. I eventually gave up on this, and used the implicit rules for making archive members. I like to pipe the output from make to a file so I can look back at any errors, etc. Trouble is, the 'ar' command gets echoed out all the time, kind of cluttering up my log file. Is there any way to turn off the echoing in an implicit rule without turning off echoing altogether? One last question ... is the exact specification of the implicit rules documented anywhere, and is it possible to replicate them exactly using explicit directives in a makefile? I would have been able to solve my problem by rewriting the implicit rule for archive members, but could not figure out how to do it. Thanks for listening. I fell better.
jay@banzai.UUCP (Jay Schuster) (07/29/89)
In article <10822@watcgl.waterloo.edu> andrewt@watnext.waterloo.edu (Andrew Thomas) writes: >I find myself in a position where I have to keep an archive up to >date, where the files in the archive are the objecs produced by >compiling all of the C files in the directory. The directory is very >large, so I would like to compile all of the C files which need >compiling first, and then perform the 'ar' command at the end, thereby >saving the (significant) time spent calling ar over and over again. I ran into this problem starting at make 3.05 and continuing up to make 3.54. In SystemV-land we are encouraged (by the manual) to do archives like this (converted to GNUish): (%.o): %.c ; $(LIB): \ $(LIB)(erasebox.o) \ $(LIB)(command.o) \ $(LIB)(errlog.o) \ $(LIB)(fmt.o) \ $(LIB)(printlib+.o) $(CC) -c $(CFLAGS) $(?:.o=.c) ar rv $(LIB) $? rm $? .PRECIOUS: $(LIB) The idea being that we should defeat the default rule as to how to make $(LIB)(foo.o), collect up what was out of date, and then just issue one `$(CC)' command, one `ar', and one `rm'. GNU make doesn't let you do this because when it runs across a rule with no command, it still pretends that the targets were updated, even though they weren't. Also, In SystemV, if $? would be a list of archive members `lib(member)', then $? actually becomes the list of `member's. Here is what I do to fix it (this is an excerpt from a larger patch, so your line numbers will be off) : *** commands.c~ Thu Jul 27 12:17:47 1989 --- commands.c Thu Jul 27 15:43:55 1989 *************** *** 102,108 **** DEFINE_VARIABLE ("%D", 2, DIRONLY (percent)); DEFINE_VARIABLE ("%F", 2, FILEONLY (percent)); ! /* Compute the values for $^ and $? and their F and D versions. */ { register unsigned int caret_len, qmark_len; --- 108,117 ---- DEFINE_VARIABLE ("%D", 2, DIRONLY (percent)); DEFINE_VARIABLE ("%F", 2, FILEONLY (percent)); ! /* Compute the values for $^ and $? and their F and D versions. ! In SystemV, if $? is a list of archive members `lib(member)'', ! then $? is the list of `member''s. We do a similar thing with ! $^ */ { register unsigned int caret_len, qmark_len; *************** *** 116,122 **** caret_len = qmark_len = 0; for (d = file->deps; d != 0; d = d->next) { ! register unsigned int i = strlen (dep_name (d)) + 1; caret_len += i; if (d->changed) qmark_len += i; --- 125,137 ---- caret_len = qmark_len = 0; for (d = file->deps; d != 0; d = d->next) { ! register unsigned int i; ! ! if (ar_name (dep_name(d))) ! i = strlen (1 + index (dep_name(d), '(')); ! else ! i = strlen (dep_name (d)) + 1; ! caret_len += i; if (d->changed) qmark_len += i; *************** *** 138,143 **** --- 153,165 ---- c = dep_name (d); len = strlen (c); + + if (ar_name (c)) + { + c = (1 + index (c, '(')); + len = strlen (c) - 1; + } + bcopy (c, cp, len); cp += len; *cp++ = ' '; *** remake.c~ Thu Jul 27 12:17:56 1989 --- remake.c Thu Jul 27 15:35:49 1989 *************** *** 414,423 **** register struct file *file; { file->updated = 1; ! if (just_print_flag) ! file->last_mtime = time ((time_t *) 0); ! else ! file->last_mtime = name_mtime (file->name); if (file->also_make != 0) { --- 414,440 ---- register struct file *file; { file->updated = 1; ! ! /* If the command we just tried to execute was empty, pretend that ! we did something anyway. This way things that depended on this ! file get updated as well. This is a hack, and not correct, but it ! will make the efficient library update method work. */ ! { ! if (just_print_flag) ! file->last_mtime = time ((time_t *) 0); ! else { ! if (file->cmds != 0) { ! char *p; ! for (p = file->cmds->commands; *p != '\0'; ++p) ! if (*p != ' ' && *p != '\t' && *p != '\n') ! break; ! file->last_mtime = (*p == '\0') ! ? time ((time_t *) 0) : name_mtime (file->name); ! } ! else ! file->last_mtime = name_mtime (file->name); ! } ! } if (file->also_make != 0) { -- Jay Schuster uunet!uvm-gen!banzai!jay, attmail!banzai!jay The People's Computer Company `Revolutionary Programming'