簡體   English   中英

共享庫和 c++20 模塊

[英]Shared libraries and c++20 modules

關於在共享庫中正確使用 C++20 模塊的在線文檔很少。 許多顯然很感興趣,但我一直未能找到明確的解決方案。

在 MSVC 中,編譯庫時需要使用dllexport ,使用符號時需要使用dllimport 這可以使用“遺留 C++”中的宏來完成,但這不適用於 C++20 模塊,因為代碼只編譯一次,而不管預處理器指令如何。

這篇文章建議您現在只需要使用dllexportdllimport將由編譯器自動處理。 但是,這來自一條評論,該評論現已被刪除,我找不到關於該主題的任何可靠來源。

如何使用 C++20 模塊創建共享庫?

背景

聲明模塊接口或模塊分區的翻譯單元將被視為模塊單元,並且在編譯時將生成 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;
    }
}

Makefile

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM