Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GNU make implicit archive rule with stem

I am trying to setup a Makefile to build either static (.a) and dynamic (.so) libraries depending on the target file extension.

I previously used the following Makefile for static libraries only :

NAME   := config
LIB    := lib$(NAME).a
SRC    := $(wildcard *.c)
OBJ    := $(SRC:.c=.o)
CFLAGS += -W -Wall

.PHONY: all clean fclean re

all: $(LIB)

clean:
    @$(RM) $(OBJ)

fclean: clean
    @$(RM) $(LIB)

re: fclean all

$(LIB): $(LIB)($(OBJ))
    ranlib $@

My main goal is to be able to compile multiple libraries by only changing the LIB and NAMEvariables.

Everything worked fine, so I added the following for the dynamic libraries :

LDFLAGS += -shared

%.so: CFLAGS += -fPIC
%.so: $(OBJ)
    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^

And changed the $(LIB): rule by the following generic rule :

%.a: %.a($(OBJ))
    ranlib $@

If I change LIB to lib$(NAME).so everything works as expected, but with the .a extension, make prints me this error :

make: *** No rule to make target 'libconfig.a', needed by 'all'. Stop.

The only solution I found was to add another explicit rule like that :

%.a($(OBJ)): $(OBJ)
    $(AR) rv $@ $^

And now everything works.

But adding this explicit rule prevents me from relying only upon GNU make's implicit rules, and makes me call explicitly ar, which I wanted to avoid.

Is this some kind of bug or am I missing something ?

GNU Make 3.82
Built for x86_64-unknown-linux-gnu
like image 949
Chnossos Avatar asked Mar 26 '14 13:03

Chnossos


1 Answers

Some quick testing seems to indicate that this can't be done. It appears that the specialized make archive support is a makefile parse time feature. That is the literal archive name must exist in the actual makefile for it to take effect.

I tried a couple of workarounds but wasn't able to get any of them to work correctly. The closest I could manage was:

$(foreach a,$(filter %.a,$(MAKECMDGOALS) $(.DEFAULT_GOAL)),$(eval $a: $a($$(OBJ)); ranlib $$@))

which doesn't work for a default goal of all but would if the default was the library name and/or if the library name is an explicit make target. You could stick any other known library names in there too and then they should work even as implicit requirements of other targets but that's a manual process.

like image 158
Etan Reisner Avatar answered Oct 18 '22 09:10

Etan Reisner