diff --git a/cppwinrt/cppwinrt.vcxproj b/cppwinrt/cppwinrt.vcxproj
index b8beed890..3efa7a64c 100644
--- a/cppwinrt/cppwinrt.vcxproj
+++ b/cppwinrt/cppwinrt.vcxproj
@@ -1,6 +1,6 @@
-
+
Debug
@@ -309,6 +309,6 @@
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
\ No newline at end of file
diff --git a/cppwinrt/cppwinrt.vcxproj.filters b/cppwinrt/cppwinrt.vcxproj.filters
index 96129ab20..935ef8c20 100644
--- a/cppwinrt/cppwinrt.vcxproj.filters
+++ b/cppwinrt/cppwinrt.vcxproj.filters
@@ -197,9 +197,9 @@
-
+
-
+
\ No newline at end of file
diff --git a/cppwinrt/packages.config b/cppwinrt/packages.config
index 9b3264e46..7b2ee1f28 100644
--- a/cppwinrt/packages.config
+++ b/cppwinrt/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/strings/base_activation.h b/strings/base_activation.h
index c657c692d..a2442d774 100644
--- a/strings/base_activation.h
+++ b/strings/base_activation.h
@@ -133,6 +133,10 @@ WINRT_EXPORT namespace winrt::impl
std::int32_t const result = *target;
_ReadWriteBarrier();
return result;
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ std::int32_t const result = *target;
+ std::atomic_signal_fence(std::memory_order_acq_rel);
+ return result;
#elif defined _M_ARM64
#if defined(__GNUC__)
std::int32_t const result = *target;
@@ -146,13 +150,17 @@ WINRT_EXPORT namespace winrt::impl
#endif
}
-#if defined _WIN64
+#if defined(_WIN64) || defined(WINRT_IMPL_64)
inline std::int64_t interlocked_read_64(std::int64_t const volatile* target) noexcept
{
#if defined _M_X64
std::int64_t const result = *target;
_ReadWriteBarrier();
return result;
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ std::int64_t const result = *target;
+ std::atomic_signal_fence(std::memory_order_acq_rel);
+ return result;
#elif defined _M_ARM64
#if defined(__GNUC__)
std::int64_t const result = *target;
@@ -176,14 +184,14 @@ WINRT_EXPORT namespace winrt::impl
template
T* interlocked_read_pointer(T* const volatile* target) noexcept
{
-#ifdef _WIN64
+#if defined(_WIN64) || defined(WINRT_IMPL_64)
return (T*)interlocked_read_64((std::int64_t*)target);
#else
return (T*)interlocked_read_32((std::int32_t*)target);
#endif
}
-#ifdef _WIN64
+#if defined(_WIN64) || defined(WINRT_IMPL_64)
inline constexpr std::uint32_t memory_allocation_alignment{ 16 };
#ifdef _MSC_VER
#pragma warning(push)
@@ -237,7 +245,7 @@ WINRT_EXPORT namespace winrt::impl
explicit factory_count_guard(std::size_t& count) noexcept : m_count(count)
{
#ifndef WINRT_NO_MODULE_LOCK
-#ifdef _WIN64
+#if defined(_WIN64) || defined(WINRT_IMPL_64)
_InterlockedIncrement64((std::int64_t*)&m_count);
#else
_InterlockedIncrement((long*)&m_count);
@@ -248,7 +256,7 @@ WINRT_EXPORT namespace winrt::impl
~factory_count_guard() noexcept
{
#ifndef WINRT_NO_MODULE_LOCK
-#ifdef _WIN64
+#if defined(_WIN64) || defined(WINRT_IMPL_64)
_InterlockedDecrement64((std::int64_t*)&m_count);
#else
_InterlockedDecrement((long*)&m_count);
@@ -282,7 +290,7 @@ WINRT_EXPORT namespace winrt::impl
object_and_count current_value{ pointer_value, 0 };
-#if defined _WIN64
+#if defined(_WIN64) || defined(WINRT_IMPL_64)
#if defined(__GNUC__)
bool exchanged = __sync_bool_compare_and_swap((__int128*)this, *(__int128*)¤t_value, (__int128)0);
#else
@@ -305,7 +313,7 @@ WINRT_EXPORT namespace winrt::impl
static_assert(std::is_standard_layout_v);
-#if !defined _M_IX86 && !defined _M_X64 && !defined _M_ARM64
+#if !defined _M_IX86 && !defined _M_X64 && !defined _M_ARM64 && !(defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)))
#error Unsupported architecture: verify that zero-initialization of SLIST_HEADER is still safe
#endif
diff --git a/strings/base_extern.h b/strings/base_extern.h
index a17908ac4..4ef71ca4a 100644
--- a/strings/base_extern.h
+++ b/strings/base_extern.h
@@ -2,10 +2,10 @@
// These global function pointers must use WINRT_EXPORT (which expands to
// 'export extern "C++"' in module builds) so that module and non-module TUs
// in the same binary share the same instances.
-WINRT_EXPORT __declspec(selectany) std::int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {};
-WINRT_EXPORT __declspec(selectany) winrt::hstring(__stdcall* winrt_to_message_handler)(void* address) {};
-WINRT_EXPORT __declspec(selectany) void(__stdcall* winrt_throw_hresult_handler)(std::uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {};
-WINRT_EXPORT __declspec(selectany) std::int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {};
+WINRT_EXPORT WINRT_IMPL_SELECTANY std::int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {};
+WINRT_EXPORT WINRT_IMPL_SELECTANY winrt::hstring(__stdcall* winrt_to_message_handler)(void* address) {};
+WINRT_EXPORT WINRT_IMPL_SELECTANY void(__stdcall* winrt_throw_hresult_handler)(std::uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {};
+WINRT_EXPORT WINRT_IMPL_SELECTANY std::int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {};
#if defined(_MSC_VER)
#ifdef _M_HYBRID
diff --git a/strings/base_includes.h b/strings/base_includes.h
index 287a09709..65c0bceeb 100644
--- a/strings/base_includes.h
+++ b/strings/base_includes.h
@@ -1,5 +1,7 @@
+#if defined(_WIN32)
#include
+#endif
#include
#include
#include
diff --git a/strings/base_macros.h b/strings/base_macros.h
index 91b0121d9..1e236fddc 100644
--- a/strings/base_macros.h
+++ b/strings/base_macros.h
@@ -73,6 +73,37 @@
#define WINRT_IMPL_NOVTABLE
#endif
+// Non-Windows (ELF) platform shims. On Linux/macOS GCC/Clang there is a single
+// calling convention, so __stdcall is meaningless and undefined as a token;
+// map it away. __declspec(selectany) has no ELF equivalent keyword — the COMDAT
+// "pick any" semantics map to a weak symbol.
+#if !defined(_WIN32)
+#ifndef __stdcall
+#define __stdcall
+#endif
+#define WINRT_IMPL_SELECTANY __attribute__((weak))
+#else
+#define WINRT_IMPL_SELECTANY __declspec(selectany)
+#endif
+
+// On 64-bit ELF (LP64) select the 64-bit interlocked/slist code paths that are
+// otherwise gated on _WIN64, and supply the MSVC interlocked intrinsics the
+// activation/factory-cache machinery references, implemented with GCC/Clang
+// atomic builtins. (The Add slice constructs via winrt::make and never hits the
+// factory cache at runtime, but the projected constructor is still instantiated,
+// so these must compile and link.)
+#if !defined(_WIN32)
+#if defined(__LP64__) || (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8)
+#define WINRT_IMPL_64 1
+#endif
+inline long _InterlockedIncrement(long volatile* operand) noexcept { return __atomic_add_fetch(operand, 1, __ATOMIC_SEQ_CST); }
+inline long _InterlockedDecrement(long volatile* operand) noexcept { return __atomic_sub_fetch(operand, 1, __ATOMIC_SEQ_CST); }
+inline __INT64_TYPE__ _InterlockedIncrement64(__INT64_TYPE__ volatile* operand) noexcept { return __atomic_add_fetch(operand, 1, __ATOMIC_SEQ_CST); }
+inline __INT64_TYPE__ _InterlockedDecrement64(__INT64_TYPE__ volatile* operand) noexcept { return __atomic_sub_fetch(operand, 1, __ATOMIC_SEQ_CST); }
+inline __INT64_TYPE__ _InterlockedCompareExchange64(__INT64_TYPE__ volatile* dest, __INT64_TYPE__ exchange, __INT64_TYPE__ comparand) noexcept { __atomic_compare_exchange_n(dest, &comparand, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return comparand; }
+inline void* _InterlockedCompareExchangePointer(void* volatile* dest, void* exchange, void* comparand) noexcept { __atomic_compare_exchange_n(dest, &comparand, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return comparand; }
+#endif
+
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(__lto_visibility_public__)
#define WINRT_IMPL_PUBLIC __attribute__((lto_visibility_public))
diff --git a/strings/base_natvis.h b/strings/base_natvis.h
index 9e78563cb..71fbc57f6 100644
--- a/strings/base_natvis.h
+++ b/strings/base_natvis.h
@@ -85,11 +85,11 @@ WINRT_EXPORT namespace winrt::impl
}
extern "C"
-__declspec(selectany)
+WINRT_IMPL_SELECTANY
decltype(winrt::impl::natvis::abi_val) & WINRT_abi_val = winrt::impl::natvis::abi_val;
extern "C"
-__declspec(selectany)
+WINRT_IMPL_SELECTANY
decltype(winrt::impl::natvis::get_val) & WINRT_get_val = winrt::impl::natvis::get_val;
#ifdef _M_IX86
diff --git a/strings/base_version.h b/strings/base_version.h
index 13d21fb2a..27ce4fcfb 100644
--- a/strings/base_version.h
+++ b/strings/base_version.h
@@ -1,7 +1,7 @@
// WINRT_version is used by Microsoft to analyze C++/WinRT library adoption and inform future product decisions.
extern "C"
-__declspec(selectany)
+WINRT_IMPL_SELECTANY
char const * const WINRT_version = "C++/WinRT version:" CPPWINRT_VERSION;
#if defined(_MSC_VER)