@@ -41,12 +41,12 @@ linked by default, but sometimes it can be useful to change this.
41
41
42
42
Linking is a very platform dependant topic - on some platforms, static linking
43
43
may not be possible at all! This section assumes some basic familiarity with
44
- linking on your platform on choice.
44
+ linking on your platform of choice.
45
45
46
46
## Linux
47
47
48
48
By default, all Rust programs on Linux will link to the system libc along with
49
- a number of other libraries Let's look at an example on a 64-bit linux machine
49
+ a number of other libraries. Let's look at an example on a 64-bit linux machine
50
50
with GCC and glibc (by far the most common libc on Linux):
51
51
52
52
``` text
@@ -68,91 +68,81 @@ Dynamic linking on Linux can be undesirable if you wish to target older
68
68
machines as applications compiled aginst newer versions glibc are not
69
69
guaranteed to run against older versions.
70
70
71
- You can examine Rust linking arguments with an option to rustc. Newlines have
72
- been added for readability:
71
+ Static linking supported via an alternative libc, musl - this must be enabled
72
+ at rust compile-time with some prerequisites available. You can compile your
73
+ own version of rust with musl enabled and install it into a custom directory
74
+ with the instructions below:
73
75
74
- ``` text
75
- $ rustc example.rs -Z print-link-args
76
- "cc"
77
- "-Wl,--as-needed"
78
- "-m64"
79
- [...]
80
- "-o" "example"
81
- "example.o"
82
- "-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive"
83
- "-Wl,--gc-sections"
84
- "-pie"
85
- "-nodefaultlibs"
86
- [...]
87
- "-Wl,--whole-archive" "-Wl,-Bstatic"
88
- "-Wl,--no-whole-archive" "-Wl,-Bdynamic"
89
- "-ldl" "-lpthread" "-lrt" "-lgcc_s" "-lpthread" "-lc" "-lm" "-lcompiler-rt"
90
76
```
91
-
92
- Arguments with a ` -L ` before them set up the linker search path and arguments
93
- ending with ` .rlib ` are linking Rust crates statically into your application.
94
- Neither of these are relevent for static linking so have been ommitted.
95
-
96
- The first step in being able to statically link is to obtain an object file.
97
- This can be achieved with ` rustc --emit obj example.rs ` , and creates a file
98
- called ` example.o ` , which you can see being passed in the command line above -
99
- rustc automatically deletes it when finished with it by default. As you now have
100
- the object file, you should be able to run the link command obtained with
101
- ` print-link-args ` to create perform the linking stage yourself.
102
-
103
- In order to statically link, there are a number of changes you must make. Below
104
- is the command required to perform a static link; we will go through them each
105
- in turn.
106
-
107
- ``` text
108
- $ rustc example.rs -Z print-link-args
109
- "cc"
110
- "-static"
111
- "-m64"
112
- [...]
113
- "-o" "example"
114
- "example.o"
115
- "-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive"
116
- "-Wl,--gc-sections"
117
- "-nodefaultlibs"
118
- [...]
119
- "-Wl,--whole-archive"
120
- "-Wl,--no-whole-archive"
121
- "-ldl" "-lpthread" "-lrt" "-lgcc_eh" "-lpthread" "-lc" "-lm" "-lcompiler-rt"
77
+ $ mkdir musldist
78
+ $ PREFIX=$(pwd)/musldist
79
+ $
80
+ $ # Build musl
81
+ $ wget http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
82
+ [...]
83
+ $ tar xf musl-1.1.10.tar.gz
84
+ $ cd musl-1.1.10/
85
+ musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX
86
+ [...]
87
+ musl-1.1.10 $ make
88
+ [...]
89
+ musl-1.1.10 $ make install
90
+ [...]
91
+ musl-1.1.10 $ cd ..
92
+ $ du -h musldist/lib/libc.a
93
+ 2.2M musldist/lib/libc.a
94
+ $
95
+ $ # Build libunwind.a
96
+ $ wget http://llvm.org/releases/3.6.1/llvm-3.6.1.src.tar.xz
97
+ $ tar xf llvm-3.6.1.src.tar.xz
98
+ $ cd llvm-3.6.1.src/projects/
99
+ llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk/ libcxxabi
100
+ llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libunwind/trunk/ libunwind
101
+ llvm-3.6.1.src/projects $ sed -i 's#^\(include_directories\).*$#\0\n\1(../libcxxabi/include)#' libunwind/CMakeLists.txt
102
+ llvm-3.6.1.src/projects $ mkdir libunwind/build
103
+ llvm-3.6.1.src/projects $ cd libunwind/build
104
+ llvm-3.6.1.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
105
+ llvm-3.6.1.src/projects/libunwind/build $ make
106
+ llvm-3.6.1.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
107
+ llvm-3.6.1.src/projects/libunwind/build $ cd cd ../../../../
108
+ $ du -h musldist/lib/libunwind.a
109
+ 164K musldist/lib/libunwind.a
110
+ $
111
+ $ # Build musl-enabled rust
112
+ $ git clone https://github.com/rust-lang/rust.git muslrust
113
+ $ cd muslrust
114
+ muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX
115
+ muslrust $ make
116
+ muslrust $ make install
117
+ muslrust $ cd ..
118
+ $ du -h musldist/bin/rustc
119
+ 12K musldist/bin/rustc
122
120
```
123
121
124
- - ` -static ` was added - this is the signal to the compiler to use a static
125
- glibc, among other things
126
- - ` -Wl,--as-needed ` was removed - this can be left in, but is unnecessary
127
- as it only applies to dynamic librares
128
- - ` -pie ` was removed - this is not compatible with static binaries
129
- - both ` -Wl,-B* ` options were removed - everything will be linked statically,
130
- so informing the linker of how certain libraries should be linked is not
131
- appropriate
132
- - ` -lgcc_s ` was changed to ` -lgcc_eh ` - ` gcc_s ` is the GCC support library,
133
- which Rust uses for unwinding support. This is only available as a dynamic
134
- library, so we must specify the static version of the library providing
135
- unwinding support.
136
-
137
- By running this command, you will likely see some warnings like
122
+ You now have a build of a musl-enabled rust! Because we've installed it to a
123
+ custom prefix we need to make sure our system can the binaries and appropriate
124
+ libraries when we try and run it:
138
125
139
- ``` text
140
- warning: Using 'getpwuid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
126
+ ```
127
+ $ export PATH=$PREFIX/bin:$PATH
128
+ $ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
141
129
```
142
130
143
- These should be considered carefully! They indicate calls in glibc which
144
- * cannot* be statically linked without significant extra effort. An application
145
- using these calls will find it is not as portable as 'static binary' would imply.
146
- Rust supports targeting musl as an alternative libc to be able to fully
147
- statically link these calls.
148
-
149
- As we are confident that our code does not use these calls, we can now see the
150
- fruits of our labour:
131
+ Let's try it out!
151
132
152
133
```
134
+ $ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs
135
+ $ rustc --target=x86_64-unknown-linux-musl example.rs
153
136
$ ldd example
154
137
not a dynamic executable
138
+ $ ./example
139
+ hi!
140
+ thread '<main>' panicked at 'failed', example.rs:1
155
141
```
156
142
157
- This binary can be copied to virtually any 64-bit Linux machine and work
158
- without requiring external libraries.
143
+ Success! This binary can be copied to almost any Linux machine with the same
144
+ machine architecture and run without issues.
145
+
146
+ ` cargo build ` also permits the ` --target ` option so you should be able to build
147
+ your crates as normal. However, you may need to recompile your native libraries
148
+ against musl before they can be linked against.
0 commit comments