Makefile编译出现fatal error: defs.h: No such file or directory
报错根因拆解
你现在遇到的defs.h: No such file or directory报错,本质是Makefile存在多处语法和逻辑错误,导致你定义的头文件搜索路径根本没有传递给g++编译器,具体问题点如下:
- 自定义编译规则完全匹配不上实际源文件
你定义的编译规则是%.o: %.c,只匹配.c后缀的C语言源文件,但项目内所有源文件都是.cpp后缀的C++文件。make找不到匹配的显式编译规则,就会自动调用内置的默认编译逻辑,也就是不带任何自定义参数的g++ -c命令——这也是为啥报错里的编译命令光秃秃的,没有任何你写的-I路径参数的原因。 - 规则的依赖与命令混写,参数完全失效
你把$(INCLUDE)变量写在了编译规则的依赖列表里,make会把这个位置的内容当成需要追踪的文件路径,根本不会把它当成编译参数传递给g++。哪怕规则能匹配上,INCLUDE变量也起不到任何头文件搜索路径的作用。 - 最终链接目标的规则语法错误
你写的vcd_converter: ${OBJ} main_converter.cpp $(CC) $(INCLUDE) -o vcd_converter ${OBJ} main_converter.cpp $(CFLAGS)这行,把编译命令全部混在了目标的依赖列表里,没有单独写在规则对应的脚本行中,make根本不会识别这段内容为要执行的编译命令。 - 编译/链接参数混放
你把-lstdc++fs -lpthread这类链接阶段才需要的参数放到了CFLAGS编译参数里,编译阶段传递这些参数没有任何作用。
注:你原来写的跨目录头文件相对路径../../../../processor/src/main/cpp本身的层级计算是正确的,只是因为规则写错了,没有生效而已。
修正后的可用Makefile
# 编译器配置 CC = g++ # 头文件搜索路径:当前目录 + processor项目下的cpp源码目录 INCLUDE = -I. -I../../../../processor/src/main/cpp # 编译阶段参数 CFLAGS = -std=c++17 -fconcepts -Wall # 链接阶段参数 LDFLAGS = -lstdc++fs -lpthread # 需要追踪的依赖头文件列表 DEPS = \ ../../../../processor/src/main/cpp/defs.h \ agu.h \ agu_mem.h \ input_agu.h \ is_configurable.h \ is_steppable.h \ output_agu.h \ output_agu_mem.h \ pe.h \ vcd_converter.h \ ../../../../processor/src/main/cpp/util.h \ input_agu_mem.h \ ../../../../processor/src/main/cpp/argparser.h # 参与链接的目标文件列表 OBJ = \ ../../../../processor/src/main/cpp/defs.o \ vcd_converter.o \ is_configurable.o \ is_steppable.o \ pe.o \ agu.o \ input_agu.o \ output_agu.o \ agu_mem.o \ input_agu_mem.o \ output_agu_mem.o \ ../../../../processor/src/main/cpp/argparser.o \ main_converter.o # 通用编译规则:匹配所有.cpp后缀的源文件 %.o: %.cpp $(DEPS) $(CC) -c $(INCLUDE) $(CFLAGS) $< -o $@ # 最终可执行文件链接规则 vcd_converter: $(OBJ) $(CC) $(INCLUDE) -o $@ $(OBJ) $(LDFLAGS) # 清理规则 .PHONY: clean clean: rm -f *.o ../../../../processor/src/main/cpp/*.o vcd_converter
修复后注意事项
- 执行正式make前,可以先运行
make -n vcd_converter预览所有实际要执行的编译、链接命令,检查每一条g++命令里是否正确携带了头文件搜索参数,避免再出现空参数的情况。 - 散落在跨目录的.o文件可以统一归集到独立的build目录下,避免源码目录被生成的目标文件污染,后续清理也更方便。
- 不要把链接库参数放到编译参数里,编译阶段只需要传递对应标准、警告等级、头文件路径等配置即可。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

