在不使用 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
模式不太正确。]
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
模式不太正确。]