|
本文目录CMake简介CMake命令CMake常见指令常用环境变量Qt应用示例一个完整的Qt 5项目CMakeLists.txt参考CMake是一个跨平台、开源的构建工具,在C/C++项目中有广泛应用。本文首先介绍CMake及常用指令,并结合工作时需要用到的Qt 5,给出一个完整的CMake项目配置。2 S/ P: t7 `# F9 w- N2 ^
CMake简介返回目录CMake如其名”Cross-platform Make”,是一个 跨平台、开源 的构建工具。与make不同,CMake并不直接构建软件,而是生成用于构建的Makefile、.sln等工程文件,相当于高阶构建工具。8 v5 x( f) a+ k" ^7 q
与另一构建工具Automake相比,CMake使用上更方便,支持更多的编译套件(Ninja、VS等)。许多编辑器和IDE,如VS Code(宇宙第一编辑器/IDE)、Clion、Visual Studio等都内置了对CMake的支持。特别的,CMake已经是QT 6的默认构建工具,官方给出从qmake迁移的理由是CMake成熟稳定、用户基数大生态完善。因此,对于需要跨平台编译运行的C/C++项目,很推荐学习和使用CMake作为构建工具,能方便的转换成各种IDE项目,团队成员无需切换编辑器/IDE即可工作。5 d, M3 u9 H7 L# ]" w5 O& X
值得一提的是,CMake由Kitware公司开发和维护,VTK和ParaView等知名开源产品均出自该公司。从这方面看,CMake也算出身名门,因此能很快流行开来。5 z5 b( ]! x' b) v
CMake命令返回目录CMake基于CMakeLists.txt文件来生成对应目标(generator)的构建文件,一个标准的CMake项目构建操作为(命令行方式):1 H9 \; n# k1 L/ F' T" f) U
cd PROJECT_DIR. A4 z# G; b" I5 D P+ W
cmake
: U5 g+ b0 l5 l1 D$ L+ y- B% @make TARGET或者使用用CMake GUI:8 l: t G4 {) ]2 ]) `8 F
$ Z6 l' ~0 A0 }0 Z8 b+ T8 H# y3 m& B) c- v5 O K# M/ g
CMake-GUI操作示意图然后使用VS打开生成的.sln项目,即可编译、运行和调试项目。- |+ F9 o6 J0 @9 P$ r6 d
Linux/Unix/MacOS平台上,CMake默认生成标准的makefile;Windows平台上则会检测Visual Studio版本,生成对应的VS .sln项目工程文件(在MSYS/Cygwin/WSL环境下执行除外)。可以使用 -G 选项切换生成目标,例如生成Ninja构建文件:3 [' n3 P& E+ e3 x( ]
cmake . -G Ninja
5 [) H9 C0 x! x5 j' Lninja TARGETCMake一个非常棒的特性是“外部构建”(out-of-source build),即支持在源码目录外构建。由于这个特性,以及CMake生成的makefile没有clean命令,一般来说都推荐在单独的build目录中构建:6 X' Y7 J- R3 {+ T: A
mkdir -p build! Q+ `. r, e- S0 l7 {
cd $_+ r4 j( c2 [5 W& ]
cmake ..! F# A5 M' ?8 G* I! f5 b+ a K
make TARGET -j4如果使用CMake GUI,Browse Build时请选择单独的构建目录。2 c$ A8 h( Z. l! f, }
命令行方式下编译Debug/Release版本、传递C++编译参数,请使用 -D 选项,例如:/ k$ Y$ X$ c! ^6 e) b
cmake .. -DCMAKE_BUILD_TYPE=Release- w9 j. Z" Y6 y# T
make TARGET -j4一些内置的宏定义参数可参考下文的环境变量。: x% Q! [7 D. g/ X
如果是生成VS项目,则只需在VS中选择构建版本、设置编译和链接参数即可。
W. z6 h# ?+ e% \5 ` CMake常见指令返回目录CMake基于CMakeLists.txt文件生成项目构建文件,因此编写CMakeLists.txt文件是CMake项目的核心。本小节介绍一些用在CMakeLists.txt文件中的常用指令。; k! q, g: T) q5 A0 k
CMakeLists.txt 使用 # 作为注释,# 所在行后续字符均作为注释被忽略: v0 t- @; s( \+ J4 A p
cmake_minimum_required一般这条指令出现在文件的最前面,用来指定项目支持的最低版本。对于Qt 5项目,建议为:cmake_minimum_required(VERSION 3.7)。- B1 ?. \6 V* x( w
project指定项目名称及属性。C/C++项目的建议值为:project(项目名称 C CXX)。
4 [) o$ a J6 r8 xset定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。
" N! _: m2 G1 G6 vif…else[if]…endif条件控制语句,注意指令后的括号不可省略:
/ r. t) x( t- @( Z% B8 ]" r" G. D5 pif (WIN32)1 S% B4 [+ h% J. D0 ]# [4 H
xxxx
' y4 o2 w6 Q. t2 x1 Delse() # 括号不可省略
6 N) Z8 e/ G1 `2 L: R/ X: _xxxx
0 ?2 n% c- g9 e, s+ G# x* xendif()
2 G2 P; U8 T" j6 Nfind_package查找指定模块,例如OpenMP。Qt 5项目一般需要:find_package(Qt5 COMPONENTS Widgets REQUIRED)。$ v9 R7 L+ m* h9 n* c' H; T
include_directories添加头文件include路径,一个更推荐使用的指令是 target_include_directories,其不污染后续目标的include路径,且能精细控制是否暴露依赖的包含路径。但是 target_include_directories 需要CMake 3.13 版本才支持,在Visual Studio 2017中使用会有问题。2 X( M- M6 N+ W$ q
link_directories设置链接库的路径,更推荐的指令是 target_link_directories,理由见 include_directories。
- I1 W; M; Y+ h- E; f) u' F; Baux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。
s9 w5 S5 {3 n y" ]4 j3 x( B2 p, Qfilefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到SRC变量中:file(GLOB_RECURSE SRC "src/*.cpp" "src/*/*.cpp")。
% B% c2 s& ?) r相对于把每个需要编译的文件添加到CMakeLists.txt中,aux_source_directory 和 file 等指令可方便的引入多个文件,但其弊端之一是CMake不能感知文件变化。当新增文件、文件被删除、重命名时需刷新CMake缓存才能被应用到项目中。
9 _& o) Q+ X( rfind_library查找指定库的路径并保存到变量中。
2 r5 w! d3 L* Nadd_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。: R3 Y. {5 ^* h
add_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。
2 o T. g7 |; S* r" J& \4 Yadd_executable构建可执行程序,一般项目的主CMakeLists.txt中会有这条指令。& y6 Q& a! h1 b- L, u `$ ?0 K
add_library构建动态或静态库,一般存在于子目录或者库的CMakeLists.txt文件中。
' T! e, T3 |. i! N: I. @message可在cmake构建时输出信息。
5 Z/ ~ y- t) g' e2 j5 K% E, a. H/ @CMakeLists.txt文件中指令不区分大小写,但一般来说同一个文件中指令应保持大小写风格一致。. q% {! X6 ]' `. C
更多指令可参考 CMake官方文档。
9 X6 v5 c2 V& V0 l* A" X 常用环境变量返回目录本小节介绍几个常用的环境变量(编译宏)。
. q/ L) d; w8 V, B& @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的使用方式。2 }9 q( ]: _ f9 A
新建Qt项目时,可以选择CMake作为构建工具:
; @6 `5 f- v! U' E8 r, P; M) Q5 b$ R2 E; Y
+ \6 Q5 S1 M: m. A. X4 t" e% D8 |0 y
Qt新建项目使用CMake生成项目后,项目文件夹将出现CMakeLists.txt和CMakeLists.txt.user两个文件,熟悉的.pro文件没有了(CMakeLists.txt.user充当了Qt Creator工程文件的角色,其他IDE用不到,可删除)。
* v: U! d6 R* R) R( V但需要注意的是,此时Qt Creator中编译项目是没问题的,但是在CLion/VS Code中打开,或者生成Visual Studio用的.sln文件会有问题,因为CMake无法检测到Qt是否安装及其安装路径。
9 Z7 z$ s0 H8 Z解决办法便是在 project 指令后增加如下指令告知Qt的安装位置:5 F. r9 b0 ?8 W# Q, m
# 具体路径请根据自身情况替换- b4 P# W" E v) h2 s8 m
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")
" I) w/ e# s4 |6 m% Vset(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake") @6 m, W) ^* I# R8 o
然后再次运行 cmake 指令或者使用CMake GUI重新运行,构建文件夹下便能正常生成.sln项目文件。
- `; ]4 N/ K' `' K1 ?5 ?3 JVS中编译好后,运行时会提示无法找到Qt相关的dll导致程序不能正常运行。解决办法包括:$ ?4 s) h5 ~7 A0 I) X- [8 E8 f
1. 设置VS选项,将Qt的dll路径包含进去;# o* Q, t1 d' Q) D# G& l
2. 将Qt相关dll拷贝到编译输出文件夹;; _$ r# \# {- \4 l5 S
3. 设置CMake,使其能自动复制所需要的dll。6 D W( K* B4 v3 a, _9 R
这里介绍第三种方式,原理是借助Qt自带的windeployqt.exe程序自动部署程序所需dll到目标文件夹。具体操作为,在项目根目录的CMakeLists.txt最后添加部署dll的指令:+ P9 y( j! o/ T# k
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")% s1 T& q. l$ |' |- F) w( ~
function(windeployqt target)+ c$ h2 {0 Y1 | a8 H1 u. _% c- U
# POST_BUILD step
s: u0 o5 Y+ N9 l# - after build, we have a bin/lib for analyzing qt dependencies
7 L3 J0 R: [- w, e# - we run windeployqt on target and deploy Qt libs
, b5 q( S- J4 c. [$ J; Padd_custom_command(TARGET ${target} POST_BUILD
9 |; z) a' c* b8 r+ r2 bCOMMAND "${QT_BIN_PATH}/windeployqt.exe"8 t+ |# \ e% E, }5 h
--verbose 1
8 w; P: j2 O1 v! y#--release # uncomment this line if built with Release9 e. u7 @% G2 t4 }, {
#--no-svg: {4 `1 o* G+ t
#--no-angle: e* w$ D( [; E# `! F
#--no-opengl& C( L* ` d: A' E/ v
#--no-opengl-sw
5 S) h. A0 b+ z& Q8 m#--no-compiler-runtime' x: X4 O5 g! ^& B+ }5 `
#--no-system-d3d-compiler
% L/ h9 H. I6 m4 c2 s\"$\"/ ~% f6 s' f/ R$ o, L
COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."
7 Z* y4 D* I% A0 l% \4 K)
f* E9 c, t+ h4 @# m3 l8 Iendfunction()
0 K1 ~* G2 k5 `* w( e) Fif (WIN32). o$ o9 U% A" z! F6 t# S# J' \& o
windeployqt(${PROJECT_NAME})) u6 l8 B! w" [2 ^, n
endif()最后,转换成VS项目时,默认是Console项目,运行时会有cmd窗口。一个解决办法是在生成可执行文件时设置目标为 WIN32:. c" c( \$ f5 @
add_executable(${PROJECT_NAME} WIN32 xxxx) W. }; \# k9 s0 h9 J7 d
一个完整的Qt 5项目CMakeLists.txt返回目录以下是一个适用于Windows平台的Qt 5项目完整CMakeLists.txt,实际使用时请替换名字和Qt 5安装路径等:
/ q4 v) p' y d6 D9 J- h" Jcmake_minimum_required(VERSION 3.7)- D4 P) u5 a7 H w
# 请将myproject改成实际的应用名字
3 P" K: @% }5 d6 ~+ H3 Nproject(myproject LANGUAGES CXX)* N. Q" F# {" T; C* A4 I# g" o
set(CMAKE_INCLUDE_CURRENT_DIR ON)' | ~# V* a9 z; I G0 r
# 请更改为实际的Qt安装目录, A) H4 x5 \, v4 z- n9 N
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")& w) X3 r& t/ v1 N
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")
2 A* r. k3 }( {set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")& Q" f* R% K- t8 i
set(CMAKE_AUTOUIC ON)
. [0 V! J& b& f4 r- A/ n/ Qset(CMAKE_AUTOMOC ON)1 x# i5 j7 y$ C6 z4 o2 Z
set(CMAKE_AUTORCC ON)
# W6 _! ]; U+ B8 L. Xset(CMAKE_CXX_STANDARD 11)- Y1 h3 a0 \* V9 p! K7 p2 ~: S
set(CMAKE_CXX_STANDARD_REQUIRED ON). F) @- Y8 t, |* Q
find_package(Qt5 COMPONENTS Widgets REQUIRED)) p. e: _( ~+ H3 |9 f7 H% r
# 默认Release构建
w% {, r% W( b3 |if (NOT CMAKE_BUILD_TYPE)
4 ~6 O8 {+ h& g3 ` set( CMAKE_BUILD_TYPE "Release" )0 l9 g' y8 F8 O
endif()
+ S: w7 [3 n jmessage("build type: ${CMAKE_BUILD_TYPE}")
% T# x+ J* {4 v2 F8 W# 按照自己的项目结构添加文件
+ Q, l+ }; P q' Z# 也可使用file/aux_source_directory批量引入,注意不要引入自动生成的文件!* n# p; R- h; R3 ~" K* Y
add_executable(${PROJECT_NAME} WIN32- {6 c7 U6 }$ s+ V; }1 U
main.cpp
v$ v t. ~% z- n9 y mainwindow.cpp# |- X1 w k E( v+ Z3 r
mainwindow.h% G: t V, g. ?+ E8 k8 w
)
, B/ g, v/ [% G6 P M* d. f7 rtarget_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)/ ~$ I2 `& b) p' t4 |& }
function(windeployqt target)7 N3 v' Q I2 o s+ G0 n. _" |
# POST_BUILD step4 M1 k' a. r% D; t% o1 h8 e% @
add_custom_command(TARGET ${target} POST_BUILD
3 {9 ~1 c3 X) m9 H! cCOMMAND "${QT_BIN_PATH}/windeployqt.exe"
- y' t! X' c) V. B--verbose 1& d( X3 y S3 Q* g
#--release ( H- p7 `/ n) J, h$ ~
#--no-svg4 v' Q' F% h+ N1 B3 Q0 Y
#--no-angle& T R9 w% Y( x2 G
#--no-opengl+ p/ c; B8 {. i( l6 j7 n: H$ T
#--no-opengl-sw3 F! _0 h# W' G$ v% \, I5 P5 u
#--no-compiler-runtime: ~0 _' W3 H( q* O0 L) S+ Z
#--no-system-d3d-compiler
- j% C3 D9 K- f2 h' S\"$\"8 e2 I* X. l$ v) v4 G7 s' R
COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."
3 x- K' w4 v$ u0 h9 P. {* z)0 v: ^( Q$ o" d% S+ G. w9 [6 }9 l
endfunction()
p! R$ F, b) q: Bif (WIN32)
3 C6 u2 { p" L; Z& x+ I& G windeployqt(${PROJECT_NAME})
: M. y7 {2 p* y8 s1 l3 S0 W" S, v0 rendif()
+ E, l+ }! I( ?6 T( y````通过上面的配置,我们的Qt项目既可在Qt Creator中正常编译运行,也可在CLion/Visual Studio中正常编译运行而 无需安装Qt插件。/ c7 T4 A' w# g) [8 ?- Q; g7 a1 R4 w
参考返回目录1. CMake官网
8 U. T+ F1 m8 S: N! X9 T, }2. CMake教程
) Y; x& P7 X+ A- |7 {3. CMake FAQ
+ x' m8 y9 r' u9 l& b5 J8 v1 a: S4. CMake指定编译器) B% p+ u2 Q- |- V: A0 n, s8 x
AD:【国外VPS推荐】 搬瓦工三网回程CN2 GIA VPS,季付46.87$打赏赞(3) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|