是否有特定于目标变量的非传递版本?

时间:2018-08-07 20:21:37

标签: makefile gnu-make

一段时间以来,我一直在使用特定于目标的变量来传递特定于对象的标志。例如,如果我需要将可执行文件与某个库链接,则可以这样做:

bin/foo: LDFLAGS += -lbar

然后bin/%规则将选取-lbar。这对于系统库非常有用,但是当我要链接的库也是项目的一部分时,就会出现问题。在这种情况下,我将具有类似的依赖项

bin/foo: lib/libbar.so

,并且在构建bin/foo时也会传递我应用于lib/libbar.so的特定于目标的规则!由于libbar.so无法链接到自身,因此无法使用。正如manual所说,

  

特定于目标的变量还有一个特殊功能:定义特定于目标的变量时,变量值也对该目标的所有先决条件及其所有先决条件等有效(除非这些先决条件覆盖了该条件,变量及其自己的特定于目标的变量值)。

我该怎么做才能仅为bin/foo添加该标志,而不添加其先决条件?上面的引用暗示了类似的内容

lib/libbar.so: LDFLAGS :=

但这不是理想的,因为我的真实项目中还有其他我想保留的LDFLAGS全局设置。

这里是一个复制者:

  

Makefile

bin/%:
  @mkdir -p $(@D)
  gcc $(LDFLAGS) $(filter %.o,$^) -o $@

lib/%:
  @mkdir -p $(@D)
  gcc $(LDFLAGS) -shared $(filter %.o,$^) -o $@

obj/%.o: src/%.c
  @mkdir -p $(@D)
  gcc $(CFLAGS) -c $< -o $@

bin/foo: obj/foo.o lib/libbar.so
bin/foo: LDFLAGS := -Wl,-rpath='$$ORIGIN/../lib' -Llib -lbar

lib/libbar.so: obj/bar.o

clean:
  rm -rf bin lib obj

.PHONY: clean
     

src / foo.c

int bar(void);

int main() {
  return bar();
}
     

src / bar.c

int bar() {
  return 42;
}

这是坏的:

$ make bin/foo
gcc  -c src/foo.c -o obj/foo.o
gcc  -c src/bar.c -o obj/bar.o
gcc -Wl,-rpath='$ORIGIN/../lib' -Llib -lbar -shared obj/bar.o -o lib/libbar.so
/bin/ld: lib/libbar.so: file not recognized: file truncated
collect2: error: ld returned 1 exit status
make: *** [Makefile:7: lib/libbar.so] Error 1

但是如果我先构建库,它将起作用:

$ make lib/libbar.so
gcc  -c src/bar.c -o obj/bar.o
gcc  -shared obj/bar.o -o lib/libbar.so
$ make bin/foo
gcc  -c src/foo.c -o obj/foo.o
gcc -Wl,-rpath='$ORIGIN/../lib' -Llib -lbar obj/foo.o -o bin/foo
$ ./bin/foo; echo $?
42

2 个答案:

答案 0 :(得分:2)

您可以使用构造的变量名称代替目标特定的变量。这是一种不同的语法,但是允许特定的目标设置。

类似的东西:

LDFLAGS += $($@_FLAGS)

bin/foo_FLAGS = -lbar

更多详细信息,请here (and related articles)

简短的答案是没有可用的特定于目标的无继承功能。如果您不想继承,则必须使用其他方法。

答案 1 :(得分:1)

我认为问题是Unix中(过时的,很抱歉)编译和链接方法的遗产。或者也许是我自己,他不了解某些情况。我发现很难理解为什么链接器调用中的库名会被修饰,以掩盖一个事实,即实际上我们是针对某个接口而不是实际文件进行链接,尽管我们需要该文件来提取该接口的详细描述。那好吧。不管真正的原因是什么,make都不满意这种隐藏和扭曲的依赖信息,因此您遇到了问题,因为对于make,您提供的信息既不是鱼也不是肉。也许像

这样的函数式变量
LIBSWITCHES = $(patsubst lib%,-l%,$(basename $(notdir $(filter %.so,$^))))

可能会有所帮助,因为它试图重新构建与链接库的依赖关系。它从依赖关系列表中获取所有共享库,并根据它们创建一个-l +库名称开关。由于您的库本身没有依赖关系,因此它不会显示在此列表中,因此不应混淆链接程序。只需取出所有-l开关,即可从$(LDFLAGS)实际重建哪个名称库:

bin/%:
    @mkdir -p $(@D)
    gcc $(LDFLAGS) $(LIBSWITCHES) $(filter %.o,$^) -o $@

lib/%:
    @mkdir -p $(@D)
    gcc $(LDFLAGS) $(LIBSWITCHES) -shared $(filter %.o,$^) -o $@

bin/foo: LDFLAGS := -Wl,-rpath='$$ORIGIN/../lib' -Llib