diff --git a/docs/docset/docSet.sql b/docs/docset/docSet.sql index 8a4272ab7..f97647d97 100644 --- a/docs/docset/docSet.sql +++ b/docs/docset/docSet.sql @@ -183,6 +183,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('Iterators', 'Guide', 'feature INSERT INTO searchIndex(name, type, path) VALUES ('JSON Merge Patch', 'Guide', 'features/merge_patch/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON Patch and Diff', 'Guide', 'features/json_patch/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON Pointer', 'Guide', 'features/json_pointer/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('nlohmann Namespace', 'Guide', 'features/namespace/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Types', 'Guide', 'features/types/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Types: Number Handling', 'Guide', 'features/types/number_handling/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Object Order', 'Guide', 'features/object_order/index.html'); @@ -225,6 +226,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTR INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE', 'Macro', 'api/macros/nlohmann_json_namespace/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_BEGIN', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_END', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_NO_VERSION', 'Macro', 'api/macros/nlohmann_json_namespace_no_version/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_SERIALIZE_ENUM', 'Macro', 'api/macros/nlohmann_json_serialize_enum/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MAJOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MINOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html'); diff --git a/docs/examples/nlohmann_json_namespace.output b/docs/examples/nlohmann_json_namespace.output index d5a8b59d6..e943d3444 100644 --- a/docs/examples/nlohmann_json_namespace.output +++ b/docs/examples/nlohmann_json_namespace.output @@ -1 +1 @@ -nlohmann::json_v3_11_1 +nlohmann::json_abi_v3_11_1 diff --git a/docs/examples/nlohmann_json_namespace_no_version.cpp b/docs/examples/nlohmann_json_namespace_no_version.cpp new file mode 100644 index 000000000..97948dd7e --- /dev/null +++ b/docs/examples/nlohmann_json_namespace_no_version.cpp @@ -0,0 +1,13 @@ +#include + +#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 1 +#include + +// macro needed to output the NLOHMANN_JSON_NAMESPACE as string literal +#define Q(x) #x +#define QUOTE(x) Q(x) + +int main() +{ + std::cout << QUOTE(NLOHMANN_JSON_NAMESPACE) << std::endl; +} diff --git a/docs/examples/nlohmann_json_namespace_no_version.output b/docs/examples/nlohmann_json_namespace_no_version.output new file mode 100644 index 000000000..1c8f3132b --- /dev/null +++ b/docs/examples/nlohmann_json_namespace_no_version.output @@ -0,0 +1 @@ +nlohmann::json_abi diff --git a/docs/mkdocs/docs/api/macros/index.md b/docs/mkdocs/docs/api/macros/index.md index 8e118b03f..099dfa671 100644 --- a/docs/mkdocs/docs/api/macros/index.md +++ b/docs/mkdocs/docs/api/macros/index.md @@ -32,7 +32,10 @@ header. See also the [macro overview page](../../features/macros.md). ## Library namespace - [**NLOHMANN_JSON_NAMESPACE**](nlohmann_json_namespace.md) - full name of the `nlohmann` namespace -- [**NLOHMANN_JSON_NAMESPACE_BEGIN**
**NLOHMANN_JSON_NAMESPACE_END**](nlohmann_json_namespace_begin.md) - open and close the library namespace +- [**NLOHMANN_JSON_NAMESPACE_BEGIN**
**NLOHMANN_JSON_NAMESPACE_END**](nlohmann_json_namespace_begin.md) - open and + close the library namespace +- [**NLOHMANN_JSON_NAMESPACE_NO_VERSION**](nlohmann_json_namespace_no_version.md) - disable the version component of + the inline namespace ## Type conversions diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_namespace.md b/docs/mkdocs/docs/api/macros/nlohmann_json_namespace.md index b44538e18..5c54dba52 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_json_namespace.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_namespace.md @@ -1,19 +1,18 @@ # NLOHMANN_JSON_NAMESPACE ```cpp -#define NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE /* value */ ``` -This macro evaluates to the full name of the `nlohmann` namespace, including the name of a versioned and ABI-tagged -inline namespace. Use this macro to unambiguously refer to the `nlohmann` namespace. +This macro evaluates to the full name of the `nlohmann` namespace. ## Default definition -The default value consists of a prefix, a version string, and optional ABI tags depending on whether ABI-affecting -macros are defined (e.g., [`JSON_DIAGNOSTICS`](json_diagnostics.md), and -[`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](json_use_legacy_discarded_value_comparison.md)). +The default value consists of the root namespace (`nlohmann`) and an inline ABI namespace. See +[`nlohmann` Namespace](../../features/namespace.md#structure) for details. -When the macro is not defined, the library will define it to its default value. +When the macro is not defined, the library will define it to its default value. Overriding this value has no effect on +the library. ## Examples @@ -35,7 +34,8 @@ When the macro is not defined, the library will define it to its default value. ## See also - [`NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END`](nlohmann_json_namespace_begin.md) +- [`NLOHMANN_JSON_NAMESPACE_NO_VERSION`](nlohmann_json_namespace_no_version.md) ## Version history -- Added in version 3.11.0. +- Added in version 3.11.0. Changed inline namespace name in version 3.11.2. diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_namespace_begin.md b/docs/mkdocs/docs/api/macros/nlohmann_json_namespace_begin.md index 5fd8fba2d..1374264a3 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_json_namespace_begin.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_namespace_begin.md @@ -1,30 +1,35 @@ # NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END ```cpp -#define NLOHMANN_JSON_NAMESPACE_BEGIN // (1) -#define NLOHMANN_JSON_NAMESPACE_END // (2) +#define NLOHMANN_JSON_NAMESPACE_BEGIN /* value */ // (1) +#define NLOHMANN_JSON_NAMESPACE_END /* value */ // (2) ``` -These macros can be used to open and close the `nlohmann` namespace. They include an inline namespace used to -differentiate symbols when linking multiple versions (including different ABI-affecting macros) of this library. +These macros can be used to open and close the `nlohmann` namespace. See +[`nlohmann` Namespace](../../features/namespace.md#structure) for details. 1. Opens the namespace. - ```cpp - namespace nlohmann - { - inline namespace json_v3_11_0 - { - ``` - 2. Closes the namespace. - ```cpp - } // namespace nlohmann - } // json_v3_11_0 - ``` ## Default definition -The default definitions open and close the `nlohmann` as well as an inline namespace. +The default definitions open and close the `nlohmann` namespace. The precise definition of +[`NLOHMANN_JSON_NAMESPACE_BEGIN`] varies as described [here](../../features/namespace.md#structure). + +1. Default definition of `NLOHMANN_JSON_NAMESPACE_BEGIN`: + + ```cpp + namespace nlohmann + { + inline namespace json_abi_v3_11_2 + { + ``` + +2. Default definition of `NLOHMANN_JSON_NAMESPACE_END`: + ```cpp + } // namespace json_abi_v3_11_2 + } // namespace nlohmann + ``` When these macros are not defined, the library will define them to their default definitions. @@ -32,7 +37,7 @@ When these macros are not defined, the library will define them to their default ??? example - The example shows an example how to use `NLOHMANN_JSON_NAMESPACE_BEGIN`/`NLOHMANN_JSON_NAMESPACE_END` from the + The example shows how to use `NLOHMANN_JSON_NAMESPACE_BEGIN`/`NLOHMANN_JSON_NAMESPACE_END` from the [How do I convert third-party types?](../../features/arbitrary_types.md#how-do-i-convert-third-party-types) page. ```cpp @@ -47,8 +52,10 @@ When these macros are not defined, the library will define them to their default ## See also +- [`nlohmann` Namespace](../../features/namespace.md) - [NLOHMANN_JSON_NAMESPACE](nlohmann_json_namespace.md) +- [`NLOHMANN_JSON_NAMESPACE_NO_VERSION`](nlohmann_json_namespace_no_version.md) ## Version history -- Added in version 3.11.0. +- Added in version 3.11.0. Changed inline namespace name in version 3.11.2. diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_namespace_no_version.md b/docs/mkdocs/docs/api/macros/nlohmann_json_namespace_no_version.md new file mode 100644 index 000000000..9e2a52d04 --- /dev/null +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_namespace_no_version.md @@ -0,0 +1,45 @@ +# NLOHMANN_JSON_NAMESPACE_NO_VERSION + +```cpp +#define NLOHMANN_JSON_NAMESPACE_NO_VERSION /* value */ +``` + +If defined to `1`, the version component is omitted from the inline namespace. See +[`nlohmann` Namespace](../../features/namespace.md#structure) for details. + +## Default definition + +The default value is `0`. + +```cpp +#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +``` + +When the macro is not defined, the library will define it to its default value. + +## Examples + +??? example + + The example shows how to use `NLOHMANN_JSON_NAMESPACE_NO_VERSION` to disable the version component of the inline + namespace. + + ```cpp + --8<-- "examples/nlohmann_json_namespace_no_version.cpp" + ``` + + Output: + + ```json + --8<-- "examples/nlohmann_json_namespace_no_version.output" + ``` + +## See also + +- [`nlohmann` Namespace](../../features/namespace.md) +- [`NLOHMANN_JSON_NAMESPACE`](nlohmann_json_namespace.md) +- [`NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END`](nlohmann_json_namespace_begin.md) + +## Version history + +- Added in version 3.11.2. diff --git a/docs/mkdocs/docs/features/namespace.md b/docs/mkdocs/docs/features/namespace.md new file mode 100644 index 000000000..8cee2ccfe --- /dev/null +++ b/docs/mkdocs/docs/features/namespace.md @@ -0,0 +1,93 @@ +# `nlohmann` Namespace + +The 3.11.0 release introduced an +[inline namespace](https://en.cppreference.com/w/cpp/language/namespace#Inline_namespaces) to allow different parts of +a codebase to safely use different versions of the JSON library as long as they never exchange instances of library +types. + +## Structure + +The complete default namespace name is derived as follows: + +- The root namespace is always `nlohmann`. +- The inline namespace starts with `json_abi` and is followed by serveral optional ABI tags according to the value of + these ABI-affecting macros, in order: + - [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) defined non-zero appends `_diag`. + - [`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](../api/macros/json_use_legacy_discarded_value_comparison.md) + defined non-zero appends `_ldvcmp`. +- The inline namespace ends with the suffix `_v` followed by the 3 components of the version number separated by + underscores. To omit the version component, see [Disabling the version component](#disabling-the-version-component) + below. + +For example, the namespace name for version 3.11.2 with `JSON_DIAGNOSTICS` defined to `1` is: + +```cpp +nlohmann::json_abi_diag_v3_11_2 +``` + +## Purpose + +Several incompatibilities have been observed. Amongst the most common ones is linking code compiled with different +definitions of [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This is illustrated in the diagram below. + +```plantuml +[**nlohmann_json (v3.10.5)**\nJSON_DIAGNOSTICS=0] as [json] +[**nlohmann_json (v3.10.5)**\nJSON_DIAGNOSTICS=1] as [json_diag] +[**some_library**] as [library] +[**application**] as [app] + +[library] ..|> [json] +[app] ..|> [json_diag] +[app] ..|>[library] +``` + +In releases prior to 3.11.0, mixing any version of the JSON library with different `JSON_DIAGNOSTICS` settings would +result in a crashing application. If `some_library` never passes instances of JSON library types to the application, +this scenario became safe in version 3.11.0 and above due to the inline namespace yielding distinct symbol names. + +## Limitations + +Neither the compiler nor the linker will issue as much as a warning when translation units – intended to be linked +together and that include different versions and/or configurations of the JSON library – exchange and use library +types. + +There is an exception when forward declarations are used (i.e., when including `json_fwd.hpp`) in which case the linker +may complain about undefined references. + +## Disabling the version component + +Different versions are not necessarily ABI-incompatible, but the project does not actively track changes in the ABI and +recommends that all parts of a codebase exchanging library types be built with the same version. Users can, **at their +own risk**, disable the version component of the linline namespace, allowing different versions – but not +configurations – to be used in cases where the linker would otherwise output undefined reference errors. + +To do so, define [`NLOHMANN_JSON_NAMESPACE_NO_VERSION`](../api/macros/nlohmann_json_namespace_no_version.md) to `1`. + +This applies to version 3.11.2 and above only, versions 3.11.0 and 3.11.1 can apply the technique described in the next +section to emulate the effect of the `NLOHMANN_JSON_NAMESPACE_NO_VERSION` macro. + +!!! danger "Use at your own risk" + + Disabling the namespace version component and mixing ABI-incompatible versions will result in crashes or incorrect + behavior. You have been warned! +## Disabling the inline namespace completely + +When interoperability with code using a pre-3.11.0 version of the library is required, users can, **at their own risk** +restore the old namespace layout by redefining +[`NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END`](../api/macros/nlohmann_json_namespace_begin.md) as +follows: + +```cpp +#define NLOHMANN_JSON_NAMESPACE_BEGIN namespace nlohmann { +#define NLOHMANN_JSON_NAMESPACE_END } +``` + +!!! danger "Use at your own risk" + + Overriding the namespace and mixing ABI-incompatible versions will result in crashes or incorrect behavior. You + have been warned! + +## Version history + +- Introduced inline namespace (`json_v3_11_0[_abi-tag]*`) in version 3.11.0. +- Changed structure of inline namespace in version 3.11.2. diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index f88784f3e..545584a92 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -58,6 +58,7 @@ nav: - features/json_pointer.md - features/json_patch.md - features/merge_patch.md + - 'nlohmann Namespace': features/namespace.md - features/object_order.md - Parsing: - features/parsing/index.md @@ -270,6 +271,7 @@ nav: - 'NLOHMANN_JSON_NAMESPACE': api/macros/nlohmann_json_namespace.md - 'NLOHMANN_JSON_NAMESPACE_BEGIN': api/macros/nlohmann_json_namespace_begin.md - 'NLOHMANN_JSON_NAMESPACE_END': api/macros/nlohmann_json_namespace_begin.md + - 'NLOHMANN_JSON_NAMESPACE_NO_VERSION': api/macros/nlohmann_json_namespace_no_version.md - 'NLOHMANN_JSON_SERIALIZE_ENUM': api/macros/nlohmann_json_serialize_enum.md - 'NLOHMANN_JSON_VERSION_MAJOR': api/macros/nlohmann_json_version_major.md - 'NLOHMANN_JSON_VERSION_MINOR': api/macros/nlohmann_json_version_major.md diff --git a/include/nlohmann/detail/abi_macros.hpp b/include/nlohmann/detail/abi_macros.hpp index dac3c58e6..867b36932 100644 --- a/include/nlohmann/detail/abi_macros.hpp +++ b/include/nlohmann/detail/abi_macros.hpp @@ -42,38 +42,59 @@ #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON #endif -#define NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch) \ - json_v ## major ## _ ## minor ## _ ## patch -#define NLOHMANN_JSON_ABI_PREFIX(major, minor, patch) \ - NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch) +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif -#define NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c) a ## b ## c -#define NLOHMANN_JSON_ABI_CONCAT(a, b, c) \ - NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c) +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) -#define NLOHMANN_JSON_ABI_STRING \ - NLOHMANN_JSON_ABI_CONCAT( \ - NLOHMANN_JSON_ABI_PREFIX( \ - NLOHMANN_JSON_VERSION_MAJOR, \ - NLOHMANN_JSON_VERSION_MINOR, \ - NLOHMANN_JSON_VERSION_PATCH), \ - NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + #ifndef NLOHMANN_JSON_NAMESPACE - #define NLOHMANN_JSON_NAMESPACE nlohmann::NLOHMANN_JSON_ABI_STRING +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) #endif #ifndef NLOHMANN_JSON_NAMESPACE_BEGIN -#define NLOHMANN_JSON_NAMESPACE_BEGIN \ - namespace nlohmann \ - { \ - inline namespace NLOHMANN_JSON_ABI_STRING \ +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ { #endif #ifndef NLOHMANN_JSON_NAMESPACE_END -#define NLOHMANN_JSON_NAMESPACE_END \ - } /* namespace (abi_string) */ \ - } /* namespace nlohmann */ +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann #endif diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2689c4194..6f956dabf 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -90,40 +90,61 @@ #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON #endif -#define NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch) \ - json_v ## major ## _ ## minor ## _ ## patch -#define NLOHMANN_JSON_ABI_PREFIX(major, minor, patch) \ - NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch) +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif -#define NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c) a ## b ## c -#define NLOHMANN_JSON_ABI_CONCAT(a, b, c) \ - NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c) +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) -#define NLOHMANN_JSON_ABI_STRING \ - NLOHMANN_JSON_ABI_CONCAT( \ - NLOHMANN_JSON_ABI_PREFIX( \ - NLOHMANN_JSON_VERSION_MAJOR, \ - NLOHMANN_JSON_VERSION_MINOR, \ - NLOHMANN_JSON_VERSION_PATCH), \ - NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + #ifndef NLOHMANN_JSON_NAMESPACE - #define NLOHMANN_JSON_NAMESPACE nlohmann::NLOHMANN_JSON_ABI_STRING +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) #endif #ifndef NLOHMANN_JSON_NAMESPACE_BEGIN -#define NLOHMANN_JSON_NAMESPACE_BEGIN \ - namespace nlohmann \ - { \ - inline namespace NLOHMANN_JSON_ABI_STRING \ +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ { #endif #ifndef NLOHMANN_JSON_NAMESPACE_END -#define NLOHMANN_JSON_NAMESPACE_END \ - } /* namespace (abi_string) */ \ - } /* namespace nlohmann */ +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann #endif // #include diff --git a/single_include/nlohmann/json_fwd.hpp b/single_include/nlohmann/json_fwd.hpp index 0718f3f65..6d0283a7e 100644 --- a/single_include/nlohmann/json_fwd.hpp +++ b/single_include/nlohmann/json_fwd.hpp @@ -60,40 +60,61 @@ #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON #endif -#define NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch) \ - json_v ## major ## _ ## minor ## _ ## patch -#define NLOHMANN_JSON_ABI_PREFIX(major, minor, patch) \ - NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch) +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif -#define NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c) a ## b ## c -#define NLOHMANN_JSON_ABI_CONCAT(a, b, c) \ - NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c) +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) -#define NLOHMANN_JSON_ABI_STRING \ - NLOHMANN_JSON_ABI_CONCAT( \ - NLOHMANN_JSON_ABI_PREFIX( \ - NLOHMANN_JSON_VERSION_MAJOR, \ - NLOHMANN_JSON_VERSION_MINOR, \ - NLOHMANN_JSON_VERSION_PATCH), \ - NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + #ifndef NLOHMANN_JSON_NAMESPACE - #define NLOHMANN_JSON_NAMESPACE nlohmann::NLOHMANN_JSON_ABI_STRING +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) #endif #ifndef NLOHMANN_JSON_NAMESPACE_BEGIN -#define NLOHMANN_JSON_NAMESPACE_BEGIN \ - namespace nlohmann \ - { \ - inline namespace NLOHMANN_JSON_ABI_STRING \ +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ { #endif #ifndef NLOHMANN_JSON_NAMESPACE_END -#define NLOHMANN_JSON_NAMESPACE_END \ - } /* namespace (abi_string) */ \ - } /* namespace nlohmann */ +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann #endif diff --git a/tests/abi/CMakeLists.txt b/tests/abi/CMakeLists.txt index c1ae5430a..ba90837cb 100644 --- a/tests/abi/CMakeLists.txt +++ b/tests/abi/CMakeLists.txt @@ -25,5 +25,6 @@ add_library(abi_compat_main STATIC main.cpp) target_link_libraries(abi_compat_main PUBLIC abi_compat_common) # add individual tests +add_subdirectory(config) add_subdirectory(diag) add_subdirectory(inline_ns) diff --git a/tests/abi/config/CMakeLists.txt b/tests/abi/config/CMakeLists.txt new file mode 100644 index 000000000..3a8367690 --- /dev/null +++ b/tests/abi/config/CMakeLists.txt @@ -0,0 +1,22 @@ +# test the different options to change the namespace + +# test default namespace +add_executable(abi_config_default default.cpp) +target_link_libraries(abi_config_default PRIVATE abi_compat_main) +add_test( + NAME test-abi_config_default + COMMAND abi_config_default ${DOCTEST_TEST_FILTER}) + +# test no version namespace +add_executable(abi_config_noversion noversion.cpp) +target_link_libraries(abi_config_noversion PRIVATE abi_compat_main) +add_test( + NAME test-abi_config_noversion + COMMAND abi_config_noversion ${DOCTEST_TEST_FILTER}) + +# test custom namespace +add_executable(abi_config_custom custom.cpp) +target_link_libraries(abi_config_custom PRIVATE abi_compat_main) +add_test( + NAME test-abi_config_custom + COMMAND abi_config_custom ${DOCTEST_TEST_FILTER}) diff --git a/tests/abi/config/config.hpp b/tests/abi/config/config.hpp new file mode 100644 index 000000000..a824625f6 --- /dev/null +++ b/tests/abi/config/config.hpp @@ -0,0 +1,35 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.11.1 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include "doctest.h" + +#include +#include +#include + +#define STRINGIZE_EX(x) #x +#define STRINGIZE(x) STRINGIZE_EX(x) + +template +std::string namespace_name(std::string ns, T* /*unused*/ = nullptr) // NOLINT(performance-unnecessary-value-param) +{ +#if DOCTEST_MSVC && !DOCTEST_CLANG + ns = __FUNCSIG__; +#elif !DOCTEST_CLANG + ns = __PRETTY_FUNCTION__; +#endif + std::smatch m; + + // extract the true namespace name from the function signature + CAPTURE(ns); + CHECK(std::regex_search(ns, m, std::regex("nlohmann(::[a-zA-Z0-9_]+)*::basic_json"))); + + return m.str(); +} diff --git a/tests/abi/config/custom.cpp b/tests/abi/config/custom.cpp new file mode 100644 index 000000000..9567e6c51 --- /dev/null +++ b/tests/abi/config/custom.cpp @@ -0,0 +1,33 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.11.1 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#include "config.hpp" + +// define custom namespace +#define NLOHMANN_JSON_NAMESPACE nlohmann // this line may be omitted +#define NLOHMANN_JSON_NAMESPACE_BEGIN namespace nlohmann { +#define NLOHMANN_JSON_NAMESPACE_END } +#include + +TEST_CASE("custom namespace") +{ + // GCC 4.8 fails with regex_error +#if !DOCTEST_GCC || DOCTEST_GCC >= DOCTEST_COMPILER(4, 9, 0) + SECTION("namespace matches expectation") + { + std::string expected = "nlohmann::basic_json"; + + // fallback for Clang + std::string ns{STRINGIZE(NLOHMANN_JSON_NAMESPACE) "::basic_json"}; + + CHECK(namespace_name(ns) == expected); + } +#endif +} diff --git a/tests/abi/config/default.cpp b/tests/abi/config/default.cpp new file mode 100644 index 000000000..0562db73b --- /dev/null +++ b/tests/abi/config/default.cpp @@ -0,0 +1,41 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.11.1 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#include "config.hpp" + +#include + +TEST_CASE("default namespace") +{ + // GCC 4.8 fails with regex_error +#if !DOCTEST_GCC || DOCTEST_GCC >= DOCTEST_COMPILER(4, 9, 0) + SECTION("namespace matches expectation") + { + std::string expected = "nlohmann::json_abi"; + +#if JSON_DIAGNOSTICS + expected += "_diag"; +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + expected += "_ldvcmp"; +#endif + + expected += "_v" STRINGIZE(NLOHMANN_JSON_VERSION_MAJOR); + expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_MINOR); + expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_PATCH) "::basic_json"; + + // fallback for Clang + std::string ns{STRINGIZE(NLOHMANN_JSON_NAMESPACE) "::basic_json"}; + + CHECK(namespace_name(ns) == expected); + } +#endif +} diff --git a/tests/abi/config/noversion.cpp b/tests/abi/config/noversion.cpp new file mode 100644 index 000000000..f8a5530bf --- /dev/null +++ b/tests/abi/config/noversion.cpp @@ -0,0 +1,40 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.11.1 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#include "config.hpp" + +#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 1 +#include + +TEST_CASE("default namespace without version component") +{ + // GCC 4.8 fails with regex_error +#if !DOCTEST_GCC || DOCTEST_GCC >= DOCTEST_COMPILER(4, 9, 0) + SECTION("namespace matches expectation") + { + std::string expected = "nlohmann::json_abi"; + +#if JSON_DIAGNOSTICS + expected += "_diag"; +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + expected += "_ldvcmp"; +#endif + + expected += "::basic_json"; + + // fallback for Clang + std::string ns{STRINGIZE(NLOHMANN_JSON_NAMESPACE) "::basic_json"}; + + CHECK(namespace_name(ns) == expected); + } +#endif +} diff --git a/tests/abi/include/nlohmann/json_v3_10_5.hpp b/tests/abi/include/nlohmann/json_v3_10_5.hpp index cb27e0581..87995556e 100644 --- a/tests/abi/include/nlohmann/json_v3_10_5.hpp +++ b/tests/abi/include/nlohmann/json_v3_10_5.hpp @@ -36,8 +36,8 @@ SOFTWARE. * file doc/README.md. * \****************************************************************************/ -#ifndef INCLUDE_NLOHMANN_JSON_HPP_ -#define INCLUDE_NLOHMANN_JSON_HPP_ +#ifndef INCLUDE_NLOHMANN_JSON_V3_10_5_HPP_ +#define INCLUDE_NLOHMANN_JSON_V3_10_5_HPP_ #define NLOHMANN_JSON_VERSION_MAJOR 3 #define NLOHMANN_JSON_VERSION_MINOR 10 @@ -22088,4 +22088,4 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std -#endif // INCLUDE_NLOHMANN_JSON_HPP_ +#endif // INCLUDE_NLOHMANN_JSON_V3_10_5_HPP_ diff --git a/tools/gdb_pretty_printer/nlohmann-json.py b/tools/gdb_pretty_printer/nlohmann-json.py index 774756de7..0099f9c0a 100644 --- a/tools/gdb_pretty_printer/nlohmann-json.py +++ b/tools/gdb_pretty_printer/nlohmann-json.py @@ -1,7 +1,7 @@ import gdb import re -ns_pattern = re.compile(r'nlohmann::json_v(?P\d+)_(?P\d+)_(?P\d+)(?P\w*)::(?P.+)') +ns_pattern = re.compile(r'nlohmann(::json_abi(?P\w*)(_v(?P\d+)_(?P\d+)_(?P\d+))?)?::(?P.+)') class JsonValuePrinter: "Print a json-value" @@ -26,7 +26,7 @@ def json_lookup_function(val): return gdb.default_visualizer(union_val.dereference()) else: return JsonValuePrinter(union_val) - except: + except Exception: return JsonValuePrinter(val['m_type']) gdb.pretty_printers.append(json_lookup_function)