Detect libstdc++ ABI incompatibility to allow compiling using clang again.

Currently, this is only relevant when using LevelDB, and a newer version
of libstdc++, which uses a different C++ ABI which clang does not yet support.

A symptom of the problem are unexpected linking failures, caused by undefined
symbols, while other symbols from the same library do not cause errors.

The solution is a workaround, that avoids using the offending symbols, at the
cost of reduced functionality. As this currently only affects the text of an
error message, the impact is minor.
This commit is contained in:
Rogier 2016-06-28 11:08:39 +02:00
parent ee0903ea78
commit 9a9b83e638
6 changed files with 40 additions and 0 deletions

View File

@ -250,6 +250,24 @@ if(NOT USE_SQLITE3 AND NOT USE_POSTGRESQL AND NOT USE_LEVELDB AND NOT USE_REDIS)
message(SEND_ERROR "No database backends are configured, or none could be found") message(SEND_ERROR "No database backends are configured, or none could be found")
endif(NOT USE_SQLITE3 AND NOT USE_POSTGRESQL AND NOT USE_LEVELDB AND NOT USE_REDIS) endif(NOT USE_SQLITE3 AND NOT USE_POSTGRESQL AND NOT USE_LEVELDB AND NOT USE_REDIS)
# Determine whether there is a libstdc++ ABI incompatibility.
# Currently only needed for leveldb.
set(CPP_ABI_STDSTRING_OK 1)
if(USE_LEVELDB)
# try_compile does not remove the temporary build directory, so put it in CMakeFiles...
# Also: use absolute paths; cmake chokes on relative paths :-(
# AARGH! try_compile does not understand the INCLUDE_DIRECTORIES directive.
try_compile(CPP_ABI_STDSTRING_RESULT
"${CMAKE_HOME_DIRECTORY}/CMakeFiles/CMakeTmp/abi-stdstring-test"
"${CMAKE_HOME_DIRECTORY}/cmake/abi-stdstring.cpp"
LINK_LIBRARIES ${LEVELDB_LIBRARY})
#INCLUDE_DIRECTORIES ${LEVELDB_INCLUDE_DIR}
if(NOT CPP_ABI_STDSTRING_RESULT)
set(CPP_ABI_STDSTRING_OK 0)
message(STATUS "C++ library ABI mismatch for std::string. Enabling workaround - this may affect functionality")
endif(NOT CPP_ABI_STDSTRING_RESULT)
endif(USE_LEVELDB)
include_directories( include_directories(
"${PROJECT_BINARY_DIR}" "${PROJECT_BINARY_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}"

View File

@ -11,6 +11,8 @@
- Fixed failure to compile with gcc 6 - Fixed failure to compile with gcc 6
- Fixed failure to compile when rpm is not installed - Fixed failure to compile when rpm is not installed
(e.g. on non-rpm systems...) (e.g. on non-rpm systems...)
- Workaround to allow compilation with clang when using leveldb.
This is broken due to libstdc++ ABI incompatibility
[31 May 2016] [31 May 2016]
Features: Features:
- Support for postgresql backend added - Support for postgresql backend added

View File

@ -285,6 +285,7 @@ EXIT /B %$EXITVAL%
SET $LINE=!$LINE:@VERSION_MINOR@=%$VERSION_MINOR%! SET $LINE=!$LINE:@VERSION_MINOR@=%$VERSION_MINOR%!
SET $LINE=!$LINE:@PACKAGING_FLAT@=%$PACKAGING_FLAT%! SET $LINE=!$LINE:@PACKAGING_FLAT@=%$PACKAGING_FLAT%!
SET $LINE=!$LINE:@INSTALL_PREFIX@=%$INSTALL_PREFIX%! SET $LINE=!$LINE:@INSTALL_PREFIX@=%$INSTALL_PREFIX%!
SET $LINE=!$LINE:@CPP_ABI_STDSTRING_OK@=1!
ECHO %$INDENT%%$LINE% >> %$OUTPUT% ECHO %$INDENT%%$LINE% >> %$OUTPUT%
ENDLOCAL ENDLOCAL

View File

@ -21,5 +21,7 @@
#define PACKAGING_FLAT @PACKAGING_FLAT@ #define PACKAGING_FLAT @PACKAGING_FLAT@
#define INSTALL_PREFIX "@INSTALL_PREFIX@" #define INSTALL_PREFIX "@INSTALL_PREFIX@"
#define CPP_ABI_STDSTRING_OK @CPP_ABI_STDSTRING_OK@
#endif #endif

7
cmake/abi-stdstring.cpp Normal file
View File

@ -0,0 +1,7 @@
#include <string>
#include <leveldb/status.h>
int main(void) {
leveldb::Status status;
std::string str = status.ToString();
return 0;
}

View File

@ -1,6 +1,7 @@
#include "db-leveldb.h" #include "db-leveldb.h"
#include <stdexcept> #include <stdexcept>
#include <sstream> #include <sstream>
#include "build_config.h"
#include "types.h" #include "types.h"
inline int64_t stoi64(const std::string &s) { inline int64_t stoi64(const std::string &s) {
@ -26,7 +27,16 @@ DBLevelDB::DBLevelDB(const std::string &mapdir) :
options.create_if_missing = false; options.create_if_missing = false;
leveldb::Status status = leveldb::DB::Open(options, mapdir + "map.db", &m_db); leveldb::Status status = leveldb::DB::Open(options, mapdir + "map.db", &m_db);
if(!status.ok()) if(!status.ok())
#if CPP_ABI_STDSTRING_OK
throw std::runtime_error(std::string("Failed to open Database: ") + status.ToString()); throw std::runtime_error(std::string("Failed to open Database: ") + status.ToString());
#else
throw std::runtime_error(std::string("Failed to open Database: ") +
( status.ok() ? "Ok (??? how is this possible ???"")" // "" is needed to prevent interpretation as trigraph -shudder-
: status.IsNotFound() ? "NotFound"
: status.IsCorruption() ? "Corruption"
: status.IsIOError() ? "IOError"
: "Cannot determine error type - could be NotSupported or InvalidArgument or something else"));
#endif
} }
DBLevelDB::~DBLevelDB() { DBLevelDB::~DBLevelDB() {