前言
一般来说使用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})
文章评论