diff --git a/base/containers/init_chain.h b/base/containers/init_chain.h index 4c25d321..5e19ab67 100644 --- a/base/containers/init_chain.h +++ b/base/containers/init_chain.h @@ -7,9 +7,24 @@ #include #include +// The chain's root is a function-local static in a class template, so every +// shared object that instantiates the template gets its own root when it is +// compiled with -fvisibility=hidden (as a component build is): an Option +// registered in one .so is then invisible to VisitAll in another. Default +// visibility makes the root one symbol per process (ELF unique binding), so +// all objects share one chain. An instantiation is only as visible as its +// template argument, so every item type (OptionBase, Feature) carries the same +// annotation. PE has no such binding; there base has to be linked as a DLL for +// the same guarantee. +#if defined(__GNUC__) || defined(__clang__) +#define BASE_SHARED_REGISTRY __attribute__((visibility("default"))) +#else +#define BASE_SHARED_REGISTRY +#endif + namespace base { template -class InitChain { +class BASE_SHARED_REGISTRY InitChain { public: constexpr InitChain() noexcept = default; diff --git a/base/feature.h b/base/feature.h index 60ee0be7..355ad90f 100644 --- a/base/feature.h +++ b/base/feature.h @@ -8,7 +8,7 @@ #include namespace base { -struct BASE_EXPORT Feature : InitChain { +struct BASE_EXPORT BASE_SHARED_REGISTRY Feature : InitChain { enum class Flags : arch_types::u32 { kNone = 1 << 0, kHidden = 1 << 1, //< If this flag isn't set, assume public. diff --git a/base/option.h b/base/option.h index 0c49626d..6c84a083 100644 --- a/base/option.h +++ b/base/option.h @@ -67,7 +67,7 @@ inline bool ParseOption(const char* text, T& out) { // Type-erased handle so every Option, whatever T is, threads onto one // self-registering list (the same InitChain trick base::Feature uses). Walk // them with OptionBase::VisitAll, or let InitOptionsFromEnv() drive them. -class BASE_EXPORT OptionBase : public InitChain { +class BASE_EXPORT BASE_SHARED_REGISTRY OptionBase : public InitChain { public: OptionBase(const char* opt_name, const char* env_var, const char* description) : name_(opt_name), env_(env_var), desc_(description) {