|
|
本文目录CMake简介CMake命令CMake常见指令常用环境变量Qt应用示例一个完整的Qt 5项目CMakeLists.txt参考CMake是一个跨平台、开源的构建工具,在C/C++项目中有广泛应用。本文首先介绍CMake及常用指令,并结合工作时需要用到的Qt 5,给出一个完整的CMake项目配置。5 Z# D8 ?3 `. i4 D" j
CMake简介返回目录CMake如其名”Cross-platform Make”,是一个 跨平台、开源 的构建工具。与make不同,CMake并不直接构建软件,而是生成用于构建的Makefile、.sln等工程文件,相当于高阶构建工具。
+ |* x& H. i* x8 w- h/ |* h- [与另一构建工具Automake相比,CMake使用上更方便,支持更多的编译套件(Ninja、VS等)。许多编辑器和IDE,如VS Code(宇宙第一编辑器/IDE)、Clion、Visual Studio等都内置了对CMake的支持。特别的,CMake已经是QT 6的默认构建工具,官方给出从qmake迁移的理由是CMake成熟稳定、用户基数大生态完善。因此,对于需要跨平台编译运行的C/C++项目,很推荐学习和使用CMake作为构建工具,能方便的转换成各种IDE项目,团队成员无需切换编辑器/IDE即可工作。& I9 {+ N `, _6 |
值得一提的是,CMake由Kitware公司开发和维护,VTK和ParaView等知名开源产品均出自该公司。从这方面看,CMake也算出身名门,因此能很快流行开来。
! |7 P4 c& e1 ^3 _ CMake命令返回目录CMake基于CMakeLists.txt文件来生成对应目标(generator)的构建文件,一个标准的CMake项目构建操作为(命令行方式):; C7 y% e- d3 t4 D7 h% S+ v/ G
cd PROJECT_DIR
3 ^% \! O+ l9 i6 Pcmake
, J% Y- x" W" \" Kmake TARGET或者使用用CMake GUI:5 P6 e8 s6 t" Y' @, x" l$ s
n v" ^. l% G
6 l& b4 V& ?5 f0 gCMake-GUI操作示意图然后使用VS打开生成的.sln项目,即可编译、运行和调试项目。0 a) ~& v3 }, z- U, {
Linux/Unix/MacOS平台上,CMake默认生成标准的makefile;Windows平台上则会检测Visual Studio版本,生成对应的VS .sln项目工程文件(在MSYS/Cygwin/WSL环境下执行除外)。可以使用 -G 选项切换生成目标,例如生成Ninja构建文件:7 j1 q7 [* _; X
cmake . -G Ninja0 H4 o9 j* B1 V$ o, L3 @2 m6 l
ninja TARGETCMake一个非常棒的特性是“外部构建”(out-of-source build),即支持在源码目录外构建。由于这个特性,以及CMake生成的makefile没有clean命令,一般来说都推荐在单独的build目录中构建:
' g$ d% H( S$ E9 s. ?4 p0 Jmkdir -p build
- J! U# C0 d4 m* ~cd $_
% M) f6 C7 O3 I( {cmake ..
+ Y: _4 t. V5 J: e: qmake TARGET -j4如果使用CMake GUI,Browse Build时请选择单独的构建目录。
, d6 _1 z$ R) A6 I命令行方式下编译Debug/Release版本、传递C++编译参数,请使用 -D 选项,例如:
& k; F8 b4 Y5 E3 ?* p+ A9 u# ?cmake .. -DCMAKE_BUILD_TYPE=Release
2 k4 j, K% h# S6 j3 Nmake TARGET -j4一些内置的宏定义参数可参考下文的环境变量。
- x1 T! [3 k1 \' y" L$ i7 X6 B如果是生成VS项目,则只需在VS中选择构建版本、设置编译和链接参数即可。, L+ \5 F$ z' Q. R
CMake常见指令返回目录CMake基于CMakeLists.txt文件生成项目构建文件,因此编写CMakeLists.txt文件是CMake项目的核心。本小节介绍一些用在CMakeLists.txt文件中的常用指令。
* I: M4 V& x2 H- ZCMakeLists.txt 使用 # 作为注释,# 所在行后续字符均作为注释被忽略8 ], J3 n" X2 M# D
cmake_minimum_required一般这条指令出现在文件的最前面,用来指定项目支持的最低版本。对于Qt 5项目,建议为:cmake_minimum_required(VERSION 3.7)。
: a- E1 D3 [& \. M1 P% B3 uproject指定项目名称及属性。C/C++项目的建议值为:project(项目名称 C CXX)。2 }* B, p# Q. G# {/ _
set定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。
2 l; d' X8 h! `, e# `9 t8 xif…else[if]…endif条件控制语句,注意指令后的括号不可省略:, i* w1 H+ B7 E. y
if (WIN32)' n$ \9 c: J2 _4 ?7 @& U2 b' O
xxxx! Y+ I1 |1 D2 {
else() # 括号不可省略( n* d) U+ L) X* W. `( t, W
xxxx
5 [/ i9 V; @# e# U: O6 |endif()
X- j4 y0 O2 e' b( _# Vfind_package查找指定模块,例如OpenMP。Qt 5项目一般需要:find_package(Qt5 COMPONENTS Widgets REQUIRED)。
) \- Q% A3 T: M& g) _# finclude_directories添加头文件include路径,一个更推荐使用的指令是 target_include_directories,其不污染后续目标的include路径,且能精细控制是否暴露依赖的包含路径。但是 target_include_directories 需要CMake 3.13 版本才支持,在Visual Studio 2017中使用会有问题。
) U1 \5 g1 C# V0 O8 ` link_directories设置链接库的路径,更推荐的指令是 target_link_directories,理由见 include_directories。 l/ `/ M- V% ]; U
aux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。* k* H C/ H: @
filefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到SRC变量中:file(GLOB_RECURSE SRC "src/*.cpp" "src/*/*.cpp")。" M" s, \9 e j+ m$ G6 k" y" R
相对于把每个需要编译的文件添加到CMakeLists.txt中,aux_source_directory 和 file 等指令可方便的引入多个文件,但其弊端之一是CMake不能感知文件变化。当新增文件、文件被删除、重命名时需刷新CMake缓存才能被应用到项目中。" ~$ ?3 }: C9 \# |4 e+ m
find_library查找指定库的路径并保存到变量中。 M7 Q% [" w o) u: H! U+ x
add_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。
1 Z9 ]3 [; P& yadd_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。
6 x/ E, Y3 `& L& q: E7 K, L) Vadd_executable构建可执行程序,一般项目的主CMakeLists.txt中会有这条指令。& I; i% n8 P1 f' W& r5 w
add_library构建动态或静态库,一般存在于子目录或者库的CMakeLists.txt文件中。
: @3 X3 Q# N, t0 V' d: @) L, P umessage可在cmake构建时输出信息。3 T& L H# M; T7 b# }
CMakeLists.txt文件中指令不区分大小写,但一般来说同一个文件中指令应保持大小写风格一致。
+ _% ]3 d# N9 N7 M* F, A. b更多指令可参考 CMake官方文档。4 W, A, P) C. t9 Q
常用环境变量返回目录本小节介绍几个常用的环境变量(编译宏)。
& v' g, f% f1 B yCMAKE_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 w4 w) ]/ |4 F* ^7 u' @- C
新建Qt项目时,可以选择CMake作为构建工具:! L6 l7 C# D( [1 J6 |( M
9 F) l( M3 y# |0 f) g& @
' m) l, [; N |: v9 FQt新建项目使用CMake生成项目后,项目文件夹将出现CMakeLists.txt和CMakeLists.txt.user两个文件,熟悉的.pro文件没有了(CMakeLists.txt.user充当了Qt Creator工程文件的角色,其他IDE用不到,可删除)。4 a o ~4 P9 q* t7 c' o" V5 i
但需要注意的是,此时Qt Creator中编译项目是没问题的,但是在CLion/VS Code中打开,或者生成Visual Studio用的.sln文件会有问题,因为CMake无法检测到Qt是否安装及其安装路径。
0 c/ k7 r" M5 k: E# p解决办法便是在 project 指令后增加如下指令告知Qt的安装位置:/ Q& U6 `" v: A: z
# 具体路径请根据自身情况替换% d/ P5 [* N9 T. Z3 L
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64") ^& }5 t9 z3 T% [8 Y' ]
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")8 ]0 W; |2 B S6 z7 \9 g
然后再次运行 cmake 指令或者使用CMake GUI重新运行,构建文件夹下便能正常生成.sln项目文件。
J" s* l1 B, f' [VS中编译好后,运行时会提示无法找到Qt相关的dll导致程序不能正常运行。解决办法包括:2 H' C9 ?0 Q2 \8 r
1. 设置VS选项,将Qt的dll路径包含进去;$ S3 B" N) b. H
2. 将Qt相关dll拷贝到编译输出文件夹;
. k% X8 E' ?! K# \: w J 3. 设置CMake,使其能自动复制所需要的dll。
9 Y Y, z4 J- w; H: z这里介绍第三种方式,原理是借助Qt自带的windeployqt.exe程序自动部署程序所需dll到目标文件夹。具体操作为,在项目根目录的CMakeLists.txt最后添加部署dll的指令:
w9 s2 R: S9 l# }. @$ t# nset(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
- [0 y3 {( p; I& u2 y% Bfunction(windeployqt target)
* d3 ]* R0 N4 P, N( b0 X# POST_BUILD step
6 ?- u* Z) h* `+ k# - after build, we have a bin/lib for analyzing qt dependencies- q- a( W4 {4 A' i' P% ]
# - we run windeployqt on target and deploy Qt libs9 O/ @9 Z2 M* V
add_custom_command(TARGET ${target} POST_BUILD6 m" p h' B2 @% e" K/ p
COMMAND "${QT_BIN_PATH}/windeployqt.exe"' B, g( C: Q0 x6 V3 o6 f2 Z
--verbose 1
2 T0 _' x. g1 A9 H0 Z8 s; z- a#--release # uncomment this line if built with Release
) |: }! z9 W- h9 O/ X#--no-svg
9 k* b, M* w7 H; V; \, l. o#--no-angle9 u. z6 X5 t8 t; M" j
#--no-opengl
5 s v- O) j5 S0 J#--no-opengl-sw
6 j" e! B" f9 C3 z0 U1 I3 t#--no-compiler-runtime
; g9 y; a) H C#--no-system-d3d-compiler& R4 L% D( i1 f! }/ ~+ f9 y/ ~
\"$\"
+ e6 y$ \7 C/ N. cCOMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."
" X" d6 l5 n6 X2 X)
! M+ B. a# G0 s- Mendfunction()6 W1 x, g( R) t( y5 C! Q# x- u
if (WIN32)+ M& ?$ _. [6 m% n1 W! y. a) k
windeployqt(${PROJECT_NAME})& p0 T) G- n, u/ y6 \7 G6 l7 n1 c
endif()最后,转换成VS项目时,默认是Console项目,运行时会有cmd窗口。一个解决办法是在生成可执行文件时设置目标为 WIN32:
9 z3 V8 L2 ~# H) O: K2 [add_executable(${PROJECT_NAME} WIN32 xxxx)
c4 v, Z6 L( N 一个完整的Qt 5项目CMakeLists.txt返回目录以下是一个适用于Windows平台的Qt 5项目完整CMakeLists.txt,实际使用时请替换名字和Qt 5安装路径等:
+ o" {' O8 I0 I: s: Bcmake_minimum_required(VERSION 3.7)5 S- R/ W% d# }0 k0 h
# 请将myproject改成实际的应用名字/ U* ?) i: o/ ^; o: U0 u2 H" i
project(myproject LANGUAGES CXX)8 c" F9 A! `* X3 @
set(CMAKE_INCLUDE_CURRENT_DIR ON)
$ D2 u8 g5 R$ J* \& }1 ~& c# 请更改为实际的Qt安装目录
6 b4 m5 w/ I0 @- o5 O7 iset(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")( k$ M0 f1 T: g# T
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")
- `! B% g+ }6 m% _. L1 Kset(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
. Y5 B9 J8 J3 o3 e9 xset(CMAKE_AUTOUIC ON)
# X. k& {8 L% B, x F7 Q; oset(CMAKE_AUTOMOC ON)( e; N7 r5 |/ F" j2 t
set(CMAKE_AUTORCC ON)
7 d8 ~8 E! x5 J+ F# Kset(CMAKE_CXX_STANDARD 11)7 v! t, [& h4 O j# \
set(CMAKE_CXX_STANDARD_REQUIRED ON)
" Z! I7 Q1 m0 d, {+ K p' Lfind_package(Qt5 COMPONENTS Widgets REQUIRED)+ O, z( `& i/ ]; d; D% |
# 默认Release构建
" `' j3 G7 z1 t1 Tif (NOT CMAKE_BUILD_TYPE)
: z" t3 |# o% [. a2 I, K1 Z set( CMAKE_BUILD_TYPE "Release" )/ Q, p. L. G8 [; L1 f, `
endif(). d+ q5 V' o! g* g$ r4 U4 S8 g
message("build type: ${CMAKE_BUILD_TYPE}")
( C; m( W% A1 @. f2 v$ q2 |9 Q/ {# 按照自己的项目结构添加文件
q) U4 c: t9 s5 x/ l# 也可使用file/aux_source_directory批量引入,注意不要引入自动生成的文件!
* E0 o8 t0 | N8 gadd_executable(${PROJECT_NAME} WIN32
L( _8 T9 Z8 z f* g7 N main.cpp9 F* y! M8 s/ \! R/ }: ]
mainwindow.cpp
C- g8 L2 t9 m/ x0 C! W mainwindow.h
$ s+ H' y/ w7 T* F( f$ U)
; N) T# ~; ^/ Dtarget_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets), ^! L7 \+ s! E" F$ r! H
function(windeployqt target)
3 o- s; V9 T+ H' k: [0 y+ ~' O# POST_BUILD step+ c. L! I0 f& _3 _
add_custom_command(TARGET ${target} POST_BUILD
: d/ Y) W( q) `: _3 u9 aCOMMAND "${QT_BIN_PATH}/windeployqt.exe"
- @1 E3 M3 X5 E! N--verbose 1& ]% }* d' F0 U, m9 E1 y" ~
#--release
0 \- \6 o! v5 B/ \0 K' m3 t#--no-svg
1 y9 }) Z9 S8 i& |5 _" e9 M( P9 B4 M& U#--no-angle. J6 D0 P6 ~% r. ~3 ? m) h
#--no-opengl) ?" f) ?3 I/ L5 @" P
#--no-opengl-sw/ N% }* J- p; F
#--no-compiler-runtime
9 w! S. G+ Q! U) J#--no-system-d3d-compiler
( m3 J% I$ {- w- Z' w+ @9 i, A' P\"$\"
$ Q4 \& s* K% @# H( ]4 {% d yCOMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."& V5 X7 Q7 S) O" l# i; q% l
)$ q) a) R5 E: q$ i: w2 ?8 D9 ~
endfunction()
$ d$ |3 _( _5 z! F% J( @if (WIN32)' c: E1 y0 ^( U t
windeployqt(${PROJECT_NAME})
% t1 [8 X; R: ?& R( lendif()
$ X! T" t4 h0 r3 S8 [4 ]# p k````通过上面的配置,我们的Qt项目既可在Qt Creator中正常编译运行,也可在CLion/Visual Studio中正常编译运行而 无需安装Qt插件。
* ?7 p) x6 C, _8 T7 W2 H5 W; L: m 参考返回目录1. CMake官网
9 Z8 L! ~* {, l2. CMake教程
" `- y$ w7 U( s; J3. CMake FAQ
" g$ o; L' {) v" e2 `4. CMake指定编译器
5 W9 G; y2 X, ` A: VAD:【国外VPS推荐】 搬瓦工三网回程CN2 GIA VPS,季付46.87$打赏赞(3) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|