[英]Shared libraries and c++20 modules
聲明模塊接口或模塊分區的翻譯單元將被視為模塊單元,並且在編譯時將生成 object 文件和二進制模塊接口(BMI)。 BMI是抽象語法樹的二進制表示,是表示程序語法和數據類型的數據結構。 我們有傳統的 C++ 編譯管道:
程序 -> 預編譯器 -> 詞法分析器 -> 解析器 -> 匯編器 -> linker
對於 GCC,我們應該添加編譯器標志-c
,告訴編譯器編譯和匯編但不鏈接。
但是共享庫是由 linker 通過一起讀取幾個已編譯的 object 文件並創建一個共享的 object 來構建的。所以這發生在 BMI 構建之后。 BMI 可以在不將它們鏈接在一起的情況下構建,因為這是兩個不同的階段。
在 C# 構建 DLL 時,我們在 class 級別上具有可見性屬性,即。 public
的, private
的, internal
的。 在 C++ 中,我們可以獲得與模塊分區相同的功能。
模塊分區,聲明為module <module>: <partition>;
將在聲明export module <module>;
,但不在該模塊之外。 這讓我想起了 C# 的internal
模式。但是如果我們使用export module <module>: <partition>;
然后它的聲明將公開可見。 閱讀有關cppreference的更多信息。
我已經用 GCC (g++-11) 解決了這個問題,請看這里。
本質上,您不需要 DLL 導入/導出,因為(可能)不涉及標頭。 我試過插入這些可見性屬性,但我的編譯器抱怨說,所以我想我們可能根本不需要它們。 除此之外,這是標准程序。 我也在這里復制/粘貼我的示例:
import <iostream>;
import mathlib;
int main()
{
int a = 5;
int b = 6;
std::cout << "a = " << a << ", b = " << b << '\n';
std::cout << "a+b = " << mathlib::add(a, b) << '\n';
std::cout << "a-b = " << mathlib::sub(a, b) << '\n';
std::cout << "a*b = " << mathlib::mul(a, b) << '\n';
std::cout << "a/b = " << mathlib::div(a, b) << '\n';
return 0;
}
export module mathlib;
export namespace mathlib
{
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
}
GCC=g++-11 -std=c++20 -fmodules-ts
APP=app
build: std_headers mathlib main
std_headers:
$(GCC) -xc++-system-header iostream
mathlib: mathlib.cpp
$(GCC) -c $< -o $@.o
$(GCC) -shared $@.o -o libmathlib.so
main: main.cpp
$(GCC) $< -o $(APP) -Xlinker ./libmathlib.so
clean:
@rm -rf gcm.cache/
@rm -f *.o
@rm -f $(APP)
@rm -f *.so
g++-11 -std=c++20 -fmodules-ts -xc++-system-header iostream
g++-11 -std=c++20 -fmodules-ts -c mathlib.cpp -o mathlib.o
g++-11 -std=c++20 -fmodules-ts -shared mathlib.o -o libmathlib.so
g++-11 -std=c++20 -fmodules-ts main.cpp -o app -Xlinker ./libmathlib.so
./app
a = 5, b = 6
a+b = 11
a-b = -1
a*b = 30
a/b = 0
現在這顯然是特定於平台的,但該方法應該適用於其他平台。 我也用 Clang 測試了類似的東西(與鏈接的回購相同)。
C++20 模塊與共享庫沒有特殊關系。 它們主要是 header 文件的替換。
這意味着您將以與 C++20 之前的 header 文件類似的方式使用 C++20 模塊開發共享庫,至少以我目前的理解是這樣。 您設計了一些導出的 API(遺憾的是仍然使用特定於供應商的屬性,如__declspec(dllexport)
或__attribute__((visibility("default")))
)並實現它。 您構建共享庫文件 (.dll/.so) 和用於分發的導入庫,方法與之前相同。 但是,您將分發模塊接口單元,而不是分發 header 個文件。 模塊接口單元是包含export module ABC;
聲明在頂部。
然后使用該共享庫的可執行文件將使用import ABC;
,而不是#include
-ing header 文件。
編輯:正如評論中所指出的,似乎仍然有必要在 Windows 上提供模塊接口內的宏開關,以在 dllexport 和 dllimport 屬性之間切換,類似於對標頭所做的那樣。 但是,我目前還沒有對此進行試驗,只能參考@jeremyong 在C++ 模塊和動態鏈接的預期關系是什么? .
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.