diff --git a/targets/platform/fs/fs.h b/targets/platform/fs/fs.h index 4b17768b9..cd2640925 100644 --- a/targets/platform/fs/fs.h +++ b/targets/platform/fs/fs.h @@ -1,3 +1,18 @@ +#pragma once + #include "IPlatformFilesystem.h" -extern IPlatformFilesystem& PlatformFilesystem; \ No newline at end of file +// Function accessor backed by a function-local static (Meyers singleton). +// Avoids the static-initialization-order fiasco that the previous +// `extern IPlatformFilesystem& PlatformFilesystem;` form had: anything reading PlatformFilesystem +// during another translation unit's static init was UB. +// +// The macro lets the existing call sites keep writing `PlatformFilesystem.foo()` +// without each call site having to add the `()`. The expansion is just +// a call to a function returning a reference, so codegen is unchanged +// once inlined. +namespace platform_internal { +IPlatformFilesystem& PlatformFilesystem_get(); +} + +#define PlatformFilesystem (::platform_internal::PlatformFilesystem_get()) diff --git a/targets/platform/fs/std/StdFilesystem.cpp b/targets/platform/fs/std/StdFilesystem.cpp index 3f605392c..e813b28d3 100644 --- a/targets/platform/fs/std/StdFilesystem.cpp +++ b/targets/platform/fs/std/StdFilesystem.cpp @@ -6,8 +6,12 @@ #include #endif -StdFilesystem std_filesystem_instance; -IPlatformFilesystem& PlatformFilesystem = std_filesystem_instance; +namespace platform_internal { +IPlatformFilesystem& PlatformFilesystem_get() { + static StdFilesystem instance; + return instance; +} +} IPlatformFilesystem::ReadResult StdFilesystem::readFile(const std::filesystem::path& path, void* buffer, std::size_t capacity) { diff --git a/targets/platform/input/input.h b/targets/platform/input/input.h index 436916435..d3f5ec9c8 100644 --- a/targets/platform/input/input.h +++ b/targets/platform/input/input.h @@ -1,3 +1,18 @@ +#pragma once + #include "IPlatformInput.h" -extern IPlatformInput& PlatformInput; +// Function accessor backed by a function-local static (Meyers singleton). +// Avoids the static-initialization-order fiasco that the previous +// `extern IPlatformInput& PlatformInput;` form had: anything reading PlatformInput +// during another translation unit's static init was UB. +// +// The macro lets the existing call sites keep writing `PlatformInput.foo()` +// without each call site having to add the `()`. The expansion is just +// a call to a function returning a reference, so codegen is unchanged +// once inlined. +namespace platform_internal { +IPlatformInput& PlatformInput_get(); +} + +#define PlatformInput (::platform_internal::PlatformInput_get()) diff --git a/targets/platform/input/sdl2/SDL2Input.cpp b/targets/platform/input/sdl2/SDL2Input.cpp index 29348e951..1f56f76bf 100644 --- a/targets/platform/input/sdl2/SDL2Input.cpp +++ b/targets/platform/input/sdl2/SDL2Input.cpp @@ -20,8 +20,12 @@ #include "../InputConstants.h" #include "../../PlatformTypes.h" -SDL2Input sdl2_input_instance; -IPlatformInput& PlatformInput = sdl2_input_instance; +namespace platform_internal { +IPlatformInput& PlatformInput_get() { + static SDL2Input instance; + return instance; +} +} static const int KEY_COUNT = SDL_NUM_SCANCODES; static const int BTN_COUNT = SDL_CONTROLLER_BUTTON_MAX; diff --git a/targets/platform/profile/profile.h b/targets/platform/profile/profile.h index 7b23288c8..d98421bfc 100644 --- a/targets/platform/profile/profile.h +++ b/targets/platform/profile/profile.h @@ -1,4 +1,18 @@ -#include "IPlatformProfile.h" -#include "ProfileConstants.h" +#pragma once -extern IPlatformProfile& PlatformProfile; +#include "IPlatformProfile.h" + +// Function accessor backed by a function-local static (Meyers singleton). +// Avoids the static-initialization-order fiasco that the previous +// `extern IPlatformProfile& PlatformProfile;` form had: anything reading PlatformProfile +// during another translation unit's static init was UB. +// +// The macro lets the existing call sites keep writing `PlatformProfile.foo()` +// without each call site having to add the `()`. The expansion is just +// a call to a function returning a reference, so codegen is unchanged +// once inlined. +namespace platform_internal { +IPlatformProfile& PlatformProfile_get(); +} + +#define PlatformProfile (::platform_internal::PlatformProfile_get()) diff --git a/targets/platform/profile/stub/StubProfile.cpp b/targets/platform/profile/stub/StubProfile.cpp index 0cff91666..c30617f3b 100644 --- a/targets/platform/profile/stub/StubProfile.cpp +++ b/targets/platform/profile/stub/StubProfile.cpp @@ -7,8 +7,12 @@ #include "../ProfileConstants.h" #include "input/input.h" -StubProfile stub_profile_instance; -IPlatformProfile& PlatformProfile = stub_profile_instance; +namespace platform_internal { +IPlatformProfile& PlatformProfile_get() { + static StubProfile instance; + return instance; +} +} namespace { constexpr PlayerUID kFakeXuidBase = 0xe000d45248242f2eULL; diff --git a/targets/platform/renderer/gl/GLRenderer.cpp b/targets/platform/renderer/gl/GLRenderer.cpp index a8e87049d..46066d25c 100644 --- a/targets/platform/renderer/gl/GLRenderer.cpp +++ b/targets/platform/renderer/gl/GLRenderer.cpp @@ -1,5 +1,6 @@ #include "GLRenderer.h" +#include "renderer/renderer.h" #include "PlatformTypes.h" #include "SDL.h" #include "SDL_error.h" @@ -54,8 +55,12 @@ #include #include -GLRenderer gl_renderer_instance; -IPlatformRenderer& PlatformRenderer = gl_renderer_instance; +namespace platform_internal { +IPlatformRenderer& PlatformRenderer_get() { + static GLRenderer instance; + return instance; +} +} // MARK: Shaders diff --git a/targets/platform/renderer/renderer.h b/targets/platform/renderer/renderer.h index 70f70b6a2..aaf9dd4fc 100644 --- a/targets/platform/renderer/renderer.h +++ b/targets/platform/renderer/renderer.h @@ -2,9 +2,17 @@ #include "IPlatformRenderer.h" -// Defined in the linked renderer backend (currently -// platform/renderer/gl/GLRenderer.cpp). The legacy gl* macro shim used -// by older rendering call sites lives in -// platform/renderer/gl/gl_compat.h, which is brought in via -// platform/stubs.h on linux. -extern IPlatformRenderer& PlatformRenderer; +// Function accessor backed by a function-local static (Meyers singleton). +// Avoids the static-initialization-order fiasco that the previous +// `extern IPlatformRenderer& PlatformRenderer;` form had: anything reading PlatformRenderer +// during another translation unit's static init was UB. +// +// The macro lets the existing call sites keep writing `PlatformRenderer.foo()` +// without each call site having to add the `()`. The expansion is just +// a call to a function returning a reference, so codegen is unchanged +// once inlined. +namespace platform_internal { +IPlatformRenderer& PlatformRenderer_get(); +} + +#define PlatformRenderer (::platform_internal::PlatformRenderer_get()) diff --git a/targets/platform/storage/storage.h b/targets/platform/storage/storage.h index 0a6d962e7..177050af8 100644 --- a/targets/platform/storage/storage.h +++ b/targets/platform/storage/storage.h @@ -1,3 +1,18 @@ +#pragma once + #include "IPlatformStorage.h" -extern IPlatformStorage& PlatformStorage; +// Function accessor backed by a function-local static (Meyers singleton). +// Avoids the static-initialization-order fiasco that the previous +// `extern IPlatformStorage& PlatformStorage;` form had: anything reading PlatformStorage +// during another translation unit's static init was UB. +// +// The macro lets the existing call sites keep writing `PlatformStorage.foo()` +// without each call site having to add the `()`. The expansion is just +// a call to a function returning a reference, so codegen is unchanged +// once inlined. +namespace platform_internal { +IPlatformStorage& PlatformStorage_get(); +} + +#define PlatformStorage (::platform_internal::PlatformStorage_get()) diff --git a/targets/platform/storage/stub/StubStorage.cpp b/targets/platform/storage/stub/StubStorage.cpp index cd4ff1300..748b2e2b4 100644 --- a/targets/platform/storage/stub/StubStorage.cpp +++ b/targets/platform/storage/stub/StubStorage.cpp @@ -6,8 +6,12 @@ #include #include -StubStorage stub_storage_instance; -IPlatformStorage& PlatformStorage = stub_storage_instance; +namespace platform_internal { +IPlatformStorage& PlatformStorage_get() { + static StubStorage instance; + return instance; +} +} static XMARKETPLACE_CONTENTOFFER_INFO s_dummyOffer = {}; static XCONTENT_DATA s_dummyContentData = {};