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) {