Что нового?
Команда Visual C++ рада сообщить, что в Visual Studio 2017 было существенно улучшено качество реализации модулей C++ согласно технической спецификации; также мы добавили возможность подключать Стандартную Библиотеку C++ через интерфейсы модулей. Эти интерфейсы, как и поддержка модулей компилятором, являются экспериментальной разработкой и будут развиваться в соответствии с процессом стандартизации.
Начало работы
Поддержка модулей Стандартной Библиотеки реализована в Visual Studio начиная с версии 2017 RTM. Эта функция на данный момент является опциональной и по умолчанию отключена. В будущих версиях модули будут устанавливаться автоматически вместе с заголовками Стандартной Библиотеки. Вам нужно лишь выбрать эту опцию при установке или обновлении поддержки C++.
Если вы уже установили VS 2017, но не устанавливали модули, это легко исправить. Просто запустите установщик еще раз и выберите соответствующие компоненты.
Проверка правильности установки
Чтобы проверить, настроена ли ваша копия 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) проекта:
2. Перейдите в раздел «Свойства конфигурации» (Configuration Properties) -> C/C++ -> «Генерация кода» (Code Generation) и убедитесь, что у вас выбрана библиотека Multithreaded Debug DLL или Multithreaded DLL (для режимов отладки и релиза соответственно). Эти библиотеки выбраны по умолчанию для новых проектов, так что, если вы ничего не меняли, никаких проблем возникнуть не должно.
3. Зайдите в раздел «Свойства конфигурации» (Configuration Properties) -> C/C++ -> «Язык» (Language) и убедитесь, что включена поддержка стандарта C++17. Если это не так, выберите из выпадающего списка стандарт C++17 или последний проект стандарта C++ (C++ Latest Draft Standard) для конфигураций, которые вы планируете использовать.
4. Впишите команду /experimental:module /module:stdIfcDir "$(VCToolsInstallDir_150)ifc\$(PlatformTarget)" в разделе «Свойства конфигурации» (Configuration Properties) -> C/C++ -> «Командная строка» (Command Line), чтобы включить поддержку модулей для текущего проекта. Обратите внимание, что данный шаг будет упразднен в будущих версиях VS 2017: среда будет сама указывать расположение файлов модулей (задается параметром /module:stdIfcDir) при включении опции поддержки модулей C++.
После этих действий сборка и запуск тестовой программы должны пройти успешно — программа распечатает имена трех философов.
Изменение синтаксиса экспорта модулей
На съезде комитета по стандартизации 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. Спасибо!
Комментарии (16)
alexeykuzmin0
12.05.2017 12:15+1А появилась ли поддержка модулей со стороны IDE (а не компилятора)? А то модули — это, конечно, круто, но писать без IntelliSense и прочего я и в блокнотике могу.
nkozhevnikov
12.05.2017 13:28Я, может, слишком глуп, но для чего вообще нужны модули в C++?
sborisov
12.05.2017 14:19+3Ускорение скорости компиляции в десятки раз.
Сейчас каждый include вставляет текст заголовка в файл после чего он компилируется, и так с каждым файлом. Каждый модуль компилируется единожды, после чего он просто соединяется с вашей частью скомпилированно файла, т.е. примерно «линковка на стероидах»mapron
12.05.2017 16:00Например, вставил несколько стандартных инклюдов типа iostream — и хоп! компилятору нужно уже мегабайтный файл процессить. А так у него уже готовые AST будут.
По сути, это эволюционное развитие идеи preprocessed headers, но на уровне одного хедера)
mapron
12.05.2017 16:06+1У меня вопрос к тем, кто их уже успел поковырять: как там обстоят дела с параллельной сборкой?
Допустим у меня такие файлы:
foo.cpp
bar.cpp
module.hpp
Модуль используется в обоих foo.cpp и bar.cpp. Соответственно, когда компилятор будет процессить модуль, ему нужно будет где-то сохранить результат. Я правильно понимаю, что до того как для module.hpp будет скомпилено бинарное представление (AST или что там), то нельзя начинать компилить foo или bar? ну а иначе же они могут одновременно попытаться получить/скомпилить данные module.hpp?
upd: кажется, да, понял, для компиляции по крайней мере msvc нужно указывать уже скомпиленные модули
ElectroGuard
13.05.2017 00:11-130 лет думали, думали и наконец придумали то, что в pascal/delphi было давным-давно :) браво! верной дорогой. мы делаем проще. сам delphi и используем.
Jamdaze
13.05.2017 11:13В каждой теме про ц++ найдётся дурачёк который использую <свойЛюбимыйЯзычёк>.
ElectroGuard
13.05.2017 15:39+1Удивительно другое, что ваш 'умный' язык постепенно превращается в наш 'глупый'. Странно как-то, правда?
Andrey2008
13.05.2017 15:45+2Да, но без потери производительности. В любой момент можно использовтаь те технологии, чтобы получить эффективность Си.
Error1024
13.05.2017 05:46+2export import Bank;
Давайте тогда ещёimport export Bank;
Я понимаю, C++ сложный язык, но почему нельзя сделать хоть тут без шизофрении :(
hdfan2
Шизофрения на марше. В чём смысл было менять module на import? Чтобы не делать module зарезервированным словом? В указанном документе не нашёл никакого объяснения.
mapron
Я так понял, что это относится к экспортируемым включениям других модулей. Как по мне, смотрится куда более логично.
Если мне нужен приватный «инклюд»
я пишу просто
import Blank;
А если мне его еще и наружу надо отдать тем, кто будет мной пользоваться:
export import Blank;
ИМХО интуитивнее.