Skip site navigation (1)Skip section navigation (2)
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>