如何在Makefile中仅对指定模式目标使用.NOTPARALLEL?
解决Makefile中特定目标串行、其余目标并行的问题
刚好碰到过类似的场景,要让批量生成的fast_target/%串行构建,同时让slow_target/%这类目标并行跑,其实有两种挺实用的方案,看你环境选就行:
方案一:用文件锁强制串行(类Unix系统首选)
这种方法最简单,利用系统的文件锁机制,让同一时间只有一个fast_target/%的构建命令在执行,其他目标不受影响可以并行。
修改你的Makefile如下:
# 定义锁文件(可以随便取个名字,放在当前目录) FAST_LOCK := .fast_target_build_lock slow_target/%: fast_target/% python $< # 这里主Make会并行启动多个Python进程,没问题 fast_target/%: # 用flock获取锁,只有拿到锁才会执行后面的构建命令 flock $(FAST_LOCK) bash -c './your_optimized_program $* > $@' # 替换上面的./your_optimized_program为你的实际多核程序命令 # 清理时顺便删掉锁文件 .PHONY: clean clean: rm -rf fast_target/ slow_target/ $(FAST_LOCK)
原理说明:
flock会给指定的锁文件加排他锁,只有当前命令执行完释放锁后,下一个fast_target/%的构建才能获取锁开始执行,完美实现所有fast_target/%串行。而slow_target/%的构建因为不需要抢锁,主Make可以并行启动多个Python脚本,完全符合你的需求。
方案二:递归Make实现串行(跨平台通用)
如果你的环境不支持flock(比如Windows),可以用Make的递归调用特性,把fast_target/%的构建放到子Make进程中,并强制子Make串行执行,主Make保持并行能力。
修改后的Makefile示例:
# 全局目标:先构建所有fast_target(串行),再并行构建slow_target .PHONY: all fast_targets slow_targets all: slow_targets # 调用子Make构建fast_targets,强制串行 fast_targets: $(MAKE) -f $(MAKEFILE_LIST) build_fast_targets .NOTPARALLEL # 实际的fast_target构建规则,这里可以用变量或通配符生成目标列表 build_fast_targets: $(wildcard fast_target/*) # 或者用$(FAST_TARGETS)变量定义所有目标 fast_target/%: # 这里写你的多核程序执行命令 ./your_optimized_program $* > $@ # 并行构建slow_targets,依赖已串行构建完成的fast_targets slow_targets: fast_targets $(MAKE) -j $(shell nproc) build_slow_targets # 生成所有slow_target的目标列表 build_slow_targets: $(patsubst fast_target/%,slow_target/%,$(wildcard fast_target/*)) slow_target/%: fast_target/% python $<
原理说明:
- 主Make先启动一个子Make进程,子Make通过
.NOTPARALLEL特殊目标强制所有fast_target/%串行构建; - 等所有
fast_target都构建完成后,主Make再启动另一个子Make(或者直接并行构建),用-j $(shell nproc)充分利用CPU核心,并行执行所有Python脚本。
这个方案完全基于Make的原生特性,跨平台兼容性更好,适合需要在不同系统上运行的场景。
内容的提问来源于stack exchange,提问作者totikom
相关产品推荐
相关产品推荐

