由於打算寫本電子書,所以重新審視了C++20 Moudle的部分
語法的不是這篇的重點,這篇講的是
- 如何跟CMake搭配使用
- 測試環境是Linux + Clang20 + CMake 3.28
Prerequisites
首先先clone git repo,所有的變化都由範例legacy
開始,這是沒有Module之前的做法
CMake
CMake已經是事實上的標準
Case1 Normal case
詳細內容請觀看 module_1
目錄,這邊只講我覺得重要的地方
這個Case就是legacy
直接翻譯成Module版本
首先看MathFunctions
的CMakeLists.txt的部分
1 | target_sources(MathFunctions |
這邊有兩個FILE_SET
- primary_interface:也就是我們要對外提供的Primary module interface unit
- implementaion_units:內部的partion unit,不對外輸出
所以在安裝的時候,只會將MathFunctions.cppm
複製到安裝的目錄下Case2: Multiple Primary Module Interface Units
接著我們稍微修改MathFunctions.cppm
的內容我們也將detail的內容也輸出了,因此我們需要做以下的修改1
2
3
4
5
6
7
8
9module;
export module Math;
export import :detail;
export namespace mathfunctions
{
double sqrt(double);
} - detail module和namespace需要標記成
export
修改我們的CMakeLists.txt的部分1
2
3
4
5
6
7
8
9
10module;
export module Math:detail;
export namespace mathfunctions::detail {
double sqrt(double x) {
return ::sqrt(x);
}
}現在我們有了兩個Primary Module Interface Units,在安裝的時候也要同時複製兩個檔案1
2
3
4
5
6
7
8
9
10target_sources(MathFunctions
PUBLIC
FILE_SET primary_interface
TYPE CXX_MODULES
FILES
MathFunctions.cppm
src/mysqrt.cppm
PRIVATE
src/MathFunctions.cxx
)Math.detail
和Math:detail
的情況類似,所以就不說了
接著來研究Mitgrate的部分,這是參考clang Transitioning to modules的部分
Case3: Mitgrate legacy to module (Part1)
看一下transform_1
的目錄
這邊主要的差別在於CMakeLists.txt
1 | target_sources(MathFunctions |
既保留原有的leagcy code,更新增了一個Primary Module Interface Units
而MathFunctions.cppm
的內容則是
1 | module; |
將Global Module Fragment中的內容導出到Module中
這種方法不會破壞原有leagcy code,殺傷力最小
Case4: Mitgrate legacy to module (Part2)
看一下transform_21
的目錄,CMakeLists.txt跟上面一樣不變
改變的是MathFunctions.cppm
和MathFunctions.h
此時的MathFunctions.cppm
長這樣
1 | module; |
而MathFunctions.h
的內容則是
1 |
|
由於只有在Module狀態下,IN_MODULE_INTERFACE才會發揮作用,因此leagcy code的情況下會維持不變
這個方法雖然比上面麻煩,不過可以順利遷移到下一個階段
Case5: Mitgrate legacy to module (Part3)
所有方案中最麻煩的一種
主要思想是在implemtation unit當中切開legacy
和module
的實作,強迫Consumer只能使用其中一種,例如原先的Header可能要加上export
1 |
|
以及Implementation的部分也要隔開
1 |
|
在這裡我選擇對CMakeLists.txt動手腳
1 | if (ENABLE_MODULE_BUILD) |
當我們指定ENABLE_MODULE_BUILD
的時候,會自動處理細節的部分
不過這邊也遇到了clang文件中的問題
Minor issue
由於我們之前的mysqrt.h
是經由src/MathFunctions.cxx
所include的,改成Module之後,這個相依性被切斷了
因此我們需要在MathFunctions.cppm
強迫加入
1 | module; |
這樣沒有問題,不過
- 原來的
mysqrt.h
不需要公開,現在變成強迫要公開了 - 更好的方法是直接使用Module Partition Unit,也就是要改寫