如何基于目标为Makefile配置不同后缀规则实现编译切换?
问题
我现在在Makefile里通过注释切换两组编译标志,来实现程序的优化编译或调试信息输出。想改成基于调用的目标(比如program-optimized或program-debug)自动使用对应的编译规则,让源码文件也用对应标志编译,不用手动注释切换。以下是现有代码和我的尝试方案,想问这个方案是否可行,以及正确的实现方式:
现有代码
FC = gfortran # 我通过注释其中一行来切换编译标志 # FFLAGS = -Og -Wall -Wextra -fcheck=all -fbacktrace -fbounds-check FFLAGS = -O3 MOD='Modules/' SRC = Modules/pyplot_module.f90 SRC += Modules/logs.f90 SRC += program.f90 OBJ = ${SRC:.f90=.o} %.o: %.f90 $(FC) -c -J${MOD} $< $(FFLAGS) -o $@ program: $(OBJ) $(FC) -J${MOD} $(FFLAGS) -o $@ $(OBJ) remake: remove program clean: rm -f **/*.o **/*.mod remove: clean rm -f program
尝试方案
FC = gfortran # 这里做了修改 DEBUGFFLAGS = -Og -Wall -Wextra -fcheck=all -fbacktrace -fbounds-check FFLAGS = -O3 MOD='Modules/' SRC = Modules/pyplot_module.f90 SRC += Modules/logs.f90 SRC += program.f90 OBJ = ${SRC:.f90=.o} %.o: %.f90 $(FC) -c -J${MOD} $< $(FFLAGS) -o $@ %.o: %.f90 # 我希望这个后缀规则只在构建program-debug目标时生效 $(FC) -c -J${MOD} $< $(DEBUGFFLAGS) -o $@ program-optimized: $(OBJ) $(FC) -J${MOD} $(FFLAGS) -o $@ $(OBJ) program-debug: $(OBJ) # 但我也希望源码文件用这些标志编译 $(FC) -J${MOD} $(DEBUGFFLAGS) -o $@ $(OBJ) remake: remove program clean: rm -f **/*.o **/*.mod remove: clean rm -f program
解决方案
你的尝试方案不可行,因为Makefile中如果有多个相同的模式规则(比如两个%.o: %.f90),只会执行最后定义的那一个。也就是说不管你构建program-optimized还是program-debug,所有.o文件都会用DEBUGFFLAGS编译,完全达不到分目标切换的效果。
下面是两种正确的实现方式:
方式一:使用目标特定变量
利用Makefile的目标特定变量功能,给不同的目标指定对应的编译标志,同时让.o文件的编译规则自动继承当前目标的标志:
FC = gfortran DEBUGFFLAGS = -Og -Wall -Wextra -fcheck=all -fbacktrace -fbounds-check OPTFFLAGS = -O3 MOD='Modules/' SRC = Modules/pyplot_module.f90 SRC += Modules/logs.f90 SRC += program.f90 OBJ = ${SRC:.f90=.o} # 默认目标设为优化版 .DEFAULT_GOAL := program-optimized # 通用编译规则 %.o: %.f90 $(FC) -c -J${MOD} $< $(FFLAGS) -o $@ # 优化版目标:指定FFLAGS为优化标志 program-optimized: FFLAGS = $(OPTFFLAGS) program-optimized: $(OBJ) $(FC) -J${MOD} $(FFLAGS) -o $@ $(OBJ) # 调试版目标:指定FFLAGS为调试标志 program-debug: FFLAGS = $(DEBUGFFLAGS) program-debug: $(OBJ) $(FC) -J${MOD} $(FFLAGS) -o $@ $(OBJ) # 切换目标时强制清理旧文件,确保重新编译 program-debug: clean program-optimized: clean remake: remove program-optimized clean: rm -f **/*.o **/*.mod remove: clean rm -f program-optimized program-debug
这种写法简洁,通过给不同目标绑定专属的FFLAGS,让编译规则自动适配。添加clean依赖是为了避免切换目标时,Makefile认为旧的.o文件已经最新而跳过编译。
方式二:分离不同模式的目标文件目录
把调试版和优化版的.o文件分别放到不同的目录(比如build/debug和build/optimized),彻底避免文件冲突,还能同时保留两种版本的可执行文件:
FC = gfortran DEBUGFFLAGS = -Og -Wall -Wextra -fcheck=all -fbacktrace -fbounds-check OPTFFLAGS = -O3 MOD='Modules/' SRC = Modules/pyplot_module.f90 SRC += Modules/logs.f90 SRC += program.f90 # 定义不同模式的目标文件路径 DEBUG_OBJ = $(addprefix build/debug/,$(SRC:.f90=.o)) OPT_OBJ = $(addprefix build/optimized/,$(SRC:.f90=.o)) .DEFAULT_GOAL := program-optimized # 调试版目标文件编译规则 build/debug/%.o: %.f90 @mkdir -p $(dir $@) $(FC) -c -J${MOD} $< $(DEBUGFFLAGS) -o $@ # 优化版目标文件编译规则 build/optimized/%.o: %.f90 @mkdir -p $(dir $@) $(FC) -c -J${MOD} $< $(OPTFFLAGS) -o $@ program-optimized: $(OPT_OBJ) $(FC) -J${MOD} $(OPTFFLAGS) -o $@ $(OPT_OBJ) program-debug: $(DEBUG_OBJ) $(FC) -J${MOD} $(DEBUGFFLAGS) -o $@ $(DEBUG_OBJ) remake: remove program-optimized clean: rm -rf build/ rm -f **/*.mod remove: clean rm -f program-optimized program-debug
这种方式的优势是可以同时保留调试版和优化版的可执行文件,切换目标时不需要手动清理,Makefile会自动处理不同目录下的目标文件,适合需要同时维护两个版本的场景。
内容的提问来源于stack exchange,提问作者nikost
相关产品推荐
相关产品推荐

