CMakeLists能传三代,人走配置长存。
版本要求
Qt版本5.12.3,CMake版本3.22.1,vscode版本1.90.2。为什么是这么奇怪的一个版本组合,主要是因为我对Qt不了解,而据说越更新越难用。估计也用不到什么新版才有的高级特性,而5.12.3是12小版本的最后一个,也是最后直接支持mysql的版本,听起来比较诱人。
也许该经验在其他版本的Qt也能够使用,cmake版本别低于3.1.0,其他情况可以试一试。
无中生有的需求
Qt是自带一个QtCreator的。说实话,还挺好用的。单纯的不想用QtCreator,只是写Qt的时候方便一些,功能性的东西跟vscode没法比。而5.12.3该版本下的QtCreator在创建项目的时候是没有办法选择构建工具的,默认为qmake。简单体验了一下qmake,不算难用,但是cmake在易用性以外都碾压qmake,完全没法比。有趣的是,虽然在创建项目时不能选择cmake构建,在我没有额外安装任何插件的情况下,QtCreator是能正确识别和使用cmake的。这一部分未经考究,究竟是我的配置出了问题还是这个版本有通病。
文件目录
下面是我正在尝试做的一个小项目的目录结构,只选取了最简单的一部分。
目录结构的生成方式是tree
,ubuntu下直接apt
安装就好,运行起来也很方便:
cd /PATH
tree > tree.md
项目目录结构:
calculatorPro
├── CMakeLists.txt
├── include
│ ├── core
│ └── ui
│ └── mainwindow.h
├── plugins
│ └── CMakeLists.txt
└── src
├── CMakeLists.txt
├── core
│ └── CMakeLists.txt
├── main.cpp
└── ui
├── CMakeLists.txt
├── mainwindow.cpp
└── mainwindow.ui
配置文件
因为是记录向的,所以可能会比较繁琐,主要是让自己很久以后能看懂,避免称为魔法(
最初
QtCreator生成的项目,所有的文件都堆在了一起。主要是main.cpp、mainwindow.cpp、mainwindow.h、mainwindow.ui。其中mainwindow.ui
是QtCreator能直接图形化设计的基础,也是后面需要vscode+QtCreator的原因。平铺的结构看起来比较混乱,难以管理,遂尝试其他结构。
根目录
根目录的CMakeLists.txt的主要作用是铺垫和组织。
# 设置最低的 CMake 版本要求为 3.1.0
cmake_minimum_required(VERSION 3.1.0)
# 定义项目名称为 CalculatorPro,版本为 0.1.0,使用 C++ 语言
project(CalculatorPro VERSION 0.1.0 LANGUAGES CXX)
# 设置 C++ 标准为 C++11
set(CMAKE_CXX_STANDARD 11)
# 强制使用 C++11 标准,防止使用其他版本的 C++ 标准
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 指定生成的可执行文件的输出目录为 ${CMAKE_BINARY_DIR}/bin
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# 指定生成的库文件的输出目录为 ${PROJECT_BINARY_DIR}/lib
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
# 启用自动处理 Qt 的 MOC、RCC 和 UIC 文件
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
# 查找并加载 Qt5 的 Widgets 组件
find_package(Qt5 COMPONENTS Widgets REQUIRED)
# 将 Qt5Widgets 的头文件路径添加到编译器的头文件搜索路径中
include_directories(
${Qt5Widgets_INCLUDE_DIRS}
)
# 处理 include/ui/mainwindow.h 文件中的 Qt 特殊语法,生成相应的 MOC 文件
qt5_wrap_cpp(header_SRC include/ui/mainwindow.h)
# 添加项目中 core 和 ui 目录下的头文件路径到编译器的头文件搜索路径中
include_directories(
${PROJECT_SOURCE_DIR}/include/core
${PROJECT_SOURCE_DIR}/include/ui
)
# 确保所有编译的代码都是位置无关的,以满足 Qt 使用 -reduce-relocations 选项的要求。
# 自动应用 -fPIC 编译选项,减少重定位并提高性能和安全性。
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# 添加 src 目录及其 CMake 配置
add_subdirectory(src)
# 添加 plugins 目录及其 CMake 配置
add_subdirectory(${CMAKE_SOURCE_DIR}/plugins)
# 定义生成可执行文件的目标,将 main.cpp 和生成的 MOC 文件一起编译
add_executable(${PROJECT_NAME} src/main.cpp
${header_SRC}
)
# 链接目标程序所需的库,包括 core、ui、plugins 和 Qt5 Widgets 库
target_link_libraries(${PROJECT_NAME} core ui plugins Qt5::Widgets)
cmake常用变量
- CMAKE_BINARY_DIR: 表示构建目录的根目录,即生成编译文件的顶层目录。
- PROJECT_BINARY_DIR: 表示当前项目的构建目录,通常与
CMAKE_BINARY_DIR
相同。 - CMAKE_SOURCE_DIR: 表示项目源代码的根目录,即顶层的
CMakeLists.txt
文件所在的目录。 - PROJECT_SOURCE_DIR: 表示当前项目的源代码目录,通常与
CMAKE_SOURCE_DIR
相同。 - CMAKE_CURRENT_BINARY_DIR: 表示当前处理的 CMakeLists.txt 文件所在子目录的构建目录。
- CMAKE_CURRENT_SOURCE_DIR: 表示当前处理的 CMakeLists.txt 文件所在子目录的源代码目录。
- EXECUTABLE_OUTPUT_PATH: 指定生成的可执行文件的输出目录。
- LIBRARY_OUTPUT_PATH: 指定生成的库文件的输出目录。
关于部分语句
set(CMAKE_AUTOMOC ON)
moc
是 Qt 中用于处理包含 Qt 特殊宏(如Q_OBJECT
)的 C++ 头文件的工具。启用CMAKE_AUTOMOC
后,CMake 会自动查找需要使用moc
处理的头文件,并生成对应的.moc
文件,免去了手动处理的麻烦。
set(CMAKE_AUTORCC ON)
rcc
是 Qt 的资源编译器,用于将 Qt 资源文件(如图片、图标、XML 文件等)编译成 C++ 代码,以便在应用程序中以资源的方式使用。启用CMAKE_AUTORCC
后,CMake 会自动查找项目中的资源文件,并调用rcc
编译它们。
set(CMAKE_AUTOUIC ON)
uic
是 Qt 的用户界面编译器,用于将 Qt Designer 创建的.ui
文件(XML 格式)转换成相应的 C++ 代码。启用CMAKE_AUTOUIC
后,CMake 会自动查找项目中的.ui
文件,并调用uic
编译它们,生成相应的 C++ 源文件。
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
- Qt 库在构建时使用了 -reduce-relocations 选项。这个选项要求生成的位置无关代码,以减少动态链接时的重定位操作,从而提升运行效率和安全性。为了与使用 -reduce-relocations 选项的 Qt 库兼容,代码也必须是位置无关的。否则,链接器可能会出现错误,因为静态库或可执行文件中的代码无法正确与 Qt 库进行链接。设置
CMAKE_POSITION_INDEPENDENT_CODE
以确保所有编译的目标代码都使用位置无关代码。这会自动将 -fPIC 编译选项应用到所有目标中,从而满足 Qt 库的要求。
- Qt 库在构建时使用了 -reduce-relocations 选项。这个选项要求生成的位置无关代码,以减少动态链接时的重定位操作,从而提升运行效率和安全性。为了与使用 -reduce-relocations 选项的 Qt 库兼容,代码也必须是位置无关的。否则,链接器可能会出现错误,因为静态库或可执行文件中的代码无法正确与 Qt 库进行链接。设置
plugins
file(GLOB PLUGINS_SOURCES "*.cpp")
# SHARED是动态库,STATIC是静态库
add_library(plugins SHARED
${PLUGINS_SOURCES}
)
# 将头文件路径添加到目标库的包含路径中
target_include_directories(plugins PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
src
src一级的配置文件只是用来添加:
add_subdirectory(core)
add_subdirectory(ui)
src下面以ui为例:
file(GLOB UI_SOURCES "*.cpp")
file(GLOB UI_FILES "*.ui")
qt5_wrap_ui(WRAP_FILES ${UI_FILES})
#确保编译器能够找到 qt5_wrap_ui 生成的头文件,避免编译错误
include_directories(${CMAKE_BINARY_DIR}/src/ui)
add_library(ui STATIC
${UI_SOURCES}
${WRAP_FILES}
)
规划
目前先做起来,别的遇到困难再说。
评论区(暂无评论)