Thoughts on the LLVM linker


I am using LLVM as the backend in a small hobby compiler project I’m working on. I plan to support all platforms that LLVM supports (limited by my available hardware only).

As far as I can tell, there are different linkers for the various host systems out there (the output of ‘lld’ if you invoke it on Arch Linux):

lld is a generic driver.
Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld (WebAssembly) instead

I am wondering if there are any plans to make a single, standard, cross-platform link tool so that people who are not locked into the Microsoft ecosystem (Visual Studio and command-line tools) can use the LLVM linker without having to maintain three driver interfaces. If I am not mistaken, you today have to use three or four different interfaces, depending on the host platform, just to link a few files.

The way I see it, a single LLVM-linker with the same options and syntax on all platforms would be highly beneficial to those who use LLVM as their backend through generating .ll files as input to the LLVM tool chain.

P.S. I am aware that I can use Clang as a gigantic driver for the linking process, but I am trying to get rid of all Clang dependencies because it is not needed by my project in any way.

Thank you,
Mikael Egevig

The reason why we have different command line interfaces for different platforms is simply because they are actually different. It is not because lld is Windows-centric (it’s not.)

The native linkers for these major platforms (e.g. link.exe or /usr/bin/ld) are quite different in terms of behavior. It’s because native linkers have evolved separately in their environment for dozens of years. Each linker has evolved their own vocabulary (e.g. command line parameters) over the course of their history, sometimes borrowing concepts and command line flags from others, but they rarely made dead-copy features. Instead, they adjusted concepts to fit to their platform. So even if two command line options have the same or very similar names, they are not quite the same. So, if you create a unified command line interface, you’d likely end up with -unix-foo, -windows-foo, -mac-foo to support option -foo. You cannot merge them to option -foo by ignoring subtle differences.

WebAssembly is quite new, but they are pretty different from other binary formats because it is not a native binary format. For example, functions don’t have addresses in wasm because they live outside of the wasm execution environment. As a result, even though wasm-ld borrows many options from Unix, it naturally has many wasm-specific command line options, and the options don’t make sense for non-wasm targets.

The other problem of an imaginary unified driver is that it allows to use impossible combinations of features. Most command line options make sense for only one target, but if your linker accepts all options of all platforms, you would have to define some reasonable behaviors for all unprecedented combinations of features. That is actually a very difficult problem to solve. (Of course you can solve the issue by disallowing all combinations of command line flags of different targets, but that nullifies the point of creating a unified driver.)

So, yeah, it may look a bit silly to have different command line interfaces for all these targets, but I think it technically makes sense.

Okay, I understand. Thanks for your explanation :slight_smile: