@@ -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