json icon indicating copy to clipboard operation
json copied to clipboard

Incompatible with C++20 modules in MSVC

Open andylizf opened this issue 2 years ago • 29 comments

Description

Importing a module file using the lib will cause a compilation error.

Reproduction steps

Codes below.

Expected vs. actual results

To compile successfully.

Minimal code example

network.ixx:

module;
#include <nlohmann/json.hpp>
#include <string>
export module network;
using nlohmann::json;
export struct message {
  message(std::string str) { json doc = json::parse(str); }
};

main.cpp:

import network;
int main() { message msg(R"({"hello": "world"})"); }

Error messages

nlohmann\json.hpp(117): error C2039: 'json_sax_dom_callback_parser': is not a member of 'nlohmann::json_abi_v3_11_2::detail'
nlohmann\detail\output\serializer.hpp(35): note: see declaration of 'nlohmann::json_abi_v3_11_2::detail'
main.cpp(3): note: see reference to class template instantiation 'nlohmann::json_abi_v3_11_2::basic_json<std::map,std::vector,std::basic_string<char,std::char_traits<char>,std::allocator<char>>,bool,int64_t,uint64_t,double,std::allocator,nlohmann::json_abi_v3_11_2::adl_serializer,std::vector<uint8_t,std::allocator<uint8_t>>>' being compiled
nlohmann\byte_container_with_subtype.hpp(101): warning C4820: 'nlohmann::json_abi_v3_11_2::byte_container_with_subtype<BinaryType>': '7' bytes padding added after data member 'nlohmann::json_abi_v3_11_2::byte_container_with_subtype<BinaryType>::m_has_subtype'
        with
        [
            BinaryType=std::vector<uint8_t,std::allocator<uint8_t>>
        ]
        [            BinaryType=std::vector<uint8_t,std::allocator<uint8_t>>
        ]
nlohmann\json.hpp(4187): warning C4820: 'nlohmann::json_abi_v3_11_2::basic_json<std::map,std::vector,std::basic_string<char,std::char_traits<char>,std::allocator<char>>,bool,int64_t,uint64_t,double,std::allocator,nlohmann::json_abi_v3_11_2::adl_serializer,std::vector<uint8_t,std::allocator<uint8_t>>>': '7' bytes padding added after data member 'nlohmann::json_abi_v3_11_2::basic_json<std::map,std::vector,std::basic_string<char,std::char_traits<char>,std::allocator<char>>,bool,int64_t,uint64_t,double,std::allocator,nlohmann::json_abi_v3_11_2::adl_serializer,std::vector<uint8_t,std::allocator<uint8_t>>>::m_type

Compiler and operating system

Visual Studio 17 2022 MSVC 19.36.32323; Windows-10.0.22624

Library version

3.11.2

Validation

andylizf avatar Mar 09 '23 13:03 andylizf

Maybe related to #3974 and fixed by #3975.

nlohmann avatar Mar 13 '23 11:03 nlohmann

Is it fixed now? BTW, how to use the new version in xmake?

andylizf avatar Mar 25 '23 09:03 andylizf

it's not fixed, I got this compilation error as well with single include and modules. It looks kinda weird, not sure why this line in particular errors but not the one above which is almost identical.

gviot avatar May 18 '23 21:05 gviot

same issue in version 3.11.3

kiraYuukiAsuna avatar Feb 06 '24 16:02 kiraYuukiAsuna

I have the issue, 3.11.3, Visual Studio, using C++20 modules.

rnikander avatar Feb 14 '24 02:02 rnikander

The issue is not an issue with nlohmann/json, but rather MSVC compiler. I get the same issue with c42f/tinyformat. The compiler does not like something in the header and I just have not yet figured out what it is.

You can work around it if you add a "compilation firewall" by defining an interface in a header and shoving the include in a regular cpp. Too bad both libraries rely heavily on template to make the client code nice and small.

rioki avatar May 05 '24 08:05 rioki

I'm having a similar issue when trying to include nlohmann/json.hpp within a C++ module file.

Dev Attribube Value
Visual Studio Version: 17.10.0 Preview 7.0
Windows SDK Version: 10.0
Platform Toolset: Visual Studio 2022 (v143)
C++ Language Standard: Preview - Features from the Latest C++ Working Draft (/std:c++latest)
nlohmann-json Version: 3.11.3

The following section of my code:

nlohmann::json config = {
	{"Version", "x.x.x.d"}
};

Provides the error:

>Main.cpp
> *\vcpkg_installed\x64 - windows\x64 - windows\include\nlohmann\json.hpp(120, 38) : error C2039 : 'json_sax_dom_callback_parser' : is not a member of 'nlohmann::json_abi_v3_11_3::detail'

I'm in a greenfield project and would love to be able to use this library to parse and export json data.

@rioki, are you able to expand on your temporary fix until either this library or MSVC have a solution?

Many thanks.

JamieSharpe avatar May 13 '24 19:05 JamieSharpe

For my project I moved to jsoncpp, which has been working fine with a module wrapper that I made.

rnikander avatar May 13 '24 19:05 rnikander

@JamieSharpe I dropped modules altogether for the time being. I ran into 1001 issues like this. I will revisit modules in a year or two. Looks promising, not there yet.

rioki avatar Jun 27 '24 09:06 rioki

The issue is not an issue with nlohmann/json, but rather MSVC compiler. I get the same issue with c42f/tinyformat. The compiler does not like something in the header and I just have not yet figured out what it is.

You can work around it if you add a "compilation firewall" by defining an interface in a header and shoving the include in a regular cpp. Too bad both libraries rely heavily on template to make the client code nice and small.

Exactly how did you implement the compilation firewall? Perhaps you can show some code. I'm getting compilation errors when I try to do it. :/

duerrbaby avatar Jul 22 '24 07:07 duerrbaby

Exactly how did you implement the compilation firewall? Perhaps you can show some code. I'm getting compilation errors when I try to do it. :/

For me the following works:

JSONTools.ixx

module;

#include <filesystem>

export module JSONTools;

import DataDefs;  // defines A

namespace myns
{
    export class JSONTools final
    {
        public:
            static A readA(const std::filesystem::path& filePath);
            static void writeA(const std::filesystem::path& filePath, const A& a);
        private:
            JSONTools() = delete;
            JSONTools(const JSONTools&) = delete;
            JSONTools(JSONTools&&) = delete;
    };    

} // namespace myns

DataDefs.cpp

module;

#include <fstream>
#include <nlohmann/json.hpp>

module JSONTools;

import DataDefs;

namespace myns
{

    A JSONTools::readA(const std::filesystem::path& filePath);
    {
        std::string fileContent = readTxt(filePath);   // readTxt defined somewhere else
        nlohmann::json jsonContent = nlohmann::json::parse(fileContent);

        A result{};

        A.setVersion(jsonContent["version"].get<int>());

        // Fill A with the data read from the json

        return result;
    }

    void JSONTools::writeA(const std::filesystem::path& filePath, const A& a);
    {
        auto oFile = std::make_unique<std::ofstream>(filePath, std::ios::ate);

        nlohmann::json jsonOutput;

        jsonOutput["version"] = 1;
        // add some more content to json file

        (*oFile) << jsonOutput; 
    }

} // myns

CMakeLists.txt

project(JSONTools CXX)

find_package(nlohmann_json CONFIG REQUIRED)

set(INTERFACE_LIST
   JSONTools.ixx
)

set(SOURCE_LIST
   DataDefs.cpp
)

add_library(${PROJECT_NAME})

target_sources(${PROJECT_NAME}
   PRIVATE
      ${SOURCE_LIST}
   PUBLIC
   FILE_SET CXX_MODULES
   FILES ${INTERFACE_LIST}
)

target_link_libraries(${PROJECT_NAME}
PRIVATE
   DataDefs
   nlohmann_json::nlohmann_json
)

For every other module I am just importing JSONTools in the target_link_libraries section of the corresponding CMakeLists.txt

Blechwolf avatar Jul 30 '24 14:07 Blechwolf