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\res 目錄已經存在,遇到這種情況,重新執行一遍 qmake,再重新編譯就好了。

雖然並不完美,但再深入就太累了。

當然還有一種思路,在 qmake 中執行已經寫好的 bat 批處理文件,然后將構建目錄作為參數傳遞給批處理文件。
時間有限,沒有實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM