Qt Creator 源碼學習 03:qtcreator.pro

當咱們準備好 Qt Creator 的源代碼以後,首先進入到它的目錄,來看一下它的源代碼目錄有什麼奧祕。python

Qt Creator 代碼目錄結構

這裏一共有 9 個文件夾和 9 個文件。咱們來一一看看它們都是幹什麼用的。linux

  • .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 項目組織結構,規定了咱們但願該項目如何編譯、編譯以後要作什麼操做等。git

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

 

 

第一行是 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)。有關$$以及相關運算符的使用至關重要。shell

$$運算符一般用於展開變量的內容,展開的內容能夠用於變量的賦值,也能夠用於函數的傳參。例如:windows

 

 

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

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

 

 

在上面代碼中,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/

相關文章
相關標籤/搜索