modern cmake的概念剖析

2021-10-11 07:28:21 字數 2456 閱讀 2679

如果要學習modern cmake,最基本的是要搞清楚檔案之間以及專案之間的依賴關係。在c++中,檔案之間的依賴關係主要來自兩個方面:

include標頭檔案;

函式宣告和實現的分離,宣告依賴於實現才能正確鏈結;

按照依賴關係,把乙個專案中所有檔案都連上箭頭,我們可以得到乙個有向圖。(通常是帶環的)

如果對這個專案進行編譯鏈結,所有的cpp檔案會編譯鏈結成乙個整體,它們的依賴關係也會合併。同時,由於cpp中的include在編譯過程中已經展開了,所以cpp檔案中由(1. include標頭檔案)引入的依賴關係會消失,而(2. 函式宣告和實現的分離,宣告依賴於實現才能正確鏈結)只會剩下.**件對.cpp檔案的依賴,.cpp檔案對.**件的依賴往往不存在(正常來說沒有人會在乙個cpp檔案宣告某個函式並且在另乙個**件中實現它)。於是,生成的lib檔案不會依賴於任何檔案(動態鏈結是另一種情況,暫且不提),不過,**件引入的依賴關係依舊會儲存。這時,整個專案只剩下不同**件之間的依賴關係和**件對lib的依賴。

如果這個專案是乙個庫,我們往往會把庫中的一些**件提供給外部使用,另一部分則隱藏起來。把提供給外部使用的標頭檔案設定為inte***ce,相應的,這些提供給外部使用的標頭檔案所依賴的其它標頭檔案也應當設定為inte***ce(顯然,inte***ce必須要隨著依賴關係傳遞,如果a依賴於b並且a是inte***ce的,那麼b也是inte***ce的)(一般的做法是把這些標頭檔案單獨放到乙個目錄並且通過target_include_libraries(inte***ce)來設定,事實上,由於include是通過目錄來尋找.**件,我們不能單獨把某個標頭檔案設定為inte***ce,只能把某個目錄設定為inte***ce)。如果乙個標頭檔案不需要提供給外面,也不會被其它提供給外部的標頭檔案引用,只是自己編譯鏈結才需要,則設定為private,private可以理解為在編譯鏈結後就不復存在的東西,只是編譯鏈結時使用。既是inte***ce又是private的標頭檔案則設定為public。絕大多數情況下,由於**件往往依賴於lib,所以lib也會提供給外部使用,預設為inte***ce,不需要顯示指出(實際上也沒法指出來,在cmake的相關教程中並未說明編譯後的lib是inte***ce還是private,但從邏輯上看,把編譯後的lib理解為inte***ce是非常合理的)。同時,由於cpp檔案無法對外提供(一般不會去include乙個cpp檔案),所以cpp檔案預設為private。(某些特殊情況下,有些cpp不會被編譯,可以把這些cpp檔案指定為inte***ce)。

簡單的理解,inte***ce是提供給外部使用的,private是自己編譯鏈結專案所使用。另外,還有乙個名為public的關鍵字,如果既是inte***ce也是private,則設定為public。

在上一節已經提到,對於乙個專案來說,設定為inte***ce的檔案是提供給外部使用的。於是,如果乙個專案要使用另乙個專案,這個專案也就只能拿到另乙個專案中設定為inte***ce的檔案而接觸不到設定為private的檔案。事實上,對於這個專案來說,另乙個專案就是另乙個專案中所有設定為inte***ce的檔案的合集。於是,可以仿照上一節中,把檔案區分為inte***ce或private,專案也可以被區分為為inte***ce或private。另外,在正式使用中,不止檔案和專案,其它屬性也可以區分為inte***ce或者private。

在cmake中還有乙個相當有趣的東西,inte***ce libraries。乙個不編譯鏈結的專案是乙個inte***ce libraries(通過add_libraries(inte***ce)指明)。由於自己不編譯鏈結,所以不存在private的東西,全是inte***ce。這個指令主要用來處理:

只有標頭檔案的庫;

沒有指明extern 「c"或者__declspec (dllexport)或者def檔案的庫(比如opengl的glad庫);

屬性表

以上這些情況下,對應的庫都不能編譯鏈結,因此只能作為inte***ce libraries來管理。

在上面幾節中,還只提到了靜態的編譯鏈結問題,對於動態鏈結與載入該如何處理則沒有提到。事實上,cmake和編譯器並不能很好的解決第三方dll的動態載入問題,動態鏈結本身也不是編譯器的任務(在path裡設定dll的路徑是無效的,只有在系統環境變數新增path或者dll和exe在同乙個目錄時才能找到正確的dll)。因此,對於dll的管理,需要自己手動寫add_custom_target和add_custom_command去管理。除此之外,在c++的**中還可能動態的載入一些檔案或者,這些同樣超出了cmake的職責,只能自己寫add_custom_target和add_custom_command去管理。

在cmake 3.0之前,cmake一直是全域性變數漫天飛,成不成功全看運氣。為了解決這一問題,從3.0開始,cmake要求盡量少的使用全域性變數,而是用專案去管理所有的東西。

從上面這幾節可以發現,乙個專案,既可以是乙個檔案、也可以是乙個大型的庫、也可以是乙個屬性表、還可以是乙個命令或者一組命令,具有非常高的靈活性。同時,又通過inte***ce和private來區分專案對其它事物的使用,極大的簡化了編譯鏈結中的邏輯,使得編譯鏈結的管理變得愈發清晰,這也正是modern cmake所推崇的。

樹剖 LCA模板 對樹剖的再認識

首先我們已經明確,樹鏈剖分是將樹上操作轉化為線性操作的高階暴力。樹轉鏈的操作,我們可以通過兩遍dfs來實現。然後我們利用線段樹或樹狀陣列之類的來維護第二遍dfs序即可。鑑於我已經兩年每寫過模擬之外的東西了 今天上午複習了spfa,這個另算 這次的重點放在了對dfs的理解上。一開始想用結構體,後來又想...

stl numeric中的power演算法剖析

在power演算法中求乙個數x的n次方分成兩部分,一是當n為偶數時計算方法,另一部分是當n為奇數時的計算方法。在n的 分解 過程中,還可能還會出現偶數和奇數部分的 都參與計算。n為偶數,計算方式 假設 y x x z n 2 那麼xn y z。例如如下步驟 28 4 4。1 44 16 2。2 16...

Gmsh的網格剖分模組

第6章 網格剖分模組 gmsh的網格剖分模組集中了幾種1維,2維,3維的網格剖分演算法,他們都能產生適合於有限元的網格 2維的非結構化演算法產生三角單元或者三角單元與四方形 當使用拼接曲面時 3維的非結構化演算法產生四面體單元。3維的結構化演算法 超限或拉伸 預設產生三角單元,但是通過recombi...