-
-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Windows Runtime (WinRT) APIs support #307
Comments
I did some experiments with using the C++/WinRT headers with clang in mingw mode a couple of years ago. I don't remember the specifics, but I think I got it working, kinda, but it required a some (more or less messy?) hacks/tweaks back then. Then for async stuff, it also required some Clang feature which wasn't enabled by default (and I think didn't quite work out back then). Hopefully the situation is better today and not worse - I'd appreciate if someone wants to pick up looking into it! |
|
I'm not very familiar with these APIs, but I think it's kinda separate - it all originates from the same kinds of IDL interfaces, but iirc C++/WinRT provides a higher level wrapper for those APIs. In this case, I think it all builds on top of Microsoft headers (but ones with acceptable licenses actually) - I don't quite know how to integrate it on top of mingw-w64/wine headers. For what I've seen, you'd essentially take the cppwinrt folder from MS and integrate it in our headers (or just initially, just keeping it separate somewhere) and looking at what it takes to use it. |
@cristianadam Can you provide the steps how to enable those bluetooth APIs in qt6? I can play with that but can not guarantee if it works or not. If it is off-topic here feel free to email me or ping me in any GitHub thread. |
I've had a look at QtBase 6.4's
Then looked at this CMake feature probe, and it boils down to this cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 17)
project(test-winrt)
file(WRITE ${CMAKE_BINARY_DIR}/test-winrt.cpp [=[
#include <winrt/base.h>
int main(void)
{
return 0;
}
]=])
add_executable(test-winrt ${CMAKE_BINARY_DIR}/test-winrt.cpp)
target_link_libraries(test-winrt runtimeobject) If this compiles, everything is fine. |
I took the latest binary release from cpprt from https://github.com/microsoft/cppwinrt/releases/download/2.0.220912.1/Microsoft.Windows.CppWinRT.2.0.220912.1.nupkg. Extracted the nupkg (a zip file) archive and ran the
which generated on my Windows 11 Machine a Then tried to build the example above (after adding a MSVC 2022 and clang-cl 15.0 and got the following error:
Afterwards tried it with LLVM-MinGW 15.0.0 and got this errors:
|
By setting With LLVM-MinGW, after doing an
|
Hmm, are you compiling for arm64, or does this expand to something that includes code for all architectures, with the assumption that winnt.h provides lots of declarations for all architectures and only some of these codepaths actually ends up emitted? We're lacking these corresponding defines in our headers, but this probably shouldn't be very hard to implement.
This is also something that normally only is used on arm/arm64. IIRC these are compiler intrinsics in MSVC mode, while for mingw we usually implement them with inline asm or similar in headers. I'm not entirely sure for this one, whether we can do that or whether it needs to be a compiler intrinsic...
This one should in generaly definitely be available - but maybe might need an explicit include of |
Yes, I am running the test on a Windows11 Arm64 laptop. |
Oh, ok, I see. It's possible that there are fewer such missing bits in the headers if building for x86_64, but we're of course interested in fixing all these to make things work for all arches. |
I am completely clueless about C++/WinRT. Is it a fully header-based wrapper around an underlying "WinRT API" that is exposed as COM interfaces? |
Yup, pretty much. There's tooling (which unfortunately exists as executables, which don't run well on other OSes since they use lots of modern APIs that wine doesn't implement) that can read metadata files and generate these modern C++ headers that implement the APIs specified in the WinRT metadata. |
So I downloaded the nuget package and generated the headers with cppwinrt.exe, then tried to compile a sample code based on https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/get-started#a-cwinrt-quick-start. I was able to get it to build and run with some hacks using llvm-mingw.
//#include <windows.h>
#include <intrin.h>
// Copied from `InterlockedCompareExchange128` in `mingw-w64-tools/widl/include/winnt.h`
static __attribute__((always_inline)) unsigned char _InterlockedCompareExchange128( volatile __int64 *dest, __int64 xchg_high, __int64 xchg_low, __int64 *compare )
{
#ifdef __x86_64__
unsigned char ret;
__asm__ __volatile__( "lock cmpxchg16b %0; setz %b2"
: "=m" (dest[0]), "=m" (dest[1]), "=r" (ret),
"=a" (compare[0]), "=d" (compare[1])
: "m" (dest[0]), "m" (dest[1]), "3" (compare[0]), "4" (compare[1]),
"c" (xchg_high), "b" (xchg_low) );
return ret;
#else
return __sync_bool_compare_and_swap( (__int128 *)dest, *(__int128 *)compare, ((__int128)xchg_high << 64) | xchg_low );
#endif
}
// Sample code from https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/get-started#a-cwinrt-quick-start
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
#include <iostream>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;
int main()
{
winrt::init_apartment();
Uri rssFeedUri{ L"https://news.ycombinator.com/rss" };
SyndicationClient syndicationClient;
SyndicationFeed syndicationFeed = syndicationClient.RetrieveFeedAsync(rssFeedUri).get();
for (const SyndicationItem syndicationItem : syndicationFeed.Items())
{
winrt::hstring titleAsHstring = syndicationItem.Title().Text();
std::wcout << titleAsHstring.c_str() << std::endl;
}
} Patch to winrt headers: (haven't actually tested the i386 block) diff --git a/base.h b/base.h
index defe873..590bb4c 100644
--- a/base.h
+++ b/base.h
@@ -480,6 +480,7 @@ extern "C"
int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept;
}
+#ifdef _MSC_VER
#ifdef _M_HYBRID
#define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:#WINRT_IMPL_" #function "@" #count "=#" #function "@" #count))
#elif _M_ARM64EC
@@ -489,6 +490,13 @@ extern "C"
#else
#define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:WINRT_IMPL_" #function "=" #function))
#endif
+#elif defined(__GNUC__)
+# if defined(__x86_64__)
+# define WINRT_IMPL_LINK(function, count) __asm__(".weak WINRT_IMPL_" #function "\n.set WINRT_IMPL_" #function ", " #function);
+# elif defined(__i386__)
+# define WINRT_IMPL_LINK(function, count) __asm__(".weak _WINRT_IMPL_" #function "@" #count "\n.set _WINRT_IMPL_" #function "@" #count ", _" #function "@" #count);
+# endif
+#endif
WINRT_IMPL_LINK(LoadLibraryW, 4)
WINRT_IMPL_LINK(FreeLibrary, 4) Build: > path\to\llvm-mingw-20220802-ucrt-x86_64\bin\clang++.exe -std=c++20 -fdeclspec -U__declspec -lole32 -loleaut32 -g -O2 -o main.exe main.cpp -Ipath\to\parent\dir\of\winrt There are a lot of warnings with unsupported |
There are two unsupported
The compile flags Something else we might have to consider is that the COM interfaces defined in the headers might have subtle bugs (ABI incompatibilities) when compiled with MinGW ABI. This may be a problem, or maybe not. (Frankly I'm not familiar with COM to know.) |
Indeed, there are some such known cases - I don't know if they crop up in the C++/WinRT headers or not though. See |
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64384 is another GCC bug report about the same issue. |
@alvinhochun thank you for the research. I've put it together in a: CMakeLists.txtcmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 20)
project(test-winrt)
file(WRITE ${CMAKE_BINARY_DIR}/test-winrt.cpp [=[
//#include <windows.h>
#include <intrin.h>
// Copied from `InterlockedCompareExchange128` in `mingw-w64-tools/widl/include/winnt.h`
static __attribute__((always_inline)) unsigned char _InterlockedCompareExchange128( volatile __int64 *dest, __int64 xchg_high, __int64 xchg_low, __int64 *compare )
{
#ifdef __x86_64__
unsigned char ret;
__asm__ __volatile__( "lock cmpxchg16b %0; setz %b2"
: "=m" (dest[0]), "=m" (dest[1]), "=r" (ret),
"=a" (compare[0]), "=d" (compare[1])
: "m" (dest[0]), "m" (dest[1]), "3" (compare[0]), "4" (compare[1]),
"c" (xchg_high), "b" (xchg_low) );
return ret;
#else
return __sync_bool_compare_and_swap( (__int128 *)dest, *(__int128 *)compare, ((__int128)xchg_high << 64) | xchg_low );
#endif
}
// Sample code from https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/get-started#a-cwinrt-quick-start
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
#include <iostream>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;
int main()
{
winrt::init_apartment();
Uri rssFeedUri{ L"https://news.ycombinator.com/rss" };
SyndicationClient syndicationClient;
SyndicationFeed syndicationFeed = syndicationClient.RetrieveFeedAsync(rssFeedUri).get();
for (const SyndicationItem syndicationItem : syndicationFeed.Items())
{
winrt::hstring titleAsHstring = syndicationItem.Title().Text();
std::wcout << titleAsHstring.c_str() << std::endl;
}
}
]=])
add_executable(test-winrt ${CMAKE_BINARY_DIR}/test-winrt.cpp)
target_include_directories(test-winrt PRIVATE ..)
target_compile_options(test-winrt PRIVATE -Wno-ignored-attributes -Wno-unknown-attributes)
add_custom_target(run COMMAND test-winrt)
I've tested on x64 and worked as expected with LLVM-MinGW 15.0.0. On Arm64 we're down to these errors:
I've tried to find a fix but no luck 😔 |
Those ARM64 intrinsics and values are documented on https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=msvc-170. We probably need to implement them in mingw-w64. The same applies to |
I've put the code in Godbolt #include <cstdint>
#include <intrin.h>
#if defined _M_ARM
#define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM_BARRIER_ISH));
#elif defined _M_ARM64
#define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM64_BARRIER_ISH));
#endif
inline int32_t interlocked_read_32(int32_t const volatile* target) noexcept
{
#if defined _M_IX86 || defined _M_X64
int32_t const result = *target;
_ReadWriteBarrier();
return result;
#elif defined _M_ARM || defined _M_ARM64
int32_t const result = __iso_volatile_load32(reinterpret_cast<int32_t const volatile*>(target));
WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER
return result;
#else
#error Unsupported architecture
#endif
}
#if defined _WIN64
inline int64_t interlocked_read_64(int64_t const volatile* target) noexcept
{
#if defined _M_X64
int64_t const result = *target;
_ReadWriteBarrier();
return result;
#elif defined _M_ARM64
int64_t const result = __iso_volatile_load64(target);
WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER
return result;
#else
#error Unsupported architecture
#endif
}
#endif
int main()
{
int32_t p32 = 0;
int64_t p64 = 0;
int32_t i32 = interlocked_read_32(&p32);
int64_t i64 = interlocked_read_64(&p64);
} dissasenbly: ;ARM64
;Flags[SingleProEpi] functionLength[36] RegF[0] RegI[0] H[0] frameChainReturn[UnChained] frameSize[16]
;Flags[SingleProEpi] functionLength[36] RegF[0] RegI[0] H[0] frameChainReturn[UnChained] frameSize[16]
;Flags[SingleProEpi] functionLength[64] RegF[0] RegI[0] H[0] frameChainReturn[Chained] frameSize[48]
|int interlocked_read_32(int const volatile *)| PROC ; interlocked_read_32
|$LN3|
sub sp,sp,#0x10
str x0,[sp,#8]
ldr x8,[sp,#8]
ldr w8,[x8]
str w8,[sp]
dmb ish
ldr w0,[sp]
add sp,sp,#0x10
ret
ENDP ; |int interlocked_read_32(int const volatile *)|, interlocked_read_32
|__int64 interlocked_read_64(__int64 const volatile *)| PROC ; interlocked_read_64
|$LN3|
sub sp,sp,#0x10
str x0,[sp]
ldr x8,[sp]
ldr x8,[x8]
str x8,[sp,#8]
dmb ish
ldr x0,[sp,#8]
add sp,sp,#0x10
ret
ENDP ; |__int64 interlocked_read_64(__int64 const volatile *)|, interlocked_read_64
|main| PROC
|$LN3|
stp fp,lr,[sp,#-0x30]!
mov fp,sp
mov w8,#0
str w8,[sp,#0x10]
mov x8,#0
str x8,[sp,#0x18]
add x0,sp,#0x10
bl |int interlocked_read_32(int const volatile *)|
mov w0,w0
str w0,[sp,#0x14]
add x0,sp,#0x18
bl |__int64 interlocked_read_64(__int64 const volatile *)|
str x0,[sp,#0x20]
mov w0,#0
ldp fp,lr,[sp],#0x30
ret
ENDP ; |main| Now all I would need is to convert the disassembly into inline C/C++ assembly code... 😅 |
For the ISO volatile loads/stores, if I understand correctly, e.g.
If I understand correctly, the reason for these intrinsics to exist in the first place, is that MSVC traditionally has treated volatile loads/stores differently from the spec, making them atomic, while the C standards say they aren't. With these For mingw mode, the default is to have the standard volatile semantics (and running in the MSVC mode isn't expected), so just turning these into regular language-level volatile loads/stores should be fine. I guess they could be stashed along with other inline implementations of MSVC intrinsics in e.g. |
I've tried a new Godbolt version for arm64 gcc and with the diff -Naur winrt-orig/base.h winrt/base.h
--- winrt-orig/base.h 2022-10-12 13:59:50.726224100 +0200
+++ winrt/base.h 2022-10-12 14:03:56.464396400 +0200
@@ -452,6 +452,7 @@
int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept;
}
+#if defined(_MSC_VER)
#ifdef _M_HYBRID
#define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:#WINRT_IMPL_" #function "@" #count "=#" #function "@" #count))
#elif _M_ARM64EC
@@ -461,6 +462,13 @@
#else
#define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:WINRT_IMPL_" #function "=" #function))
#endif
+#elif defined(__GNUC__)
+# if defined(__x86_64__) || defined(__aarch64__)
+# define WINRT_IMPL_LINK(function, count) __asm__(".weak WINRT_IMPL_" #function "\n.set WINRT_IMPL_" #function ", " #function);
+# elif defined(__i386__)
+# define WINRT_IMPL_LINK(function, count) __asm__(".weak _WINRT_IMPL_" #function "@" #count "\n.set _WINRT_IMPL_" #function "@" #count ", _" #function "@" #count);
+# endif
+#endif
WINRT_IMPL_LINK(LoadLibraryW, 4)
WINRT_IMPL_LINK(FreeLibrary, 4)
@@ -6091,7 +6099,11 @@
#if defined _M_ARM
#define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM_BARRIER_ISH));
#elif defined _M_ARM64
-#define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM64_BARRIER_ISH));
+# if defined __GNUC__
+# define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER __asm__ __volatile__ ("dmb ish");
+# else
+# define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM64_BARRIER_ISH));
+# endif
#endif
namespace winrt::impl and the new functions: #if defined(__GNUC__) && defined(__aarch64__)
static __attribute__((always_inline)) __int32 __iso_volatile_load32(__int32 const volatile *ptr) {
return *ptr;
}
static __attribute__((always_inline)) __int64 __iso_volatile_load64(__int64 const volatile *ptr) {
return *ptr;
}
#endif The example from above compiled and ran on Windows 11 arm64! 🎉 |
I submitted a PR: microsoft/cppwinrt#1200 Regarding |
Great! (Didn’t check the contents of it at the moment.)
Yes, we should provide those too. And then we should probably provide the |
But I didn't know how to use it with |
It is implemented in Clang, but it’s only exposed if building in MSVC mode (or maybe with |
We could just change the cppwinrt headers to use FYI I am working on adding a CMake build for cppwinrt itself and also trying to get the tests to work. If things go well there should soon be CI checks upstream to make sure things will continue to be compatible with llvm-mingw. |
Hello, I'm interested in this, seems that it might allow me to compile some existing C++ code with Clang+MinGW. How can I test this WinRT support? Thanks. |
You need to build cppwinrt.exe from master, either with the official VS project + VS2022 or the CMake build + llvm-mingw, then generate the C++/WinRT projection headers with it and use them to compile your code. |
Is there a documentation about that step? |
See my reponse at #307 (comment). It's just a matter of running
|
Thanks. Here's what I did, maybe it will be helpful to somebody:
Did I do it right? Could any of you perhaps upload your |
Looks about right. I did the same thing, then I compiled the following cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 20)
project(test-winrt)
file(WRITE ${CMAKE_BINARY_DIR}/test-winrt.cpp [=[
// Sample code from https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/get-started#a-cwinrt-quick-start
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
#include <iostream>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;
int main()
{
winrt::init_apartment();
Uri rssFeedUri{ L"https://news.ycombinator.com/rss" };
SyndicationClient syndicationClient;
SyndicationFeed syndicationFeed = syndicationClient.RetrieveFeedAsync(rssFeedUri).get();
for (const SyndicationItem syndicationItem : syndicationFeed.Items())
{
winrt::hstring titleAsHstring = syndicationItem.Title().Text();
std::wcout << titleAsHstring.c_str() << std::endl;
}
}
]=])
add_executable(test-winrt ${CMAKE_BINARY_DIR}/test-winrt.cpp)
target_include_directories(test-winrt PRIVATE ../repo/_build/x64/Release)
add_custom_target(run COMMAND test-winrt) With LLVM-MinGW 15.0.0 (arm64) and it all worked without any hacks!
@alvinhochun Hat off for pulling this out! Thank you! @mstorsjo can we get a |
Sure, we'll just have to figure out the cross-build story. (All releases are cross-built - out of the downloadable releases, no files of those are ever built on Windows.) If I understand correctly, all the headers generated by the cppwinrt.exe tool are properly redistributable with a permissive enough license. This is totally mandatory and a dealbreaker if it isn't. Then, if I understand correctly, the cppwinrt.exe tool only works on Windows, and it reads the Windows-bundled winmd files to generate headers. So if you run the tool on an older version of Windows, you'd get different/older winrt headers generated. Is this correct? In that case, we'd need to set up a repo somewhere (github.com/mingw-w64 maybe?), with the generated output of the tool, which we then can download on other OSes, use for cross compilation, and bundle in llvm-mingw. Then someone can periodically update that repo, and we'd make llvm-mingw bundle newer versions of it in each release. WDYT about that, @alvinhochun? |
@cristianadam I tried the sample you posted from learn.microsoft.com, but without cmake.
First I tried with c++17, it emitted errors like the following, even though
Then, after changing it to c++20, I got the following:
Any ideas? Edit: I added Edit 2: I added
Is it something with my setup? |
I'm too tired to respond properly to the other replies (will do that tomorrow), but I can address this now:
You just ran into a case of a missing mingw-w64 header, which I actually added specifically for cppwinrt a while ago with mingw-w64/mingw-w64@2b6272b. For now, you can download |
Yes, it helped, thanks! Next thing I got was:
I'm not the first one to encounter this. I added |
If you want winrt headers I can try to add it in msys2/mingw-packages. That way llvm-mingw would not be bloated with extra headers. But cross compilation would not be straight-forward. |
For the llvm-mingw perspective, cross compilation is the primary concern, and I'm sure cross compiling users will want it in one form or another. But that doesn't exclude packaging it in msys2 in a way that directly uses cppwinrt.exe. (But that would be weird in a way if it ends up packaging stuff based on whatever was available on the runner that built that package.) |
With the diff --git a/src/network/configure.cmake b/src/network/configure.cmake
index 0de16ae90b..7e613f579f 100644
--- a/src/network/configure.cmake
+++ b/src/network/configure.cmake
@@ -210,6 +210,7 @@ qt_config_compile_test(networklistmanager
LABEL "Network List Manager"
CODE
"#include <netlistmgr.h>
+#include <ocidl.h>
#include <wrl/client.h>
int main(void)
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
index 72023c6628..35ce6345ad 100644
--- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
@@ -155,7 +155,7 @@ bool QNetworkListManagerEvents::checkBehindCaptivePortal()
VariantInit(&variant);
const auto scopedVariantClear = qScopeGuard([&variant]() { VariantClear(&variant); });
- const wchar_t *versions[] = { NA_InternetConnectivityV6, NA_InternetConnectivityV4 };
+ const wchar_t *versions[] = { L"NA_InternetConnectivityV6", L"NA_InternetConnectivityV4" };
for (const auto version : versions) {
hr = propertyBag->Read(version, &variant, nullptr);
if (SUCCEEDED(hr)
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
index cf9a08ca84..aba8528fda 100644
--- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
@@ -15,7 +15,7 @@
#include <wrl/wrappers/corewrappers.h>
#include <comdef.h>
-#if QT_CONFIG(cpp_winrt) && !defined(Q_CC_CLANG)
+#if QT_CONFIG(cpp_winrt)
#define SUPPORTS_WINRT 1
#endif I was able to configure and build Qt6's qtbase.
and the 🎉 |
My impression is they are MIT-licensed (microsoft/cppwinrt#929) but the headers themselves don't include the licence header by default. If we do ship generated headers we may need to add that somehow. Cppwinrt actually has a
Cppwinrt can generate headers from the system winmd files provided in It's true that cppwinrt currently only builds and runs on Windows, but from what I've seen so far the only Windows-specific parts are the registry reads for finding the Windows SDK and some
I'm not sure yet, but here are some things to note:
|
Ok, good.
Ah, ok. So if using an SDK as source, there's a fair bit more of reproducibility. Still for the llvm-mingw build process, we probably don't want to have "fetch a WinSDK" as a step - so for that, and for many other consumers, having a repo with pregenerated headers probably is valuable.
Hmm, ok. I think I tried executing binaries of it in Wine a couple years ago, and it failed due to using some WinRT style API (or API for dealing with WinRT style APIs?) that wasn't implemented back then, but maybe things have changed. If it could be built into a native unix executable with some amount of effort, that would of course be the best.
Yep, bundling the headers like the WinSDK does, sounds reasonable as a first step. Secondly, if the cppwinrt can be made a proper standalone native unix executable, it would indeed be good to ship that along as well. Ideally maybe mingw-w64 (and/or wine?) should ship winmd files - as a future next step? I'm clearly not familiar enough with them, how they work, what they contain, and that whole ecosystem yet in any case.
Ah, good point, I hadn't thought about that aspect yet. Yes, with that in mind, having the cppwinrt tool available would be good.
Thanks, that's good to keep in mind.
Yeah, clearly. With most things like this, there will always be things missing, but if whatever we have works for some use cases, it's usually better than nothing :-) I'll probably make the next llvm-mingw release when LLVM 16.0.0 is released (probably with a prerelease from the first RC, at the end of January 2023, and final release around March), so there's still quite some time to get things to a usable-enough state until then. Thanks for your efforts on this matter so far! |
(Ouch I meant to say xmllite...) |
@Biswa96 Since you are here, perhaps you might want to try packaging the cppwinrt tool for CLANG64. The tagged release https://github.com/microsoft/cppwinrt/releases/tag/2.0.221117.1 should be good for an initial version. Remember to pass |
At mstorsjo/llvm-mingw#307 we can see that LLVM-MinGW is able to build qtbase with winrt headers and cxx20 feature. Change-Id: Ib4b5df7481f684ebdb26cbc4246bdf86ff3dd648 Reviewed-by: Cristian Adam <[email protected]>
Some updates: Status of C++/WinRT on mingw-w64The current upstream HEAD (newer than release 2.0.221121.5) does work mostly fine on both Clang 15 (w/ libc++) and GCC 12. The exception is anything that involves coroutine -- there is a lot of potential for miscompilation, so I would advice to test things thoroughly and avoid Other than that, there are still some more work needed to be done -- some test cases are still excluded for mingw-w64 which I haven't have time to start looking into fixing them properly, and I haven't looked into authoring/consuming custom WinRT components at all. Otherwise, normal usage of the WinRT APIs provided by Windows should work without issues. Delivery of the headersMy current idea is that the C++/WinRT headers should not be bundled with any mingw-w64 toolchains, following the reason why using the C++/WinRT headers in the official Windows SDK is discouraged. The tool or headers if bundled can rapidly become outdated, which is not something we want now when more fixes to upstream may still be needed in the near future. Also, when using the official cppwinrt NuGet package with Visual Studio, there is a built-in mechanism that overrides the default include paths so that the newer generated C++/WinRT headers replaces the outdated WinSDK C++/WinRT headers completely to avoid confusion. The way llvm-mingw and other mingw-w64 toolchains are set up now do not support anything similar to that. Therefore, at this time, instead of trying to have C++/WinRT included in llvm-mingw releases, I am experimenting (slowly) with providing it as a separate package instead and also trying to provide some sort of CMake build integration, in a separate project https://github.com/alvinhochun/mingw-w64-cppwinrt (Don't actually depend on it yet.) In the meantime you can compile the cppwinrt tool from master, then manually generate the headers with |
We might also need a way to create winmd files ourselves. |
Yes, that would be required for authoring your own components, but I am really putting this on low priority because I don't yet see the real-world use case for this. (Though one can still use MIDL from the Windows SDK to make the winmd file. It sucks have to manually do it every time the IDL file is changed, but at least it's not fully impossible.)
Unfortunately. But at least MIDL 3.0 is quite well documented (unlike MIDL 2.0 / MIDLRT) which probably helps a bit.
I am not sure whether it will be easier to adapt some C#/Mono tooling to generate the winmd file or to implement winmd writing capabilities to widl. The compiler infrastructure in Mono should be able to write winmd files easily but we will need an MIDL parser in C#. Widl can already parse MIDL (we "just" need to add MIDL 3.0 syntax) but there isn't an FOSS library for writing winmd files. (microsoft/winmd is read-only but perhaps it could be extended to support writing too?) Both paths seem difficult. Anyway, I filed an issue for widl: https://bugs.winehq.org/show_bug.cgi?id=53905 (Btw doesn't look like windows-rs currently has any built-in support for authoring components -- still requires manually running MIDL.) |
Authoring will be needed if XAML (Windows.UI.Xaml) is used for UI, where WinRT classes are needed for your view model for data binding. But that is an even deeper rabbit hole (XAML compiler and such).
It's not like the experience in Visual Studio is any better. ╯▂╰ |
|
@alvinhochun any progress on this issue? I have seen https://github.com/alvinhochun/mingw-w64-cppwinrt/ but I don't think cppwinrt headers / libraries are bundled with any mingw-w64 distro. |
It should be more or less done by now, so far nothing is terribly broken. As for the headers, it is expected that one build their own from winmds. MSYS2 provides a prebuilt set in their repos though. My take on various aspects of cppwinrt with MinGW: |
Just build the upstream tool and generate the headers yourself, or use MSYS2. I haven't really managed to develop further on my ideas, mostly due to the lack of motivation (not needing to use it right now). I still don't think a mingw-w64 toolchain should bundle them, but I guess it is fine with MSYS2 since they are distributed as an individual package and it does get updated. |
Windows 10 has been exposing APIs via Windows Runtime (WinRT) APIs. These APIs can also be used on Desktop, not just for Windows Store for UWP applications.
One example would be the Windows.Devices.Bluetooth Namespace which is described as:
Qt 6.2 is using this with the MSVC compiler and has dropped the previous Win32 API version that MinGW was using.
This WinRT support is being offered by the The C++/WinRT language projection which is :
Note that the project has a (closed) issue named MinGW GCC support, but since clang-cl can handle MSVC quirks, I think LLVM-MinGW would be in a better shape than the GCC MinGW.
This would be an extra argument for the QTBUG-107516 - Migrate from GCC MinGW to LLVM-MinGW migration.
The text was updated successfully, but these errors were encountered: