@@ -10,44 +10,72 @@ else()
1010endif ()
1111
1212# Build one set of {registry, method, overrider} shared libraries plus a test
13- # executable. Each variant compiles the very same sources but with a different
14- # default registry, selected by extra preprocessor definitions (ARGN) applied to
15- # every target so all modules agree (ODR). Targets are suffixed and outputs go
16- # to a per-variant directory so that main.cpp, which locates its sibling
17- # libraries by filename fragment at runtime, never picks up the other variant.
18- function (boost_openmethod_add_dynamic_loading_variant suffix )
13+ # executable. Each variant compiles the very same sources but with two knobs:
14+ #
15+ # owner - which module owns and exports the single shared registry-state
16+ # symbol: "dll" (lib_registry owns it; method/overrider/exe import it)
17+ # or "exe" (the executable owns it; all three libraries import it).
18+ # In the "exe" case the libraries must link *against* the executable
19+ # (reverse linkage); ENABLE_EXPORTS makes the exe produce the import
20+ # library / -rdynamic exports needed for that.
21+ # ARGN - extra preprocessor definitions (e.g. the default registry) applied
22+ # to every target so all modules agree (ODR).
23+ #
24+ # Targets are suffixed and outputs go to a per-variant directory so that
25+ # main.cpp, which locates its sibling libraries by filename fragment at runtime,
26+ # never picks up another variant's libraries.
27+ function (boost_openmethod_add_dynamic_loading_variant suffix owner )
1928 set (extra_defs ${ARGN} )
2029 set (reg boost_openmethod-dl_test_registry${suffix} )
2130 set (meth boost_openmethod-dl_test_method${suffix} )
2231 set (ovr boost_openmethod-dl_test_overrider${suffix} )
2332 set (exe boost_openmethod-test_dynamic_loading${suffix} )
2433 set (outdir "${CMAKE_CURRENT_BINARY_DIR } /dynamic_loading${suffix} " )
2534
26- # lib_registry: exports the registry's static policy state
2735 add_library (${reg} SHARED registry.cpp )
28- target_link_libraries (${reg} PUBLIC Boost::openmethod PRIVATE Boost::dll )
29-
30- # lib_method: exports the speak method; imports registry state from lib_registry
3136 add_library (${meth} SHARED method.cpp )
32- target_link_libraries (${meth} PUBLIC Boost::openmethod ${reg} PRIVATE Boost::dll )
33-
34- # lib_overrider: adds a Dog overrider; imported at runtime via Boost.DLL
3537 add_library (${ovr} SHARED overrider.cpp )
36- target_link_libraries (${ovr} PRIVATE Boost::openmethod ${meth} Boost::dll )
37-
38- # Test executable: links against lib_method (and lib_registry transitively);
39- # dynamically loads lib_overrider at runtime.
4038 add_executable (${exe} main.cpp )
41- target_link_libraries (${exe}
42- PUBLIC Boost::openmethod ${reg} ${meth}
43- PRIVATE Boost::openmethod Boost::unit_test_framework Boost::dll )
44- add_dependencies (${exe} ${reg} ${meth} ${ovr} )
39+
40+ # ENABLE_EXPORTS must be set before any library links against the executable
41+ # (the exe-owned case below), as CMake validates that at the
42+ # target_link_libraries call. The properties are (re)applied to every target
43+ # in the foreach further down.
44+ set_target_properties (${exe} PROPERTIES ENABLE_EXPORTS ON )
45+
46+ if (owner STREQUAL "exe" )
47+ # The executable owns and exports the registry state; the libraries
48+ # import it and therefore link against the executable.
49+ list (APPEND extra_defs REGISTRY_IN_EXE)
50+ target_link_libraries (${reg} PUBLIC Boost::openmethod ${exe} PRIVATE Boost::dll )
51+ target_link_libraries (${meth} PUBLIC Boost::openmethod ${exe} PRIVATE Boost::dll )
52+ target_link_libraries (${ovr} PRIVATE Boost::openmethod ${meth} ${exe} Boost::dll )
53+ target_link_libraries (${exe}
54+ PRIVATE Boost::openmethod Boost::unit_test_framework Boost::dll )
55+ else ()
56+ # lib_registry owns and exports the registry state; method/overrider/exe
57+ # import it. lib_method links lib_registry; the exe links both and loads
58+ # lib_overrider at runtime.
59+ target_link_libraries (${reg} PUBLIC Boost::openmethod PRIVATE Boost::dll )
60+ target_link_libraries (${meth} PUBLIC Boost::openmethod ${reg} PRIVATE Boost::dll )
61+ target_link_libraries (${ovr} PRIVATE Boost::openmethod ${meth} Boost::dll )
62+ target_link_libraries (${exe}
63+ PUBLIC Boost::openmethod ${reg} ${meth}
64+ PRIVATE Boost::openmethod Boost::unit_test_framework Boost::dll )
65+ # The exe links/loads the libraries, so build them first.
66+ add_dependencies (${exe} ${reg} ${meth} ${ovr} )
67+ endif ()
68+ # In the exe-owned case the libraries link against the exe, so the build
69+ # order is the reverse (handled by the link dependency); we must not add
70+ # exe -> libraries here or we'd form a cycle. Either way, building `tests`
71+ # builds every module of the variant.
4572
4673 # Put all of this variant's outputs in one directory so Boost.DLL can locate
4774 # the shared libraries relative to the test executable at runtime.
48- # ENABLE_EXPORTS is required so that symbols from each shared library are
49- # visible to other shared libraries loaded at runtime (e.g. the overrider
50- # can resolve symbols from the method/registry libraries).
75+ # ENABLE_EXPORTS is required so that symbols from each module are visible to
76+ # the shared libraries loaded at runtime (e.g. the overrider can resolve
77+ # symbols from the method/registry/exe, and an exe-owned registry state can
78+ # be imported by the dlopen'd libraries).
5179 # CXX_VISIBILITY_PRESET must be "default" so that the template static
5280 # variables used as the shared registry state are exported with DEFAULT ELF
5381 # visibility. With hidden visibility (as set by BoostRoot.cmake in the
@@ -69,17 +97,20 @@ function(boost_openmethod_add_dynamic_loading_variant suffix)
6997 endforeach ()
7098
7199 if (TARGET tests)
72- add_dependencies (tests ${exe} )
100+ add_dependencies (tests ${reg} ${meth} ${ovr} ${ exe} )
73101 endif ()
74102
75103 boost_openmethod_add_test (${exe} )
76104endfunction ()
77105
78- # Variant 1: the default registry.
79- boost_openmethod_add_dynamic_loading_variant ("" )
80-
81- # Variant 2: indirect_registry (default_registry + indirect_vptr policy),
82- # selected via BOOST_OPENMETHOD_DEFAULT_REGISTRY.
106+ # Four variants: {registry owned by dll, by exe} x {default, indirect} registry.
107+ # indirect_registry (default_registry + indirect_vptr) is selected via
108+ # BOOST_OPENMETHOD_DEFAULT_REGISTRY.
109+ boost_openmethod_add_dynamic_loading_variant ("_default" dll )
110+ boost_openmethod_add_dynamic_loading_variant (
111+ "_indirect" dll
112+ BOOST_OPENMETHOD_DEFAULT_REGISTRY=::boost::openmethod::indirect_registry )
113+ boost_openmethod_add_dynamic_loading_variant ("_exereg_default" exe )
83114boost_openmethod_add_dynamic_loading_variant (
84- "_indirect"
115+ "_exereg_indirect" exe
85116 BOOST_OPENMETHOD_DEFAULT_REGISTRY=::boost::openmethod::indirect_registry )
0 commit comments