Skip to content

Commit 0e61ee8

Browse files
Restructure inline namespace and allow version component to be disabled (#3683)
1 parent 93112fb commit 0e61ee8

21 files changed

+501
-100
lines changed

docs/docset/docSet.sql

+2
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('Iterators', 'Guide', 'feature
183183
INSERT INTO searchIndex(name, type, path) VALUES ('JSON Merge Patch', 'Guide', 'features/merge_patch/index.html');
184184
INSERT INTO searchIndex(name, type, path) VALUES ('JSON Patch and Diff', 'Guide', 'features/json_patch/index.html');
185185
INSERT INTO searchIndex(name, type, path) VALUES ('JSON Pointer', 'Guide', 'features/json_pointer/index.html');
186+
INSERT INTO searchIndex(name, type, path) VALUES ('nlohmann Namespace', 'Guide', 'features/namespace/index.html');
186187
INSERT INTO searchIndex(name, type, path) VALUES ('Types', 'Guide', 'features/types/index.html');
187188
INSERT INTO searchIndex(name, type, path) VALUES ('Types: Number Handling', 'Guide', 'features/types/number_handling/index.html');
188189
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
225226
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE', 'Macro', 'api/macros/nlohmann_json_namespace/index.html');
226227
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_BEGIN', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html');
227228
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_END', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html');
229+
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_NO_VERSION', 'Macro', 'api/macros/nlohmann_json_namespace_no_version/index.html');
228230
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_SERIALIZE_ENUM', 'Macro', 'api/macros/nlohmann_json_serialize_enum/index.html');
229231
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MAJOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html');
230232
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MINOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html');
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nlohmann::json_v3_11_1
1+
nlohmann::json_abi_v3_11_1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <iostream>
2+
3+
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 1
4+
#include <nlohmann/json.hpp>
5+
6+
// macro needed to output the NLOHMANN_JSON_NAMESPACE as string literal
7+
#define Q(x) #x
8+
#define QUOTE(x) Q(x)
9+
10+
int main()
11+
{
12+
std::cout << QUOTE(NLOHMANN_JSON_NAMESPACE) << std::endl;
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nlohmann::json_abi

docs/mkdocs/docs/api/macros/index.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ header. See also the [macro overview page](../../features/macros.md).
3232
## Library namespace
3333

3434
- [**NLOHMANN_JSON_NAMESPACE**](nlohmann_json_namespace.md) - full name of the `nlohmann` namespace
35-
- [**NLOHMANN_JSON_NAMESPACE_BEGIN**<br>**NLOHMANN_JSON_NAMESPACE_END**](nlohmann_json_namespace_begin.md) - open and close the library namespace
35+
- [**NLOHMANN_JSON_NAMESPACE_BEGIN**<br>**NLOHMANN_JSON_NAMESPACE_END**](nlohmann_json_namespace_begin.md) - open and
36+
close the library namespace
37+
- [**NLOHMANN_JSON_NAMESPACE_NO_VERSION**](nlohmann_json_namespace_no_version.md) - disable the version component of
38+
the inline namespace
3639

3740
## Type conversions
3841

docs/mkdocs/docs/api/macros/nlohmann_json_namespace.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
# NLOHMANN_JSON_NAMESPACE
22

33
```cpp
4-
#define NLOHMANN_JSON_NAMESPACE
4+
#define NLOHMANN_JSON_NAMESPACE /* value */
55
```
66
7-
This macro evaluates to the full name of the `nlohmann` namespace, including the name of a versioned and ABI-tagged
8-
inline namespace. Use this macro to unambiguously refer to the `nlohmann` namespace.
7+
This macro evaluates to the full name of the `nlohmann` namespace.
98
109
## Default definition
1110
12-
The default value consists of a prefix, a version string, and optional ABI tags depending on whether ABI-affecting
13-
macros are defined (e.g., [`JSON_DIAGNOSTICS`](json_diagnostics.md), and
14-
[`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](json_use_legacy_discarded_value_comparison.md)).
11+
The default value consists of the root namespace (`nlohmann`) and an inline ABI namespace. See
12+
[`nlohmann` Namespace](../../features/namespace.md#structure) for details.
1513
16-
When the macro is not defined, the library will define it to its default value.
14+
When the macro is not defined, the library will define it to its default value. Overriding this value has no effect on
15+
the library.
1716
1817
## Examples
1918
@@ -35,7 +34,8 @@ When the macro is not defined, the library will define it to its default value.
3534
## See also
3635
3736
- [`NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END`](nlohmann_json_namespace_begin.md)
37+
- [`NLOHMANN_JSON_NAMESPACE_NO_VERSION`](nlohmann_json_namespace_no_version.md)
3838
3939
## Version history
4040
41-
- Added in version 3.11.0.
41+
- Added in version 3.11.0. Changed inline namespace name in version 3.11.2.
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,43 @@
11
# NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END
22

33
```cpp
4-
#define NLOHMANN_JSON_NAMESPACE_BEGIN // (1)
5-
#define NLOHMANN_JSON_NAMESPACE_END // (2)
4+
#define NLOHMANN_JSON_NAMESPACE_BEGIN /* value */ // (1)
5+
#define NLOHMANN_JSON_NAMESPACE_END /* value */ // (2)
66
```
77
8-
These macros can be used to open and close the `nlohmann` namespace. They include an inline namespace used to
9-
differentiate symbols when linking multiple versions (including different ABI-affecting macros) of this library.
8+
These macros can be used to open and close the `nlohmann` namespace. See
9+
[`nlohmann` Namespace](../../features/namespace.md#structure) for details.
1010
1111
1. Opens the namespace.
12+
2. Closes the namespace.
13+
14+
## Default definition
15+
16+
The default definitions open and close the `nlohmann` namespace. The precise definition of
17+
[`NLOHMANN_JSON_NAMESPACE_BEGIN`] varies as described [here](../../features/namespace.md#structure).
18+
19+
1. Default definition of `NLOHMANN_JSON_NAMESPACE_BEGIN`:
20+
1221
```cpp
1322
namespace nlohmann
1423
{
15-
inline namespace json_v3_11_0
24+
inline namespace json_abi_v3_11_2
1625
{
1726
```
1827
19-
2. Closes the namespace.
28+
2. Default definition of `NLOHMANN_JSON_NAMESPACE_END`:
2029
```cpp
30+
} // namespace json_abi_v3_11_2
2131
} // namespace nlohmann
22-
} // json_v3_11_0
2332
```
2433
25-
## Default definition
26-
27-
The default definitions open and close the `nlohmann` as well as an inline namespace.
28-
2934
When these macros are not defined, the library will define them to their default definitions.
3035
3136
## Examples
3237
3338
??? example
3439
35-
The example shows an example how to use `NLOHMANN_JSON_NAMESPACE_BEGIN`/`NLOHMANN_JSON_NAMESPACE_END` from the
40+
The example shows how to use `NLOHMANN_JSON_NAMESPACE_BEGIN`/`NLOHMANN_JSON_NAMESPACE_END` from the
3641
[How do I convert third-party types?](../../features/arbitrary_types.md#how-do-i-convert-third-party-types) page.
3742
3843
```cpp
@@ -47,8 +52,10 @@ When these macros are not defined, the library will define them to their default
4752
4853
## See also
4954
55+
- [`nlohmann` Namespace](../../features/namespace.md)
5056
- [NLOHMANN_JSON_NAMESPACE](nlohmann_json_namespace.md)
57+
- [`NLOHMANN_JSON_NAMESPACE_NO_VERSION`](nlohmann_json_namespace_no_version.md)
5158
5259
## Version history
5360
54-
- Added in version 3.11.0.
61+
- Added in version 3.11.0. Changed inline namespace name in version 3.11.2.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# NLOHMANN_JSON_NAMESPACE_NO_VERSION
2+
3+
```cpp
4+
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION /* value */
5+
```
6+
7+
If defined to `1`, the version component is omitted from the inline namespace. See
8+
[`nlohmann` Namespace](../../features/namespace.md#structure) for details.
9+
10+
## Default definition
11+
12+
The default value is `0`.
13+
14+
```cpp
15+
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
16+
```
17+
18+
When the macro is not defined, the library will define it to its default value.
19+
20+
## Examples
21+
22+
??? example
23+
24+
The example shows how to use `NLOHMANN_JSON_NAMESPACE_NO_VERSION` to disable the version component of the inline
25+
namespace.
26+
27+
```cpp
28+
--8<-- "examples/nlohmann_json_namespace_no_version.cpp"
29+
```
30+
31+
Output:
32+
33+
```json
34+
--8<-- "examples/nlohmann_json_namespace_no_version.output"
35+
```
36+
37+
## See also
38+
39+
- [`nlohmann` Namespace](../../features/namespace.md)
40+
- [`NLOHMANN_JSON_NAMESPACE`](nlohmann_json_namespace.md)
41+
- [`NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END`](nlohmann_json_namespace_begin.md)
42+
43+
## Version history
44+
45+
- Added in version 3.11.2.
+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# `nlohmann` Namespace
2+
3+
The 3.11.0 release introduced an
4+
[inline namespace](https://en.cppreference.com/w/cpp/language/namespace#Inline_namespaces) to allow different parts of
5+
a codebase to safely use different versions of the JSON library as long as they never exchange instances of library
6+
types.
7+
8+
## Structure
9+
10+
The complete default namespace name is derived as follows:
11+
12+
- The root namespace is always `nlohmann`.
13+
- The inline namespace starts with `json_abi` and is followed by serveral optional ABI tags according to the value of
14+
these ABI-affecting macros, in order:
15+
- [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) defined non-zero appends `_diag`.
16+
- [`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](../api/macros/json_use_legacy_discarded_value_comparison.md)
17+
defined non-zero appends `_ldvcmp`.
18+
- The inline namespace ends with the suffix `_v` followed by the 3 components of the version number separated by
19+
underscores. To omit the version component, see [Disabling the version component](#disabling-the-version-component)
20+
below.
21+
22+
For example, the namespace name for version 3.11.2 with `JSON_DIAGNOSTICS` defined to `1` is:
23+
24+
```cpp
25+
nlohmann::json_abi_diag_v3_11_2
26+
```
27+
28+
## Purpose
29+
30+
Several incompatibilities have been observed. Amongst the most common ones is linking code compiled with different
31+
definitions of [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This is illustrated in the diagram below.
32+
33+
```plantuml
34+
[**nlohmann_json (v3.10.5)**\nJSON_DIAGNOSTICS=0] as [json]
35+
[**nlohmann_json (v3.10.5)**\nJSON_DIAGNOSTICS=1] as [json_diag]
36+
[**some_library**] as [library]
37+
[**application**] as [app]
38+
39+
[library] ..|> [json]
40+
[app] ..|> [json_diag]
41+
[app] ..|>[library]
42+
```
43+
44+
In releases prior to 3.11.0, mixing any version of the JSON library with different `JSON_DIAGNOSTICS` settings would
45+
result in a crashing application. If `some_library` never passes instances of JSON library types to the application,
46+
this scenario became safe in version 3.11.0 and above due to the inline namespace yielding distinct symbol names.
47+
48+
## Limitations
49+
50+
Neither the compiler nor the linker will issue as much as a warning when translation units – intended to be linked
51+
together and that include different versions and/or configurations of the JSON library – exchange and use library
52+
types.
53+
54+
There is an exception when forward declarations are used (i.e., when including `json_fwd.hpp`) in which case the linker
55+
may complain about undefined references.
56+
57+
## Disabling the version component
58+
59+
Different versions are not necessarily ABI-incompatible, but the project does not actively track changes in the ABI and
60+
recommends that all parts of a codebase exchanging library types be built with the same version. Users can, **at their
61+
own risk**, disable the version component of the linline namespace, allowing different versions – but not
62+
configurations – to be used in cases where the linker would otherwise output undefined reference errors.
63+
64+
To do so, define [`NLOHMANN_JSON_NAMESPACE_NO_VERSION`](../api/macros/nlohmann_json_namespace_no_version.md) to `1`.
65+
66+
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
67+
section to emulate the effect of the `NLOHMANN_JSON_NAMESPACE_NO_VERSION` macro.
68+
69+
!!! danger "Use at your own risk"
70+
71+
Disabling the namespace version component and mixing ABI-incompatible versions will result in crashes or incorrect
72+
behavior. You have been warned!
73+
## Disabling the inline namespace completely
74+
75+
When interoperability with code using a pre-3.11.0 version of the library is required, users can, **at their own risk**
76+
restore the old namespace layout by redefining
77+
[`NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END`](../api/macros/nlohmann_json_namespace_begin.md) as
78+
follows:
79+
80+
```cpp
81+
#define NLOHMANN_JSON_NAMESPACE_BEGIN namespace nlohmann {
82+
#define NLOHMANN_JSON_NAMESPACE_END }
83+
```
84+
85+
!!! danger "Use at your own risk"
86+
87+
Overriding the namespace and mixing ABI-incompatible versions will result in crashes or incorrect behavior. You
88+
have been warned!
89+
90+
## Version history
91+
92+
- Introduced inline namespace (`json_v3_11_0[_abi-tag]*`) in version 3.11.0.
93+
- Changed structure of inline namespace in version 3.11.2.

docs/mkdocs/mkdocs.yml

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ nav:
5858
- features/json_pointer.md
5959
- features/json_patch.md
6060
- features/merge_patch.md
61+
- 'nlohmann Namespace': features/namespace.md
6162
- features/object_order.md
6263
- Parsing:
6364
- features/parsing/index.md
@@ -270,6 +271,7 @@ nav:
270271
- 'NLOHMANN_JSON_NAMESPACE': api/macros/nlohmann_json_namespace.md
271272
- 'NLOHMANN_JSON_NAMESPACE_BEGIN': api/macros/nlohmann_json_namespace_begin.md
272273
- 'NLOHMANN_JSON_NAMESPACE_END': api/macros/nlohmann_json_namespace_begin.md
274+
- 'NLOHMANN_JSON_NAMESPACE_NO_VERSION': api/macros/nlohmann_json_namespace_no_version.md
273275
- 'NLOHMANN_JSON_SERIALIZE_ENUM': api/macros/nlohmann_json_serialize_enum.md
274276
- 'NLOHMANN_JSON_VERSION_MAJOR': api/macros/nlohmann_json_version_major.md
275277
- 'NLOHMANN_JSON_VERSION_MINOR': api/macros/nlohmann_json_version_major.md

include/nlohmann/detail/abi_macros.hpp

+45-24
Original file line numberDiff line numberDiff line change
@@ -42,38 +42,59 @@
4242
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
4343
#endif
4444

45-
#define NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch) \
46-
json_v ## major ## _ ## minor ## _ ## patch
47-
#define NLOHMANN_JSON_ABI_PREFIX(major, minor, patch) \
48-
NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch)
49-
50-
#define NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c) a ## b ## c
51-
#define NLOHMANN_JSON_ABI_CONCAT(a, b, c) \
52-
NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c)
53-
54-
#define NLOHMANN_JSON_ABI_STRING \
55-
NLOHMANN_JSON_ABI_CONCAT( \
56-
NLOHMANN_JSON_ABI_PREFIX( \
57-
NLOHMANN_JSON_VERSION_MAJOR, \
58-
NLOHMANN_JSON_VERSION_MINOR, \
59-
NLOHMANN_JSON_VERSION_PATCH), \
60-
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
45+
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
46+
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
47+
#endif
48+
49+
// Construct the namespace ABI tags component
50+
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
51+
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
52+
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
53+
54+
#define NLOHMANN_JSON_ABI_TAGS \
55+
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
56+
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
6157
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
6258

59+
// Construct the namespace version component
60+
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
61+
_v ## major ## _ ## minor ## _ ## patch
62+
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
63+
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
64+
65+
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
66+
#define NLOHMANN_JSON_NAMESPACE_VERSION
67+
#else
68+
#define NLOHMANN_JSON_NAMESPACE_VERSION \
69+
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
70+
NLOHMANN_JSON_VERSION_MINOR, \
71+
NLOHMANN_JSON_VERSION_PATCH)
72+
#endif
73+
74+
// Combine namespace components
75+
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
76+
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
77+
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
78+
6379
#ifndef NLOHMANN_JSON_NAMESPACE
64-
#define NLOHMANN_JSON_NAMESPACE nlohmann::NLOHMANN_JSON_ABI_STRING
80+
#define NLOHMANN_JSON_NAMESPACE \
81+
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
82+
NLOHMANN_JSON_ABI_TAGS, \
83+
NLOHMANN_JSON_NAMESPACE_VERSION)
6584
#endif
6685

6786
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
68-
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
69-
namespace nlohmann \
70-
{ \
71-
inline namespace NLOHMANN_JSON_ABI_STRING \
87+
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
88+
namespace nlohmann \
89+
{ \
90+
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
91+
NLOHMANN_JSON_ABI_TAGS, \
92+
NLOHMANN_JSON_NAMESPACE_VERSION) \
7293
{
7394
#endif
7495

7596
#ifndef NLOHMANN_JSON_NAMESPACE_END
76-
#define NLOHMANN_JSON_NAMESPACE_END \
77-
} /* namespace (abi_string) */ \
78-
} /* namespace nlohmann */
97+
#define NLOHMANN_JSON_NAMESPACE_END \
98+
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \
99+
} // namespace nlohmann
79100
#endif

0 commit comments

Comments
 (0)