Skip to main content

Module link

Module link 

Source
Expand description

Finding a linker and telling it what to link.

Design: spec/04-driver-and-cli.md section 4.9. There is no linker of our own before 1.0, so this finds one on the machine and builds the command line it wants.

The linker is invoked directly rather than through the system compiler driver. Going through cc would be shorter to write and would borrow that compiler’s idea of where everything is, and it would also mean this compiler cannot link on a machine that has no other compiler on it, which is most of the machines a compiler ends up on. It would also make -### output a line that does not say what happens, since the interesting half would be inside the program being spawned.

§What is not decided here

The startup files and the library directories are looked for rather than configured, for the same reason library looks for the headers: gcc settles this when it is built because a gcc is built for the machine it will run on, and this is one binary that runs wherever it is copied. So the shape of the answer is a list of candidates per platform of which the ones that exist are taken, and a cross build says where the rest is with --sysroot.

§The compiler’s own runtime

crtbegin, crtend and the runtime libraries are found the same way, on the machine rather than by configuration. Ours is librucc_builtins.a, looked for beside the compiler, and the machine’s libgcc goes on after it for the parts we have not written, which today is the unwinder and its personality routine. The C library goes in front of both, so that on a target that has one its memcpy is the one that answers rather than ours. -fno-builtins-lib leaves ours off, for somebody who wants libgcc to answer for everything.

On a static link the three archives go inside --start-group, because libc.a refers to the unwinder and the unwinder refers back to libc.a, and a linker walking a list once resolves whichever of the two it reaches first and leaves the other undefined. That circularity is the whole reason -static failed before this, and it is issue #277.

§Linking for a machine that is not this one

Everything above describes a link against the machine running the compiler, and it is what runs when the target is that machine. A target that is not is a different problem: there is no crt1.o for it in /usr/lib, the libc.so there is the wrong architecture, and a line built out of what is lying around either fails at the first input or, worse, links. So a cross link does not look at this machine at all. It is built by rucc_sysroot::argv out of the target and a sysroot under the cache directory, and spec/cross-compile/11-linking.md section 11.3 is the design. cross_sysroot is the one place that decides which of the two it is.

Two conditions keep that out of the way of everything that works today. The target has to differ from the host, and --sysroot must not have been given: somebody who assembled a tree and named it is asking for the line above with their own root in front of every path, which is what a cross compile with a real distribution tree in it has always been.

That second condition is also the escape hatch for a machine which has a distribution’s own cross files installed, where /usr/lib/aarch64-linux-gnu really does hold an AArch64 crt1.o. --sysroot=/ takes the line above, and then every directory it decides is that machine’s again.

§What is not here yet

Darwin, and Windows in Microsoft’s ABI. ld64 wants a platform version load command and a different set of default libraries, and lld-link wants a /-style command line and an import library set out of an SDK nobody may redistribute. Each arrives with the target that needs it, and a cross link to either is refused by name rather than approximated. A mingw-w64 target does have a line, because PE in that environment is written in the GNU style and the import libraries for it are ours to produce.

The headers are the other half of a cross compile and crate::library::header_dirs is where they are decided. It asks cross_sysroot the same question this file asks it, which is the point: a compile that took its libc from the sysroot and its declarations from this machine would be wrong in the quietest way available, and one function answering for both is what stops that being possible.

Structs§

LinkOptions
What the command line said about linking.
Linker
A linker, found.

Enums§

Error
Why a link could not be run.
Item
One item on the link line, in the order it was written, because link order is semantic.

Functions§

builtins_archive
Our own runtime library for this target, if it was built.
candidates
Where the library’s own files might be, in search order.
cross_kernel
The kernel headers that go with cross_sysroot, for the targets that have any.
cross_sysroot
The sysroot a cross link would use, or None for a link against this machine.
find
The linker to use, looked for where a linker is.
find_in_search
The full path of a file with that name, when one of the search directories holds it.
line
What the linker is told, in order, not counting the linker itself.
multiarch
The name a distribution that holds two architectures at once files this target under.
order
The names to look for, in the order section 4.9 gives.
preflight
Whether this link can be run at all, asked before anything is compiled.
render
The whole invocation as one line, quoted the way -### prints it.
run
Runs the linker and waits for it.
runtime_dirs
Where a gcc on this machine keeps crtbegin.o, crtend.o and libgcc.a, newest first.
search_dirs
Where a library is looked for, in the order it is looked for in.