Skip to content

Commit 13b052c

Browse files
committed
support dynamic loading on Windows
1 parent 3f31b7d commit 13b052c

File tree

10 files changed

+106
-67
lines changed

10 files changed

+106
-67
lines changed

CLAUDE.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,24 @@ When adding static variables to policies:
276276
277277
This pattern ensures static variables can be properly decorated with dllexport/dllimport for shared library usage.
278278
279+
5. **Add an `id()` function** to the policy's `fn<Registry>` class returning the address of the first byte of the state:
280+
```cpp
281+
static auto id() -> const void* {
282+
return &static_::variable_name;
283+
}
284+
```
285+
For policies with two possible state variables (e.g., `vptr_vector`), use `if constexpr` to select the active one:
286+
```cpp
287+
static auto id() -> const void* {
288+
if constexpr (Registry::has_indirect_vptr) {
289+
return &static_::vptr_vector_indirect_vptrs;
290+
} else {
291+
return &static_::vptr_vector_vptrs;
292+
}
293+
}
294+
```
295+
For `stderr_output`, which inherits its state, use the class name: `&fn::os`.
296+
279297
**Example from fast_perfect_hash**:
280298
```cpp
281299
// In detail namespace

doc/modules/ROOT/examples/shared_libs/CMakeLists.txt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ add_compile_definitions(BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS)
2424
# ------------------------------------------------------------------------------
2525
# dynamic loading, direct virtual_ptrs
2626

27-
if(UNIX)
28-
message(STATUS "Boost.OpenMethod: disabling symbol exports on POSIX (hidden visibility)")
29-
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
30-
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
31-
endif()
32-
3327
add_executable(boost_openmethod-dynamic dynamic_main.cpp)
3428
set_target_properties(boost_openmethod-dynamic PROPERTIES ENABLE_EXPORTS ON)
3529
target_link_libraries(boost_openmethod-dynamic Boost::openmethod Boost::dll)

include/boost/openmethod/core.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ struct use_class_aux<Registry, mp11::mp_list<Class, Bases...>>
360360
}
361361

362362
// coverity[uninit] - zero-initialized static storage
363-
Registry::st.classes.push_back(*this);
363+
Registry::static_::st.classes.push_back(*this);
364364
}
365365

366366
void resolve_type_ids() {
@@ -370,7 +370,7 @@ struct use_class_aux<Registry, mp11::mp_list<Class, Bases...>>
370370
}
371371

372372
~use_class_aux() {
373-
Registry::st.classes.remove(*this);
373+
Registry::static_::st.classes.remove(*this);
374374
}
375375
};
376376

@@ -2420,7 +2420,7 @@ method<Id, ReturnType(Parameters...), Registry>::method() {
24202420

24212421
// zero-initalized static variable
24222422
// coverity[uninit_use]
2423-
Registry::st.methods.push_back(*this);
2423+
Registry::static_::st.methods.push_back(*this);
24242424
}
24252425

24262426
template<
@@ -2440,7 +2440,7 @@ void method<Id, ReturnType(Parameters...), Registry>::resolve_type_ids() {
24402440
template<
24412441
typename Id, typename... Parameters, typename ReturnType, class Registry>
24422442
method<Id, ReturnType(Parameters...), Registry>::~method() {
2443-
Registry::st.methods.remove(*this);
2443+
Registry::static_::st.methods.remove(*this);
24442444
}
24452445

24462446
// -----------------------------------------------------------------------------

include/boost/openmethod/initialize.hpp

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -61,30 +61,26 @@ struct aggregate_reports<mp11::mp_list<Reports...>, mp11::mp_list<>, Void> {
6161

6262
// Policy initialization helpers
6363

64-
// Detect if a policy fn has an initialize function with the expected signature
65-
template<typename PolicyFn, typename Context, typename Options, typename = void>
66-
struct has_initialize : std::false_type {};
67-
6864
#if defined(_MSC_VER) && _MSC_VER <= 1950
69-
template<typename PolicyFn, typename Context, typename Options>
70-
struct has_initialize<
71-
PolicyFn, Context, Options,
72-
std::void_t<decltype(&PolicyFn::template initialize<Context, Options>)>>
73-
: std::true_type {};
65+
template<typename, class, class...>
66+
struct has_initialize_aux : std::false_type {};
67+
68+
template<class T, class... Args>
69+
struct has_initialize_aux<
70+
std::void_t<decltype(&T::template initialize<std::decay_t<Args>...>)>,
71+
T, Args...> : std::true_type {};
72+
73+
template<class T, class... Args>
74+
constexpr bool has_initialize = has_initialize_aux<void, T, Args...>::value;
7475
#else
75-
template<typename PolicyFn, typename Context, typename Options>
76-
struct has_initialize<
77-
PolicyFn, Context, Options,
78-
std::void_t<decltype(PolicyFn::initialize(
79-
std::declval<const Context&>(), std::declval<const Options&>()))>>
80-
: std::true_type {};
76+
BOOST_OPENMETHOD_DETAIL_HAS_STATIC_FN(has_initialize, initialize);
8177
#endif
8278

8379
// Call initialize on a single policy if it has the function
8480
template<typename Policy, typename Registry, typename Context, typename Options>
8581
void initialize_policy(const Context& ctx, const Options& options) {
8682
using PolicyFn = typename Policy::template fn<Registry>;
87-
if constexpr (has_initialize<PolicyFn, Context, Options>::value) {
83+
if constexpr (has_initialize<PolicyFn, const Context&, const Options&>) {
8884
PolicyFn::initialize(ctx, options);
8985
}
9086
}
@@ -585,7 +581,7 @@ template<class... Options>
585581
void registry<Policies...>::compiler<Options...>::initialize() {
586582
compile();
587583
install_global_tables();
588-
registry<Policies...>::st.initialized = true;
584+
registry<Policies...>::static_::st.initialized = true;
589585
}
590586

591587
#ifdef _MSC_VER
@@ -654,7 +650,7 @@ void registry<Policies...>::compiler<Options...>::augment_classes() {
654650
// The standard does not guarantee that there is exactly one
655651
// type_info object per class. However, it guarantees that the
656652
// type_index for a class has a unique value.
657-
for (auto& cr : registry::st.classes) {
653+
for (auto& cr : registry::static_::st.classes) {
658654
if constexpr (has_deferred_static_rtti) {
659655
static_cast<deferred_class_info&>(cr).resolve_type_ids();
660656
}
@@ -691,7 +687,7 @@ void registry<Policies...>::compiler<Options...>::augment_classes() {
691687
// All known classes now have exactly one associated class_* in the
692688
// map. Collect the bases.
693689

694-
for (auto& cr : registry::st.classes) {
690+
for (auto& cr : registry::static_::st.classes) {
695691
auto rtc = class_map[rtti::type_index(cr.type)];
696692

697693
for (auto& base : range{cr.first_base, cr.last_base}) {
@@ -820,14 +816,14 @@ void registry<Policies...>::compiler<Options...>::augment_methods() {
820816
using namespace policies;
821817
using namespace detail;
822818

823-
methods.resize(registry::st.methods.size());
819+
methods.resize(registry::static_::st.methods.size());
824820

825821
++tr << "Methods:\n";
826822
indent _(tr);
827823

828824
auto meth_iter = methods.begin();
829825

830-
for (auto& meth_info : registry::st.methods) {
826+
for (auto& meth_info : registry::static_::st.methods) {
831827
if constexpr (has_deferred_static_rtti) {
832828
static_cast<deferred_method_info&>(meth_info).resolve_type_ids();
833829
}
@@ -1530,7 +1526,7 @@ void registry<Policies...>::compiler<Options...>::write_global_data() {
15301526

15311527
detail::initialize_policies<registry>::fn(*this, options);
15321528

1533-
new_dispatch_data.swap(st.dispatch_data);
1529+
new_dispatch_data.swap(static_::st.dispatch_data);
15341530
}
15351531

15361532
template<class... Policies>
@@ -1749,14 +1745,7 @@ inline auto initialize(Options&&... options) {
17491745

17501746
namespace detail {
17511747

1752-
template<typename, class Policy, class... Options>
1753-
struct has_finalize_aux : std::false_type {};
1754-
1755-
template<class Policy, class... Options>
1756-
struct has_finalize_aux<
1757-
std::void_t<decltype(Policy::finalize(
1758-
std::declval<std::tuple<Options...>>()))>,
1759-
Policy, Options...> : std::true_type {};
1748+
BOOST_OPENMETHOD_DETAIL_HAS_STATIC_FN(has_finalize, finalize);
17601749

17611750
} // namespace detail
17621751

@@ -1766,13 +1755,13 @@ auto registry<Policies...>::finalize(Options... opts) -> void {
17661755
std::tuple<Options...> options(opts...); // gcc-8 doesn't like CTAD here
17671756
mp11::mp_for_each<policy_list>([&options](auto policy) {
17681757
using fn = typename decltype(policy)::template fn<registry>;
1769-
if constexpr (detail::has_finalize_aux<void, fn, Options...>::value) {
1758+
if constexpr (detail::has_finalize<fn, const std::tuple<Options...>&>) {
17701759
fn::finalize(options);
17711760
}
17721761
});
17731762

1774-
st.dispatch_data.clear();
1775-
st.initialized = false;
1763+
static_::dispatch_data.clear();
1764+
static_::initialized = false;
17761765
}
17771766

17781767
//! Release resources held by registry.

include/boost/openmethod/policies/default_error_handler.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ struct default_error_handler : error_handler {
114114
return prev ? prev : default_handler;
115115
}
116116

117+
static auto id() -> const void* {
118+
return &static_::handler;
119+
}
120+
117121
//! The default error handler function.
118122
//!
119123
//! @param error A variant containing the error.

include/boost/openmethod/policies/fast_perfect_hash.hpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ struct fast_perfect_hash : type_hash {
8686
//!
8787
//! @tparam Registry The registry containing this policy
8888
template<class Registry>
89-
class fn : detail::static_hash_fn<detail::hash_fn, Registry> {
89+
class fn {
90+
using static_ = detail::static_hash_fn<detail::hash_fn, Registry>;
9091
static void check(std::size_t index, type_id type);
9192

9293
template<class InitializeContext, class... Options>
@@ -124,7 +125,7 @@ struct fast_perfect_hash : type_hash {
124125
//!
125126
//! @return A pair containing the minimum and maximum hash values.
126127
static auto hash_range() -> std::pair<std::size_t, std::size_t> {
127-
return std::pair{hash_fn.min_value, hash_fn.max_value};
128+
return std::pair{static_::hash_fn.min_value, static_::hash_fn.max_value};
128129
}
129130

130131
//! Hash a type id
@@ -142,7 +143,7 @@ struct fast_perfect_hash : type_hash {
142143
//! @return The hash value
143144
BOOST_FORCEINLINE
144145
static auto hash(type_id type) -> std::size_t {
145-
auto index = hash_fn(type);
146+
auto index = static_::hash_fn(type);
146147

147148
if constexpr (Registry::has_runtime_checks) {
148149
check(index, type);
@@ -160,6 +161,10 @@ struct fast_perfect_hash : type_hash {
160161
static auto finalize(const std::tuple<Options...>&) -> void {
161162
detail::fast_perfect_hash_control<Registry>.clear();
162163
}
164+
165+
static auto id() -> const void* {
166+
return &static_::hash_fn;
167+
}
163168
};
164169
};
165170

@@ -187,10 +192,10 @@ void fast_perfect_hash::fn<Registry>::initialize_aux(
187192
std::uniform_int_distribution<std::size_t> uniform_dist;
188193

189194
for (std::size_t pass = 0; pass < 5; ++pass, ++M) {
190-
hash_fn.shift = 8 * sizeof(type_id) - M;
195+
static_::hash_fn.shift = 8 * sizeof(type_id) - M;
191196
auto hash_size = 1 << M;
192-
hash_fn.min_value = (std::numeric_limits<std::size_t>::max)();
193-
hash_fn.max_value = (std::numeric_limits<std::size_t>::min)();
197+
static_::hash_fn.min_value = (std::numeric_limits<std::size_t>::max)();
198+
static_::hash_fn.max_value = (std::numeric_limits<std::size_t>::min)();
194199

195200
if constexpr (InitializeContext::template has_option<trace>) {
196201
ctx.tr << " trying with M = " << M << ", " << hash_size
@@ -205,16 +210,16 @@ void fast_perfect_hash::fn<Registry>::initialize_aux(
205210
buckets.begin(), buckets.end(), type_id(detail::uintptr_max));
206211
++attempts;
207212
++total_attempts;
208-
hash_fn.mult = uniform_dist(rnd) | 1;
213+
static_::hash_fn.mult = uniform_dist(rnd) | 1;
209214

210215
for (auto iter = ctx.classes_begin(); iter != ctx.classes_end();
211216
++iter) {
212217
for (auto type_iter = iter->type_id_begin();
213218
type_iter != iter->type_id_end(); ++type_iter) {
214219
auto type = *type_iter;
215-
auto index = hash_fn(type);
216-
hash_fn.min_value = (std::min)(hash_fn.min_value, index);
217-
hash_fn.max_value = (std::max)(hash_fn.max_value, index);
220+
auto index = static_::hash_fn(type);
221+
static_::hash_fn.min_value = (std::min)(static_::hash_fn.min_value, index);
222+
static_::hash_fn.max_value = (std::max)(static_::hash_fn.max_value, index);
218223

219224
if (detail::uintptr(buckets[index]) !=
220225
detail::uintptr_max) {
@@ -226,9 +231,9 @@ void fast_perfect_hash::fn<Registry>::initialize_aux(
226231
}
227232

228233
if constexpr (InitializeContext::template has_option<trace>) {
229-
ctx.tr << " found " << hash_fn.mult << " after "
234+
ctx.tr << " found " << static_::hash_fn.mult << " after "
230235
<< total_attempts << " attempts; span = ["
231-
<< hash_fn.min_value << ", " << hash_fn.max_value
236+
<< static_::hash_fn.min_value << ", " << static_::hash_fn.max_value
232237
<< "]\n";
233238
}
234239

@@ -251,7 +256,7 @@ void fast_perfect_hash::fn<Registry>::initialize_aux(
251256

252257
template<class Registry>
253258
void fast_perfect_hash::fn<Registry>::check(std::size_t index, type_id type) {
254-
if (index < hash_fn.min_value || index > hash_fn.max_value ||
259+
if (index < static_::hash_fn.min_value || index > static_::hash_fn.max_value ||
255260
detail::fast_perfect_hash_control<Registry>[index] != type) {
256261

257262
if constexpr (Registry::has_error_handler) {

include/boost/openmethod/policies/stderr_output.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ struct stderr_output : output {
2828
struct fn : detail::static_os<detail::ostderr, Registry> {
2929
//! A @ref LightweightOuputStream.
3030
// static detail::ostderr os; // now inherited from static_os
31+
32+
static auto id() -> const void* {
33+
return &fn::os;
34+
}
3135
};
3236
};
3337

include/boost/openmethod/policies/vptr_map.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ class vptr_map : public vptr {
120120
static auto finalize(const std::tuple<Options...>&) -> void {
121121
static_::vptrs.clear();
122122
}
123+
124+
static auto id() -> const void* {
125+
return &static_::vptrs;
126+
}
123127
};
124128
};
125129

include/boost/openmethod/policies/vptr_vector.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,14 @@ struct vptr_vector : vptr {
187187
static_::vptr_vector_vptrs.clear();
188188
}
189189
}
190+
191+
static auto id() -> const void* {
192+
if constexpr (Registry::has_indirect_vptr) {
193+
return &static_::vptr_vector_indirect_vptrs;
194+
} else {
195+
return &static_::vptr_vector_vptrs;
196+
}
197+
}
190198
};
191199
};
192200

0 commit comments

Comments
 (0)