Использование модулей C++ в Visual Studio 2017

https://blogs.msdn.microsoft.com/vcblog/2017/05/05/cpp-modules-in-visual-studio-2017/
  • Перевод

Что нового?


Команда Visual C++ рада сообщить, что в Visual Studio 2017 было существенно улучшено качество реализации модулей C++ согласно технической спецификации; также мы добавили возможность подключать Стандартную Библиотеку C++ через интерфейсы модулей. Эти интерфейсы, как и поддержка модулей компилятором, являются экспериментальной разработкой и будут развиваться в соответствии с процессом стандартизации.

Начало работы


Поддержка модулей Стандартной Библиотеки реализована в Visual Studio начиная с версии 2017 RTM. Эта функция на данный момент является опциональной и по умолчанию отключена. В будущих версиях модули будут устанавливаться автоматически вместе с заголовками Стандартной Библиотеки. Вам нужно лишь выбрать эту опцию при установке или обновлении поддержки C++.

Picture 5



Если вы уже установили VS 2017, но не устанавливали модули, это легко исправить. Просто запустите установщик еще раз и выберите соответствующие компоненты.

Picture 23


Проверка правильности установки


Чтобы проверить, настроена ли ваша копия VS 2017 для поддержки модулей, скомпилируйте и запустите приведенную ниже программу (назовите ее, например, test-vs2017-slm.cxx) из командной строки разработчика. Поскольку модули на данный момент являются экспериментальной функцией, их поддержка пока еще очень слабо реализована в среде VS.

import std.core; 
  
int main() { 
    using namespace std; 
    vector<string> v { "Plato", "Descartes", "Bacon" }; 
    copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n")); 
} 

При компиляции этого кода с командой

cl /experimental:module /EHsc /MD /std:c++latest test-vs2017-slm.cxx

на выходе должен получиться исполняемый файл (test-vs2017-slm.exe), который при запуске распечатает слова «Plato», «Descartes» и «Bacon» — каждое отдельной строкой.

Ключ компилятора для подключения модулей Стандартной Библиотеки


Необходимо добавить ключ /MD при компиляции исходного файла, чтобы подключить модули Стандартной Библиотеки. Ключ /MD инициализирует динамическую библиотеку времени выполнения C (CRT). В режиме отладки следует использовать ключ /MDd.

Если вы забыли указать ключ /MD (или /MDd в режиме отладки), линковщик выдаст ряд предупреждений и ошибку линковки LNK2019, говорящую о наличии неразрешенных внешних символов.

Никаких других ключей для использования модулей Стандартной Библиотеки не требуется. Эти модули могут применяться только для использования с библиотеками импорта DLL Универсальной библиотеки CRT (UCRT).

Подключение модулей Стандартной Библиотеки из среды разработки VS


Если вы хотите использовать среду разработки вместо командной строки, настройте ваш проект для использования экспериментальных модулей согласно следующей инструкции.

1. Откройте окно «Свойства» (Properties) проекта:

Picture 10


2. Перейдите в раздел «Свойства конфигурации» (Configuration Properties) -> C/C++ -> «Генерация кода» (Code Generation) и убедитесь, что у вас выбрана библиотека Multithreaded Debug DLL или Multithreaded DLL (для режимов отладки и релиза соответственно). Эти библиотеки выбраны по умолчанию для новых проектов, так что, если вы ничего не меняли, никаких проблем возникнуть не должно.

Picture 22


3. Зайдите в раздел «Свойства конфигурации» (Configuration Properties) -> C/C++ -> «Язык» (Language) и убедитесь, что включена поддержка стандарта C++17. Если это не так, выберите из выпадающего списка стандарт C++17 или последний проект стандарта C++ (C++ Latest Draft Standard) для конфигураций, которые вы планируете использовать.

Picture 15


4. Впишите команду /experimental:module /module:stdIfcDir "$(VCToolsInstallDir_150)ifc\$(PlatformTarget)" в разделе «Свойства конфигурации» (Configuration Properties) -> C/C++ -> «Командная строка» (Command Line), чтобы включить поддержку модулей для текущего проекта. Обратите внимание, что данный шаг будет упразднен в будущих версиях VS 2017: среда будет сама указывать расположение файлов модулей (задается параметром /module:stdIfcDir) при включении опции поддержки модулей C++.

Picture 17



После этих действий сборка и запуск тестовой программы должны пройти успешно — программа распечатает имена трех философов.

Picture 20


Изменение синтаксиса экспорта модулей


На съезде комитета по стандартизации C++ в ноябре 2016 года было принято решение об изменении синтаксиса экспорта модулей (см. Проблема модулей N1).

Было:

export module Bank;

Стало:

export import Bank;

Настоящая версия Visual C++ учитывает это изменение, но также позволяет использовать и старый синтаксис, предупреждая о переходе к устаревшему варианту. Комитет по C++ рассматривает возможность присвоения старому синтаксису нового значения, несовместимого с прежним. Мы призываем вас использовать новый синтаксис; поддержка старого синтаксиса будет прекращена в целях соответствия проекту технической спецификации по модулям согласно поправкам комитета ISO C++.

Модули Стандартной Библиотеки (экспериментальная функция)


Ключевым нововведением в версии VS2017 RTM стала поддержка подключения Стандартной Библиотеки C++ посредством модулей. Это экспериментальный инструмент, описанный в предложении по C++ о Модулях Стандартной Библиотеки. В текущей версии модули организованы следующим образом:

  • std.regex предоставляет доступ к содержимому заголовка <regex>
  • std.filesystem предоставляет доступ к содержимому заголовка <experimental/filesystem>
  • std.memory предоставляет доступ к содержимому заголовка <memory>
  • std.threading предоставляет доступ к содержимому заголовков <atomic>, <condition_variable>, <future>, <mutex>, <shared_mutex>, <thread>
  • std.core предоставляет доступ к прочему содержимому Стандартной Библиотеки C++

Чтобы использовать эти модули в своей программе, просто впишите в верхнем уровне исходного файла инструкцию import M, где M — название модуля из списка выше. См. тестовый пример.

Если вы хотите использовать модули для включения заголовков не из Стандартной Библиотеки, сгенерировать модули Стандартной Библиотеки можно с помощью ключей /module:name (см. исходную заметку по модулям C++) и /module:export. Если ваш проект зависит от других библиотек и вы хотите попробовать собрать код совсем без заголовков, упаковать заголовки из таких библиотек можно тем же самым способом.

Новые версии VS будут в большей степени соответствовать предложению по модулям Стандартной Библиотеки.

Призыв к действию


Скачайте Visual Studio 2017 и опробуйте модули со своими C++-проектами и программами. Для начала можно просто заменить в исходных файлах все команды #include стандартных заголовков для контейнеров и алгоритмов на import std.core и добавить ключи компиляции /experimental:module и /MD или /MDd (в режиме отладки) к определению сборки. О результатах сообщайте нам.

В заключение


Как всегда, мы будем рады вашим отзывам. Свои комментарии присылайте по адресу visualcpp@microsoft.com либо оставляйте в Twitter @visualc или на странице Facebook Microsoft Visual Cpp.

О прочих проблемах, связанных с использованием среды MSVC в VS 2017, можно сообщить с помощью функции Сообщить о проблеме (Report a Problem) из установщика или из самой среды Visual Studio. Свои предложения оставляйте на сайте UserVoice. Спасибо!

PVS-Studio

253,95

Ищем ошибки в C, C++ и C# на Windows, Linux, macOS

Поделиться публикацией
Комментарии 19
    +9
    export import Bank;

    Шизофрения на марше. В чём смысл было менять module на import? Чтобы не делать module зарезервированным словом? В указанном документе не нашёл никакого объяснения.
      +1
      Я так понял, что это относится к экспортируемым включениям других модулей. Как по мне, смотрится куда более логично.
      Если мне нужен приватный «инклюд»
      я пишу просто
      import Blank;
      А если мне его еще и наружу надо отдать тем, кто будет мной пользоваться:
      export import Blank;
      ИМХО интуитивнее.
      +1
      А появилась ли поддержка модулей со стороны IDE (а не компилятора)? А то модули — это, конечно, круто, но писать без IntelliSense и прочего я и в блокнотике могу.
        0
        Судя по статье — пока нет.
        0
        Я, может, слишком глуп, но для чего вообще нужны модули в C++?
          +3
          Ускорение скорости компиляции в десятки раз.
          Сейчас каждый include вставляет текст заголовка в файл после чего он компилируется, и так с каждым файлом. Каждый модуль компилируется единожды, после чего он просто соединяется с вашей частью скомпилированно файла, т.е. примерно «линковка на стероидах»
            0
            Например, вставил несколько стандартных инклюдов типа iostream — и хоп! компилятору нужно уже мегабайтный файл процессить. А так у него уже готовые AST будут.
            По сути, это эволюционное развитие идеи preprocessed headers, но на уровне одного хедера)
            +1
              0
              А со статической линковкой CRT(/MT /MTd) пока не работает?
                +1
                У меня вопрос к тем, кто их уже успел поковырять: как там обстоят дела с параллельной сборкой?
                Допустим у меня такие файлы:
                foo.cpp
                bar.cpp
                module.hpp
                Модуль используется в обоих foo.cpp и bar.cpp. Соответственно, когда компилятор будет процессить модуль, ему нужно будет где-то сохранить результат. Я правильно понимаю, что до того как для module.hpp будет скомпилено бинарное представление (AST или что там), то нельзя начинать компилить foo или bar? ну а иначе же они могут одновременно попытаться получить/скомпилить данные module.hpp?

                upd: кажется, да, понял, для компиляции по крайней мере msvc нужно указывать уже скомпиленные модули
                  –1
                  30 лет думали, думали и наконец придумали то, что в pascal/delphi было давным-давно :) браво! верной дорогой. мы делаем проще. сам delphi и используем.
                    0
                    В каждой теме про ц++ найдётся дурачёк который использую <свойЛюбимыйЯзычёк>.
                      +1
                      Удивительно другое, что ваш 'умный' язык постепенно превращается в наш 'глупый'. Странно как-то, правда?
                        +2
                        Да, но без потери производительности. В любой момент можно использовтаь те технологии, чтобы получить эффективность Си.
                    +2
                    export import Bank;

                    Давайте тогда ещё
                    import export Bank;


                    Я понимаю, C++ сложный язык, но почему нельзя сделать хоть тут без шизофрении :(
                      0
                      Хммм… Как я думаю — следующий этап — это встроить c++ компилер в ОС: ку по defaultу, на манер C#. Тогда можно будет подумать на тему «C++ скрипт», и я надесь что перепишу свою утилиту syncProj уже на нативный c++.
                        0
                        Так есть же WSL, в ней g++ подтянут. Нужно только сделать сборку винды, в которой оно ставится прямо при установке системы и все.
                          0
                          Только мне ещё нужен модуль для компиляции C++ кода. это наверное самое сложное.

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое