Re: llvm & RTTI over shared libraries
Date: Mon, 25 Apr 2022 22:39:48 UTC
• <jbo_at_insane.engineer> wrote on • Date: Mon, 25 Apr 2022 13:01:48 UTC : > I've created a small minimal test case which reproduces the problem (attached). > The key points here are: > - CMake based project consisting of: > - The header-only interface for the plugin and the types (test-interface). > - The main executable that loads the plugin (test-core). > - A plugin implementation (plugin-one). > - Compiles out-of-the-box on FreeBSD 13/stable with both lang/gcc11 and devel/llvm14. > - It uses the exact mechanism I use to load the plugins in my actual application. > > stdout output when compiling with lang/gcc11: > > t is type int > t is type string > done. > > > stdout output when compiling with lang/llvm14: > > could not cast t > could not cast t > done. > > > Unfortunately, I could not yet figure out which compiler/linker flags llvm requires to implement the same behavior as GCC does. I understand that eventually I'd be better of rewriting the necessary parts to eliminate that problem but this is not a quick job. > > Could somebody lend me a hand in figuring out which compiler/linker flags are necessary to get this to work with llvm? The GCC default behavior is technically wrong. GCC allows being configured to do the correct thing --at the cost of ABI mismatches vs. what they originally did. (At least that is how I understand what I read in the code.) To my knowledge LLVM does not allow clang++ being configured to do the wrong thing: it never had the ABI messed up and so did not face the self-compatibility question. (Bug-for-bug clang++ vs. g++ compatibility has not been the major goal.) I have a nearly-minimalist change to your example that makes it result in: # ./test-core t is type_int t is type_string done. under clang. I pasted a diff -ruN in the message later below but that may lead to white space not being fully preserved. (I could send it to you in another form if it proved needed.) Basically I avoid inline definitions of: virtual ~type_base(); virtual ~type_int(); virtual ~type_string(); Also, these are deliberately(!) the first non-inline virtual member functions in the 3 types. Where the implementations are placed controls were the type_info is put for the 3 types. (Not a language definition issue but a fairly common implementation technique.) I also make the place with the implementation be a tiny .so that both test-core and libplugin-one.so are bound to. This makes them use the same type_info definitions instead of having multiple competing ones around, sort of a form of single-definition-rule (unique addresses in the process). With the single definition rule followed, RTTI works just fine. I do warn that this is the first direct adjustment of cmake material that I've ever done. So if anything looks odd for how I did the cmake aspects, do not be surprised. I'm not cmake literate. For reference: # find clang_test_dist_m_m/ -print clang_test_dist_m_m/ clang_test_dist_m_m/plugins clang_test_dist_m_m/plugins/CMakeLists.txt clang_test_dist_m_m/plugins/plugin_one clang_test_dist_m_m/plugins/plugin_one/CMakeLists.txt clang_test_dist_m_m/plugins/plugin_one/plugin.cpp clang_test_dist_m_m/shared_types_impl clang_test_dist_m_m/shared_types_impl/CMakeLists.txt clang_test_dist_m_m/shared_types_impl/types_impl.cpp clang_test_dist_m_m/core clang_test_dist_m_m/core/dlclass.hpp clang_test_dist_m_m/core/CMakeLists.txt clang_test_dist_m_m/core/main.cpp clang_test_dist_m_m/CMakeLists.txt clang_test_dist_m_m/interface clang_test_dist_m_m/interface/plugin.hpp clang_test_dist_m_m/interface/types.hpp clang_test_dist_m_m/interface/CMakeLists.txt where the diff -ruN is . . . diff -ruN clang_test_dist/ clang_test_dist_m_m/ | more diff -ruN clang_test_dist/CMakeLists.txt clang_test_dist_m_m/CMakeLists.txt --- clang_test_dist/CMakeLists.txt 2022-04-19 13:38:59.000000000 -0700 +++ clang_test_dist_m_m/CMakeLists.txt 2022-04-25 12:51:03.448582000 -0700 @@ -5,4 +5,5 @@ add_subdirectory(core) add_subdirectory(interface) +add_subdirectory(shared_types_impl) add_subdirectory(plugins) diff -ruN clang_test_dist/core/CMakeLists.txt clang_test_dist_m_m/core/CMakeLists.txt --- clang_test_dist/core/CMakeLists.txt 2022-04-19 13:38:59.000000000 -0700 +++ clang_test_dist_m_m/core/CMakeLists.txt 2022-04-25 13:18:52.539921000 -0700 @@ -19,9 +19,12 @@ PRIVATE test-interface dl + PUBLIC + shared-types-impl ) add_dependencies( ${TARGET} + shared-types-impl plugin-one ) diff -ruN clang_test_dist/interface/types.hpp clang_test_dist_m_m/interface/types.hpp --- clang_test_dist/interface/types.hpp 2022-04-19 13:38:59.000000000 -0700 +++ clang_test_dist_m_m/interface/types.hpp 2022-04-25 14:48:52.534159000 -0700 @@ -7,18 +7,20 @@ struct type_base { - virtual ~type_base() = default; + virtual ~type_base(); }; struct type_int : type_base { + virtual ~type_int(); int data; }; struct type_string : type_base { + virtual ~type_string(); std::string data; }; diff -ruN clang_test_dist/plugins/plugin_one/CMakeLists.txt clang_test_dist_m_m/plugins/plugin_one/CMakeLists.txt --- clang_test_dist/plugins/plugin_one/CMakeLists.txt 2022-04-19 13:38:59.000000000 -0700 +++ clang_test_dist_m_m/plugins/plugin_one/CMakeLists.txt 2022-04-25 13:19:20.188778000 -0700 @@ -12,3 +12,14 @@ PRIVATE plugin.cpp ) + +target_link_libraries( + ${TARGET} + PUBLIC + shared-types-impl +) + +add_dependencies( + ${TARGET} + shared-types-impl +) diff -ruN clang_test_dist/shared_types_impl/CMakeLists.txt clang_test_dist_m_m/shared_types_impl/CMakeLists.txt --- clang_test_dist/shared_types_impl/CMakeLists.txt 1969-12-31 16:00:00.000000000 -0800 +++ clang_test_dist_m_m/shared_types_impl/CMakeLists.txt 2022-04-25 12:55:29.760985000 -0700 @@ -0,0 +1,15 @@ +set(TARGET shared-types-impl) +add_library(${TARGET} SHARED) + +target_compile_features( + ${TARGET} + PRIVATE + cxx_std_20 +) + +target_sources( + ${TARGET} + PRIVATE + types_impl.cpp +) + diff -ruN clang_test_dist/shared_types_impl/types_impl.cpp clang_test_dist_m_m/shared_types_impl/types_impl.cpp --- clang_test_dist/shared_types_impl/types_impl.cpp 1969-12-31 16:00:00.000000000 -0800 +++ clang_test_dist_m_m/shared_types_impl/types_impl.cpp 2022-04-25 14:49:23.599440000 -0700 @@ -0,0 +1,5 @@ +#include "../interface/types.hpp" + +interface::type_base::~type_base() {} +interface::type_int::~type_int() {} +interface::type_string::~type_string() {} That is all there is to the changes. === Mark Millard marklmi at yahoo.com