|
本文目录CMake简介CMake命令CMake常见指令常用环境变量Qt应用示例一个完整的Qt 5项目CMakeLists.txt参考CMake是一个跨平台、开源的构建工具,在C/C++项目中有广泛应用。本文首先介绍CMake及常用指令,并结合工作时需要用到的Qt 5,给出一个完整的CMake项目配置。( T) m( ]! q4 ~- ^$ |# V
CMake简介返回目录CMake如其名”Cross-platform Make”,是一个 跨平台、开源 的构建工具。与make不同,CMake并不直接构建软件,而是生成用于构建的Makefile、.sln等工程文件,相当于高阶构建工具。
* Y. \0 @! o, }: G( b! y与另一构建工具Automake相比,CMake使用上更方便,支持更多的编译套件(Ninja、VS等)。许多编辑器和IDE,如VS Code(宇宙第一编辑器/IDE)、Clion、Visual Studio等都内置了对CMake的支持。特别的,CMake已经是QT 6的默认构建工具,官方给出从qmake迁移的理由是CMake成熟稳定、用户基数大生态完善。因此,对于需要跨平台编译运行的C/C++项目,很推荐学习和使用CMake作为构建工具,能方便的转换成各种IDE项目,团队成员无需切换编辑器/IDE即可工作。
6 x& Q8 l( n0 E# |2 c+ h值得一提的是,CMake由Kitware公司开发和维护,VTK和ParaView等知名开源产品均出自该公司。从这方面看,CMake也算出身名门,因此能很快流行开来。; v3 [7 R y( S, f! Q/ r" T, A' q
CMake命令返回目录CMake基于CMakeLists.txt文件来生成对应目标(generator)的构建文件,一个标准的CMake项目构建操作为(命令行方式):' K+ H& Y3 {* j4 n G
cd PROJECT_DIR( e$ H! h# g# X% ]/ l( M' x( o
cmake2 W; y9 J, w/ S% x
make TARGET或者使用用CMake GUI:
6 @, t5 F9 m" l( }% i# D, A9 m1 y7 G6 C" u" _
: w2 f- `3 @; N+ R
CMake-GUI操作示意图然后使用VS打开生成的.sln项目,即可编译、运行和调试项目。
0 z& B& }) ? K1 A. y) GLinux/Unix/MacOS平台上,CMake默认生成标准的makefile;Windows平台上则会检测Visual Studio版本,生成对应的VS .sln项目工程文件(在MSYS/Cygwin/WSL环境下执行除外)。可以使用 -G 选项切换生成目标,例如生成Ninja构建文件:
. P% @+ [! b) |; c/ B w# N+ q$ hcmake . -G Ninja, a+ T$ a, g% E
ninja TARGETCMake一个非常棒的特性是“外部构建”(out-of-source build),即支持在源码目录外构建。由于这个特性,以及CMake生成的makefile没有clean命令,一般来说都推荐在单独的build目录中构建:0 W& |7 i+ ?1 x" o! K5 Z
mkdir -p build
3 p) S8 }; @- t0 l6 R/ H+ D& Gcd $_
) \; a& l2 H$ m- w; ^ pcmake ..$ d! E6 {3 g+ m; j9 I
make TARGET -j4如果使用CMake GUI,Browse Build时请选择单独的构建目录。. E6 C D) c8 U9 S% o. U# D
命令行方式下编译Debug/Release版本、传递C++编译参数,请使用 -D 选项,例如:4 z" W' l5 R0 H- q7 L0 j! u
cmake .. -DCMAKE_BUILD_TYPE=Release$ G8 @3 \. G9 T$ I; P7 N7 J
make TARGET -j4一些内置的宏定义参数可参考下文的环境变量。, c3 @6 X0 q( K* s: _
如果是生成VS项目,则只需在VS中选择构建版本、设置编译和链接参数即可。
( ]$ [% l, [; g8 J CMake常见指令返回目录CMake基于CMakeLists.txt文件生成项目构建文件,因此编写CMakeLists.txt文件是CMake项目的核心。本小节介绍一些用在CMakeLists.txt文件中的常用指令。
' }- x3 }: S. V Z" o* sCMakeLists.txt 使用 # 作为注释,# 所在行后续字符均作为注释被忽略
" y6 |& o$ A. x' Zcmake_minimum_required一般这条指令出现在文件的最前面,用来指定项目支持的最低版本。对于Qt 5项目,建议为:cmake_minimum_required(VERSION 3.7)。
% i( h( o- z/ F0 gproject指定项目名称及属性。C/C++项目的建议值为:project(项目名称 C CXX)。) x9 R! G: R% V& N6 t
set定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。* ]# o: p% b) L6 D9 |9 {
if…else[if]…endif条件控制语句,注意指令后的括号不可省略:
5 A' B$ Q3 v' @1 v$ ~1 @if (WIN32)
$ S/ G- V; t: z, @xxxx$ K* ^' D; i' S5 o+ ~% }- V
else() # 括号不可省略
! ~) `+ h9 }, g# [! V7 h' vxxxx
! w% A! y2 ]2 G1 U, ~6 @endif() ]) {) Q2 d9 U& a& _5 q) [2 b
find_package查找指定模块,例如OpenMP。Qt 5项目一般需要:find_package(Qt5 COMPONENTS Widgets REQUIRED)。
/ l0 m% \0 ~9 z0 x6 d# {+ [" D9 vinclude_directories添加头文件include路径,一个更推荐使用的指令是 target_include_directories,其不污染后续目标的include路径,且能精细控制是否暴露依赖的包含路径。但是 target_include_directories 需要CMake 3.13 版本才支持,在Visual Studio 2017中使用会有问题。
) I. \" ~4 h( x$ e# C. y$ j link_directories设置链接库的路径,更推荐的指令是 target_link_directories,理由见 include_directories。) ?9 L, Y$ @$ m1 K8 L
aux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。
3 }" r" w$ \+ G) d5 k3 u! Rfilefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到SRC变量中:file(GLOB_RECURSE SRC "src/*.cpp" "src/*/*.cpp")。
0 c" U% s* R: `相对于把每个需要编译的文件添加到CMakeLists.txt中,aux_source_directory 和 file 等指令可方便的引入多个文件,但其弊端之一是CMake不能感知文件变化。当新增文件、文件被删除、重命名时需刷新CMake缓存才能被应用到项目中。- _7 R0 d; `$ f) d8 E9 H
find_library查找指定库的路径并保存到变量中。% p! M2 W1 {( L, K) z
add_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。
/ ?* }8 E, n- A2 d+ e5 vadd_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。+ h1 q1 t0 ?* C, B. N# e
add_executable构建可执行程序,一般项目的主CMakeLists.txt中会有这条指令。
* |8 C, U# k0 J' G8 x) xadd_library构建动态或静态库,一般存在于子目录或者库的CMakeLists.txt文件中。; ~$ G, @, r- ]
message可在cmake构建时输出信息。) B! _+ G/ ]) h2 w4 b% S' @& b
CMakeLists.txt文件中指令不区分大小写,但一般来说同一个文件中指令应保持大小写风格一致。7 e+ n$ S7 E& C l
更多指令可参考 CMake官方文档。
) r$ X( o; f+ ?9 v! ~ 常用环境变量返回目录本小节介绍几个常用的环境变量(编译宏)。! d. ~" F' Q3 ]! j
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 n2 d; e4 g, T0 u* C
新建Qt项目时,可以选择CMake作为构建工具:
4 z3 d! }- G0 L0 t2 Y. p5 U5 |* X& B: b6 E; b( B4 }
2 N1 N2 `- f5 q
Qt新建项目使用CMake生成项目后,项目文件夹将出现CMakeLists.txt和CMakeLists.txt.user两个文件,熟悉的.pro文件没有了(CMakeLists.txt.user充当了Qt Creator工程文件的角色,其他IDE用不到,可删除)。 [- f! Z) }5 A w; [+ T0 g
但需要注意的是,此时Qt Creator中编译项目是没问题的,但是在CLion/VS Code中打开,或者生成Visual Studio用的.sln文件会有问题,因为CMake无法检测到Qt是否安装及其安装路径。
) W% V) K# \+ g1 c$ F1 r, P4 Z解决办法便是在 project 指令后增加如下指令告知Qt的安装位置:/ N S0 j, G7 Q0 N0 x
# 具体路径请根据自身情况替换: [% w$ w/ p% O( | _ R
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")
h# d) I A, Hset(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")% V/ o+ A `) h8 d$ C% b
然后再次运行 cmake 指令或者使用CMake GUI重新运行,构建文件夹下便能正常生成.sln项目文件。" x3 D5 u t0 N' u' b2 T& Z( ]
VS中编译好后,运行时会提示无法找到Qt相关的dll导致程序不能正常运行。解决办法包括:# O7 [! O! u4 _7 D2 R7 y
1. 设置VS选项,将Qt的dll路径包含进去;
% Q1 h3 ^+ @4 G: g# }2 ]) @3 _ 2. 将Qt相关dll拷贝到编译输出文件夹;
/ s% _- H# @9 o' N8 t% K; P 3. 设置CMake,使其能自动复制所需要的dll。8 K- L2 o; I- K- F( P: C
这里介绍第三种方式,原理是借助Qt自带的windeployqt.exe程序自动部署程序所需dll到目标文件夹。具体操作为,在项目根目录的CMakeLists.txt最后添加部署dll的指令:3 x- Q# m3 B/ g; X% L" `! ]1 h
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
j8 v" j2 r _/ u: y& zfunction(windeployqt target)1 p! n+ C3 T& A! s& [
# POST_BUILD step, ~1 T: ]" D4 P# H Q M& [
# - after build, we have a bin/lib for analyzing qt dependencies
0 R: E+ [0 M$ G; c/ {7 k' t# - we run windeployqt on target and deploy Qt libs9 x. d! d7 X: `" P
add_custom_command(TARGET ${target} POST_BUILD
( t! y- [0 W6 e$ n& h& c5 {COMMAND "${QT_BIN_PATH}/windeployqt.exe"2 j$ a# x/ g& Q/ k4 e. P! ~
--verbose 1% H- z9 w2 |& z4 x$ g" {, F
#--release # uncomment this line if built with Release
! x+ o; b1 y! f+ K#--no-svg! x. S0 J# m& R( _
#--no-angle
; ^% g' A7 B9 h' L J( b* ]4 c#--no-opengl
+ W) T7 h# O! Y# g#--no-opengl-sw1 y3 p8 d D! P
#--no-compiler-runtime
- d' _- Y% l1 O7 ^# I#--no-system-d3d-compiler
: l6 q4 B5 p: ]. _\"$\"9 p" n+ t& Z: n% T
COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."9 r$ x/ V* S; w$ K. R& y) x
)
* d. i* p) T# Qendfunction()
- y+ o2 L% w" p( Dif (WIN32)( o& v8 i) M* n" k; Z! f6 T* y
windeployqt(${PROJECT_NAME})
5 ^6 `8 _+ {9 {( |6 r m4 Sendif()最后,转换成VS项目时,默认是Console项目,运行时会有cmd窗口。一个解决办法是在生成可执行文件时设置目标为 WIN32: b3 v/ b& X$ }; E6 w$ R! G
add_executable(${PROJECT_NAME} WIN32 xxxx)7 l8 T: L+ q+ e/ X
一个完整的Qt 5项目CMakeLists.txt返回目录以下是一个适用于Windows平台的Qt 5项目完整CMakeLists.txt,实际使用时请替换名字和Qt 5安装路径等: ]' V0 [, B" @' ^2 x% ^
cmake_minimum_required(VERSION 3.7)
# `0 D/ i; h' y V0 D( m# 请将myproject改成实际的应用名字/ U" {! _ u r, h2 l' ^
project(myproject LANGUAGES CXX)
3 J/ ^) l7 p0 N( Q% L; _6 _, sset(CMAKE_INCLUDE_CURRENT_DIR ON)
* [# s6 E2 A* q9 R0 b P# 请更改为实际的Qt安装目录9 C* Y3 _1 r2 |8 p M0 O
set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")2 E9 t: w* Z: q0 [) |" R, ?# c
set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")2 I$ V" o6 S. r. m% Z
set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
5 d% g0 t% R# E' f& l+ i3 s O# gset(CMAKE_AUTOUIC ON)
G: l& t9 b1 zset(CMAKE_AUTOMOC ON)
' V5 x* [' h" q- Z* s: T1 ?. ]set(CMAKE_AUTORCC ON)
. `& j5 O' h# [$ U1 |7 ~set(CMAKE_CXX_STANDARD 11)* v, S0 _# V9 v5 B. s! L
set(CMAKE_CXX_STANDARD_REQUIRED ON)
& ~) a3 H3 R2 a8 Z/ Pfind_package(Qt5 COMPONENTS Widgets REQUIRED)
: m5 ^& ^/ p, Y/ g+ f* t4 R4 _' O# 默认Release构建$ y1 e6 v5 b6 k- M; C$ q8 y* e
if (NOT CMAKE_BUILD_TYPE)- ]( p- `8 V7 ~$ p/ l# ?
set( CMAKE_BUILD_TYPE "Release" )
6 {) P0 i: J3 x' d% r$ `1 bendif()
4 b4 x$ i( c# _message("build type: ${CMAKE_BUILD_TYPE}")! P2 \, k5 `9 R* u. k
# 按照自己的项目结构添加文件$ K9 c7 e. y5 z, j* J+ z
# 也可使用file/aux_source_directory批量引入,注意不要引入自动生成的文件!$ J' K+ I3 a5 r! m, V$ D& s0 S) t0 h
add_executable(${PROJECT_NAME} WIN32 \ _6 P& x2 S. l% C, `: _
main.cpp
/ E4 i+ Q. s% l$ ], A1 Y7 X7 p; S mainwindow.cpp" n M+ i$ w g# E0 q% H9 [& S
mainwindow.h
! r% P- i* p, {! t)
6 \1 u7 b( k5 A h: k9 Gtarget_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)
% W0 t8 T& j' F7 ]0 J7 h# [function(windeployqt target): y! n7 ~0 B5 U" ~: q4 K
# POST_BUILD step9 R% Z$ m/ u) p
add_custom_command(TARGET ${target} POST_BUILD. z! ?8 _9 T0 C# R8 G, h. y+ ~/ N
COMMAND "${QT_BIN_PATH}/windeployqt.exe"6 W* k$ `* M" e; l0 K2 t
--verbose 1; S6 T8 N1 Z! b" W* [- [
#--release
[0 D) G2 K2 }2 b2 S7 D#--no-svg
6 E3 o: Q. N* \2 _- r l#--no-angle- I4 k/ \' U& C+ U
#--no-opengl; c, K% k) O, D6 ?7 Z
#--no-opengl-sw
- S, l2 g- q+ H P#--no-compiler-runtime+ S7 Y( V1 |: Q' l) R6 `7 v
#--no-system-d3d-compiler7 n# [. _. i6 {) k+ o9 k g
\"$\"1 s& A# K1 g( v7 i3 n: h
COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."
' }0 a: {* `& V! O9 ^& m, H)
7 q7 \0 k) z, U5 C# @$ Qendfunction()
1 [3 q% [2 U& iif (WIN32)
" E; H) |# Y, [, y7 ] windeployqt(${PROJECT_NAME})
9 e1 W& S7 G" P$ W' G$ X3 z0 S$ Mendif()
9 |% _ h/ `5 Y) h8 [, U````通过上面的配置,我们的Qt项目既可在Qt Creator中正常编译运行,也可在CLion/Visual Studio中正常编译运行而 无需安装Qt插件。
3 J. d8 s' D5 @3 e/ ]/ _ 参考返回目录1. CMake官网
: l5 ^) b$ b" r0 D8 w2. CMake教程 z5 y, Q& T- n& W) s1 `
3. CMake FAQ
, D- y1 o$ X9 n2 Z+ L8 d' b; k4. CMake指定编译器
9 m! K* z5 ]+ @0 E" fAD:【国外VPS推荐】 搬瓦工三网回程CN2 GIA VPS,季付46.87$打赏赞(3) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|