代码之家  ›  专栏  ›  技术社区  ›  Tavian Barnes

是否存在目标特定变量的非传递版本?

  •  1
  • Tavian Barnes  · 技术社区  · 6 年前

    我已经使用了一段时间的目标特定变量来传递对象特定的标志。例如,如果我需要将可执行文件链接到某个库,我可以:

    bin/foo: LDFLAGS += -lbar
    

    以及 bin/% 规则会起作用的 -lbar . 这对系统库非常有用,但是当我链接的库也是项目的一部分时,就会出现问题。在这种情况下,我会有一个依赖

    bin/foo: lib/libbar.so
    

    以及我应用到的目标特定规则 bin/foo 建造时也通过 lib/libbar.so ! 这不起作用,因为 libbar.so 无法链接到自身。作为 manual 说,

    目标特定变量还有一个更特殊的特性:当您定义目标特定变量时,该变量值也适用于此目标的所有先决条件及其所有先决条件等(除非这些先决条件使用自己的目标特定变量值覆盖该变量)。

    我能做些什么来添加这个标志呢 垃圾箱/食品 但不是先决条件?上面的引文暗示

    lib/libbar.so: LDFLAGS :=
    

    但这并不理想,因为我真正的项目已经在全球设置了其他LDFLAGS,我想保留它们。

    这里有一个复制器:

    生成文件

    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();
    }
    

    钢筋混凝土

    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
    

    但如果我先构建lib,它就会工作:

    $ 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 回复  |  直到 6 年前
        1
  •  2
  •   MadScientist    6 年前

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

    类似于:

    LDFLAGS += $($@_FLAGS)
    
    bin/foo_FLAGS = -lbar
    

    可以找到更多详细信息 here (and related articles)

    简而言之,如果没有可用的继承特性,就没有特定的目标。如果你不想继承遗产,你就得用不同的方法。

        2
  •  1
  •   Vroomfondel    6 年前

    我认为问题在于Unix中(老式的,呃,对不起)编译和链接方法的传统。或者是我不知道什么背景。我发现很难理解为什么库名称在链接器调用中被破坏,以隐藏这样一个事实:实际上,我们链接的是一个接口,而不是一个实际的文件——尽管我们需要这个文件来提取对所述接口的一个微不足道的描述。哦,好吧。不管真正的原因是什么, make 对这种隐藏和扭曲的依赖性信息不满意,所以你遇到了问题,因为 制作 ,你提供的信息既不是鱼也不是肉。也许像变量这样的函数

    LIBSWITCHES = $(patsubst lib%,-l%,$(basename $(notdir $(filter %.so,$^))))
    

    可能会有所帮助,因为它试图重建与链接库的依赖关系。它从依赖关系列表中获取所有共享对象,并创建 -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