使用CMake在工程中加入qt库

2022年4月24日 2375点热度 6人点赞 0条评论

前言

一般来说使用qt库,直接使用Qt Creator创建工程就可以了,或者使用Vs studio 中的qt tools也可以在vs中创建一个qt工程。

但大多数时候工程中依赖的第三方库,不止有qt,当依赖的第三方库比较多的情况下,直接使用Qt Creator或者是Vs studio 管理这些依赖不是一个明智的选择。

这个时候最好是使用CMake管理工程,CMake提供了良好的跨平台特性,对于第三方依赖的管理也要优雅许多。

QT 库本身就提供了对CMake的支持,在CMake中只需要简单的几行脚本就可以处理好对QT的依赖。

find_package()

find_package()的作用是通过库已经组件的名称,查找PC上已安装的库,查找的前提是这个库本身提供了对CMake的支持,一般来说需要在库目录下提供xxxx.cmake文件。

find_package(<PackageName> [version] [EXACT] [QUIET]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [CONFIG|NO_MODULE]
             [NO_POLICY_SCOPE]
             [NAMES name1 [name2 ...]]
             [CONFIGS config1 [config2 ...]]
             [HINTS path1 [path2 ... ]]
             [PATHS path1 [path2 ... ]]
             [PATH_SUFFIXES suffix1 [suffix2 ...]]
             [NO_DEFAULT_PATH]
             [NO_PACKAGE_ROOT_PATH]
             [NO_CMAKE_PATH]
             [NO_CMAKE_ENVIRONMENT_PATH]
             [NO_SYSTEM_ENVIRONMENT_PATH]
             [NO_CMAKE_PACKAGE_REGISTRY]
             [NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing.
             [NO_CMAKE_SYSTEM_PATH]
             [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
             [CMAKE_FIND_ROOT_PATH_BOTH |
              ONLY_CMAKE_FIND_ROOT_PATH |
              NO_CMAKE_FIND_ROOT_PATH])

这是函数的完整声明,不要被这一长串吓到,只用<>中的参数才是必须的,其他参数都是可选的,所以简单的使用只需要

find_package(QT)

详细的参数说明可以查看cmake的文档

如果找到依赖库,那么cmake会生成一些变量,通过这些变量可以判断查找是否成功,并且再添加C++包含目录以及链接库文件时需要的文件路径,也会再查找成功后生成,这些详细的内容文档中也有相当不错的描述。

CMAKE_PREFIX_PATH

有些情况下一台电脑上会安装多个qt版本的包,或者多个编译器版本,默认的find_package()只会按照查找顺序,依赖第一个找到的保本。

这个时候最好的做法是为了查找设置一个优先路径,CMAKE_PREFIX_PATH是一个路径的list,find_package(), find_program(), find_library(), find_file(), find_path() 这些函数都会优先在这个list中去查找。

set(QT_PATH "D:/QT/5.9.9/msvc2013_64" CACHE PATH "qt5 cmake dir")
set(CMAKE_PREFIX_PATH ${QT_PATH})

这样就可以为find_package()指定一个优先搜索的目录了,当然如果有多个路径的情况下,可以使用:

list(APPEND <list> [<element>...])

例如:

list(append CMAKE_PREFIX_PATH
    ${qt_path}
    ${vtk_pacth}
    ${boost_path}
    )

当然这里只有一个路径,用set指定一个值也是可以的。

QT的编译步骤

众所周知,Qt Creator在编译工程之前会先执行qmake,qmake不仅是生成makefile,在这之前,还需要对.ui .qrc文件进行处理,并且qt元编译也是在qmake的时候完成的,要使用信号、槽,以及qt的资源文件这些步骤都是必不可少的,那么在cmake中这些步骤应该如何实现?

QT提供一些CMake的函数,只需要在cmake脚本中调用这些函数,传入相应的文件即可。

qt5_wrap_cpp

这个函数的功能是处理需要使用QT 元编译步骤的文件,简单来说如果你的C++类中使用Q_OBJECT宏,那么就必须使用这个步骤生成对应的MOC文件,否则编译时会出现错误。

函数原型:

qt_wrap_cpp(result SourceLists ...)

result 是生成的MOC文件路径。

SourceLists 是需要元编译的头文件,可以是一个也可以是多个用空格隔开,也可以直接使用一个list作为参数。

qt5_wrap_ui

这个函数的功能是为了要通过*.ui文件生成对应的C++代码,即ui_xxxx.h文件,这个函数的使用方式与qt5_wrap_cpp() 基本相同,直接参考即可。

QT5_ADD_RESOURCES

这个函数的作用主要是将.qrc文件做处理,即生成xx_resource.cpp文件,它的原理是将.qrc中的资源文件,把文件流读取为十六进制数据,然后将这些数据作为值写入到cpp文件中,然后编译的时候会将这些值编译到工程中,所以可以在工程中直接使用.qrc中的资源文件。

这个函数的使用方式与qt5_wrap_cpp() 基本相同,直接参考即可。

因为这些生成的文件也是需要参加编译的,所以在为工程添加源文件时,必须要加上result中的文件。

示例

了解了以上信息之后,就可以尝试手动构建一个工程了

CMakeLists.txt

#设置cmake的最低版本
cmake_minimum_required(VERSION 3.10)

project(hello_camke)
#设置C++版本
set(CMAKE_CXX_STANDARD 11)

set(QT_PATH "D:/QT/5.9.9/msvc2013_64" CACHE PATH "qt5 cmake dir")

set(CMAKE_PREFIX_PATH ${QT_PATH})
#可以直接寻找QT 也可以向这样寻找QT中的单个组件
#不需要寻找所有的组件,只查找需要的即可
find_package (Qt5Core)
find_package (Qt5Widgets)
find_package (Qt5Gui)
find_package (Qt5Core)
find_package (Qt5Network)

#添加cmake build目录 以保证ui_xx.h再#includ的时候被找到
include_directories(${CMAKE_BINARY_DIR})
#添加外部库依赖目录
link_directories(${QT5_LIB_DIR})
#添加每个组件的头文件目录,方便引用
include_directories(
    ${Qt5Core_INCLUDE_DIRS}
    ${Qt5Widgets_INCLUDE_DIRS}
    ${Qt5OpenGL_INCLUDE_DIRS}
    ${Qt5PrintSupport_INCLUDE_DIRS}
    ${Qt5Svg_INCLUDE_DIRS}
    ${Qt5Network_INCLUDE_DIRS}
    ${Qt5UiTools_INCLUDE_DIRS}
 )
#需要用到的qt库
list(APPEND QT_LIB
     ${Qt5Core_LIBRARIES}
     ${Qt5Widgets_LIBRARIES}
     ${Qt5OpenGL_LIBRARIES}
     ${Qt5PrintSupport_LIBRARIES}
     ${Qt5Svg_LIBRARIES}
     ${Qt5Network_LIBRARIES}
     ${Qt5UiTools_LIBRARIES}
)

# 将源代码添加到工程
SET(SOURCES main.cpp mainWindow.h mainWindow.cpp)
qt5_wrap_cpp(MOC_SRC mainWindow.h )
qt5_wrap_ui(UI_SRC mainWindow.ui)

source_group("moc" FILES ${MOC_SRC})
source_group("ui_src" FILES ${UI_SRC})
source_group("src" FILES ${SOURCES})
#设定工程的生成方式 并添加工程源文件
add_executable(hello_camke ${SOURCES} ${UI_SRC} ${MOC_SRC})
#为工程添加依赖库链接
target_link_libraries(hello_camke ${Hello_LIB} ${QT_LIB})

大脸猫

这个人虽然很勤快,但什么也没有留下!

文章评论