build-process - 具有目录树创建功能的makefile适合并行(-j)构建

标签 build-process build makefile

我的项目需要使用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/

相关文章:

visual-studio - 在同一解决方案中管理多个项目的连接字符串

visual-studio - 清理 Visual Studio 自定义构建步骤输出

windows - MSYS/Cygwin 中的 "make clean"问题

细化算法的C++代码(EVG-thin)

java - 我可以在构建时使用 Ant 在我的 Android 项目中设置一些静态变量吗?

为类创建文件夹的 Java makefile

.net - 如何自动从 TFS 在线下载最后一个版本?

java - Maven 父 pom 与模块 pom

logging - 是否可以在项目文件中指定 MSBuild 自定义记录器?

rest - Sonatype Nexus REST Api 获取最新的构建版本