Skip to content

Commit 21b3afb

Browse files
committed
add indirect test
1 parent 8ff3764 commit 21b3afb

4 files changed

Lines changed: 164 additions & 124 deletions

File tree

test/dynamic_loading/CMakeLists.txt

Lines changed: 68 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,69 +9,77 @@ else()
99
return()
1010
endif()
1111

12-
# lib_registry: exports the default registry's static policy state
13-
add_library(boost_openmethod-dl_test_registry SHARED registry.cpp)
14-
target_link_libraries(
15-
boost_openmethod-dl_test_registry
16-
PUBLIC Boost::openmethod PRIVATE Boost::dll)
12+
# 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)
19+
set(extra_defs ${ARGN})
20+
set(reg boost_openmethod-dl_test_registry${suffix})
21+
set(meth boost_openmethod-dl_test_method${suffix})
22+
set(ovr boost_openmethod-dl_test_overrider${suffix})
23+
set(exe boost_openmethod-test_dynamic_loading${suffix})
24+
set(outdir "${CMAKE_CURRENT_BINARY_DIR}/dynamic_loading${suffix}")
1725

18-
# lib_method: exports the speak method; imports registry state from lib_registry
19-
add_library(boost_openmethod-dl_test_method SHARED method.cpp)
20-
target_link_libraries(
21-
boost_openmethod-dl_test_method
22-
PUBLIC Boost::openmethod boost_openmethod-dl_test_registry PRIVATE Boost::dll)
26+
# lib_registry: exports the registry's static policy state
27+
add_library(${reg} SHARED registry.cpp)
28+
target_link_libraries(${reg} PUBLIC Boost::openmethod PRIVATE Boost::dll)
2329

24-
# lib_overrider: adds a Dog overrider; imported at runtime via Boost.DLL
25-
add_library(boost_openmethod-dl_test_overrider SHARED overrider.cpp)
26-
target_link_libraries(
27-
boost_openmethod-dl_test_overrider
28-
PRIVATE Boost::openmethod boost_openmethod-dl_test_method Boost::dll)
30+
# lib_method: exports the speak method; imports registry state from lib_registry
31+
add_library(${meth} SHARED method.cpp)
32+
target_link_libraries(${meth} PUBLIC Boost::openmethod ${reg} PRIVATE Boost::dll)
2933

30-
# Test executable: links against lib_method (and lib_registry transitively);
31-
# dynamically loads lib_overrider at runtime.
32-
add_executable(
33-
boost_openmethod-test_dynamic_loading main.cpp)
34-
target_link_libraries(
35-
boost_openmethod-test_dynamic_loading
36-
PUBLIC
37-
Boost::openmethod boost_openmethod-dl_test_registry
38-
Boost::openmethod boost_openmethod-dl_test_method
39-
PRIVATE Boost::openmethod Boost::unit_test_framework Boost::dll)
40-
add_dependencies(
41-
boost_openmethod-test_dynamic_loading
42-
boost_openmethod-dl_test_registry
43-
boost_openmethod-dl_test_method
44-
boost_openmethod-dl_test_overrider)
34+
# lib_overrider: adds a Dog overrider; imported at runtime via Boost.DLL
35+
add_library(${ovr} SHARED overrider.cpp)
36+
target_link_libraries(${ovr} PRIVATE Boost::openmethod ${meth} Boost::dll)
4537

46-
# Put all outputs in the same directory so Boost.DLL can locate the shared
47-
# 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. boost_openmethod-dl_test_overrider
50-
# can resolve symbols from boost_openmethod-dl_test_method/boost_openmethod-dl_test_registry).
51-
# CXX_VISIBILITY_PRESET must be "default" so that the template static variables
52-
# used as the shared registry state (policy statics) are exported with DEFAULT
53-
# ELF visibility. With hidden visibility (as set by BoostRoot.cmake in the
54-
# super-project build) they become UNIQUE HIDDEN and are not deduplicated by
55-
# the dynamic linker, breaking cross-DSO state sharing.
56-
foreach(
57-
target
58-
boost_openmethod-dl_test_registry
59-
boost_openmethod-dl_test_method
60-
boost_openmethod-dl_test_overrider
61-
boost_openmethod-test_dynamic_loading)
62-
set_target_properties(
63-
${target}
64-
PROPERTIES
65-
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
66-
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
67-
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
68-
ENABLE_EXPORTS ON
69-
CXX_VISIBILITY_PRESET default
70-
VISIBILITY_INLINES_HIDDEN OFF)
71-
endforeach()
38+
# Test executable: links against lib_method (and lib_registry transitively);
39+
# dynamically loads lib_overrider at runtime.
40+
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})
7245

73-
if (TARGET tests)
74-
add_dependencies(tests boost_openmethod-test_dynamic_loading)
75-
endif()
46+
# Put all of this variant's outputs in one directory so Boost.DLL can locate
47+
# 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).
51+
# CXX_VISIBILITY_PRESET must be "default" so that the template static
52+
# variables used as the shared registry state are exported with DEFAULT ELF
53+
# visibility. With hidden visibility (as set by BoostRoot.cmake in the
54+
# super-project build) they become UNIQUE HIDDEN and are not deduplicated by
55+
# the dynamic linker, breaking cross-DSO state sharing.
56+
foreach(target ${reg} ${meth} ${ovr} ${exe})
57+
set_target_properties(
58+
${target}
59+
PROPERTIES
60+
RUNTIME_OUTPUT_DIRECTORY "${outdir}"
61+
LIBRARY_OUTPUT_DIRECTORY "${outdir}"
62+
ARCHIVE_OUTPUT_DIRECTORY "${outdir}"
63+
ENABLE_EXPORTS ON
64+
CXX_VISIBILITY_PRESET default
65+
VISIBILITY_INLINES_HIDDEN OFF)
66+
if (extra_defs)
67+
target_compile_definitions(${target} PRIVATE ${extra_defs})
68+
endif()
69+
endforeach()
70+
71+
if (TARGET tests)
72+
add_dependencies(tests ${exe})
73+
endif()
74+
75+
boost_openmethod_add_test(${exe})
76+
endfunction()
77+
78+
# Variant 1: the default registry.
79+
boost_openmethod_add_dynamic_loading_variant("")
7680

77-
boost_openmethod_add_test(boost_openmethod-test_dynamic_loading)
81+
# Variant 2: indirect_registry (default_registry + indirect_vptr policy),
82+
# selected via BOOST_OPENMETHOD_DEFAULT_REGISTRY.
83+
boost_openmethod_add_dynamic_loading_variant(
84+
"_indirect"
85+
BOOST_OPENMETHOD_DEFAULT_REGISTRY=::boost::openmethod::indirect_registry)

test/dynamic_loading/Jamfile

Lines changed: 78 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -39,63 +39,84 @@ local RDYNAMIC =
3939
# linker deduplicates them across DSOs. MSVC ignores this property.
4040
local VISIBILITY = <local-visibility>global ;
4141

42-
# lib_registry: owns and exports the default registry's static policy state.
43-
# registry.cpp defines EXPORT_REGISTRY and INCLUDED_FROM itself.
44-
lib boost_openmethod-dl_test_registry
45-
: registry.cpp
46-
: <link>shared
47-
$(VISIBILITY)
48-
<library>/boost/dll//boost_dll/<warnings>off
49-
<location-prefix>dynamic_loading.test
50-
;
42+
# Build one set of {registry, method, overrider} shared libraries plus a test
43+
# executable. Each variant compiles the very same sources but with a different
44+
# default registry, selected by extra requirements (e.g. a <define>) applied to
45+
# every target so all modules agree (ODR). Targets are suffixed and outputs go
46+
# to a per-variant <location-prefix> so that main.cpp, which locates its sibling
47+
# libraries by filename fragment at runtime, never picks up the other variant.
48+
rule make-variant ( suffix : extra-req * )
49+
{
50+
# lib_registry: owns and exports the registry's static policy state.
51+
# registry.cpp defines EXPORT_REGISTRY and INCLUDED_FROM itself.
52+
lib boost_openmethod-dl_test_registry$(suffix)
53+
: registry.cpp
54+
: <link>shared
55+
$(VISIBILITY)
56+
$(extra-req)
57+
<library>/boost/dll//boost_dll/<warnings>off
58+
<location-prefix>dynamic_loading$(suffix).test
59+
;
5160

52-
# lib_method: exports the speak() open-method; imports registry from
53-
# lib_registry. method.cpp defines EXPORT_METHOD and INCLUDED_FROM itself.
54-
lib boost_openmethod-dl_test_method
55-
: method.cpp
56-
: <link>shared
57-
$(VISIBILITY)
58-
<library>/boost/dll//boost_dll/<warnings>off
59-
<library>boost_openmethod-dl_test_registry
60-
<location-prefix>dynamic_loading.test
61-
;
61+
# lib_method: exports the speak() open-method; imports registry from
62+
# lib_registry. method.cpp defines EXPORT_METHOD and INCLUDED_FROM itself.
63+
lib boost_openmethod-dl_test_method$(suffix)
64+
: method.cpp
65+
: <link>shared
66+
$(VISIBILITY)
67+
$(extra-req)
68+
<library>/boost/dll//boost_dll/<warnings>off
69+
<library>boost_openmethod-dl_test_registry$(suffix)
70+
<location-prefix>dynamic_loading$(suffix).test
71+
;
6272

63-
# lib_overrider: adds the Dog overrider; dynamically loaded at runtime.
64-
# overrider.cpp defines INCLUDED_FROM itself.
65-
lib boost_openmethod-dl_test_overrider
66-
: overrider.cpp
67-
: <link>shared
68-
$(VISIBILITY)
69-
<library>/boost/dll//boost_dll/<warnings>off
70-
<library>boost_openmethod-dl_test_method
71-
<target-os>windows:<library>boost_openmethod-dl_test_registry
72-
<target-os>cygwin:<library>boost_openmethod-dl_test_registry
73-
<location-prefix>dynamic_loading.test
74-
;
73+
# lib_overrider: adds the Dog overrider; dynamically loaded at runtime.
74+
# overrider.cpp defines INCLUDED_FROM itself.
75+
lib boost_openmethod-dl_test_overrider$(suffix)
76+
: overrider.cpp
77+
: <link>shared
78+
$(VISIBILITY)
79+
$(extra-req)
80+
<library>/boost/dll//boost_dll/<warnings>off
81+
<library>boost_openmethod-dl_test_method$(suffix)
82+
<target-os>windows:<library>boost_openmethod-dl_test_registry$(suffix)
83+
<target-os>cygwin:<library>boost_openmethod-dl_test_registry$(suffix)
84+
<location-prefix>dynamic_loading$(suffix).test
85+
;
7586

76-
# Test executable:
77-
# sources (linked) : main.cpp, lib_registry, unit_test_framework, boost_dll
78-
# runtime-loaded : lib_method, lib_overrider
79-
# All shared libraries are placed alongside the test executable via
80-
# <location-prefix>dynamic_loading.test, so main.cpp can find them by scanning
81-
# dll::program_location().parent_path() on all platforms.
82-
run main.cpp
83-
boost_openmethod-dl_test_registry
84-
/boost/test//boost_unit_test_framework/<warnings>off
85-
/boost/dll//boost_dll/<warnings>off
86-
:
87-
:
88-
: <link>shared
89-
$(RDYNAMIC)
90-
$(VISIBILITY)
91-
<library>/boost/filesystem//boost_filesystem/<warnings>off
92-
<target-os>linux:<linkflags>"-ldl"
93-
<target-os>freebsd:<linkflags>"-ldl"
94-
<target-os>android:<linkflags>"-ldl"
95-
<target-os>windows:<library>boost_openmethod-dl_test_registry
96-
<target-os>windows:<library>boost_openmethod-dl_test_method
97-
<target-os>cygwin:<library>boost_openmethod-dl_test_method
98-
<dependency>boost_openmethod-dl_test_method
99-
<dependency>boost_openmethod-dl_test_overrider
100-
: dynamic_loading
101-
;
87+
# Test executable:
88+
# sources (linked) : main.cpp, lib_registry, unit_test_framework, boost_dll
89+
# runtime-loaded : lib_method, lib_overrider
90+
# All shared libraries are placed alongside the test executable via
91+
# <location-prefix>dynamic_loading$(suffix).test, so main.cpp can find them
92+
# by scanning dll::program_location().parent_path() on all platforms.
93+
run main.cpp
94+
boost_openmethod-dl_test_registry$(suffix)
95+
/boost/test//boost_unit_test_framework/<warnings>off
96+
/boost/dll//boost_dll/<warnings>off
97+
:
98+
:
99+
: <link>shared
100+
$(RDYNAMIC)
101+
$(VISIBILITY)
102+
$(extra-req)
103+
<library>/boost/filesystem//boost_filesystem/<warnings>off
104+
<target-os>linux:<linkflags>"-ldl"
105+
<target-os>freebsd:<linkflags>"-ldl"
106+
<target-os>android:<linkflags>"-ldl"
107+
<target-os>windows:<library>boost_openmethod-dl_test_registry$(suffix)
108+
<target-os>windows:<library>boost_openmethod-dl_test_method$(suffix)
109+
<target-os>cygwin:<library>boost_openmethod-dl_test_method$(suffix)
110+
<dependency>boost_openmethod-dl_test_method$(suffix)
111+
<dependency>boost_openmethod-dl_test_overrider$(suffix)
112+
: dynamic_loading$(suffix)
113+
;
114+
}
115+
116+
# Variant 1: the default registry.
117+
make-variant "" : ;
118+
119+
# Variant 2: indirect_registry (default_registry + indirect_vptr policy),
120+
# selected via BOOST_OPENMETHOD_DEFAULT_REGISTRY.
121+
make-variant _indirect
122+
: <define>BOOST_OPENMETHOD_DEFAULT_REGISTRY=::boost::openmethod::indirect_registry ;

test/dynamic_loading/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ bool same_ids(const void** ids1, const void** ids2) {
4444

4545
int diffs = 0;
4646

47-
mp11::mp_for_each<default_registry::policy_list>([&](auto p) {
47+
mp11::mp_for_each<test_registry::policy_list>([&](auto p) {
4848
using P = decltype(p);
4949

50-
if constexpr (detail::has_id<default_registry::policy<P>>) {
50+
if constexpr (detail::has_id<test_registry::policy<P>>) {
5151
BOOST_TEST_MESSAGE(
5252
setw(60) << boost::core::demangle(typeid(P).name()) << ": "
5353
<< *ids1 << " " << *ids2);

test/dynamic_loading/registry.hpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,30 @@
1818

1919
#include <boost/openmethod/default_registry.hpp>
2020

21+
// The registry under test. The build selects the variant by defining
22+
// BOOST_OPENMETHOD_DEFAULT_REGISTRY on the command line (e.g. to
23+
// ::boost::openmethod::indirect_registry); otherwise fall back to
24+
// default_registry, matching core.hpp's own default. This must be set before
25+
// the .cpp files include core.hpp.
26+
#ifndef BOOST_OPENMETHOD_DEFAULT_REGISTRY
27+
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY ::boost::openmethod::default_registry
28+
#endif
29+
30+
using test_registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY;
31+
2132
static auto get_ids() -> const void** {
2233
using namespace boost::openmethod;
2334
namespace mp11 = boost::mp11;
2435

25-
constexpr auto n_policies = mp11::mp_size<default_registry::policy_list>::value;
26-
static const void* ids[1 + n_policies + 1] = {default_registry::id()};
36+
constexpr auto n_policies = mp11::mp_size<test_registry::policy_list>::value;
37+
static const void* ids[1 + n_policies + 1] = {test_registry::id()};
2738
std::size_t i = 1;
2839

29-
mp11::mp_for_each<default_registry::policy_list>([&](auto p) {
40+
mp11::mp_for_each<test_registry::policy_list>([&](auto p) {
3041
using P = decltype(p);
3142

32-
if constexpr (detail::has_id<default_registry::policy<P>>) {
33-
ids[i++] = default_registry::policy<P>::id();
43+
if constexpr (detail::has_id<test_registry::policy<P>>) {
44+
ids[i++] = test_registry::policy<P>::id();
3445
}
3546
});
3647

0 commit comments

Comments
 (0)