Date: Mon, 25 Apr 2022 15:39:48 -0700 From: Mark Millard <marklmi@yahoo.com> To: jbo@insane.engineer, FreeBSD Hackers <freebsd-hackers@freebsd.org> Cc: joerg@bec.de Subject: Re: llvm & RTTI over shared libraries Message-ID: <079B1A26-DA8B-4158-8FD4-28EE1374CF1F@yahoo.com> References: <079B1A26-DA8B-4158-8FD4-28EE1374CF1F.ref@yahoo.com>
next in thread | previous in thread | raw e-mail | index | archive | help
=E2=80=A2 <jbo_at_insane.engineer> wrote on =E2=80=A2 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. >=20 > stdout output when compiling with lang/gcc11: >=20 > t is type int > t is type string > done. >=20 >=20 > stdout output when compiling with lang/llvm14: >=20 > could not cast t > could not cast t > done. >=20 >=20 > 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. >=20 > 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 @@ =20 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 ) =20 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 @@ =20 struct type_base { - virtual ~type_base() =3D default; + virtual ~type_base(); }; =20 struct type_int : type_base { + virtual ~type_int(); int data; }; =20 struct type_string : type_base { + virtual ~type_string(); std::string data; }; =20 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. =3D=3D=3D Mark Millard marklmi at yahoo.com
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?079B1A26-DA8B-4158-8FD4-28EE1374CF1F>