天天看点

c++20 module

VS2019 C++20的module

    • 01 module一些资料
    • 02 vs2019中关于module的配置
      • 02.01 安装配置
      • 02.02 项目配置
    • 03 测试项目

01 module一些资料

对于大型项目,include头文件的方式会严重影响编译性能。比如类似chromium的开源项目。module是一个工程化特性,头文件中的信息现在分成导出的部分和不导出的部分,可以有效减少实现细节影响的范围,带来一个非常有用的特性——重新编译速度变快。

module是很早就被提及的概念,微软在vs2015中就开始部分支持,参考VS 2015 Update 1中C++Modules;在vs2017中的支持更进一步,参考在Visual Studio 2017 中使用C++ Modules。

参考资料:

  1. github上有代码,有文档较详细的资料
  2. cppreference.com的模块 (C++20 起):
  3. 在Visual Studio 2017中使用C ++模块
  4. 使用Visual Studio 2017 C++17模块(module)特性
  5. C++ 中的模块概述
  6. 模块,导入,导出

02 vs2019中关于module的配置

02.01 安装配置

vs2019 到2019年11月为止,只在实验功能中支持module。需要安装实验组件:

在vs2019的16.4.1中选择 [使用C++的桌面开发] 中的 [用于v142生产工具的C++模块(x64/x86-实验性)]

如下图所示:

c++20 module

02.02 项目配置

  1. 项目工程配置

    vs2019中不需要(像vs2017中那样)在

    C/C++

    命令行

    中配置

    /experimental:module /module:stdIfcDir "$(VCToolsInstallDir_150)ifc\$(PlatformTarget)

    如果项目中使用了module功能,只要再

    C/C++

    语言

    中配置如下两项即可:

    C++语言标准

    =

    /std:c++latest

    启用C++模块(实验性)

    =

    /experimental:module

    c++20 module
  2. 独立模块编译配置

    如果在项目中自己独立使用模块,需要使用命令行编译。而且如果在模块中引用了标准模块,需要在命令行中指定

    /module:stdIfcDir

    编译的相关命令行参数有:

    /experimental:module

    :启用C++模块属性

    /std:c++latest

    :C++语言标准

    /module:export

    :导出模块

    /module:stdIfcDir

    :指定标准库模块路径

    /MD|/MDd|/MT|/MTd

    :运行时库

    还要注意平台属性:即

    x64|x86

    最后把这个汇总到一个bat文件中,把平台属性和运行时库做为bat文件的参数,配置到配置属性的

    生成事件

    –>

    生成前事件

    –>

    命令行

    里,如图
    c++20 module
  3. 模块编译脚本样例
@echo off

rem 这里要根据你编译的x86/x64;relase/debug选择对应目录下的cl.exe
rem set clcmd=D:\install\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\bin\Hostx64\x64\cl.exe
rem 在vs中自己会找到准确的cl.exe版本,不需要特别指定
set clcmd=cl.exe

rem 如果module中引用了标准库,需要指定/module:stdIfcDir
rem /experimental:module /module:stdIfcDir "$(VCToolsInstallDir_160)ifc\$(PlatformTarget)"
rem $(VCToolsInstallDir_160)=D:\install\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\
rem $(PlatformTarget)=x64
set target=%1%
if "%target%"=="" set target=x64
@echo %target%
rem 根据自己的实际目录设置
set stdIfcDir="D:\install\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\ifc\%target%"

rem 指定代码生成的运行库md mdd mt mtd(动态库 动态调试库 静态库 静态调试库)
rem 本bat的第一个参数指定是否是debug版本,如果是debug版本,第一个参数是 d
set rundll=%2%
if "%rundll%"=="" set rundll=MD

rem 显示运行时库参数
@echo %rundll%

set CFLAGS=/experimental:module /std:c++latest /EHsc /%rundll% /c /module:stdIfcDir %stdIfcDir% /module:export 

rem cl.exe /experimental:module /std:c++latest /EHsc /MD /c /module:stdIfcDir "D:\install\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\ifc\x64" /module:export module01.cpp 
"%clcmd%" %CFLAGS% module01.cpp

rem "%clcmd%" %CFLAGS% 模块文件
"%clcmd%" %CFLAGS% hello.mpp hello.cpp

"%clcmd%" %CFLAGS% module02.cpp
           
  1. /module:stdIfcDir参数确定方式

    在项目属性的

    预处理器

    中的

    预处理器定义

    里查看

    $(VCToolsInstallDir_150)ifc\$(PlatformTarget)

    c++20 module

03 测试项目

C++20的module在vs2019 16.4.1上面的测试

  1. module01.cpp
module module01;

// 在模块中未使用基础库,极少数情况
// 编译时,可以不指定/module:stdIfcDir
namespace module01 {

   int test(int x)
   {
       return x * x;
   }
}
           
  1. module02.cpp
module module02;

// 在模块中未使用基础库,极少数情况
// 编译时,必须指定/module:stdIfcDir
import std.core;
using namespace std;

namespace module02 {
   void say(const char* str) {
       cout << str << endl;
   }
}

           
  1. hello.mpp
#pragma once
// 模块接口单元(module interface unit),类似于头文件
export module hello;

namespace hello {
   void say_hi();
}

export namespace hello {
   void say_hello();
   void say_xz();
}
           
  1. hello.cpp
// 模块实现单元(module implementation unit)
module hello;
// 在模块中使用import标准模块,需要在编译语句中指定/module:stdIfcDir 参数
import std.core;
using namespace std;

namespace hello {

   void say_hi() {
       cout << "hello hi!" << endl;
   }

   void say_hello() {
       cout << "hello world!" << endl;
   }

   void say_xz() {
       cout << "hello xz!" << endl;
   }
}
           
  1. module.cpp
import std.core; // 使用标准导入模块
import module01; // 导入自定义模块
import hello;
import module02;

using namespace module01; // 使用自定义模块的命名空间

// 使用标准导入模块(import std.core;)
void use_standard_import_module() {
    std::cout << "hello world! use_standard_import_module" << std::endl;
}

int main(int argc, char** argv)
{
    use_standard_import_module();

    // 直接使用模块中的函数名
    std::cout << "module01::test(100) = " << test(100) << std::endl;

    hello::say_hello();
    hello::say_xz();
    hello::say_hi();
    module02::say("module02::say!");

    return 0;
}
           

运行结果:

c++20 module

这里只测试了 https://github.com/mutouyun/cncppcon2018-cppmodules/blob/master/About-Cpp-Modules.md 中介绍的2.1/2.2/2.3;2.4/2.5/2.6没有测试通过。

2.4 Module Partitions vs2019应该还不支持;

2.5 Global Module Fragment

2.6 Legacy Header Unit

继续阅读