@@ -47,3 +47,129 @@ meaning.
4747It is highly recommended to * not* use this attribute, and rather use the more
4848formal ` #[link(...)] ` attribute on ` extern ` blocks instead.
4949
50+ # Static linking
51+
52+ Static linking refers to the process of creating output that contain all
53+ required libraries and so don't need libraries installed on every system where
54+ you want to use your compiled project. Rust libraries are statically linked by
55+ default so you can use Rust-created binaries and libraries without installing
56+ the Rust runtime everywhere. By contrast, native libraries are dynamically
57+ linked by default, but sometimes it can be useful to change this.
58+
59+ Linking is a very platform dependant topic - on some platforms, static linking
60+ may not be possible at all! This section assumes some basic familiarity with
61+ linking on your platform on choice.
62+
63+ ## Linux
64+
65+ By default, all Rust programs on Linux will link to the system libc along with
66+ a number of other libraries Let's look at an example on a 64-bit linux machine
67+ with GCC and glibc (by far the most common libc on Linux):
68+
69+ ``` text
70+ $ cat example.rs
71+ fn main() {}
72+ $ rustc example.rs
73+ $ ldd example
74+ linux-vdso.so.1 => (0x00007ffd565fd000)
75+ libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa81889c000)
76+ libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa81867e000)
77+ librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa818475000)
78+ libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa81825f000)
79+ libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa817e9a000)
80+ /lib64/ld-linux-x86-64.so.2 (0x00007fa818cf9000)
81+ libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa817b93000)
82+ ```
83+
84+ Dynamic linking on Linux can be undesirable if you wish to target older
85+ machines as applications compiled aginst newer versions glibc are not
86+ guaranteed to run against older versions.
87+
88+ You can examine Rust linking arguments with an option to rustc. Newlines have
89+ been added for readability:
90+
91+ ``` text
92+ $ rustc example.rs -Z print-link-args
93+ "cc"
94+ "-Wl,--as-needed"
95+ "-m64"
96+ [...]
97+ "-o" "example"
98+ "example.o"
99+ "-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive"
100+ "-Wl,--gc-sections"
101+ "-pie"
102+ "-nodefaultlibs"
103+ [...]
104+ "-Wl,--whole-archive" "-Wl,-Bstatic"
105+ "-Wl,--no-whole-archive" "-Wl,-Bdynamic"
106+ "-ldl" "-lpthread" "-lrt" "-lgcc_s" "-lpthread" "-lc" "-lm" "-lcompiler-rt"
107+ ```
108+
109+ Arguments with a ` -L ` before them set up the linker search path and arguments
110+ ending with ` .rlib ` are linking Rust crates statically into your application.
111+ Neither of these are relevent for static linking so have been ommitted.
112+
113+ The first step in being able to statically link is to obtain an object file.
114+ This can be achieved with ` rustc --emit obj example.rs ` , and creates a file
115+ called ` example.o ` , which you can see being passed in the command line above -
116+ rustc automatically deletes it when finished with it by default. As you now have
117+ the object file, you should be able to run the link command obtained with
118+ ` print-link-args ` to create perform the linking stage yourself.
119+
120+ In order to statically link, there are a number of changes you must make. Below
121+ is the command required to perform a static link; we will go through them each
122+ in turn.
123+
124+ ``` text
125+ $ rustc example.rs -Z print-link-args
126+ "cc"
127+ "-static"
128+ "-m64"
129+ [...]
130+ "-o" "example"
131+ "example.o"
132+ "-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive"
133+ "-Wl,--gc-sections"
134+ "-nodefaultlibs"
135+ [...]
136+ "-Wl,--whole-archive"
137+ "-Wl,--no-whole-archive"
138+ "-ldl" "-lpthread" "-lrt" "-lgcc_eh" "-lpthread" "-lc" "-lm" "-lcompiler-rt"
139+ ```
140+
141+ - ` -static ` was added - this is the signal to the compiler to use a static
142+ glibc, among other things
143+ - ` -Wl,--as-needed ` was removed - this can be left in, but is unnecessary
144+ as it only applies to dynamic librares
145+ - ` -pie ` was removed - this is not compatible with static binaries
146+ - both ` -Wl,-B* ` options were removed - everything will be linked statically,
147+ so informing the linker of how certain libraries should be linked is not
148+ appropriate
149+ - ` -lgcc_s ` was changed to ` -lgcc_eh ` - ` gcc_s ` is the GCC support library,
150+ which Rust uses for unwinding support. This is only available as a dynamic
151+ library, so we must specify the static version of the library providing
152+ unwinding support.
153+
154+ By running this command, you will likely see some warnings like
155+
156+ ``` text
157+ warning: Using 'getpwuid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
158+ ```
159+
160+ These should be considered carefully! They indicate calls in glibc which
161+ * cannot* be statically linked without significant extra effort. An application
162+ using these calls will find it is not as portable as 'static binary' would imply.
163+ Rust supports targeting musl as an alternative libc to be able to fully
164+ statically link these calls.
165+
166+ As we are confident that our code does not use these calls, we can now see the
167+ fruits of our labour:
168+
169+ ```
170+ $ ldd example
171+ not a dynamic executable
172+ ```
173+
174+ This binary can be copied to virtually any 64-bit Linux machine and work
175+ without requiring external libraries.
0 commit comments