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