原文:https://blog.csdn.net/qq_32768743/article/details/80056316 

写在前面的话:强烈建议优先阅读Qt官网文档对cmake的使用介绍——CMake Manual

前言
我去年用clion写Qt的时候,找了很多教程,也没有什么让我觉得很满意的。后来自己摸索,构建了一个我自己比较喜欢的方式。我的环境是Deepin 15.5。

在Deepin上,获取Qt环境最快的方式莫过于sudo apt install qtcreator-dde。它会帮你安装qt开发包,qt集成环境等。由于我自己非常喜欢JetBrains家的产品,如Intellij IDEA等,当它出了c++的IDE时,也非常希望能用JetBrains家的产品做Qt开发。我目前的环境是Clion 2018.1。

一个简单的案例
首先介绍一下创建一个Qt的工程,这和创建一个普通的C++工程是一样的。

接下来,我们进行Qt工程的改造。

目录结构

pikachu@pikachu-PC:~/src/Demo/QtDemo$ tree
.
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.cpp

把模板代码贴上

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(QtDemo)
add_subdirectory(src) src/CMakeLists.txt cmake_minimum_required(VERSION 3.7)
set(TARGET_NAME QtDemo)
set(CMAKE_CXX_STANDARD )
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
file(GLOB_RECURSE SOURCES "*.cpp")
file(GLOB_RECURSE HEADERS "*.h")
file(GLOB_RECURSE FORMS "*.ui")
file(GLOB_RECURSE RESOURCES "*.qrc")
find_package(PkgConfig REQUIRED)
set(QT Core Gui Widgets Network DBus Sql)
find_package(Qt5 REQUIRED ${QT})
pkg_check_modules(3rd_lib REQUIRED
dtkwidget dframeworkdbus
)
add_executable(${TARGET_NAME} ${SOURCES} ${HEADERS} ${FORMS} ${RESOURCES})
target_include_directories(${TARGET_NAME} PUBLIC ${3rd_lib_INCLUDE_DIRS} )
target_link_libraries(${TARGET_NAME} ${3rd_lib_LIBRARIES} )
qt5_use_modules(${TARGET_NAME} ${QT})
set(CMAKE_INSTALL_PREFIX /usr)
install(TARGETS ${TARGET_NAME} DESTINATION bin)

使用了DTK的模板代码

#include <DApplication>
#include <DUtil>
#include <DMainWindow>
#include <DWidgetUtil>
#include <DLog>
#include <zconf.h> DWIDGET_USE_NAMESPACE
DCORE_USE_NAMESPACE
int main(int argc, char *argv[]) {
DLogManager::registerConsoleAppender();
DLogManager::registerFileAppender();
DApplication::loadDXcbPlugin();
DApplication app(argc, argv);
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
const QString socket_path(QString("QtDemo_%1").arg(getuid()));
if (app.setSingleInstance(socket_path)) {
app.setTheme("light");
app.loadTranslator();
const QString descriptionText = QApplication::tr("A simple Qt Demo by CLion 2018.1 and CMake");
const QString acknowledgementLink = "https://github.com/PikachuHy";
app.setOrganizationName("pikachu");
app.setApplicationName("QtDemo");
app.setApplicationDisplayName(QObject::tr("Qt Demo"));
app.setApplicationVersion("1.0.0");
app.setProductName(QApplication::tr("Qt Demo"));
app.setApplicationDescription(descriptionText);
app.setApplicationAcknowledgementPage(acknowledgementLink); DMainWindow window;
window.setFixedWidth();
Dtk::Widget::moveToCenter(&window);
window.show();
return app.exec();
}
qDebug() << "app has started";
return ;
}

分析与解释

首先是目录结构,我是在根目录下又套了一个src目录,为什么这样做呢?

自然,这是有使用Qt的原因在的。Qt自己有一个moc编译器,会自动生成一些代码。下面的代码就是让Qt自动生成相关的代码,无需我们自己干预。

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

另一个是CLion本身的原因。CLion会为每个项目创建如cmake-build-debug这样的配置文件,而我常常是使用后缀名来匹配文件,如果不隔离,会导致函数重定义的问题。建立一个src目录可以很好的解决这个问题。搜索文件的代码如下

file(GLOB_RECURSE SOURCES "*.cpp")
file(GLOB_RECURSE HEADERS "*.h")
file(GLOB_RECURSE FORMS "*.ui")
file(GLOB_RECURSE RESOURCES "*.qrc")

通常,我们会用到Qt的很多模块,在cmake中怎么体现呢?我在寻找了很久后,发现了一个非常简洁的写法。你只需要在set(QT ...)这里添加你需要的模块即可。代码如下:

set(QT Core Gui Widgets Network DBus Sql)
find_package(Qt5 REQUIRED ${QT})
qt5_use_modules(${TARGET_NAME} ${QT})

嗯,看样子还是很好的。可是,使用C++,经常要用到的是它的生态,如何使用第三方库呢?在这里,我是这样定义的,先看代码:

find_package(PkgConfig REQUIRED)
pkg_check_modules(3rd_lib REQUIRED
dtkwidget dframeworkdbus
)
target_include_directories(${TARGET_NAME} PUBLIC ${3rd_lib_INCLUDE_DIRS} )
target_link_libraries(${TARGET_NAME} ${3rd_lib_LIBRARIES} )

我依赖了2个第三方的包,dtkwidget和dframeworkdbus,以及定义一个3rd_lib的变量,然后通过target_include_directories和target_link_libraries用在项目中。如果需要添加新的库,也仅仅是在pkg_check_modules(3rd_lib REQUIRED ...)中,写上你库的名字,非常方便。

如果你对QtCreator的配置文件.pro文件很熟悉的话,你会很惊讶的发现,我用CMake的写法和用pro文件的写法有诸多类似的地方。为什么呢?因为我常常需要在QtCreator和CLion两个IDE之间切换,以便我更好的利用两个IDE的优势,(QtCreator对Qt良好的支持,CLion对重构的良好支持)。

对CMakeLists.txt的介绍就到这里了,如果你对它的代码还有什么疑问,可以参考附录中的注释。

附:
CMakeLists.txt

# 需用使用的最小的CMake版本
cmake_minimum_required(VERSION 3.7)
# 本次构建的可执行文件名称
set(TARGET_NAME QtDemo)
# 本次使用C++标准版本
set(CMAKE_CXX_STANDARD )
# 字面意思,包含当前目录,可以方便开发
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 开启Qt代码自动生成,不再需用自己手写了。按顺序,分别是`Q_OBJECT`宏展开,资源文件,界面文件。
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
# 简单粗暴的把源码搜集起来。按顺序,分别是实现文件,头文件,界面文件,资源文件
file(GLOB_RECURSE SOURCES "*.cpp")
file(GLOB_RECURSE HEADERS "*.h")
file(GLOB_RECURSE FORMS "*.ui")
file(GLOB_RECURSE RESOURCES "*.qrc")
# 使用第三方库需要用到的一个包
find_package(PkgConfig REQUIRED)
# 使用Qt的模块,写法和.pro文件类似
set(QT Core Gui Widgets Network DBus Sql)
find_package(Qt5 REQUIRED ${QT})
# 使用的第三方模块
pkg_check_modules(3rd_lib REQUIRED
dtkwidget dframeworkdbus
)
add_executable(${TARGET_NAME} ${SOURCES} ${HEADERS} ${FORMS} ${RESOURCES})
target_include_directories(${TARGET_NAME} PUBLIC ${3rd_lib_INCLUDE_DIRS} )
target_link_libraries(${TARGET_NAME} ${3rd_lib_LIBRARIES} )
# 在CMake中使用Qt最快捷的方式,一句代码搞定
qt5_use_modules(${TARGET_NAME} ${QT})
# 字面意思,安装文件的前缀
set(CMAKE_INSTALL_PREFIX /usr)
# 安装可执行文件
install(TARGETS ${TARGET_NAME} DESTINATION bin)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

# 项目名
PROJECT(VRVDZWDYWTX CXX) # 增加 QT 支持
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
SET(CMAKE_AUTOMOC ON)
SET(CMAKE_AUTOUIC ON) set(CMAKE_SKIP_BUILD_RPATH FALSE)
# 帮助信息
SET(${PROJECT_NAME}_HELP_MSG "\n编译选项:
cmake -DDDM_INSTALL_PREFIX=</absolute/path> \\
-DCOMMON_SRCS=<relative/path/from/current/to/common-ddm> \\
-DPLATFROM=<RUN_ON_UBUNTU|RUN_ON_FANGDE|RUN_ON_FANGDE32|RUN_ON_YINHE|RUN_ON_ZHONGBIAO|RUN_ON_ZBx86> \\
-DCMAKE_BUILD_TYPE=<Debug|Release>\\
<relative/path/to/${PROJECT_NAME}> ") # 检查相关设置
INCLUDE (../CommonCode.cmake) ## 检查变量是否定义
IF (NOT DEFINED COMMON_SRCS)
MESSAGE(FATAL_ERROR "COMMON-DDM 源码到该 build 目录的相对路径没有指定. ${${PROJECT_NAME}_HELP_MSG}")
ENDIF() ## COMMON_DDM 项目的源码路径
SET(COMMON_PATH ${CMAKE_BINARY_DIR}/${COMMON_SRCS}) ## 设置安装路径
IF (NOT DEFINED DDM_INSTALL_PREFIX)
GET_DEFUAT_INSTALL(DDM_INSTALL_PREFIX)
ENDIF() ## 检查目标平台
IF (NOT DEFINED PLATFROM)
MESSAGE(FATAL_ERROR "没有指定目标平台。${${PROJECT_NAME}_HELP_MSG}")
ENDIF()
GET_PLATFROM(${PLATFROM} TGT_PF ${${PROJECT_NAME}_HELP_MSG})
ADD_DEFINITIONS(-D${TGT_PF})
MESSAGE(STATUS "${PROJECT_NAME} 目标平台为:${TGT_PF}") ## RPATH 设置
GET_RPATH(${TGT_PF} ${PROJECT_NAME} TGT_RPATH ${${PROJECT_NAME}_HELP_MSG})
SET(CMAKE_INSTALL_RPATH "${TGT_RPATH}")
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
MESSAGE(STATUS "${PROJECT_NAME} RPATH 为:${TGT_RPATH}") # COMMON_DDM 项目的源码路径
SET(COMMON_PATH ${CMAKE_BINARY_DIR}/${COMMON_SRCS}) # 源文件列表
SET(${PROJECT_NAME}_SRC src/main.cpp
src/server.cpp
src/webinterface.cpp
${COMMON_PATH}/common/SoImport/SoImport.cpp
${COMMON_PATH}/common/common/common.cpp)
SET(${PROJECT_NAME}_HDR src/server.h
src/webinterface.h
${COMMON_PATH}/common/SoImport/SoImport.h
${COMMON_PATH}/common/common/common.h) # RPATH
SET(CMAKE_INSTALL_RPATH "${DDM_INSTALL_PREFIX}/lib/vrvlib")
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) # 可执行程序及依赖库
FIND_PACKAGE(Qt5Widgets CONFIG REQUIRED)
FIND_PACKAGE(Qt5Gui CONFIG REQUIRED)
FIND_PACKAGE(Qt5Network CONFIG REQUIRED)
FIND_PACKAGE(Qt5Xml CONFIG REQUIRED) ADD_EXECUTABLE(${PROJECT_NAME} ${${PROJECT_NAME}_SRC} ${${PROJECT_NAME}_HDR}) TARGET_LINK_LIBRARIES(${PROJECT_NAME} Qt5::Widgets Qt5::Gui Qt5::Network Qt5::Xml)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} rt pthread) # 头文件路径
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${COMMON_PATH})
INCLUDE_DIRECTORIES(${COMMON_PATH}/common)
INCLUDE_DIRECTORIES(${COMMON_PATH}/libs) # Flags 选项
SET(CMAKE_CXX_FLAGS " -Wall")
SET(CMAKE_CXX_FLAGS_DEBUG " $ENV{CXXFLAGS} -O0 -Wall -g ") # 安装选项
INSTALL(TARGETS ${PROJECT_NAME}
DESTINATION ${DDM_INSTALL_PREFIX}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)

最新文章

  1. 解决 odoo.py: error: option --addons-path: The addons-path &#39;local-addons/&#39; does not seem to a be a valid Addons Directory!
  2. 【转帖】ActiveX部件不能创建对象的终极解决方案
  3. Python基础语法(二)
  4. .net MVC全球化资源使用心得
  5. 拷贝,集合,函数,enumerate,内置函数
  6. 第一零三天上课 PHP TP框架下控制器的方法分离
  7. 微软 PowerShell Script Explorer 满血复活,正式发布
  8. Spring中Bean的生命中期与InitializingBean和DisposableBean接口
  9. Android 开发笔记“调用.net webservice遇到的问题”
  10. python环境搭建(linux)
  11. Windows与系统信息相关的DOS命令
  12. 【2015 软件工程 个人项目 PJ1】四则运算题目生成程序
  13. Spring基础(3) : 静态工厂和实例工厂创建bean
  14. LVS的优点和缺点
  15. Homebrew替换源
  16. 自适应XAML布局经验总结 (一)原则和页面结构设计
  17. python基础学习1-装饰器在登陆模块应用
  18. js异步任务处理方式
  19. 迷你MVVM框架 avalonjs 学习教程1、引入avalon
  20. 苹果receipt样例

热门文章

  1. C++运算符重载三种形式(成员函数,友元函数,普通函数)详解
  2. WebService-01-使用jdk发布第一个WebService服务并调用
  3. Android版本分布——2017年5月更新
  4. asp.net页面传值方法汇总
  5. Linux 命令学习之rm
  6. tomcat启动(Ⅷ)--请求最终目的地 getContainer().getPipeline().getFirst().invoke(request, response)
  7. log4配置
  8. CUBA 7 新特性(上篇)
  9. c# 获取应用程序exe文件路径及退出应用程序的几种方法
  10. [转]查看SQL Server被锁的表以及如何解锁