C++ 模块的两步编译?

问题描述

Clang 和 GCC(也许还有 MSVC?)目前正在为其模块实现使用两步编译:

  • 生成 BMI/CMI(MSVC 的 IPR,如果它仍然这样做?)以供其他人的导入使用。
  • 生成要提供给链接器的目标文件

似乎有一些可能用于生成 BMI/CMI 但不生成目标文件的模块,例如仅导出用于条件编译的类型或 constexpr 变量的模块。

据我从标准中了解到,没有什么说我必须生成/链接对象文件。所以我想知道我是否遗漏了使用此类模块的一些明显内容,并且我们是否希望工具支持这种“作为模块构建,而不是作为对象构建”的工作流程?

解决方法

我希望模块能够为通常不包含标题的内容提供定义。

想象一下这个模块:

export module hello;

export inline auto say_hello() -> char const* {
    return "hello world";
}

如您所见,该函数是内联的。它也在界面中。现在有了标题,就没有地方放置实现了。为了使内联函数成为可能,该语言允许找到多个定义。所以每个 TU 在目标文件中输出他们自己的定义。

这是使用模块可以避免的重复工作。如您所见,模块接口就像任何其他 cpp 文件一样都是 TU。当您导出内联函数时,是的,其他 TU 可以使用该实现,但是 所有 tu 不需要提供实现,因为它可以放在一个地方:具有其中的内联函数。

我希望 constexpr 变量也能做到这一点。它们还需要定义,因为您可以引用它们或提供地址。以这个为例:

export module foo;
import <tuple>;
export constexpr auto tup = std::tuple{1,'a',5.6f};
import foo;
int a = std::get<0>(tup);

std::get 函数引用元组。即使它是一个 constexpr 变量,某些上下文(尤其是没有优化)可能需要使用 ODR 变量。

所以在我的例子中,即使模块 foo 只导出一个 constexpr 变量,我希望 cpp 文件编译成一个包含定义的目标文件。


也可能发生目标文件中什么都没有的情况。我也希望它今天表现得像一个空的 TU:

// I'm empty

您可以毫无问题地将这样的 cpp 文件添加到项目中,并将其链接到您的可执行文件。我希望这些工具与模块的行为相同。