依赖于makefile规则中的子目录创建

时间:2014-01-05 22:03:32

标签: makefile directory dependencies subdirectory

我有一个项目,其中包含src/目录及其子目录(例如src/foo/src/bar/)中的源,以及obj目录中的对象和匹配的子目录(例如obj/foo/obj/bar/)。

我使用以下(smimplified)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

如何判断%.o文件是否依赖于其包含目录的创建?

我尝试了什么

当没有子目录时,

One solution使用“仅订购先决条件”:

$(OBJECTS): | obj

obj:
    mkdir $@

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

我还在每个目录中使用了隐藏的标记文件,但这只是一个黑客攻击,而且我还在GCC命令之前放了一个mkdir -p,但这也感觉很乱。我宁愿避免使用递归的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

2 个答案:

答案 0 :(得分: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 $@

答案 1 :(得分:1)

我这样做:

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 $@