我的项目需要使用mkdir -p在构建过程中创建的临时目录,与此类似:
all: dirtree $(OBJFILES)
dirtree:
@mkdir -p $(BUILD)/temp_directory
但是,此方法不能与-j开关一起使用,因为首先在创建mkdir目标之前先编译OBJFILES。
有没有标准的方法可以做到这一点?
最佳答案
makefile的问题在于,创建目标文件不依赖于相关目录的创建(只有虚假的“all”目标才这样做)。对于-j
选项,这种依赖性是必需的,即使没有它,您的makefile也只能偶然地起作用。有两种(正确的)方式强加所讨论的依赖项。
目录作为单独的目标
您创建了用于创建目录的目标;剩下的只是将其作为目标文件规则的先决条件:
$(BUILD)/temp_directory/%.o: %.c | dirtree
$(CC) $^ -o $@
管道符号
|
表示dirtyree是"order only prerequisite"。当以“dirtree”为先决条件,但尘土变化不会使目标文件无效且不影响编译命令的结果时,将使用此命令。在此使用“仅订购”先决条件很重要。事实是,每次Make调用都会重新生成
dirtree
目标。这也将导致所有依赖它的东西都被重新制作,因此它将每次都重建所有目标文件。在shell命令中创建目录
另一种方法是确保在调用编译之前立即创建目录
$(BUILD)/temp_directory/%.o: %.c
@mkdir -p $(@D)
$(CC) $^ -o $@
注意
$(@D)
的用法。将其扩展为“目标文件的目录”。因此,即使在变量的帮助下,它也可以在许多地方统一使用。Mkdir=@mkdir -p $(@D)
$(BUILD)/temp_directory/%.o: %.c
$(Mkdir)
$(CC) $^ -o $@
$(INSTALL_DIR)/%: src_dir/%
$(Mkdir)
cp -p $^ $@
两种方式均确保在调用编译命令之前已创建目录。两种方法都要求您在每个需要它的规则上写一些文本(
| dirtree
或$(Mkdir)
)。两种方式都与-j
兼容,但是第二种解决方案要求mkdir -p
具有线程安全性(因为两个这样的命令一次可能尝试创建相同的目录,而其中一个会失败)。尽管大多数系统以某种方式实现
mkdir -p
或多或少是线程安全的,但在某些系统(as in some Solaris systems, for example)上,它们的线程安全性却低于其他系统。但是,即使在GNU工具链中,如果mkdir -p
同时调用相同的mkdir(2)
库调用,也可能会失败。如果您想非常安全,也可以解决此问题。可能是什么问题呢?这两个
mkdir -p
脚本试图创建相同的目录,并在C库中的某个位置发生冲突。然后,这些mkdir
-s之一将成功,而另一个将失败。但是,如果您调用的mkdir
失败,则仅当目录由并发mkdir
创建时,它才可能是与线程不安全相关的失败。因此,仅需检查mkdir
调用后是否创建了目标目录就足够了:Mkdir=@mkdir -p $(@D) || test -d $(@D)
(此解决方案在模式方面也存在问题:当目录存在时,mkdir可能会失败,但不符合umask,因此您可能也要进行检查。但是我想这太多了。)
关于build-process - 具有目录树创建功能的makefile适合并行(-j)构建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1894427/