GNU使用stem进行隐式归档规则

时间:2014-03-26 13:28:03

标签: 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 $@

我的主要目标是只需更改LIBNAME变量即可编译多个库。

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

LDFLAGS +=  -shared

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

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

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

如果我将LIB更改为lib$(NAME).so,一切都按预期工作,但使用.a扩展程序,make会将此错误打印出来:

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

我找到的唯一解决方案是添加另一个显式规则

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

现在一切正常。

但是添加这个明确的规则会阻止我仅仅依赖于GNU make的隐式规则,并且让我明确地调用ar,这是我想要避免的。

这是某种错误还是我错过了什么?

P.S。:make -v打印以下输出:

GNU Make 3.82
Built for x86_64-unknown-linux-gnu

我正在使用OpenSUSE 12.3(达特茅斯)64位。

3 个答案:

答案 0 :(得分:3)

一些快速测试似乎表明无法做到这一点。专用的make archive支持似乎是一个makefile解析时功能。也就是说,文字存档名必须存在于实际的makefile中才能生效。

我尝试了几种解决方法,但无法使其中任何一种正常工作。我能管理得最近的是:

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

对于all的默认目标不起作用,但如果默认值是库名称和/或库名称是显式make目标,则会起作用。您也可以在其中粘贴任何其他已知的库名称,然后它们应该作为其他目标的隐含要求工作,但这是一个手动过程。

答案 1 :(得分:0)

您需要告诉make 给定.a文件所依赖的 .o文件。您可以通过简单的依赖而无需操作来实现:

libconfig.a: libconfig.a($(OBJ))

make然后会调用默认规则将.o文件放入.a文件中以实际构建libconfig.a

答案 2 :(得分:0)

归档和共享库不共享相同的先决条件语法,因此无法使用单个规则来处理这两种语法。

最简单的解决方案是在目标扩展程序上使用conditional

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

满足要求的工作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

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