由於打算寫本電子書,所以重新審視了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,也就是要改寫