扫一扫,微信登陆

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

搜索
查看: 651|回复: 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项目配置。
    7 X  |. A, w: L( @* r; g8 k. m
    CMake简介返回目录CMake如其名”Cross-platform Make”,是一个 跨平台、开源 的构建工具。与make不同,CMake并不直接构建软件,而是生成用于构建的Makefile、.sln等工程文件,相当于高阶构建工具。
    ) Q) d! ^: ^. J& R* Y- J# B与另一构建工具Automake相比,CMake使用上更方便,支持更多的编译套件(Ninja、VS等)。许多编辑器和IDE,如VS Code(宇宙第一编辑器/IDE)、Clion、Visual Studio等都内置了对CMake的支持。特别的,CMake已经是QT 6的默认构建工具,官方给出从qmake迁移的理由是CMake成熟稳定、用户基数大生态完善。因此,对于需要跨平台编译运行的C/C++项目,很推荐学习和使用CMake作为构建工具,能方便的转换成各种IDE项目,团队成员无需切换编辑器/IDE即可工作。! y  @$ R% [! r% g7 `$ x
    值得一提的是,CMake由Kitware公司开发和维护,VTK和ParaView等知名开源产品均出自该公司。从这方面看,CMake也算出身名门,因此能很快流行开来。5 v$ M. {6 y. }# T
    CMake命令返回目录CMake基于CMakeLists.txt文件来生成对应目标(generator)的构建文件,一个标准的CMake项目构建操作为(命令行方式):1 N* a" T1 b( w0 e* Y1 q# e9 [5 H
    cd PROJECT_DIR4 D4 }4 m  d5 D! j& u- Q) e8 w4 p/ W8 e
    cmake
    . ^% X' M. v' qmake TARGET或者使用用CMake GUI:
    ( W) z5 G! y3 N; P, u( ~: E2 X1 l2 z( I+ \

    3 ^6 |, b* ]1 l3 ~  z8 {! ACMake-GUI操作示意图然后使用VS打开生成的.sln项目,即可编译、运行和调试项目。: V* \$ x7 `) H$ o
    Linux/Unix/MacOS平台上,CMake默认生成标准的makefile;Windows平台上则会检测Visual Studio版本,生成对应的VS .sln项目工程文件(在MSYS/Cygwin/WSL环境下执行除外)。可以使用 -G 选项切换生成目标,例如生成Ninja构建文件:
    . u0 M! D: e" u5 ^$ Ocmake . -G Ninja2 T0 c0 h/ Q0 |8 H" Q9 H+ u( u9 i
    ninja TARGETCMake一个非常棒的特性是“外部构建”(out-of-source build),即支持在源码目录外构建。由于这个特性,以及CMake生成的makefile没有clean命令,一般来说都推荐在单独的build目录中构建:  e- @! Z' Z1 s8 F
    mkdir -p build6 l3 I2 q5 P9 x+ m% [
    cd $_
    ! W: A- s' P" p& B1 N5 I4 w) ccmake ..
    + I/ W8 A2 }9 d! u4 Cmake TARGET -j4如果使用CMake GUI,Browse Build时请选择单独的构建目录。( `2 u7 R% K( ~% z- D: d
    命令行方式下编译Debug/Release版本、传递C++编译参数,请使用 -D 选项,例如:
    0 V' ~. d+ d6 P" y& _* H! z* }3 a) ocmake .. -DCMAKE_BUILD_TYPE=Release9 @# M% ~& C" U4 i  X' i0 f5 I. O: R3 a
    make TARGET -j4一些内置的宏定义参数可参考下文的环境变量。' A- ~: m8 H. }' t9 T
    如果是生成VS项目,则只需在VS中选择构建版本、设置编译和链接参数即可。
    ! t3 r1 K/ a8 I% l7 k CMake常见指令返回目录CMake基于CMakeLists.txt文件生成项目构建文件,因此编写CMakeLists.txt文件是CMake项目的核心。本小节介绍一些用在CMakeLists.txt文件中的常用指令。
    ( y+ A( R0 g- j+ o( yCMakeLists.txt 使用  # 作为注释,# 所在行后续字符均作为注释被忽略
    5 ~8 [* C) T. y5 q& y* ?: o
  • cmake_minimum_required一般这条指令出现在文件的最前面,用来指定项目支持的最低版本。对于Qt 5项目,建议为:cmake_minimum_required(VERSION 3.7)。
    , w) d- E! L7 M* j/ c
  • project指定项目名称及属性。C/C++项目的建议值为:project(项目名称 C CXX)。* C( M9 T3 h/ ]' B& O8 a: c1 {4 |/ O
  • set定义一些变量、宏的值。该指令一般会出现多次,例如设置C++语法标准:set(CMAKE_CXX_STANDARD 11)。相反的指令是unset。- P7 a/ s2 P( E1 m
  • if…else[if]…endif条件控制语句,注意指令后的括号不可省略:
    0 X7 P8 y4 r, u, O/ P5 |6 Kif (WIN32)
    + J, f3 o. }: @3 p6 p: ~) Axxxx7 _; b) e5 I! a% H; R# @: M
    else() # 括号不可省略( ^' U) @6 a, ^% y# r4 U
    xxxx2 p7 o% q* k& }5 j/ i+ p1 E
    endif()- A; a/ X  f4 I. E
  • find_package查找指定模块,例如OpenMP。Qt 5项目一般需要:find_package(Qt5 COMPONENTS Widgets REQUIRED)。+ m" |2 w0 j" ]# b
  • include_directories添加头文件include路径,一个更推荐使用的指令是 target_include_directories,其不污染后续目标的include路径,且能精细控制是否暴露依赖的包含路径。但是 target_include_directories 需要CMake 3.13 版本才支持,在Visual Studio 2017中使用会有问题。
    * j* d  i* A8 J# {& G5 T
  • link_directories设置链接库的路径,更推荐的指令是 target_link_directories,理由见 include_directories。1 e  G1 h; P7 J6 _7 i
  • aux_source_directory将指定目录下的源文件添加到变量中,例如:aux_source_directory(./src SRC)。注意该命令不会递归包含子目录源文件。- M3 R) X4 y# w
  • filefile命令是一个功能丰富的目录和文件操作指令,例如递归找出目录下的所有源文件保存到SRC变量中:file(GLOB_RECURSE SRC "src/*.cpp" "src/*/*.cpp")。
    % p: l2 l) P& f' N. c2 s, P相对于把每个需要编译的文件添加到CMakeLists.txt中,aux_source_directory 和 file 等指令可方便的引入多个文件,但其弊端之一是CMake不能感知文件变化。当新增文件、文件被删除、重命名时需刷新CMake缓存才能被应用到项目中。
    & R* V4 m/ c: L5 O- e( L/ c
  • find_library查找指定库的路径并保存到变量中。- h# o6 Y! u/ `9 A+ L% x( e
  • add_custom_command添加自定义命令,可用于构建前进行moc,构建后拷贝文件等用途。) \# e3 V8 T! y  ]! ?% H( F0 N4 s& v
  • add_subdirectory添加一个需要构建的子目录,子目录下有CMakeLists.txt文件设定好构建规则。) ]  ]2 S. v8 z% Q8 x! i
  • add_executable构建可执行程序,一般项目的主CMakeLists.txt中会有这条指令。
    ' N  D5 j. t. |- o9 `  S6 b
  • add_library构建动态或静态库,一般存在于子目录或者库的CMakeLists.txt文件中。
    ! [1 L3 v2 V: j5 f6 Y. ^2 _
  • message可在cmake构建时输出信息。
    0 j. u2 d- D; D, RCMakeLists.txt文件中指令不区分大小写,但一般来说同一个文件中指令应保持大小写风格一致。# a+ b. g+ F  }2 V  l3 r' q
    更多指令可参考 CMake官方文档。
    ) Z4 W3 Q! o3 N. D+ ? 常用环境变量返回目录本小节介绍几个常用的环境变量(编译宏)。! K$ {' u9 Z' B- i- C
  • 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的使用方式。
    ; \" `: q/ s# F6 ^! x新建Qt项目时,可以选择CMake作为构建工具:
    , d& h  j% i& D& i# u4 N5 ]: u6 C% T# b

    ( k- ~. A' \. z4 B8 [3 i. GQt新建项目使用CMake生成项目后,项目文件夹将出现CMakeLists.txt和CMakeLists.txt.user两个文件,熟悉的.pro文件没有了(CMakeLists.txt.user充当了Qt Creator工程文件的角色,其他IDE用不到,可删除)。
    3 Q3 ]$ j) m$ E) G: t4 h但需要注意的是,此时Qt Creator中编译项目是没问题的,但是在CLion/VS Code中打开,或者生成Visual Studio用的.sln文件会有问题,因为CMake无法检测到Qt是否安装及其安装路径。
    - C' r5 M2 w. O5 p解决办法便是在 project 指令后增加如下指令告知Qt的安装位置:
    ' n7 b5 p2 q0 W) o5 m. Z# 具体路径请根据自身情况替换
    ; f1 b  J6 h1 d4 i" {* Rset(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")3 s& Y8 Y1 |6 K0 O
    set(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")! ]7 d2 R2 t7 e+ ~. X. C0 d
    然后再次运行 cmake 指令或者使用CMake GUI重新运行,构建文件夹下便能正常生成.sln项目文件。
    6 L) ~+ h$ U9 `VS中编译好后,运行时会提示无法找到Qt相关的dll导致程序不能正常运行。解决办法包括:( Q" v6 p  @: ]7 P
    1. 设置VS选项,将Qt的dll路径包含进去;
    & g! Y$ f  M0 H( K: r 2. 将Qt相关dll拷贝到编译输出文件夹;
    6 c3 M  x0 D% u( O 3. 设置CMake,使其能自动复制所需要的dll。
    5 S1 @8 w6 h, a  @% C% ^( t  N% Z这里介绍第三种方式,原理是借助Qt自带的windeployqt.exe程序自动部署程序所需dll到目标文件夹。具体操作为,在项目根目录的CMakeLists.txt最后添加部署dll的指令:1 `4 j- E- N1 @/ K" v& _& _9 i
    set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
    ) v* y% s/ J4 Q0 I. {6 Ffunction(windeployqt target). G9 P5 }" c& f! S9 E; D! E. j6 r
    # POST_BUILD step
    1 b3 G' ]* w, O) X: Y) O& `# - after build, we have a bin/lib for analyzing qt dependencies
    4 P7 v! H- ~" J$ P, `0 r# - we run windeployqt on target and deploy Qt libs! Q8 V( m$ C6 y% F) \" l
    add_custom_command(TARGET ${target} POST_BUILD/ U0 ?9 j% V( P* I9 o' }3 I
    COMMAND "${QT_BIN_PATH}/windeployqt.exe"
    - z2 z( V4 I; Q! u* n* n/ F--verbose 1/ w( \  B0 x3 }
    #--release # uncomment this line if built with Release6 y6 q$ c: W# O9 Q9 g( T  [
    #--no-svg, E" N# l9 `+ D& ~; V
    #--no-angle
    7 Y' l; b, r7 e! C. F4 |#--no-opengl
    6 s% w7 m/ B! a% X#--no-opengl-sw" i5 c# _& Y' j, i7 A0 E6 B
    #--no-compiler-runtime
    2 e1 ^" A# A! G2 g  q! E#--no-system-d3d-compiler
    ; Z7 H" n  u: w, t4 ~6 I+ W* P& W; |- @\"$\"
    - s3 K/ d) ]6 n, R; ~; l' ~% Q4 MCOMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ...". e9 k, i% s5 }6 C5 ?
    )
    ! d# V9 q- i" a3 yendfunction()5 u+ g3 m6 T: c
    if (WIN32)
    6 T$ O9 v5 ]7 J  windeployqt(${PROJECT_NAME})
    2 h" p8 H' |& ?, @  K: D. fendif()最后,转换成VS项目时,默认是Console项目,运行时会有cmd窗口。一个解决办法是在生成可执行文件时设置目标为 WIN32:
    8 _' o# Q5 `" ^$ C6 _add_executable(${PROJECT_NAME} WIN32 xxxx)
    4 X3 v5 H  d+ v: {" |' C 一个完整的Qt 5项目CMakeLists.txt返回目录以下是一个适用于Windows平台的Qt 5项目完整CMakeLists.txt,实际使用时请替换名字和Qt 5安装路径等:) `% D! W1 Q. n% N* Q
    cmake_minimum_required(VERSION 3.7)
    4 I  S7 }* e' G8 t- m; M, w# 请将myproject改成实际的应用名字
    - v4 y1 J( l- v4 ^1 Rproject(myproject LANGUAGES CXX)
    7 `3 Q% x% \% P- }- A" b4 U- a' i# Vset(CMAKE_INCLUDE_CURRENT_DIR ON)
    3 w$ q3 O' E9 A3 E* e) r  L, I9 ]& Q# 请更改为实际的Qt安装目录
    . V1 G* r$ O; ?! F8 ]! s( tset(QT_MSVC_PATH "C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64")
    0 g; `6 S" B! ]0 b5 p7 _- W2 l+ Lset(CMAKE_PREFIX_PATH "${QT_MSVC_PATH}/lib/cmake")5 p; l8 L) q/ F
    set(QT_BIN_PATH "${QT_MSVC_PATH}/bin")
    8 ~8 z* S+ t+ a! Uset(CMAKE_AUTOUIC ON)7 T$ \; ~3 F! P  V/ F5 w9 ]
    set(CMAKE_AUTOMOC ON); }% h* i4 l7 \! e2 U
    set(CMAKE_AUTORCC ON)
    # o" `: k, E/ lset(CMAKE_CXX_STANDARD 11)) N) C$ U: Y/ M1 S, v& [7 H
    set(CMAKE_CXX_STANDARD_REQUIRED ON)" Q/ G3 x6 m' B$ `5 R8 t
    find_package(Qt5 COMPONENTS Widgets REQUIRED): c' D; O) m6 n+ i4 [1 r& b
    # 默认Release构建' M4 N* y' h- N$ [
    if (NOT CMAKE_BUILD_TYPE)
    # [1 L+ \7 ^. C$ M    set( CMAKE_BUILD_TYPE "Release" )& U% \$ D& Z& a* I
    endif()1 g5 q4 {1 X0 V" k
    message("build type: ${CMAKE_BUILD_TYPE}")" q! ?  D% X' R$ x% H2 X
    # 按照自己的项目结构添加文件
    & }5 e' K0 C1 x$ j0 n# 也可使用file/aux_source_directory批量引入,注意不要引入自动生成的文件!
    7 O9 [+ G4 O! N+ c. M* B- O& Eadd_executable(${PROJECT_NAME} WIN32
    : u/ g' ?; Q; S  main.cpp
    6 ]  D. O3 @  `0 B' C6 m% t# L* c5 D$ [  mainwindow.cpp
    ( ?8 V4 I5 W" B9 D* M  mainwindow.h
    ) W8 T1 ]0 \% @# s/ y# e)* L4 X$ ~- D3 w: o- `  f
    target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)
    * \5 o. @! S# _  p8 p) gfunction(windeployqt target). W  y# M3 B  b1 M
    # POST_BUILD step
    + {$ u  [, i: ?; G; N& m0 g! zadd_custom_command(TARGET ${target} POST_BUILD
    $ h" P  Y) z% M2 @* O! FCOMMAND "${QT_BIN_PATH}/windeployqt.exe": Y3 b: j  l6 _+ T' H* ?+ H/ W) e
    --verbose 1
      c" F8 A: P+ ^0 E& [3 X( L1 M#--release
    - f" `# d% [3 w' E1 E& n) t#--no-svg6 v( U' Z- W( U8 \( \& g
    #--no-angle
    . |% g" x$ n, K% U& L8 P' B#--no-opengl
    " ~% o( I+ Q7 m% d7 C#--no-opengl-sw1 D) \2 g) b! n- F* Q  b3 }8 K
    #--no-compiler-runtime
    ! E" j( n- ~* [4 C; `#--no-system-d3d-compiler
    ( c( Z% p5 _; I$ }% U: z\"$\"# q" |* _2 g, m4 M* r1 @) q+ i
    COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."/ h5 G8 E2 G. P+ \$ w0 V
    )
    " |3 M3 p* z0 E+ {endfunction()" w! w& e8 A, h6 Y# Q: R
    if (WIN32)9 W  C- U& V5 @# l- u. o! b+ h
      windeployqt(${PROJECT_NAME})9 J, H8 R% J9 g$ I* r2 `! U% T2 j
    endif()
    " b4 q' N6 Z* s: ]& P9 ]* D````通过上面的配置,我们的Qt项目既可在Qt Creator中正常编译运行,也可在CLion/Visual Studio中正常编译运行而 无需安装Qt插件。4 |& u0 D" Y" p. d. X* O
    参考返回目录1. CMake官网
    9 Z- ]3 u# X# G0 i, q2. CMake教程
    ' F5 O+ t+ `6 }( M" Q3 [3. CMake FAQ( @* I' K, I# L$ Q# ]% k
    4. CMake指定编译器, v: K! e6 z& _" x$ v/ d2 |  r
    AD:【国外VPS推荐】 搬瓦工三网回程CN2 GIA VPS,季付46.87$打赏赞(3)
  • 本帖子中包含更多资源

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

    x
    回复

    使用道具 举报

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

    本版积分规则

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