|
本文目录CMake简介CMake命令CMake常见指令常用环境变量Qt应用示例一个完整的Qt 5项目CMakeLists.txt参考CMake是一个跨平台、开源的构建工具,在C/C++项目中有广泛应用。本文首先介绍CMake及常用指令,并结合工作时需要用到的Qt 5,给出一个完整的CMake项目配置。
7 X |. A, w: L( @* r; g8 k. m CMake简介返回目录CMake如其名”Cross-platform Make”,是一个 跨平台、开源 的构建工具。与make不同,CMake并不直接构建软件,而是生成用于构建的Makefile、.sln等工程文件,相当于高阶构建工具。
) Q) d! ^: ^. J& R* Y- J# B与另一构建工具Automake相比,CMake使用上更方便,支持更多的编译套件(Ninja、VS等)。许多编辑器和IDE,如VS Code(宇宙第一编辑器/IDE)、Clion、Visual Studio等都内置了对CMake的支持。特别的,CMake已经是QT 6的默认构建工具,官方给出从qmake迁移的理由是CMake成熟稳定、用户基数大生态完善。因此,对于需要跨平台编译运行的C/C++项目,很推荐学习和使用CMake作为构建工具,能方便的转换成各种IDE项目,团队成员无需切换编辑器/IDE即可工作。! y @$ R% [! r% g7 `$ x
值得一提的是,CMake由Kitware公司开发和维护,VTK和ParaView等知名开源产品均出自该公司。从这方面看,CMake也算出身名门,因此能很快流行开来。5 v$ M. {6 y. }# T
CMake命令返回目录CMake基于CMakeLists.txt文件来生成对应目标(generator)的构建文件,一个标准的CMake项目构建操作为(命令行方式):1 N* a" T1 b( w0 e* Y1 q# e9 [5 H
cd PROJECT_DIR4 D4 }4 m d5 D! j& u- Q) e8 w4 p/ W8 e
cmake
. ^% X' M. v' qmake TARGET或者使用用CMake GUI:
( W) z5 G! y3 N; P, u( ~: E2 X1 l2 z( I+ \
3 ^6 |, b* ]1 l3 ~ z8 {! ACMake-GUI操作示意图然后使用VS打开生成的.sln项目,即可编译、运行和调试项目。: V* \$ x7 `) H$ o
Linux/Unix/MacOS平台上,CMake默认生成标准的makefile;Windows平台上则会检测Visual Studio版本,生成对应的VS .sln项目工程文件(在MSYS/Cygwin/WSL环境下执行除外)。可以使用 -G 选项切换生成目标,例如生成Ninja构建文件:
. u0 M! D: e" u5 ^$ Ocmake . -G Ninja2 T0 c0 h/ Q0 |8 H" Q9 H+ u( u9 i
ninja TARGETCMake一个非常棒的特性是“外部构建”(out-of-source build),即支持在源码目录外构建。由于这个特性,以及CMake生成的makefile没有clean命令,一般来说都推荐在单独的build目录中构建: e- @! Z' Z1 s8 F
mkdir -p build6 l3 I2 q5 P9 x+ m% [
cd $_
! W: A- s' P" p& B1 N5 I4 w) ccmake ..
+ I/ W8 A2 }9 d! u4 Cmake TARGET -j4如果使用CMake GUI,Browse Build时请选择单独的构建目录。( `2 u7 R% K( ~% z- D: d
命令行方式下编译Debug/Release版本、传递C++编译参数,请使用 -D 选项,例如:
0 V' ~. d+ d6 P" y& _* H! z* }3 a) ocmake .. -DCMAKE_BUILD_TYPE=Release9 @# M% ~& C" U4 i X' i0 f5 I. O: R3 a
make TARGET -j4一些内置的宏定义参数可参考下文的环境变量。' A- ~: m8 H. }' t9 T
如果是生成VS项目,则只需在VS中选择构建版本、设置编译和链接参数即可。
! t3 r1 K/ a8 I% l7 k CMake常见指令返回目录CMake基于CMakeLists.txt文件生成项目构建文件,因此编写CMakeLists.txt文件是CMake项目的核心。本小节介绍一些用在CMakeLists.txt文件中的常用指令。
( y+ A( R0 g- j+ o( yCMakeLists.txt 使用 # 作为注释,# 所在行后续字符均作为注释被忽略
5 ~8 [* C) T. y5 q& y* ?: ocmake_minimum_required一般这条指令出现在文件的最前面,用来指定项目支持的最低版本。对于Qt 5项目,建议为:cmake_minimum_required(VERSION 3.7)。
, w) d- E! L7 M* j/ cproject指定项目名称及属性。C/C++项目的建议值为:project(项目名称 C CXX)。* C( M9 T3 h/ ]' B& O8 a: c1 {4 |/ O
set定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。- P7 a/ s2 P( E1 m
if…else[if]…endif条件控制语句,注意指令后的括号不可省略:
0 X7 P8 y4 r, u, O/ P5 |6 Kif (WIN32)
+ J, f3 o. }: @3 p6 p: ~) Axxxx7 _; b) e5 I! a% H; R# @: M
else() # 括号不可省略( ^' U) @6 a, ^% y# r4 U
xxxx2 p7 o% q* k& }5 j/ i+ p1 E
endif()- A; a/ X f4 I. E
find_package查找指定模块,例如OpenMP。Qt 5项目一般需要:find_package(Qt5 COMPONENTS Widgets REQUIRED)。+ m" |2 w0 j" ]# b
include_directories添加头文件include路径,一个更推荐使用的指令是 target_include_directories,其不污染后续目标的include路径,且能精细控制是否暴露依赖的包含路径。但是 target_include_directories 需要CMake 3.13 版本才支持,在Visual Studio 2017中使用会有问题。
* j* d i* A8 J# {& G5 T link_directories设置链接库的路径,更推荐的指令是 target_link_directories,理由见 include_directories。1 e G1 h; P7 J6 _7 i
aux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。- M3 R) X4 y# w
filefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到SRC变量中:file(GLOB_RECURSE SRC "src/*.cpp" "src/*/*.cpp")。
% p: l2 l) P& f' N. c2 s, P相对于把每个需要编译的文件添加到CMakeLists.txt中,aux_source_directory 和 file 等指令可方便的引入多个文件,但其弊端之一是CMake不能感知文件变化。当新增文件、文件被删除、重命名时需刷新CMake缓存才能被应用到项目中。
& R* V4 m/ c: L5 O- e( L/ cfind_library查找指定库的路径并保存到变量中。- h# o6 Y! u/ `9 A+ L% x( e
add_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。) \# e3 V8 T! y ]! ?% H( F0 N4 s& v
add_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。) ] ]2 S. v8 z% Q8 x! i
add_executable构建可执行程序,一般项目的主CMakeLists.txt中会有这条指令。
' N D5 j. t. |- o9 ` S6 badd_library构建动态或静态库,一般存在于子目录或者库的CMakeLists.txt文件中。
! [1 L3 v2 V: j5 f6 Y. ^2 _message可在cmake构建时输出信息。
0 j. u2 d- D; D, RCMakeLists.txt文件中指令不区分大小写,但一般来说同一个文件中指令应保持大小写风格一致。# a+ b. g+ F }2 V l3 r' q
更多指令可参考 CMake官方文档。
) Z4 W3 Q! o3 N. D+ ? 常用环境变量返回目录本小节介绍几个常用的环境变量(编译宏)。! K$ {' u9 Z' B- i- C
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的使用方式。
; \" `: q/ s# F6 ^! x新建Qt项目时,可以选择CMake作为构建工具:
, d& h j% i& D& i# u4 N5 ]: u6 C% T# b
( k- ~. A' \. z4 B8 [3 i. GQt新建项目使用CMake生成项目后,项目文件夹将出现CMakeLists.txt和CMakeLists.txt.user两个文件,熟悉的.pro文件没有了(CMakeLists.txt.user充当了Qt Creator工程文件的角色,其他IDE用不到,可删除)。
3 Q3 ]$ j) m$ E) G: t4 h但需要注意的是,此时Qt Creator中编译项目是没问题的,但是在CLion/VS Code中打开,或者生成Visual Studio用的.sln文件会有问题,因为CMake无法检测到Qt是否安装及其安装路径。
- C' r5 M2 w. O5 p解决办法便是在 project 指令后增加如下指令告知Qt的安装位置:
' n7 b5 p2 q0 W) o5 m. Z# 具体路径请根据自身情况替换
; f1 b J6 h1 d4 i" {* Rset(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")3 s& Y8 Y1 |6 K0 O
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")! ]7 d2 R2 t7 e+ ~. X. C0 d
然后再次运行 cmake 指令或者使用CMake GUI重新运行,构建文件夹下便能正常生成.sln项目文件。
6 L) ~+ h$ U9 `VS中编译好后,运行时会提示无法找到Qt相关的dll导致程序不能正常运行。解决办法包括:( Q" v6 p @: ]7 P
1. 设置VS选项,将Qt的dll路径包含进去;
& g! Y$ f M0 H( K: r 2. 将Qt相关dll拷贝到编译输出文件夹;
6 c3 M x0 D% u( O 3. 设置CMake,使其能自动复制所需要的dll。
5 S1 @8 w6 h, a @% C% ^( t N% Z这里介绍第三种方式,原理是借助Qt自带的windeployqt.exe程序自动部署程序所需dll到目标文件夹。具体操作为,在项目根目录的CMakeLists.txt最后添加部署dll的指令:1 `4 j- E- N1 @/ K" v& _& _9 i
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
) v* y% s/ J4 Q0 I. {6 Ffunction(windeployqt target). G9 P5 }" c& f! S9 E; D! E. j6 r
# POST_BUILD step
1 b3 G' ]* w, O) X: Y) O& `# - after build, we have a bin/lib for analyzing qt dependencies
4 P7 v! H- ~" J$ P, `0 r# - we run windeployqt on target and deploy Qt libs! Q8 V( m$ C6 y% F) \" l
add_custom_command(TARGET ${target} POST_BUILD/ U0 ?9 j% V( P* I9 o' }3 I
COMMAND "${QT_BIN_PATH}/windeployqt.exe"
- z2 z( V4 I; Q! u* n* n/ F--verbose 1/ w( \ B0 x3 }
#--release # uncomment this line if built with Release6 y6 q$ c: W# O9 Q9 g( T [
#--no-svg, E" N# l9 `+ D& ~; V
#--no-angle
7 Y' l; b, r7 e! C. F4 |#--no-opengl
6 s% w7 m/ B! a% X#--no-opengl-sw" i5 c# _& Y' j, i7 A0 E6 B
#--no-compiler-runtime
2 e1 ^" A# A! G2 g q! E#--no-system-d3d-compiler
; Z7 H" n u: w, t4 ~6 I+ W* P& W; |- @\"$\"
- s3 K/ d) ]6 n, R; ~; l' ~% Q4 MCOMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ...". e9 k, i% s5 }6 C5 ?
)
! d# V9 q- i" a3 yendfunction()5 u+ g3 m6 T: c
if (WIN32)
6 T$ O9 v5 ]7 J windeployqt(${PROJECT_NAME})
2 h" p8 H' |& ?, @ K: D. fendif()最后,转换成VS项目时,默认是Console项目,运行时会有cmd窗口。一个解决办法是在生成可执行文件时设置目标为 WIN32:
8 _' o# Q5 `" ^$ C6 _add_executable(${PROJECT_NAME} WIN32 xxxx)
4 X3 v5 H d+ v: {" |' C 一个完整的Qt 5项目CMakeLists.txt返回目录以下是一个适用于Windows平台的Qt 5项目完整CMakeLists.txt,实际使用时请替换名字和Qt 5安装路径等:) `% D! W1 Q. n% N* Q
cmake_minimum_required(VERSION 3.7)
4 I S7 }* e' G8 t- m; M, w# 请将myproject改成实际的应用名字
- v4 y1 J( l- v4 ^1 Rproject(myproject LANGUAGES CXX)
7 `3 Q% x% \% P- }- A" b4 U- a' i# Vset(CMAKE_INCLUDE_CURRENT_DIR ON)
3 w$ q3 O' E9 A3 E* e) r L, I9 ]& Q# 请更改为实际的Qt安装目录
. V1 G* r$ O; ?! F8 ]! s( tset(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")
0 g; `6 S" B! ]0 b5 p7 _- W2 l+ Lset(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")5 p; l8 L) q/ F
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
8 ~8 z* S+ t+ a! Uset(CMAKE_AUTOUIC ON)7 T$ \; ~3 F! P V/ F5 w9 ]
set(CMAKE_AUTOMOC ON); }% h* i4 l7 \! e2 U
set(CMAKE_AUTORCC ON)
# o" `: k, E/ lset(CMAKE_CXX_STANDARD 11)) N) C$ U: Y/ M1 S, v& [7 H
set(CMAKE_CXX_STANDARD_REQUIRED ON)" Q/ G3 x6 m' B$ `5 R8 t
find_package(Qt5 COMPONENTS Widgets REQUIRED): c' D; O) m6 n+ i4 [1 r& b
# 默认Release构建' M4 N* y' h- N$ [
if (NOT CMAKE_BUILD_TYPE)
# [1 L+ \7 ^. C$ M set( CMAKE_BUILD_TYPE "Release" )& U% \$ D& Z& a* I
endif()1 g5 q4 {1 X0 V" k
message("build type: ${CMAKE_BUILD_TYPE}")" q! ? D% X' R$ x% H2 X
# 按照自己的项目结构添加文件
& }5 e' K0 C1 x$ j0 n# 也可使用file/aux_source_directory批量引入,注意不要引入自动生成的文件!
7 O9 [+ G4 O! N+ c. M* B- O& Eadd_executable(${PROJECT_NAME} WIN32
: u/ g' ?; Q; S main.cpp
6 ] D. O3 @ `0 B' C6 m% t# L* c5 D$ [ mainwindow.cpp
( ?8 V4 I5 W" B9 D* M mainwindow.h
) W8 T1 ]0 \% @# s/ y# e)* L4 X$ ~- D3 w: o- ` f
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)
* \5 o. @! S# _ p8 p) gfunction(windeployqt target). W y# M3 B b1 M
# POST_BUILD step
+ {$ u [, i: ?; G; N& m0 g! zadd_custom_command(TARGET ${target} POST_BUILD
$ h" P Y) z% M2 @* O! FCOMMAND "${QT_BIN_PATH}/windeployqt.exe": Y3 b: j l6 _+ T' H* ?+ H/ W) e
--verbose 1
c" F8 A: P+ ^0 E& [3 X( L1 M#--release
- f" `# d% [3 w' E1 E& n) t#--no-svg6 v( U' Z- W( U8 \( \& g
#--no-angle
. |% g" x$ n, K% U& L8 P' B#--no-opengl
" ~% o( I+ Q7 m% d7 C#--no-opengl-sw1 D) \2 g) b! n- F* Q b3 }8 K
#--no-compiler-runtime
! E" j( n- ~* [4 C; `#--no-system-d3d-compiler
( c( Z% p5 _; I$ }% U: z\"$\"# q" |* _2 g, m4 M* r1 @) q+ i
COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."/ h5 G8 E2 G. P+ \$ w0 V
)
" |3 M3 p* z0 E+ {endfunction()" w! w& e8 A, h6 Y# Q: R
if (WIN32)9 W C- U& V5 @# l- u. o! b+ h
windeployqt(${PROJECT_NAME})9 J, H8 R% J9 g$ I* r2 `! U% T2 j
endif()
" b4 q' N6 Z* s: ]& P9 ]* D````通过上面的配置,我们的Qt项目既可在Qt Creator中正常编译运行,也可在CLion/Visual Studio中正常编译运行而 无需安装Qt插件。4 |& u0 D" Y" p. d. X* O
参考返回目录1. CMake官网
9 Z- ]3 u# X# G0 i, q2. CMake教程
' F5 O+ t+ `6 }( M" Q3 [3. CMake FAQ( @* I' K, I# L$ Q# ]% k
4. CMake指定编译器, v: K! e6 z& _" x$ v/ d2 | r
AD:【国外VPS推荐】 搬瓦工三网回程CN2 GIA VPS,季付46.87$打赏赞(3) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|