C++ 编译相关
概念
-
GNU 是一个自由操作系统项目,其中包括了与操作系统相关的工具和应用程序,包括 GCC。
-
Linux 是一个类 Unix 的操作系统内核,与 GNU 工具一起用于创建完整的 Linux 操作系统。
-
GCC 是 GNU 组织开发的一套编译器集合(如:C、C++、Objective-C、Java 等),其中包括 g++(C++ 编译器)。
一、构建过程工具介绍
各类工具之间的关系图
1、项目构建生成工具
首先cmake是项目构建生成工具, cmake 的代码可以与平台系统和编译器无关。类似 cmake 的工具还有autotools 、qmake、GN,其中 qmake 已基本由 cmake 替代。也就是说 cmake 是用来根据 CMakeLists.txt
文件内容自动生成不同种类项目构建系统
所需要使用的 构建过程描述文件 如 make (Makefile)、Ninja(build.ninja)、msvc (.vcxproj) 等 ,这些配置文件通常是 Makefile 或 IDE 需要的项目文件。
2.项目构建工具
Makefile 可以理解为是 make 工具使用的构建过程描述文件
,make 读取 Makefile 中的配置信息来实现编译、链接和部署。
类似 make 作用的工具还有 Ninja 、nmake 、devenv(vs),mingw32-make.exe
是 windows 版本的 make 工具
3.项目编译链接工具
- 预处理器 (Preprocessor):
- 工具:
cpp
(C/C++ 预处理器) - 步骤:展开宏、处理条件编译指令 (
#ifdef
,#ifndef
,#include
等)。
- 工具:
- 编译器前端 (Compiler Frontend):
- 工具:
clang
,g++
(GCC 的 C++ 编译器)、MSVC
(Microsoft Visual C++ 编译器)等。 - 步骤:将源代码翻译成中间表示(例如 LLVM IR)。
- 工具:
- 编译器后端 (Compiler Backend):
- 工具:
llc
(LLVM 编译器)、as
(汇编器)。 - 步骤:将中间表示编译成汇编代码。
- 工具:
- 汇编器 (Assembler):
- 工具:
as
(GNU 汇编器)、masm
(Microsoft 汇编器)等。 - 步骤:将汇编代码翻译成二进制目标文件。
- 工具:
- 链接器 (Linker):
- 工具:
ld
(GNU 链接器)、link
(Microsoft 链接器)等。 - 步骤:将多个目标文件和库文件链接成可执行文件或共享库。
- 工具:
- 库工具 (Library Tool):
- 工具:
ar
(GNU 归档工具)、lib
(Microsoft 静态库工具)等。 - 步骤:创建和管理静态库文件(
.a
,.lib
等)。
- 工具:
- 动态链接器 (Dynamic Linker):
- 工具:系统特定,如 Linux 上的
ld.so
。 - 步骤:在运行时加载共享库,并解析符号引用。
- 工具:系统特定,如 Linux 上的
- 其他工具:
objdump
(目标文件分析工具):用于查看目标文件的内容和信息。nm
(符号表工具):用于查看目标文件或可执行文件中的符号表信息。strip
(符号剥离工具):用于删除目标文件或可执行文件中的符号信息,减小文件大小。
二、工具链构成
- 编译器(Compiler)
- 汇编器(Assembler)
- 链接器(Linker)
- 标准库(Standard Library)
- 头文件和库文件(Header Files and Library Files)
- 构建工具(Build Tools)
- 调试器(Debugger)
- 性能分析工具(Performance Profiling Tools)
- 交叉编译工具链(Cross-Compilation Toolchain)
三、为什么不直接使用项目编译链接工具
为什么要有上面说的三类工具,首先说下“项目编译链接工具” 只是使用这些工具其实就能够编译出所有的目标,但由于命令过于复杂,编译的流程不好控制。比如编译一个执行程序 g++ a.cpp -o a -I../include -L../../lib -lpthread
这种方式在涉及到多个多项目、多库、多参数和各种依赖关系是维护难度很大。还有涉及到换编译器时,比如从 g++ 换成 clang 或者 cl.exe,也需要改动很多内容。
那如果换成 make:
INCLUDE=-I../include
LIBS=-lpthread
a:a.o
${CC} -o $@ $< ${INCLUDE} ${LIBS}
依赖关系和所有目标都可以很清晰的管理。
四、为什么不直接使用make或者Ninja
其实很多公司和项目就是直接使用 make ,但 make 代码规则严格,语法过于复杂,在做跨平台和跨编译器时的管理更加复杂,移植到不同环境的成本过大。这是就要引入 cmake 来生成 make 或者 NInja 使用的文件。Android 的 NDK 开发和鸿蒙 native SDK 都使用了 cmake 生成 Ninja 项目文件。
cmake 本身配置就与环境和编译器完全无关了,可以由生成时指定
cmake 直接编译一个程序的配置也就一个函数add_executable的调用
cmake_minimum_required(VERSION 3.20)
project(项目名称)
add_executable(项目名称 a.cpp)
五、make、Ninja 和 Visual Studio 区别
make
、Ninja
和 Visual Studio
是不同的构建工具,它们用于管理和构建项目的方式有所不同。以下是它们之间的主要区别:
- make:
make
是最常见的构建工具之一,广泛用于 Unix 和类 Unix 系统。make
使用Makefile
文件来定义项目的构建规则和依赖关系。Makefile
使用 Make 编程语言,可以在其中编写自定义构建规则。make
的优点是广泛支持,几乎在所有 POSIX 兼容的系统上都可用。
- Ninja:
Ninja
是一种轻量级的构建系统,旨在提供快速和高效的构建。Ninja
的配置文件通常比Makefile
更简洁和易于理解,这使得构建速度更快。Ninja
不支持像Makefile
那样复杂的条件构建规则,但对于许多项目来说,速度和简单性是更重要的。
- Visual Studio:
Visual Studio
是 Microsoft 开发的集成开发环境 (IDE),内置了强大的构建和调试工具。- 在 Windows 平台上,
Visual Studio
提供了完整的开发环境,包括代码编辑、调试、版本控制和构建。 - 使用
Visual Studio
构建 C/C++ 项目通常需要创建项目文件(如.vcproj
或.sln
文件),并在 IDE 中配置构建选项。
选择使用哪个工具取决于项目的需求和开发环境:
- 如果你在 Unix 或类 Unix 系统上工作,
make
是一个常见的选择,尤其对于开源项目。 - 如果你追求构建速度和简洁性,可以考虑使用
Ninja
。 - 如果你在 Windows 上工作,
Visual Studio
提供了一体化的解决方案,包括 IDE 和构建工具。
对于跨平台项目,可以使用 CMake
来生成适用于不同构建工具的配置文件,这样可以保持项目的可移植性。
六、cmake
1、前言
CMake是一个跨平台的项目构建生成工具
。它能生成各种项目构建工具
所需要的 构建过程描述文件(例如 Makefile,build.ninja,.vcxproj 等文件),能测试编译器所支持的C++特性,类似UNIX下的automake。Cmake 并不直接建构出最终的软件,而是产生标准的建构档,然后再依一般的建构方式使用。 —— 百度百科
2、安装步骤
2、解压压缩包到指定目录(路径不要有中文)
3、将bin目录添加至用户环境变量
4、验证安装成功,打开cmd,cmake --version
3、cmake指定编译器
注意:在 windows 下一般使用 cmake-gui.exe 工具指定编译器会更加方便
在 cmd 中输入cmake -G
可以看到当前版本支持的各种编译器
cmake指定主要的编译器示例
# -S 指定源码文件路径,-B指定编译输出文件夹名称,-G 指定编译工具
# 1、指定使用 `MinGW Makefiles` 编译器
cmake -S . -B build -G "MinGW Makefiles"
# 2、Visual Studio 编译器支持(生成项目文件和解决方案)
cmake -S . -B build -G "Visual Studio 17 2022"
cmake -S . -B build -G "Visual Studio 16 2019"
cmake -S . -B build -G "Visual Studio 15 2017"
cmake -S . -B build -G "Visual Studio 10 2010"
# 3、windows下nmake支持(vs控制台编译)
cmake -S . -B build -G "NMake Makefiles"
# 4、Ninja (安卓和鸿蒙方案)
cmake -S . -B build -G "Ninja"
七、CMakeLists文件介绍
编辑该文件时一定要注意,这个文件的指令是自上到下执行的,指令顺序不同会导致各种各样的问题出现
cmake官网命令大全:https://cmake.org/cmake/help/latest/
CMakeLists.txt语法规则小结:https://blog.csdn.net/weixin_46135347/article/details/122172470
命令介绍
cmake_minimum_required # 用于指定能够正确执行CMakeLists.txt文件中指令的cmake最小版本
project # 指定项目名称,会引入一些变量
set(CMAKE_CXX_STANDARD 14) # 设置C++语法标准
set(CMAKE_VERBOSE_MAKEFILE ON) # 开启生成Makefile时的详细日志输出
add_subdirectory # cmake子目录继续编译,这个目录中必须含有CMakeLists.txt文件
aux_source_directory # 搜索指定目录中的cpp文件,将搜索到的所有文件相对路径存储在变量中
file # 将匹配指定正则的所有文件信息保存到一个变量中
include_directories # 添加头文件搜索目录
link_directories # 添加库文件搜索目录
find_library
find_package # 设置依赖库
link_libraries # 用在add_executable之前,主要用来链接静态库
add_compile_options # 添加一个g++编译选项
add_definitions # 添加一个g++编译宏定义选项
add_dependencies # 用于描述两个target之间的依赖关系
add_library # 添加一个生成库文件的 target
add_executable # 添加一个生成可执行文件的 target
target_link_libraries # 用在add_executable之后,主要用来链接导入库或者动态库
set # 设置一个变量的值
list # 对一个列表变量进行一些操作
message # 生成构建文件时输出一些信息
install # 复制当前工程中的一些文件到指定的目录下
include # 执行某个文件中的cmake指令
CMakeLists.txt中的条件控制语句
# 逻辑判断和比较
if (expression) # expression 不为空(0,N,NO,OFF,FALSE,NOTFOUND)时为真
if (not exp) # 与上面相反
if (var1 AND var2)
if (var1 OR var2)
if (COMMAND cmd) # 如果 cmd 确实是命令并可调用时为真
if (EXISTS dir) if (EXISTS file) # 如果目录或文件存在为真
# 当 file1 比 file2 新,或 file1/file2 中有一个不存在时为真,文件名需使用全路径
if (file1 IS_NEWER_THAN file2)
if (IS_DIRECTORY dir) # 当 dir 是目录时为真
if (DEFINED var) # 如果变量被定义为真
# 给定的变量或者字符串能够匹配正则表达式 regex 时为真,此处 var 可以用 var 名,也可以用 ${var}
if (var MATCHES regex)
if (string MATCHES regex)
# 数字比较 #
if (variable LESS number) # LESS 小于
if (string LESS number)
if (variable GREATER number) # GREATER 大于
if (string GREATER number)
if (variable EQUAL number) # EQUAL 等于
if (string EQUAL number)
# 字母表顺序比较 #
if (variable STRLESS string)
if (string STRLESS string)
if (variable STRGREATER string)
if (string STRGREATER string)
if (variable STREQUAL string)
if (string STREQUAL string)
- 示例
if(MSVC)
set(LINK_LIBS common)
else()
set(boost_thread boost_log.a boost_system.a)
endif()
target_link_libraries(demo ${LINK_LIBS})
# 或者
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -g")
else()
add_definitions(-D_SCL_SECURE_NO_WARNINGS
D_CRT_SECURE_NO_WARNINGS
-D_WIN32_WINNT=0x601
-D_WINSOCK_DEPRECATED_NO_WARNINGS)
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "debug")
...
else()
...
endif()
CMakeLists.txt中的循环控制语句
# 方式一
while(condition)
# TODO
endwhile()
# 方式二
# start 表示起始数,stop 表示终止数,step 表示步长
foreach(loop_var RANGE start stop [step])
# TODO
endforeach(loop_var)
# 示例 #
foreach(i RANGE 1 9 2)
message(${i}) # 依次输出:13579
endforeach(i)
常见变量
# 预定义变量 #
PROJECT_SOURCE_DIR # 工程的根目录
PROJECT_BINARY_DIR # 运行 cmake 命令的目录,通常是 ${PROJECT_SOURCE_DIR}/build
PROJECT_NAME # 返回通过 project 命令定义的项目名称
CMAKE_CURRENT_SOURCE_DIR # 当前处理的 CMakeLists.txt 所在的路径
CMAKE_CURRENT_BINARY_DIR # target 编译目录
CMAKE_CURRENT_LIST_DIR # CMakeLists.txt 的完整路径
CMAKE_CURRENT_LIST_LINE # 当前所在的行
EXECUTABLE_OUTPUT_PATH # 重新指定目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH # 重新定义目标链接库文件的存放位置
CMAKE_MODULE_PATH # 定义自己的 cmake 模块所在的路径,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块
# 系统环境变量 #
$ENV{Path} # 获取系统环境变量Path的值
set(ENV{Name} value) # 临时设置一个环境变量,注意这里没有“$”符号
# 系统信息 #
CMAKE_MAJOR_VERSION # cmake 主版本号,比如 3.4.1 中的 3
CMAKE_MINOR_VERSION # cmake 次版本号,比如 3.4.1 中的 4
CMAKE_PATCH_VERSION # cmake 补丁等级,比如 3.4.1 中的 1
CMAKE_SYSTEM # 系统名称,比如 Linux-2.6.22
CMAKE_SYSTEM_NAME # 不包含版本的系统名,比如 Linux
CMAKE_SYSTEM_VERSION # 系统版本,比如 2.6.22
CMAKE_SYSTEM_PROCESSOR # 处理器名称,比如 i686
UNIX # 在所有的类 UNIX 平台下该值为 TRUE,包括 OS X 和 cygwin
WIN32 # 在所有的 win32 平台下该值为 TRUE,包括 cygwin
# 主要开关选项 #
CMAKE_C_FLAGS # 设置 C 编译选项,也可以通过指令 add_definitions() 添加
CMAKE_CXX_FLAGS # 设置 C++ 编译选项,也可以通过指令 add_definitions() 添加
BUILD_SHARED_LIBS # 这个开关用来控制默认的库编译方式,如果不进行设置,使用 add_library 又没有指定库类型的情况下,默认编译生成的库都是静态库。如果 set(BUILD_SHARED_LIBS ON) 后,默认生成的为动态库
列如:add_definitions(-DENABLE_DEBUG -DABC) # 参数之间用空格分隔
八、Makefile入门
一般该文件是用 cmake 工具生成的,但有时需要了解其中符号有何种用途,所以在这里留个传送门,将来可能要查阅
Makefile文件中的命令有一定规范,一旦该文件编写好以后在 Linux 命令行中执行一条 make 命令即可自动编译整个工程。不同厂家的make可能会稍有不同,并且语法上也有区别,不过基本思想都差不多,主要还是落在目标依赖上,最广泛使用的是 GNUmake
九、Windows环境 C++ 编译工具
什么是 MinGW-w64
MinGW 的全称是:Minimalist GNU on Windows 。它实际上是将经典的开源 C语言 编译器 GCC 移植到了 Windows 平台下,并且包含了 Win32API ,因此可以将源代码编译为可在 Windows 中运行的可执行程序。而且还可以使用一些 Windows 不具备的,Linux平台下的开发工具。一句话来概括:MinGW 就是 GCC 的 Windows 版本 。
以上是 MinGW 的介绍,MinGW-w64 与 MinGW 的区别在于 MinGW 只能编译生成32位可执行程序,而 MinGW-w64 则可以编译生成 64位 或 32位 可执行程序。
正因为如此,MinGW 现已被 MinGW-w64 所取代,且 MinGW 也早已停止了更新,内置的 GCC 停滞在了 4.8.1 版本,而 MinGW-w64 内置的 GCC 则更新到了 6.2.0 版本。
为什么使用 MinGW-w64
- MinGW-w64 是开源免费的软件
- MinGW-w64 由一个活跃的开源社区在持续维护,因此不会过时
- MinGW-w64 支持最新的 C语言 标准
- MinGW-w64 使用 Windows 的C语言运行库,因此编译出的程序不需要第三方 DLL ,可以直接在 Windows 下运行。那些著名的开源 IDE 实际只是将 MinGW-w64 封装了起来,使它拥有友好的图形化界面,简化了操作,但内部核心仍然是 MinGW-w64
- MinGW-w64 是稳定可靠的、持续更新的 C/C++ 编译器,使用它可以免去很多麻烦,不用担心跟不上时代,也不用担心编译器本身有bug,可以放心的去编写程序
安装MinGW-W64
下载:https://sourceforge.net/projects/mingw-w64/files/
版本截图:
十、交叉编译参考
msys2安装及简单使用
https://blog.csdn.net/u010251191/article/details/79118468
为什么是msys2,而不是cygwin
https://segmentfault.com/a/1190000002789600
https://blog.51cto.com/u_15067227/4549473
参考文章
cmake安装参考:https://blog.csdn.net/m0_55048235/article/details/122277696
cmake与make的区别:https://blog.csdn.net/jiedichina/article/details/126676349
CMakeLists文件指令详解:https://blog.csdn.net/afei__/article/details/81201039
Makefile入门(超详细一文读懂):https://blog.csdn.net/ZBraveHeart/article/details/123187908
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!