Skip to content

Commit

Permalink
Export globals and make them weak on static builds so they work acros…
Browse files Browse the repository at this point in the history
…s SOs.
  • Loading branch information
mosra committed Sep 1, 2019
1 parent 16b3f1e commit 1bef569
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 10 deletions.
6 changes: 6 additions & 0 deletions doc/corrade-changelog.dox
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ namespace Corrade {

@subsection corrade-changelog-latest-changes Changes and improvements

- Global state used by @ref PluginManager::Manager, @ref Utility::Debug and
@ref Utility::Resource internals is no longer duplicated when Corrade is
built statically and linked to more than one dynamic library or executable.
Currently that holds only for Linux and macOS, Windows support will come
next.

@subsubsection corrade-changelog-latest-changes-containers Containers library

- It's now possible to create @ref Containers::ScopeGuard without a handle
Expand Down
27 changes: 23 additions & 4 deletions src/Corrade/PluginManager/AbstractManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,12 @@ struct AbstractManager::State {

const int AbstractManager::Version = CORRADE_PLUGIN_VERSION;

#ifndef CORRADE_BUILD_STATIC
/* (Of course) can't be in an unnamed namespace in order to export it below */
namespace {
#endif

struct {
struct Globals {
/* A linked list of static plugins. Managed using utilities from
Containers/Implementation/RawForwardList.h, look there for more info. */
Implementation::StaticPlugin* staticPlugins;
Expand All @@ -147,17 +150,33 @@ struct {
errors because std::pair is trying to copy itself. So calm down and
ignore those few delete calls. Please. Last tried: March 2018. */
std::map<std::string, AbstractManager::Plugin*>* plugins;
};

#if defined(CORRADE_BUILD_STATIC) && !defined(CORRADE_TARGET_WINDOWS)
/* On static builds that get linked to multiple shared libraries and then used
in a single app we want to ensure there's just one global symbol. On Linux
it's apparently enough to just export, macOS needs the weak attribute.
Windows not handled yet, as it needs a workaround using DllMain() and
GetProcAddress(). */
CORRADE_VISIBILITY_EXPORT
#ifdef __GNUC__
__attribute__((weak))
#else
/* uh oh? the test will fail, probably */
#endif
#endif
/* The value of this variable is guaranteed to be zero-filled even before any
static plugin initializers are executed, which means we don't hit any static
initialization order fiasco. */
} globals{nullptr, nullptr};
Globals globals{nullptr, nullptr};

#ifndef CORRADE_BUILD_STATIC
}
#endif

static_assert(std::is_pod<Implementation::StaticPlugin>::value,
"static plugins shouldn't cause any global initialization / finalization to happen on their own");

}

#ifndef DOXYGEN_GENERATING_OUTPUT
void AbstractManager::importStaticPlugin(int version, Implementation::StaticPlugin& plugin) {
CORRADE_ASSERT(version == Version,
Expand Down
32 changes: 28 additions & 4 deletions src/Corrade/Utility/Debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,47 @@ HANDLE streamOutputHandle(const std::ostream* s) {
}
#endif

#ifdef CORRADE_BUILD_MULTITHREADED
CORRADE_THREAD_LOCAL
}

#ifndef CORRADE_BUILD_STATIC
/* (Of course) can't be in an unnamed namespace in order to export it below */
namespace {
#endif
struct {

struct DebugGlobals {
std::ostream *output, *warningOutput, *errorOutput;
#if !defined(CORRADE_TARGET_WINDOWS) ||defined(CORRADE_UTILITY_USE_ANSI_COLORS)
Debug::Color color;
bool colorBold;
#endif
} debugGlobals {
};

#ifdef CORRADE_BUILD_MULTITHREADED
CORRADE_THREAD_LOCAL
#endif
#if defined(CORRADE_BUILD_STATIC) && !defined(CORRADE_TARGET_WINDOWS)
/* On static builds that get linked to multiple shared libraries and then used
in a single app we want to ensure there's just one global symbol. On Linux
it's apparently enough to just export, macOS needs the weak attribute.
Windows not handled yet, as it needs a workaround using DllMain() and
GetProcAddress(). */
CORRADE_VISIBILITY_EXPORT
#ifdef __GNUC__
__attribute__((weak))
#else
/* uh oh? the test will fail, probably */
#endif
#endif
DebugGlobals debugGlobals{
&std::cout, &std::cerr, &std::cerr,
#if !defined(CORRADE_TARGET_WINDOWS) ||defined(CORRADE_UTILITY_USE_ANSI_COLORS)
Debug::Color::Default, false
#endif
};

#ifndef CORRADE_BUILD_STATIC
}
#endif

template<Debug::Color c, bool bold> Debug::Modifier Debug::colorInternal() {
return [](Debug& debug) {
Expand Down
23 changes: 21 additions & 2 deletions src/Corrade/Utility/Resource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@

namespace Corrade { namespace Utility {

#ifndef CORRADE_BUILD_STATIC
/* (Of course) can't be in an unnamed namespace in order to export it below */
namespace {
#endif

struct {
struct ResourceGlobals {
/* A linked list of resources. Managed using utilities from
Containers/Implementation/RawForwardList.h, look there for more info. */
Implementation::ResourceGroup* groups;
Expand All @@ -56,13 +59,29 @@ struct {
Resource::overrideGroup() and stores a pointer to a function-local
static variable from there. */
std::map<std::string, std::string>* overrideGroups;
};

#if defined(CORRADE_BUILD_STATIC) && !defined(CORRADE_TARGET_WINDOWS)
/* On static builds that get linked to multiple shared libraries and then used
in a single app we want to ensure there's just one global symbol. On Linux
it's apparently enough to just export, macOS needs the weak attribute.
Windows not handled yet, as it needs a workaround using DllMain() and
GetProcAddress(). */
CORRADE_VISIBILITY_EXPORT
#ifdef __GNUC__
__attribute__((weak))
#else
/* uh oh? the test will fail, probably */
#endif
#endif
/* The value of this variable is guaranteed to be zero-filled even before any
resource initializers are executed, which means we don't hit any static
initialization order fiasco. */
} resourceGlobals{nullptr, nullptr};
ResourceGlobals resourceGlobals{nullptr, nullptr};

#ifndef CORRADE_BUILD_STATIC
}
#endif

struct Resource::OverrideData {
const Configuration conf;
Expand Down

0 comments on commit 1bef569

Please sign in to comment.