1

学习QT系列2 - CMake

 1 year ago
source link: https://blog.devwiki.net/2023/07/04/study-qt-2-cmake.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

1. QT 构建系统


我们在创建QT项目时,可以选择的构建系统有三种, 目前最新版默认为 CMake

  • qmake : 为 Qt 量身打造的,使用起来非常方便,单设计相对简陋,难于继续扩展。
  • CMake:C++ 项目通用的构建工具,虽用起来不太友好, 但是生态完善,功能全面。
  • Qbs :Qt Build Suite, 号称新一代的构建工具,比qmake 快,官方称因市场原因弃用。

202211272248715.png

从QT4.9 开始弃用 Qbs,从QT6 开始以CMake 为重点。

2. CMake下载安装


官方下载地址为:Download | CMake,根据自己的平台选择安装包。 本文使用的是windows平台,使用安装版本可在安装过程选择加入Path路径, 如果使用免安装则需要手动加入Path 路径。

202212022007927.png

202212022001332.png

配置好后打开命令行, 输入: cmake, 可以查看到提示, 说明配置正常.

$ cmake
Usage

  cmake [options] <path-to-source>
  cmake [options] <path-to-existing-build>
  cmake [options] -S <path-to-source> -B <path-to-build>

Specify a source directory to (re-)generate a build system for it in the
current working directory.  Specify an existing build directory to
re-generate its build system.

Run 'cmake --help' for more information.

3. CMake的使用


CMake官方提供的使用教程:CMake Tutorial — CMake 3.25.1 Documentation,原文为英文教程, 如果英文比较好可以直接阅读。 本文也是依据该教程来学习使用 CMake,逐步学习。

可以从官网下载代码压缩包, 也可以 clone 此项目: DevWiki/cmake-3.25.1-tutorial-source - cmake-3.25.1-tutorial-source - DevWiki Gitea

可以使用 VS 打开此项目:

202212112139141.png

3.1 CMakeLists 变量篇

我们可以使用 SET(set) 来定义变量

语法SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

指令功能 : 用来显式的定义变量

例子 : SET (SRC_LST main.c other.c)

说明: 用变量代替值,例子中定义 SRC_LST 代替后面的字符串。

我们可以使用 ${NAME} 来获取变量的名称。

cmake 目录变量

环境变量名描述
CMAKE_BINARY_DIR, PROJECT_BINARY_DIR, <projectname>_BINARY_DIR如果是 in source 编译,指得就是工程顶层目录,如果是 out-of-source 编译,指的是工程编译发生的目录。PROJECT_BINARY_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。
CMAKE_SOURCE_DIR, PROJECT_SOURCE_DIR, <projectname>_SOURCE_DIR工程顶层目录。
CMAKE_CURRENT_SOURCE_DIR当前处理的 CMakeLists.txt 所在的路径,比如上面我们提到的 src 子目录。
CMAKE_CURRRENT_BINARY_DIR如果是 in-source 编译,它跟 CMAKE_CURRENT_SOURCE_DIR 一致,如果是 out-of-source 编译,他指的是 target 编译目录。
EXECUTABLE_OUTPUT_PATH , LIBRARY_OUTPUT_PATH最终目标文件存放的路径。
PROJECT_NAME通过 PROJECT 指令定义的项目名称。

cmake 系统信息

系统信息变量名描述
CMAKE_MAJOR_VERSIONCMAKE 主版本号,比如 2.4.6 中的 2
CMAKE_MINOR_VERSIONCMAKE 次版本号,比如 2.4.6 中的 4
CMAKE_PATCH_VERSIONCMAKE 补丁等级,比如 2.4.6 中的 6
CMAKE_SYSTEM系统名称,比如 Linux-2.6.22
CMAKE_SYSTEM_NAME不包含版本的系统名,比如 Linux
CMAKE_SYSTEM_VERSION系统版本,比如 2.6.22
CMAKE_SYSTEM_PROCESSOR处理器名称,比如 i686.
UNIX在所有的类 UNIX 平台为 TRUE,包括 OS X 和 cygwin
WIN32在所有的 win32 平台为 TRUE,包括 cygwin

cmake 编译选项

编译控制开关名描述
BUILD_SHARED_LIBS使用 ADD_LIBRARY 时生成动态库
BUILD_STATIC_LIBS使用 ADD_LIBRARY 时生成静态库
CMAKE_C_FLAGS设置 C 编译选项,也可以通过指令 ADD_DEFINITIONS()添加。
CMAKE_CXX_FLAGS设置 C++编译选项,也可以通过指令 ADD_DEFINITIONS()添加。

3.2 CMake 常用指令

  • ADD_DEFINITIONS
语法 : ADD_DEFINITIONS(-DENABLE_DEBUG -DABC)

向 C/C++编译器添加 -D 定义. 如果你的代码中定义了#ifdef ENABLE_DEBUG #endif,这个代码块就会生效。

  • ADD_DEPENDENCIES

语法: ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)

定义 target 依赖的其他 target, 确保在编译本 target 之前,其他的 target 已经被构建。

  • AUX_SOURCE_DIRECTORY
语法 : AUX_SOURCE_DIRECTORY(dir VARIABLE)

作用是发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前 cmake 还不能自动发现新添加的源文件。

AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(main ${SRC_LIST})
  • ADD_SUBDIRECTORY
语法 : ADD_SUBDIRECTORY(NAME)

添加一个文件夹进行编译,该文件夹下的 CMakeLists.txt 负责编译该文件夹下的源码. NAME是想对于调用add_subdirectory的CMakeListst.txt的相对路径.

  • find_package
语法 : find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] [components...]] [OPTIONAL_COMPONENTS components...] [NO_POLICY_SCOPE])

查找并从外部项目加载设置。 <PackageName>_FOUND 将设置为指示是否找到该软件包。 找到软件包后,将通过软件包本身记录的变量和“导入的目标”提供特定于软件包的信息。 该QUIET选项禁用信息性消息,包括那些如果未找到则表示无法找到软件包的消息REQUIRED`。REQUIRED`如果找不到软件包,该选项将停止处理并显示一条错误消息。

COMPONENTS选件后(或REQUIRED选件后,如果有的话)可能会列出所需组件的特定于包装的列表 。后面可能会列出其他可选组件OPTIONAL_COMPONENTS。可用组件及其对是否认为找到包的影响由目标包定义。

  • include_directories
语法 : include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

将给定目录添加到编译器用来搜索包含文件的目录中。相对路径被解释为相对于当前源目录。

包含目录添加到 INCLUDE_DIRECTORIES 当前CMakeLists文件的目录属性。它们也被添加到INCLUDE_DIRECTORIES当前CMakeLists文件中每个目标的target属性。目标属性值是生成器使用的属性值。

  • link_libraries
语法 : link_libraries([item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)

将库链接到以后添加的所有目标。

  • ADD_EXECUTABLE
语法 : ADD_EXECUTABLE(<name> [source1] [source2 ...])

利用源码文件生成目标可执行程序。

  • ADD_LIBRARY
语法 : ADD_LIBRARY(<name> [STATIC | SHARED | MODULE] [source1] [source2 ...])

根据源码文件生成目标库。

STATIC,SHARED 或者 MODULE 可以指定要创建的库的类型。 STATIC库是链接其他目标时使用的目标文件的存档。 SHARED库是动态链接的,并在运行时加载

  • ENABLE_TESTING
语法: ENABLE_TESTING().

控制 Makefile 是否构建 test 目标,涉及工程所有目录。 一般情况这个指令放在工程的主CMakeLists.txt 中.

  • ADD_TEST
语法 : ADD_TEST(testname Exename arg1 arg2 ...)

testname 是自定义的 test 名称,Exename 可以是构建的目标文件也可以是外部脚本等等。 后面连接传递给可执行文件的参数。 如果没有在同一个 CMakeLists.txt 中打开ENABLE_TESTING()指令, 任何 ADD_TEST 都是无效的。

  • CMAKE_MINIMUM_REQUIRED
语法 : CMAKE_MINIMUM_REQUIRED

定义 cmake 的最低兼容版本 比如 CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR) 如果 cmake 版本小与 2.5,则出现严重错误,整个过程中止。

  • EXEC_PROGRAM

在 CMakeLists.txt 处理过程中执行命令,并不会在生成的 Makefile 中执行。 具体语法为:

EXEC_PROGRAM(Executable [directory in which to run]
                [ARGS <arguments to executable>]
                [OUTPUT_VARIABLE <var>]
                [RETURN_VALUE <var>])

用于在指定的目录运行某个程序,通过 ARGS 添加参数,如果要获取输出和返回值,可通过OUTPUT_VARIABLE 和 RETURN_VALUE 分别定义两个变量.

这个指令可以帮助你在 CMakeLists.txt 处理过程中支持任何命令,比如根据系统情况去修改代码文件等等。

  • FILE 指令

文件操作指令

 FILE(WRITE filename "message to write"... )
 FILE(APPEND filename "message to write"... )
 FILE(READ filename variable)
 FILE(GLOB variable [RELATIVE path] [globbing expression_r_rs]...)
 FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expression_r_rs]...)
 FILE(REMOVE [directory]...)
 FILE(REMOVE_RECURSE [directory]...)
 FILE(MAKE_DIRECTORY [directory]...)
 FILE(RELATIVE_PATH variable directory file)
 FILE(TO_CMAKE_PATH path result)
 FILE(TO_NATIVE_PATH path result)

3.3 CMake 控制指令

  • IF 指令
if(<condition>)
  <commands>
elseif(<condition>) # optional block, can be repeated
  <commands>
else()              # optional block
  <commands>
endif()

#####

IF(var),如果变量不是:空,0,N, NO, OFF, FALSE, NOTFOUND 或<var>_NOTFOUND 时,表达式为真。
IF(NOT var ),与上述条件相反。
IF(var1 AND var2),当两个变量都为真是为真。
IF(var1 OR var2),当两个变量其中一个为真时为真。
IF(COMMAND cmd),当给定的 cmd 确实是命令并可以调用是为真。
IF(EXISTS dir)或者 IF(EXISTS file),当目录名或者文件名存在时为真。
IF(file1 IS_NEWER_THAN file2),当 file1 比 file2 新,或者 file1/file2 其中有一个不存在时为真,文件名请使用完整路径。
IF(IS_DIRECTORY dirname),当 dirname 是目录时,为真。
IF(variable MATCHES regex)
IF(string MATCHES regex)
  • FOREACH 指令
foreach(<loop_var> <items>)
  <commands>
endforeach()

其中<items>是以分号或空格分隔的项目列表。记录foreach匹配和匹配之间的所有命令endforeach而不调用。 一旦endforeach评估,命令的记录列表中的每个项目调用一次<items>。在每次迭代开始时,变量loop_var将设置为当前项的值。

  • WHILE 指令
while(<condition>)
  <commands>
endwhile()

while和匹配之间的所有命令 endwhile()被记录而不被调用。 一旦endwhile()如果被评估,则只要为<condition>真,就会调用记录的命令列表。

CMake 不仅仅用于 QT项目, 也在很多C++项目中使用, 学习CMake 是学习 C++ 和 QT 的基础。

本文主要内容参考:

如果你觉得本文对你有帮助,欢迎点赞。或者添加我的微信:【dev-wiki】进群交流学习。

WeiXin-DevWiki-Common.jpg

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK