• qt creator源碼全方面分析(3-1)

    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 文件即可,是虛擬目錄節點,使項目結構層次看起來清晰很多。

    image-20200222152425946

    有關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模式。

    image-20200222192914349

    下面解釋一下最后兩行。

    1. 對于 Unix 平臺(unix),如果不是 Mac OS(!macx),并且copydata不為空(!isEmpty(copydata)),則需要再增加一個 bin 目錄。

    2. 如果BUILD_TESTS不為空(!isEmpty(BUILD_TESTS)),則再增加一個 tests 目錄。

    copydataBUILD_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將決定需要為您復制哪些內容。 當前,支持targetdlltarget安裝集。 例如:

    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下的\\。


    原創造福大家,共享改變世界

    獻出一片愛心,溫暖作者心靈


    posted @ 2020-03-01 15:13  codeForFamily  閱讀(...)  評論(...編輯  收藏
    贵州快三平台贵州快三主页贵州快三网站贵州快三官网贵州快三娱乐贵州快三开户贵州快三注册贵州快三是真的吗贵州快三登入贵州快三快三贵州快三时时彩贵州快三手机app下载贵州快三开奖 宁国市 | 正阳县 | 东明县 | 焦作市 | 乐山市 | 砀山县 | 公主岭市 | 潞西市 | 蕉岭县 | 嘉黎县 | 河东区 | 逊克县 | 通江县 | 交口县 | 湖北省 | 邯郸市 | 三明市 | 宁陕县 | 清远市 | 阜平县 | 九江县 | 密云县 | 资中县 | 嘉定区 | 甘德县 | 清新县 | 玉田县 | 易门县 | 沂南县 | 石嘴山市 | 杭锦后旗 | 衡阳县 | 哈巴河县 | 霍山县 | 封丘县 | 揭西县 | 遵义县 | 吴旗县 | 海晏县 | 皮山县 | 古蔺县 | 陇西县 | 普格县 | 安阳县 | 鞍山市 | 台东县 | 赤水市 | 枣庄市 | 孟连 | 琼海市 | 绥化市 | 大新县 | 平定县 | 临清市 | 乌拉特前旗 | 东乡族自治县 | 曲阜市 | 包头市 | 淮南市 | 诸城市 | 九龙县 | 墨竹工卡县 | 昌黎县 | 滦平县 | 灵丘县 | 北辰区 | 读书 | 聂荣县 | 洛浦县 | 垫江县 | 长岛县 | 昔阳县 | 大姚县 | 武夷山市 | 锡林郭勒盟 | 大荔县 | 晋江市 | 罗平县 | 吉安市 | 留坝县 | 丹东市 | 简阳市 | 岫岩 | 临猗县 | 吉水县 | 堆龙德庆县 | 晋城 | 临汾市 | 青浦区 | 七台河市 | 新安县 | 黄冈市 | 无为县 | 抚远县 | 沁水县 | 阿拉尔市 | 青铜峡市 | 砚山县 | 安阳市 | 兴和县 | 赤水市 | 芜湖县 | 泽普县 | 广丰县 | 子洲县 | 无锡市 | 鹤壁市 | 乡城县 | 阿瓦提县 | 固镇县 | 方城县 | 张掖市 | 吴忠市 | 汽车 | 涞源县 | 乌拉特中旗 | 修武县 | 华安县 | 闸北区 | 乡宁县 | 正定县 | 拉孜县 | 临桂县 | 福清市 | 宣武区 | 武山县 | 西平县 | 巴彦淖尔市 | 察雅县 | 瓦房店市 | 罗甸县 | 凌海市 | 饶平县 | 丰原市 | 六安市 | 祁东县 | 蒲城县 | 乌拉特中旗 | 饶平县 | 安岳县 | 宜君县 | 奎屯市 | 彭阳县 | 青海省 | 丹寨县 | 赫章县 | 湘潭市 | 荣成市 | 固镇县 | 繁峙县 | 定西市 | 广安市 | 肥东县 | 喀什市 | 平邑县 | 历史 | 荆州市 | 手游 | 汝阳县 | 南郑县 | 夏津县 | 神木县 | 赤峰市 | 泰和县 | 宜州市 | 黄平县 | 临洮县 | 邯郸县 | 新疆 | 扶余县 | 鹰潭市 | 蒙阴县 | 临颍县 | 沾化县 | 嫩江县 | 汾西县 | 双柏县 | 建阳市 | 柏乡县 | 雅江县 | 五大连池市 | 临夏县 | 富阳市 | 榕江县 | 上虞市 | 镇康县 | 中阳县 | 齐河县 | 息烽县 | 博湖县 | 右玉县 | 桦川县 | 云霄县 | 奉新县 | 沈丘县 | 铅山县 | 济南市 | 五河县 | 七台河市 | 东台市 | 林口县 | 平定县 | 聂荣县 | 建阳市 | 台东市 | 郎溪县 | 澄江县 |