dan*_*tel 8 build-process makefile build
我的项目需要使用mkdir -p在构建期间创建的临时目录,类似于:
all: dirtree $(OBJFILES)
dirtree:
@mkdir -p $(BUILD)/temp_directory
Run Code Online (Sandbox Code Playgroud)
但是这种方法不能与-j开关一起使用,因为在制作mkdir目标之前首先编译OBJFILES.
有没有标准的方法来做到这一点?
P S*_*ved 15
makefile的问题在于,创建目标文件不依赖于相关目录的创建(只有虚假的"所有"目标).这种依赖关系对于-j
选项是必要的,即使没有它,你的makefile也只是偶然的.有两种(正确的)方法可以强制使用相关性.
目录作为单独的目标
您为目录创建创建了目标; 剩下的就是把它作为对象文件规则的先决条件:
$(BUILD)/temp_directory/%.o: %.c | dirtree
$(CC) $^ -o $@
Run Code Online (Sandbox Code Playgroud)
管道符号|
表示dirtree是"仅限订单的先决条件".当"dirtree"是先决条件时使用它,但是dirtree中的更改不会使目标文件无效,也不会影响编译命令的结果.
在这里使用"仅订购"先决条件非常重要.问题是dirtree
每次Make调用都会重新生成目标.这将导致依赖于它的所有内容也被重新创建,因此它每次都会重建所有目标文件.
在shell命令中创建目录
另一种方法是确保在调用编译之前立即创建目录
$(BUILD)/temp_directory/%.o: %.c
@mkdir -p $(@D)
$(CC) $^ -o $@
Run Code Online (Sandbox Code Playgroud)
注意用法$(@D)
.这被扩展为"目标文件的目录".因此它可以在许多地方统一使用,甚至可以在变量的帮助下使用.
Mkdir=@mkdir -p $(@D)
$(BUILD)/temp_directory/%.o: %.c
$(Mkdir)
$(CC) $^ -o $@
$(INSTALL_DIR)/%: src_dir/%
$(Mkdir)
cp -p $^ $@
Run Code Online (Sandbox Code Playgroud)
两种方式都可确保在调用编译命令之前创建目录.两种方式都要求您在需要它的每个规则上写一些文本(| dirtree
或者$(Mkdir)
).两种方式都是-j
兼容的,但第二种解决方案需要mkdir -p
是线程安全的(因为两个这样的命令可能会尝试创建相同的目录,其中一个会失败).
虽然大多数系统mkdir -p
在某些系统(例如某些Solaris系统)中以一种或多或少线程安全的方式实现它,但它们的线程安全性低于其他系统.但是,即使在GNU工具链中,mkdir -p
如果它们同时调用相同的mkdir(2)
库调用,也可能会失败.
如果你想要非常安全,你也可以这样做.可能是什么问题呢?这两个mkdir -p
脚本尝试创建相同的目录,并在C库中的某个地方发生冲突.然后,其中一个mkdir
-s将成功,另一个将失败.但是,如果mkdir
您调用失败,那么只有当目录是由并发创建的时,它才可能与线程不安全相关mkdir
.因此,只需检查mkdir
调用后是否创建目标目录就足够了:
Mkdir=@mkdir -p $(@D) || test -d $(@D)
Run Code Online (Sandbox Code Playgroud)
(这个解决方案也存在模式问题:当目录存在时mkdir可能会失败,但是不符合umask,所以你可能也想检查它.但是我想这太多了.)
归档时间: |
|
查看次数: |
3592 次 |
最近记录: |