Упакуйте существующие сторонние приложения в отдельные модули C++20

Я пытаюсь использовать модули, чтобы немного ускорить сборку наших окон. По моим первым впечатлениям, модули C++20 определенно быстрее, чем PCH (по крайней мере, в Windows).

В настоящее время я сосредоточен только на Windows с последней версией MSVC 17 и последней версией CMake. Я также использую import std, который доступен только на C++23. Я знаю, что эти функции являются передовыми, но это первая попытка, которая не использовалась ни в одной продуктивной системе. (Мне нужно сохранить обратную совместимость, хотя и с «классическими» включениями) Поскольку MSVC17 имеет хорошую поддержку рабочих модулей, а CMake добавил стандарт импорта в свою последнюю версию, я бы хотел попробовать.

Теперь проблемы, с которыми я столкнулся, - это конфликты имен. Итак, поскольку я использую import std;, я бы хотел избежать всех включений stl. Модифицировать наш код не составляет большого труда, настоящая задача — упаковать существующие сторонние модули (например, fmt и nlohmann_json) в модули, поскольку их заголовки включают несколько заголовков std (которые вызывают конфликты имен с import std;).

Я смотрел рассказы Даниэлы Энгерт о модулях C++20 на некоторых конференциях CppCon и ознакомился с ее примерами. https://github.com/DanielaE/asio/tree/d212efd69aedf221475dc2434c45a6baeee10d16/asio/module По сути, она включила в экспорт сторонний заголовок. Однако это не сработало для меня.

// Global module fragment where #includes can happen
module;

//inlcuded headers will not be exported to the client


// first thing after the Global module fragment must be a module command
export module nlohmann_json;

extern "C++"
{
  export
  {
#include <nlohmann/json.hpp>
  }
}


module: private;
//possbile to include headers here, but they will not be exported to the client

Это моя тестовая программа

#include <gtest/gtest.h>
import nlohmann_json;
TEST(CxxModuleTest, nlohman_json)
{
  nlohmann::json j = {
  {"pi", 3.141},
  {"happy", true},
  {"name", "Niels"},
  {"nothing", nullptr},
  {"answer", {
    {"everything", 42}
  }},
  {"list", {1, 0, 2}},
  {"object", {
    {"currency", "USD"},
    {"value", 42.99}
  }}
  };

  EXPECT_EQ(j["pi"], 3.141);
  EXPECT_EQ(j["happy"], true);
  EXPECT_EQ(j["name"], "Niels");
  EXPECT_EQ(j["nothing"], nullptr);
  EXPECT_EQ(j["answer"]["everything"], 42);
  EXPECT_EQ(j["list"][0], 1);
  EXPECT_EQ(j["list"][1], 0);
  EXPECT_EQ(j["list"][2], 2);
  EXPECT_EQ(j["object"]["currency"], "USD");
  EXPECT_EQ(j["object"]["value"], 42.99);
}

Однако это не компилируется. Я получаю

'#include <filename>' in the purview of module 'module-name-1' appears erroneous. Consider moving that directive before the module declaration, or replace the textual inclusion with 'import <filename>;'.

Я закончил с этим

// Global module fragment where #includes can happen
module;

//inlcuded headers will not be exported to the client
#include <nlohmann/json.hpp>

// first thing after the Global module fragment must be a module command
export module nlohmann_json;

export
{
  namespace nlohmann::json_abi_v3_11_2::detail
  {
    using ::nlohmann::json_abi_v3_11_2::detail::json_sax_dom_callback_parser;
    using ::nlohmann::json_abi_v3_11_2::detail::json_sax_dom_parser;
  }

  namespace nlohmann
  {

    using ::nlohmann::basic_json;
    using ::nlohmann::json;
    using ::nlohmann::json_sax;
    using ::nlohmann::detail::json_sax_dom_parser;
    using ::nlohmann::detail::json_sax_dom_callback_parser;
  }
}


module: private;
//possbile to include headers here, but they will not be exported to the client

Однако это попытка и ошибка. Мне нужно добавить все типы, пока программа не скомпилируется.

=>Мой вопрос: Есть ли лучший (более общий) способ?

спасибо, ребята, за вашу помощь :)

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете export import заголовочный файл в интерфейсном блоке модуля, чтобы экспортировать в него все символы.

// in .ixx file, module interface unit
export module nlohmann_json;

export import <nlohmann/json.hpp>;

// in .cpp file
import nlohmann_json;
// use nlohmann/json here

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

Обратите внимание, что ограничение экспортируемых символов в будущем станет критическим изменением API, поэтому авторам библиотек не следует делать это слишком часто.

Пример CMakeLists.txt:

cmake_minimum_required(VERSION 3.28)

set(CMAKE_CXX_STANDARD 20)
set(JSON_BuildTests OFF CACHE INTERNAL "")

project(cpp_json)

add_subdirectory(external/json)  # nlohmann_json directory

add_executable(cpp_json main.cpp)

target_sources(cpp_json
  PUBLIC
    FILE_SET modules TYPE CXX_MODULES
      BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/module
      FILES module/nlohmann_json.ixx
)
target_link_libraries(cpp_json PUBLIC nlohmann_json::nlohmann_json)

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

cmake_minimum_required(VERSION 3.28)

set(CMAKE_CXX_STANDARD 20)
set(JSON_BuildTests OFF CACHE INTERNAL "")

project(cpp_json)

add_subdirectory(external/json)  # nlohmann_json directory

add_library(nlohmann_json_interface)  # linking target for import

target_sources(nlohmann_json_interface
  PUBLIC
    FILE_SET modules TYPE CXX_MODULES
      BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/module
      FILES module/nlohmann_json.ixx
)
target_link_libraries(nlohmann_json_interface PUBLIC nlohmann_json::nlohmann_json)

add_executable(cpp_json main.cpp)
# only need my interface target
target_link_libraries(cpp_json nlohmann_json_interface)

эй, спасибо за твой ответ. К сожалению, это дает мне заголовок ошибки компилятора nlohmann/json.hpp>;, который не найден. Я что-то пропустил?

JHeni 29.07.2024 15:51

Конечно, вы правы, мне нужно экспортировать все символы, иначе я сломаю свой API. Вот почему мне не нравится мой подход. Однако другого рабочего способа я не нашел :(

JHeni 29.07.2024 15:53

@JHeni, он отлично работает на моей машине с использованием Visual Studio 17.11.0 Preview 2. Вы уверены, что какая бы цель ни имела этот .ixx файл, она также использует target_link_libraries(something PUBLIC nlohmann_json::nlohmann_json), чтобы каталоги включения были установлены правильно?

Ahmed AEK 29.07.2024 16:30

@JHeni также работает в Visual Studio 17.9.6, я добавил CMakeLists.txt

Ahmed AEK 29.07.2024 21:58

извини. Похоже, я делаю что-то не так. Я создал новый пустой проект cmake и скопировал первый фрагмент cmake (модуль и основной в пределах одной цели), и я все еще получаю hederunit for nlohmann/json.hpp не найден, мне пришлось удалить add_subdirectory(external/json) # nlohmann_json directory В моем фиктивном проекте external/json - это папка только с заголовком, а не отдельный модуль cmake

JHeni 31.07.2024 09:58

@JHeni, если вы используете библиотеку только для заголовков, у вас должна быть target_include_directories(cpp_json PUBLIC external/json) или что-то в этом роде, чтобы добавить каталог включения заголовка, который будет общедоступен для cmake.

Ahmed AEK 31.07.2024 10:54

да, я сделал это. (Сначала я пропустил это и получил ошибку «файл не найден»;)) Ребята, вы действительно используете проект cmake или решение VS? export import <nlohmann/json.hpp>; это не шапка? Блоки заголовков пока не поддерживаются Cmake (с другой стороны, VS имеет поддержку блоков заголовков)

JHeni 31.07.2024 11:13

@JHeni, я работаю с cd build, затем cmake .., затем cmake --build ., не могли бы вы обновить свою версию Visual Studio? На панели инструментов используйте Help -> check for updates, вы можете найти весь проект в этом zip-файле file.io/6Zgfnh3L85YU. Если на вашем устройстве произойдет сбой, значит, у вас проблема с установкой Visual Studio.

Ahmed AEK 31.07.2024 11:55

ах, спасибо за разъяснения. Когда я строю из CLI, это тоже работает. Когда я импортирую этот проект как проект cmake в VS, он не работает: O

JHeni 01.08.2024 17:07

Другие вопросы по теме