c++怎么编写简单的MakeFile_c++工程编译脚本【指南】

2次阅读

makefile中需显式定义c++编译规则,如%.o: %.cpp并用g++ -c $

c++怎么编写简单的MakeFile_c++工程编译脚本【指南】

Makefile 里怎么写 C++ 编译规则

直接写 g++ 命令就行,但得把源文件、目标文件、依赖关系和编译选项串对。别指望 Make 自动识别 .cpp 文件该用什么命令——它默认只认 .ccc,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++ 可能卡在 -fPICstd=c++17 写法差异上;windows 的 MinGW 甚至不认 rm -f

兼容性影响:一个 CXX = g++ 看似简单,但没设 CXXFLAGSLDFLAGS 分离,后期切 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,而且这个错误不会告诉你哪一行——得逐行检查缩进。

text=ZqhQzanResources