diff --git a/CMakeLists.txt b/CMakeLists.txt index 48b06611c..93b523d9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,6 +186,7 @@ else() set(ON_EXCEPT_EMSCRIPTEN ON) endif() option(BUILD_STATIC_PIC "Build static libraries and plugins with position-independent code" ${ON_EXCEPT_EMSCRIPTEN}) +cmake_dependent_option(BUILD_STATIC_UNIQUE_GLOBALS "Build static libraries with globals unique across shared libraries" ${ON_EXCEPT_EMSCRIPTEN} "BUILD_STATIC" OFF) option(BUILD_PLUGINS_STATIC "Build static plugins (default are dynamic)" OFF) option(BUILD_TESTS "Build unit tests" OFF) cmake_dependent_option(BUILD_GL_TESTS "Build unit tests for OpenGL code" OFF "BUILD_TESTS;TARGET_GL" OFF) @@ -219,6 +220,9 @@ endif() if(BUILD_STATIC) set(MAGNUM_BUILD_STATIC 1) + if(BUILD_STATIC_UNIQUE_GLOBALS) + set(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS 1) + endif() endif() # Check dependencies diff --git a/doc/building.dox b/doc/building.dox index 77419cd74..b3ad556c7 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -630,6 +630,11 @@ Options controlling the build: code. Enabled by default when building static libraries, disable if you don't need this feature. On @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten" this option is always off. +- `BUILD_STATIC_UNIQUE_GLOBALS` --- Build static libraries in a way that + keeps their globals unique even across different shared libraries. Enabled + by default for static builds. May introduce additional overhead on some + platforms, disable if you will only link static libraries to one final + executable and won't use any dynamic plugins. - `BUILD_PLUGINS_STATIC` --- Build plugins as static. By default, plugins are built as dynamic. Independent of the `BUILD_STATIC` option to allow having static libraries with dynamic plugins and vice versa. diff --git a/doc/changelog.dox b/doc/changelog.dox index 9940c4fd1..5ae3e9647 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -317,6 +317,8 @@ See also: executable location where possible and use hardcoded paths only if explicitly specified. See @ref Trade::AbstractImporter::pluginSearchPaths() for more information. +- Added an ability to disable unique globals across shared libraries using + @ref MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS on static builds that don't need it @subsubsection changelog-latest-changes-audio Audio library diff --git a/doc/cmake.dox b/doc/cmake.dox index 5617decf9..ad8d51df6 100644 --- a/doc/cmake.dox +++ b/doc/cmake.dox @@ -308,6 +308,9 @@ are also available as preprocessor variables if including included - `MAGNUM_BUILD_STATIC` --- Defined if compiled as static libraries. Default are shared libraries. +- `MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS` --- Defined if static libraries keep + their globals unique even across different shared libraries. Enabled by + default for static builds. - `MAGNUM_TARGET_GL` --- Defined if compiled with OpenGL interoperability enabled - `MAGNUM_TARGET_GLES` --- Defined if compiled for OpenGL ES diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 30161db04..5b096339f 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -126,6 +126,8 @@ # MAGNUM_BUILD_DEPRECATED - Defined if compiled with deprecated APIs # included # MAGNUM_BUILD_STATIC - Defined if compiled as static libraries +# MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS - Defined if static libraries keep the +# globals unique even across different shared libraries # MAGNUM_TARGET_GL - Defined if compiled with OpenGL interop # MAGNUM_TARGET_GLES - Defined if compiled for OpenGL ES # MAGNUM_TARGET_GLES2 - Defined if compiled for OpenGL ES 2.0 @@ -249,6 +251,7 @@ string(REGEX REPLACE "\n" ";" _magnumConfigure "${_magnumConfigure}") set(_magnumFlags BUILD_DEPRECATED BUILD_STATIC + BUILD_STATIC_UNIQUE_GLOBALS TARGET_GL TARGET_GLES TARGET_GLES2 diff --git a/src/Magnum/Audio/Context.cpp b/src/Magnum/Audio/Context.cpp index d30523c24..a60a2f9e9 100644 --- a/src/Magnum/Audio/Context.cpp +++ b/src/Magnum/Audio/Context.cpp @@ -41,7 +41,7 @@ #include "Magnum/Audio/Extensions.h" -#if defined(CORRADE_TARGET_WINDOWS) && defined(MAGNUM_BUILD_STATIC) && !defined(CORRADE_TARGET_WINDOWS_RT) +#if defined(CORRADE_TARGET_WINDOWS) && defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) && !defined(CORRADE_TARGET_WINDOWS_RT) #include "Magnum/Implementation/WindowsWeakSymbol.h" #endif @@ -119,7 +119,7 @@ std::vector Context::deviceSpecifierStrings() { return list; } -#if !defined(MAGNUM_BUILD_STATIC) || defined(CORRADE_TARGET_WINDOWS) +#if !defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) || defined(CORRADE_TARGET_WINDOWS) /* (Of course) can't be in an unnamed namespace in order to export it below (except for Windows, where we do extern "C" so this doesn't matter) */ namespace { @@ -127,8 +127,9 @@ namespace { /* Unlike GL, this isn't thread-local. Would need to implement ALC_EXT_thread_local_context first */ -#if !defined(MAGNUM_BUILD_STATIC) || (defined(MAGNUM_BUILD_STATIC) && !defined(CORRADE_TARGET_WINDOWS)) -#ifdef MAGNUM_BUILD_STATIC +/* What the hell is going on here with the #ifdefs?! */ +#if !defined(MAGNUM_BUILD_STATIC) || !defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) || (defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) && !defined(CORRADE_TARGET_WINDOWS)) +#ifdef MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS /* 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. @@ -152,7 +153,7 @@ extern "C" { } #endif -#if !defined(MAGNUM_BUILD_STATIC) || defined(CORRADE_TARGET_WINDOWS) +#if !defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) || defined(CORRADE_TARGET_WINDOWS) } #endif @@ -161,7 +162,7 @@ extern "C" { pick up the same symbol of the final exe independently of the DLL it was called from. To avoid #ifdef hell in code below, the currentContext is redefined to return a value from this uniqueness-ensuring function. */ -#if defined(CORRADE_TARGET_WINDOWS) && defined(MAGNUM_BUILD_STATIC) && !defined(CORRADE_TARGET_WINDOWS_RT) +#if defined(CORRADE_TARGET_WINDOWS) && defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) && !defined(CORRADE_TARGET_WINDOWS_RT) namespace { Context*& windowsCurrentContext() { diff --git a/src/Magnum/Audio/Test/GlobalStateAcrossLibrariesALTest.cpp b/src/Magnum/Audio/Test/GlobalStateAcrossLibrariesALTest.cpp index b6d96ee08..6150be227 100644 --- a/src/Magnum/Audio/Test/GlobalStateAcrossLibrariesALTest.cpp +++ b/src/Magnum/Audio/Test/GlobalStateAcrossLibrariesALTest.cpp @@ -42,9 +42,19 @@ GlobalStateAcrossLibrariesALTest::GlobalStateAcrossLibrariesALTest() { } void GlobalStateAcrossLibrariesALTest::test() { + #if defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) && !defined(MAGNUM_BUILD_STATIC) + CORRADE_VERIFY(!"MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS enabled but MAGNUM_BUILD_STATIC not"); + #endif + Context context; CORRADE_VERIFY(Context::hasCurrent()); - CORRADE_COMPARE(currentContextInALibrary(), &context); + + { + #ifndef MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS + CORRADE_EXPECT_FAIL("MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS not enabled."); + #endif + CORRADE_COMPARE(currentContextInALibrary(), &context); + } } }}}} diff --git a/src/Magnum/GL/Context.cpp b/src/Magnum/GL/Context.cpp index 88284d14a..aabef1582 100644 --- a/src/Magnum/GL/Context.cpp +++ b/src/Magnum/GL/Context.cpp @@ -65,7 +65,7 @@ #include "Magnum/GL/Implementation/TransformFeedbackState.h" #endif -#if defined(CORRADE_TARGET_WINDOWS) && defined(MAGNUM_BUILD_STATIC) && !defined(CORRADE_TARGET_WINDOWS_RT) +#if defined(CORRADE_TARGET_WINDOWS) && defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) && !defined(CORRADE_TARGET_WINDOWS_RT) #include "Magnum/Implementation/WindowsWeakSymbol.h" #endif @@ -500,7 +500,7 @@ Containers::ArrayView Extension::extensions(Version version) { CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } -#if !defined(MAGNUM_BUILD_STATIC) || defined(CORRADE_TARGET_WINDOWS) +#if !defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) || defined(CORRADE_TARGET_WINDOWS) /* (Of course) can't be in an unnamed namespace in order to export it below (except for Windows, where we do extern "C" so this doesn't matter) */ namespace { @@ -509,7 +509,7 @@ namespace { #ifdef CORRADE_BUILD_MULTITHREADED CORRADE_THREAD_LOCAL #endif -#if defined(MAGNUM_BUILD_STATIC) && !defined(CORRADE_TARGET_WINDOWS) +#if defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) && !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. @@ -523,7 +523,7 @@ CORRADE_VISIBILITY_EXPORT #endif Context* currentContext = nullptr; -#if !defined(MAGNUM_BUILD_STATIC) || defined(CORRADE_TARGET_WINDOWS) +#if !defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) || defined(CORRADE_TARGET_WINDOWS) } #endif @@ -535,7 +535,7 @@ Context* currentContext = nullptr; pick up the same symbol of the final exe independently of the DLL it was called from. To avoid #ifdef hell in code below, the currentContext is redefined to return a value from this uniqueness-ensuring function. */ -#if defined(CORRADE_TARGET_WINDOWS) && defined(MAGNUM_BUILD_STATIC) && !defined(CORRADE_TARGET_WINDOWS_RT) +#if defined(CORRADE_TARGET_WINDOWS) && defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) && !defined(CORRADE_TARGET_WINDOWS_RT) /* Clang-CL complains that the function has a return type incompatible with C. I don't care, I only need an unmangled name to look up later at runtime. */ #ifdef CORRADE_TARGET_CLANG_CL diff --git a/src/Magnum/GL/Test/GlobalStateAcrossLibrariesGLTest.cpp b/src/Magnum/GL/Test/GlobalStateAcrossLibrariesGLTest.cpp index 70b488a53..faa32bd81 100644 --- a/src/Magnum/GL/Test/GlobalStateAcrossLibrariesGLTest.cpp +++ b/src/Magnum/GL/Test/GlobalStateAcrossLibrariesGLTest.cpp @@ -41,8 +41,18 @@ GlobalStateAcrossLibrariesGLTest::GlobalStateAcrossLibrariesGLTest() { } void GlobalStateAcrossLibrariesGLTest::test() { + #if defined(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS) && !defined(MAGNUM_BUILD_STATIC) + CORRADE_VERIFY(!"MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS enabled but MAGNUM_BUILD_STATIC not"); + #endif + CORRADE_VERIFY(GL::Context::hasCurrent()); - CORRADE_COMPARE(currentContextInALibrary(), &GL::Context::current()); + + { + #ifndef MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS + CORRADE_EXPECT_FAIL("MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS not enabled."); + #endif + CORRADE_COMPARE(currentContextInALibrary(), &GL::Context::current()); + } } }}}} diff --git a/src/Magnum/Magnum.h b/src/Magnum/Magnum.h index e2e24b0db..136d426b8 100644 --- a/src/Magnum/Magnum.h +++ b/src/Magnum/Magnum.h @@ -66,6 +66,16 @@ Defined if built as static libraries. Default are shared libraries. #define MAGNUM_BUILD_STATIC #undef MAGNUM_BUILD_STATIC +/** +@brief Static library build with globals unique across shared libraries +@m_since_latest + +Enabled by default in a static build. +@see @ref building, @ref cmake +*/ +#define MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS +#undef MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS + #ifdef MAGNUM_BUILD_DEPRECATED /** @brief Multi-threaded build * @m_deprecated_since{2019,10} Use @ref CORRADE_BUILD_MULTITHREADED instead. diff --git a/src/Magnum/configure.h.cmake b/src/Magnum/configure.h.cmake index 11a42448b..4e976bb87 100644 --- a/src/Magnum/configure.h.cmake +++ b/src/Magnum/configure.h.cmake @@ -27,6 +27,7 @@ #cmakedefine MAGNUM_BUILD_DEPRECATED #cmakedefine MAGNUM_BUILD_STATIC +#cmakedefine MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS #cmakedefine MAGNUM_TARGET_GL #cmakedefine MAGNUM_TARGET_GLES #cmakedefine MAGNUM_TARGET_GLES2