是否可以针对特定先决条件抑制变量继承? [英] Is it possible to suppress variable inheritance for a specific prerequisite?

查看:55
本文介绍了是否可以针对特定先决条件抑制变量继承?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个生成共享库的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_SHAREDLINK被定义为以适当的方式调用编译器. rpath的魔力是确保动态链接程序链接到我刚刚编译并要测试的库的确切版本,而不是已安装的库.

问题在于,默认情况下,所有特定于目标的变量都由先决条件继承,因此libstuff.so在其LDFLAGS中获取-lstuff,并且链接程序抱怨找不到它(duh!). /p>

有没有办法说我不想特定的先决条件来继承我的变量,并且仅将其用于依赖关系?

有些我不喜欢的变通办法.例如,我可以覆盖libstuff.so规范中的LDFLAGS=,但是如果我决定定义它们,那么它将不会使用全局LDFLAGS.

变量上有一个"private"修饰符 ,这可以解决LDFLAGS的特殊问题,但是我仍然可以继承CFLAGS之类的其他东西(我想希望由其他先决条件(例如.o文件)继承).我想在先决条件上使用诸如private修饰符之类的东西.

我可以使测试可执行文件与我正在测试的目标文件静态链接,但是我实际上喜欢我正在测试的事实,即我正确链接了共享对象.

我可以通过使用递归make调用来强制make从干净的板岩开始.

.PHONY: test_prerequisites
test_prerequisites:
    $(MAKE) testlib.so

将目标标记为phony会使它每次都执行(应该这样做,因为原始make无法知道其实际依赖关系,否则它将尝试使它们自己运行).不幸的副作用是test可执行文件本身每次都被重建(尽管它是可以容忍的,并且除非必要,至少testlib.so不重建 ).

解决方案

看起来不可能以理智的方式来做,但是由于@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)我几乎总是想要无论如何,在运行测试时都可以重建测试二进制文件,因为我只是更改了要测试的东西.

I have a C++ project that produces a shared library and I want to add tests to it, in a separate executable that dynamically links with the library. So the relevant part of the Makefile looks like this:

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 and LINK are defined to invoke the compiler in an appropriate fashion. The rpath magic is to make sure the dynamic linker links with the exact version of the library I just compiled and want to test, not with the installed one.

The problem is that by default all target-specific variables are inherited by the prerequisites, so libstuff.so gets -lstuff in its LDFLAGS and the linker complains that it can't find it (duh!).

Is there a way to say that I don't want a specific prerequisite to inherit my variables and be used for dependency purposes only?

There are some hacky workarounds that I don't like. For example I can override LDFLAGS= in the libstuff.so specification, but then it wouldn't pick up the global LDFLAGS if I decide to define them.

There's a "private" modifier on variables, which would solve my particular problem with LDFLAGS but I'd still have other things like CFLAGS inherited (and I want it to be inherited by other prerequisites like the .o files). I want something like a private modifier on a prerequisite instead.

I can make the test executable statically link with the object files I'm testing, but I actually like the fact that I'm testing that I linked the shared object properly.

I can force make to start from a clean slate variable-wise by using recursive make invocation:

.PHONY: test_prerequisites
test_prerequisites:
    $(MAKE) testlib.so

Marking the target as phony makes it execute every time (as it should, since the original make can't know about its real dependencies or it would try to make them itself). An unfortunate side effect is that the test executable itself is rebuilt every time (though it's tolerable, and at least testlib.so is not rebuilt unless necessary).

解决方案

Looks like it's impossible to do in a sane way, but I figured out a diabolical contraption that makes the recursive invocation solution work entirely correctly, thanks to @EtanReisner. Here's a complete runnable Makefile mock-up demonstrating the technique:

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)

It uses two "witness" temporary files. When libstuff.so (or any other possible prerequisite) is modified, both witness files are updated and test is rebuilt.

However when libstuff.so is not updated, the first recipe is still always executed (thanks to having a phony prerequisite), then the recursive make invocation sees that the second witness doesn't need to be updated and doesn't execute its recipe, so the first witness is not updated either and test is not rebuilt.

Note: for this particular problem I decided to use the original, simpler recursive make solution because a) I happen to already have a phony target used to build all shared libraries in the project, and b) I pretty much always want the test binary to be rebuilt when running tests anyway, because I just changed something, the thing I want to test.

这篇关于是否可以针对特定先决条件抑制变量继承?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆