|
本文目录CMake简介CMake命令CMake常见指令常用环境变量Qt应用示例一个完整的Qt 5项目CMakeLists.txt参考CMake是一个跨平台、开源的构建工具,在C/C++项目中有广泛应用。本文首先介绍CMake及常用指令,并结合工作时需要用到的Qt 5,给出一个完整的CMake项目配置。
8 q/ H8 G5 g8 L8 m CMake简介返回目录CMake如其名”Cross-platform Make”,是一个 跨平台、开源 的构建工具。与make不同,CMake并不直接构建软件,而是生成用于构建的Makefile、.sln等工程文件,相当于高阶构建工具。+ O; ~( [, b1 n3 l
与另一构建工具Automake相比,CMake使用上更方便,支持更多的编译套件(Ninja、VS等)。许多编辑器和IDE,如VS Code(宇宙第一编辑器/IDE)、Clion、Visual Studio等都内置了对CMake的支持。特别的,CMake已经是QT 6的默认构建工具,官方给出从qmake迁移的理由是CMake成熟稳定、用户基数大生态完善。因此,对于需要跨平台编译运行的C/C++项目,很推荐学习和使用CMake作为构建工具,能方便的转换成各种IDE项目,团队成员无需切换编辑器/IDE即可工作。
; R1 |- Z' _8 C U7 g4 ] F值得一提的是,CMake由Kitware公司开发和维护,VTK和ParaView等知名开源产品均出自该公司。从这方面看,CMake也算出身名门,因此能很快流行开来。
) X+ K m2 R1 J( w CMake命令返回目录CMake基于CMakeLists.txt文件来生成对应目标(generator)的构建文件,一个标准的CMake项目构建操作为(命令行方式):
1 u( I' B' u7 Y4 b! r! H& Lcd PROJECT_DIR
6 E/ a k6 i# Kcmake
8 t7 W* f7 J& |make TARGET或者使用用CMake GUI:
# f7 ~+ ~$ r5 O" @( e0 c
* [( j/ {0 v* S0 W: p0 m3 K* a4 c9 P% V& x& i4 C! y$ S
CMake-GUI操作示意图然后使用VS打开生成的.sln项目,即可编译、运行和调试项目。
8 R& I$ Y* F. V/ b8 yLinux/Unix/MacOS平台上,CMake默认生成标准的makefile;Windows平台上则会检测Visual Studio版本,生成对应的VS .sln项目工程文件(在MSYS/Cygwin/WSL环境下执行除外)。可以使用 -G 选项切换生成目标,例如生成Ninja构建文件:/ d( w1 R4 }) {3 ?5 N
cmake . -G Ninja0 a# g. j: T/ a! C- [% H
ninja TARGETCMake一个非常棒的特性是“外部构建”(out-of-source build),即支持在源码目录外构建。由于这个特性,以及CMake生成的makefile没有clean命令,一般来说都推荐在单独的build目录中构建:+ Y6 U( R- H. A8 ?4 h& h9 `0 g
mkdir -p build' g! I9 B! F, b3 k8 x4 E
cd $_
. Q& \4 L) u* \5 Vcmake ..! M: Y! \4 B. r3 U
make TARGET -j4如果使用CMake GUI,Browse Build时请选择单独的构建目录。0 _7 W* G* W, B8 w/ @, m$ J
命令行方式下编译Debug/Release版本、传递C++编译参数,请使用 -D 选项,例如:
4 C1 y+ D% a$ Fcmake .. -DCMAKE_BUILD_TYPE=Release& n' A+ k# N1 t0 Y
make TARGET -j4一些内置的宏定义参数可参考下文的环境变量。/ D/ f/ M) v R0 r' h7 Z
如果是生成VS项目,则只需在VS中选择构建版本、设置编译和链接参数即可。
' M9 c) v8 \+ ]: M CMake常见指令返回目录CMake基于CMakeLists.txt文件生成项目构建文件,因此编写CMakeLists.txt文件是CMake项目的核心。本小节介绍一些用在CMakeLists.txt文件中的常用指令。. S* t0 g, d0 Y
CMakeLists.txt 使用 # 作为注释,# 所在行后续字符均作为注释被忽略
. F5 S5 ~! W3 b% J6 I% jcmake_minimum_required一般这条指令出现在文件的最前面,用来指定项目支持的最低版本。对于Qt 5项目,建议为:cmake_minimum_required(VERSION 3.7)。* |5 M: k" W. \7 v0 `; i& j
project指定项目名称及属性。C/C++项目的建议值为:project(项目名称 C CXX)。
# o, B" R( j! v# ?7 t: }7 g5 ?set定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。9 P9 d; Z3 Q$ |& ^
if…else[if]…endif条件控制语句,注意指令后的括号不可省略:
; M: |2 @. g6 H! I0 h( w6 l4 W, ^if (WIN32)
- C3 ]; ]/ U$ u3 I; N7 Oxxxx: U- X9 J! g8 ^7 Z0 U
else() # 括号不可省略# R- ^, {* o( C6 H: b- y
xxxx# V: Z6 _5 A. |6 H& u
endif()4 i* p. p5 ]1 v) ?/ s
find_package查找指定模块,例如OpenMP。Qt 5项目一般需要:find_package(Qt5 COMPONENTS Widgets REQUIRED)。$ t& x+ Z! @- w* K5 `# A$ n# y
include_directories添加头文件include路径,一个更推荐使用的指令是 target_include_directories,其不污染后续目标的include路径,且能精细控制是否暴露依赖的包含路径。但是 target_include_directories 需要CMake 3.13 版本才支持,在Visual Studio 2017中使用会有问题。
' q! ~0 e+ M4 {3 N6 e& j) P link_directories设置链接库的路径,更推荐的指令是 target_link_directories,理由见 include_directories。0 B6 N4 Q% M( r- [
aux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。
- T q# J j6 P; E1 I5 cfilefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到SRC变量中:file(GLOB_RECURSE SRC "src/*.cpp" "src/*/*.cpp")。4 x5 P' [3 \/ f+ h2 K
相对于把每个需要编译的文件添加到CMakeLists.txt中,aux_source_directory 和 file 等指令可方便的引入多个文件,但其弊端之一是CMake不能感知文件变化。当新增文件、文件被删除、重命名时需刷新CMake缓存才能被应用到项目中。* f% N8 O) p+ O( ?
find_library查找指定库的路径并保存到变量中。
& E. U5 N/ ~( fadd_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。
% U7 `- W% o/ @# [add_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。
# B8 P6 u# N( B- A) T6 y G* {add_executable构建可执行程序,一般项目的主CMakeLists.txt中会有这条指令。
2 `2 y* y1 a3 Z* s; x4 g7 Padd_library构建动态或静态库,一般存在于子目录或者库的CMakeLists.txt文件中。( E' ^; h; C0 e
message可在cmake构建时输出信息。 E% l2 x+ b: \/ h2 r6 M
CMakeLists.txt文件中指令不区分大小写,但一般来说同一个文件中指令应保持大小写风格一致。/ @) F m! @% W$ Y0 e e& H
更多指令可参考 CMake官方文档。; R: f$ J N R
常用环境变量返回目录本小节介绍几个常用的环境变量(编译宏)。6 t6 s9 u" X" d1 }$ H! x
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的使用方式。3 k3 R8 H; I& t% M, e. r: g7 N1 u
新建Qt项目时,可以选择CMake作为构建工具:" L. a3 u. n2 [2 ^% R; p( C) W/ k
5 P: r) e9 Z8 L* X. L& y
" x/ K* R4 S) L1 n0 I1 mQt新建项目使用CMake生成项目后,项目文件夹将出现CMakeLists.txt和CMakeLists.txt.user两个文件,熟悉的.pro文件没有了(CMakeLists.txt.user充当了Qt Creator工程文件的角色,其他IDE用不到,可删除)。
( B+ z: Y3 D: q. l4 b但需要注意的是,此时Qt Creator中编译项目是没问题的,但是在CLion/VS Code中打开,或者生成Visual Studio用的.sln文件会有问题,因为CMake无法检测到Qt是否安装及其安装路径。
: v4 E1 _/ D: ~: ?8 j, K解决办法便是在 project 指令后增加如下指令告知Qt的安装位置:
. J, n; w Y' b% x% p/ A# 具体路径请根据自身情况替换% U7 Y! `0 m, i
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")9 z# J) |5 }8 Y- q8 B. i! D% e8 `
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")1 Z0 j+ ]1 u! U5 Y8 a; }
然后再次运行 cmake 指令或者使用CMake GUI重新运行,构建文件夹下便能正常生成.sln项目文件。
4 Y+ @' p9 ^1 K0 {+ F# Y, i* ? BVS中编译好后,运行时会提示无法找到Qt相关的dll导致程序不能正常运行。解决办法包括:. x) j4 H! M, s
1. 设置VS选项,将Qt的dll路径包含进去;- P1 w' S! t; `3 Q8 G
2. 将Qt相关dll拷贝到编译输出文件夹;
/ K% m3 D, D* S; H1 r* ? 3. 设置CMake,使其能自动复制所需要的dll。7 c+ u5 ]+ I; M- R/ J$ c
这里介绍第三种方式,原理是借助Qt自带的windeployqt.exe程序自动部署程序所需dll到目标文件夹。具体操作为,在项目根目录的CMakeLists.txt最后添加部署dll的指令:" D" h0 J; {4 i
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")$ G0 n& N$ t+ P
function(windeployqt target)7 ], S! ]4 _: G
# POST_BUILD step( y3 l/ ?5 {7 B) c8 @: s, z% v
# - after build, we have a bin/lib for analyzing qt dependencies4 ^4 M8 P, a! g4 z+ r P3 e4 m9 R
# - we run windeployqt on target and deploy Qt libs
+ l9 l( `& j; T1 B. {' _: Fadd_custom_command(TARGET ${target} POST_BUILD
} `5 _- u/ _" M/ b) f! |6 tCOMMAND "${QT_BIN_PATH}/windeployqt.exe": I0 _6 \& o# \: ~( _
--verbose 1- R! ~! J7 y, R1 w3 n0 b5 o
#--release # uncomment this line if built with Release
& h3 h3 y9 i ]/ e2 {#--no-svg
& y. z3 v5 L% i3 U3 ^# H' k3 G#--no-angle
7 N" c; t0 P1 ]' ^( G#--no-opengl- d2 N5 l/ r% m; y
#--no-opengl-sw; I7 {! }6 J& I+ {: j, H4 g' G
#--no-compiler-runtime
6 q# W+ e8 F% k" Q J' N) m% o#--no-system-d3d-compiler
) _: i6 m3 Q# B) P\"$\"
$ M( D+ f7 a. G0 h) M FCOMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."0 @3 G6 ]- {& s4 ]$ s3 y6 r' u3 t# o
)
D% O9 @" |2 d! D8 I: Mendfunction()
0 u' W6 v( J1 V( h% Lif (WIN32)! b+ R. b0 l. w1 p: Z& G' {
windeployqt(${PROJECT_NAME})
% Z- Y- j* Q2 F$ Pendif()最后,转换成VS项目时,默认是Console项目,运行时会有cmd窗口。一个解决办法是在生成可执行文件时设置目标为 WIN32:
* h3 t/ U* z8 K% n! Hadd_executable(${PROJECT_NAME} WIN32 xxxx)
! H& s5 o3 X8 {; v2 z+ V 一个完整的Qt 5项目CMakeLists.txt返回目录以下是一个适用于Windows平台的Qt 5项目完整CMakeLists.txt,实际使用时请替换名字和Qt 5安装路径等:
% e# c9 B" _; B- Xcmake_minimum_required(VERSION 3.7)7 m% t" `! U( R. u0 [$ X$ c
# 请将myproject改成实际的应用名字
: k) k: E, C6 T; b, _project(myproject LANGUAGES CXX)) L( |( g ~! d5 Q, [% f% S/ p
set(CMAKE_INCLUDE_CURRENT_DIR ON): u+ v$ K& z" e M4 @
# 请更改为实际的Qt安装目录2 E* Y2 m! ]7 q, ?$ w" q
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")% E( U4 A( r8 w7 K6 L$ ^0 C
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")$ h& b9 k x/ \- i5 D% T! z' h2 Q
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
# j' m1 }# ^- f+ ~set(CMAKE_AUTOUIC ON)
- @4 J% ~2 F5 ]set(CMAKE_AUTOMOC ON)5 b* o$ m$ q4 w1 _) H1 Q
set(CMAKE_AUTORCC ON)
* J, x" k# b1 r, [1 N( F% J/ Oset(CMAKE_CXX_STANDARD 11)
! D/ h/ N3 N% r% t7 b2 |3 Rset(CMAKE_CXX_STANDARD_REQUIRED ON)
: y* e& E+ ~5 ^find_package(Qt5 COMPONENTS Widgets REQUIRED)8 U( s/ h! i" v9 n- T: l
# 默认Release构建0 `2 l1 j9 l( j6 {0 u' U6 a7 P
if (NOT CMAKE_BUILD_TYPE)
' R& Y* M( K- `5 q set( CMAKE_BUILD_TYPE "Release" )
% ]0 A& y0 \! q, B. |endif()
2 c* x* X" Y6 [' |& x& d5 a4 Tmessage("build type: ${CMAKE_BUILD_TYPE}")
# o" m' }3 h- ^ g5 G/ t# 按照自己的项目结构添加文件# a" d/ W; `( W, |: _
# 也可使用file/aux_source_directory批量引入,注意不要引入自动生成的文件!
0 j5 _/ O: H3 yadd_executable(${PROJECT_NAME} WIN32
* }8 b& e B; e( C9 `6 t2 q main.cpp
9 y0 O# d4 B2 @( R; n) E mainwindow.cpp
- ^; Z/ d3 T `/ r mainwindow.h/ u2 u9 S( I2 R# U5 y% Q+ v
); A! h' c) l2 e: [/ i, \
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)+ I$ ?. l. x G# P1 O* o9 ^
function(windeployqt target)7 G% R3 n6 I. M4 c/ _
# POST_BUILD step
6 v- g+ {, L+ ^* y8 @9 xadd_custom_command(TARGET ${target} POST_BUILD* a0 [1 `" m; C1 r
COMMAND "${QT_BIN_PATH}/windeployqt.exe"
$ m; s5 I9 z* K7 M--verbose 1+ }+ q: _' P; O; _% W, D
#--release
9 h3 q' B ^+ n& T#--no-svg# J' G) j+ G# s/ z1 F D
#--no-angle) p9 u. E0 j# O% B" ~
#--no-opengl
. Q8 v! k. b$ f8 u" t3 x6 ]" W0 l#--no-opengl-sw
7 V/ B0 ~* [0 L5 p#--no-compiler-runtime$ J# X8 X/ X, N& t2 m) ^1 l- H4 ]
#--no-system-d3d-compiler/ r4 I" p2 `9 x* |# J3 b' a# ~
\"$\") \ e5 B4 e+ |: a: n" Y
COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ...") ?3 E$ I, ~& t$ V
)
9 F1 k5 A6 X7 f( Q6 o, Lendfunction()
, V5 J8 Y; h' _! L X: r( W" Uif (WIN32)
" a4 k d; }! z; X0 ~ windeployqt(${PROJECT_NAME})
. c7 X) u6 J8 d; pendif()
" V. b% P' V. ~3 l! C- a" ]````通过上面的配置,我们的Qt项目既可在Qt Creator中正常编译运行,也可在CLion/Visual Studio中正常编译运行而 无需安装Qt插件。
3 K. j2 {' p" e) e 参考返回目录1. CMake官网" i& ?# P# g- @) o, P( p
2. CMake教程
4 K, L+ u: l) `- s- V$ N3. CMake FAQ
4 S% h! L; G0 w1 J2 R# S/ k$ A4. CMake指定编译器
. a A$ g( c8 E) }" hAD:【国外VPS推荐】 搬瓦工三网回程CN2 GIA VPS,季付46.87$打赏赞(3) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|