zoukankan      html  css  js  c++  java
  • Qmake 配置自定义编译过程

    Qmake 配置自定义编译过程

    需求:动态更换资源文件

    在 Windows10 下编写 Qt 项目时,有这样的需求:

    • 程序用到的资源文件可以动态更换而不需要重新编译整个项目

    解决方案 0.1

    将所有的资源文件全部放到 qrc 文件中,由 Qt 负责管理资源文件。

    但是这种方法在每次更改了 res 中的文件后都需要重新编译程序。比较麻烦。

    新的需求

    于是需求变成了:

    • 将源代码目录下的 res 文件夹下的 xml 文件全部复制到编译好的程序同级目录下

    解决方案 1.0

    最初的解决方案是在 res 目录下编写一个批处理文件:update.bat,然后每次更新了 xml 文件后,
    手动执行这个批处理文件。由于 xml 文件写好后基本上不需要怎么修改,所以写完代码后在自己的环境中
    运行起来没有问题,不会出现程序运行时找不到 xml 文件的情况。

    该批处理文件的内容如下:

    mkdir ../../build-DEMO-Desktop_Qt_5_6_3_MSVC2015_64bit-Debug/debug/res
    copy /y *.xml ../../build-DEMO-Desktop_Qt_5_6_3_MSVC2015_64bit-Debug/debug/res
    mkdir ../../build-DEMO-Desktop_Qt_5_6_3_MSVC2015_64bit-Release/realse/res
    copy /y *.xml ../../build-DEMO-Desktop_Qt_5_6_3_MSVC2015_64bit-Release/realse/res
    

    思路是这样的:

    1. 首先创建相应的目录
    2. 将项目下面所有的 xml 文件复制到指定的目录

    在我的电脑环境中运行正常,但是问题很明显,如果我换了编译器,或者更换了构建目录,我就得去批处理文件中添加两行代码,
    而且还得把所有的文件复制到好几个目录下面。非常麻烦!

    我在把源代码拷给别人的时候,由于别人用的编译器是 MinGW 编译器,结果我的批处理文件没有办法直接使用。
    所以在别人的编译环境中生成的程序由于缺少资源文件,程序运行不正常。

    那么我需要找到一种方法,得到 Qt 构建项目的目录,并将需要的资源文件复制到相应目录下。

    解决方案 2.0

    QtCreator 编译项目时,IDE 会调用 qmake 根据项目 .pro 文件自动生成一个 Makefile
    然后 IDE 就能根据这个 Makefile 对项目进行编译处理。

    经过一番搜索,在 stackoverflow 上搜到了可用的内容,然后我在 .pro 文件末尾添加了这些内容(修改了部分内容):

    DESTDIR = $$OUT_PWD
    defineTest(resToDestdir) {
        files = $$1
    
        for(FILE, files) {
            DDIR = $$RAWDDIR
            
            # Replace slashes in paths with backslashes for Windows
            win32:DDIR ~= s,/,\,g
            win32:FILE ~= s,/,\,g
    
            QMAKE_POST_LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DDIR) $$escape_expand(\n\t)
        }
    
        export(QMAKE_POST_LINK)
        return(true)
    }
    
    # update xml files into proper folder
    XML_FILES = $$PWD/res/*.xml
    
    ## note, if there is something wrong when compiling, annote following sentence
    resToDestdir($$XML_FILES)
    

    Qt 官方文档 里对这些用到的变量都有说明。
    这里简单说一下。

    • DESTDIR: 指定放置 target 文件的位置
    • QMAKE_POST_LINK: 在链接 TARGET 后指定要执行的命令
    • export(variablename): 将 variablename 在函数的局域上下文中的值导出到全局上下文
    • defineTest:定义一个测试函数,以便复用代码(尽管这里并没有复用代码:))

    经过几次尝试后,发现要运行 .pro 文件中的这段代码需要每次都重新编译。因为直接在 QtCreator 中点击编译会先比较
    文件,如果没有更改源文件(或者说被依赖文件没有更新,那么编译就可以跳过)。而且每次更改了 .pro 文件都需要先运行
    一次 qmake,确保 Makefile 是最新的。

    解决方案 2.9

    我对代码进行了修改,添加了创建目录的语句,并用 exists 函数判断是否存在目录,如果不存在就创建。

    在 Windows 上,目录分隔符是反斜杠 "" ,因此直接利用 win32:DDIR 进行判断是否存在相应目录, exists 函数返回的都是 false。

    官方文档 对此已经有说明了:

    Note: "/" should be used as a directory separator, regardless of the platform in use.

    即:

    注意: 目录分隔符应该用 “/” ,不论你用的是什么平台。

    所以判断目录是否已经存在需要用最开始的斜杠分隔符,但是创建目录的命令还是要用反斜杠(调用的是 Windows 的命令行)。

    最终修改后的 qmake 代码:

    #-----------------------------------
    # @author BriFuture
    # @details this is used for automated build
    #
    # Copies the given files to the destination directory
    #-----------------------------------
    
    ## set destdir
    DESTDIR = $$OUT_PWD
    defineTest(resToDestdir) {
        files = $$1
        ddir  = $$2
    
        for(FILE, files) {
            # Replace slashes in paths with backslashes for Windows
            DDIR = $$DESTDIR/$$ddir
            ## if res folder is created, then no need to exec mkdir
            ## note, whatever the platform you are using( Windows, Linux, Mac),
            ## the directory seperator must be slash "/"
            !exists($$DDIR) {
                log($$DDIR not  exists)
                mkpath($$DDIR)
            }
            win32:DDIR ~= s,/,\,g
            win32:FILE ~= s,/,\,g
    
            QMAKE_POST_LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DDIR) $$escape_expand(\n\t)
    #        QMAKE_POST_LINK += echo $$FILE $$escape_expand(\n\t)
    #        message(FILE $$FILE)
        }
    
    #    QMAKE_POST_LINK += echo $$quote($$PWD  == $$DESTDIR)
    #    message(LINK: $$QMAKE_POST_LINK)
        export(QMAKE_POST_LINK)
        return(true)
    }
    
    # update xml files into proper folder
    XML_FILES = $$PWD/res/*.xml
    
    ## note, if there is something wrong when compiling, annote following sentence
    resToDestdir($$XML_FILES, res)
    

    总结

    最终这个代码可以完美的复制需要的资源文件到指定的目录下,但是还有一些小 bug,偶尔编译时会报错:
    mkdir ..debug es 目录已经存在,遇到这种情况,重新执行一遍 qmake,再重新编译就好了。

    虽然并不完美,但再深入就太累了。

    当然还有一种思路,在 qmake 中执行已经写好的 bat 批处理文件,然后将构建目录作为参数传递给批处理文件。
    时间有限,没有实现。

    本博客由 BriFuture 原创,并在个人博客(WordPress构建) BriFuture's Blog 上发布。欢迎访问。
    欢迎遵照 CC-BY-NC-SA 协议规定转载,请在正文中标注并保留本人信息。
  • 相关阅读:
    jQuery插件实践之轮播练习(二)
    jQuery插件实践之轮播练习(一)
    AngularJS+Node.js+socket.io 开发在线聊天室
    Ubuntu上部署Ghost博客
    综合架构的简述
    进程
    路由配置
    计算机专用英语词汇1695个词汇表
    Linux打包压缩解压工具
    磁盘知识体系结构
  • 原文地址:https://www.cnblogs.com/brifuture/p/8635317.html
Copyright © 2011-2022 走看看