Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion base/containers/init_chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,24 @@
#include <base/arch.h>
#include <base/compiler.h>

// 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 <typename TItem>
class InitChain {
class BASE_SHARED_REGISTRY InitChain {
public:
constexpr InitChain() noexcept = default;

Expand Down
2 changes: 1 addition & 1 deletion base/feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <base/containers/init_chain.h>

namespace base {
struct BASE_EXPORT Feature : InitChain<Feature> {
struct BASE_EXPORT BASE_SHARED_REGISTRY Feature : InitChain<Feature> {
enum class Flags : arch_types::u32 {
kNone = 1 << 0,
kHidden = 1 << 1, //< If this flag isn't set, assume public.
Expand Down
2 changes: 1 addition & 1 deletion base/option.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ inline bool ParseOption(const char* text, T& out) {
// Type-erased handle so every Option<T>, 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<OptionBase> {
class BASE_EXPORT BASE_SHARED_REGISTRY OptionBase : public InitChain<OptionBase> {
public:
OptionBase(const char* opt_name, const char* env_var, const char* description)
: name_(opt_name), env_(env_var), desc_(description) {
Expand Down