Add versioned, ABI-tagged inline namespace and namespace macros (#3590)

* Add versioned inline namespace

Add a versioned inline namespace to prevent ABI issues when linking code
using multiple library versions.

* Add namespace macros

* Encode ABI information in inline namespace

Add _diag suffix to inline namespace if JSON_DIAGNOSTICS is enabled, and
_ldvcmp suffix if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON is enabled.

* Move ABI-affecting macros into abi_macros.hpp

* Move std_fs namespace definition into std_fs.hpp

* Remove std_fs namespace from unit test

* Format more files in tests directory

* Add unit tests

* Update documentation

* Fix GDB pretty printer

* fixup! Add namespace macros

* Derive ABI prefix from NLOHMANN_JSON_VERSION_*
This commit is contained in:
Florian Albrechtskirchinger
2022-07-30 21:59:13 +02:00
committed by GitHub
parent fca1ddda96
commit d909f80960
72 changed files with 23116 additions and 561 deletions

View File

@@ -0,0 +1,19 @@
# test linking library built with different JSON_DIAGNOSTICS setting
# into the same executable
# compile code using JSON_DIAGNOSTICS=1
add_library(abi_compat_diag_on STATIC diag_on.cpp)
target_link_libraries(abi_compat_diag_on PUBLIC abi_compat_common)
# compile code using JSON_DIAGNOSTICS=0
add_library(abi_compat_diag_off STATIC diag_off.cpp)
target_link_libraries(abi_compat_diag_off PUBLIC abi_compat_common)
# build test executable and add test
add_executable(abi_compat_diag diag.cpp)
target_link_libraries(abi_compat_diag PRIVATE
abi_compat_main abi_compat_diag_on abi_compat_diag_off)
add_test(
NAME test-abi_compat_diag
COMMAND abi_compat_diag ${DOCTEST_TEST_FILTER})

21
tests/abi/diag/diag.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include "doctest_compatibility.h"
#include "diag.hpp"
TEST_CASE("ABI compatible diagnostics")
{
SECTION("basic_json size")
{
// basic_json with diagnostics is larger because of added data members
CHECK(json_sizeof_diag_on() == json_sizeof_diag_on_explicit());
CHECK(json_sizeof_diag_off() == json_sizeof_diag_off_explicit());
CHECK(json_sizeof_diag_on() > json_sizeof_diag_off());
}
SECTION("basic_json at")
{
// accessing a nonexistent key throws different exception with diagnostics
CHECK_THROWS_WITH(json_at_diag_on(), "[json.exception.out_of_range.403] (/foo) key 'bar' not found");
CHECK_THROWS_WITH(json_at_diag_off(), "[json.exception.out_of_range.403] key 'bar' not found");
}
}

12
tests/abi/diag/diag.hpp Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <cstddef>
std::size_t json_sizeof_diag_on();
std::size_t json_sizeof_diag_on_explicit();
std::size_t json_sizeof_diag_off();
std::size_t json_sizeof_diag_off_explicit();
void json_at_diag_on();
void json_at_diag_off();

View File

@@ -0,0 +1,22 @@
#undef JSON_DIAGNOSTICS
#define JSON_DIAGNOSTICS 0
#include <nlohmann/json.hpp>
#include "diag.hpp"
std::size_t json_sizeof_diag_off()
{
return sizeof(nlohmann::json);
}
std::size_t json_sizeof_diag_off_explicit()
{
return sizeof(::NLOHMANN_JSON_NAMESPACE::json);
}
void json_at_diag_off()
{
using nlohmann::json;
json j = json{{"foo", json::object()}};
j.at(json::json_pointer("/foo/bar"));
}

View File

@@ -0,0 +1,22 @@
#undef JSON_DIAGNOSTICS
#define JSON_DIAGNOSTICS 1
#include <nlohmann/json.hpp>
#include "diag.hpp"
std::size_t json_sizeof_diag_on()
{
return sizeof(nlohmann::json);
}
std::size_t json_sizeof_diag_on_explicit()
{
return sizeof(::NLOHMANN_JSON_NAMESPACE::json);
}
void json_at_diag_on()
{
using nlohmann::json;
json j = json{{"foo", json::object()}};
j.at(json::json_pointer("/foo/bar"));
}