扫一扫,微信登陆

 青浦修电脑 青浦笔记本维修 青浦手机维修 青浦电器维修

搜索
查看: 1051|回复: 0

CMake简明实用教程 - 青浦海洋数码电脑城

[复制链接]

1万

主题

1万

帖子

5万

积分

论坛元老

Rank: 8Rank: 8

积分
56206
发表于 2022-9-11 20:40:15 | 显示全部楼层 |阅读模式
本文目录
  • CMake简介
  • CMake命令
  • CMake常见指令
  • 常用环境变量
  • Qt应用示例
  • 一个完整的Qt 5项目CMakeLists.txt
  • 参考CMake是一个跨平台、开源的构建工具,在C/C++项目中有广泛应用。本文首先介绍CMake及常用指令,并结合工作时需要用到的Qt 5,给出一个完整的CMake项目配置。
    . d9 p4 z0 e6 e, Q0 E3 S7 ~
    CMake简介返回目录CMake如其名”Cross-platform Make”,是一个 跨平台、开源 的构建工具。与make不同,CMake并不直接构建软件,而是生成用于构建的Makefile、.sln等工程文件,相当于高阶构建工具。- X+ ]! {! J8 t
    与另一构建工具Automake相比,CMake使用上更方便,支持更多的编译套件(Ninja、VS等)。许多编辑器和IDE,如VS Code(宇宙第一编辑器/IDE)、Clion、Visual Studio等都内置了对CMake的支持。特别的,CMake已经是QT 6的默认构建工具,官方给出从qmake迁移的理由是CMake成熟稳定、用户基数大生态完善。因此,对于需要跨平台编译运行的C/C++项目,很推荐学习和使用CMake作为构建工具,能方便的转换成各种IDE项目,团队成员无需切换编辑器/IDE即可工作。! _7 u1 N, H- w  f9 P  ?
    值得一提的是,CMake由Kitware公司开发和维护,VTK和ParaView等知名开源产品均出自该公司。从这方面看,CMake也算出身名门,因此能很快流行开来。2 Z6 a# }8 B; w
    CMake命令返回目录CMake基于CMakeLists.txt文件来生成对应目标(generator)的构建文件,一个标准的CMake项目构建操作为(命令行方式):6 j4 [. a! }7 c9 k
    cd PROJECT_DIR% T; e0 ~7 Z+ f: z6 s) s$ T
    cmake
    8 [6 x+ E6 }& S. \* z: wmake TARGET或者使用用CMake GUI:8 m; {( a  l& H1 Z+ D
    ( C. F9 b% E6 e. [* l+ v, B0 y, C
      l4 ]6 m$ Y: j% X; i
    CMake-GUI操作示意图然后使用VS打开生成的.sln项目,即可编译、运行和调试项目。
    * h+ G2 }+ k  z) T" P  ?Linux/Unix/MacOS平台上,CMake默认生成标准的makefile;Windows平台上则会检测Visual Studio版本,生成对应的VS .sln项目工程文件(在MSYS/Cygwin/WSL环境下执行除外)。可以使用 -G 选项切换生成目标,例如生成Ninja构建文件:
    4 p# {  t/ T2 |cmake . -G Ninja( M3 D5 B! q/ c) o5 X, p
    ninja TARGETCMake一个非常棒的特性是“外部构建”(out-of-source build),即支持在源码目录外构建。由于这个特性,以及CMake生成的makefile没有clean命令,一般来说都推荐在单独的build目录中构建:: S+ A$ G5 A# M9 B
    mkdir -p build
      y6 B1 F, y6 t; A$ ycd $_
    9 U; V/ i. `2 [) G* Y" H6 U! wcmake ..; b) d# p: G! ]2 W- e
    make TARGET -j4如果使用CMake GUI,Browse Build时请选择单独的构建目录。
    " r; K+ B0 r6 c命令行方式下编译Debug/Release版本、传递C++编译参数,请使用 -D 选项,例如:# x0 d  r. Q& m+ C% k) ]7 i
    cmake .. -DCMAKE_BUILD_TYPE=Release. x( }, G/ z1 s' D) R, Y( }' n/ E9 Z
    make TARGET -j4一些内置的宏定义参数可参考下文的环境变量。
    7 s: _+ S& Y/ O$ p$ a0 M- O如果是生成VS项目,则只需在VS中选择构建版本、设置编译和链接参数即可。
    9 n. G6 l3 {: g  w1 N CMake常见指令返回目录CMake基于CMakeLists.txt文件生成项目构建文件,因此编写CMakeLists.txt文件是CMake项目的核心。本小节介绍一些用在CMakeLists.txt文件中的常用指令。
    ( n) M8 K/ `; B% k/ x3 {1 CCMakeLists.txt 使用  # 作为注释,# 所在行后续字符均作为注释被忽略+ u& R* I+ @9 d  Z8 Y
  • cmake_minimum_required一般这条指令出现在文件的最前面,用来指定项目支持的最低版本。对于Qt 5项目,建议为:cmake_minimum_required(VERSION 3.7)。
    % _4 B+ N. a  ?2 j
  • project指定项目名称及属性。C/C++项目的建议值为:project(项目名称 C CXX)。
    8 U9 [  l9 l: v" M3 C; h$ M
  • set定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。( P" W0 b- j% A
  • if…else[if]…endif条件控制语句,注意指令后的括号不可省略:8 o$ j9 @/ q# E  W$ |% z" f% o( @" z% A; H
    if (WIN32)
    - c5 ^9 X% x: y- v3 }( V6 Dxxxx
    9 c. H. @# a3 X- u5 x- ?else() # 括号不可省略+ G8 j* y' F6 |9 Q& Y3 F
    xxxx
    / K5 J- x, v- Z/ v+ ]% s7 [' Lendif()
    % p4 B; ~, z/ n& ^! k
  • find_package查找指定模块,例如OpenMP。Qt 5项目一般需要:find_package(Qt5 COMPONENTS Widgets REQUIRED)。; B, |& w% M! ^: E
  • include_directories添加头文件include路径,一个更推荐使用的指令是 target_include_directories,其不污染后续目标的include路径,且能精细控制是否暴露依赖的包含路径。但是 target_include_directories 需要CMake 3.13 版本才支持,在Visual Studio 2017中使用会有问题。  _  _" e$ Q4 H+ T' o# [
  • link_directories设置链接库的路径,更推荐的指令是 target_link_directories,理由见 include_directories。
    + q5 t1 V) Q( G! x; Y! X9 Q
  • aux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。  m7 o" r5 k; G$ i4 r
  • filefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到SRC变量中:file(GLOB_RECURSE SRC "src/*.cpp" "src/*/*.cpp")。+ |3 k6 e7 r4 ~  T
    相对于把每个需要编译的文件添加到CMakeLists.txt中,aux_source_directory 和 file 等指令可方便的引入多个文件,但其弊端之一是CMake不能感知文件变化。当新增文件、文件被删除、重命名时需刷新CMake缓存才能被应用到项目中。" e- T- Z8 F5 L2 b0 F1 Z2 U
  • find_library查找指定库的路径并保存到变量中。
    # Q: v  E& G' Q/ S! t2 h
  • add_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。
    ! s: W7 `+ N7 M+ s. b( \
  • add_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。
    ' Y  j" a( \$ D$ C9 p* s  B
  • add_executable构建可执行程序,一般项目的主CMakeLists.txt中会有这条指令。. H9 h2 D; Q- y* p% ~% Q% _; X# c
  • add_library构建动态或静态库,一般存在于子目录或者库的CMakeLists.txt文件中。
    ' ]) D2 F# K. d$ v1 X9 T
  • message可在cmake构建时输出信息。$ ^! Q6 w  _) v- w; b
    CMakeLists.txt文件中指令不区分大小写,但一般来说同一个文件中指令应保持大小写风格一致。( Y, ]% P/ `! A/ c/ k2 X# v
    更多指令可参考 CMake官方文档。! J, T, C# K3 p) d! {' [* T$ O
    常用环境变量返回目录本小节介绍几个常用的环境变量(编译宏)。
    6 y% J  p, o! y8 Q2 p' I8 ?# W
  • 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的使用方式。
    1 [; e( c' u) i% d& K7 r; N( d新建Qt项目时,可以选择CMake作为构建工具:
    8 k) y9 w3 t! R8 g! y7 B0 Z8 v, N) T# L( I' t' @

    % K3 t8 h: E! I( O! {0 a3 M2 p1 T/ ~Qt新建项目使用CMake生成项目后,项目文件夹将出现CMakeLists.txt和CMakeLists.txt.user两个文件,熟悉的.pro文件没有了(CMakeLists.txt.user充当了Qt Creator工程文件的角色,其他IDE用不到,可删除)。
    8 a+ \0 E0 U& d' U但需要注意的是,此时Qt Creator中编译项目是没问题的,但是在CLion/VS Code中打开,或者生成Visual Studio用的.sln文件会有问题,因为CMake无法检测到Qt是否安装及其安装路径。  L& R2 c4 `3 g5 t: D
    解决办法便是在 project 指令后增加如下指令告知Qt的安装位置:3 m$ i2 W; P9 }1 E* u0 [
    # 具体路径请根据自身情况替换
    & R: F' @* a5 h0 B, z& ?set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")+ }( b9 q% j" c
    set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")
    ' c- M1 M0 q* _& p然后再次运行 cmake 指令或者使用CMake GUI重新运行,构建文件夹下便能正常生成.sln项目文件。
    ' Q) [- O$ Z9 PVS中编译好后,运行时会提示无法找到Qt相关的dll导致程序不能正常运行。解决办法包括:4 `2 o% r$ ]! ]. z+ K
    1. 设置VS选项,将Qt的dll路径包含进去;1 Q: E9 S9 z! t: o' l, A0 a) n
    2. 将Qt相关dll拷贝到编译输出文件夹;
    $ G% R1 D& C' g/ e* U. ~4 K% `4 P, y 3. 设置CMake,使其能自动复制所需要的dll。8 r. u* S2 |" {
    这里介绍第三种方式,原理是借助Qt自带的windeployqt.exe程序自动部署程序所需dll到目标文件夹。具体操作为,在项目根目录的CMakeLists.txt最后添加部署dll的指令:0 r: Y. }1 O3 d( |. t" o/ M
    set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
    9 F; m( z7 J  W, G! Q( t% ufunction(windeployqt target)3 I* m- ^0 R' ?; A
    # POST_BUILD step0 k) p% e( n, K8 Q8 [2 ]2 e
    # - after build, we have a bin/lib for analyzing qt dependencies
    " ?: c6 {/ O- ~! J# }: R# - we run windeployqt on target and deploy Qt libs2 F1 L4 ~  m' R+ @0 l, C6 }
    add_custom_command(TARGET ${target} POST_BUILD
    1 [, P3 d+ U! n% R+ WCOMMAND "${QT_BIN_PATH}/windeployqt.exe"
      p& i2 E" `' |) s* Z# o& }--verbose 16 F: s$ j/ {: n( Y- r& M
    #--release # uncomment this line if built with Release
    1 J6 U$ B8 n: h#--no-svg
    % }9 z7 H6 p1 w#--no-angle
    5 J% W" O0 {! Q, n#--no-opengl
    6 `; n: S+ n) W. B7 A/ k+ y" k#--no-opengl-sw8 s4 Q* k) t+ Q: [. f5 u) s
    #--no-compiler-runtime0 Y7 i7 n2 d! ~: m- Z
    #--no-system-d3d-compiler
    4 z# F% c1 W' F\"$\"
    4 B6 {$ i8 O# e# w) D/ P4 NCOMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."7 @: C6 _4 `. f( r- D
    )
    ; V! A, |) r+ t$ d' o& Fendfunction()# e1 K+ r& Y% j( X* h% v
    if (WIN32)
    $ ^7 u& l- a- v  windeployqt(${PROJECT_NAME})' i  @3 k/ F& u; \
    endif()最后,转换成VS项目时,默认是Console项目,运行时会有cmd窗口。一个解决办法是在生成可执行文件时设置目标为 WIN32:
    / a% x- s  c/ d- c' xadd_executable(${PROJECT_NAME} WIN32 xxxx)
    7 {- a; }6 \- _& R 一个完整的Qt 5项目CMakeLists.txt返回目录以下是一个适用于Windows平台的Qt 5项目完整CMakeLists.txt,实际使用时请替换名字和Qt 5安装路径等:
    $ h6 {3 C5 g) a3 x$ Wcmake_minimum_required(VERSION 3.7)" [$ O- H2 W1 X' x4 `* b" c5 C
    # 请将myproject改成实际的应用名字
    ; C+ g/ r, N6 [: ?project(myproject LANGUAGES CXX)
    3 k7 X: C. P+ I) w4 O1 K+ [) `set(CMAKE_INCLUDE_CURRENT_DIR ON)
    ! f% N- n7 N3 ~/ v3 q# 请更改为实际的Qt安装目录2 Z$ G6 E' u) Z  J" }8 M
    set(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")$ t- m9 p0 n+ m
    set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")4 o# Q5 W+ q  Q" y9 W! z
    set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
    4 j6 S$ N5 E, m7 l, k0 N! z6 Bset(CMAKE_AUTOUIC ON). _7 ?' U5 r: X4 l
    set(CMAKE_AUTOMOC ON)
    # x  |8 D) @- W! Oset(CMAKE_AUTORCC ON)
    / H8 Q% s- h0 W0 K6 u& Pset(CMAKE_CXX_STANDARD 11)
    . h6 {; a8 @2 H3 b7 L7 T4 Gset(CMAKE_CXX_STANDARD_REQUIRED ON)
    4 i7 Q- S$ ^* {7 A0 j* i; afind_package(Qt5 COMPONENTS Widgets REQUIRED)8 O3 v; r9 [- ~
    # 默认Release构建& C# W3 K6 g0 ^, s* U
    if (NOT CMAKE_BUILD_TYPE)# b& I% e) w; p. A
        set( CMAKE_BUILD_TYPE "Release" )
    ' P  F0 s+ e4 R' hendif(). ^% K2 y( y% Y9 @3 O
    message("build type: ${CMAKE_BUILD_TYPE}")
    . V( R$ }# _2 }9 H8 R# 按照自己的项目结构添加文件$ B) N& x2 g$ l: e+ O  V7 m6 [# v
    # 也可使用file/aux_source_directory批量引入,注意不要引入自动生成的文件!( A2 i' B: \; I
    add_executable(${PROJECT_NAME} WIN32
    ) ?* e1 B3 S7 g  main.cpp
    ' w/ h/ m3 {3 Z$ ^6 }  mainwindow.cpp
    7 Q" n( P( \: l  mainwindow.h$ g; k3 H0 w% K- M- U
    )/ u- E! e5 X: x0 l
    target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)& t1 w( Z8 |; t. L" G! _
    function(windeployqt target)
    3 W6 Y. F6 ~1 c% k9 `# POST_BUILD step( ~9 k# U! h2 _2 G. o% _  E! @
    add_custom_command(TARGET ${target} POST_BUILD6 h& ~. f, _  U* P, Z
    COMMAND "${QT_BIN_PATH}/windeployqt.exe"/ F+ }9 V/ G2 l3 Z, _
    --verbose 1
    % a& q' _+ S- m# G#--release
    / ?7 e7 n) Z) a& p9 x#--no-svg9 f# a* p# k2 }. Z8 K# X: l9 q
    #--no-angle5 A2 m- `9 m9 c' w8 G
    #--no-opengl
      i: q2 U! t9 v#--no-opengl-sw
    ' j  j9 D+ U/ q% v) e* t  b#--no-compiler-runtime7 e0 f5 p" H. ?# R3 a3 J7 l- l
    #--no-system-d3d-compiler
    5 l/ o, y! E% e  f! l2 s\"$\"
      |, L8 C' I3 I. DCOMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."
      Z7 f% c  L8 g5 i2 r/ T9 W" u2 J4 O3 B)1 N1 C2 ~( J! i) H' O5 m6 P7 x
    endfunction()
    8 I; r1 Z+ t9 R% }+ Q& Y0 gif (WIN32)9 k. D, X. ^- N) I' d* U
      windeployqt(${PROJECT_NAME})9 j6 R8 O8 ?, \/ h0 j9 `* {) o
    endif()' J/ O" a/ A/ m6 N4 Z7 u- o+ L. h
    ````通过上面的配置,我们的Qt项目既可在Qt Creator中正常编译运行,也可在CLion/Visual Studio中正常编译运行而 无需安装Qt插件。
    ; `' J: e3 u, V# v  m7 q 参考返回目录1. CMake官网
    ( ?* f% X5 q- X% c2 m2. CMake教程
    5 h1 C. r6 [- p% a4 l3. CMake FAQ
    3 N  K6 w2 T& p5 j3 S! Y4. CMake指定编译器- Y) u0 b* r% a5 ?! o- d
    AD:【国外VPS推荐】 搬瓦工三网回程CN2 GIA VPS,季付46.87$打赏赞(3)
  • 本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    Copyright © 2001-2013 Comsenz Inc.Powered by Discuz!X3.4( 沪ICP备18024137号 )
    快速回复 返回顶部 返回列表