1. 程式人生 > >qt creator原始碼全方面分析(3-2)

qt creator原始碼全方面分析(3-2)

[TOC] # qtcreator.pri 前面我們介紹了qtcreator.pro,下面我們開始介紹qtcreator.pri,來看看pro中include的pri到底是幹什麼用的。 注意,許多函式/變數/關鍵字的含義,某些基礎用法,在qtcreator.pro中進行了介紹。 ## 判斷重複包含 qtcreator.pri第一部分是 ``` !isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included") QTCREATOR_PRI_INCLUDED = 1 ``` 很明顯,isEmpty()為false,則呼叫error報錯退出編譯。那麼只能是為true,即要求QTCREATOR_PRI_INCLUDED為空,並在下一行立即定義為1。 那麼這個是在幹什麼呢?我們看變數的名稱就能略窺一二,INCLUDED就是已包含的意思,那麼這裡就是為了避免在其他地方重複包含qtcreator.pri檔案,類似於C/C++標頭檔案中的 ```c++ # ifndef XXX_H # define XXX_H #endif ``` ## 定義版本資訊 接下來是 ``` QTCREATOR_VERSION = 4.6.2 QTCREATOR_COMPAT_VERSION = 4.6.0 VERSION = $$QTCREATOR_VERSION QTCREATOR_DISPLAY_VERSION = 4.6.2 QTCREATOR_COPYRIGHT_YEAR = 2018 BINARY_ARTIFACTS_BRANCH = 4.6 ``` ### [VERSION](https://doc.qt.io/qt-5/qmake-variable-reference.html#version) > 如果TEMPLATE值為app,則指定應用程式的版本號;如果TEMPLATE值為lib,則指定庫的版本號。 > > 在Windows上,如果未設定RC_FILE和RES_FILE變數,則自動生成.rc檔案。 生成的.rc檔案將具有FILEVERSION和PRODUCTVERSION條目,並用主,次,補丁和構建版本號填充。 每個數字的範圍必須在0到65535之間。有關.rc檔案生成的更多詳細資訊,請參見[Platform Notes](https://doc.qt.io/qt-5/qmake-platform-notes.html)。 > > 示例: > > ``` > win32:VERSION = 1.2.3.4 # major.minor.patch.build > else:VERSION = 1.2.3 # major.minor.patch > ``` 很明顯,是在定義QtCreator的版本,相容性版本,版權,以及git分支。 ## 定義IDE名稱 接下來是 ``` isEmpty(IDE_DISPLAY_NAME): IDE_DISPLAY_NAME = Qt Creator isEmpty(IDE_ID): IDE_ID = qtcreator isEmpty(IDE_CASED_ID): IDE_CASED_ID = QtCreator isEmpty(PRODUCT_BUNDLE_IDENTIFIER): PRODUCT_BUNDLE_IDENTIFIER = org.qt-project.$$IDE_ID ``` 我們在qtcreator.pro中已經介紹過isEmpty這種用法。這裡在給相關變數設定預設值。 ## 啟用C++14 接下來是 ``` CONFIG += c++14 ``` ### [CONFIG](https://doc.qt.io/qt-5/qmake-variable-reference.html#config) > 指定專案配置和編譯器選項。 這些值由qmake內部識別,並具有特殊含義。 > > 以下CONFIG值控制編譯標誌: > > | 選項 | 描述 | > | ------------------------------- | ------------------------------------------------------------ | > | release | 該專案將以release模式構建。 如果還指定了debug,則最後那個生效。 | > | debug | 該專案將以debug模式構建。 | > | debug_and_release | 該專案將同時構建debug和release模式。 | > | debug_and_release_target | 預設情況下設定此選項。 如果還設定了debug_and_release,則debug和release版本最終將放置在單獨的debug和release目錄中。 | > | build_all | 如果指定了debug_and_release,則預設情況下專案同時構建debug和release模式。 | > | autogen_precompile_source | 自動生成一個.cpp檔案,其中包含.pro檔案中指定的預編譯標頭檔案。 | > | ordered | 當TEMPLATE為subdirs時,此選項指定應按給出的順序處理列出的目錄。
注意:不建議使用此選項。 如[SUBDIRS](https://doc.qt.io/qt-5/qmake-variable-reference.html#subdirs)變數文件中所述指定依賴項。 | > | precompile_header | 使能支援在專案中使用[precompiled headers](https://doc.qt.io/qt-5/qmake-precompiledheaders.html)。 | > | precompile_header_c (MSVC only) | 使能支援在C檔案中使用[precompiled headers](https://doc.qt.io/qt-5/qmake-precompiledheaders.html)。 | > | warn_on | 編譯器應儘可能多的輸出警告。 如果還指定了warn_off,則最後那個生效。 | > | warn_off | 編譯器應儘可能少的輸出警告。 | > | exceptions | 使能異常支援。預設設定該選項。 | > | exceptions_off | 禁用異常支援。 | > | rtti | 使能RTTI支援。預設情況下,使用編譯器預設值。 | > | rtti_off | 禁用RTTI支援。預設情況下,使用編譯器預設值。 | > | stl | 使能STL支援。預設情況下,使用編譯器預設值。 | > | stl_off | 禁用STL支援。預設情況下,使用編譯器預設值。 | > | thread | 使能Thread支援。當CONFIG包含qt(預設設定)時,將使能此功能。 | > | c99 | 使能C99支援。 如果編譯器不支援C99或無法選擇C標準,則此選項無效。 預設情況下,使用編譯器預設值。 | > | c11 | 使能C11支援。 如果編譯器不支援C11或無法選擇C標準,則此選項無效。 預設情況下,使用編譯器預設值。 | > | strict_c | 禁用對C編譯器擴充套件的支援。 預設情況下,它們是使能的。 | > | c++11 | 使能C++11支援。 如果編譯器不支援C++11或無法選擇C++標準,則此選項無效。 預設情況下,使用編譯器預設值。 | > | c++14 | 使能C++14支援。 如果編譯器不支援C++14或無法選擇C++標準,則此選項無效。 預設情況下,使用編譯器預設值。 | > | c++1z | 使能C++17支援。 如果編譯器不支援C++17或無法選擇C++標準,則此選項無效。 預設情況下,使用編譯器預設值。 | > | c++17 | 同c++1z | > | c++2a | 使能C++2a支援。 如果編譯器不支援C++2a或無法選擇C++標準,則此選項無效。 預設情況下,使用編譯器預設值。 | > | c++latest | 如果編譯器支援,使能最新C++語言標準的支援。 預設情況下,此選項是禁用的。 | > | strict_c++ | 禁用對C++編譯器擴充套件的支援。 預設情況下,它們是使能的。 | > | depend_includepath | 使能將INCLUDEPATH的值附加到DEPENDPATH。 預設設定此選項。 | > | lrelease | 對[TRANSLATIONS](https://doc.qt.io/qt-5/qmake-variable-reference.html#translations) 和[EXTRA_TRANSLATIONS](https://doc.qt.io/qt-5/qmake-variable-reference.html#extra-translations)中列出的所有檔案執行lrelease。 如果未設定embed_translations,則將生成的.qm檔案安裝到[QM_FILES_INSTALL_PATH](https://doc.qt.io/qt-5/qmake-variable-reference.html#qm-files-install-path)中。 使用[QMAKE_LRELEASE_FLAGS](https://doc.qt.io/qt-5/qmake-variable-reference.html#qmake-lrelease-flags)向lrelease呼叫新增引數選項。 預設情況下未設定此選項。 | > | embed_translations | 將lrelease生成的翻譯內容嵌入[QM_FILES_RESOURCE_PREFIX](https://doc.qt.io/qt-5/qmake-variable-reference.html#qm-files-resource-prefix)下的可執行檔案中。 也需要同時設定lrelease。 預設情況下未設定此選項。 | > | create_libtool | 為當前構建的庫建立一個libtool.la檔案。 | > | create_pc | 為當前構建的庫建立一個pkg-config .pc檔案。 | > | no_batch | 僅限NMake:關閉NMake批處理規則或推斷規則的生成。 | > | skip_target_version_ext | 在Windows上禁止附加自動版本號到DLL檔名。 | > | suppress_vcproj_warnings | 禁止VS專案生成器的警告。 | > | windeployqt | 連結後自動呼叫windeployqt,並將輸出新增為部署項。 | > | dont_recurse | 禁止對當前子專案的qmake遞迴。 | > | no_include_pwd | 不要將當前目錄新增到INCLUDEPATHS。 | > > 當您使用debug_and_release選項(在Windows下是預設設定)時,專案將被處理三次:一次生成元Makefile,再兩次生成Makefile.Debug和Makefile.Release。 > > 在後面的過程中,將build_pass和相應的debug或release選項附加到CONFIG。 這樣就可以執行特定構建任務。 例如: > > ``` > build_pass:CONFIG(debug, debug|release) { > unix: TARGET = $$join(TARGET,,,_debug) > else: TARGET = $$join(TARGET,,,d) > } > ``` > > 作為手動編寫構建型別條件的替代方法,除了常規[QMAKE_LFLAGS](https://doc.qt.io/qt-5/qmake-variable-reference.html#qmake-lflags)外,某些變數還提供特定構建變數,例如 [QMAKE_LFLAGS_RELEASE](https://doc.qt.io/qt-5/qmake-variable-reference.html#qmake-lflags-release)。 這些應在可用時使用。 > > 元Makefile通過debug和release目標進行子構建呼叫,並可通過all目標進行聯合構建呼叫。 使用build_all選項時,聯合構建為預設設定。 否則,CONFIG中最後指定的來自集合(debug,release)的選項會變為預設選項。 在這種情況下,您可以顯式呼叫all以一次構建兩個配置: > > ``` > make all > ``` > > 注意:在生成Visual Studio和Xcode專案時,詳細資訊略有不同。 > > 連結庫時,qmake依賴基礎平臺,來了解該庫應該連結的其他庫。 但是,如果是靜態連結,qmake不會獲取此資訊,除非使用以下CONFIG選項: > > | 選項 | 描述 | > | -------------- | ------------------------------------------------------------ | > | create_prl | 此選項使qmake可以跟蹤這些依賴性。 使能此選項後,qmake將建立副檔名為.prl的檔案,該檔案將儲存有關庫的元資訊(有關更多資訊,請參見[Library Dependencies](https://doc.qt.io/qt-5/qmake-advanced-usage.html#libdepend))。 | > | link_prl | 使能此選項後,qmake將處理該應用程式連結的所有庫並找到其元資訊(有關更多資訊,請參見[Library Dependencies](https://doc.qt.io/qt-5/qmake-advanced-usage.html#libdepend))。 | > | no_install_prl | 此選項禁用建立.prl檔案的安裝規則的生成。 | > > 注意:構建靜態庫時,需要create_prl選項,而使用靜態庫時,則需要link_prl選項。 > > 以下選項定義應用程式或庫的型別: > > | 選項 | 描述 | > | ------------------ | ------------------------------------------------------------ | > | qt | 目標是Qt應用程式或庫,並且需要Qt庫和標頭檔案。 Qt庫正確的包含和庫路徑將自動新增到專案中。 這是預設定義的,可以使用\l{#qt}{QT}變數進行微調。 | > | x11 | 目標是X11應用程式或庫。 正確的包含路徑和庫將自動新增到專案中。 | > | testcase | 目標是一個自動測試。 一個[檢查目標](https://doc.qt.io/qt-5/qmake-common-projects.html#building-a-testcase)將被新增到生成的Makefile中,以執行測試。 僅在生成Makefile時相關。 | > | insignificant_test | 自動測試的退出程式碼將被忽略。 僅當還設定了testcase時才相關。 | > | windows | 目標是Win32視窗應用程式(僅適用於TEMPLATE為app)。 正確的包含路徑,編譯器標誌和庫將自動新增到專案中。 | > | console | 目標是Win32控制檯應用程式(僅適用於TEMPLATE為app)。 正確的包含路徑,編譯器標誌和庫將自動新增到專案中。考慮將選項cmdline用於跨平臺應用程式。 | > | cmdline | 目標是跨平臺的命令列應用程式。 在Windows上,這意味著CONFIG += console。 在macOS上,這意味著CONFIG -= app_bundle。 | > | shared | 目標是共享物件/DLL。 正確的包含路徑,編譯器標誌和庫將自動新增到專案中。 請注意,dll也可以在所有平臺上使用。 將建立帶有目標平臺的適當字尾(.dll或.so)的共享庫檔案。 | > | dll | 同上。 | > | static | 目標是靜態庫(僅lib)。 正確的編譯器標誌將自動新增到專案中。 | > | staticlib | 同上。 | > | plugin | 目標是外掛(僅lib)。 這也會使能dll。 | > | designer | 目標是Qt Designer的外掛。 | > | no_lflags_merge | 確保儲存在LIBS變數中的庫列表在使用前不減少為值唯一(去除了重複的)列表。 | > > 這些選項僅在Windows上定義特定功能: > > | 選項 | 描述 | > | ------------------ | ------------------------------------------------------------ | > | flat | 使用vcapp模板時,這會將所有原始檔置於源組中,並將標頭檔案置於頭組中,而不管它們位於哪個目錄中。關閉此選項,將根據檔案所在目錄歸類。 預設情況下是開啟的。 | > | embed_manifest_dll | 將清單檔案嵌入到作為庫專案一部分的DLL中。 | > | embed_manifest_exe | 將清單檔案嵌入到作為應用程式專案一部分的EXE中。 | > > 有關嵌入清單檔案的選項的更多資訊,請參見[Platform Notes](https://doc.qt.io/qt-5/qmake-platform-notes.html#visual-studio-manifest-files)。 > > 以下選項僅在macOS上有效: > > | 選項 | 描述 | > | ------------- | ------------------------------------------------ | > | app_bundle | 將可執行檔案放入捆綁包(這是預設設定)。 | > | lib_bundle | 將庫放入庫包(這是預設設定)。 | > | plugin_bundle | 將外掛放入外掛包中。 Xcode專案生成器不支援此值。 | > > 捆綁軟體的構建過程也受[QMAKE_BUNDLE_DATA](https://doc.qt.io/qt-5/qmake-variable-reference.html#qmake-bundle-data)變數內容的影響。 > > 以下選項僅在Linux / Unix平臺上有效: > > | 選項 | 描述 | > | ------------------- | ------------------------------ | > | largefile | 支援大檔案的包含 | > | separate_debug_info | 把庫的除錯資訊放到單獨的檔案中 | > > 解析作用域時,將檢查CONFIG變數。 您可以為該變數分配任何內容。 > > 例如: > > ``` > CONFIG += console newstuff > ... > newstuff { > SOURCES += new.cpp > HEADERS += new.h > } > ``` ## 自定義函式 接下來是 ``` defineReplace(qtLibraryTargetName) { unset(LIBRARY_NAME) LIBRARY_NAME = $$1 CONFIG(debug, debug|release) { !debug_and_release|build_pass { mac:RET = $$member(LIBRARY_NAME, 0)_debug else:win32:RET = $$member(LIBRARY_NAME, 0)d } } isEmpty(RET):RET = $$LIBRARY_NAME return($$RET) } defineReplace(qtLibraryName) { RET = $$qtLibraryTargetName($$1) win32 { VERSION_LIST = $$split(QTCREATOR_VERSION, .) RET = $$RET$$first(VERSION_LIST) } return($$RET) } defineTest(minQtVersion) { maj = $$1 min = $$2 patch = $$3 isEqual(QT_MAJOR_VERSION, $$maj) { isEqual(QT_MINOR_VERSION, $$min) { isEqual(QT_PATCH_VERSION, $$patch) { return(true) } greaterThan(QT_PATCH_VERSION, $$patch) { return(true) } } greaterThan(QT_MINOR_VERSION, $$min) { return(true) } } greaterThan(QT_MAJOR_VERSION, $$maj) { return(true) } return(false) } # For use in custom compilers which just copy files defineReplace(stripSrcDir) { return($$relative_path($$absolute_path($$1, $$OUT_PWD), $$_PRO_FILE_PWD_)) } ``` ### [Replace Functions](https://doc.qt.io/qt-5/qmake-language.html#replace-functions) > qmake提供了一些內建函式,以允許處理變數的內容。 這些函式處理提供給它們的引數,並返回一個值或值列表。 `要將結果分配給變數,可以將$$運算子與此類函式一起使用`,就像將一個變數的內容分配給另一個一樣: > > ``` > HEADERS = model.h > HEADERS += $$OTHER_HEADERS > HEADERS = $$unique(HEADERS) > ``` > > 此類函式應在賦值的右側(即,作為運算元)。 > > 您可以定義自己的函式來處理變數的內容,如下所示: > > ``` > defineReplace(functionName){ > #function code > } > ``` > > 以下示例函式將變數名作為唯一引數,使用內建函式eval()從變數中提取值列表,並編譯檔案列表: > > ``` > defineReplace(headersAndSources) { > variable = $$1 > names = $$eval($$variable) > headers = > sources = > > for(name, names) { > header = $${name}.h > exists($$header) { > headers += $$header > } > source = $${name}.cpp > exists($$source) { > sources += $$source > } > } > return($$headers $$sources) > } > ``` > > 引數$$1 ### [Test Functions](https://doc.qt.io/qt-5/qmake-language.html#test-functions) > qmake提供了內建函式,可以在編寫作用域時用作條件。 這些函式不返回值,而是指示成功或失敗: > > ``` > count(options, 2) { > message(Both release and debug specified.) > } > ``` > > 此類函式應僅在條件表示式中使用。 > > 可以定義自己的函式以提供作用域條件。 以下示例測試列表中的每個檔案是否存在,如果全部存在,則返回true,否則返回false: > > ``` > defineTest(allFiles) { > files = $$ARGS > > for(file, files) { > !exists($$file) { > return(false) > } > } > return(true) > } > ``` > > 引數列表$$ARGS ### [\_PRO_FILE_PWD_](https://doc.qt.io/qt-5/qmake-variable-reference.html#pro-file-pwd) > 包含正在使用的專案檔案的目錄的路徑。(即使該變量出現在 .pri 檔案,也是指包含該 .pri 檔案的 .pro 檔案所在目錄的路徑。) > > 例如,以下行導致包含專案檔案的目錄的位置寫入控制檯: > > ``` > message($$_PRO_FILE_PWD_) > ``` > > 注意:請勿嘗試覆蓋此變數的值。 ### [\_PRO_FILE_](https://doc.qt.io/qt-5/qmake-variable-reference.html#pro-file) > 包含正在使用的專案檔案的路徑。 > > 例如,以下行導致專案檔案的位置寫入控制檯: > > ``` > message($$_PRO_FILE_) > ``` > > 注意:請勿嘗試覆蓋此變數的值。 現在我們來分析pri中定義的三個函式。 因為這兩個函式在 Qt Creator 中使用了多次,並且完全可以拷貝複製到其它專案繼續使用。 自定義替換函式`qtLibraryTargetName`。 1. 取消LIBRARY_NAME的定義,設定LIBRARY_NAME為 `$$1`,即函式的第一個引數。 2. CONFIG測試函式判斷debug或release模式。 1. 如果是debug模式,再次進行判斷。 2. 如果CONFIG沒有設定debug_and_release或者是構建過程build_pass,則設定RET變數。對於 mac,LIBRARY_NAME值後面新增_debug賦給RET。對於win,LIBRARY_NAME值後面新增d賦給RET。 3. 如果RET為空,則把LIBRARY_NAME值賦給RET。 4. 返回RET。 簡單來說,該函式實現功能:在debug環境下,在庫名後面新增\_debug或\_d尾綴,來跟release模式進行區分。當然,也有其他方式來實現上述功能,譬如使用join()函式,見CONFIG小節。 自定義替換函式`qtLibraryName`。 1. 使用qtLibraryTargetName()函式,對輸入的第一個引數進行替換,並賦值給RET。 2. 如果 是win32 系統。 1. 使用split()函式,將前面定義的QTCREATOR_VERSION(即4.6.2),使用\'.\'進行分隔得到列表,賦值給VERSION_LIST 2. 使用first()函式,獲取VERSION_LIST的第一個元素(即4),與RET拼接,並賦值給RET。 3. 返回RET。 簡單來說,該函式實現功能:為了在win32系統中避免出現 dll hell,在win32系統下,在庫名後面新增主版本號。 自定義測試函式`minQtVersion`。 1. 獲取三個引數(即,主/次/補丁),並賦值給maj,min,patch。 2. maj <= QT_MAJOR_VERSION,min <= QT_MINOR_VERSION和patch <= QT_PATCH_VERSION,則返回true。其他返回false。 簡單來說,該函式實現功能:函式引數的版本號小於等於當前Qt的版本號。 自定義替換函式`stripSrcDir`。 1. 獲取絕對路徑,absolute_path返回$$OUT_PWD/$$1。 2. 獲取相對路徑,步驟1中獲取的絕對路徑相對與$$\_PRO_FILE_PWD_的相對路徑。 簡單來說,該函式實現功能(見自帶的註釋):用於自定義編譯器拷貝檔案。 ## 設定macOS最小版本 接下來是: ``` darwin:!minQtVersion(5, 7, 0) { # Qt 5.6 still sets deployment target 10.7, which does not work # with all C++11/14 features (e.g. std::future) QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.8 } ``` 如果是基於Darwin作業系統的,並且Qt 的版本低於`5.7.0`時,設定應用程式支援的macOs最小版本。可以從註釋看出,10.7不支援C++11/14特性。 ## 設定QTEST模組 接下來是 ``` QTC_BUILD_TESTS = $$(QTC_BUILD_TESTS) !isEmpty(QTC_BUILD_TESTS):TEST = $$QTC_BUILD_TESTS !isEmpty(BUILD_TESTS):TEST = 1 isEmpty(TEST):CONFIG(debug, debug|release) { !debug_and_release|build_pass { TEST = 1 } } isEmpty(IDE_LIBRARY_BASENAME) { IDE_LIBRARY_BASENAME = lib } equals(TEST, 1) { QT +=testlib DEFINES += WITH_TESTS } ``` 1. 如果設定了QTC_BUILD_TESTS,則賦值給TEST。 2. 如果設定了BUILD_TESTS,則給TEST賦值1。 3. 如果TEST沒有值,且為debug模式,並且沒有設定debug_and_release,則在構建過程中,設定TEST為1。 4. 如果IDE_LIBRARY_BASENAME為空,則為庫賦值基礎名為lib。 5. 如果TEST等於1,則新增QTEST模組功能。 ## 設定源目錄和構建目錄 接下來是 ``` IDE_SOURCE_TREE = $$PWD isEmpty(IDE_BUILD_TREE) { sub_dir = $$_PRO_FILE_PWD_ sub_dir ~= s,^$$re_escape($$PWD),, IDE_BUILD_TREE = $$clean_path($$OUT_PWD) IDE_BUILD_TREE ~= s,$$re_escape($$sub_dir)$,, } ``` ### [re_escape(string)](https://doc.qt.io/qt-5/qmake-function-reference.html#re-escape-string) > 對每個string中的特殊正則表示式字元,使用反斜槓轉義,返回轉義後的字串。 該函式是QRegExp::escape的包裝。 > > 例如: > > ``` > s1 = QRegExp::escape("bingo"); // s1 == "bingo" > s2 = QRegExp::escape("f(x)"); // s2 == "f\\(x\\)" > ``` ### [clean_path(path)](https://doc.qt.io/qt-5/qmake-function-reference.html#clean-path-path) > 處理path,對目錄分隔符進行規範化(轉換為"/"),刪除了多餘的目錄分隔符,並且解析"."和".."(儘可能)。 該函式是QDir::cleanPath的包裝。 > > 另請閱[absolute_path()](https://doc.qt.io/qt-5/qmake-function-reference.html#absolute-path-path-base), [relative_path()](https://doc.qt.io/qt-5/qmake-function-reference.html#relative-path-filepath-base), [shell_path()](https://doc.qt.io/qt-5/qmake-function-reference.html#shell-path-path), [system_path()](https://doc.qt.io/qt-5/qmake-function-reference.html#system-path-path). 我們在程式碼後面插樁輸出語句 ``` build_pass:message($$PWD) # 當前pri檔案所在目錄 build_pass:message($$OUT_PWD) # 生成makefile所在目錄 build_pass:message($$_PRO_FILE_) # 包含當前pri的pro所在路徑 build_pass:message($$_PRO_FILE_PWD_) # 包含當前pri的pro所在目錄 ``` 現在,我們來看一下部分輸出。 ``` Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2 Project MESSAGE: F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info/bin Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/bin/bin.pro Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/bin Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2 Project MESSAGE: F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info/src/app Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/src/app/app.pro Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/src/app ``` 我們可以發現 1. PWD沒有發生變化。 2. 對比OUT_PWD和\_PRO_FILE_PWD_,輸出目錄和源目錄的子資料夾組織架構一樣。 下面我們分析pri中的語句 1. 設定源目錄IDE_SOURCE_TREE。 2. 如果構建目錄IDE_BUILD_TREE為空。 1. 設定sub_dir,並進行替換。可以認為是從\_PRO_FILE_PWD_減去PWD,剩下子資料夾相對路徑,如bin/和app/。 2. 初始化IDE_BUILD_TREE,並進行替換。可以認為是從OUT_PWD減去相對路徑,剩下相同的根目錄。 大家可以用我們上面的message輸出結果來簡單的計算下即可。 IDE_SOURCE_TREE為F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2, IDE_BUILD_TREE為F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info。 ## 設定IDE和INSTALLS相關路徑 接下來是 ``` IDE_APP_PATH = $$IDE_BUILD_TREE/bin osx { IDE_APP_TARGET = "$$IDE_DISPLAY_NAME" # check if IDE_BUILD_TREE is actually an existing Qt Creator.app, # for building against a binary package exists($$IDE_BUILD_TREE/Contents/MacOS/$$IDE_APP_TARGET): IDE_APP_BUNDLE = $$IDE_BUILD_TREE else: IDE_APP_BUNDLE = $$IDE_APP_PATH/$${IDE_APP_TARGET}.app # set output path if not set manually isEmpty(IDE_OUTPUT_PATH): IDE_OUTPUT_PATH = $$IDE_APP_BUNDLE/Contents IDE_LIBRARY_PATH = $$IDE_OUTPUT_PATH/Frameworks IDE_PLUGIN_PATH = $$IDE_OUTPUT_PATH/PlugIns IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/Resources IDE_DATA_PATH = $$IDE_OUTPUT_PATH/Resources IDE_DOC_PATH = $$IDE_DATA_PATH/doc IDE_BIN_PATH = $$IDE_OUTPUT_PATH/MacOS copydata = 1 LINK_LIBRARY_PATH = $$IDE_APP_BUNDLE/Contents/Frameworks LINK_PLUGIN_PATH = $$IDE_APP_BUNDLE/Contents/PlugIns INSTALL_LIBRARY_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Frameworks INSTALL_PLUGIN_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/PlugIns INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Resources INSTALL_DATA_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Resources INSTALL_DOC_PATH = $$INSTALL_DATA_PATH/doc INSTALL_BIN_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/MacOS INSTALL_APP_PATH = $$QTC_PREFIX/ } else { contains(TEMPLATE, vc.*):vcproj = 1 IDE_APP_TARGET = $$IDE_ID # target output path if not set manually isEmpty(IDE_OUTPUT_PATH): IDE_OUTPUT_PATH = $$IDE_BUILD_TREE IDE_LIBRARY_PATH = $$IDE_OUTPUT_PATH/$$IDE_LIBRARY_BASENAME/qtcreator IDE_PLUGIN_PATH = $$IDE_LIBRARY_PATH/plugins IDE_DATA_PATH = $$IDE_OUTPUT_PATH/share/qtcreator IDE_DOC_PATH = $$IDE_OUTPUT_PATH/share/doc/qtcreator IDE_BIN_PATH = $$IDE_OUTPUT_PATH/bin win32: \ IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/bin else: \ IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/libexec/qtcreator !isEqual(IDE_SOURCE_TREE, $$IDE_OUTPUT_PATH):copydata = 1 LINK_LIBRARY_PATH = $$IDE_BUILD_TREE/$$IDE_LIBRARY_BASENAME/qtcreator LINK_PLUGIN_PATH = $$LINK_LIBRARY_PATH/plugins INSTALL_LIBRARY_PATH = $$QTC_PREFIX/$$IDE_LIBRARY_BASENAME/qtcreator INSTALL_PLUGIN_PATH = $$INSTALL_LIBRARY_PATH/plugins win32: \ INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/bin else: \ INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/libexec/qtcreator INSTALL_DATA_PATH = $$QTC_PREFIX/share/qtcreator INSTALL_DOC_PATH = $$QTC_PREFIX/share/doc/qtcreator INSTALL_BIN_PATH = $$QTC_PREFIX/bin INSTALL_APP_PATH = $$QTC_PREFIX/bin } ``` 我們可以發現上面的內容大部分是基於IDE_BUILD_TREE和QTC_PREFIX的。 程式碼首先設定了可執行程式的目錄。 接下來,我們重點分析else分支的內容。 1. 如果TEMPLATE包含vc.*,其實就是vcapp或vclib,設定vcproj為1,表示是vs工程。 2. 設定可執行程式檔名為IDE_ID(預設為qtcreator)。 3. 設定輸出路徑IDE_OUTPUT_PATH預設為IDE_BUILD_TREE。 4. 設定IDE相關子資料夾路徑,可以發現都是相對於IDE_OUTPUT_PATH的。
5. 如果輸出路徑不是源目錄,則設定copydata為1,表示需要拷貝資料。 6. 考慮到IDE_BUILD_TREE與IDE_OUTPUT_PATH可能不一樣,設定IDE庫和外掛的連結路徑。 7. 設定INSTALLS用的相關子資料夾路徑。 ## 設定字串巨集 接下來是 ``` RELATIVE_PLUGIN_PATH = $$relative_path($$IDE_PLUGIN_PATH, $$IDE_BIN_PATH) RELATIVE_LIBEXEC_PATH = $$relative_path($$IDE_LIBEXEC_PATH, $$IDE_BIN_PATH) RELATIVE_DATA_PATH = $$relative_path($$IDE_DATA_PATH, $$IDE_BIN_PATH) RELATIVE_DOC_PATH = $$relative_path($$IDE_DOC_PATH, $$IDE_BIN_PATH) DEFINES += $$shell_quote(RELATIVE_PLUGIN_PATH=\"$$RELATIVE_PLUGIN_PATH\") DEFINES += $$shell_quote(RELATIVE_LIBEXEC_PATH=\"$$RELATIVE_LIBEXEC_PATH\") DEFINES += $$shell_quote(RELATIVE_DATA_PATH=\"$$RELATIVE_DATA_PATH\") DEFINES += $$shell_quote(RELATIVE_DOC_PATH=\"$$RELATIVE_DOC_PATH\") ``` ### [shell_quote](https://linux.die.net/man/1/shell-quote) > 在qmake中的介紹很簡單:為shell對arg加引號,當構建構建專案時。 > > 在linux man page中的介紹:可讓您通過shell傳遞任意字串,shell不會更改它們。 這使您可以安全地處理帶有`嵌入式空格`或shell globbing字元的命令或檔案。 ### qmake定義字串巨集 > 有時候,我們想定義字串巨集,並在原始碼中進行使用。假設你想在qmake中定義字串巨集,這裡有三種途徑 > >
> > 我們先來看一下qmake編譯得到的Makefile.Debug,符合makefile語法的形式 > > > > 現在我們來介紹下DEFINES中的含義: > > 1. NAME1中第一個"對,告訴qmake引導裡面的是字串。裡面的\\"對,是對引號的轉義,在makefile中變為"。再裡面的\\\\對,也是轉義,在makefile中變為\\。在裡面的\\"同樣,最終變為"。最終得到我們想要的字串。 > > 2. NAME2使用shell_quote()函式,該函式對引數加引號。 > > 3. NAME0對比NAME1,少了最外面的"對,這導致NAME0只能定義沒有空格的字串。如果存在空格,這會導致內容發生變化,中間多了個-D。 > > ``` > qmake: DEFINES += NAME0=\"\\\"app1 .0\\\"\" > makefile: -DNAME0="\"app1 -D.0\"" > ``` > > 此外,對於沒有空格的字串巨集定義,我們甚至可以不需要最外層的引號轉義。 > > ``` > qmake: DEFINES += NAME0=\\\"app1\\\" > makefile: -DNAME0=\"app1\" > ``` 分析程式碼: 1. 設定了PLUGIN,LIBEXEC,DATA和DOC相對於BIN的相對路徑,譬如PLUGIN的為../lib/qtcreator/plugins。 2. 使步驟1中的變數稱為字串,新增到DEFINES中,變為巨集。 ## 設定INCLUDEPATH 接下來是 ``` INCLUDEPATH += \ $$IDE_BUILD_TREE/src