如何修改Makefile以分别编译C与C++文件?兼容多版本Make
解决Makefile中C/C++源文件编译规则冲突及跨Make版本兼容问题
首先,原Makefile里的模式规则写法存在核心问题——%.$(OBJ_EXT) : $(C_SRCS) 这条规则的含义是所有.o文件都依赖全部C源文件,而且因为它是第一个模式规则,不管你的.o是从.c还是.cpp生成的,Make都会优先匹配这条规则,自然会用C编译命令处理.cpp对应的目标,这就是你遇到混淆的根本原因。
第一步:修复模式规则,让C/C++文件精准匹配编译命令
把原来的两个错误模式规则替换成针对单个源文件的后缀匹配规则,这是Make处理不同扩展名源文件的标准写法,能让Make根据源文件后缀自动选择对应的编译逻辑:
%.$(OBJ_EXT) : %.$(C_EXT) $(COMPILE_C_COMMAND) %.$(OBJ_EXT) : %.$(CXX_EXT) $(COMPILE_CXX_COMMAND)
这种写法下,每个.o文件只依赖对应的单个源文件,规则是精准匹配后缀的,不会再出现C编译命令处理Cpp文件的情况。
第二步:解决OPUS Make在无.cpp文件时的报错问题
你之前尝试的明确目标列表写法,在CXX_SRCS为空时,$(CXX_OBJ_FILES)也会变成空值,导致规则变成:,这在OPUS Make里会触发"No targets on dependency line"错误,而GNU Make会自动忽略这种空规则。
如果因为特殊需求必须使用明确目标列表的方式,我们可以用Make的条件判断来避免生成空规则:
# 仅当CXX_SRCS不为空时,才定义C++目标规则 ifneq ($(strip $(CXX_SRCS)),) $(CXX_OBJ_FILES) : $(CXX_SRCS) $(COMPILE_CXX_COMMAND) endif # 同理处理C目标规则(可选,若C_SRCS大概率不为空可省略) ifneq ($(strip $(C_SRCS)),) $(C_OBJ_FILES) : $(C_SRCS) $(COMPILE_C_COMMAND) endif
不过更推荐使用第一步的标准模式规则方案,因为模式规则本身就会在没有对应源文件时自动被忽略,完全不会触发跨Make版本的兼容性问题。
完整修正后的Makefile示例
结合上述修复,最终的Makefile如下:
C_EXT ?= c CXX_EXT ?= cpp OBJ_EXT ?= o C_SRCS := \ src/RT_Socket.c \ src/products.c CXX_SRCS := \ src/BurnedInAddress.cpp \ src/DiskID.cpp C_OBJ_FILES += $(C_SRCS:.$(C_EXT)=.$(OBJ_EXT)) CXX_OBJ_FILES += $(CXX_SRCS:.$(CXX_EXT)=.$(OBJ_EXT)) $(ARCHIVE_FILENAME) : $(C_OBJ_FILES) $(CXX_OBJ_FILES) $(CREATE_ARCHIVE_COMMAND) $(LIBRARY_FILENAME) : $(ARCHIVE_FILENAME) $(CREATE_LIBRARY_COMMAND) # 标准后缀匹配模式规则,自动适配C/C++源文件 %.$(OBJ_EXT) : %.$(C_EXT) $(COMPILE_C_COMMAND) %.$(OBJ_EXT) : %.$(CXX_EXT) $(COMPILE_CXX_COMMAND)
这个版本既解决了原规则的混淆问题,又能完美兼容OPUS Make和GNU Make——当没有.cpp文件时,对应的模式规则因为找不到匹配的源文件,会被Make自动忽略,不会触发任何错误。
内容的提问来源于stack exchange,提问作者solvingJ
相关产品推荐
相关产品推荐

