VS 2015更新1中的C++模块

点这里看中文版

null

[这篇文章是加布里埃尔·多斯雷斯和安德鲁·帕多写的]

更新:请参阅 在MSVC中通过模块使用标准库 .

VC++团队很高兴能预览VS 2015 Update 1中的一个新特性:的第一个实验性实现 一个C++模块系统 提出了C++ 17。该提案得到了Kona 17夏威夷2015秋季会议上的C++ C++技术规范的批准。这个 技术规范草案 正在被C++标准核心工作组审查。

模块经常被认为是加速编译的一种方法。但他们提供的远不止是建立性能!C++模块可以帮助您改进代码的组件化。事实上,组件化是编译和构建吞吐量的有效途径。模块允许您将代码与难以调试的预处理器状态隔离开来。它们使开发工具来处理代码变得更容易。

模块允许您直接在代码中表示组件对所需功能的提供者的符号依赖关系,以及该依赖关系的边界。模块消除了通过头文件指定接口的复杂预处理器巫毒的需要。如果您别无选择,只能使用基于宏的接口、条件编译和代码生成,那么预处理器就在那里,可以与模块系统一起工作。预处理器是一个强大的动物,没有结构,C++模块不是设计来做它所做的一切。预处理器的工作是生成lexer要使用的预令牌。40多年来,它被创造性地用于生成各种文本,包括HTML源文档。

如果您想了解C++模块的设计选择背后的原理和原理,请立即停止阅读并阅读建议: 一个C++模块系统 也有一个伟大的讨论关于C++模块从Gabriel Dos Reis从CPPCON 2015。 CppCon YouTube频道 ; 演讲中的幻灯片也可以在 IsoCpp GitHub回购 . 但是,如果你想直接跳进去看看这个功能提供了什么,请继续阅读!

在Visual C++ 2015更新1中的实现是对正在进行的努力的预览,所以我们渴望听到您的反馈。 这是一个机会,你会对一个主要的C++特性产生影响。我们想构建一个C++模块系统,它可以为所有开发人员提供所有编译器,所以如果你有任何反馈,请告诉我们。你可以打电话给我们 modules@microsoft.com .

在Visual C++ 2015更新1中的模块支持

首先,您应该知道模块支持完全由交换机保护: /经验erimental:module . 如果您不使用这个开关,那么模块特性将不会影响您的代码。另外,请注意,对模块的支持目前仅在命令行工具中提供。很多IDE功能应该可以正常工作,但是还没有完全集成IDE。另外,本预览的重点是组件化。随着我们在完成C++语言特性的支持方面的进步,我们将把重点放在优化模块支持中的构建吞吐量上;如果不首先进行组件化,那么复制一个特定的构建逻辑就太容易了,而不会对基本问题产生重大影响。

生产模块

创建和使用模块非常简单:开发人员只需通过编写一个源文件来声明包含模块定义的源文件 module M; . 然后,她通过在这些实体的每个声明前面加上 export 关键字。

可以导出任何顶级声明或大括号中包含的任何顶级声明序列。模块不定义新的名称空间或以任何方式更改名称查找规则。它们只允许开发人员为源文件指定和发布接口。因此,您确实不需要学习新的名称查找规则。

在本例中,函数 f(int) g(double, int) 作为的接口的一部分导出 module M .

//文件:foo.ixx 模块 米; 导出int f级( 内景 ) { 返回 2 + ; } 出口双倍 克( 双重的 y , 内景 z ) { 返回 y * z ; }

编译模块接口的命令行只是 信用证/支出erimental:module foo.ixx . 扩展名“ixx”是特殊的。它告诉编译器源文件的内容应该是模块接口源代码。如果要在接口文件上使用另一个扩展名,还必须提供开关 /module:interface . (注意这些开关可能会在将来发生变化!)

编译模块接口文件时,通常会得到一个OBJ文件。编译器还生成扩展名为“.ifc”的文件(称为 IFC文件 )包含模块接口的元数据描述的。这是模块支持在传统编译之外产生任何附加功能的唯一一次。IFC文件的二进制格式将是开源的;它是仿照 内部程序表示 加布里埃尔·多斯雷斯和比亚恩·斯特劳斯鲁普十年前所做的工作。IPR的原始实现是开源的,可以在 GitHub知识产权回购 .

消费模块

为了使用模块,开发人员编写 import M; 在源文件的顶部,从而声明 f(int) g(double, int) 在源文件中可见。指定已编译二进制模块接口文件的编译器开关为 /module:reference .

//文件:bar.cpp 进口 米; 内景 主() {f(5);g(0.0,1); 返回 0; }

使用命令行编译bar.cpp cl/exp公司erimental:module /module:参考M.ifc bar.cpp foo.obj . 函数定义 f(int) g(double, int) 由于import语句的原因,在bar.cpp中可用。如果引用文件太多,或者将所有IFC文件放在给定目录中,则可以改用编译器选项 /module:search 它以目录名作为参数。

概述

在文件级别,包含模块定义的源文件称为foo.ixx(在我们的示例中,模块定义的名称M不需要与文件名foo匹配。)编译foo.ixx会创建模块接口文件M.ifc,它是接口的二进制表示形式,此外还有标准的Windows对象文件foo.obj。

使用模块时(使用 /module:reference 开关),编译器读入M.ifc以使接口中的顶级导出名称对当前正在编译的源文件可用,并且链接器像往常一样使用foo.obj。

这三个关键字和两个开关足以让您试用C++模块。对于过渡场景,还有一些开关可用,但它们不是可以依赖的,因为它们可能会随着设计的发展而改变。

编辑2016年10月4日:我们对指定输出目录和接口文件名很感兴趣。这个选择很简单/module:output,如下所示: cl/exp公司erimental:module /module:导出/module:name ModuleName /module:wrapper C:OutputpathModuleName.h /module:output C:OutputpathModuleName.ifc -c<源文件>

便利功能

重要的是,C++模块可以在源代码中逐步采用。我们已经创建了一些方便的函数来帮助迁移场景。微软内部的团队正在测试所有这些功能。它们可能会根据内部和外部开发人员的反馈进行更改。我们还创建了一些工具来帮助操作模块接口文件,我们将在另一篇博客文章中讨论这些文件。

将现有的旧头文件用作模块接口

假设您有一个在宏和预处理器状态方面表现良好的现有源文件(特别是头文件)。您希望将该头作为模块接口使用。我们已经在编译器中建立了一个方便,允许您假装在C++源文件中所有具有外部链接的顶级声明被标记为导出。你用开关 /module:name /module:export 从标头自动创建编译模块接口(IFC)。对…的论点 /module:name 指定模块接口(.IFC)的名称和 /module:export 指定创建模块接口时应使用的头文件。请注意,由于编译器的文件处理受到限制,当前必须在.cpp文件中包含头文件(或重命名头文件)。

//文件:foo.cpp 内景 f级( 内景 ) { 返回 2 + ; } 双重的 克( 双重的 y , 内景 z ) { 返回 y * z ; }

命令行 信用证/支出erimental:module /module:名称mymodule/module:export foo.cpp 生成mymodule.ifc,这是一个包含 f(int) g(double, int) .

模块搜索路径

/module:search 指示编译器应在其中搜索通过引用的文件的目录 /module:reference . 例如,上面bar.cpp的编译命令行(在 消费模块 )可以写成 cl/exp公司erimental:module /module:搜索。吧台.cpp foo.obj 在当前目录中搜索IFC文件。

保存宏

最后,如果遗留源文件定义了对其使用者至关重要的宏,则可以让编译器生成一个包含导入声明的包装头文件,后跟这些宏的预处理器定义。编译器开关 /module:exportActiveMacros 当编译器编译完定义模块的源文件时,导出所有活动的宏定义。如果你想有选择性,你可以使用 /module:exportMacro 相反,在哪里 指定要在包装文件中定义的宏。包装头文件的名称是通过开关指定的 /module:wrapper 它接受一个文件名参数。

//文件:baz.h #ifndef公司 包括酒吧 #定义 6 内景 f级( 内景 ) { 返回 2 + ; } 双重的 克( 双重的 y , 内景 z ) { 返回 y * z ; } #结束 //包括酒吧

//文件:baz.cpp #包括 “巴兹·h”

用编译上述源文件 信用证/支出erimental:module /module:导出/module:name mymodule 巴兹.cpp/module:wrapper baz-wrapper.h /module:exportActiveMacros 将按预期生成mymodule.ifc,但还将生成一个头文件baz wrapper.h,其中包含以下内容:

#ifndef公司 包括mymoduleu WRAPPERu #定义 包括mymoduleu WRAPPERu 导入mymodule; #定义 6 #结束 //包括mymoduleu WRAPPERu

现在可以包含baz wrapper.h而不是baz.h,并获得模块的组件化好处,即使baz.h最初不是作为模块编写的。这项技术保留了预处理器的状态,并使您有机会清理您当时可能没有意识到处于活动状态的任何宏。可悲的是,排序通过流氓预处理器状态是一个非常普遍的经验。

玩得高兴!

VS 2015更新1中的C++模块是一个令人兴奋的特性,即使在这种早期状态。很明显,我们缺少一些基本的功能,比如与VSIDE和构建系统的集成,但是我们希望尽早得到一些东西,这样我们的开发人员社区就有机会对工作产生重大影响。请试用C++模块,让我们知道你的想法。 modules@microsoft.com .

© 版权声明
THE END
喜欢就支持一下吧,技术咨询可以联系QQ407933975
点赞0 分享