|
本文目录CMake简介CMake命令CMake常见指令常用环境变量Qt应用示例一个完整的Qt 5项目CMakeLists.txt参考CMake是一个跨平台、开源的构建工具,在C/C++项目中有广泛应用。本文首先介绍CMake及常用指令,并结合工作时需要用到的Qt 5,给出一个完整的CMake项目配置。, v+ I4 I: X. `6 p
CMake简介返回目录CMake如其名”Cross-platform Make”,是一个 跨平台、开源 的构建工具。与make不同,CMake并不直接构建软件,而是生成用于构建的Makefile、.sln等工程文件,相当于高阶构建工具。* i8 K# N6 C) @
与另一构建工具Automake相比,CMake使用上更方便,支持更多的编译套件(Ninja、VS等)。许多编辑器和IDE,如VS Code(宇宙第一编辑器/IDE)、Clion、Visual Studio等都内置了对CMake的支持。特别的,CMake已经是QT 6的默认构建工具,官方给出从qmake迁移的理由是CMake成熟稳定、用户基数大生态完善。因此,对于需要跨平台编译运行的C/C++项目,很推荐学习和使用CMake作为构建工具,能方便的转换成各种IDE项目,团队成员无需切换编辑器/IDE即可工作。2 n% k$ x' m5 Y, O" ~
值得一提的是,CMake由Kitware公司开发和维护,VTK和ParaView等知名开源产品均出自该公司。从这方面看,CMake也算出身名门,因此能很快流行开来。
- j& n$ D9 n7 i3 ` CMake命令返回目录CMake基于CMakeLists.txt文件来生成对应目标(generator)的构建文件,一个标准的CMake项目构建操作为(命令行方式):
3 m: F# d7 T6 N4 I$ i; ^0 xcd PROJECT_DIR
. d' h, m% `, i; U! b5 n, k5 ycmake8 Q+ Y/ i+ ~& O# Q
make TARGET或者使用用CMake GUI:" F7 l& m4 M( s5 G9 p# z) Z
1 Z4 u) \4 [* N; V5 o
+ Z. E; U3 l1 d' Y2 {" X! QCMake-GUI操作示意图然后使用VS打开生成的.sln项目,即可编译、运行和调试项目。
9 r9 k( H* ?/ ~( pLinux/Unix/MacOS平台上,CMake默认生成标准的makefile;Windows平台上则会检测Visual Studio版本,生成对应的VS .sln项目工程文件(在MSYS/Cygwin/WSL环境下执行除外)。可以使用 -G 选项切换生成目标,例如生成Ninja构建文件:6 i2 [' Y$ F# i4 _. c+ L0 c
cmake . -G Ninja6 K9 P6 } B d2 o7 [# w
ninja TARGETCMake一个非常棒的特性是“外部构建”(out-of-source build),即支持在源码目录外构建。由于这个特性,以及CMake生成的makefile没有clean命令,一般来说都推荐在单独的build目录中构建:
6 T2 j9 X: _1 [- c3 ^4 y0 gmkdir -p build4 Y6 ?9 w$ g7 z0 c
cd $_* v* T/ S' S; ]) Y- B, G& k
cmake ..
( |- G* p( ~4 Xmake TARGET -j4如果使用CMake GUI,Browse Build时请选择单独的构建目录。
/ q( S3 A/ J# w$ S- ^, L* @命令行方式下编译Debug/Release版本、传递C++编译参数,请使用 -D 选项,例如:6 l" \2 R: U0 v+ R
cmake .. -DCMAKE_BUILD_TYPE=Release
- R0 |% p4 i0 f% f! X7 m/ c) ]make TARGET -j4一些内置的宏定义参数可参考下文的环境变量。
7 b9 A9 w/ v& y4 q% q2 O+ F如果是生成VS项目,则只需在VS中选择构建版本、设置编译和链接参数即可。
1 R% [. X. D5 o, C- u9 H CMake常见指令返回目录CMake基于CMakeLists.txt文件生成项目构建文件,因此编写CMakeLists.txt文件是CMake项目的核心。本小节介绍一些用在CMakeLists.txt文件中的常用指令。
1 G7 p) x) h; `3 [4 u( B1 ]- C9 _CMakeLists.txt 使用 # 作为注释,# 所在行后续字符均作为注释被忽略( a+ f, f1 m1 K3 B
cmake_minimum_required一般这条指令出现在文件的最前面,用来指定项目支持的最低版本。对于Qt 5项目,建议为:cmake_minimum_required(VERSION 3.7)。' ?: S* ~$ r, O1 a
project指定项目名称及属性。C/C++项目的建议值为:project(项目名称 C CXX)。
* b$ a) R% o( Sset定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。
0 l2 S* P2 C. C; ?! q3 h: Iif…else[if]…endif条件控制语句,注意指令后的括号不可省略:+ L( o# b8 m% e( O- ]
if (WIN32)2 v7 p) Z, Z0 R* u
xxxx
* B$ ~" Z/ p9 Y' d; e& f, Y: W& gelse() # 括号不可省略
' O; l& X+ i2 Z1 a4 R, Sxxxx0 Y* n! _- x( r4 _; E; l# D0 `
endif()8 q; t: O C7 ^% l
find_package查找指定模块,例如OpenMP。Qt 5项目一般需要:find_package(Qt5 COMPONENTS Widgets REQUIRED)。
4 T$ z9 R6 ~# I- c: G+ s) Einclude_directories添加头文件include路径,一个更推荐使用的指令是 target_include_directories,其不污染后续目标的include路径,且能精细控制是否暴露依赖的包含路径。但是 target_include_directories 需要CMake 3.13 版本才支持,在Visual Studio 2017中使用会有问题。: W1 j4 N' ~7 [1 F/ w6 Z9 X# N
link_directories设置链接库的路径,更推荐的指令是 target_link_directories,理由见 include_directories。
$ y4 A9 k0 p. k7 Maux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。+ s8 N8 j5 s5 E) A M
filefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到SRC变量中:file(GLOB_RECURSE SRC "src/*.cpp" "src/*/*.cpp")。
" Y' [8 u% U2 m) Z) x0 D$ m5 a相对于把每个需要编译的文件添加到CMakeLists.txt中,aux_source_directory 和 file 等指令可方便的引入多个文件,但其弊端之一是CMake不能感知文件变化。当新增文件、文件被删除、重命名时需刷新CMake缓存才能被应用到项目中。# M& K$ q7 c- L2 [" h3 h
find_library查找指定库的路径并保存到变量中。5 ~5 `4 \9 v; N' [# b+ }. O
add_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。
8 B p: l% B9 [1 Eadd_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。 \5 |6 \0 t2 F1 N9 R9 ]! S3 I
add_executable构建可执行程序,一般项目的主CMakeLists.txt中会有这条指令。
0 e. l h! L) N; C& _add_library构建动态或静态库,一般存在于子目录或者库的CMakeLists.txt文件中。
) {/ R. u. Z- dmessage可在cmake构建时输出信息。
0 J7 |0 Q3 i! c' f& W: L3 JCMakeLists.txt文件中指令不区分大小写,但一般来说同一个文件中指令应保持大小写风格一致。0 O5 @" N* Z. W* L0 c. b
更多指令可参考 CMake官方文档。* }# A" G. Q2 [( f& p6 T
常用环境变量返回目录本小节介绍几个常用的环境变量(编译宏)。8 v" E+ M- u! R7 I- m4 \5 y! P
CMAKE_BUILD_TYPE: 指定构建类型,常用值为 Debug、Release、RelWithDebInfo 和 MinSizeRel;CMAKE_C(XX)_FLAGS:传递给C/C++编译器的编译选项,例如输出所有警告: -DCMAKE_CXX_FLAGS="-Wall";– CMAKE_EXE/MODULE/_LINKER_FLAGS:传递给C/C++链接器的编译选项,例如指定链接数学库:-DCMAKE_LINKER_FLAGS="-lmath"。 Qt应用示例返回目录本节结合工作时需要用到的Qt 5,介绍Qt 5工程中CMake的使用方式。& {6 N+ C9 ]- W# t; r7 L' M6 B
新建Qt项目时,可以选择CMake作为构建工具:
* q5 |& }: V+ Z& }8 r
3 `8 e5 p/ u. o# ?# n, U5 X! _2 m" d, @. Q
Qt新建项目使用CMake生成项目后,项目文件夹将出现CMakeLists.txt和CMakeLists.txt.user两个文件,熟悉的.pro文件没有了(CMakeLists.txt.user充当了Qt Creator工程文件的角色,其他IDE用不到,可删除)。5 S( T5 C& o Z/ Z
但需要注意的是,此时Qt Creator中编译项目是没问题的,但是在CLion/VS Code中打开,或者生成Visual Studio用的.sln文件会有问题,因为CMake无法检测到Qt是否安装及其安装路径。" I8 z' u0 ^/ n/ D& {
解决办法便是在 project 指令后增加如下指令告知Qt的安装位置:" q& K! C, U, ]6 Z2 I+ s. R
# 具体路径请根据自身情况替换! ]2 v* W3 M+ K
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")+ G' y9 m. e4 L4 Q. L
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")! _; @# P! ], \/ ~7 f% {
然后再次运行 cmake 指令或者使用CMake GUI重新运行,构建文件夹下便能正常生成.sln项目文件。
( d4 w1 t9 \9 A& j: g3 l m1 W4 D$ ]VS中编译好后,运行时会提示无法找到Qt相关的dll导致程序不能正常运行。解决办法包括:7 f, \7 g, w) E0 }0 k& ?) b
1. 设置VS选项,将Qt的dll路径包含进去;
$ K- b$ E8 G3 H+ Q/ U) m2 n 2. 将Qt相关dll拷贝到编译输出文件夹;! b; N J o9 p2 q7 s6 [
3. 设置CMake,使其能自动复制所需要的dll。/ }- `" J. y7 {* ?
这里介绍第三种方式,原理是借助Qt自带的windeployqt.exe程序自动部署程序所需dll到目标文件夹。具体操作为,在项目根目录的CMakeLists.txt最后添加部署dll的指令:& m0 l8 Y' G0 }; |/ j+ n
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
3 D1 t7 E1 N v/ kfunction(windeployqt target)
1 [; G! V5 ^/ u7 s; D# POST_BUILD step) j: z# ~: C9 o( i
# - after build, we have a bin/lib for analyzing qt dependencies0 ^5 N8 ~3 n& ~0 }$ ? q6 y
# - we run windeployqt on target and deploy Qt libs
' r; Q* s1 e2 o( Badd_custom_command(TARGET ${target} POST_BUILD
9 s% S% }. k/ U1 C8 W. t& jCOMMAND "${QT_BIN_PATH}/windeployqt.exe"# E3 u8 B$ _7 G s3 h
--verbose 1
5 l" U0 c2 F3 d3 g8 p& W9 z#--release # uncomment this line if built with Release7 L) f5 S, D8 t# \( _9 J
#--no-svg; }6 y7 T! g9 q2 {" v1 \
#--no-angle! x8 u4 B' k: X% K( Z3 y
#--no-opengl
8 ]8 P' P7 o# Y! Z! d#--no-opengl-sw" J- F' ^1 C7 a9 Y8 J+ G( x
#--no-compiler-runtime- A% j p& X- y6 M6 y7 w2 C$ f# X
#--no-system-d3d-compiler @% w% Y: U- G- p' k1 }
\"$\"
, g. d' f. h* E2 |$ p6 K* G- qCOMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."
! k1 M6 {- I; p( N$ @# C" O3 J)
$ z% n' K, S Z* E9 Y2 a8 Zendfunction()& ^2 p* S: o: {* \9 d, [6 T# l
if (WIN32)) ^/ O: u* b" p4 y: n' p: i
windeployqt(${PROJECT_NAME})
2 T) t8 q) k* gendif()最后,转换成VS项目时,默认是Console项目,运行时会有cmd窗口。一个解决办法是在生成可执行文件时设置目标为 WIN32:
0 q# f1 m) b, Z1 }% gadd_executable(${PROJECT_NAME} WIN32 xxxx)
& P: w5 S( e' l, q; A& y1 N4 K 一个完整的Qt 5项目CMakeLists.txt返回目录以下是一个适用于Windows平台的Qt 5项目完整CMakeLists.txt,实际使用时请替换名字和Qt 5安装路径等:& z2 E# R9 o; t/ @
cmake_minimum_required(VERSION 3.7)
' O! s k( j- j4 I# 请将myproject改成实际的应用名字; H# s T2 X; I/ f7 h8 ~: D
project(myproject LANGUAGES CXX)
/ }, M# E1 Y% L5 {0 Bset(CMAKE_INCLUDE_CURRENT_DIR ON)
( I& ]7 Q1 R' ]4 k$ A6 \7 |# 请更改为实际的Qt安装目录: [& \! y! x+ j! p
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")+ N' l: S3 [) c" Q$ |
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")
. I5 U* s% o3 [1 fset(QT_BIN_PATH "${QT_MSVC_PATH}/bin")$ N' T& S Z1 l* q* C
set(CMAKE_AUTOUIC ON)
! N8 |1 h' @( R' J8 j$ w Sset(CMAKE_AUTOMOC ON), |/ x" d, w% N' n% B7 w% C
set(CMAKE_AUTORCC ON)4 X D4 G! U( L% `0 }1 g* M
set(CMAKE_CXX_STANDARD 11)1 G! g! D3 T+ k+ A) t
set(CMAKE_CXX_STANDARD_REQUIRED ON)' F# P2 v) V. p0 w% _$ R9 g; r
find_package(Qt5 COMPONENTS Widgets REQUIRED)
& ~+ k2 I+ V' y5 l9 l4 g# 默认Release构建
4 r# C$ L& @3 Hif (NOT CMAKE_BUILD_TYPE)4 ^% D; n4 a; z9 z8 Q$ h
set( CMAKE_BUILD_TYPE "Release" )6 `) _5 S6 m$ u
endif()9 W% c- p% q4 G6 i4 i1 z8 K
message("build type: ${CMAKE_BUILD_TYPE}")7 t6 D( X, V3 X
# 按照自己的项目结构添加文件
! v+ \' y( \5 x# 也可使用file/aux_source_directory批量引入,注意不要引入自动生成的文件!
, v# f4 x! h, u9 jadd_executable(${PROJECT_NAME} WIN326 V0 S" e) J9 Y% t
main.cpp
! W, c' U% p: g$ R& o mainwindow.cpp" r# I+ T, e7 ^- a3 H* \
mainwindow.h
: `" Z P4 w) u- r$ h)$ i. V: X% p a2 c0 T2 \/ `$ j- t6 q5 e
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)/ Q( S" j* e ^7 D' Q; X
function(windeployqt target)
/ q' y' _2 y% W( [, D) z8 I/ m# POST_BUILD step/ K* k' O6 ]7 n) B [; H( b
add_custom_command(TARGET ${target} POST_BUILD
- i; J; Z! w$ m3 _7 A* qCOMMAND "${QT_BIN_PATH}/windeployqt.exe"
' R0 B/ T4 P" w) Y& m--verbose 1- t4 a0 H6 `1 c; @/ U; w
#--release & A$ B, R; q2 h& I1 |1 n! c
#--no-svg% [' _6 r: [" Z+ B# L
#--no-angle
4 z# C; ]) F& z#--no-opengl# l' `3 J7 b4 A0 O
#--no-opengl-sw# j5 o3 p& U* e/ M* ~# T
#--no-compiler-runtime
: N6 Z, `+ o+ o/ ~& g) [#--no-system-d3d-compiler6 [! k8 E |% G9 k. X/ s
\"$\"0 j6 a5 A! ]* h3 g+ o' ]
COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."
: E- V3 C/ |& `4 x" Q: ^)
# [3 n9 a) {9 D7 sendfunction()
2 P# `1 J( X8 `$ Yif (WIN32)
" m6 w4 W C0 q2 r# D* |8 M6 R4 R3 R windeployqt(${PROJECT_NAME})
4 s( k" T, G& ]# V- Qendif()
) r) n$ q- J. O) a( u````通过上面的配置,我们的Qt项目既可在Qt Creator中正常编译运行,也可在CLion/Visual Studio中正常编译运行而 无需安装Qt插件。
" O7 c7 t1 h& {9 H0 L& c 参考返回目录1. CMake官网
9 s2 u) ~6 `& {& \5 u7 M2. CMake教程
8 t. K7 s7 Z3 N3. CMake FAQ
5 V! [1 Y* a" x4. CMake指定编译器$ k% l, h; j4 u" C+ z' m) _
AD:【国外VPS推荐】 搬瓦工三网回程CN2 GIA VPS,季付46.87$打赏赞(3) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|