Repository navigation
Export the implementations of the interfaces that are exported - #463
Conversation
The library builds with hidden visibility, and a polymorphic class emits its typeinfo where its first out-of-line virtual is defined, which is inside the library. Without REXLIB_API on the class that typeinfo stays hidden, so a consumer that reaches for RTTI on one of these finds nothing to link against. Their interfaces, executor and image_reader_provider, already carry it; the implementations did not, which makes each hierarchy exported halfway. Ordinary use never notices, since it needs no RTTI, but anything building a type map over the boundary does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A class carrying the dll interface may not repeat it on its members: MSVC rejects that with C2487, which the first commit hit on every member of the four. An exported class here does not repeat it — completion and image_reader_provider both leave their members bare — so these follow. The std members a dll-interface class holds then warn with C4251, and REXLIB_STD_MEMBER_INTERFACE silences each one where it sits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
oierlauzi
left a comment
There was a problem hiding this comment.
This should not be needed, as the constructor and destructor of these classes has REXLIB_API. If there is an obscure reason for having it in the class declaration, remove it from the constructor, destructor and other member methods. Also add REXLIB_STD_MEMBER to the implementation pointer to avoid MSVC warnings
|
Both of those are in b877466, which landed about half a minute before the On whether the class attribute is needed at all — it is, and the reason is An exported constructor and destructor let a caller build one and destroy it, That is what broke, and it broke at load time rather than at build time:
Measured on
The symbol is emitted either way, which is why
|
|



Four classes carry
REXLIB_APIon their methods but not on the class itself,so their typeinfo never leaves the shared object:
thread_pool_executorandsynchronous_executordirect_image_reader_providerandcaching_image_reader_providerTheir interfaces,
executorandimage_reader_provider, are bothREXLIB_API. The implementations are not, which leaves each hierarchyexported halfway.
Why it has never shown
The library builds with hidden visibility, and a polymorphic class emits its
typeinfo in the translation unit that defines its first out-of-line virtual —
inside the library. Without
REXLIB_APIon the class, that symbol isHIDDENand nothing outside can link against it.
Ordinary C++ use never asks for it: constructing one of these, calling through
it, destroying it, all go through the methods, and those are exported one by
one. It only bites something that reaches for RTTI across the boundary, which
is what a language binding does — pybind11 calls
typeid()on every type itregisters.
It surfaced in gigabit-clowns/rexlib-python#157, as a load-time failure of the
extension with no build warning ahead of it:
which demangles to
typeinfo for rexlib::thread_pool_executor.The change, and the evidence
One keyword on each of the four classes. Measured on
thread_pool_executor.cpp, compiled with the same-fvisibility=hidden -fvisibility-inlines-hiddenthe build uses:_ZTIN6rexlib20thread_pool_executorEHIDDENDEFAULTThe symbol was emitted either way; what changed is whether it crosses the
boundary.
image_sourceandimage_batch_sourceare left alone deliberately. Neitheris polymorphic, so their typeinfo is a weak symbol any consumer emits for
itself, and nothing is missing.
The per-method
REXLIB_APIon these classes is now redundant but left inplace:
image_read_format_managerandimage_reader_providerboth alreadycarry the class attribute and repeat it on members, so removing it here would
be a larger diff against a convention this does not settle.
🤖 Generated with Claude Code