GNU使用干创建隐式归档规则

Chn*_*sos 5 c makefile gnu-make

我正在尝试设置一个Makefile以根据目标文件扩展名构建静态(.a)和动态(.so)库。

我以前仅将以下Makefile用于静态库:

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 $@
Run Code Online (Sandbox Code Playgroud)

我的主要目标是仅通过更改LIBNAME变量就能够编译多个库。

一切正常,因此我为动态库添加了以下内容:

LDFLAGS +=  -shared

%.so:   CFLAGS += -fPIC
%.so:   $(OBJ)
    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
Run Code Online (Sandbox Code Playgroud)

$(LIB):通过以下通用规则更改了规则:

%.a:    %.a($(OBJ))
    ranlib $@
Run Code Online (Sandbox Code Playgroud)

如果我更改LIBlib$(NAME).so一切正常,但使用.a扩展名,make将显示此错误:

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

我发现的唯一解决方案是添加另一个类似的显式规则

%.a($(OBJ)):    $(OBJ)
    $(AR) rv $@ $^
Run Code Online (Sandbox Code Playgroud)

现在一切正常。

但是添加此显式规则可以防止我仅依赖GNU make的隐式规则,并使我显式地调用ar,这是我想要避免的。

这是某种错误还是我错过了一些东西?

PS:make -v打印以下输出:

GNU Make 3.82
Built for x86_64-unknown-linux-gnu
Run Code Online (Sandbox Code Playgroud)

我正在使用64位的OpenSUSE 12.3(Dartmouth)。

Chn*_*sos 0

档案和共享库不共享相同的先决条件语法,因此不可能有一个规则来处理这两者。

最简单的解决方案是在目标扩展上使用条件:

ifeq "$(suffix $(LIB))" ".a"
$(LIB): $(LIB)($(OBJ))
else ifeq "$(suffix $(LIB))" ".so"
$(LIB): override CFLAGS += -fPIC
$(LIB): $(OBJ)
    $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
endif
Run Code Online (Sandbox Code Playgroud)

满足要求的工作 Makefile 现在如下所示:

NAME := config

LIB := lib$(NAME).so

SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(OBJ:.o=.d)

CPPFLAGS := -MMD -MP
CFLAGS   := -W -Wall
LDFLAGS  := -shared
ARFLAGS  := rs

.PRECIOUS: $(OBJ)
.PHONY: all clean fclean re

all: $(LIB)

clean:
    $(RM) $(OBJ) $(DEP)

fclean: clean
    $(RM) $(LIB)

re: fclean all

ifeq "$(suffix $(LIB))" ".a"
$(LIB): $(LIB)($(OBJ))
else ifeq "$(suffix $(LIB))" ".so"
$(LIB): override CFLAGS += -fPIC
$(LIB): $(OBJ)
    $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
endif

ifeq "$(MAKECMDGOALS)" ""
-include $(DEP)
endif
Run Code Online (Sandbox Code Playgroud)

请注意,该ARFLAGS变量控制将哪些标志传递给 的调用ar。在这里,我使用该r标志来替换现有对象(如果存在),并使用该s标志来构建或更新索引(ranlib不再需要)。