Rust target for Windows Universal

Can rust be used to write Windows Universal applications? If yes, how can I tell whether the code is being compiled for Windows Universal or not?

I am not trying to write a Windows Universal application, but I would like to port some functionality from C++ that does different things depending on whether Windows Universal API is available and whether the classic API is also available or not.

And at the moment, I only see x86_64-pc-windows-msvc target, but no Universal/classic distinction.

4 Likes

AFAIK, the Universal Windows Platform is not a new machine architecture / target, just a unified set of APIs.

According to this document, you compile your app for each individual arch you target, e.g. x86_64-windows, armv7-windows, and such, and the .AppX installer file will choose the right architecture.

Additionally, you have a common set of functions.

The closest you can get to building UWP apps on Rust is using the Windows Runtime. WinRT is the "base" of the UWP, so if you can use it to access some basic functions.

https://github.com/contextfree/winrt-rust

You would have to manually build your code for each arch you want to support, then modify the .AppX build process to link to the right crate for each arch.

2 Likes

Thanks.

Well, a different set of APIs normally is part of the target. Namely, the fourth one. For Windows, there is currently -gnu and -msvc, for Linux we have -gnu and -musl etc. The question is whether any code designed for either Win32 or WinRT will link to both. Which is what I am not sure about. If it does, it's OK. If not, I need a target, or at least a config option.

And I am not actually concerned about the new APIs. They are all used over COM, COM exists for ages and if the specific API does not, the first request will simply return error and will be handled by falling back to whatever the classic equivalent is.

What I am concerned is whether the classic fallback will link. It does not have to work as long as it returns errors that can be handled—then the code can simply try both and see which works. But it has to link first.

Microsoft also provides the Universal C RunTime, which is what Rust links against.

Instead of linking of a Desktop-specific msvcrt.dll, Rust prefers linking against the api-ms-something DLLs, which are available when writing UWP code.

You can see this link, this link and this one for a list of DLLs you can use in UWP apps. If you link your program against them, then your app will still work on UWP.

Here is what an example Rust x86_64-msvc executable links against:

DLL Name: KERNEL32.dll
DLL Name: ADVAPI32.dll
DLL Name: USERENV.dll
DLL Name: SHELL32.dll
DLL Name: VCRUNTIME140.dll
DLL Name: api-ms-win-crt-string-l1-1-0.dll
DLL Name: api-ms-win-crt-runtime-l1-1-0.dll
DLL Name: api-ms-win-crt-math-l1-1-0.dll
DLL Name: api-ms-win-crt-stdio-l1-1-0.dll
DLL Name: api-ms-win-crt-locale-l1-1-0.dll
DLL Name: api-ms-win-crt-heap-l1-1-0.dll

Most of these DLLs are available on UWP, but the first few are not.

In other words, you can always try to build a UWP library with #![no_std].

This seems to imply that there is now indeed only one way to compile and it can be linked into either Store App (or whatever they call it) and Desktop App. Which means that

No, it actually does not. Well, how did you get this list anyway? By inspecting which DLLs are open at runtime. That is, fortunately. irrelevant. If the “universal” CRT is actually universal, these DLLs were LoadLibrary'd because they are available, but would be skipped when they are not. Windows 7 don't even have all the api-ms-win-crt-* ones, but the executables run there.

I didn't run anything, I just downloaded ripgrep and did objdump -x rg.exe | rg ".dll". These are the ones loaded when the executable is loaded. A search on GitHub shows that LoadLibrary is not even mentioned in the Rust source code.

As for Windows 7: they are available if you have the latest updates installed. This is the update which installs the DLLs on Win7 machines. And there are a lot of people whose program fails to start if the Universal CRT is not installed.

The only problem in the list are the first few DLLs, such as Kernel32 and AdvAPI, which are not available, and for those, you might need to use no_std, since some functions will be unavailable.

One idea is that Rust does not specify the libraries it links against on the command line, it just uses the linker's default ones, and the ones the user specifies. Meaning you might be able to just create a static Rust library, then link using the linker you use for UWP C++ apps, and it will automatically replace the Kernel32 references with whatever api-ms-*.dll is available.

There's also the winrt crate, which provides autogenerated WinRT bindings.

Ok, I checked with dumpbin and they are indeed linked directly. That said, I actually think that they are not linked explicitly by std, but by metadata in one of the standard libs, msvcrt.lib, vcruntime.lib and ucrt.lib, and it seems that is intended to work in both rt and legacy environment. I am also pretty sure that kernel32.dll does, in fact, exist in rt environment.

And I never expected it to be. I did, however, expect it to be used extensively inside msvcrt.lib, vcruntime.lib or ucrt.lib, because all the new WinRT APIs are COM and that is normally loaded on-demand.

Rust is already linking it with the linker for UWP C++ apps! If it wasn't, it wouldn't have the api-ms-*.dlls at all.

I'll try to get verbose output from it tomorrow when I am at work where I have Windows and Visual Studio 14.0.

That was already mentioned. It is, also, not exactly relevant. The question is whether code linked into store and classic applications needs to be compiled differently and if yes, how to tell which is being targeted.

Another (somewhat) useful link: a post on the D language forums on UWP apps.

It links to this D project, which does build for UWP.

If a language like D, with a much bigger runtime and a garbage collector, and no built-in support for UWP can be used in Windows Store apps, I believe Rust should also be usable.

It does, however, use conditional compilation (D's version(x) is analogous to Rust's #[cfg(x)].

Should be. I don't actually care. I want to make sure the code I want to write works in either store or legacy app now and in future.

Have you written an UWP app with Rust since you wrote in October? Would love to see some "Hello World" example with Rust and UWP.

No I didn't. I never even intended to.

If there's anyone interested in this, I'd be glad to contribute. I'm still kind of a noob in Rust but have done some work with the Windows Runtime recently.
The new standard C++ projection they offer is a massive upgrade over their previous solution and it'd be awesome to have a similar thing in Rust. I've seen the winrt crate already and commented on an issue, but I think this would need some more people to pull of, so that's why I'm posting here.

Also, here's a golang issue that references UWP support. It seems stalled for now but it's still marked as a milestone for the next version.

Is there some kind of working group for this?

4 Likes