Qt Creator 源碼學習 03:qtcreator.pro


當我們准備好 Qt Creator 的源代碼之后,首先進入到它的目錄,來看一下它的源代碼目錄有什么奧秘。

Qt Creator 代碼目錄結構

這里一共有 9 個文件夾和 9 個文件。我們來一一看看它們都是干什么用的。

  • .git: 版本控制 git 的隱藏目錄,這與 Qt Creator 代碼沒有關系。
  • bin: 生成 Linux 平台 shell 腳本。
  • dist: 安裝文件配置信息和版本更新記錄。
  • doc: 生成 doxygen 文檔的配置文件。
  • qbs: QBS 配置文件。QBS,即 Qt Build Suite,是一種跨平台的編譯工具,目的是將高層的項目描述(使用類似 QML 的語言)轉換成底層的編譯描述(供 make 等工具使用的信息)。它可以簡化多平台的編譯過程。QBS 與 qmake 類似,區別在於前者適用於任意項目,而后者一般僅供 Qt 項目使用。我們在閱讀代碼時將關注 qmake,不會深入研究 QBS 的使用。
  • scripts: Qt Creator 使用的 perl 以及 python 等腳本。
  • share: 源代碼中所需要的一些非代碼共享文件,例如代碼模板等。
  • src: Qt Creator 源代碼文件。
  • tests: Qt Creator 測試代碼。
  • .gitignore: git 忽略文件配置。
  • .gitmodules: git 子模塊配置。
  • HACKING: Qt Creator 編碼規范。
  • LICENSE.GPL3-EXCEPT: GPLv3 協議。
  • qtcreator.pri: Qt Creator 項目需要使用的通用配置,該文件一般會被 include 到大部分 pro 文件。
  • qtcreator.pro: Qt Creator 的 qmake 項目文件。
  • qtcreator.qbs: Qt Creator 的 QBS 項目文件。
  • qtcreatordata.pri: Qt Creator 數據相關的配置。
  • README.md: 有關如何編譯 Qt Creator 等相關事宜的一些說明。

閱讀源代碼,一般可以從main()着手。但是閱讀 Qt 項目的源代碼,我們也可以從 pro 文件開始。pro 文件是 Qt 項目組織結構,規定了我們希望該項目如何編譯、編譯之后要做什么操作等。

下面我們從根目錄的 qtcreator.pro 開始。使用 Qt Creator 或者任意文本編輯器打開 qtcreator.pro,開始真正的代碼閱讀。

 

 

第一行是 include qtcreator.pri。前面我們提到過,qtcreator.pri 中定義了很多函數和適用於各個模塊的通用操作。pri 文件可以理解為 pro 文件片段,可以使用include操作符將其引入一個 pro 文件。qmake 會自動處理引用操作,類似於將 pri 文件的全部內容復制到include語句處。這與 C++ 的#include指令類似。這里的處理是線性的,也就是 qmake 會從上向下進行解析。因此,如果你在 pri 中定義了一個函數,那么必須在include語句之后才能正常使用該函數。這是在使用時需要注意的。有關 qtcreator.pri 文件的內容,會在以后的文章中詳細介紹。如果你使用 Qt Creator 打開,include語句會在左側的項目樹中顯示一個節點。這種節點不需要物理上的文件夾隔離,只需要include不同的 pri 文件即可。這樣,即便你的所有文件都在同一個目錄下,你也可以使用 pri 文件創建出來多個虛擬目錄節點。這樣的項目結構看起來會清晰很多。

 

 

接下來的幾行用於判斷 Qt 的版本。minQtVersion()是在 qtcreator.pri 中定義的函數。沒錯!pro 也可以定義自己的函數!這正是 pro 的強大之處。我們會在后面詳細介紹如何定義函數。顧名思義,這個函數函數用於判斷 Qt 的版本。前面的!即取非運算符,這與 C++ 一致。當 Qt 的版本低於 5.6.0 時,執行塊中的操作。message()是 qmake 預定義的函數,類似於qDebug(),可以在控制台輸出一段文本。這里我們輸出的是“Cannot build Qt Creator with Qt version $${QT_VERSION}.”。字符串最后的$${QT_VERSION}是占位符,會使用QT_VERSION變量的內容進行替換。這一操作被稱為變量展開(variable expansion)。有關$$以及相關運算符的使用相當重要。

$$運算符通常用於展開變量的內容,展開的內容可以用於變量的賦值,也可以用於函數的傳參。例如:

 

 

上面的代碼中,第一行將SOURCESHEADERS的內容賦值給EVERYTHING;第三行則將EVERYTHING作為函數參數賦值給message()函數。如果沒有$$運算符,將只會輸出EVERYTHING字符串。

變量可以保存環境變量。這些變量可以在 qmake 執行時計算出,或者直接包含在 Makefile 中以便構建時使用。如果需要在 qmake 運行時獲取環境變量的值,使用$$()$${}運算符。例如:

 

 

在上面代碼中,PWD是 qmake 內置的一個環境變量,用於表示當前正在處理的文件所在文件夾的絕對路徑。使用$$()${}運算符,會在 qmake 運行時將值賦給DESTDIR。如果需要在生成 Makefile 時獲取環境變量的值,則需要使用$()運算符。例如:

 

 

在上面的語句中,PWD的值在 qmake 處理是就已經獲取到了,但是$(PWD)則會在生成的 Makefile 中賦值給DESTDIR。這能夠保證在處理 Makefile 時環境變量是正確的。

通過上面的解釋,我們知道,$${QT_VERSION}會在 qmake 運行時進行變量展開。

下面再來看另外的代碼:

 

 

這是 qmake 典型的配置。TEMPLATE即代碼模板,將告訴 qmake 我們要怎么生成最后的文件。它的可選值分別是:

  • app:創建用於構建可執行文件的 Makefile。
  • lib:創建用於構建庫的 Makefile。
  • subdirs:創建依次構建子目錄中文件的 Makefile。子目錄使用SUBDIRS變量指定。
  • aux:創建不構建任何東西的 Makefile。如果構建目標不需要編譯器,就可以使用這個模板。例如,你的項目使用的是解釋型語言,就可以這么做。注意,此時生成的 Makefile 僅適用於基於 Makefile 的生成器,不一定能供 vcxproj 或 Xcode 使用。
  • vcapp:僅適用於 Windows 平台,用於生成 VS 應用程序項目。
  • vclib:僅適用於 Windows 平台,用於生成 VS 庫項目。

我們最常用的是前三種設置。對於大型項目,一般會分成多個源代碼文件夾,因此,Qt Creator 使用的是 subdirs。接下來一行,CONFIG += ordered意思是,按照SUBDIRS書寫順序來編譯。很多時候,我們雖然將源代碼分為不同目錄,但是這些目錄之間是存在依賴關系的。比如,一個基礎類庫要被其它所有模塊使用,在編譯時,該類庫應該首先被編譯。這要求我們按照一定的順序來添加SUBDIRS。有關這一點,Qt Creator 是這樣做的:

 

 

首先,SUBDIRS只有兩個目錄:src 和 share。按照順序,應該是先編譯 src,然后編譯 share。后面則是一串復雜的判斷:對於 Unix 平台(unix),如果不是 Mac OS(!macx),並且copydata不為空(!isEmpty(copydata)),則需要再增加一個 bin 目錄。最后再判斷,如果BUILD_TESTS不為空(!isEmpty(BUILD_TESTS)),則再增加一個 tests 目錄。+=運算符就像它所展示的那樣,用於追加新的值。copydataBUILD_TESTS都是在 qtcreator.pri 中定義的宏。因為我們是在最前面include了 qtcreator.pri,所以我們可以自由使用在 qtcreator.pri 文件中定義的變量。類似!isEmpty(BUILD_TESTS):SUBDIRS += tests這樣的寫法是一種簡寫,完整的寫法應該如下所示:

 

 

有關isEmpty()這樣的函數,我們會在下面詳細介紹。我們在看這段代碼時,可以同 C++ 代碼作類比,以便我們理解:

 

 

接下來我們遇到的是

 

 

DESTFILES知道需要在最終的目標包括的文件。按照 qmake 的文檔,這一特性只適用於 UnixMake。這里我們又遇到了熟悉的$$file(),只不過這里不是變量展開,而是函數調用。

qmake 提供了兩類函數:替換函數(replace functions)和測試函數(test fucntion)。替換函數用於處理數據並將處理結果返回;測試函數的返回值只能是bool值,並且可以用於一些測試的情形。在使用時,替換函數需要添加$$先導符而測試函數則不需要。

$$file()正是一個替換函數,接受一個正則表達式作為參數,其返回值是所有符合這個正則表達式的文件名列表。因此,$$file(dist/changes-*)返回的是在當前目錄下的 dist 文件夾中,所有以 changes- 開頭的文件,將它們全部添加到了DESTFILES。另外,這一函數還可以有第二個參數,是一個bool值,默認是false,表示是不是要遞歸尋找文件。

之后我們看到了

 

 

exists()則是一個測試函數,顧名思義,該函數用於測試其參數作為文件名,所代表的文件是否存在。注意測試函數的使用:它可以直接作為測試條件,后面跟着一對大括號,如果函數返回值為true則執行塊中的語句。這里我們發現 src/shared/qbs/qbs.pro 並不存在,因此其中的語句並不會執行。

下面是語句

 

 

QT_VERSION是 qmake 內置的一個變量,用於表示 Qt 的架構。很明顯,contains()是一個測試函數,其函數原型是contains(variablename, value),當變量variablename中包含了value時,測試通過。那么,上面語句即是,如果QT_ARCH中有i386,則將ARCHITECTURE賦值為x86,否則就是$$QT_ARCH。注意在使用contains函數時,QT_ARCH並沒有使用$$運算符。因為在使用該函數時,第一個參數是變量名,函數會自己取該變量名的實際值。

 

 

定義了一個新的宏PLATFORM。注意這里使用了前面剛剛定義的ARCHITECTURE宏。

接下來,

 

 

是一種常見的寫法。首先,我們定義了BASENAME宏為$$(INSTALL_BASENAME);之后,如果BASENAME為空的話(使用了測試函數isEmpty()進行判斷),則定義新的BASENAME的值。這種寫法一方面允許我們在編譯時通過傳入自定義值改變默認設置(也就是說,如果之前定義了INSTALL_BASENAME,那么就會使用我們定義的值),否則就會生成一個默認值。以后我們會發現,Qt Creator 的 pro 文件中,很多地方都使用了類似的寫法。

跳過部分代碼,接下來是一大段:

 

 

這里使用macx分為兩部分。很明顯,如果系統是macx,則定義宏APPBUNDLE。我們需要詳細解釋的是,在定義新的變量時,Qt Creator 所用到的那些宏。首先,$$OUT_PWD是 qmake 生成的 Makefile 所在的文件夾。

下面我們會看到一個新的語法:$$[]。這是取 qmake 的屬性。qmake 內置了很多屬性值,例如:

 

 

在運行時,qmake 可以自定義屬性:

 

 

然后,我們就可以用下面語句獲取這個屬性:

 

 

在 pro 文件中,則可以使用$$[]獲取這些屬性。可以查閱文檔找到 qmake 內置了哪些屬性。

語句

 

 

定義了一個目標 deployqt,這個目標的命令是$$PWD/scripts/deployqtHelper_mac.sh \"$${APPBUNDLE}\" \"$$[QT_INSTALL_TRANSLATIONS]\" \"$$[QT_INSTALL_PLUGINS]\" \"$$[QT_INSTALL_IMPORTS]\" \"$$[QT_INSTALL_QML]\"。我們可以使用message()函數輸出這條命令。命令的具體實現暫不深究,感興趣的話可以閱讀 scripts/deployqtHelper_mac.sh 文件。接下來的語句是類似的。最后,這些定義的目標被添加到QMAKE_EXTRA_TARGETS。這才是真正重要的內容。

盡管 qmake 努力成為一個跨平台的構建工具,但是很多時候,我們不得不使用特定平台的語句。例如,一個常見的任務是,在編譯完成之后,將預置的配置文件復制到特定目錄。這種目標可以通過類似的語法進行定義,然后將定義好的目標添加到QMAKE_EXTRA_TARGETS。當 qmake 運行完畢后,會接着執行這些目標,直到編譯成功。

例如,

 

 

mytarget是一個自定義目標;mytarget.target是這個自定義目標的名字。之后生成的 Makefile 中將會使用這個名字作為 target。mytarget.commands定義了這個目標的命令:使用touch命令生成一個文件。mytarget.depends定義這個目標依賴於mytarget2,盡管mytarget2是在后面定義的。最后,我們將這兩個目標都添加到QMAKE_EXTRA_TARGETS

 

 

最后,我們來看

 

 

有是一個新的語法~=~=運算符將符合正則表達式的內容替換為后面的部分。例如DEFINES ~= s/QT_[DT].+/QT會將以QT_DQT_T開頭的文本替換為QT。后面s,/,\\\\,g是替換操作。三個逗號分為四個部分:第一個s表示輸入字符串;第二個/表示 /;第三個\\\\表示 \,之所以是四個,是因為 \ 需要轉義;第四個g表示全局替換。合起來的意思就是,將輸入字符串中的 / 全部替換為 \。這是適配命令路徑中,Unix 的 / 和 Windows 的 \。這一個技巧在編寫跨平台代碼中非常有用,很多時候我們在 pro 中給出了 Unix 格式的路徑,只需要使用簡單的語句,例如

 

 

就可以轉換為合法的 Windows 路徑。

本章我們着重學習了 Qt Creator 的主項目文件 qtcreator.pro 的寫法。下一節我們將詳細介紹 qtcreator.pri 的寫法。

https://www.devbean.net/2016/08/qt-creator-source-study-03/


免責聲明!

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



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