clang++ -c 是唯一可靠方式让 clang++ 仅编译不链接,生成可链接的 .o 文件;不加 -c 会默认执行完整编译+链接流程,导致 undefined reference to 'main' 等链接错误。

clang++ -c 是唯一可靠方式
想让 clang++ 只编译不链接,必须加 -c 参数。不加它,默认会走完编译+链接全流程,直接生成可执行文件——哪怕你只传一个 .cpp 文件。
常见错误是以为「没写 -o 就不会链接」,其实不会:clang++ main.cpp 仍会尝试链接,失败时抛出类似 undefined reference to 'main' 的错误(因为链接器找不到入口符号或标准库)。
-
clang++ -c main.cpp→ 输出main.o -
clang++ -c utils.cpp -o utils.o→ 指定输出名,避免覆盖 - 多个文件分别编译:
clang++ -c a.cpp b.cpp c.cpp→ 生成a.o、b.o、c.o
为什么不能用 -S 或 -E 替代 -c
-S 生成汇编文件(.s),-E 只做预处理(.ii),它们都停在更早阶段,无法直接用于后续链接。只有 -c 产出的目标文件(.o)含符号表、重定位信息,是链接器能识别的输入格式。
误用示例:clang++ -S main.cpp 得到 main.s,但 clang++ main.s -o main 会失败——除非你确认汇编语法和目标平台完全匹配,且没漏掉运行时启动代码(如 _start)。
立即学习“C++免费学习笔记(深入)”;
-
-c输出的是机器码级目标文件,含调试信息(如有-g)、符号引用,可安全链接 -
-S输出的是人类可读汇编,跨平台/跨工具链易出错,不推荐作为构建中间态 -
-save-temps会生成全套中间文件(.ii、.s、.o),但体积大、冗余,仅调试用
链接时必须用 clang++ 而不是 clang
即使你用 clang++ -c 编译出 .o 文件,后续链接也得用 clang++,而不是 clang。否则大概率报错:undefined reference to 'std::cout' 或其他 C++ 运行时符号。
原因:C++ 标准库(libstdc++ 或 libc++)不会被 clang 自动链接,而 clang++ 会隐式加 -lstdc++(或对应 libc++)和启动文件(crt0.o 等)。
- ✅ 正确:
clang++ main.o utils.o -o myapp - ❌ 错误:
clang main.o utils.o -o myapp→ 缺 C++ 运行时,链接失败 - ⚠️ 例外:若项目纯 C 风格且未用任何 STL,
clang可能侥幸成功,但不可依赖
多文件项目中 -c 的实际价值
分步用 -c 编译的核心价值不在“单次操作”,而在增量构建:改了 network.cpp,只需重新跑 clang++ -c network.cpp,再链接全部 .o,跳过其他未变文件的编译。
容易忽略的点是头文件依赖——如果 utils.h 被修改,所有包含它的 .cpp 都应重新 -c。Makefile 或 CMake 会自动跟踪这类依赖,手动操作时得自己记清楚。
- 对象文件名默认和源文件同名(
foo.cpp→foo.o),避免手误写成foo.o: foo.cpp却漏掉foo.h - 调试时加
-g:clang++ -c -g main.cpp,否则.o里没调试信息,GDB 无法单步 - 发布构建常用
-O2 -DNDEBUG,但开发中建议先不用优化,避免优化干扰调试逻辑
clang/clang++ 或漏掉 C++ 运行时;-c 本身很简单,但前后环节的工具选择和参数一致性才是真坑。


















