扫一扫,微信登陆

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

搜索
查看: 324|回复: 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项目配置。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 x
  • set定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。
    " N! _: m2 G1 G6 v
  • if…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 N
  • find_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; B
  • aux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。
      s9 w5 S5 {3 n  y" ]4 j3 x( B2 p, Q
  • filefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到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( r
  • find_library查找指定库的路径并保存到变量中。
    2 r5 w! d3 L* N
  • add_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。: R3 Y. {5 ^* h
  • add_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。
    2 o  T. g7 |; S* r" J& \4 Y
  • add_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
    回复

    使用道具 举报

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

    本版积分规则

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