我正在尝试设置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 $@
我的主要目标是只需更改LIB
和NAME
变量即可编译多个库。
一切正常,所以我为动态库添加了以下内容:
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位。
答案 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
不再需要了)。