qt creator原始碼全方面分析(3)
目錄
- qtcreator.pro
- 包含qtcreator.pri
- include(filename)
- Qt版本判斷
- message(string)
- $$運算子
- error(string)
- 包含doc.pri
- 原始碼組織架構
- TEMPLATE
- SUBDIRS
- 指定dist檔案列表
- DISTFILES
- files(pattern[, recursive=false])
- Replace Functions概述
- qbs配置
- exists(filename)
- Test Functions概述
- 指定架構和平臺
- contains(variablename, value)
- Scopes
- 指定基礎名
- 指定linux平臺安裝內容
- INSTALLS
- Installing Files
- 指定其他平臺安裝內容
- INSTALL_ROOT
- QTC_PREFIX
- PWD
- OUT_PWD
- TARGET
- QMAKE_EXTRA_TARGETS
- Adding Custom Targets
- 指定安裝存檔
- Operators
- 指定額外構建目標
- 包含qtcreator.pri
qtcreator.pro
首先我們來學習根專案檔案qtcreator.pro。
包含qtcreator.pri
qtcreator.pro第一行為
include(qtcreator.pri)
include(filename)
包含filename指定的檔案內容到當前專案中。 如果filename被包含,則此函式執行成功; 否則失敗。 被包含的檔案將立即被解析。
將此函式作為某個作用域的判斷條件,可以檢查是否成功包含檔案。 例如:
include( shared.pri ) OPTIONS = standard custom !include( options.pri ) { message( "No custom build options specified" ) OPTIONS -= custom }
我們學習過C/C++,這和#include
非常相似。
qtcreator.pri
中定義了很多巨集和通用操作。定義在pri中的函式,必須先include
後pro才能使用。qmake處理pro和pri檔案是線性從上往下解析的。對比C/C++,我們可以認為pri檔案是標頭檔案,pro檔案是原始檔。
如果你使用 Qt Creator 開啟專案,你會發現include
語句會在專案樹的左側顯示一個節點。這種節點只需要include
不同的 pri 檔案即可,是虛擬目錄節點,使專案結構層次看起來清晰很多。
有關qtcreator.pri的內容,請見下節。
Qt版本判斷
接下來是
\#version check qt
!minQtVersion(5, 6, 2) {
message("Cannot build $$IDE_DISPLAY_NAME with Qt version $${QT_VERSION}.")
error("Use at least Qt 5.6.2.")
}
minQtVersion()
顧名思義是最小Qt版本的意思,函式定義在qtcreator.pri
中。當 Qt 的版本低於5.6.2
時,minQtVersion()返回false,!
取反則為true,因此會執行塊中的操作。
message(string)
函式執行不會失敗,並將string作為常規訊息顯示給使用者。 與error()函式不同,此函式允許qmake繼續往下處理。
message( "This is a message" )
上一行導致"This is a message"被寫入控制檯。引號的使用是可選的,但建議使用。
注意:預設情況下,訊息被寫入qmake為給定專案生成的每個Makefile中。 如果要確保訊息在每個專案中僅出現一次,在作用域中聯合使用build_pass變數測試,用於構建時過濾掉訊息。例如:
!build_pass:message( "This is a message" )
這裡輸出的是"Cannot build $$IDE_DISPLAY_NAME with Qt version $${QT_VERSION}.",其中$${QT_VERSION}是佔位符,會使用QT_VERSION
變數的內容進行替換。
$$運算子
Variable
專案檔案中使用的許多變數是特殊變數,用於qmake生成Makefile時使用,例如DEFINES,SOURCES和HEADERS。另外,您可以建立自己的變數。在給某個名稱賦值時,qmake使用該名稱建立新變數。例如:
MY_VARIABLE = value
您可以對自己的變數執行任何操作,因為qmake會忽略它們,除非在處理作用域時需要評估它們。
您還可以通過在變數名稱前新增$$來將當前變數的值分配給另一個變數。例如:
MY_DEFINES = $$DEFINES
現在,MY_DEFINES變數包含了此時DEFINES變數的內容。這也等效於:
MY_DEFINES = $${DEFINES}
第二種表示法允許您將變數的內容附加到另一個值,而不用空格將兩者分開。例如,以下內容將確保為最終的可執行檔案指定一個名稱,其中包括正在使用的專案模板:
TARGET = myproject_$${TEMPLATE}
Variable Expansion
$$運算子用於提取變數的內容,並可用於在變數之間傳遞值或將其提供給函式:
EVERYTHING = $$SOURCES $$HEADERS message("The project contains the following files:") message($$EVERYTHING)
變數可用於儲存環境變數的內容。可以在執行qmake時對其進行評估,或者包含到專案構建時生成的Makefile中進行評估。
要在執行qmake時,獲取環境變數值的內容,請使用
$$(...)
運算子:DESTDIR = $$(PWD) message(The project will be installed in $$DESTDIR)
在上述賦值中,當處理專案檔案時,PWD環境變數的值被讀取。
要在生成的Makefile被處理時,獲取環境變數值的內容,請使用
$(...)
運算子:DESTDIR = $$(PWD) message(The project will be installed in $$DESTDIR) DESTDIR = $(PWD) message(The project will be installed in the value of PWD) message(when the Makefile is processed.)
在上述賦值中,當處理專案檔案時,PWD的值被立即讀取,但是$(PWD)被賦值給生成的Makefile中的DESTDIR。這使得構建過程更加靈活,只要在處理Makefile時正確設定了環境變數。
Accessing qmake Properties
特殊的$$[...]運算子可用於訪問qmake屬性:
message(Qt version: $$[QT_VERSION]) message(Qt is installed in $$[QT_INSTALL_PREFIX]) message(Qt resources can be found in the following locations:) message(Documentation: $$[QT_INSTALL_DOCS]) message(Header files: $$[QT_INSTALL_HEADERS]) message(Libraries: $$[QT_INSTALL_LIBS]) message(Binary files (executables): $$[QT_INSTALL_BINS]) message(Plugins: $$[QT_INSTALL_PLUGINS]) message(Data files: $$[QT_INSTALL_DATA]) message(Translation files: $$[QT_INSTALL_TRANSLATIONS]) message(Settings: $$[QT_INSTALL_CONFIGURATION]) message(Examples: $$[QT_INSTALL_EXAMPLES])
有關更多資訊,請參見Configuring qmake。
該操作符可訪問的屬性,通常用於整合第三方外掛和元件到Qt中。 例如,如果在其專案檔案中進行了以下宣告,則可以將Qt Designer自定義外掛安裝到Qt Designer內建外掛路徑中:
target.path = $$[QT_INSTALL_PLUGINS]/designer INSTALLS += target
最後是error()函式,顯示錯誤資訊,並退出。
error(string)
此函式從不返回值。 qmake將字串作為錯誤訊息顯示給使用者並退出。 此功能僅應用於不可恢復的錯誤。
包含doc.pri
接下來是
include(doc/doc.pri)
doc.pri中對qdocconf進行了配置,關於qdocconf幹什麼用的,請看我釋出的文章。
原始碼組織架構
下面是重點,涉及原始碼的整體架構和組織模式。
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS = src share
unix:!macx:!isEmpty(copydata):SUBDIRS += bin
!isEmpty(BUILD_TESTS):SUBDIRS += tests
TEMPLATE
指定生成專案時要使用的模板的名稱。 允許的值為:
選項 描述 app 建立用於構建應用程式的Makefile(預設)。 有關更多資訊,請參見Building an Application。 lib 建立用於構建庫的Makefile。 有關更多資訊,請參見Building a Library。 subdirs 建立用於在子資料夾中構建目標的Makefile。 子資料夾是使用SUBDIRS變數指定的。 aux 建立一個不生成任何內容的Makefile。 如果不需要呼叫任何編譯器來建立目標,請使用此選項; 例如,因為您的專案是以解釋性語言編寫的。
注意:此模板型別僅適用於基於Makefile的生成器。 特別是,它不適用於vcxproj和Xcode生成器。vcapp 僅Windows系統。 為Visual Studio建立一個應用程式專案。 有關更多資訊,請參見Creating Visual Studio Project Files。 vclib 僅Windows系統。 為Visual Studio建立一個庫。 例如:
TEMPLATE = lib SOURCES = main.cpp TARGET = mylib
模板可以被覆蓋,通過使用-t命令列選項指定新的模板型別。 覆蓋模板型別在處理.pro檔案之後。 對於使用.pro檔案的模板型別來確定專案生成方式的,必須在命令列上宣告TEMPLATE,而不要使用-t選項。
SUBDIRS
此變數與subdirs模板一起使用,指定所有子資料夾的名稱,或者包含需要構建的專案部分的專案檔案。使用此變數指定的每個子資料夾,都必須包含其自己的專案檔案。
建議每個子目錄中的專案檔案都具有與子目錄本身相同的基本名稱,因為這樣可以省略檔名。 例如,如果子目錄名為myapp,則該目錄中的專案檔案應名為myapp.pro。
或者,您可以在任何目錄中指定.pro檔案的相對路徑。 強烈建議您僅在當前專案的父目錄或其子目錄中指定路徑。
例如:
SUBDIRS = kernel \ tools \ myapp
如果需要確保以特定順序構建子目錄,請在相關的SUBDIRS元素上使用
.depends
修飾符。例如:
SUBDIRS += my_executable my_library tests doc my_executable.depends = my_library tests.depends = my_executable
上面的配置確保my_library是在my_executable之前構建的,並且my_executable是在tests之前構建的。 但是,doc可以與其他子目錄並行構建,從而加快了構建過程。
注意:可以列出多個依賴項,並且它們都將在依賴它們的目標之前構建。
注意:不建議使用CONFIG += ordered,因為它會減慢多核並行構建。與上面的示例不同,所有構建不會並行而是依次發生,即使它們沒有依賴性。
除了定義構建順序之外,還可以通過為SUBDIRS元素提供其他修飾符來修改SUBDIRS的預設行為。 支援的修飾符是:
修飾符 效果 .subdir 使用指定的子目錄而不是SUBDIRS值。 .file 顯式指定子專案pro檔案。 不能與.subdir修飾符一起使用。 .depends 本子專案依賴指定的子專案。 .makefile 子專案的makefile。 僅在使用makefile的平臺上可用。 .target 用於與此子專案相關的makefile目標的基本字串。 僅在使用makefile的平臺上可用。 例如,定義兩個子目錄,這兩個子目錄都位於與SUBDIRS值不同的目錄中,並且其中一個子目錄必須在另一個子目錄之前構建:
SUBDIRS += my_executable my_library my_executable.subdir = app my_executable.depends = my_library my_library.subdir = lib
看了上面的解釋,我們可以理解得到,使用subdirs模式依次順序構建專案,首先構建src資料夾,然後是share資料夾。在src資料夾中,還可以劃分為多個子目錄,再次使用subdirs模式。
下面解釋一下最後兩行。
對於 Unix 平臺(
unix
),如果不是 Mac OS(!macx
),並且copydata
不為空(!isEmpty(copydata)
),則需要再增加一個 bin 目錄。如果
BUILD_TESTS
不為空(!isEmpty(BUILD_TESTS)
),則再增加一個 tests 目錄。
copydata
和BUILD_TESTS
都是在 qtcreator.pri 中定義的巨集。
指定dist檔案列表
接下來是
DISTFILES += dist/copyright_template.txt \
README.md \
$$files(dist/changes-*) \
qtcreator.qbs \
qbs/pluginjson/pluginjson.qbs \
$$files(scripts/*.py) \
$$files(scripts/*.sh) \
$$files(scripts/*.pl)
DISTFILES
指定要包含在dist目標中的檔案列表。 僅UnixMake規範支援此功能。
例如:
DISTFILES += ../program.txt
files(pattern[, recursive=false])
擴充套件指定的萬用字元pattern並返回檔名列表。 如果recursive為true,則此函式會下降到子目錄中進行遞迴。
Replace Functions概述
qmake提供了用於在配置過程中處理變數內容的函式。 這些函式稱為替換函式。 通常,它們返回可以分配給其他變數的值。 您可以通過在函式前面加上$$運算子來獲取這些值。 替換函式可以分為內建函式和函式庫。
那麼我們就可以理解$$files(dist/changes-*),就是返回當前目錄下的 dist 資料夾中,所有以 changes- 開頭的檔案。
qbs配置
接下來是
exists(src/shared/qbs/qbs.pro) {
# Make sure the qbs dll ends up alongside the Creator executable.
QBS_DLLDESTDIR = $${IDE_BUILD_TREE}/bin
cache(QBS_DLLDESTDIR)
...
}
exists(filename)
測試具有給定filename檔名的檔案是否存在。 如果檔案存在,則函式成功;否則失敗。如果為檔名指定了正則表示式,則只要任何一個檔案與指定的正則表示式匹配,則此函式成功。
例如:
exists( $(QTDIR)/lib/libqt-mt* ) { message( "Configuring for multi-threaded Qt..." ) CONFIG += thread }
注意:無論使用什麼平臺,都應將“ /”用作目錄分隔符。
Test Functions概述
測試函式返回一個布林值,您可以在作用域範圍的條件部分中進行測試。 測試函式可以分為內建函式和函式庫。
略。
指定架構和平臺
接下來是
contains(QT_ARCH, i386): ARCHITECTURE = x86
else: ARCHITECTURE = $$QT_ARCH
macx: PLATFORM = "mac"
else:win32: PLATFORM = "windows"
else:linux-*: PLATFORM = "linux-$${ARCHITECTURE}"
else: PLATFORM = "unknown"
contains(variablename, value)
如果變數variablename包含值value,則成功; 否則失敗。 可以為引數value指定正則表示式。
您可以使用作用域範圍來檢查此函式的返回值。
例如:
contains( drivers, network ) { # drivers contains 'network' message( "Configuring for network build..." ) HEADERS += network.h SOURCES += network.cpp }
僅當drivers變數包含值network時,才處理範圍內的內容。 在這種情況下,會將適當的檔案新增到SOURCES和HEADERS變數中。
Scopes
作用域範圍類似於過程程式語言中的if語句。如果滿足某個條件,則將處理域內的宣告。
Scope Syntax
作用域三部分組成,第一行為條件語句和在同一行上的左大括號,一系列命令和定義,以及另起一行上的右大括號:
<condition> { <command or definition> ... }
左大括號
必須與條件在同一行上
。 作用域可以串聯起來,以包含多個條件,如以下各節所述。作用域和條件
作用域由一個條件後跟一對大括號中包含的一系列宣告組成。 例如:win32 { SOURCES += paintwidget_win.cpp }
以上程式碼,在Windows平臺構建時,會將paintwidget_win.cpp檔案新增到生成的Makefile中的原始檔列表中。 在其他平臺構建時,定義將被忽略。
作用域中使用的條件也可以取反,以提供多種宣告方式,可在原始條件為false時進行處理。例如,要在除Windows以外的所有平臺構建時進行處理,請對作用域取反,如下所示:
!win32 { SOURCES -= paintwidget_win.cpp }
作用域可以巢狀,以聯合多個條件。 例如,要為特定平臺包括特定檔案,且僅在啟用除錯的情況下包含,請編寫以下內容:
macx { CONFIG(debug, debug|release) { HEADERS += debugging.h } }
要少寫巢狀作用域,可以使用
:
運算子來進行巢狀。上例中的巢狀作用域可以通過以下方式重寫:macx:CONFIG(debug, debug|release) { HEADERS += debugging.h }
您也可以使用
:
運算子來執行單行條件賦值。 例如:win32:DEFINES += USE_MY_STUFF
上一行僅在Windows平臺構建時,才將USE_MY_STUFF新增到DEFINES變數中。 通常,
:
運算子的行為類似於邏輯AND運算子,將多個條件結合在一起,並且要求所有條件都為真。這裡還有一個
|
運算子,其行為類似於邏輯OR運算子,將多個條件結合在一起,並且僅要求其中一個為真。win32|macx { HEADERS += debugging.h }
如果需要混合使用兩個運算子,則可以使用if函式指定運算子優先順序。
if(win32|macos):CONFIG(debug, debug|release) { # Do something on Windows and macOS, # but only for the debug configuration. } win32|if(macos:CONFIG(debug, debug|release)) { # Do something on Windows (regardless of debug or release) # and on macOS (only for debug). }
該條件接受萬用字元,可匹配一系列
CONFIG
值或mkspec
名稱。win32-* { # Matches every mkspec starting with "win32-" SOURCES += win32_specific.cpp }
注意:以前,使用萬用字元檢查mkspec名稱是qmake檢查平臺的方法。 如今,我們建議使用mkspec定義的
QMAKE_PLATFORM
變數中的值。您還可以使用
else
作用域來提供多種宣告方式。 如果前面作用域的條件為false,則處理下面的else
作用域。此外,你還可以通過聯合其他作用域,編寫複雜的測試(如上所述,由:
運算子分隔)。 例如:win32:xml { message(Building for Windows) SOURCES += xmlhandler_win.cpp } else:xml { SOURCES += xmlhandler.cpp } else { message("Unknown configuration") }
Configuration and Scopes
CONFIG
變數中儲存的值被qmake特殊處理。 每個可能的值都可以用作作用域的條件。 例如,可以使用opengl值擴充套件CONFIG的值的列表:CONFIG += opengl
作為此操作的結果,所有測試opengl的作用域將被處理。我們可以使用此功能為最終可執行檔案指定適當的名稱:
opengl { TARGET = application-gl } else { TARGET = application }
通過此功能,可以輕鬆更改專案的配置,而不會丟失特定配置可能需要的所有自定義設定。 在上面的程式碼中,第一個作用域中的宣告被處理,最終的可執行檔案為application-gl。 但是,如果未指定opengl,則將處理第二個作用域中的宣告,最終的可執行檔案為application。
由於可以在CONFIG行上放置自己的值,因此這為您提供了一種方便的方法,來自定義專案檔案並微調生成的Makefile。
Platform Scope Values
除了在許多作用域條件中使用的
win32,macx和unix
值之外,還可以使用各種其他內建平臺和特定編譯器的值。 這些都基於Qt的mkspecs資料夾
中提供的平臺規範。 例如,專案檔案中的以下幾行顯示了當前使用的規範,並測試了linux-g++規範:message($$QMAKESPEC) linux-g++ { message(Linux) }
您可以測試任何其他平臺-編譯器組合,只要在
mkspecs資料夾
中存在針對它的規範即可。
很明顯,這裡進行了判斷,並最終指定了ARCHITECTURE和PLATFORM的值。
指定基礎名
接下來是
BASENAME = $$(INSTALL_BASENAME)
isEmpty(BASENAME): BASENAME = qt-creator-$${PLATFORM}$(INSTALL_EDITION)-$${QTCREATOR_VERSION}$(INSTALL_POSTFIX)
對於BASENAME,這是是一種常見的寫法。首先,定義BASENAME
巨集為$$(INSTALL_BASENAME)
;之後,如果BASENAME
為空的話(使用測試函式isEmpty()
判斷),則定義新的BASENAME
的值。
這種寫法允許我們在編譯時通過命令列傳入自定義值改變預設設定(也就是說,如果之前定義了INSTALL_BASENAME
,那麼就會使用我們定義的值),否則就會生成一個預設值。以後我們會發現,Qt Creator 的 pro 檔案中,很多地方都使用了類似的寫法。
指定linux平臺安裝內容
接下來是
linux {
appstream.files = dist/org.qt-project.qtcreator.appdata.xml
appstream.path = $$QTC_PREFIX/share/metainfo/
desktop.files = dist/org.qt-project.qtcreator.desktop
desktop.path = $$QTC_PREFIX/share/applications/
INSTALLS += appstream desktop
}
INSTALLS
指定執行make install或類似安裝命令時將安裝的資源列表。 列表中的每個專案通常都定義有屬性,這些屬性提供有關安裝位置的資訊。
例如,以下
target.path
定義描述了構建目標的安裝位置,並且INSTALLS賦值將構建目標新增到要安裝的現有資源列表中:target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target
Installing Files
在Unix上,通常也使用構建工具來安裝應用程式和庫。 例如,通過呼叫make install。 因此,qmake具有安裝集(install set)的概念,該物件包含如何安裝專案內容的指令集。例如,可以通過以下方式描述文件檔案的集合:
documentation.path = /usr/local/program/doc documentation.files = docs/*
path
成員通知qmake應該將檔案安裝在/usr/local/program/doc中,並且files
成員指定應複製到安裝目錄的檔案。 在這種情況下,docs目錄中的所有內容都將複製到/usr/local/program/doc中。完整描述了安裝集後,您可以使用如下行將其追加到安裝列表中:
INSTALLS += documentation
qmake確保將指定的檔案複製到安裝目錄。 如果需要對該過程進行更多控制,則還可以為物件的
extra
成員提供定義。 例如,下行告訴qmake為此安裝集執行一系列命令:unix:documentation.extra = create_docs; mv master.doc toc.doc
Unix作用域可確保僅在Unix平臺上執行這些特定命令。 可以使用其他作用域規則來定義用於其他平臺的適當命令。
物件首先執行extra成員中指定的命令,再執行物件的其他成員中的指令。
如果您將內建安裝集附加到INSTALLS變數,並且不指定files或extra成員,則qmake將決定需要為您複製哪些內容。 當前,支援
target
和dlltarget
安裝集。 例如:target.path = /usr/local/myprogram INSTALLS += target
在以上幾行中,qmake知道需要複製什麼,並將自動處理安裝過程。
想必大家也都明白了吧,如果是linux平臺,則把.files指定的檔案拷貝到.path指定的路徑中。
指定其他平臺安裝內容
接下來是
macx {
APPBUNDLE = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app"
BINDIST_SOURCE = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app"
deployqt.commands = $$PWD/scripts/deployqtHelper_mac.sh \"$${APPBUNDLE}\" \"$$[QT_INSTALL_BINS]\" \"$$[QT_INSTALL_TRANSLATIONS]\" \"$$[QT_INSTALL_PLUGINS]\" \"$$[QT_INSTALL_IMPORTS]\" \"$$[QT_INSTALL_QML]\"
codesign.commands = codesign --deep -s \"$(SIGNING_IDENTITY)\" $(SIGNING_FLAGS) \"$${APPBUNDLE}\"
dmg.commands = python -u \"$$PWD/scripts/makedmg.py\" \"$${BASENAME}.dmg\" \"Qt Creator\" \"$$IDE_SOURCE_TREE\" \"$$OUT_PWD/bin\"
# dmg.depends = deployqt
QMAKE_EXTRA_TARGETS += codesign dmg
} else {
BINDIST_SOURCE = "$(INSTALL_ROOT)$$QTC_PREFIX"
BINDIST_EXCLUDE_ARG = "--exclude-toplevel"
deployqt.commands = python -u $$PWD/scripts/deployqt.py -i \"$(INSTALL_ROOT)$$QTC_PREFIX/bin/$${IDE_APP_TARGET}\" \"$(QMAKE)\"
deployqt.depends = install
win32 {
deployartifacts.depends = install
deployartifacts.commands = git clone --depth 1 -b $$BINARY_ARTIFACTS_BRANCH \
"http://code.qt.io/qt-creator/binary-artifacts.git" \
&& xcopy /s /q /y /i "binary-artifacts\\win32" \"$(INSTALL_ROOT)$$QTC_PREFIX\" \
&& rmdir /s /q binary-artifacts
QMAKE_EXTRA_TARGETS += deployartifacts
}
}
INSTALL_ROOT
環境變數
make install時更改安裝目錄的位置,例如$BUILDDIR/install/qtcreator(在Mac上不使用),具體安裝到$(INSTALL_ROOT)$$QTC_PREFIX中。
QTC_PREFIX
qmake變數
用於make install安裝目錄的目錄字首,以及make bindist打包的目錄物件,且必須以/開頭,例如/qt-creator-x.y.z,安裝到$(INSTALL_ROOT)$$QTC_PREFIX中。
PWD
指定包含正在被解析的當前檔案的目錄的完整路徑。在編寫支援影子構建的專案檔案時,這對於引用原始檔樹中的檔案很有用。
注意:請勿嘗試覆蓋此變數的值。
OUT_PWD
指定資料夾完整路徑,qmake把生成的Makefile放到此資料夾中。
注意:請勿嘗試覆蓋此變數的值。
TARGET
指定目標檔案的名稱。 預設情況下包含專案檔案的基本名稱。
例如:
TEMPLATE = app TARGET = myapp SOURCES = main.cpp
上面的專案檔案將在unix上生成一個名為myapp的可執行檔案,在Windows上生成一個名為myapp.exe的可執行檔案。
QMAKE_EXTRA_TARGETS
指定額外的qmake目標的列表。
另請參閱Adding Custom Targets。
Adding Custom Targets
qmake試圖做一個跨平臺構建工具所期望的一切。當您確實需要執行特殊的平臺相關命令時,這通常不理想。 但是,這可以使用平臺特定的指令指向不同的qmake後端來實現。
自定義Makefile輸出可通過執行物件風格(object-style)的API來實現,如在qmake中的其他位置所發現的那樣。在指定成員時會自動定義物件。 例如:
mytarget.target = .buildfile mytarget.commands = touch $$mytarget.target mytarget.depends = mytarget2 mytarget2.commands = @echo Building $$mytarget.target
上面的定義定義了一個名為mytarget的qmake目標,目標包含一個名為.buildfile的Makefile目標,並通過touch命令生成。 最後,.depends成員指定mytarget依賴於mytarget2,後者是隨後定義的另一個目標。 mytarget2是一個虛擬目標。 它僅定義為向控制檯回顯一些文字。
最後一步是使用QMAKE_EXTRA_TARGETS變數來指示qmake該物件是要構建的目標:
QMAKE_EXTRA_TARGETS += mytarget mytarget2
這是實際構建自定義目標所需要做的一切。 當然,您可能希望將這些目標的其中一個與qmake構建目標(qmake build target)聯絡起來。 為此,您只需要在PRE_TARGETDEPS列表中包括Makefile目標即可。
自定義目標規範支援以下成員:
成員 描述 commands 用於生成自定義構建目標的命令。 CONFIG 自定義構建目標的特定配置選項。 可以設定為 recursive
,以指示應在Makefile中建立規則,以呼叫子目標特定的Makefile中的相關目標。 該成員預設為每個子目標建立一個條目。depends 自定義構建目標所依賴的現有構建目標。 recurse 指定子目標,在Makefile中建立規則是被使用,以呼叫子目標特定的Makefile。 此成員僅當CONFIG設定為recursive時才使用。 典型值為"Debug"和"Release"。 recurse_target 指定應該通過Makefile的規則對應的子目標Makefile構建的目標。 該成員添加了類似$(MAKE) -f Makefile.[subtarget] [recurse_target]的東西。 此成員僅當CONFIG設定為recursive時才使用。 target 自定義構建目標的名稱
上面的語句中用到了Scopes條件判斷,$$運算子,自定義目標等內容,我們在前面都已經講過了。現在我們也清楚了,首先進行了平臺判斷,然後定義了自定義構建目標,用於編譯輸出。大家感興趣,可以使用message()
函式進行輸出。具體內容就不深究了。
指定安裝存檔
接下來是
INSTALLER_ARCHIVE_FROM_ENV = $$(INSTALLER_ARCHIVE)
isEmpty(INSTALLER_ARCHIVE_FROM_ENV) {
INSTALLER_ARCHIVE = $$OUT_PWD/$${BASENAME}-installer-archive.7z
} else {
INSTALLER_ARCHIVE = $$OUT_PWD/$$(INSTALLER_ARCHIVE)
}
INSTALLER_ARCHIVE_DEBUG = $$INSTALLER_ARCHIVE
INSTALLER_ARCHIVE_DEBUG ~= s/(.*)[.]7z/\1-debug.7z
Operators
在許多專案檔案中,賦值(=)和追加(+ =)運算子可用於包括有關專案的所有資訊。 典型的使用模式是為變數分配值列表,並根據各種測試的結果附加更多值。 由於qmake使用預設值定義某些變數,因此有時有必要使用remove(-=)運算子過濾掉不需要的值。 以下各節描述如何使用運算子來操縱變數的內容。
Assigning Values
=運算子為變數分配一個值:
TARGET = myapp
上一行將TARGET變數設定為myapp。 這將使用myapp覆蓋先前為TARGET設定的任何值。
Appending Values
+=運算子將新值附加到變數的值列表中:
DEFINES += USE_MY_STUFF
上一行將USE_MY_STUFF追加到預處理定義列表中,最後寫入生成的Makefile。
Removing Values
-=運算子從變數的值列表中刪除一個值:
DEFINES -= USE_MY_STUFF
上一行從預處理定義列表中刪除了USE_MY_STUFF。
Adding Unique Values
*=運算子將一個值新增到變數的值列表中,但前提是尚不存在。 這樣可以防止將值多次包含在變數中。 例如:
DEFINES *= USE_MY_STUFF
在上面的行中,如果尚未定義USE_MY_STUFF,則只會將其新增到預處理定義列表中。 請注意,unique()函式還可用於確保變數僅包含每個值的一個例項。
Replacing Values ~=
〜=運算子將所有與正則表示式匹配的值替換為指定的值:
DEFINES ~= s/QT_[DT].+/QT
在上一行中,列表中以QT_D或QT_T開頭的任何值都將替換為QT。
INSTALLER_ARCHIVE的定義方式,我們在"指定基礎名"小節中就介紹過這種用法,不再贅述。對於INSTALLER_ARCHIVE_DEBUG的~=運算,就是在檔名後面加了-debug。
指定額外構建目標
最後是
bindist.commands = python -u $$PWD/scripts/createDistPackage.py $$OUT_PWD/$${BASENAME}.7z \"$$BINDIST_SOURCE\"
bindist_installer.commands = python -u $$PWD/scripts/createDistPackage.py $$BINDIST_EXCLUDE_ARG $${INSTALLER_ARCHIVE} \"$$BINDIST_SOURCE\"
bindist_debug.commands = python -u $$PWD/scripts/createDistPackage.py --debug $$BINDIST_EXCLUDE_ARG $${INSTALLER_ARCHIVE_DEBUG} \"$$BINDIST_SOURCE\"
win32 {
deployqt.commands ~= s,/,\\\\,g
bindist.commands ~= s,/,\\\\,g
bindist_installer.commands ~= s,/,\\\\,g
}
QMAKE_EXTRA_TARGETS += deployqt bindist bindist_installer bindist_debug
首先建立了bindist,bindist_installer和bindist_debug三個自定義構建目標,然後在win32平臺下進行了替換。最終新增到QMAKE_EXTRA_TARGETS進行編譯構建。
簡單解釋下上面的正則表示式,其實就是替換路徑中的分隔符,全域性替換unix中的/為windows下的\\。
原創造福大家,共享改變世界
獻出一片愛心,溫暖作者心靈
<