From: Ernest Van Hoecke <[email protected]> When jsoncpp is built with C++17, 1.9.7 drops several legacy overloads that C++11 consumers can still link against.
Backport the upstream fix to restore compatibility. Fixes errors such as: | undefined reference to `Json::Value::operator[](char const*)' Patch can be dropped when we move to 1.9.8. Signed-off-by: Ernest Van Hoecke <[email protected]> --- ...akage-when-compiled-with-C-17-1668-1.patch | 368 ++++++++++++++++++ .../recipes-devtools/jsoncpp/jsoncpp_1.9.7.bb | 1 + 2 files changed, 369 insertions(+) create mode 100644 meta-oe/recipes-devtools/jsoncpp/jsoncpp/0001-Fix-C-11-ABI-breakage-when-compiled-with-C-17-1668-1.patch diff --git a/meta-oe/recipes-devtools/jsoncpp/jsoncpp/0001-Fix-C-11-ABI-breakage-when-compiled-with-C-17-1668-1.patch b/meta-oe/recipes-devtools/jsoncpp/jsoncpp/0001-Fix-C-11-ABI-breakage-when-compiled-with-C-17-1668-1.patch new file mode 100644 index 000000000000..887bf14d2af5 --- /dev/null +++ b/meta-oe/recipes-devtools/jsoncpp/jsoncpp/0001-Fix-C-11-ABI-breakage-when-compiled-with-C-17-1668-1.patch @@ -0,0 +1,368 @@ +From c67034e4b4c722579ee15fddb8e4af8f04252b08 Mon Sep 17 00:00:00 2001 +From: Jordan Bayles <[email protected]> +Date: Thu, 9 Apr 2026 10:37:08 -0700 +Subject: [PATCH] Fix C++11 ABI breakage when compiled with C++17 #1668 (#1675) + +When JSONCPP_HAS_STRING_VIEW was defined, the library dropped the +`const char*` and `const String&` overloads for `operator[]`, `get`, +`removeMember`, and `isMember`, breaking ABI compatibility for projects +consuming the library with C++11. + +This change unconditionally declares and defines the legacy overloads +so they are always exported, restoring compatibility. + +This commit completely eliminates the ABI breakage that occurs across +C++ standard boundaries when using `std::string_view`. + +Previously, when the library was built with C++17+, CMake would leak +`JSONCPP_HAS_STRING_VIEW=1` as a PUBLIC definition. A C++11 consumer +would receive this definition, attempt to parse the header, and fail +with compiler errors because `std::string_view` is not available in +their environment. + +Conversely, if the library was built in C++11 (without `string_view` +symbols), a C++17 consumer would naturally define +`JSONCPP_HAS_STRING_VIEW` based on `__cplusplus` inside `value.h`. The +consumer would then call the declared `string_view` methods, resulting +in linker errors because the methods weren't compiled into the library. + +By moving all `std::string_view` overloads directly into `value.h` as +`inline` methods that delegate to the fundamental +`const char*, const char*` methods: +1. The consumer's compiler dictates whether the overloads are visible + (via `__cplusplus >= 201703L`). +2. The consumer compiles the inline wrappers locally, removing any + reliance on the library's exported symbols for `std::string_view`. +3. CMake no longer needs to pollute the consumer's environment with + PUBLIC compile definitions. + +Backported only the library/header changes. Upstream CI and example +test additions are omitted. + +Upstream-Status: Backport [https://github.com/open-source-parsers/jsoncpp/commit/c67034e4b4c722579ee15fddb8e4af8f04252b08] +Signed-off-by: Ernest Van Hoecke <[email protected]> +--- + include/json/value.h | 54 ++++++++++++++++++++---------- + src/lib_json/CMakeLists.txt | 9 ----- + src/lib_json/json_value.cpp | 66 ------------------------------------- + 3 files changed, 36 insertions(+), 93 deletions(-) + +diff --git a/include/json/value.h b/include/json/value.h +index f32f45609365..2007e6b4251d 100644 +--- a/include/json/value.h ++++ b/include/json/value.h +@@ -357,7 +357,8 @@ public: + Value(const StaticString& value); + Value(const String& value); + #ifdef JSONCPP_HAS_STRING_VIEW +- Value(std::string_view value); ++ inline Value(std::string_view value) ++ : Value(value.data(), value.data() + value.length()) {} + #endif + Value(bool value); + Value(std::nullptr_t ptr) = delete; +@@ -405,7 +406,14 @@ public: + /** Get string_view of string-value. + * \return false if !string. (Seg-fault if str is NULL.) + */ +- bool getString(std::string_view* str) const; ++ inline bool getString(std::string_view* str) const { ++ char const* begin; ++ char const* end; ++ if (!getString(&begin, &end)) ++ return false; ++ *str = std::string_view(begin, static_cast<size_t>(end - begin)); ++ return true; ++ } + #endif + Int asInt() const; + UInt asUInt() const; +@@ -496,12 +504,19 @@ public: + #ifdef JSONCPP_HAS_STRING_VIEW + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. +- Value& operator[](std::string_view key); ++ inline Value& operator[](std::string_view key) { ++ return resolveReference(key.data(), key.data() + key.length()); ++ } + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. +- const Value& operator[](std::string_view key) const; +-#else ++ inline const Value& operator[](std::string_view key) const { ++ Value const* found = find(key.data(), key.data() + key.length()); ++ if (!found) ++ return nullSingleton(); ++ return *found; ++ } ++#endif + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. +@@ -516,7 +531,6 @@ public: + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const String& key) const; +-#endif + /** \brief Access an object value by name, create a null member if it does not + * exist. + * +@@ -533,8 +547,10 @@ public: + #ifdef JSONCPP_HAS_STRING_VIEW + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy +- Value get(std::string_view key, const Value& defaultValue) const; +-#else ++ inline Value get(std::string_view key, const Value& defaultValue) const { ++ return get(key.data(), key.data() + key.length(), defaultValue); ++ } ++#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; +@@ -542,7 +558,6 @@ public: + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const String& key, const Value& defaultValue) const; +-#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. +@@ -588,13 +603,14 @@ public: + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + #if JSONCPP_HAS_STRING_VIEW +- void removeMember(std::string_view key); +-#else ++ inline void removeMember(std::string_view key) { ++ removeMember(key.data(), key.data() + key.length(), nullptr); ++ } ++#endif + void removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + void removeMember(const String& key); +-#endif + /** \brief Remove the named map member. + * + * Update 'removed' iff removed. +@@ -602,13 +618,14 @@ public: + * \return true iff removed (no exceptions) + */ + #if JSONCPP_HAS_STRING_VIEW +- bool removeMember(std::string_view key, Value* removed); +-#else ++ inline bool removeMember(std::string_view key, Value* removed) { ++ return removeMember(key.data(), key.data() + key.length(), removed); ++ } ++#endif + bool removeMember(String const& key, Value* removed); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); +-#endif + /// Same as removeMember(String const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. +@@ -622,15 +639,16 @@ public: + #ifdef JSONCPP_HAS_STRING_VIEW + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. +- bool isMember(std::string_view key) const; +-#else ++ inline bool isMember(std::string_view key) const { ++ return isMember(key.data(), key.data() + key.length()); ++ } ++#endif + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const String& key) const; +-#endif + /// Same as isMember(String const& key)const + bool isMember(const char* begin, const char* end) const; + +diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt +index 03e9335525ca..a0695e9eba83 100644 +--- a/src/lib_json/CMakeLists.txt ++++ b/src/lib_json/CMakeLists.txt +@@ -131,9 +131,6 @@ if(BUILD_SHARED_LIBS) + + target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES}) + +- if(JSONCPP_HAS_STRING_VIEW) +- target_compile_definitions(${SHARED_LIB} PUBLIC JSONCPP_HAS_STRING_VIEW=1) +- endif() + + target_include_directories(${SHARED_LIB} PUBLIC + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> +@@ -168,9 +165,6 @@ if(BUILD_STATIC_LIBS) + + target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES}) + +- if(JSONCPP_HAS_STRING_VIEW) +- target_compile_definitions(${STATIC_LIB} PUBLIC JSONCPP_HAS_STRING_VIEW=1) +- endif() + + target_include_directories(${STATIC_LIB} PUBLIC + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> +@@ -198,9 +192,6 @@ if(BUILD_OBJECT_LIBS) + + target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES}) + +- if(JSONCPP_HAS_STRING_VIEW) +- target_compile_definitions(${OBJECT_LIB} PUBLIC JSONCPP_HAS_STRING_VIEW=1) +- endif() + + target_include_directories(${OBJECT_LIB} PUBLIC + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> +diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp +index 74f77896fa7b..a8eb72d6b75f 100644 +--- a/src/lib_json/json_value.cpp ++++ b/src/lib_json/json_value.cpp +@@ -441,14 +441,6 @@ Value::Value(const String& value) { + value.data(), static_cast<unsigned>(value.length())); + } + +-#ifdef JSONCPP_HAS_STRING_VIEW +-Value::Value(std::string_view value) { +- initBasic(stringValue, true); +- value_.string_ = duplicateAndPrefixStringValue( +- value.data(), static_cast<unsigned>(value.length())); +-} +-#endif +- + Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast<char*>(value.c_str()); +@@ -656,21 +648,6 @@ bool Value::getString(char const** begin, char const** end) const { + return true; + } + +-#ifdef JSONCPP_HAS_STRING_VIEW +-bool Value::getString(std::string_view* str) const { +- if (type() != stringValue) +- return false; +- if (value_.string_ == nullptr) +- return false; +- const char* begin; +- unsigned length; +- decodePrefixedString(this->isAllocated(), this->value_.string_, &length, +- &begin); +- *str = std::string_view(begin, length); +- return true; +-} +-#endif +- + String Value::asString() const { + switch (type()) { + case nullValue: +@@ -1190,17 +1167,6 @@ Value* Value::demand(char const* begin, char const* end) { + "objectValue or nullValue"); + return &resolveReference(begin, end); + } +-#ifdef JSONCPP_HAS_STRING_VIEW +-const Value& Value::operator[](std::string_view key) const { +- Value const* found = find(key.data(), key.data() + key.length()); +- if (!found) +- return nullSingleton(); +- return *found; +-} +-Value& Value::operator[](std::string_view key) { +- return resolveReference(key.data(), key.data() + key.length()); +-} +-#else + const Value& Value::operator[](const char* key) const { + Value const* found = find(key, key + strlen(key)); + if (!found) +@@ -1221,7 +1187,6 @@ Value& Value::operator[](const char* key) { + Value& Value::operator[](const String& key) { + return resolveReference(key.data(), key.data() + key.length()); + } +-#endif + + Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +@@ -1261,18 +1226,12 @@ Value Value::get(char const* begin, char const* end, + Value const* found = find(begin, end); + return !found ? defaultValue : *found; + } +-#ifdef JSONCPP_HAS_STRING_VIEW +-Value Value::get(std::string_view key, const Value& defaultValue) const { +- return get(key.data(), key.data() + key.length(), defaultValue); +-} +-#else + Value Value::get(char const* key, Value const& defaultValue) const { + return get(key, key + strlen(key), defaultValue); + } + Value Value::get(String const& key, Value const& defaultValue) const { + return get(key.data(), key.data() + key.length(), defaultValue); + } +-#endif + + bool Value::removeMember(const char* begin, const char* end, Value* removed) { + if (type() != objectValue) { +@@ -1288,31 +1247,13 @@ bool Value::removeMember(const char* begin, const char* end, Value* removed) { + value_.map_->erase(it); + return true; + } +-#ifdef JSONCPP_HAS_STRING_VIEW +-bool Value::removeMember(std::string_view key, Value* removed) { +- return removeMember(key.data(), key.data() + key.length(), removed); +-} +-#else + bool Value::removeMember(const char* key, Value* removed) { + return removeMember(key, key + strlen(key), removed); + } + bool Value::removeMember(String const& key, Value* removed) { + return removeMember(key.data(), key.data() + key.length(), removed); + } +-#endif +- +-#ifdef JSONCPP_HAS_STRING_VIEW +-void Value::removeMember(std::string_view key) { +- JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, +- "in Json::Value::removeMember(): requires objectValue"); +- if (type() == nullValue) +- return; + +- CZString actualKey(key.data(), unsigned(key.length()), +- CZString::noDuplication); +- value_.map_->erase(actualKey); +-} +-#else + void Value::removeMember(const char* key) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::removeMember(): requires objectValue"); +@@ -1323,7 +1264,6 @@ void Value::removeMember(const char* key) { + value_.map_->erase(actualKey); + } + void Value::removeMember(const String& key) { removeMember(key.c_str()); } +-#endif + + bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type() != arrayValue) { +@@ -1353,18 +1293,12 @@ bool Value::isMember(char const* begin, char const* end) const { + Value const* value = find(begin, end); + return nullptr != value; + } +-#ifdef JSONCPP_HAS_STRING_VIEW +-bool Value::isMember(std::string_view key) const { +- return isMember(key.data(), key.data() + key.length()); +-} +-#else + bool Value::isMember(char const* key) const { + return isMember(key, key + strlen(key)); + } + bool Value::isMember(String const& key) const { + return isMember(key.data(), key.data() + key.length()); + } +-#endif + + Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( +-- +2.43.0 diff --git a/meta-oe/recipes-devtools/jsoncpp/jsoncpp_1.9.7.bb b/meta-oe/recipes-devtools/jsoncpp/jsoncpp_1.9.7.bb index 797f093f3349..354f4e91156a 100644 --- a/meta-oe/recipes-devtools/jsoncpp/jsoncpp_1.9.7.bb +++ b/meta-oe/recipes-devtools/jsoncpp/jsoncpp_1.9.7.bb @@ -15,6 +15,7 @@ PE = "1" SRCREV = "3455302847cf1e4671f1d8f5fa953fd46a7b1404" SRC_URI = "git://github.com/open-source-parsers/jsoncpp;branch=master;protocol=https;tag=${PV} \ + file://0001-Fix-C-11-ABI-breakage-when-compiled-with-C-17-1668-1.patch \ file://run-ptest \ " -- 2.43.0
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#236304): https://lists.openembedded.org/g/openembedded-core/message/236304 Mute This Topic: https://lists.openembedded.org/mt/119108287/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
