【问题标题】:Complex pattern substitution in Makefile prerequisitesMakefile 先决条件中的复杂模式替换
【发布时间】:2012-05-16 01:43:49
【问题描述】:

我有以下目录结构:

./
 |- obj/
 |--- debug/
 |--- release/
 |- bin/
 |--- debug/
 |--- release/
 |- src/
 |--- main.c
 |--- libb/
 |----- foo.c
 |- include/
 |--- libb/
 |----- foo.h

此外,我在Makefile 中手动指定各个对象的依赖关系,格式如下(示例):

 main_DEPS = libb/foo

现在我希望能够输入make bin/debug/main,这会生成必要的依赖项和目标文件:

  • obj/debug/libb/foo.o
  • obj/debug/main.o
  • bin/debug/main

我该怎么做?我目前的方法非常复杂且不完整:

  • 以下创建目标文件。但是,如果它们尚不存在,则无法创建任何必要的子文件夹 (libb)。它也不跟踪任何更改的头文件。 Makefile tutorial trick to generate prerequisites automatically 可以改编吗?

    CFLAGS+=-I include
    
    obj/*/%.o: src/%.cpp
        $(CC) $(CFLAGS) $< -c -o $@
    
  • 以下尝试解决二进制文件的依赖关系并从所有必需的目标文件构建它。但我不知道如何从 *_DEPS 变量中检索这些目标文件。

    .SECONDEXPANSION:
    
    bin/debug/%: obj/debug/%.o $(patsubst %,obj/debug/%.o,$($(patsubst bin/debug/%,%,$@)_DEPS))
        $(LD) $(LDFLAGS) $< $(patsubst %,obj/debug/%.o,$($(patsubst bin/debug/%,%,$@)_DEPS)) -o $@
    
    bin/release/%: obj/release/%.o $(patsubst %,obj/release/%.o,$($(patsubst bin/release/%,%,$@)_DEPS))
        $(CXX) $(LDFLAGS) $< $(patsubst %,obj/release/%.o,$($(patsubst bin/release/%,%,$@)_DEPS)) -o $@
    

    不幸的是,这不会自动构建依赖关系:它只是抱怨“obj/debug/libb/foo.o:没有这样的文件或目录”——但如果我使用 mkdir obj/debug/libb; make obj/debug/libb/foo.o 手动构建这个文件,它的工作方式就够奇怪了。

    它也非常复杂,并且使用了无缘无故的代码重复(如果不让它变得更加复杂,我就无法摆脱它)。

对此最简单的解决方案是什么?原则上我不反对使用 make 以外的其他东西,如果它可以广泛使用(autoconf ...),但我更喜欢将努力(和所需的新学习)保持在最低限度,并且从我迄今为止看到的所有其他构建系统似乎比 make 复杂得多。

【问题讨论】:

    标签: dependencies makefile build-automation


    【解决方案1】:

    更新以回应chat message

    @sehe 稍微简单了点,是的……但是重复的还是有的,还有没有构建依赖的问题

    我找到了一种冗长但有效(不​​复杂)的方法来使其与 submake 调用一起工作(在单个 Makefile 中)。

    我们有只包含一个规则和依赖定义的“外部制作”

    A_DEPS=dep1 dep2
    C_DEPS=dep2
    
    ##########################
    # "outer" Make
    bin/%/A bin/%/B bin/%/C:
        $(MAKE) BUILD="$*" TARGET=$(@F) DEPS="$($(@F)_DEPS)" GENRULE
    

    实际上,我们将“推导”的信息转换为子调用 make 时的显式变量。 Makefile 的其余部分包含我们的'通用目标规则'的定义,GENRULE:

    ##########################
    # "inner" Make
    
    %/*.o:
        mkdir -p "$(@D)" && touch "$@"
    
    GENRULE: obj/$(BUILD)/$(TARGET).o $(DEPS:%=obj/$(BUILD)/%.o) 
        echo gcc -o "bin/$(BUILD)/$(TARGET)" $^
        mkdir -p "bin/$(BUILD)" && touch "bin/$(BUILD)/$(TARGET)"
    .PHONY: GENRULE
    

    再次进行测试:

    $ for target in bin/{debug,release}/{A,B,C}; do make -Bs "$target"; done
    
    gcc -o bin/debug/A obj/debug/A.o obj/debug/dep1.o obj/debug/dep2.o
    gcc -o bin/debug/B obj/debug/B.o
    gcc -o bin/debug/C obj/debug/C.o obj/debug/dep2.o
    gcc -o bin/release/A obj/release/A.o obj/release/dep1.o obj/release/dep2.o
    gcc -o bin/release/B obj/release/B.o
    gcc -o bin/release/C obj/release/C.o obj/release/dep2.o
    

    对象已全部创建:

    $ find bin obj
    
    bin
    bin/debug
    bin/debug/A
    bin/debug/B
    bin/debug/C
    bin/release
    bin/release/A
    bin/release/B
    bin/release/C
    obj
    obj/debug
    obj/debug/A.o
    obj/debug/B.o
    obj/debug/C.o
    obj/debug/dep1.o
    obj/debug/dep2.o
    obj/release
    obj/release/A.o
    obj/release/B.o
    obj/release/C.o
    obj/release/dep1.o
    obj/release/dep2.o
    

    对于简单变量(非依赖项),这是一个使用 $@ 和 $(@F) 自动变量的简单示例:

    EXTRA="--standardopts"
    A_FLAGS="--a-opts"
    B_FLAGS="--b-opts"
    
    .SECONDEXPANSION:
        
    debug/% release/%: EXTRA+=$($(@F)_FLAGS)
    
    %/A %/B %/C:
        echo building $@ with $(EXTRA)
    

    【讨论】:

      猜你喜欢
      • 2023-03-23
      • 1970-01-01
      • 2013-04-22
      • 1970-01-01
      • 2016-08-18
      • 2015-05-18
      • 1970-01-01
      • 1970-01-01
      • 2014-03-08
      相关资源
      最近更新 更多