|
本文目录CMake简介CMake命令CMake常见指令常用环境变量Qt应用示例一个完整的Qt 5项目CMakeLists.txt参考CMake是一个跨平台、开源的构建工具,在C/C++项目中有广泛应用。本文首先介绍CMake及常用指令,并结合工作时需要用到的Qt 5,给出一个完整的CMake项目配置。
6 C3 ^1 J# X' \3 w# z) R) b CMake简介返回目录CMake如其名”Cross-platform Make”,是一个 跨平台、开源 的构建工具。与make不同,CMake并不直接构建软件,而是生成用于构建的Makefile、.sln等工程文件,相当于高阶构建工具。
/ C) T9 O) O- ~) E y5 Z8 |4 B与另一构建工具Automake相比,CMake使用上更方便,支持更多的编译套件(Ninja、VS等)。许多编辑器和IDE,如VS Code(宇宙第一编辑器/IDE)、Clion、Visual Studio等都内置了对CMake的支持。特别的,CMake已经是QT 6的默认构建工具,官方给出从qmake迁移的理由是CMake成熟稳定、用户基数大生态完善。因此,对于需要跨平台编译运行的C/C++项目,很推荐学习和使用CMake作为构建工具,能方便的转换成各种IDE项目,团队成员无需切换编辑器/IDE即可工作。8 j5 |, N2 Z$ c" X2 ?- N
值得一提的是,CMake由Kitware公司开发和维护,VTK和ParaView等知名开源产品均出自该公司。从这方面看,CMake也算出身名门,因此能很快流行开来。
# @0 y* F2 o/ B% A y. }6 `3 ` CMake命令返回目录CMake基于CMakeLists.txt文件来生成对应目标(generator)的构建文件,一个标准的CMake项目构建操作为(命令行方式):8 N# ]( r/ c8 J6 f6 g; H# P8 k
cd PROJECT_DIR& o% X4 Q6 y0 H8 j4 j/ O
cmake8 T/ A) e: `% ~5 D7 V
make TARGET或者使用用CMake GUI:) K( `! N0 j" b' W+ V" c/ s( @% c# A
1 X- K% @' X4 V* {+ s* j
; E! D6 F4 q7 {% ~5 k1 K
CMake-GUI操作示意图然后使用VS打开生成的.sln项目,即可编译、运行和调试项目。. ?0 v/ G; [% i% _, E8 ]6 s1 w
Linux/Unix/MacOS平台上,CMake默认生成标准的makefile;Windows平台上则会检测Visual Studio版本,生成对应的VS .sln项目工程文件(在MSYS/Cygwin/WSL环境下执行除外)。可以使用 -G 选项切换生成目标,例如生成Ninja构建文件:
! f% o! K+ V5 A; W6 S$ }, {cmake . -G Ninja
* ]' q# A& E' ]: B: c7 uninja TARGETCMake一个非常棒的特性是“外部构建”(out-of-source build),即支持在源码目录外构建。由于这个特性,以及CMake生成的makefile没有clean命令,一般来说都推荐在单独的build目录中构建:
/ I o. ~" c$ B* {8 s8 z; \& Lmkdir -p build
8 s$ p W. y. @' `3 u( X& Hcd $_( Q+ s3 J2 _ }6 j3 u- G3 Z
cmake ..1 |# Q u6 V- R& \ y
make TARGET -j4如果使用CMake GUI,Browse Build时请选择单独的构建目录。- p& ~$ H1 |+ L+ ]2 l
命令行方式下编译Debug/Release版本、传递C++编译参数,请使用 -D 选项,例如:, V, Y( K( J6 x
cmake .. -DCMAKE_BUILD_TYPE=Release0 n; C, p( M8 j* W6 q7 l/ }5 h X! D
make TARGET -j4一些内置的宏定义参数可参考下文的环境变量。
/ y3 B h% m8 R% I+ K如果是生成VS项目,则只需在VS中选择构建版本、设置编译和链接参数即可。. M+ y, w" {4 C" x" ~( \6 K
CMake常见指令返回目录CMake基于CMakeLists.txt文件生成项目构建文件,因此编写CMakeLists.txt文件是CMake项目的核心。本小节介绍一些用在CMakeLists.txt文件中的常用指令。: }& v1 N$ v3 }4 X7 O
CMakeLists.txt 使用 # 作为注释,# 所在行后续字符均作为注释被忽略) C6 q3 ^9 ]. ~: h) g, J
cmake_minimum_required一般这条指令出现在文件的最前面,用来指定项目支持的最低版本。对于Qt 5项目,建议为:cmake_minimum_required(VERSION 3.7)。
) O1 h+ h! q3 c* f6 ?' C6 _" Bproject指定项目名称及属性。C/C++项目的建议值为:project(项目名称 C CXX)。. m8 v( B3 a- a3 j3 q# B; v$ R0 Y
set定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。* N/ D7 g1 `' C$ p1 |# j
if…else[if]…endif条件控制语句,注意指令后的括号不可省略:! d' h7 y8 r. Y3 D
if (WIN32)1 h& C1 }4 s4 L9 n
xxxx! }: }& L7 U$ d6 N
else() # 括号不可省略* F" L+ `% X! f
xxxx
; {7 Y& Y" R) F5 \% }6 U- ]endif()
# _$ X+ T" z6 O0 Z, H$ ufind_package查找指定模块,例如OpenMP。Qt 5项目一般需要:find_package(Qt5 COMPONENTS Widgets REQUIRED)。
$ P0 L; l1 e& f/ Qinclude_directories添加头文件include路径,一个更推荐使用的指令是 target_include_directories,其不污染后续目标的include路径,且能精细控制是否暴露依赖的包含路径。但是 target_include_directories 需要CMake 3.13 版本才支持,在Visual Studio 2017中使用会有问题。
& R! ] V8 p/ S link_directories设置链接库的路径,更推荐的指令是 target_link_directories,理由见 include_directories。
' P& t f* j8 l c; c% @aux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。
2 y8 C, {- c O5 o( {$ C6 dfilefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到SRC变量中:file(GLOB_RECURSE SRC "src/*.cpp" "src/*/*.cpp")。
! O7 U2 L( u7 E! ?: O7 X相对于把每个需要编译的文件添加到CMakeLists.txt中,aux_source_directory 和 file 等指令可方便的引入多个文件,但其弊端之一是CMake不能感知文件变化。当新增文件、文件被删除、重命名时需刷新CMake缓存才能被应用到项目中。+ q# U7 F- N3 y! k
find_library查找指定库的路径并保存到变量中。
% j$ _5 ~5 \# y- S& {! d( @. `add_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。
+ X8 C) o- U' V* [# V4 z$ ?& t# Badd_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。
0 W5 u( m; p7 M" c- Uadd_executable构建可执行程序,一般项目的主CMakeLists.txt中会有这条指令。& c* g; A7 E( U; W" z4 C
add_library构建动态或静态库,一般存在于子目录或者库的CMakeLists.txt文件中。
$ O- V/ t- [0 Y1 g0 [0 t2 Hmessage可在cmake构建时输出信息。/ V* G4 Y, q. ^
CMakeLists.txt文件中指令不区分大小写,但一般来说同一个文件中指令应保持大小写风格一致。8 e% X3 A) j* J, Z W5 {
更多指令可参考 CMake官方文档。9 ~' y& y8 S5 k* a
常用环境变量返回目录本小节介绍几个常用的环境变量(编译宏)。
4 C7 \$ \; G1 r6 \! I xCMAKE_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 h. M k2 Y1 u8 q4 l# X新建Qt项目时,可以选择CMake作为构建工具:
8 _5 y7 C& ]( S2 S, m5 @0 c; t5 Z. O: V$ d* k# W5 N
3 G( n+ ]6 ~/ V7 j! PQt新建项目使用CMake生成项目后,项目文件夹将出现CMakeLists.txt和CMakeLists.txt.user两个文件,熟悉的.pro文件没有了(CMakeLists.txt.user充当了Qt Creator工程文件的角色,其他IDE用不到,可删除)。; L: |. P+ E! y8 {- q, N/ b
但需要注意的是,此时Qt Creator中编译项目是没问题的,但是在CLion/VS Code中打开,或者生成Visual Studio用的.sln文件会有问题,因为CMake无法检测到Qt是否安装及其安装路径。# C) Q% n; ~) ?; P
解决办法便是在 project 指令后增加如下指令告知Qt的安装位置:( K3 p j' E' G
# 具体路径请根据自身情况替换
Z' y/ X( A& O$ c% Z7 rset(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")
! i6 g l) G: `4 _5 hset(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")
$ a9 K2 z2 z$ {# h1 i然后再次运行 cmake 指令或者使用CMake GUI重新运行,构建文件夹下便能正常生成.sln项目文件。 c* W, ~( `* v
VS中编译好后,运行时会提示无法找到Qt相关的dll导致程序不能正常运行。解决办法包括:9 g6 a- y+ {+ x0 @* m9 C9 \
1. 设置VS选项,将Qt的dll路径包含进去;& e8 m* I3 C+ _0 `7 ?
2. 将Qt相关dll拷贝到编译输出文件夹;5 X/ K2 e( {7 R2 t
3. 设置CMake,使其能自动复制所需要的dll。; t/ a. V# F. w) E$ h8 H
这里介绍第三种方式,原理是借助Qt自带的windeployqt.exe程序自动部署程序所需dll到目标文件夹。具体操作为,在项目根目录的CMakeLists.txt最后添加部署dll的指令:2 e1 a/ d6 x/ F2 K+ L' v& E
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
# x0 }/ ^; J4 O; h9 Lfunction(windeployqt target)
8 B' g2 h; ~1 u7 i0 F7 _# POST_BUILD step
3 k& x$ P, O8 K- a. m: n* C |# - after build, we have a bin/lib for analyzing qt dependencies
: d; a0 w" o7 X4 g3 V2 i, F+ `# - we run windeployqt on target and deploy Qt libs$ s: o1 u- g( R. V9 Y
add_custom_command(TARGET ${target} POST_BUILD- _6 t, F- n, g1 K! b8 e4 k
COMMAND "${QT_BIN_PATH}/windeployqt.exe". M* g1 x9 K; A q% s/ a
--verbose 19 z: u6 y' p: ]# r4 [/ O8 D8 A
#--release # uncomment this line if built with Release
) `8 r& \0 o- b& T& }) l#--no-svg* i6 N/ l* N4 P7 E W6 s
#--no-angle+ C0 S( E; w! w* o' U- n
#--no-opengl
& W$ j6 o+ ?6 l7 ]/ _0 ?1 c#--no-opengl-sw& T. J+ ~; Z# L4 M, Z4 J
#--no-compiler-runtime( F& K- q+ r, c" g ^# T
#--no-system-d3d-compiler
- |( r2 V8 G. m9 p\"$\"
o' B8 h1 r7 ]. RCOMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."/ d5 y$ ]. j% j/ s
)- c- z: K& W7 s9 V9 K9 x
endfunction()- g" e1 l/ l/ A& p8 g! ]2 s
if (WIN32)# l0 j# H3 X4 j' P* F; A
windeployqt(${PROJECT_NAME})* x9 N1 S1 E) |
endif()最后,转换成VS项目时,默认是Console项目,运行时会有cmd窗口。一个解决办法是在生成可执行文件时设置目标为 WIN32:
7 `: k" {% A/ P @% L0 Radd_executable(${PROJECT_NAME} WIN32 xxxx)
, F$ {- R) |4 X& r! h1 w. ?* I 一个完整的Qt 5项目CMakeLists.txt返回目录以下是一个适用于Windows平台的Qt 5项目完整CMakeLists.txt,实际使用时请替换名字和Qt 5安装路径等:) G( |/ v9 j( D& d+ y1 S/ |
cmake_minimum_required(VERSION 3.7)
+ W4 @0 g" u7 V' M! i9 J# 请将myproject改成实际的应用名字: D- k8 r" G3 X. e
project(myproject LANGUAGES CXX)
$ R+ q) w( `2 fset(CMAKE_INCLUDE_CURRENT_DIR ON)% C0 z' `% H+ W& O3 r k
# 请更改为实际的Qt安装目录4 r6 _$ R3 Y1 S0 x1 ?
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")& x% F$ K1 l, \' g9 O7 d* T
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")1 x1 W( ?( w9 N- ~1 K) h" L+ R( z/ [
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin"): U, J2 z. K; @+ z$ Q
set(CMAKE_AUTOUIC ON)
+ L! K7 ~; P" |2 C$ bset(CMAKE_AUTOMOC ON)
6 {8 \( A/ [/ t4 L- Yset(CMAKE_AUTORCC ON): \4 I. d* J% |+ _# q
set(CMAKE_CXX_STANDARD 11)
! u& [3 C& ~1 R: V$ w6 cset(CMAKE_CXX_STANDARD_REQUIRED ON)) F% ` D; `; U, L. ~
find_package(Qt5 COMPONENTS Widgets REQUIRED), i2 x$ m; e2 \6 d
# 默认Release构建
0 C# p' V0 x) W; w" sif (NOT CMAKE_BUILD_TYPE)" |! T+ d$ N* x) Y' J
set( CMAKE_BUILD_TYPE "Release" )- }; W2 x5 F' x5 C; Z1 Q9 g- g
endif()
- x+ M1 @$ G; u* q! N: Z+ Smessage("build type: ${CMAKE_BUILD_TYPE}")2 Y6 ~6 l1 K. f5 I' P
# 按照自己的项目结构添加文件2 ?2 b. p: O- {3 P
# 也可使用file/aux_source_directory批量引入,注意不要引入自动生成的文件!
1 D$ I; z6 P+ k5 badd_executable(${PROJECT_NAME} WIN32% z3 n# Y# l3 K* K5 s$ c; [
main.cpp: S- {5 V8 z9 }! O% m% l
mainwindow.cpp. S+ p) f) B$ T) Z; L0 S, t
mainwindow.h) t' I2 t o' S+ Z3 h& s
)( a* V( K* M- `& R
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)
; q) m6 ]4 Q0 Cfunction(windeployqt target)
3 D. q9 \5 [1 o% `& _. B# POST_BUILD step
- C8 v, N$ L4 {' vadd_custom_command(TARGET ${target} POST_BUILD
- L0 y9 X1 s p. HCOMMAND "${QT_BIN_PATH}/windeployqt.exe"
/ T# N* p9 v0 u! Q- q--verbose 11 v! N; y" d& a: f6 f. W/ j: V
#--release
: h3 y/ O* E: e" w6 P/ F#--no-svg- i n9 V3 L+ i9 _) s6 Z
#--no-angle {7 Y# Y" m" |+ J* ]
#--no-opengl
8 L: i4 p+ o8 p, @% m# A3 D2 s, U#--no-opengl-sw( H" v5 [9 B+ \$ R
#--no-compiler-runtime
! g3 \7 h% g! [' r0 u0 e& F#--no-system-d3d-compiler
, X2 ^& J6 Z5 l* C\"$\"9 D! H2 {( `' {' |! ~
COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."' H" q( S5 O, ]/ R# ?, ]
)0 S6 K# W/ O5 H6 D
endfunction()+ X: g, g) d) ^+ L! Q2 z
if (WIN32)
' S X3 T" v: E! I4 H8 H8 q9 |9 u windeployqt(${PROJECT_NAME})$ w5 G. k k* ]5 f" J/ f/ {5 i
endif()
( S8 |4 ~& ^1 n````通过上面的配置,我们的Qt项目既可在Qt Creator中正常编译运行,也可在CLion/Visual Studio中正常编译运行而 无需安装Qt插件。
( h7 I* }8 k. g4 k2 a- e 参考返回目录1. CMake官网6 y4 a3 B( v# x8 R, U! p/ C6 F8 A* x( ^( _
2. CMake教程
3 k9 Q% z( E6 y) Y; p2 F6 D3. CMake FAQ
7 ~& D/ e5 S& Q5 _1 e* F4. CMake指定编译器* T+ s# |3 E- ?$ I0 }! R
AD:【国外VPS推荐】 搬瓦工三网回程CN2 GIA VPS,季付46.87$打赏赞(3) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|