Does `target.linker` influence the C compiler for *-sys crates?

I'm targeting aarch64-unknown-linux-gnu and building openssl-sys with the vendored feature enabled. If have an cross toolchain installed, so I can specify target.linker = aarch64-linux-gnu-gcc and it successfully builds. I'm wondering why I don't need to also specify the compiler/archiver as well. Does setting linker imply that rustc should use the associated toolchain of said linker?

Thanks!

Typically sys crates don't do any linking.

  • They either make or find you a static library, which isn't really a library, but a bunch of unlinked object files.
  • Or you emit a "please link to this later" directive for dynamic libraries, which have already been linked long before you even installed them on your system.

Cargo doesn't support building and linking Rust dependencies as dylibs (as opposed to the internal rlib format for staticlaly-linked Rust dependencies), and doesn't have features for managing install paths of dylibs, so there isn't really a viable third option for building dylibs on the fly for the current Rust build.

Sure, that all makes sense. I'm more wondering for the static case how it actually builds the C code.

Static libraries are not linked by the sys crates, by definition. They're not a binary. They're an ar archive, which is like a .zip file of .o files before linking. There is nothing linker-specific about the ar files.

Static libraries are an unfinished product that is later fed to to the linker along with all other object files and other static libraries to produce the final Rust program or dylib. That happens only after sys crates finish running.

sys crates that build code typically use the cc crate, which can be configured with environment variables: GitHub - rust-lang/cc-rs: Rust library for build scripts to compile C/C++ code into a Rust library

Interesting, maybe I'm using the wrong terminology. I thought that when I depend on openssl-sys, with the vendored features, that that enabled the openssl-src feature which adds a dependency that literally contains the openssl source code, builds that, and statically links it into my Rust binary.

In my case, CC and CXX point to clang (on mac) which I wouldn't expect to work at vendoring openssl for aarch64

Though I guess clang is a cross-compiler without needing a separate toolchain, sans the linker?

Clang would still need a cross-sysroot to work with, and the right -target passed to it.

There is a chance that OpenSSL's build glue looks for the standard target-prefixed cross compiler on your PATH, which could be what's making it "just work".

That's what I assume it must be doing, but then rustc doesn't try to be so "clever" and needs an explicit linker argument?

Yeah, I think that rustc will just use cc unless you override though I am not 100% confident there.

And all of that vendored openssl build literally does not touch the linker at any point. It uses the compiler, archiver, but no linker.

Dynamic libraries are made by compiling and linking, and static libraries are made by compiling and NOT linking. That's the primary difference between them. If you use a linker on a static library, it's not going to be a static library any more.

Another way to think about it is that linker can be run only once, as the final step in making a binary. If you're building a Rust executable, this means the one and only invocation of the linker happened when Rust/Cargo created the executable, and nowhere earlier in the process of building dependencies.

3 Likes

I see what you're saying. The build fails at the very last step due to the linker not knowing how to assemble the final binary for the target platform (?). As for actually producing assembly, the openssl build crate likely looks for the cross toolchain in my path.

After uninstalling the cross toolchain, cargo was still able to compile all the crates, including openssl-sys, which makes me thing that it is just using clangs inherent cross compiling capabilities? It still failed the final link step, obviously.

Yeah, after removing clang from my path and re-running the build, it fails to find cc, which pointed to clang.

Are you sure it actually built a functional cross OpenSSL? If it was actually build targeting macOS you wouldn't find out until the final link failed.

Clang is able to generate code for whatever architecture, but without a sysroot with headers, a libc, etc it can't do much.

That's a good point, I guess it could compile but not produce a working build.