[gnu.utils.bug] Make 3.57 on archives

ian@sibyl.eleceng.ua.oz.au (01/15/90)

I have trouble getting GNU make to rebuild archives reasonably.

In Sys V make I can do

$(LIBNAME):: $(LIBNAME)(foo.o) $(LIBNAME)(bar.o)
	$(CC) -c $(CFLAGS) $(?:.o=.c)
	ar rv $(LIBNAME) $?
	rm $?

In practice to make this work I had to define a null .c.a rule, but
otherwise it is very nice because cc and ar only get executed once.
This is a considerable advantage, especially in the case of ar. Granted
there must be some ugly special case code in SysV make to handle this.

In the case of GNU make, running with -n led me to believe that the
following might work

$(LIBNAME):: $(LIBNAME)(foo.o) $(LIBNAME)(bar.o)
	$(CC) -c $(CFLAGS) $(?:$(LIBNAME)(%.o)=%.c)
	ar rv $(LIBNAME) $(?:$(LIBNAME)(%)=%)
	rm $(?:$(LIBNAME)(%)=%)

It is a bit more complicated but the syntax is more general. Alas,
although make -n indicates exactly the right thing, when exectued
with out the -n flag $? expands to null. (An echo $? line proves
this). This seems to me to be a bug.

What I currently have is (somewhat edited):

LIBNAME = /lib/libc.a

all: libc

libc: $(LIBNAME)

CMODULES = $(LIBNAME)(signal.o)

SMODULES = $(LIBNAME)(memmove.o)

$(LIBNAME):: $(CMODULES) $(SMODULES)

$(CMODULES):
	$(CC) -c $(CFLAGS) $(%:%.o=%.c)
	ar rv $(LIBNAME) $%
	rm $%

$(SMODULES):
	$(AS) $(%:%.o=%.s)
	ar rv $(LIBNAME) $%
	rm $%

This results has the disadvantage that a) all the files get compiled
regardless of whether $(LIBNAME)(signal.o) is newer than signal.c or
not and b) ar gets seperately executed for each module.

Is this a bug? If not how can I do what I want with GNU make?

jay@banzai.PCC.COM (Jay Schuster) (01/17/90)

ian@sibyl.eleceng.ua.oz.au writes:
>I have trouble getting GNU make to rebuild archives reasonably.
>
>In Sys V make I can do
>
>$(LIBNAME):: $(LIBNAME)(foo.o) $(LIBNAME)(bar.o)
>	$(CC) -c $(CFLAGS) $(?:.o=.c)
>	ar rv $(LIBNAME) $?
>	rm $?
>
>In practice to make this work I had to define a null .c.a rule, but
>otherwise it is very nice because cc and ar only get executed once.

This has been a longstanding problem in make.  There doesn't seem to
be a clean way to implement it, but I do have a patch (UNOFFICIAL) that
exhibits the desired behavior.

It required changes to commands.c to set up the $? and $^ lists a
la SysV (when archives are being referenced) and changes to remake.c
that look at the command, and if it is explicitly empty (whitespace),
then it assumes that it hasn't done anything, and so later rules
it runs into will force an update.

Short context diff follows:

*** commands.c~	Thu Jul 27 12:17:47 1989
--- commands.c	Thu Jul 27 15:43:55 1989
***************
*** 23,29 ****
--- 23,35 ----
  #include "variable.h"
  #include "job.h"
  
+ #ifdef USG
+ #ifndef sigmask
+ #define sigmask(sig) (1 << ((sig) - 1))
+ #endif
+ #endif
  
+ 
  /* Set FILE's automatic variables up.  */
  
  static void
***************
*** 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 <jay@pcc.COM>	uunet!uvm-gen!banzai!jay, attmail!banzai!jay
The People's Computer Company	`Revolutionary Programming'