【问题标题】:Depend on subdirectory creation in makefile rule依赖于 makefile 规则中的子目录创建
【发布时间】:2014-01-23 06:08:31
【问题描述】:

我有一个项目,其源代码位于src/ 目录及其子目录(例如src/foo/src/bar/),以及obj 目录和匹配的子目录中的对象(例如obj/foo/ 和@987654328 @)。

我使用以下(简化的)Makefile

SOURCES=$(shell find src/ -type f -name '*.c')
OBJECTS=$(patsubst src/%.c,obj/%.o,$(SOURCES))

all: $(OBJECTS)

obj/%.o: src/%.c
    gcc -c $< -o $@

问题

问题是,如果obj/ 或其子目录之一不存在,我会收到以下错误:

Fatal error: can't create obj/foo/f1.o: No such file or directory

我如何告诉 make %.o 文件依赖于其包含目录的创建?

我尝试了什么

One solution没有子目录的时候是使用“order only 先决条件”:

$(OBJECTS): | obj

obj:
    mkdir $@

但这仅解决了obj/ 的问题,而不是obj/fooobj/bar/。我考虑过使用$(@D),但我不知道如何将所有这些放在一起。

我还在每个目录中使用了隐藏的标记文件,但这只是一个 hack,我还在 GCC 命令之前放了一个mkdir -p,但这也让人觉得很hacky。如果这是一个潜在的解决方案,我宁愿避免使用递归 makefile。

小例子

要创建一个类似于我的最小项目,您可以运行:

mkdir /tmp/makefile-test
cd /tmp/makefile-test
mkdir src/ src/foo/ src/bar/
echo "int main() { return 0; }" > src/main.c
touch src/foo/f1.c src/bar/b1.c src/bar/b2.c

【问题讨论】:

    标签: makefile directory dependencies subdirectory


    【解决方案1】:

    我不知道你为什么考虑在每个编译器操作之前添加mkdir -p 是“hacky”;这可能就是我会做的。但是,如果您不介意一直创建的所有目录,您也可以这样做:

    首先,您应该使用:= 来分配shell 变量,而不是=。前者更有效率。其次,一旦有了文件名列表,就很容易计算目录列表。试试这个:

    SOURCES := $(shell find src/ -type f -name '*.c')
    OBJECTS := $(patsubst src/%.c,obj/%.o,$(SOURCES))
    
    # Compute the obj directories
    OBJDIRS := $(sort $(dir $(OBJECTS))
    
    # Create all the obj directories
    __dummy := $(shell mkdir -p $(OBJDIRS))
    

    如果您真的希望仅在对象即将创建时创建目录,那么您将不得不使用第二次扩展(未测试):

    SOURCES := $(shell find src/ -type f -name '*.c')
    OBJECTS := $(patsubst src/%.c,obj/%.o,$(SOURCES))
    
    # Compute the obj directories
    OBJDIRS := $(sort $(dir $(OBJECTS))
    
    .SECONDEXPANSION:
    
    obj/%.o : src/%.c | $$(@D)
            $(CC) -c $< -o $@
    
    $(OBJDIRS):
            mkdir -p $@
    

    【讨论】:

      【解决方案2】:

      我会这样做:

      SOURCES=$(shell find src -type f -name '*.c')  # corrected small error
      
      ...
      
      obj/%.o: src/%.c
          if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi
          gcc -c $< -o $@
      

      【讨论】:

      • 谢谢,我使用了$(shell dirname $@),但是$(dir $@) 更干净。否则,这大致相当于我已经在做的事情(mkdir -p 忽略了已经存在的目录的创建,所以if 是多余的)。现在想来,$(@D) 更好,虽然更神秘。
      猜你喜欢
      • 1970-01-01
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多