找回密码
 立即注册
收起左侧

【独家连载】Qt入门与提高:KS02-06 一劳永逸:引入pri体系

0
回复
6969
查看
[复制链接]
累计签到:41 天
连续签到:1 天
来源: 原创 2018-10-7 11:07:08 显示全部楼层 |阅读模式

马上注册,查看详细内容!注册请先查看:注册须知

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 baizy77 于 2019-7-2 20:25 编辑

版权声明
---------------------------------------------------------------------------------------------------------------------
该文章原创于Qter开源社区(www.qter.org
作者: 女儿叫老白
转载请注明出处!
---------------------------------------------------------------------------------------------------------------------
网页版课程源码 提取码:1uy7
引言
----------------------------------------------------------------------------------------------------------------------
       上一节我们介绍了pri文件的作用与使用方法,在项目开发尤其是大型项目开发中,pri文件的使用是非常重要的。当我们开展不同的项目开发时,这些项目有非常多的配置项都是完全一样的。因此,建立一套完整的pri体系变得非常重要。
正文
----------------------------------------------------------------------------------------------------------------------
       一般情况下,我们会建立一套常用的pri文件,他们各自负责不同的功能,比如有的负责处理编译选项;有的负责处理目录设置。今天,我们为了方便,把这些不同的pri整合成一个文件来介绍,当然,大家也可以根据需要把这个文件拆成不同的pri文件。
       注:本节的内容默认您的项目使用gcc编译器。

       直接给出pri文件(读者也可以跳过代码直接看详细说明部分):

代码清单:
----------------------------------------------------------------------------------------------------------------------
#gui_base.pri
#########################################################################################
# 注意:此文件用于放置本次课程各子项目的公共设置,
# 在各子项目的 QT 工程文件中通过 include 语句包含
# 需要提前定义如下系统环境变量:
# TRAINDEVHOME      根目录,放置各个子模块
# TRAINBUILDTYPE    编译版本: debug|release|all
# TRAINBUILDBIT       编译位数: 32|64
#########################################################################################

# 需先通过环境变量 TRAINDEVHOME 指定开发目录
# 由于 isEmpty 函数不能直接对环境变量进行判断,所以先将其放入一个临时变量中
  1. DEVHOME = $(TRAINDEVHOME)
  2. isEmpty(DEVHOME) {
  3.        error('TRAINDEVHOME'环境变量必须被定义.)
  4. }
复制代码

# 设置变量:系统执行文件路径、库文件路径、临时文件生成路径、头文件包含路径
  1. TRAIN_BIN_PATH = $(TRAINDEVHOME)/bin
  2. TRAIN_LIB_PATH = $(TRAINDEVHOME)/lib
  3. TRAIN_OBJ_PATH = $(TRAINDEVHOME)/obj
  4. TRAIN_SRC_PATH = $(TRAINDEVHOME)/src
  5. TRAIN_UIC_PATH = $(TRAINDEVHOME)/obj/uic
  6. TRAIN_INCLUDE_PATH = $(TRAINDEVHOME)/include
复制代码
# 设置所引用的库文件的路径
  1. QMAKE_LIBDIR *= $TRAIN_LIB_PATH

  2. DEPENDPATH *=  .\
  3.               $TRAIN_INCLUDE_PATH

  4. INCLUDEPATH *=  .\
  5.               $TRAIN_INCLUDE_PATH
复制代码
#########################################################################################
#
# 不同平台的编译器设置
#
#####################################################################################################

# 获取编译 Qt 的编译器类型
  1. TRAIN_QMAKESPEC = $(QMAKESPEC)
复制代码


#UNIX + gcc下声明使用预编译头文件
  1. #GCC 3.4 及以后版本支持预编译头文件
  2. unix{
  3.        contains( TRAIN_QMAKESPEC, g++) {
  4.               CONFIG *=precompile_header
  5.        }
  6. }
复制代码

#WIN32下声明使用预编译头文件
  1. win32{
  2.        CONFIG *= precompile_header

  3.        # 去掉 strcpy 等编译警告
  4.        QMAKE_CXXFLAGS *= -wd4996
  5. }
复制代码


#UNIX下编译设置
  1. unix{
  2.        DEFINES *= unix __unix   
  3. }
复制代码


#WIN32下编译设置
  1. win32{
  2.        DEFINES *= WIN32
  3. }
复制代码


#激活 STL、RTTI、EXCEPTIONS 支持
  1. CONFIG *= stl exceptions rtti
复制代码
#激活多线程、编译警告
  1. CONFIG *= thread warn_on
复制代码
#-------------------------------------------------------
# 不同编译版本相关的配置
  1. BUILDTYPE = $(TRAINBUILDTYPE)
  2. equals(BUILDTYPE,debug){
  3.     CONFIG += debug
  4.     CONFIG -= release
  5. }
  6. equals(BUILDTYPE,release){
  7.     CONFIG += release
  8.     CONFIG -= debug
  9. }
  10. equals(BUILDTYPE,all){
  11.     CONFIG -= debug
  12.     CONFIG -= release
  13.     CONFIG += debug_and_releasebuild_all
  14. }
复制代码



# 指定代码中宏定义
  1. debug_and_release {
  2.        CONFIG(debug, debug|release) {
  3.     DEFINES += TRAIN_DEBUG
  4.        }
  5.        CONFIG(release, debug|release){
  6.     DEFINES += TRAIN_RELEASE
  7.        }
  8. } else {
  9.     debug: DEFINES += TRAIN_DEBUG
  10.     release: DEFINES +=TRAIN_RELEASE
  11. }
复制代码


#-------------------------------------------------------
# 配置系统使用的编译位数类型
  1. BUILDBIT = $(TRAINBUILDBIT)
复制代码


# 不同编译版本相关的配置
  1. equals(BUILDBIT,32){
  2.        # 扩展 32 位配置项
  3.        CONFIG *= x86
  4.        DEFINES *= TRAIN_32
  5. }
  6. equals(BUILDBIT,64){
  7.        # 扩展 64 位配置项
  8.        CONFIG *= x64
  9.        DEFINES *= TRAIN_64
  10. }
复制代码

#-------------------------------------------------------
# 指定不同编译版本中间文件目录
  1. debug_and_release {
  2.        CONFIG(debug, debug|release) {
  3.     TRAIN_OBJ_PATH = $TRAIN_OBJ_PATH/debug
  4.        }
  5.        CONFIG(release, debug|release){
  6.     TRAIN_OBJ_PATH = $TRAIN_OBJ_PATH/release
  7.        }
  8. } else {
  9.     debug:TRAIN_OBJ_PATH =$TRAIN_OBJ_PATH/debug
  10.     release:TRAIN_OBJ_PATH =$TRAIN_OBJ_PATH/release
  11. }
复制代码

----------------------------------------------------------------------------------------------------------------------
       下面我们来详细介绍一下这个pri文件。

1, 开头的声明
       首先,在pri文件开头有一个声明,指明了需要创建的环境变量。也就是说,这个pri文件依赖于环境变量值,当然,您也可以选择不用环境变量,而是通过修改pri文件中的相关内容来改变这些设置,但是使用环境变量会方便一些,因为不用每次都修改这个pri文件。
       这个pri文件用到的环境变量有3个,分别是:
       1)  TRAINDEVHOME
用来描述项目的根目录,目录结构如下:
  1. $TRAINDEVHOME
  2. ------bin                编译好的运行程序所在目录
  3. ------lib                 编译好的lib文件所在目录
  4. ------include          公共头文件目录,其下可以再分子目录
  5. ------src                源代码根目录
  6. ------temp             临时文件目录
复制代码

2) TRAINBUILDTYPE
编译版本,取值:
debug           编译debug版本
release           编译release版本
all                  同时编译debug、release版本,即两个版本都编译。
3) TRAINBUILDBIT   
编译位数,取值:
32                 编译成32位程序
64                 编译成64位程序
       当然了,QTDIR、QMAKESPEC是安装完Qt后必不可少的环境变量,本文不再赘述。
2)  环境变量检查
代码清单:
  1. DEVHOME = $(TRAINDEVHOME)
  2. isEmpty(DEVHOME) {
  3.        error('TRAINDEVHOME'环境变量必须被定义.)
  4. }
复制代码

       通过Qt的isEmpty()函数判断环境变量是否存在,如果为空,则输出错误信息并退出。
       因为isEmpty()只能使用自定义变量而无法使用环境变量,因此我们先定义了DEVHOME这个变量并赋值为环境变量值,然后用它进行判断。
3)  公共目录
代码清单:
----------------------------------------------------------------------------------------------------------------------
# 设置变量:系统执行文件路径、库文件路径、临时文件生成路径、头文件包含路径
  1. TRAIN_BIN_PATH = $(TRAINDEVHOME)/bin
  2. TRAIN_LIB_PATH = $(TRAINDEVHOME)/lib
  3. TRAIN_OBJ_PATH = $(TRAINDEVHOME)/obj
  4. TRAIN_SRC_PATH = $(TRAINDEVHOME)/src
  5. TRAIN_UIC_PATH = $(TRAINDEVHOME)/obj/uic
  6. TRAIN_INCLUDE_PATH = $(TRAINDEVHOME)/include
复制代码


# 设置所引用的库文件的路径
  1. QMAKE_LIBDIR *= $TRAIN_LIB_PATH
复制代码
       这里定义了可执行程序目录等路径,都依赖于TRAINDEVHOME环境变量,如果您不想用环境变量,可以使用自定义变量来替换(需要注意自定义变量的语法跟环境变量不同)。
       上述变量都是公共路径设置,在pro中引用本pri文件后,还可以继续对这些变量值进行引用加工(比如继续追加目录层级),从这些变量的名称就可以对其用途略知一二,现在我们分别看一下:
  1. TRAIN_BIN_PATH        编译完成的可执行程序的存放路径
  2.        TRAIN_LIB_PATH        编译完成的lib文件的存放路径
  3.        TRAIN_OBJ_PATH       编译产生的临时文件的根目录
  4.        TRAIN_SRC_PATH       源代码的根目录
  5.        TRAIN_UIC_PATH        编译ui文件产生的临时文件根目录(可以看出是obj目录的子目录)
复制代码
   下面依次介绍:
    TRAIN_INCLUDE_PATH      项目的公共include目录
    QMAKE_LIBDIR           Qt关键字,设置所引用的库文件的路径(编译exe时如果用到了dll文件,那么这个变量用来告诉编译器到哪个目录去找所需的lib文件)
    DEPENDPATH              Qt关键字,用来指明所依赖的头文件路径
    INCLUDEPATH             Qt关键字,用来告诉编译器头文件的搜索目录。
    这样的话,在源代码中引用头文件时,就可以直接写文件名或者
    相对路径,比如:
  1. #include"header.h"
复制代码
    此处的目录是相对于INCLUDEPATH,也就是:
  1. $INCLUDEPATH/base/basedll/header.h
复制代码
4)  编译器设置
代码清单:
  1. # 获取编译 Qt 的编译器类型
  2. TRAIN_QMAKESPEC = $(QMAKESPEC)

  3. #UNIX + gcc下声明使用预编译头文件
  4. #GCC 3.4 及以后版本支持预编译头文件
  5. unix{
  6.     contains( TRAIN_QMAKESPEC, g++) {
  7.         CONFIG *=precompile_header
复制代码
    本部分内容用来处理预编译头文件的内容,gcc3.4及以后的版本支持预编译头文件。为了判断gcc编译器,我们使用了Qt的contains()函数,该函数也无法识别环境变量,因此我们定义了变量TRAIN_QMAKESPEC,当unix(linux也走pri中的unix分支)的编译器为gcc时,CONFIG配置项就增加了预编译头文件的支持:
  1. CONFIG *= precompile_header
复制代码
    windows下(pri中的win32分支,win32是Qt的关键字)默认提供预编译头文件支持,因此无条件增加precompile_header的选项。
为了消除strcpy造成的4996编译警告,我们增加如下语句:      
  1. QMAKE_CXXFLAGS *= -wd4996
复制代码
5)  宏定义
代码清单:
  1. #UNIX下编译设置
  2. unix{
  3.     DEFINES *= unix __unix   
  4. }

  5. #WIN32下编译设置
  6. win32{
  7.     DEFINES *= WIN32
  8. }
复制代码

在代码中,我们经常需要判断当前运行程序的操作系统类型,因此需要预先定义操作系统类型宏,上述代码就给出了在unix以及windows下的定义操作系统类型宏的方法,使用了DEFINES语法,这样在源代码中,我们就可以直接使用这些宏进行判断了。本部分内容在上节进行过讲解,这里不再展开。

6)  激活stl、rtti、exceptions支持
代码清单:
  1. #激活 STL、RTTI、EXCEPTIONS 支持
  2. CONFIG *= stl exceptions rtti
复制代码
       如果您使用stl库,那么请激活stl支持。
       如果您使用异常处理,那么请激活exceptions。
       如果您需要运行时类型识别,那么请激活rtti。
       这些选项都是CONFIG配置项,可以单独配置。

7)  激活多线程,编译
代码清单:
  1. #激活多线程、编译警告
  2. CONFIG *= thread warn_on
复制代码
    如果您的项目中用到多线程,请激活thread。因为本pri文件是公共pri,所以如果您的某个子模块用不到多线程支持,您可以在子模块的pro中禁用多线程,方法是在子模块的pro中使用如下语句:
  1. CONFIG -= thread
复制代码
8)  编译成debug版还是release版本
代码清单:
# 不同编译版本相关的配置
  1. BUILDTYPE = $(TRAINBUILDTYPE)
  2. equals(BUILDTYPE,debug){
  3.     CONFIG += debug
  4.     CONFIG -= release
  5. }
  6. equals(BUILDTYPE,release){
  7.     CONFIG += release
  8.     CONFIG -= debug
  9. }
  10. equals(BUILDTYPE,all){
  11.     CONFIG -= debug
  12.     CONFIG -= release
  13.     CONFIG += debug_and_releasebuild_all
  14. }
复制代码

       如果需要对我们的程序进行调试,我们会选择debug版本,因为debug版的程序含有很多调试信息,而如果我们需要发布版则使用release版本,因为它的执行效率更高运行更快。此处我们使用了Qt的equals()函数来判断编译版本。同样这个函数也不识别环境变量,因此我们定义了BUILDTYPE变量来进行判断。请注意,equals()函数中的第二个参数中的debug、release只是个字符串,下列语句中的debug、release才是Qt的关键字。
  1. CONFIG+=debug
  2. CONFIG -= release
复制代码
9)  程序运行时如何区分debug版还是releaes版
       有时候,我们在程序运行过程中,需要知道自己是debug版还是release版,该怎么做呢:

代码清单:
# 指定代码中宏定义
  1. debug_and_release {
  2.        CONFIG(debug, debug|release) {
  3.     DEFINES += TRAIN_DEBUG
  4.        }
  5.        CONFIG(release, debug|release){
  6.     DEFINES += TRAIN_RELEASE
  7.        }
  8. } else {
  9.     debug: DEFINES += TRAIN_DEBUG
  10.     release: DEFINES +=TRAIN_RELEASE
  11. }
复制代码

       上述语法是分支判断语法,其{}前面的字符串是CONFIG的配置项,比如此处的debug_and_release。我们使用上述方法得知当前编译版本并定义了相关的宏TRAIN_DEBUG、TRAIN_RELEASE,这样在源代码中就可以直接用这两个宏来区分debug版与release版本了。请大家务必注意下列代码的语法:      
  1. CONFIG(debug, debug|release)
复制代码
       上述语句用来判断是否正在编译debug版本。     
  1. CONFIG(release, debug|release)
复制代码
       上述语句用来判断是否正在编译release版本。

       而下面的语句用来区分debug编译分支可release编译分支,方法是在debug或者release后使用冒号:
  1. debug: DEFINES += TRAIN_DEBUG
  2. release: DEFINES += TRAIN_RELEASE
复制代码

10)  程序运行时如何区分32位程序还是64位程序
       程序运行的时候,有可能需要知道自己被编译成了32位还是64位,方法如下:

代码清单:
  1. #-------------------------------------------------------
  2. # 配置系统使用的编译位数类型
  3. BUILDBIT = $(TRAINBUILDBIT)

  4. # 不同编译版本相关的配置
  5. equals(BUILDBIT,32){
  6.     # 扩展 32 位配置项
  7.     CONFIG *= x86
  8.     DEFINES *= TRAIN_32
  9. }
  10. equals(BUILDBIT,64){
  11.     # 扩展 64 位配置项
  12.     CONFIG *= x64
  13.     DEFINES *= TRAIN_64
  14. }
复制代码

       方法与区分debug版本还是release版本类似,因此不再详述。

11)  区分debug版本、release版本的临时文件
       编译程序时,编译同一个项目的debug版本与release版本会产生不同的临时文件,我们当然不希望这些临时文件会相互覆盖,因此我们需要为它们指定不同的目录:

代码清单:
  1. # 指定不同编译版本中间文件目录
  2. debug_and_release {
  3.     CONFIG(debug, debug|release) {
  4.         TRAIN_OBJ_PATH = $TRAIN_OBJ_PATH/debug
复制代码
       从上述代码可以看出,debug版本与release版本产生的临时文件分别存放到obj下面的debug目录、release目录,这样就不会相互覆盖了。

结语
----------------------------------------------------------------------------------------------------------------------
       本节详细介绍了如何为项目引入pri体系并且使它正常运转起来。本文提到的pri使用了比较多的配置项,大家可以根据个人的需求调整其中的配置项。但是其中最常被修改的可能也就下面3个:
TRAINDEVHOME  根目录,放置各个子模块
TRAINBUILDTYPE 编译版本: debug|release|all
TRAINBUILDBIT   编译位数: 32|64
       原因就是使用者可能根据自己的项目需求创建了不同的环境变量名,或者干脆不用环境变量仅仅使用自定义变量。如果仅仅使用自定义变量,那么就需要将本pri中所有使用环境变量的地方改成使用自定义变量,而且一定要注意自定义变量的使用语法跟环境变量不同:
       环境变量: $$(环境变量名)
       变量:     $$变量名
       内容比较多,大家慢慢消化吧。

上一节: KS02-05   pri 文件有啥用?
下一节: KS02-07   还是不知道pri咋用?来练练手吧

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了