From c011da65ff628c100632f8d06b9653febda5cdab Mon Sep 17 00:00:00 2001 From: Connor Behrend Date: Tue, 23 Jun 2026 20:35:46 -0700 Subject: [PATCH 1/2] Add cppwinrt to solution --- cppwinrt/cppwinrt.vcxproj | 4 ++-- cppwinrt/cppwinrt.vcxproj.filters | 4 ++-- cppwinrt/packages.config | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) 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 From 58cbfa513ce5993c5e3bb8a1128df0c7f3d54009 Mon Sep 17 00:00:00 2001 From: Connor Behrend Date: Thu, 25 Jun 2026 20:12:49 -0700 Subject: [PATCH 2/2] Add Linux/ELF support to base headers (gated, MSVC-identical) Port the proven WSL/ELF spike edits into the strings/*.h source-of-truth so cppwinrt.exe regenerates a Linux-buildable winrt/base.h. All edits are gated behind !_WIN32 / __GNUC__+ELF so MSVC output is byte-identical: - base_macros.h: platform-shim block (__stdcall, WINRT_IMPL_SELECTANY, WINRT_IMPL_64 LP64 macro, six inline GCC-builtin interlocked shims). - base_activation.h: interlocked_read_32/64 GCC branches; six _WIN64 gates widened to (defined(_WIN64) || defined(WINRT_IMPL_64)); SLIST #error guard relaxed for GCC/ELF on x86/x64/arm64. - base_extern.h / base_natvis.h / base_version.h: __declspec(selectany) -> WINRT_IMPL_SELECTANY (weak symbol on non-MSVC). - base_includes.h: guard behind _WIN32. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- strings/base_activation.h | 22 +++++++++++++++------- strings/base_extern.h | 8 ++++---- strings/base_includes.h | 2 ++ strings/base_macros.h | 31 +++++++++++++++++++++++++++++++ strings/base_natvis.h | 4 ++-- strings/base_version.h | 2 +- 6 files changed, 55 insertions(+), 14 deletions(-) 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)