在不使用 mkdir -p 的情况下在 Makefile 中创建子目录

Creating subdirectories in Makefile without mkdir -p

GNU standard 表示不对 mkdir 使用 -p 命令是个好主意:

For example, don’t use ‘mkdir -p’, convenient as it may be, because a few systems don’t support it at all and with others, it is not safe for parallel execution

我想遵守这个标准,因此我 运行 在我的 Makefile 中遇到了问题。

我正在递归编译 src 目录中所有目录中的所有 C 源代码,并希望将它们放在 obj 目录中。 obj 目录中镜像了相同的目录结构,但是这些目录最初并不存在。

我可以很容易地 mkdir -p $(@D) 创建我的目录,但是按照 GNU 的标准,我不能这样做,这让我想到了我的问题:我如何在 Makefile 中解决这个问题?

下面是我的 Makefile:

SRCDIR=src
OBJDIR=obj

CC=cc

CFLAGS=
CFLAGS=-g -O2 -pedantic -Wall
ALL_CFLAGS=-std=c89 $(CFLAGS)

# Copied from 
rwildcard=$(foreach d, $(wildcard /*), $(call rwildcard, $d, ) $(filter $(subst *, %, ), $d))

SOURCES=$(call rwildcard, $(SRCDIR), *.c)
OBJECTS=$(subst $(SRCDIR),$(OBJDIR),$(SOURCES:.c=.o))

all: $(OBJECTS)

$(OBJDIR)/%.o: $(SRCDIR)/%.c
    $(CC) $(ALL_CFLAGS) -c -o $@ $<

GNU 标准在很多地方都已经过时了。这似乎是这些地方之一。

如今,mkdir -p is part of POSIX。它甚至不是最近的发明,因为它来自 System V。

由于您的 makefile 假定 C 编译器是 GCC(或至少具有与 GCC 兼容的命令行语法),因此您不妨假定 mkdir -p 有效。如果你想让用户有一种简单的方法来覆盖它,如果它不适合他们,你可以添加:

MKDIR_P = mkdir -p

并在食谱中使用 $(MKDIR_P) 代替 mkdir -p

但这一切真的没有必要。即使是 GNU 的可移植 mkinstalldirs 脚本也已经使用 mkdir -p 很长很长时间了。

您可以只使用 make 依赖项。 在每个文件夹中放置一个文件,例如 .created。 使用模式规则构建 .created 文件, 这自然会创建文件夹作为副作用。

SOURCES=$(call rwildcard, $(SRCDIR), *.c)
OBJECTS=$(subst $(SRCDIR),$(OBJDIR),$(SOURCES:.c=.o))

.PHONY: all
all: $(OBJECTS)

%/.created:
    mkdir -p ${@D}
    touch $@

$(OBJDIR)/%.o: $(SRCDIR)/%.c | ${OBJDIR}/.created
    $(CC) $(ALL_CFLAGS) -c -o $@ $<

表示文件夹由make创建一次,仅在需要时创建。并联也是安全的。

[这只是草图。 你的替换对我来说不合适 — 我假设您在另一个 src/ 文件夹下没有 src/ 文件夹(???), 而且您的 %.o 模式不太正确。]