我有一个C ++项目,它生成一个共享库,我希望在一个单独的可执行文件中添加测试,它可以动态地链接到库。所以Makefile的相关部分如下所示:
libstuff.so: stuff.o
$(LINK_SHARED)
test: LDLFAGS += -L$(CURDIR) -Wl,-rpath=$(CURDIR) -lstuff
test: libstuff.so
test: test.o
$(LINK)
check:: test
./test
LINK_SHARED
和LINK
被定义为以适当的方式调用编译器。 rpath
法术是为了确保动态链接器链接到我刚刚编译并想要测试的库的确切版本,而不是使用已安装的库。
问题是默认情况下所有特定于目标的变量都由先决条件继承,因此libstuff.so
在其-lstuff
中获得LDFLAGS
,并且链接器抱怨它无法找到它(杜!)。
有没有办法说我不想要一个特定的先决条件来继承我的变量并仅用于依赖目的?
我不喜欢一些hacky变通方法。例如,我可以覆盖LDFLAGS=
规范中的libstuff.so
,但如果我决定定义它们,它就不会获取全局LDFLAGS。
有一个"private" modifier on variables,它会解决我LDFLAGS
的特殊问题,但我仍然会继承CFLAGS
之类的其他内容(我想要它要被.o
文件等其他先决条件继承。我希望在先决条件上使用类似私有修饰符的东西。
我可以使测试可执行文件与我正在测试的目标文件静态链接,但我实际上喜欢我正在测试我正确链接共享对象的事实。
我可以通过使用递归make调用来强制make从一个干净的slate开始变量:
.PHONY: test_prerequisites
test_prerequisites:
$(MAKE) testlib.so
将目标标记为虚假使其每次都执行(因为它应该,因为原始make无法知道它的真实依赖性,或者它会尝试自己制作它们)。一个不幸的副作用是test
可执行文件本身每次都被重建(尽管它是可以容忍的,并且除非必要,否则至少{em}> 不重建
答案 0 :(得分:1)
看起来不可能以理智的方式做,但我想出了一个恶魔般的装置,使得递归调用解决方案完全正确,感谢@EtanReisner。这是一个完整的可运行Makefile模型,演示了该技术:
all:test
define LINK =
@echo linking $@ with LDFLAGS=$(LDFLAGS)
@touch $@
endef
stuff.o test.o:
@echo compiling $@
@touch $@
libstuff.so: stuff.o
$(LINK)
.PHONY: FORCE
# A hack to avoid spilling LDFLAGS to prerequisites
.test_prerequisites.tmp: FORCE
$(MAKE) .test_prerequisites2.tmp
.test_prerequisites2.tmp: libstuff.so
touch .test_prerequisites.tmp .test_prerequisites2.tmp
test: LDFLAGS += -L$(CURDIR) -Wl,-rpath=$(CURDIR) -lstuff
test: .test_prerequisites.tmp
test: test.o
$(LINK)
它使用两个“见证”临时文件。修改libstuff.so
(或任何其他可能的先决条件)时,将更新两个见证文件并重建test
。
但是当libstuff.so
没有更新时,第一个配方仍然总是被执行(由于有一个虚假的先决条件),然后递归make调用看到第二个见证不需要更新并且不会执行其配方,因此第一个见证人也不会更新,test
不会重建。
注意:对于这个特殊问题,我决定使用原始的,更简单的递归make解决方案,因为a)我碰巧已经有一个用于在项目中构建所有共享库的虚假目标,并且b)我几乎总是希望测试二进制文件,无论如何都要在运行测试时重建,因为我只是改变了一些东西,我想要测试它。
答案 1 :(得分:0)
添加变量LDFLAGS_TEST并将其添加到LINK命令进行测试。
如果您不想这样做,请参阅以下类似问题: Define make variable at rule execution time