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