目录
一、cmake
前言
CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)
。它能生成各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CMakeLists.txt
。Cmake 并不直接建构出最终的软件,而是产生标准的建构档,然后再依一般的建构方式使用。 —— 百度百科
安装步骤
2、解压压缩包到指定目录(路径不要有中文)
3、将bin目录添加至用户环境变量
4、验证安装成功,打开cmd,cmake --version
二、cmake与make
两者区别
要说明区别先要区分下面三类工具:
- 1.项目构建生成工具
首先cmake是项目构建生成工具,cmake的代码可以与平台系统和编译器无关。类似cmake的工具还有autotools、qmake、GN,其中qmake已基本由cmake替代。也就是说cmake是用来根据CMakeLists文件内容生成makefile和其他项目生成工具配置的。
- 2.项目构建工具
makefile 可以理解为是make工具使用的代码,make读取makefile中的配置信息来实现编译、链接和部署。
类似make的工具有 Ninja 、nmake 、devenv(vs)。
- 3.项目编译链接工具
比如有:gcc、 cl.exe 、link 、ar
各类工具之间的关系图
梳理一下 cmake
、make
、 gcc
以及的关系:
-
cmake :根据指定的 CMakeLists.txt 文件,跨平台来生成对应平台的 makefile 文件;
-
make :可以看作一个智能的批处理工具,本身没有编译和链接功能,而是通过调用 makefile 文件中用户指定的命令来进行编译和链接的;
-
gcc:即 GNU Compiler Collection(GNU 编译器套件),也可以理解为编译器,可用于编译很多种编程语言(如:C、C++、Objective-C、Java 等);
总结一下:gcc 是用于编译和链接和工具,编译少量文件可以直接使用 gcc 命令完成,但当源文件很多,用 gcc 命令去逐个编译则是很混乱且工作量巨大。因此,需要借助 make 来来管理整个编译过程,make 安装 makefile 中的命令进行编译和链接,而 makefile 命令中就包含了调用 gcc 去编译某个源文件的命令。而当工程规模非常大时,且需要跨平台时,手写 makefile 也开始变得麻烦,这是可以借助 cmake 来生成 makefile 。
为什么不直接使用项目编译链接工具(gcc/g++ ...)
为什么要有上面说的三类工具,首先说下“项目编译链接工具” 只是使用这些工具其实就能够编译出所有的目标,但由于命令过于复杂,编译的流程不好控制。比如我们编译一个执行程序 g++ first_main.cpp -o first_main -I ../include -L../../lib -lpthread
这种方式在涉及到多个多项目、多库、多参数和各种依赖关系是维护难度很大。还有涉及到换编译器时,比如从g++换成clang或者cl.exe,也需要改动很多内容。
那如果换成make:
INCLUDE=-I../include
LIBS=-lpthread
first_main:first_main.o
${CC} -o $@ $< ${INCLUDE} $
依赖关系和所有目标都可以很清晰的管理。
为什么不直接使用make或者Ninja
其实很多公司和项目就是直接使用make的,但make代码规则严格,语法过于复杂,在做跨平台和跨编译器时的管理更加复杂,移植到不同环境的成本过大。这是就要引入cmake来生成make或者NInja使用的文件。Android 的NDK开发和鸿蒙native SDK都使用了cmake生成Ninja项目文件。
cmake本身配置就与环境和编译器完全无关了,可以由生成时指定。
cmake直接编译一个程序的配置也就一个函数add_executable的调用:
cmake_minimum_required(VERSION 3.20)
project(xlog)
add_executable(first_main first_main.cpp)
cmake指定编译器(cmake -G)
在cmd中输入cmake -G
可以看到当前版本支持的各种编译器
cmake指定主要的编译器示例
- 1.指定是用
MinGW Makefiles
编译器
cmake -S . -B build -G "MinGW Makefiles"
-S 指定源码文件路径,-B指定编译输出文件夹名称,-G 指定编译工具
- 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文件介绍
命令介绍
1.指定cmake最小版本:cmake_minimum_required(VERSION 3.0)
这行命令是可选的,我们可以不写这句话,但在有些情况下,如果 CMakeLists.txt 文件中使用了一些高版本 cmake
特有的一些命令的时候,就需要加上这样一行,提醒用户升级到该版本之后再执行 cmake。
2.设置项目名称:project(demo)
这个命令不是强制性的但最好都加上。它会引入两个变量 demo_BINARY_DIR
和 demo_SOURCE_DIR
,同时,cmake
自动定义了两个等价的变量 PROJECT_BINARY_DIR
和 PROJECT_SOURCE_DIR
。
3.设置编译类型
add_executable(demo demo.cpp) # 生成可执行文件
add_library(common STATIC util.cpp) # 生成静态库
add_library(common SHARED util.cpp) # 生成动态库或共享库
add_library 默认生成是静态库,通过以上命令生成文件名字,
- 在 Linux 下以此是:
demo
libcommon.a
libcommon.so - 在 Windows 下以此是:
demo.exe
common.lib
common.dll
4.指定编译时包含的源文件
- 明确指定包含哪些源文件
add_library(demo demo.cpp test.cpp util.cpp)
- 搜索所有的cpp文件
aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件,并将搜索到的源文件相对路径列表存储在变量 SRC_LIST 中。
add_library(demo ${SRC_LIST})
- 自定义搜索规则
file(GLOB SRC_LIST "*.cpp" "dir_name/*.cpp") # 其中GLOB命令将所有正则匹配(可选,不写则匹配到空)的文件挑选出来,默认以字典顺序排序。
add_library(demo ${SRC_LIST})
# 或者
file(GLOB SRC_LIST "*.cpp")
file(GLOB SRC_LIST_2 "dir_name/*.cpp")
add_library(demo ${SRC_LIST} ${SRC_LIST_2})
# 或者
aux_source_directory(. SRC_LIST)
aux_source_directory(dir_name SRC_LIST_2)
add_library(demo ${SRC_LIST} ${SRC_LIST_2})
5.查找指定的库文件
find_library(VAR name path)
查找到指定的预编译库,并将它的路径存储在变量中。
默认的搜索路径为 cmake
包含的系统库,因此如果是 NDK
的公共库只需要指定库的 name
即可,如下。
find_library( log-lib log )
# Sets the name of the path variable.
# Specifies the name of the NDK library that you want CMake to locate.
类似的命令还有 find_file()
、 find_path()
、 find_program()
、 find_package()
。
6.设置包含的目录
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# Linux 下还可以通过如下方式设置包含的目录
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}")
7.设置链接库搜索目录
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs)
# Linux 下还可以通过如下方式设置包含的目录
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/libs")
8.设置需要链接的库
在cmake语法中,link_libraries
和target_link_libraries
是很重要的两个链接库的方式,虽然写法上很相似,但是功能上有很大区别:
link_libraries用在add_executable之前,target_link_libraries用在add_executable之后。
link_libraries用来链接静态库,target_link_libraries用来链接导入库,即按照header file + .lib + .dll方式隐式调用动态库的.lib库。
# log-lib 是上面 find_library 指定的变量名
# ${log-lib}无需含有文件后缀,下同
link_libraries(${log-lib})
# 目标库
# 目标库需要链接的库
target_link_libraries(demo ${log-lib} )
在 Windows 下,系统会根据链接库目录,搜索 xxx.lib
文件,Linux 下会搜索 xxx.so
或者 xxx.a
文件,如果都存在会优先链接动态库(so 后缀)。
- 指定链接动态库或静态库
target_link_libraries(demo libface.a) # 链接libface.a
target_link_libraries(demo libface.so) # 链接libface.so
- 指定全路径
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a)
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.so)
- 指定链接多个库
target_link_libraries(demo
${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a
boost_system.a
boost_thread
pthread)
9.设置变量
# set 直接设置变量的值
set(SRC_LIST main.cpp test_fun.cpp)
add_executable(demo ${SRC_LIST})
# set 追加设置变量的值
set(SRC_LIST main.cpp)
set(SRC_LIST ${SRC_LIST} test.cpp)
add_executable(demo ${SRC_LIST})
# list 追加或者删除变量的值
set(SRC_LIST main.cpp)
list(APPEND SRC_LIST test_fun.cpp) # SRC_LIST中追加 test_fun.cpp
list(REMOVE_ITEM SRC_LIST main.cpp) # SRC_LIST中删除 main.cpp
add_executable(demo ${SRC_LIST})
10.条件控制if…elseif…else…endif
# 逻辑判断和比较 #
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) # 如果目录或文件存在为真
if (file1 IS_NEWER_THAN file2) # 当 file1 比 file2 新,或 file1/file2 中有一个不存在时为真,文件名需使用全路径
if (IS_DIRECTORY dir) # 当 dir 是目录时为真
if (DEFINED var) # 如果变量被定义为真
if (var MATCHES regex) # 给定的变量或者字符串能够匹配正则表达式 regex 时为真,此处 var 可以用 var 名,也可以用 ${var}
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()
11.循环控制语句
# 方式一
while(condition)
# TODO
endwhile()
# 方式二
foreach(loop_var RANGE start stop [step]) # start 表示起始数,stop 表示终止数,step 表示步长
# TODO
endforeach(loop_var)
# 示例 #
foreach(i RANGE 1 9 2)
message(${i}) # 依次输出:13579
endforeach(i)
12.打印信息
message(${PROJECT_SOURCE_DIR})
message("build with debug mode")
message(WARNING "this is warnning message") # 输出报警信息
message(FATAL_ERROR "this build has many error") # FATAL_ERROR 会导致编译失败
13.包含其它 cmake 文件
include(./common.cmake) # 指定包含文件的全路径
include(def) # 在搜索路径中搜索def.cmake文件
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # 设置include的搜索路径
常见变量
# 预定义变量 #
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 + CMake)
安装MinGW-W64
下载:https://sourceforge.net/projects/mingw-w64/files/
版本截图:
版本选择总结
系统类型 | 系统架构(Architecture) | 线程模型(Threads) | 异常类型(Exception) |
---|---|---|---|
x86(32位系统) | i686 | win32 | dwarf |
x64(64位系统) | x86_64 | posix | seh |
1、系统架构(Architecture)
说明: 是指电脑系统是32位还是64位,根据你的电脑系统做出对应选择。
操作: 我的电脑系统是 64位的,所以我选择了x86_64,如果你是32位系统,则选择i686即可。
2、线程模型(Threads)
说明: 这个世界上只有两种操作系统,符合posix协议的和windows。如果你想要开发windows程序,需要选择 win32 ,而开发 Linux、Unix、MacOS等其他操作系统下的程序,则需要选择posix。
操作: 我只开发在windows下运行的程序,所以选择了win32 。
3、异常类型(Exception)
(64位):
说明: 异常处理在开发中非常重要,你在开发的过程中,大部分的时间会耗在处理各种异常情况上。如果你之前选择了64位,则这里有两个异常处理模型供你选择,seh是新发明的,而sjlj则是古老的。seh性能比较好,但不支持32位。sjlj稳定性好,支持32位。
操作: 我这里选择了seh。
(32位):
说明: 选择了32位后,则可以用dwarf和sjlj两种异常处理模型。同样的,dwarf的性能要优于sjlj,但是它不支持64位。
操作: 建议选择dwarf。
MinGW-W64 配置
MinGW-w64 就是 Windows 平台下集成了 gcc 、g++ 、 make 等众多构建工具集合 ,为了更好地配合这两个工具来完成工程的编译,下载完成后需要再完成一点点额外的配置:
打开 MinGW-w64 的 bin 目录,拷贝一份 mingw32-make.exe 改名为make.exe
:
参考文章
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
MinGW-W64版本安装选择方法:https://segmentfault.com/a/1190000041394399
mingw不同版本全解析:https://www.codenong.com/cs105494164/
标签:SRC,CMAKE,demo,LIST,C++,编译,相关,cmake From: https://www.cnblogs.com/hhddd-1024/p/17077184.html