CMake基础
CMake(Cross platform Make,在线帮助文档,wiki,chs)是一个开源的跨平台自动化建构系统(目前仅支持C / C++ / Java语言),不依赖于某特定编译器,并可支持多层目录、多个应用程序与多个库。
对于其他GNU Make ,QT的qmake ,微软的nmake等Make工具,如果要在不同平台上编译,就得为每一种标准写一次 Makefile,这将是一件让人抓狂的工作。
CMake就是针对上面问题而设计的工具:它首先允许开发者编写一种平台无关的 CMakeLists.txt文件(注:名字大小写要完全一致)来定制整个编译流程,并不直接建构出最终的软件
再根据目标用户的平台进一步生成所需的本地化Makefile(如:Unix的Makefile)或工程文件(如:Windows的Visual Studio 工程、MacOS的Xcode工程)。从而做到:Write once, run everywhere.
在linux平台下使用CMake生成Makefile并编译的流程如下:
① 编写 CMake 配置文件 CMakeLists.txt 。
② 执行命令 cmake PATH 或者 ccmake PATH 生成 Makefile(注:ccmake 和 cmake 的区别在于前者提供了一个交互式的界面)。其中, PATH 是 CMakeLists.txt 所在的目录。
③ 使用 make 命令进行编译。
linux平台默认就会安装CMake(没有装的话,通过yum install cmake或apt-get install cmake来安装)
rpm包和deb包是Linux系统下最常见的两种安装包格式。
rpm包用在RedHat系列(Redhat、Centos、Fedora等)的Linux系统上,使用yum来管理。
deb包用于Debian系列(Debian、Ubuntu 等)的Linux系统上,使用apt-get来管理。
MacOS平台可通过brew install cmake来安装。
Windows平台可从官网下载最新版本进行安装。
注:vs2019也内置了一份CMake:
为了方便使用cmake,在windows可将cmake路径(E:\Program Files\CMake\bin)到PATH环境变量中。
执行cmake.exe --version打印出cmake的版本 (如:cmake version 3.18.4),来确认cmake安装和环境是否配置成功。
vscode插件CMake、CMakeTools
CMake有如下主要功能:
① Colorization(着色)
② Snippets & Completion Lists(自动完成)
③ Quick Help(快速帮助)
CMakeTools有如下主要功能:
① Configure a project(配置一个项目) 注:使用CMake配置一个项目
② Build a project(编译一个项目) 注:CMake自身没有编译功能,它只是拉起相关编译器、链接器进行编译链接
② Debug a project(调试一个项目) 注:CMake自身没有调试功能,它只是拉起相关Debugger进行调试
更多功能详见:github README
CMakeTools相关设置见菜单“File” -- “Preferences” -- “Settings”面板中“Extensions” -- “CMake Tools”标签
注1:User表示设置会保存在当前用户下,对当前用户下所有CMake都起作用
注2:Workspace表示设置会保存在当前工作空间下,仅对当前工作空间CMake起作用
项目示例
CMakeLists.txt内容如下:
cmake_minimum_required(VERSION 3.10) project(Test1) add_executable(Test1 main.cpp)
main.cpp内容如下:
#include <iostream> int main() { std::cout << "Hello World!" << std::endl; return 0; }
配置项目(Configure a project)
点击vscode菜单View -- Command Palette...,输入:>CMake: Configure,在弹出的下拉框中选择对应的编译器(如下)
x86:编译器为x86版本,输出文件为x86。
amd64_x86:编译器为amd64版本,输出文件为x86。
amd64:编译器为amd64版本,输出文件为amd64。
x86_amd64:编译器为x86版本,输出文件为amd64。
注1:需要根据本机cpu型号和目标机器cpu型号来确定使用那个编译器。
注2:amd64指x64,因为x86-64是amd首先设计出来的,因此intel的x86-64和amd64是一回事。
注3:CMakeTools重新Configure a project时,需要将当前工作目录改名(不换目录名的话,不会弹出上图编译器的选择下拉列表),然后执行CMake: Delete Cache and Reconfigure
build目录中会生成vs2019相关工程
也可通过命令行来Configure项目
编译项目(Build a project)
点击vscode菜单View -- Command Palette...,输入:>CMake: Build
这个过程中cmake会拉起MSBuild.exe来编译ALL_BUILD.vcxproj项目
注1:执行编译项目时,若之前未配置项目,会先进行配置,然后再编译
注2:按F7也可以编译项目
也可通过命令行来Build项目
build目录中会生成Test1.exe可执行文件
调试项目(Debug a project)
① 双击Test1.sln,用vs2019打开该解决方案文件
② 将Test1项目设置为缺省,放置断点,按F5进行调试
手动下载、管理和引用第三方库
① 下载各个第三方库
② 逐个用cmake -S . -B build编译第三方库
③ 指定各个第三方库所在路径
使用vcpkg下载、管理和引用第三方库
vcpkg(github)是一个开源跨平台(支持Windows、 Linux 和 MacOS)的管理C / C++ 库的工具。
安装和配置vcpkg
① 克隆下载vcpkg的工程
git clone https://github.com/microsoft/vcpkg
② 执行工程中的bootstrap-vcpkg.bat脚本,下载vcpkg.exe
③ 创建环境变量VCPKG_ROOT,并设置为G:\svn\vcpkg
④ 将G:\svn\vcpkg添加到PATH环境变量中 注:方便在任何目录中使用vcpkg.exe
⑤ 配置Using cached binary package第三方库的位置,更多信息详见:Binary Caching
创建环境变量VCPKG_DEFAULT_BINARY_CACHE,并设置为F:\vcpkg\ThirdParty,使得vcpkg安装的第三方库存放到F:\vcpkg\ThirdParty目录中
若不设置该环境变量时,vcpkg安装的第三方库会存放在C:\Users\<用户名>\AppData\Local\vcpkg\archives目录中
vcpkg命令用法
vcpkg --help // 查看vcpkg帮助
vcpkg install glfw3 // 编译并安装x86版本的glfw3库 注:缺省为x86
vcpkg install glfw3:x64-windows // 编译并安装x64版本的glfw3库
vcpkg install glfw3 --triplet=x64-windows // 功能同上
安装的库会解压放在vcpkg\installed\x64-windows目录中:
注:保证dll能被加载到,可将G:\svn\vcpkg\installed\x64-windows\bin放到PATH变量中
vcpkg remove glfw3:x64-windows // 删除x64版本的glfw3库
vcpkg search glfw // 查找glfw相关库的信息
glfw3 3.3.8 GLFW is a free, Open Source, multi-platform library for OpenGL, OpenGL ES ... imgui[glfw-binding] Make available GLFW binding libigl[glfw] Build with glfw magnum[glfwapplication] GlfwApplication library opensubdiv[glfw] Path to glfw The result may be outdated. Run `git pull` to get the latest results. If your port is not listed, please open an issue at and/or consider making a pull request. - https://github.com/Microsoft/vcpkg/issues
在Visual Studio 中使用vcpkg管理的第三方库
① 执行命令:vcpkg integrate install
② 在此之后,在VS的项目中,所有已安装的库均可直接使用 #include头文件且无需额外配置
在cmake中使用vcpkg管理的第三方库
① 在CMakeLists.txt文件中使用find_package来使用 vcpkg 中已安装的库
find_package(glfw3 REQUIRED)
② 带上CMAKE_TOOLCHAIN_FILE来配置项目:cmake -B [build directory] -S . "-DCMAKE_TOOLCHAIN_FILE=G:/svn/vcpkg/scripts/buildsystems/vcpkg.cmake"
在vscode中,可在workspace的settings.json文件cmake.configureSettings标签下,配置"CMAKE_TOOLCHAIN_FILE": "G:/svn/vcpkg/scripts/buildsystems/vcpkg.cmake"
③ 编译项目:cmake --build [build directory]
在cmake中使用vcpkg来引用指定版本的第三方库
vcpkg提供了versioning特性并默认开启,来解决指定版本的第三方库的引用。详见:Getting started with versioning和Versioning
① 通过vcpkg.json来配置各个第三方库的版本信息
{ "name": "versions-test", "version": "1.0.0", "dependencies": [ { "name": "zlib", "version>=": "1.2.11#12" }, { "name": "glfw3", "version>=": "3.3.6" }, "fmt" ], "builtin-baseline": "99dc49dae7e170c3be63dd097230007f3bb73c4f", "overrides": [ { "name": "glfw3", "version": "3.3.3" } ] }
vcpkg.json中配置了依赖的3个第三方库:zlib、glfw3、fmt。
zlib的版本号1.2.11#12通过#分割,是由version和port-version两部分组成,version(1.2.11)是zlib的实际的版本号,port-version(12) 是这个版本在vcpkg中的补丁版本。两者组合可以获得该库在vcpkg中的具体版本。
glfw3的version要求>=3.3.6,由于overrides中指定其版本号为3.3.3,因此glfw3最终使用3.3.3的版本。
fmt没有设置版本信息,会使用builtin-baseline指定的版本,即:versions/baseline.json(commit id为99dc49dae7e170c3be63dd097230007f3bb73c4f)文件中配置的版本7.13
git show 99dc49dae7e170c3be63dd097230007f3bb73c4f:versions/baseline.json // 查看G:/svn/vcpkg/versions/baseline.json的commit id为99dc49dae7e170c3be63dd097230007f3bb73c4f版本,其内容如下
。。。 。。。 "fmt": { "baseline": "7.1.3", "port-version": 0 }, 。。。 。。。 "glfw3": { "baseline": "3.3.2", "port-version": 1 }, 。。。 。。。 "zlib": { "baseline": "1.2.11", "port-version": 9 }, 。。。 。。。
注1:第三方库版本的确定顺序是overrides --》 dependencies version>= --》builtin-baseline
注2:dependencies version>= 主要用于表示需要使用的最低版本(保持最大程度的兼容)
注3:如果在配置项目时,没有执行vcpkg install并报如下错误:CMake Error at E:/Program Files/CMake/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake
可通过执行CMake: Delete Cache and Reconfigure来解决。
CMakeLists.txt内容如下:
cmake_minimum_required(VERSION 3.10) project(Test1) add_executable(Test1 main.cpp) find_package(ZLIB REQUIRED) find_package(fmt CONFIG REQUIRED) find_package(glfw3 CONFIG REQUIRED) target_link_libraries(Test1 PRIVATE ZLIB::ZLIB fmt::fmt glfw)
main.cpp内容如下:
#include <iostream> #include <fmt/core.h> #include <zlib.h> #include <GLFW/glfw3.h> int main() { std::cout << "fmt version is " << FMT_VERSION << std::endl; std::cout << "zlib version is " << ZLIB_VERSION << std::endl; std::cout << "glfw3 version is " << GLFW_VERSION_MAJOR << "." << GLFW_VERSION_MINOR << "." << GLFW_VERSION_REVISION << std::endl; return 0; }
第三方库编译出来的文件
运行Test1.exe输出的结果
fmt version is 70103 zlib version is 1.2.11 glfw3 version is 3.3.3