3

I haven't been doing a lot of C programming lately, but recently I revisited an old project and found the old Makefile to build a library under FreeBSD no longer works. Here's a much simplified version of the Makefile that used to work:

TEST    = Test
LIBTEST = lib$(TEST).a

CC      = cc

.PRECIOUS: $(LIBTEST)

all: $(LIBTEST)

LIBSRC  = test.c

# Do not automatically delete library source files
.SECONDARY: $(LIBSRC)

LIBOBJ  = $(LIBSRC:%.c=%.o)

$(LIBTEST): $(LIBTEST)($(LIBOBJ))
        $(AR) $(ARFLAGS) $@ $?
        rm -f $?

clean:
        @rm -f *.o $(LIBTEST)

And here's a trivial C program to go with it:

/* test.c */
#include <stdio.h>

int
test(char const *text)
{
    printf("%s\n", text);
    return 1;
}

It looks like the Makefile directive dependency:

$(LIBTEST): $(LIBTEST)($(LIBOBJ))

no longer works. It results in:

 ar -crD libTest.a
 rm -f

I've been perusing 'man make' without success.

One thing that puzzles me is that 'man make' says "For a more thorough description of make and makefiles, please refer to PMake - A Tutorial."

Is this accurate? I was under the impression that pmake was replaced by bsdmake in recent versions of FreeBSD - is this the source of my problems?

Note: I am not interested in answers that boil down to "you can do this just fine using GNU make" - this is a question for FreeBSD make.

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
varro
  • 2,382
  • 2
  • 16
  • 24

1 Answers1

1
$(LIBTEST): $(LIBTEST)($(LIBOBJ))

suggests that prerequisite of $(LIBTEST) (here libTest.a) is a $(LIBOBJ) (here test.o) member of that archive, which I am not really sure what make would be supposed to conclude from, but for me (FreeBSD 11.0) it comes up with all (which really means libTest.a) is already up to date (see also an example below the ruler). Changing the line to:

$(LIBTEST): $(LIBOBJ)

Would seem to make sense (and unless I've missed something, should be what you want), an object file is prerequisite of the library target and rule updates the library with all prerequisites newer then the target ($?).

Which leads me to one more comment. That rm seems not only unnecessary, but actually harmful, because it means test.o always gets recompiled on invocation of make all and library always gets updated even there is no source (test.c) change as the intermediate prerequisite target is not there (i.e. out of date).


I'd really get that behavior even if I resolve all the stuff around and strip that Makefile to a bare minimum:

$ ls
Makefile        test.c
$ cat Makefile 
libTest.a: libTest.a(test.o)
        $(AR) $(ARFLAGS) $@ $?
$ make
`libTest.a' is up to date.
$ ls
Makefile        test.c
Ondrej K.
  • 8,841
  • 11
  • 24
  • 39
  • Using `$(LIBTEST): $(LIBOBJ)` is not what I want, since it makes the target depend on external object files. The parentheses syntax for maintaining archives is ancient and I've used it in the past under various flavours of Unix, including FreeBSD. You can check up on it for pmake [here](https://www.freebsd.org/doc/en/books/pmake/archivesandlibraries.html) and for gmake [here](https://www.gnu.org/software/make/manual/html_node/Archive-Members.html#Archive-Members)] I can of course work around it by simply using gnumake instead, but I'd rather use the standard `make` if possible. – varro Oct 04 '18 at 21:58
  • Right, I've tried that with `gmake` and it actually appears to work as you expected (and I can imagine other flavors or versions of `make` could just as well). How does `gmake` make sense out of member of self being prerequisite of an archive? It has an (implicit) pattern rule making `test.o` a prerequisite of `libTest.a(test.o)`, not sure how to express that with a suffix rule for (bsd) `make` (actually I unsure it is even possible). – Ondrej K. Oct 04 '18 at 22:48
  • That means though that `test.o` would still get built and used. I am not sure, what do you mean by "external object files", that you're trying to avoid? You do not want to use `.o` (built from local `.c`) in case the archive already had a member of that name? I guess I wonder what exactly is the desired behavior in order to properly devise how to achieve it (and why object file as prerequisite) does not fit the bill. – Ondrej K. Oct 04 '18 at 22:51