makefile中需显式定义c++编译规则,如%.o: %.cpp并用g++ -c $
Makefile 里怎么写 C++ 编译规则
直接写
g++命令就行,但得把源文件、目标文件、依赖关系和编译选项串对。别指望 Make 自动识别.cpp文件该用什么命令——它默认只认.c和cc,C++ 必须显式定义规则。常见错误现象:
make: *** No rule to make target 'main.o', needed by 'app'. Stop.,本质是没告诉 Make 如何把main.cpp变成main.o。
- 必须加一条模式规则:
%.o: %.cpp,后面跟g++ -c $$ 是第一个依赖(即 <code>.cpp文件),$@是目标(即.o文件),别手滑写成$*或漏掉-c- 如果用了 C++17 特性,记得在编译选项里加
-std=c++17,否则默认可能是 C++98,报错像Error: 'optional' is not a member of 'std'头文件修改后不重新编译?检查依赖生成方式
手动写
main.o: main.cpp utils.h看似稳妥,但工程一多就崩——你根本记不住谁 include 了谁。Makefile 本身不解析#include,得靠编译器帮我们生成依赖项。使用场景:改了
vector<String></string>相关逻辑,结果make说“全是最新”,运行却崩,大概率是头文件变更没触发重编译。立即学习“C++免费学习笔记(深入)”;
- 在编译
.o时加-MMD -MP:前者生成.d依赖文件,后者让 Make 能安全处理头文件被删的情况- 在 Makefile 开头加
-include *.d,让 Make 读取这些自动生成的依赖- 别用
-MM(它忽略系统头文件)或漏掉-MP,否则删掉某个头文件后可能报No rule to make target 'xxx.h'如何避免反复链接整个工程
链接阶段最慢,所以得确保只在必要时才执行
g++ -o app main.o util.o。核心是让可执行文件明确依赖所有.o,且每个.o又依赖自己的源和头文件。性能影响:如果写成
app: *.cpp,每次make都会重新编译全部源文件,哪怕只改了一行注释。
- 目标写成
app: main.o util.o,不是app: *.o—— 后者在空目录下会让 Make 报*** No rule to make target '*.o'- 如果用
$(wildcard *.o),确保先有.o文件再运行 make,否则变量展开为空,链接命令直接失效- 加
-Wall -Wextra到链接命令里没意义,那是编译阶段的选项;链接时加-Static-libstdc++才能避免运行时缺 libstdc++.so跨平台或换编译器时容易栽在哪
linux 下用
g++写的 Makefile,在 macos 上跑clang++可能卡在-fPIC或std=c++17写法差异上;windows 的 MinGW 甚至不认rm -f。兼容性影响:一个
CXX = g++看似简单,但没设CXXFLAGS和LDFLAGS分离,后期切 clang 就得全局搜替换。
- 开头定义
CXX ?= g++,问号表示“只在没设置时才赋值”,方便外部传参:make CXX=clang++- 删除命令统一用
$(RM),并在开头写RM = rm -f;Windows 用户可改RM = del /f(但更建议用 WSL)- 别硬编码路径如
/usr/local/include/boost,用-I$(BOOST_INC),通过make BOOST_INC=/opt/boost/include注入最容易被忽略的是:Make 对 Tab 键极其敏感,任何命令行前混入空格都会报
Makefile:5: *** missing separator,而且这个错误不会告诉你哪一行——得逐行检查缩进。
