Skip to content

Commit a8a49fb

Browse files
committed
musl static linking not glibc
1 parent 7af865b commit a8a49fb

File tree

1 file changed

+71
-81
lines changed

1 file changed

+71
-81
lines changed

src/doc/trpl/advanced-linking.md

+71-81
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ installing the Rust everywhere. By contrast, native libraries
4040
(e.g. `libc` and `libm`) usually dynamically linked, but it is possible to
4141
change this and statically link them as well.
4242

43-
Linking is a very platform dependent topic - on some platforms, static linking
43+
Linking is a very platform dependent topic on some platforms, static linking
4444
may not be possible at all! This section assumes some basic familiarity with
45-
linking on your platform on choice.
45+
linking on your platform of choice.
4646

4747
## Linux
4848

4949
By default, all Rust programs on Linux will link to the system `libc` along with
50-
a number of other libraries. Let's look at an example on a 64-bit linux machine
50+
a number of other libraries. Let's look at an example on a 64-bit Linux machine
5151
with GCC and `glibc` (by far the most common `libc` on Linux):
5252

5353
``` text
@@ -69,91 +69,81 @@ Dynamic linking on Linux can be undesirable if you wish to use new library
6969
features on old systems or target systems which do not have the required
7070
dependencies for your program to run.
7171

72-
The first step in using static linking is examining the Rust linking arguments
73-
with an option to rustc. Newlines have been added for readability:
74-
75-
``` text
76-
$ rustc example.rs -Z print-link-args
77-
"cc"
78-
"-Wl,--as-needed"
79-
"-m64"
80-
[...]
81-
"-o" "example"
82-
"example.o"
83-
"-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive"
84-
"-Wl,--gc-sections"
85-
"-pie"
86-
"-nodefaultlibs"
87-
[...]
88-
"-Wl,--whole-archive" "-Wl,-Bstatic"
89-
"-Wl,--no-whole-archive" "-Wl,-Bdynamic"
90-
"-ldl" "-lpthread" "-lrt" "-lgcc_s" "-lpthread" "-lc" "-lm" "-lcompiler-rt"
91-
```
92-
93-
Arguments with a `-L` before them set up the linker search path and arguments
94-
ending with `.rlib` are linking Rust crates statically into your application.
95-
Neither of these are relevent for static linking so have been ommitted.
96-
97-
The first step in being able to statically link is to obtain an object file.
98-
This can be achieved with `rustc --emit obj example.rs`, and creates a file
99-
called `example.o`, which you can see being passed in the command line above -
100-
rustc automatically deletes it when finished with it by default. As you now have
101-
the object file, you should be able to run the link command obtained with
102-
`print-link-args` to create perform the linking stage yourself.
103-
104-
In order to statically link, there are a number of changes you must make. Below
105-
is the command required to perform a static link; we will go through them each
106-
in turn.
107-
108-
``` text
109-
$ rustc example.rs -Z print-link-args
110-
"cc"
111-
"-static"
112-
"-m64"
113-
[...]
114-
"-o" "example"
115-
"example.o"
116-
"-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive"
117-
"-Wl,--gc-sections"
118-
"-nodefaultlibs"
119-
[...]
120-
"-Wl,--whole-archive"
121-
"-Wl,--no-whole-archive"
122-
"-ldl" "-lpthread" "-lrt" "-lgcc_eh" "-lpthread" "-lc" "-lm" "-lcompiler-rt"
72+
Static linking is supported via an alternative `libc`, `musl` - this must be
73+
enabled at Rust compile-time with some prerequisites available. You can compile
74+
your own version of Rust with `musl` enabled and install it into a custom
75+
directory with the instructions below:
76+
77+
```text
78+
$ mkdir musldist
79+
$ PREFIX=$(pwd)/musldist
80+
$
81+
$ # Build musl
82+
$ wget http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
83+
[...]
84+
$ tar xf musl-1.1.10.tar.gz
85+
$ cd musl-1.1.10/
86+
musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX
87+
[...]
88+
musl-1.1.10 $ make
89+
[...]
90+
musl-1.1.10 $ make install
91+
[...]
92+
musl-1.1.10 $ cd ..
93+
$ du -h musldist/lib/libc.a
94+
2.2M musldist/lib/libc.a
95+
$
96+
$ # Build libunwind.a
97+
$ wget http://llvm.org/releases/3.6.1/llvm-3.6.1.src.tar.xz
98+
$ tar xf llvm-3.6.1.src.tar.xz
99+
$ cd llvm-3.6.1.src/projects/
100+
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk/ libcxxabi
101+
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libunwind/trunk/ libunwind
102+
llvm-3.6.1.src/projects $ sed -i 's#^\(include_directories\).*$#\0\n\1(../libcxxabi/include)#' libunwind/CMakeLists.txt
103+
llvm-3.6.1.src/projects $ mkdir libunwind/build
104+
llvm-3.6.1.src/projects $ cd libunwind/build
105+
llvm-3.6.1.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
106+
llvm-3.6.1.src/projects/libunwind/build $ make
107+
llvm-3.6.1.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
108+
llvm-3.6.1.src/projects/libunwind/build $ cd cd ../../../../
109+
$ du -h musldist/lib/libunwind.a
110+
164K musldist/lib/libunwind.a
111+
$
112+
$ # Build musl-enabled rust
113+
$ git clone https://github.com/rust-lang/rust.git muslrust
114+
$ cd muslrust
115+
muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX
116+
muslrust $ make
117+
muslrust $ make install
118+
muslrust $ cd ..
119+
$ du -h musldist/bin/rustc
120+
12K musldist/bin/rustc
123121
```
124122

125-
- `-static` was added - this is the signal to the compiler to use a static
126-
glibc, among other things
127-
- `-Wl,--as-needed` was removed - this can be left in, but is unnecessary
128-
as it only applies to dynamic librares
129-
- `-pie` was removed - this is not compatible with static binaries
130-
- both `-Wl,-B*` options were removed - everything will be linked statically,
131-
so informing the linker of how certain libraries should be linked is not
132-
appropriate
133-
- `-lgcc_s` was changed to `-lgcc_eh` - `gcc_s` is the GCC support library,
134-
which Rust uses for unwinding support. This is only available as a dynamic
135-
library, so we must specify the static version of the library providing
136-
unwinding support.
137-
138-
By running this command, you will likely see some warnings like
123+
You now have a build of a `musl`-enabled Rust! Because we've installed it to a
124+
custom prefix we need to make sure our system can the binaries and appropriate
125+
libraries when we try and run it:
139126

140-
``` text
141-
warning: Using 'getpwuid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
127+
```text
128+
$ export PATH=$PREFIX/bin:$PATH
129+
$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
142130
```
143131

144-
These should be considered carefully! They indicate calls in glibc which
145-
*cannot* be statically linked without significant extra effort. An application
146-
using these calls will find it is not as portable as 'static binary' would imply.
147-
Rust supports targeting musl as an alternative libc to be able to fully
148-
statically link these calls.
132+
Let's try it out!
149133

150-
As we are confident that our code does not use these calls, we can now see the
151-
fruits of our labour:
152-
153-
```
134+
```text
135+
$ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs
136+
$ rustc --target=x86_64-unknown-linux-musl example.rs
154137
$ ldd example
155138
not a dynamic executable
139+
$ ./example
140+
hi!
141+
thread '<main>' panicked at 'failed', example.rs:1
156142
```
157143

158-
This binary can be copied to virtually any 64-bit Linux machine and work
159-
without requiring external libraries.
144+
Success! This binary can be copied to almost any Linux machine with the same
145+
machine architecture and run without issues.
146+
147+
`cargo build` also permits the `--target` option so you should be able to build
148+
your crates as normal. However, you may need to recompile your native libraries
149+
against `musl` before they can be linked against.

0 commit comments

Comments
 (0)