pub struct LinkLine {
pub start: Vec<PathBuf>,
pub libraries: Vec<PathBuf>,
pub end: Vec<PathBuf>,
}Expand description
The inputs to a link, in the three groups a linker needs them in.
Paths rather than strings, and no flags at all, because
spec/cross-compile/11-linking.md owns which linker is invoked and how its arguments are
spelled and crate::argv is where that happens. What is here is what has to be linked and in
what order, which is a target fact and the same fact whichever linker reads it.
Fields§
§start: Vec<PathBuf>The start files, before the user’s objects.
libraries: Vec<PathBuf>The libraries, after the user’s objects.
end: Vec<PathBuf>The end files, after the libraries.
Implementations§
Source§impl LinkLine
impl LinkLine
Sourcepub fn for_target(
sysroot: &Sysroot,
mode: LinkMode,
builtins: Option<&Path>,
) -> Self
pub fn for_target( sysroot: &Sysroot, mode: LinkMode, builtins: Option<&Path>, ) -> Self
The line for a link against this sysroot, whichever libc the target names.
The dispatch rather than the line, and it is libc that decides: a real archive, a stub
shared object, or nothing. The three methods below are the three answers. A target whose
sysroot we do not produce yet still gets the right shape, because the shape follows from
whether the libc on the target machine is an archive or a shared object and that is known
before any of it is built.
The runtime is a path from the caller rather than a name joined onto the sysroot, and
None means it is not on this machine and the line goes without it. Whether that is worth
refusing over is the driver’s question, since the driver is what knows whether it looked.
Sourcepub fn freestanding(builtins: Option<&Path>) -> Self
pub fn freestanding(builtins: Option<&Path>) -> Self
The line for a freestanding link against this sysroot, which is our runtime and nothing else.
Section 8.2’s first row: nine compiler headers and no link inputs. There is no crt1.o,
because nothing here decides what runs before main or whether there is a main at all, and
no crti.o or crtn.o, because those come from a libc too. A kernel or a bootloader brings
its own start file and says so with -nostartfiles, which it would have to pass anyway.
librucc_builtins.a stays, because it is ours rather than the platform’s.
spec/cross-compile/10-runtime.md is the argument: an architecture with no division
instruction needs __divti3 whether there is a libc in the picture or not, and freestanding
code that does 64-bit arithmetic on a 32-bit target reaches it without asking.
The mode is not a parameter because it changes nothing here. Every difference between the modes is a start file and there are none. Neither is the sysroot, now that the one file on this line is not in it: a freestanding link reads headers out of a sysroot and links nothing out of one.
Sourcepub fn musl(sysroot: &Sysroot, mode: LinkMode, builtins: Option<&Path>) -> Self
pub fn musl(sysroot: &Sysroot, mode: LinkMode, builtins: Option<&Path>) -> Self
The line for a musl link against this sysroot.
crt1.o runs before main and calls it. crti.o and crtn.o are the prologue and the
epilogue of the .init and .fini sections, which is why one is at the front and the other
is at the very back. libc.a carries musl’s whole C library, and librucc_builtins.a
carries the operations the architecture does not have an instruction for, which
spec/cross-compile/10-runtime.md says has to be ours rather than the platform’s.
The builtins go after libc.a because musl calls some of them, and an archive that is
searched before the thing that needs it contributes nothing.
libc.a on every mode including the dynamic ones, because what a musl sysroot here holds is
musl built static: section 9.3 takes musl first precisely because one tarball built one way
exercises the whole pipeline, and a shared musl is a second build of it that buys nothing
until somebody asks for a dynamically linked musl program.
Sourcepub fn glibc(sysroot: &Sysroot, mode: LinkMode, builtins: Option<&Path>) -> Self
pub fn glibc(sysroot: &Sysroot, mode: LinkMode, builtins: Option<&Path>) -> Self
The line for a link against a generated stub, which is glibc and every other hosted libc that is not musl.
Named for glibc because glibc is the case spec/cross-compile/09-libc-stubs.md is written
about and the hard one. bionic, the BSDs and illumos reach the same line for the same reason:
their libc is a shared object on the target machine, so a list of the names it exports is
enough to link against it, and that is what rucc-stub produces. The paragraphs below about
libc_nonshared.a and libm are glibc’s own.
The same start files as musl’s and different libraries. A stub libc is linked against
dynamically, so what goes on the line is the libc.so rucc-stub wrote into
Sysroot::stubs rather than an archive, and the version nodes in it are what make a
program built here run on an older machine. The driver writes it before the link, cut at
the release the tuple names, and the directory is on the line as a -L too so that -lm
and -lpthread find their stubs there.
libc_nonshared.a comes next and out of the sysroot. glibc’s own libc.so is a linker
script naming libc.so.6, libc_nonshared.a and the loader as a group, and that archive
holds real compiled objects: atexit, __stack_chk_fail_local on i386, and the stat
family on releases before 2.33. None of it can be written from a description, because a
stub is a list of names and these are bodies, so it is built from glibc’s sources and
fetched with the start files. It goes after the stub because what is in it calls into
libc, which is the order glibc’s script gives them. It is glibc’s alone, so bionic and the
BSDs get the stub and nothing between it and our runtime.
The archive in the sysroot is 2.44’s, and 2.44’s has no stat in it, because 2.33 moved the
family into libc.so.6. A target pinned before 2.33 gets libc_nonshared_stat.a after it,
which rucc-cross builds the way 2.32 built those ten functions, each a call to __xstat or
one of its siblings. Without it a program that calls stat links at -O2, where the old
headers inline the call, and not at -O0. A target with no pin is the newest release and
does not get it.
libm.so is not on the line, and that is a decision. glibc’s libm is real code and a
program that wants it passes -lm, which every build system that does arithmetic already
does, so putting it on every line would record a dependency the program does not have.
A static glibc link is not one of these: there is no libc.a in a sysroot whose libc is a
stub, because a stub is a list of names and a static link needs bodies.
crate::argv::argv refuses that combination by name rather than producing this line with
-static in front of it.
Sourcepub fn mingw(sysroot: &Sysroot, mode: LinkMode, builtins: Option<&Path>) -> Self
pub fn mingw(sysroot: &Sysroot, mode: LinkMode, builtins: Option<&Path>) -> Self
The line for a mingw-w64 link against this sysroot.
One start file and no end file, which is the first thing that is different from every ELF
line above. crt2.o runs before main and calls it, dllcrt2.o is its counterpart for a
DLL, and there is no crti.o and no crtn.o because PE has no .init and .fini sections
for a pair of files to open and close. What those two bracket on ELF is done on Windows by a
table of pointers in the .CRT$XC sections, which the linker sorts by section name, so the
ordering problem the three groups exist for does not arise here.
crtbegin.o and crtend.o are deliberately absent. They are GCC’s files rather than
mingw-w64’s, they bracket GCC’s own list of constructors, and a toolchain that is not GCC
writes that list the way the platform writes it instead. Ours is not written yet: a mingw
link runs main and does not run a file scope constructor, which is a known gap that belongs
with the sysroot build rather than with the line, and the gap is in the codegen for the
format rather than here.
The libraries are a set rather than one file, because the C library on Windows is several
DLLs and the CRT calls into the system ones. libmingw32.a holds the start code crt2.o
calls, libmoldname.a is the layer that gives the old unprefixed spellings of the names
Microsoft deprecated, libmingwex.a is everything C requires that the CRT does not have, and
libmsvcrt.a is the import library for the CRT itself. Then the four Win32 libraries that
mingw-w64’s own code calls into, which are on the line for the same reason they are on gcc’s:
a program that uses none of them directly still reaches kernel32 through malloc.
libmsvcrt.a is the right name for either CRT, which is why nothing here asks the sysroot
which one it has. mingw-w64 installs it as a copy of the default runtime’s import library, so
in the UCRT sysroot this compiler fetches it is libucrt.a and names the api-ms-win-crt-*
API sets, and in a -msvcrt sysroot it names msvcrt.dll. gcc’s spec says -lmsvcrt on a
UCRT toolchain for the same reason, so the line follows the sysroot without being told.
-pthread adds -lpthread after the objects, as on every other target, and the sysroot’s
libpthread.a is winpthreads, built static so the program needs no libwinpthread-1.dll.
It is not on this line otherwise. A gcc built with the posix thread model lists it for every
program, and a program that asked for no threads has nothing to take from it.
The order is the one a single pass linker needs, which is GNU ld’s PE port: a library after
everything that calls into it. librucc_builtins.a is last for the reason it is last on the
musl line, which is that the things before it call it and it calls none of them. lld’s COFF
linker resolves archives to a fixed point and does not care about any of this, and writing
the line for the stricter of the two is what makes one line serve both.
Sourcepub fn msvc(crt: Crt, builtins: Option<&Path>) -> Self
pub fn msvc(crt: Crt, builtins: Option<&Path>) -> Self
The line for a program in Microsoft’s environment, linked against the CRT crt names.
No start file, because the one Microsoft ships is not a file of its own. mainCRTStartup is
a member of libcmt.lib, or of msvcrt.lib for the other runtime, and the linker picks it
as the entry point because the program defines main, so the start of the program is left
to the CRT the way cl.exe leaves it. The mode is not a parameter for the same reason: a
DLL is started by _DllMainCRTStartup, which is in the same libraries.
Names rather than paths, which is where this differs from every other line here. The tree
keeps the CRT in crt/lib and the SDK’s libraries in two directories of sdk/lib, and
crate::argv names those directories to the linker, which is how lld-link and
link.exe both look for a library and how a -L of the user’s own gets in front of ours.
kernel32.lib because the CRT calls into it and says so only in a directive, and
oldnames.lib because it is what makes open and strdup mean _open and _strdup,
which a C program written for anything but Windows calls by the old names. Ours goes last,
the same as on the mingw-w64 line, so that the CRT answers for everything it has.
Sourcepub fn with_objects(&self, objects: &[PathBuf]) -> Vec<PathBuf>
pub fn with_objects(&self, objects: &[PathBuf]) -> Vec<PathBuf>
Every input, in the order they reach the linker, with the caller’s objects in the middle.
The one function that knows the whole order, so that a caller cannot assemble the three groups in the wrong sequence.