From 365be8fb52b0d2ae1521f615142cc473bd047af1 Mon Sep 17 00:00:00 2001 From: Bruno Postle Date: Thu, 4 Jun 2026 22:31:02 +0100 Subject: [PATCH] Support RocksDB shared library and new unique_ptr DB::Open API Some distributions (e.g. Fedora) ship only a shared RocksDB that exports RocksDB::rocksdb-shared rather than RocksDB::rocksdb. The CMake target selection now falls back to the shared target when the static one is absent. Newer RocksDB also changed DB::Open and DB::OpenForReadOnly to take std::unique_ptr* instead of DB**. IfcFile.cpp uses SFINAE tag dispatch to build against both old and new APIs without version detection. --- cmake/CMakeLists.txt | 10 +++++++--- src/ifcparse/IfcFile.cpp | 30 ++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 917e66d192..baafc5c459 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -258,10 +258,14 @@ if(WITH_ROCKSDB) set(ROCKSDB_LIBRARIES "IFCOPENSHELL_RocksDB") target_compile_definitions(IFCOPENSHELL_RocksDB INTERFACE IFOPSH_WITH_ROCKSDB) set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_ROCKSDB) - # Shared binaries for `rocksdb` only support limited API (only `c.h`), but we use `db.h` API. - # So rocksdb supported only as a static library. # See https://github.com/facebook/rocksdb/issues/981. - target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb) + if(TARGET RocksDB::rocksdb) + target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb) + elseif(TARGET RocksDB::rocksdb-shared) + target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb-shared) + else() + message(FATAL_ERROR "RocksDB found but neither RocksDB::rocksdb nor RocksDB::rocksdb-shared target exists") + endif() if(WITH_ZSTD) # @todo do we actually need the zstd include dir or rather just pass diff --git a/src/ifcparse/IfcFile.cpp b/src/ifcparse/IfcFile.cpp index 9e26b24442..06521d5565 100644 --- a/src/ifcparse/IfcFile.cpp +++ b/src/ifcparse/IfcFile.cpp @@ -7,6 +7,8 @@ #endif #include +#include +#include #include #include @@ -410,6 +412,26 @@ IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::assert_existance(s } namespace { +#ifdef IFOPSH_WITH_ROCKSDB + // Newer RocksDB releases (e.g. the one shipped by Fedora rawhide) changed + // DB::Open / DB::OpenForReadOnly to take a std::unique_ptr* and removed + // the raw DB** overloads. These helpers select whichever signature the + // installed RocksDB exposes, so the code builds against both old and new + // headers. The int/long tag prefers the unique_ptr form when both exist. + template + auto rocksdb_open(Fn&& open, rocksdb::DB*& db, int) + -> decltype(open(std::declval*>())) { + std::unique_ptr owned; + auto status = open(&owned); + db = owned.release(); + return status; + } + template + auto rocksdb_open(Fn&& open, rocksdb::DB*& db, long) + -> decltype(open(std::declval())) { + return open(&db); + } +#endif rocksdb::DB* init_db(const std::string& filepath, bool readonly) { rocksdb::DB* db = nullptr; #ifdef IFOPSH_WITH_ROCKSDB @@ -446,9 +468,13 @@ namespace { rocksdb::Status status; if (readonly) { - status = rocksdb::DB::OpenForReadOnly(options, filepath, &db); + status = rocksdb_open([&](auto* dbptr) -> decltype(rocksdb::DB::OpenForReadOnly(options, filepath, dbptr)) { + return rocksdb::DB::OpenForReadOnly(options, filepath, dbptr); + }, db, 0); } else { - status = rocksdb::DB::Open(options, filepath, &db); + status = rocksdb_open([&](auto* dbptr) -> decltype(rocksdb::DB::Open(options, filepath, dbptr)) { + return rocksdb::DB::Open(options, filepath, dbptr); + }, db, 0); } if (!status.ok()) { return nullptr;