惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Vulnerabilities – Threatpost
aimingoo的专栏
aimingoo的专栏
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
GbyAI
GbyAI
阮一峰的网络日志
阮一峰的网络日志
Engineering at Meta
Engineering at Meta
IT之家
IT之家
V
Visual Studio Blog
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
A
About on SuperTechFans
博客园 - 聂微东
Blog — PlanetScale
Blog — PlanetScale
N
News and Events Feed by Topic
A
Arctic Wolf
WordPress大学
WordPress大学
小众软件
小众软件
C
CERT Recently Published Vulnerability Notes
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Darknet – Hacking Tools, Hacker News & Cyber Security
F
Fortinet All Blogs
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Y
Y Combinator Blog
T
Threat Research - Cisco Blogs
Latest news
Latest news
Simon Willison's Weblog
Simon Willison's Weblog
Cyberwarzone
Cyberwarzone
S
Schneier on Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
L
Lohrmann on Cybersecurity
Stack Overflow Blog
Stack Overflow Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy International News Feed
J
Java Code Geeks
Spread Privacy
Spread Privacy
宝玉的分享
宝玉的分享
I
Intezer
L
LangChain Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
G
GRAHAM CLULEY
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
The GitHub Blog
The GitHub Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
N
News and Events Feed by Topic
AWS News Blog
AWS News Blog
Attack and Defense Labs
Attack and Defense Labs
Security Archives - TechRepublic
Security Archives - TechRepublic
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

I'm OWenT

国产大模型(GLM 5.1、Kimi K2.6)真实场景效果和 Coding Plan 额度测试 新版本libatapp的连接管理——从etcd服务发现到拓扑驱动的自动重连 新版本libatbus的设计变更——从树形路由到拓扑驱动 Protobuf又一坑 - C++标准和ABI兼容性 AI真好用-给Blog主题统一加mermaid,chart.js,excalidraw,draw.io的多种引入方式支持 给内网部署Squid-通用HTTP下载缓存 UE使用CodeChecker和clang-tidy生成静态分析报告 找出UE的循环依赖 C++小协程栈和临时变量及作用域的栈溢出问题分析 游戏服务的可观测性能力建设(C++生态) 指标上报的多线程优化和多拉取源点优化 协程(libcopp)的Channel功能和CPU命中率优化 通用RPC代码生成器 实现strong_rc_ptr(比shared_ptr更快的引用计数智能指针) 手夯一个STL allocator和对象内存分析组件 std::condition_variable 的信号丢失问题 踩坑一处(GCC)STL std::async 实现BUG导致的crash问题 GCC 14的一个warning to error BUG 给xresloader(Excel导表工具)增强UE读表支持(包含蓝图,Blueprint) Opentelemetry社区在gRPC的几个链接问题(静态库和动态库混用,musl工具链,符号裁剪) Excel转表工具(xresloader)的新验证器(验证外部Excel和文本数据,唯一性和自定义规则) protobuf v22和gRPC v1.55版本升级的依赖变化和upb适配 关于protobuf近期版本(v20/v3.20+)和 gRPC v1.54版本在某些编译环境下的一些链接和编译问题 xresloader-Excel导表工具链的近期变更汇总 打通游戏服务端框架的C++20协程改造的最后一环 Opentelemetry-cpp的Logs模块标准更新(涉及近期版本:1.8-1.9的BREAK CHANGES) 给cmake-toolset和工具链(curl等)加HTTP/2和HTTP/3支持 又开新坑之 coredns 插件: nftables和filter 关于opentelemetry-cpp社区对于C++ Head Only组件单例和符号可见性的讨论小记 填个转表工具 xresloader 去年的坑(数组尾部裁剪) 集成 upb 和 lua binding 的踩坑小记 libcopp对C++20协程的接入和接口设计 再度优化GCC、LLVM、Clang、libc++、libc++abi等套件的构建脚本 游戏服务的分布式事务优化(二)- 事务管理 游戏服务的分布式事务优化(一)- Write Ahead Log(WAL) 模块 记录一些bazel适配用编译选项 测试现代化硬件C++浮点数性能和一致性 适配Boringssl和OpenSSL 3.0 近期cmake-toolset的一些适配问题 C++20 Text Formatting/fmtlib 适配问题小记 再次重构LLVM+Clang+libcxx+libc++abi+其他相关工具的构建流程 重构基于CMake的构建工具链 新版GCC和LLVM+Clang终于Release啦 折腾一下nftables下的双拨 [Rust] 实现一个线程安全且迭代器可以保存的链表 基于protobuf的代码生成 几个使用protobuf中C++接口的Arena的坑 Amazon Aurora DB存储引擎论文阅读小记 近期对libatapp的一些优化调整(增加服务发现和连接管理,支持yaml等) xresloader转表工具链增加了一些新功能(map,oneof支持,输出矩阵,基于模板引擎的加载代码生成等) 在游戏服务器中使用分布式事务 libcopp接入C++20 Coroutine和一些过渡期的设计 libatbus 的大幅优化 nftables初体验 容器配置开发环境小计 PALM Tree - 适合多核并发架构的B+树 - 论文阅读小记 跨平台协程库 - libcopp 简介 C++20 Coroutine 性能测试 (附带和libcopp/libco/libgo/goroutine/linux ucontext对比) 尝鲜Github Action 一些xresloader(转表工具)的改进 protobuf、flatbuffer、msgpack 针对小数据包的简单对比 协程框架(libcopp) 小幅优化 Excel转表工具(xresloader) 增加protobuf插件功能和集成 UnrealEngine 支持 Anna(支持任意扩展和超高性能的KV数据库系统)阅读笔记 C++20 Coroutine libcopp merge boost.context 1.69.0 Google去中心化分布式系统论文三件套(Percolator、Spanner、F1)读后感 Rust玩具-企业微信机器人通用服务 使用ELK辅助监控开发测试环境服务质量和问题定位 2018年的新通用伪随机数算法(xoshiro / xoroshiro)的C++(head only)实现 Webpack+vue+boostrap+ejs构建Web版GM工具 Rust的第二次接触-写个小服务器程序 理解和适配AEAD加密套件 atsf4g-co的进化:协程框架v2、对象路由系统和一些其他细节优化 协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比 可执行文件压缩 初识Rust 使用restructedtext编写xresloader文档 atframework的etcd模块化重构 C++的backtrace ECDH椭圆双曲线(比DH快10倍的密钥交换)算法简介和封装 protobuf-net的动态Message实现 pbc的proto3接入 atgateway内置协议流程优化-加密、算法协商和ECDH 整理一波软件源镜像同步工具+DevOps工具 Blog切换到Hugo libcopp v2的第一波优化完成 libcopp(v2) vs goroutine性能测试 libcopp的线程安全、栈池和merge boost.context 1.64.0 GCC 7和LLVM+Clang+libc++abi 4.0的构建脚本 libatbus的几个藏得很深的bug 用cmake交叉编译到iOS和Android 开源项目得一些小维护 atapp的c binding和c#适配 对象路由系统设计 2016年总结 近期的一个协程流程BUG 重写了llvm+clang+libc++和libc++abi的构建脚本 atsf4g完整游戏工程示例|I'm OWenT atframework基本框架已经完成|I'm OWenT
[C++20] Module partitions和符号交叉引用(声明和实现分离)
owent · 2021-03-26 · via I'm OWenT

blog-website

C++20 开始支持 Module 了。在以前C++为了解决循环依赖问题,经常会把类或者函数声明写前面,实现写后面。然后中间的代码就可以实现内部模块的内聚而互相引用。比如:

class foo;

void bar(foo*);

class foo {
public:
    foo(){
        bar(this);
    }
};

那么在 Module 里怎么处理这种需求呢?其实我之前一直只是知道有这么个东西,并没有深入研究过。前段时间看到公司论坛里有同学问,就现学了并且试了一下,以下是一些记录。

问题

举个例子,比如有两个文件:

// file: base.ixx
module;
#include <iostream>
#include <typeinfo>
export module base;

class derived;
export class base {
public:
	virtual ~base() = default;
	virtual void visit(derived*) {
		std::cout << "base::visit -> "<< typeid(*this).name() << std::endl;
	}
};
// file: derived.ixx
module;
#include <iostream>
#include <typeinfo>
export module derived;
export import base;

export class derived : public base {
public:
	virtual void visit(derived*) override {
		std::cout << "derived::visit -> "<< typeid(*this).name() << std::endl;
	}
};

程序的本意是 derived 继承 base 类。但是 derived::visit(derived*) 在多态上override了 base::visit(derived*) 。但是实际上这里在 base.ixx 里的 class derivedderived.ixx 里的 class derived 不是同一个类。因为他们是处于不同模块内的,作用域和可见性也都不同。

按目前 Modules 文档的说法,是 禁止跨模块交叉引用 的。 为了实现模块可以跨多个文件和让接口与实现隔离,可以使用 Module partitions 功能。

最新 Module partitions 的规范见 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1103r3.pdf 的 2.2 Module partitions 章节。 最早关于 Module partitions 的提案和要解决的问题可参见 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0775r0.pdf 。

简单来说 Module partitions 有几个特性:

  1. 使用 : 符号来分隔base模块名和partition名。
  2. base模块名决定了链接符号的所有权。
  3. 通过 export module INDETIFYINDETIFY 是否包含 : 来区分当前文件是一个 Module partitions 还是 Unpartitioned module
  4. Module partitions 仅能被其他同一个base模块名的 Module partitions 或者base模块本身来 imported

写个sample

// file: foo-types.ixx
module;

export module foo:types;
export class derived;
// file: foo-base.ixx
module;
#include <iostream>
#include <typeinfo>

export module foo:base;
import :types;

export class base {
public:
    virtual ~base() = default;
    virtual void visit(derived*) {
        std::cout << "base::visit -> "<< typeid(*this).name() << std::endl;
    }
};
// file: foo-derived.ixx
module;
#include <iostream>
#include <typeinfo>

export module foo:derived;
import :types;
import :base;

export class derived : public base {
public:
    virtual void visit(derived*) {
        std::cout << "derived::visit -> "<< typeid(*this).name() << std::endl;
    }
};
// file: foo.ixx
module;

export module foo;

export import :types;
export import :base;
export import :derived;
// file: main.cpp
import foo;

int main() {
    derived d;
    derived* pd = &d;
    base* pb = pd;
    pb->visit(nullptr);
    pd->visit(nullptr);

    return 0;
}

执行输出结果如下:

derived::visit -> class derived
derived::visit -> class derived

编译命令

MSVC

cl /std:c++latest /c /experimental:module foo-types.ixx /nologo /EHsc /MDd
cl /std:c++latest /c /experimental:module foo-base.ixx /nologo /EHsc /MDd
cl /std:c++latest /c /experimental:module foo-derived.ixx /nologo /EHsc /MDd
cl /std:c++latest /c /experimental:module foo.ixx /nologo /EHsc /MDd
cl /std:c++latest /c /experimental:module main.cpp /nologo /EHsc /MDd
cl /nologo /EHsc /MDd main.obj foo.obj foo-derived.obj foo-base.obj foo-types.obj

Clang

Clang 目前还不支持 Module partitions 功能。(我这里的版本是 Clang 11.0.0) 猜测以后支持了的话,命令应该是下面这样:

clang++ -std=c++20 -stdlib=libc++ -fmodules --precompile -fprebuilt-module-path=. -x c++-module foo-types.ixx -o foo-types.pcm
clang++ -std=c++20 -stdlib=libc++ -fmodules --precompile -fprebuilt-module-path=. -x c++-module foo-base.ixx -o foo-base.pcm
clang++ -std=c++20 -stdlib=libc++ -fmodules --precompile -fprebuilt-module-path=. -x c++-module foo-derived.ixx -o foo-derived.pcm
clang++ -std=c++20 -stdlib=libc++ -fmodules --precompile -fprebuilt-module-path=. -x c++-module foo.ixx -o foo.pcm
clang++ -std=c++20 -stdlib=libc++ -fmodules -fprebuilt-module-path=. main.cpp

也可能需要用 module-map-file 来辅助文件查找。

GCC

GCC 11以上才初步支持 Module 。我本地下了个snapshot的GCC( gcc version 11.0.1 20210321 (experimental) (GCC) )。 但是GCC有BUG编不出来。可以有兴趣可以跟进一下 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99769 ,等解决了大致上就是下面这样的命令:

g++ -fmodules-ts -std=c++20 -x c++ -c foo-types.ixx -o foo-types.o
g++ -fmodules-ts -std=c++20 -x c++ -c foo-base.ixx -o foo-base.o
g++ -fmodules-ts -std=c++20 -x c++ -c foo-derived.ixx -o foo-derived.o
g++ -fmodules-ts -std=c++20 -x c++ -c foo.ixx -o foo.o
g++ -fmodules-ts -std=c++20 -c main.cpp foo.o foo-derived.o foo-base.o foo-types.o

参考文献

  • https://www.modernescpp.com/index.php/c-20-module-interface-unit-and-module-implementation-unit
  • https://zhuanlan.zhihu.com/p/350136757
  • http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1103r3.pdf
  • http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0775r0.pdf
  • https://en.cppreference.com/w/cpp/language/modules
  • https://clang.llvm.org/docs/Modules.html
  • https://gcc.gnu.org/wiki/cxx-modules#Compiled_Module_Interface_Files
  • https://devblogs.microsoft.com/cppblog/standard-c20-modules-support-with-msvc-in-visual-studio-2019-version-16-8/

最后

第一次上手 C++ Module ,可能文中有不正确的地方。欢迎指正交流。