Is anyone working on seamless cross-compilation?

Both Go and Zig have a much better cross-compilation story than Rust where cross-compilation pretty much works out of the box simply by specifying the target triple. In Rust you can install extra targets with rustup (which I think is fine), and this works quite well when it comes to pure-rust programs, but falls down:

  • When you need to compile rust programs that include C libraries
  • When you need to cross-compile to windows or macOS
  • When you need to target an older version of glibc

In these scenarios (which of course covers rather a lot of Rust programs), the advice tends to be either to find a way to compile natively, or to use Docker. Not great.

While Go's approach (mostly avoiding C entirely) is unlikely to work for Rust, it seems like Zig's approach (shipping compressed, versioned libc headers for all major platforms, along with a C cross-compiler (clang) and a cross-linker (formerly lld, latterly their own zld)) could be ported wholesale (and indeed we could probably reuse a lot of their work, which is all seems to under a MIT license).

Some relevant repos from the zig project:

There is also this issue which goes into detail about we might fix some of the licensing issues on the windows MSVC side of things Pre-RFC: Remove Rust's dependency on Visual Studio in 4 (...complex?) steps. Looks like Microsoft might actually be open sourcing the relevant libraries (Q3 2021 priorities · Issue #2046 · microsoft/STL · GitHub).

Does anyone know if there is any ongoing work (or plans) in this area. Or how I might get involved in proposing and/or implementing this myself?

(I have a decent amount of Rust experience, but no experience with working on compilers).

15 Likes

There is Rustix, which is "a path to a Rust on Linux without libc", just like Go. It won't help with Windows or macOS, but it will help with glibc.

1 Like

The prospect of shipping zig in rustup for use as a cross-compiler has been discussed before. It's honestly just low priority.

The possibility of a windows-msvc target that doesn't require msvc is getting more possible daily. We basically just require the startup code to be open-sourced, and there's "it's been brought up for consideration" from the people inside Microsoft working on Rust support. With Rust being the 3rd first-class supported language for programming against Windows APIs, it's actually possible. The new build tools licensing now allows you to build (but not develop) against MSVC without a Visual Studio license.

windows-gnu doesn't have any obstacles to cross-compiling just working, IIUC. Though it might actually also need the same startup code that MSVC needs? Unsure. There've also been some discussions of clean room reimplementation of the startup code Rust requires; the scope is actually quite small. For the time being, though, pursuing getting it open sourced seems more fruitful.

(These are the links in the OP.)

For macOS, it's not going to happen. Anything that claims to is smoke and mirrors that just happens to work. You need XCode to build applications to run on macOS, and until Apple changes that, you need a Mac to target macOS or other Apple operating systems.

4 Likes

I believe we ship all parts of MinGW that we need as part of rustc. That includes a linker, the CRT and MinGW compatible import libraries.

It should be possible to get raw-dylib working on macOS too as macOS has an import library equivalent in the form of .tbd files, right? Lld should already be able to link for macOS on other targets. For code signing and notarization there is also a rust implementation: PyOxidizer/apple-codesign at main · indygreg/PyOxidizer · GitHub

1 Like

Regarding mac support, there seems to be also this project GitHub - tpoechtrager/osxcross: Mac OS X cross toolchain for Linux, FreeBSD, OpenBSD and Android (Termux), although I haven't tried it out.

1 Like

osxcross relies on the user providing a macos SDK, which afaik is difficult without access to XCode and may run into licensing issues: https://github.com/tpoechtrager/osxcross#packaging-the-sdk.

1 Like

I was aware of the latter two, but not of the possibility of raw-dylib working on macOS. If that's possible, and we could ship an SDK in the style of MinGW, that would be incredible. If anyone has plans to work on that, I'd love to supply whatever support I can, as well as connect them to others who may be interested and supportive.

4 Likes

XCode doesn't ship with dylibs for iOS. Instead the iOS sdk contains .tbd yaml files listing all exported symbols. The macOS sdk also contains .tbd files I believe. I think it would be possible for raw-dylib to produce .tbd files. I think it did only need a couple of extra attributes to specify the install location and dylib version. See ios - Why Xcode 7 shows *.tbd instead of *.dylib? - Stack Overflow for an example of such a file.

Excellent; if we can get cross-linking to link against those, and if we can get some confirmation that those only contain symbols (and thus might be purely descriptive and thus redistributable), that would be a huge win for macOS target usability.

Symbols, paths, UUIDs, version numbers, target OS/architecture identifiers, and a few other bits of metadata. The full format is documented here. It's YAML-based, so easy to inspect.

For the linker itself, lld might work; lld's Mach-O support was recently rewritten in its entirety, mostly by Chromium developers (from a very broken prior state), and Chromium has used it for about a year. On the other hand, Apple has not been contributing to this and still only ships ld64. ld64 is open source, however, and there is a third-party port for running it on other platforms.

I wasn't suggesting distributing the .tbd file, but having libc generate them through raw-dylib.

That would work as well, but it'd be nice if we can generate the Rust code that binds to those symbols by using the tbd files, without creating something we can't redistribute.

Tbd files don't contain any function signatures, so that won't work.

Generating .tbds seems reasonable to me, especially since Darwin has very little additional information introduced at the linking step. No equivalent of Windows' function ordinals or its multiple types of symbols. No equivalent of Linux's symbol versioning (at least, none that's handled by the linker). Even in .tbd files, much of the metadata is not required and doesn't end up getting encoded into the linked binaries. For most purposes you literally just need the library path, the current and compatibility version numbers, and a list of symbol names.

Just to clarify, the startup code is (relatively) trivial. It's fairly easy to do a pure Rust implementation. However, the problem is C++ exception handling which is not so easy to replace. The hope is that the vcruntime will be open sourced under the microsoft/STL but it might still be awhile before that happens.

1 Like

There is GitHub - cloudpeers/xbuild: Cross compile rust to any platform. A tool for cross compiling/packaging rust and flutter applications. Cross compiling is not too difficult. You need to create a sysroot and configure some rust flags to use the sysroot and lld. Packaging is quite a bit harder as it involves a bunch of proprietary file formats, signing schemes, etc. Xbuild works on Linux, Mac, win, android, iOS. I've not worked on it for a while now. If the fact that it has some code to build flutter projects is too repulsive for you, I'm sure there's one or the other thing in the source code that can help you in your endeavors.