跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C/C++ 项目开发流程与构建指南

C/C++ 项目的完整构建流程,涵盖预处理、编译、汇编、链接及加载步骤。详细对比了静态库与动态库的构建命令、优缺点及适用场景,并提供了基于 CMake 的跨平台项目构建实战指南。内容包括 Windows 下 Visual Studio 与 Linux 下 Makefile 的配置差异,涉及 CMakeLists.txt 的编写规范、库的输出目录设置、RPATH 配置以及多模块项目的组织方式。

Ne0发布于 2026/3/25更新于 2026/7/2545 浏览
C/C++ 项目开发流程与构建指南

C/C++ 项目构建过程

  • 预处理:预处理器将 C/C++源码(cpp, hpp, c, h, inl 等)中的头文件嵌入进去(查找包含文件),展开由 define 定义的宏,移除注释并解析条件编译指令,最终生成一个不包含预处理代码的 .i 文件:g++ -E main.cpp -o main.i。
  • 汇编:词法、语法、语义的分析,优化并编译为汇编代码:g++ -S main.i -o main.s或 g++ -S main.cpp -o main.s。
  • 编译:将汇编代码翻译成机器指令,打包成目标文件。使用 -c 进行汇编得到 .o 文件,不是一个文本文件,并不能直接查看其内容。但是可以通过反汇编指令 objdump -d main.o 将机器码翻译回汇编代码进行查看。
  • 链接:将所需的静态库打包并嵌入到可执行文件中,Linux 下是 ELF,Windows 下是 EXE。注意对于静态库,链接器是单项扫描。假设 main 依赖静态库 la,静态库 la 又依赖静态库 lb,那么链接的顺序是 g++ main.o la lb,当然了,现代链接器可能对这一点进行了优化,也就是不需要强调链接的顺序也能正确链接。在 Linux 系统中,静态库通常以 .a 作为后缀,并以 lib 开头,例如 libxxx.a。如果有动态库的话,链接器会标记引用,记录下动态库的位置。
  • 加载:运行可执行文件时,操作系统的加载器会解析可执行文件中的引用标记,在标准搜索路径中查找系统中的动态库(Linux 下的 .so、Windows 下的 .lib、MacOS 下的 .dylib,在编译时被编译为位置无关代码Position Independent Code)并将其加载到内存中的任意可用位置,实现多进程共享。

动态库与静态库

以 Linux 系统为例

(1)静态库构建过程

假设现在有三个文件 main.cpp, add.cpp, minus.cpp,我需要将后面两个编译成静态库,下面是命令行实现源文件的构建与加载运行过程:

g++ -c add.cpp minus.cpp main.cpp ar rcs libmath.a add.o minus.o g++ main.o libmath.a -o exec /exec 

上面的命令过程是:先编译所有的 cpp 文件,每个 cpp 文件生成对应的目标文件 .o,然后使用 ar 命令将 add 和 minus 打包成数学静态库 libmath.a,接着将 main 和 libmath 链接为可执行文件 exec,最后直接运行可执行文件。

(2)动态库的构建

和上面一样的例子

g++ -c -fPIC add.cpp minus.cpp g++ -shared -o libmath.so add.o minus.o g++ -c main.cpp g++ main.o -L. -lmath -o exec

生成目标文件,PIC 告诉编译器:生成的代码不要依赖于被加载到内存中的绝对地址。接下来由目标文件创建动态库。第 4 行命令告诉链接器记录引用,-L. 告诉编译器在当前目录中搜索动态库,-lmath 是告诉编译器链接标准命名为 math 的动态库,标准命名 lib<标准>.so,math 前面的 l 表示跨平台的快捷方式。可以使用命令 ldd exec(list dynamic dependencies)来查看 exec 所需的动态库。

选择建议

  • 当静态库更新时,整个项目需要重新编译并链接,对于一个大型的应用程序来说,该过程会非常漫长。而动态库是独立的,还能够多进程共享,还能以插件的方式动态扩展功能(在 Qt 开发中尤为常见)。
  • 在不同平台,动态库有不同的后缀,而且命名规范更加严格。
  • 动态库的链接失效、链接地狱(引用层级过深)都是缺点。
  • 如果项目不是特别庞大的话,Windows 系统下还是推荐使用静态库,能避免很多麻烦。

    如何使用 CMake 构建项目

    手动使用命令行构建项目过于繁琐。CMake 是一个 Build Generator,只需要我们在每个目录下编写 CMakeLists.txt 即可。作为一个自动化构建工具,它会根据平台的不同生成对应的构建文件,比如 Linux 系统下的 Makefile。本节的重点在构建项目的流程,而不是 CMake 的语法。

    现在我有一个较为复杂的项目,项目结构如下:

    <...>/ ├── Demo/ │ ├── CMakeLists.txt (【1】顶层 CMakeLists) │ ├── main/ │ │ ├── main.cpp │ │ └── CMakeLists.txt (【2】main 的 CMakeLists) │ ├── math/ │ │ ├── add.cpp │ │ ├── add.h │ │ └── CMakeLists.txt (【3】math 的 CMakeLists) │ ├── logger/ │ │ ├── logger.cpp │ │ ├── logger.h │ │ └── CMakeLists.txt (【4】logger 的 CMakeLists) │ └── dependencies/ │ └── (比如:some_header.h) │ └── build/ (生成 VS 解决方案的地方) 
    

    math 编译为动态库,logger 编译为静态库,提供给主程序使用。Demo 文件夹下还有一个依赖文件夹 dependencies,不作为项目,仅作为主程序包含头文件。

    Windows 平台上的 Visual Studio C/C++ 项目

    首先确保电脑上安装了 CMake,并且配置了系统环境变量:使用 cmake --version 命令来检验。以 Visual Studio 2019 为例,使用 CMake 构建 vs 的解决方案。

    接下来编写每层的 CMakeLists.txt:

    1️⃣顶层 Demo/CMakeLists.txt
    # CMake 最低版本要求,VS2019 建议 3.15 或更高
    cmake_minimum_required(VERSION 3.15)
    # 顶层项目名称
    project(Demo CXX)
    # CXX 表示 C++ 项目
    # 设置输出目录
    # 这可以确保 .exe 和 .dll 文件在同一个目录下,方便运行
    # ${CMAKE_BINARY_DIR} 指向 'build' 目录
    # 1. 可执行文件 (.exe)
    # 输出到:build/bin/Debug/main_app.exe
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
    # 2. 动态库 (.dll) 和 动态库的导入库 (.lib)
    # 输出到:build/bin/Debug/math.dll 和 math.lib
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
    # 3. 静态库 (.lib)
    # 输出到:build/lib/Debug/logger.lib
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
    # 包含子项目
    # 最佳实践是先添加库,再添加依赖它们的可执行文件
    add_subdirectory(logger)
    add_subdirectory(math)
    add_subdirectory(main)
    
    2️⃣Demo/logger/CMakeLists.txt (静态库)
    # 1. 定义静态库 (STATIC) 目标 "logger"
    add_library(logger STATIC logger.cpp logger.h )
    # 2. "发布" 头文件目录
    # 任何链接到 "logger" 的项目,都将自动获得这个 include 路径
    target_include_directories(logger PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
    # CMAKE_CURRENT_SOURCE_DIR 指向 Demo/logger
    )
    
    3️⃣Demo/math/CMakeLists.txt (动态库)
    # 1. 定义动态库 (SHARED) 目标 "math"
    add_library(math SHARED add.cpp add.h )
    # 2. "发布" 头文件目录
    # 任何链接到 "math" 的项目,都将自动获得这个 include 路径
    target_include_directories(math PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
    # CMAKE_CURRENT_SOURCE_DIR 指向 Demo/math
    )
    # 3. (Windows 平台) 自动导出 DLL 符号
    # 这是一个简便方法,可以避免在 .h/.cpp 中手动添加 __declspec(dllexport)
    # CMake 会尝试导出所有全局符号
    set_target_properties(math PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE )
    
    4️⃣Demo/main/CMakeLists.txt (主程序)
    # 1. 定义可执行文件目标
    # 避免使用 "main" 与目录名混淆
    add_executable(main_app main.cpp)
    # 2. 添加 "dependencies" 文件夹到 include 路径
    # ${CMAKE_SOURCE_DIR} 指向顶层 "Demo" 目录
    target_include_directories(main_app PRIVATE ${CMAKE_SOURCE_DIR}/dependencies )
    # 3. 链接 "logger" 和 "math" 库
    # CMake 会自动处理:
    # - 找到 logger.lib (静态库)
    # - 找到 math.lib (动态库的导入库)
    # - 将 Demo/logger 和 Demo/math 目录添加到 main_app 的 include 路径
    # (因为它们在各自的 CMakeLists 中设置了 PUBLIC)
    target_link_libraries(main_app PRIVATE logger math )
    

    进入 build 目录,打开命令行执行命令

    cmake -G "Visual Studio 16 2019"../Demo
    

    其中,-G "Visual Studio 16 2019" 指定使用 VS2019 64 位(默认)生成器。../Demo 表示 build 上一级目录的 Demo 文件夹下的项目。如果顺利的话,可以看到命令行的构建结果。

    若失败,可尝试打开命令行终端 "x64 Native Tools Command Prompt for VS 2019",或者配置系统环境变量,将 \\Microsoft_Visual_Studio\\2019\\Professional\\VC\\Tools\\MSVC\\14.29.30133\\bin\\Hostx64\\x64 配置进去,以确保 CMake 能找到 VS。

    构建完成后进入 build 文件夹,打开 Demo.sln 解决方案即可用 VS 来 Debug 项目。或者在 build 的命令行下使用命令 cmake --build . 默认构建 Debug 版本,如果需要 release 版本则在命令后面添加 --config Release:

    这个和打开 VS2019 并右键项目选择'生成解决方案'是一样的效果。

    打开各项目的属性设置,可以发现 CMake 帮我们自动配置好了,不必再手动添加。

    根据在顶层 CMakeLists.txt 中设置的路径,可以得到最终生成的产物位置:

    • 可执行文件和 DLL:
      • build/bin/Debug/main_app.exe
      • build/bin/Debug/math.dll (因为它们在同一个目录,main_app.exe 运行时可以立即找到 math.dll)
    • 静态库:
      • build/lib/Debug/logger.lib (在链接 main_app.exe 时,链接器会自动从这里找到它)

    Linux 平台下的 C/C++ 项目构建

    针对上述项目,在 Linux 平台下差不多。只需要修改动态库的 CMakeLists 设置 Demo/math/CMakeLists.txt:

    add_library(math SHARED add.cpp add.h )
    target_include_directories(math PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
    # (跨平台) 仅在 Windows 上设置导出属性
    if(WIN32)
        set_target_properties(math PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE )
    endif()
    

    如果是跨平台的项目,则从 10 行开始可以像上面那样写,如果仅仅在 Linux 上构建,则可以删除。同时,在 Linux 上,库文件(.so 动态库和 .a 静态库)的标准约定是都放在 lib 目录下,而不是像 Windows 那样把 .dll 和 .exe 放在一起。因此顶层的 CMakeLists.txt 可以修改如下(可修改可不修改):

    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
    # Linux RPATH 设置
    # RPATH (Runtime Path) 告诉可执行文件在哪里寻找 .so 动态库。
    # $ORIGIN 是一个特殊变量,指向可执行文件所在的目录。
    # # 这条设置会"烧录"一个相对路径到 main_app 中,告诉它:
    # "去你 (main_app) 所在的目录的上一级(..),然后去 lib 目录找 .so"
    # (即:build/bin/../lib -> build/lib)
    # # 这样设置后,你可以直接在 build/bin 目录下运行 ./main_app,
    # 而无需设置 LD_LIBRARY_PATH 环境变量。
    if(UNIX AND NOT APPLE) # $ORIGIN 在链接时会被解析
        set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
        set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
    endif()
    

    在 Linux 上默认使用 Makefiles(或 Ninja)。在 build 目录下构建 Release 或 Debug(用于 GDB 调试)版本需要明确指定:

    cmake -DCMAKE_BUILD_TYPE=Release ../Demo
    cmake -DCMAKE_BUILD_TYPE=Debug ../Demo
    

    当然不指明也行:

    cmake ../Demo
    

    CMake 会在 build 目录中生成一个 Makefile,接下来要生成可执行文件,可以通过以下两种操作:

    • 方案 1:使用命令:
    make -j8
    

    其中 -j8 表示 8 核心编译,加快编译速度,可要可不要。

    • 方案 2:当然也可以直接使用 cmake:
    cmake --build . -- -j8 # 末尾的 -- -j8 是把参数传给底层的 make,这一坨也是可选的
    

    这样可以生成一个可执行文件,使用命令 ./bin/main_app 即可运行。如果 CMakeLists.txt 里面没有指明链接生成的文件,即 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin),那么可执行文件默认生成在 build 下。

    目录

    1. C/C++ 项目构建过程
    2. 动态库与静态库
    3. (1)静态库构建过程
    4. (2)动态库的构建
    5. 选择建议
    6. 如何使用 CMake 构建项目
    7. Windows 平台上的 Visual Studio C/C++ 项目
    8. 1️⃣顶层 Demo/CMakeLists.txt
    9. CMake 最低版本要求,VS2019 建议 3.15 或更高
    10. 顶层项目名称
    11. CXX 表示 C++ 项目
    12. 设置输出目录
    13. 这可以确保 .exe 和 .dll 文件在同一个目录下,方便运行
    14. ${CMAKEBINARYDIR} 指向 'build' 目录
    15. 1. 可执行文件 (.exe)
    16. 输出到:build/bin/Debug/main_app.exe
    17. 2. 动态库 (.dll) 和 动态库的导入库 (.lib)
    18. 输出到:build/bin/Debug/math.dll 和 math.lib
    19. 3. 静态库 (.lib)
    20. 输出到:build/lib/Debug/logger.lib
    21. 包含子项目
    22. 最佳实践是先添加库,再添加依赖它们的可执行文件
    23. 2️⃣Demo/logger/CMakeLists.txt (静态库)
    24. 1. 定义静态库 (STATIC) 目标 "logger"
    25. 2. "发布" 头文件目录
    26. 任何链接到 "logger" 的项目,都将自动获得这个 include 路径
    27. CMAKECURRENTSOURCE_DIR 指向 Demo/logger
    28. 3️⃣Demo/math/CMakeLists.txt (动态库)
    29. 1. 定义动态库 (SHARED) 目标 "math"
    30. 2. "发布" 头文件目录
    31. 任何链接到 "math" 的项目,都将自动获得这个 include 路径
    32. CMAKECURRENTSOURCE_DIR 指向 Demo/math
    33. 3. (Windows 平台) 自动导出 DLL 符号
    34. 这是一个简便方法,可以避免在 .h/.cpp 中手动添加 __declspec(dllexport)
    35. CMake 会尝试导出所有全局符号
    36. 4️⃣Demo/main/CMakeLists.txt (主程序)
    37. 1. 定义可执行文件目标
    38. 避免使用 "main" 与目录名混淆
    39. 2. 添加 "dependencies" 文件夹到 include 路径
    40. ${CMAKESOURCEDIR} 指向顶层 "Demo" 目录
    41. 3. 链接 "logger" 和 "math" 库
    42. CMake 会自动处理:
    43. - 找到 logger.lib (静态库)
    44. - 找到 math.lib (动态库的导入库)
    45. - 将 Demo/logger 和 Demo/math 目录添加到 main_app 的 include 路径
    46. (因为它们在各自的 CMakeLists 中设置了 PUBLIC)
    47. Linux 平台下的 C/C++ 项目构建
    48. (跨平台) 仅在 Windows 上设置导出属性
    49. Linux RPATH 设置
    50. RPATH (Runtime Path) 告诉可执行文件在哪里寻找 .so 动态库。
    51. $ORIGIN 是一个特殊变量,指向可执行文件所在的目录。
    52. # 这条设置会"烧录"一个相对路径到 main_app 中,告诉它:
    53. "去你 (main_app) 所在的目录的上一级(..),然后去 lib 目录找 .so"
    54. (即:build/bin/../lib -> build/lib)
    55. # 这样设置后,你可以直接在 build/bin 目录下运行 ./main_app,
    56. 而无需设置 LDLIBRARYPATH 环境变量。
    • 免费图片AI生成工具免费生成了解详情
    • Magick API 一键接入全球大模型注册送1000万token查看
    • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
    • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
    • 100+免费在线小游戏爽一把
    极客日志微信公众号二维码

    微信扫一扫,关注极客日志

    微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

    更多推荐文章

    查看全部
    • Vue Skills:让 AI 掌握 Vue 最佳实践
    • Wan2.2 视频生成风格单一?LoRA 微调实战提升多样性
    • 5 款论文 AIGC 检测降重工具实测与避坑指南
    • 飞书机器人图片消息发送实战及常见报错解决方案
    • VSCode 本地运行 DeepSeek 模型指南
    • VR-Reversal:基于 MPV 的 3D 转 2D 视频工具使用指南
    • Spring AI ImageModel 集成 OpenAI DALL-E 图像生成指南
    • 基于 Isaac Lab 训练自定义机器人行走
    • JavaWeb 基础:动静态 Web、URL 与 HTTP 协议
    • Webots 2025a + ROS 2 Jazzy e-puck 机器人仿真与导航教程
    • Qt QRegularExpression 类主要用法
    • 百度 AI 产品经理三轮面试复盘与准备指南
    • 从人类视频到机器人跳舞:BeyondMimic 全流程解析与 rl_sar 部署实践
    • Coze 智能体开发指南:插件、知识库与数据库详解
    • C/C++ 局部、静态局部及全局变量区别与使用场景
    • Odoo 12 入门实战:深入理解 Onchange 机制
    • 1D-CNN 算法原理与 PyTorch 多步预测实现
    • 前端地图基本操作控制:平移、缩放、旋转与样式切换
    • LLaMA-Factory 大模型 LoRA 微调实战指南
    • 基于 CasADi 的无人机非线性模型预测控制与 Matlab 实现

    相关免费在线工具

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

    • Markdown转HTML

      将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

    • HTML转Markdown

      将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

    • JSON 压缩

      通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

    • JSON美化和格式化

      将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online