如何创建没有标题的库?

问题描述

我们在 C++20 中有模块,我们可以完全删除代码中的 #include 吗?

比如我们可以写

import boost.asio;
...

代替

#include <boost/asio.hpp>
...

过去我们需要这些步骤来安装一个库:

  • 将所有源 (.cpp) 编译为对象 (.o)。
  • 将它们打包到一个库中(.a 或 .so)。
  • 将标头安装到 /usr/include 中。
  • 将库文件安装到 /usr/lib 中。

在 C++20 中,我们可以:

  • 编译所有源代码,但每个源文件可能会生成一个对象 (.o) 和一个编译模块接口 (CMI)。对于 gcc,它们有 .gcm 后缀。
  • 将对象 (.o) 打包到库(.a 或 .so)中。
  • 将库文件安装到 /usr/lib 中。
  • 将 CMI 安装到某个路径中。

但是使用 CMI 发布您的库会导致问题:

  • 我们没有专门的文件夹来放置 CMI(我猜可能是 /usr/include/c++-modules)。
  • 不同的编译器产生不同的 CMI。开发人员为他们的库提供不同版本的 CMI 是很糟糕的。
  • 如果我们根据模块 B 编译模块 A,但使用不同的编译标志会怎样?不同的标志可能不会引起您的注意,但可能会导致潜在的错误

用 CMI 替换标头不是一个方法。那么我们如何才能从 C++ 中彻底删除文件呢?


我不是在谈论标准库,因为在 c++23 中引入了模块化的 c++ 标准库。

解决方法

模块并不是一种二进制分发机制;您应该期望提供模块接口文件(,编译为库中目标文件的相同文件, 它们不是头文件)以非常头文件的方式,并将 CMI 生成和缓存留给客户端的编译器和构建树(分别)。因此,只有在使用给定模块的第一个翻译单元之后,每个客户端才能实现构建速度优势。

在实践中很可能会出现其他共享机制,但这里的重要部分是它本质上并不比现有的构建策略更复​​杂或更不兼容。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...