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

依赖于makefile规则中的子目录创建,makefile,directory,dependencies,subdirectory,Makefile,Directory,Dependencies,Subdirectory,我有一个项目,源代码位于src/目录及其子目录(例如src/foo/和src/bar/),对象位于obj目录和匹配的子目录(例如obj/foo/和obj/bar/) 我使用以下(简化)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

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

我使用以下(简化)
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 $@
我如何判断
%.o
文件是否依赖于其包含目录的创建

我试过的 如果没有子目录,则使用“仅订购先决条件”:

但这只解决了
obj/
的问题,而不是
obj/foo
obj/bar/
的问题。我考虑过使用,但我不知道如何将所有这些结合起来

我还在每个目录中使用了隐藏的标记文件,但这只是一个黑客行为,我还在GCC命令前面放了一个
mkdir-p
,但这也让人感觉有黑客行为。如果这是一个潜在的解决方案,我宁愿避免使用递归生成文件

最小示例 要创建与我类似的最小项目,您可以运行:

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

我不知道为什么你在编译前要添加<代码> MKDIr -P<代码>,以“Haky”;我可能会这么做。但是,如果您不介意一直创建的所有目录,也可以这样做:

首先,应该使用
:=
来分配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')
对象:=$(patsubst src/%.c,obj/%.o,$(源代码))
#计算obj目录
OBJDIRS:=$(排序$(目录$(对象))
.第二次扩展:
obj/%.o:src/%.c |$$(@D)
$(CC)-c$<-o$@
美元(OBJDIRS):
mkdir-p$@
我会这样做:

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 $@
SOURCES=$(shell find src-type f-name'*.c')#更正了小错误
...
obj/%.o:src/%.c
如果[!-d$(dir$@)];则mkdir-p$(dir$@);fi
gcc-c$<-o$@
谢谢,我使用了
$(shell dirname$@)
,但是
$(dir$@)
要干净得多。否则,这大致相当于我已经在做的事情(
mkdir-p
忽略已存在目录的创建,因此
if
是多余的)。现在我想一想,
$(@D)
甚至更好,尽管更神秘。
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 $@
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 $@