Skip to content

Commit 483d805

Browse files
committed
Add ARM MUSL targets.
The targets are: - `arm-unknown-linux-musleabi` - `arm-unknown-linux-musleabihf` - `armv7-unknown-linux-musleabihf` These mirror the existing `gnueabi` targets. All of these targets produce fully static binaries, similar to the x86 MUSL targets. For now these targets can only be used with `--rustbuild` builds, as rust-lang/compiler-rt#22 only made the necessary compiler-rt changes in the CMake configs, not the plain GNU Make configs. I've tested these targets GCC 5.3.0 compiled again musl-1.1.12 (downloaded from http://musl.codu.org/). An example `./configure` invocation is: ``` ./configure \ --enable-rustbuild --target=arm-unknown-linux-musleabi \ --musl-root="$MUSL_ROOT" ``` where `MUSL_ROOT` points to the `arm-linux-musleabi` prefix. Usually that path will be of the form `/foobar/arm-linux-musleabi/arm-linux-musleabi`. Usually the cross-compile toolchain will live under `/foobar/arm-linux-musleabi/bin`. That path should either by added to your `PATH` variable, or you should add a section to your `config.toml` as follows: ``` [target.arm-unknown-linux-musleabi] cc = "/foobar/arm-linux-musleabi/bin/arm-linux-musleabi-gcc" cxx = "/foobar/arm-linux-musleabi/bin/arm-linux-musleabi-g++" ``` As a prerequisite you'll also have to put a cross-compiled static `libunwind.a` library in `$MUSL_ROOT/lib`. This is similar to [how the x86_64 MUSL targets are built] (https://doc.rust-lang.org/book/advanced-linking.html).
1 parent 51153db commit 483d805

20 files changed

+225
-90
lines changed

configure

+1-1
Original file line numberDiff line numberDiff line change
@@ -1176,7 +1176,7 @@ do
11761176
;;
11771177

11781178

1179-
x86_64-*-musl)
1179+
x86_64-*-musl | arm-*-musleabi)
11801180
if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ]
11811181
then
11821182
err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"

mk/cfg/arm-unknown-linux-musleabi.mk

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# This file is intentially left empty to indicate that, while this target is
2+
# supported, it's not supported using plain GNU Make builds. Use a --rustbuild
3+
# instead.
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# This file is intentially left empty to indicate that, while this target is
2+
# supported, it's not supported using plain GNU Make builds. Use a --rustbuild
3+
# instead.
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# This file is intentially left empty to indicate that, while this target is
2+
# supported, it's not supported using plain GNU Make builds. Use a --rustbuild
3+
# instead.

src/bootstrap/build/compile.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ pub fn std_link(build: &Build,
8282
}
8383
add_to_sysroot(&out_dir, &libdir);
8484

85-
if target.contains("musl") &&
86-
(target.contains("x86_64") || target.contains("i686")) {
85+
if target.contains("musl") && !target.contains("mips") {
8786
copy_third_party_objects(build, target, &libdir);
8887
}
8988
}

src/bootstrap/build/native.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@ pub fn compiler_rt(build: &Build, target: &str) {
125125
target.contains("netbsd") {
126126
let os = if target.contains("android") {"-android"} else {""};
127127
let arch = if arch.starts_with("armv7") {
128-
"armv7"
128+
"armv7"
129129
} else if arch.starts_with("arm") {
130-
if target.contains("eabihf") || target.contains("android") {
131-
"armhf"
132-
} else {
133-
"arm"
134-
}
130+
if target.contains("eabihf") || target.contains("android") {
131+
"armhf"
132+
} else {
133+
"arm"
134+
}
135135
} else {
136136
arch
137137
};

src/bootstrap/build/sanity.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub fn check(build: &mut Build) {
8888
}
8989

9090
// Make sure musl-root is valid if specified
91-
if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
91+
if target.contains("musl") && !target.contains("mips") {
9292
match build.config.musl_root {
9393
Some(ref root) => {
9494
if fs::metadata(root.join("lib/libc.a")).is_err() {

src/liballoc_jemalloc/build.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,16 @@ fn main() {
4646
.replace("\\", "/"))
4747
.current_dir(&build_dir)
4848
.env("CC", compiler.path())
49-
.env("EXTRA_CFLAGS", cflags)
49+
.env("EXTRA_CFLAGS", cflags.clone())
50+
// jemalloc generates Makefile deps using GCC's "-MM" flag. This means
51+
// that GCC will run the preprocessor, and only the preprocessor, over
52+
// jemalloc's source files. If we don't specify CPPFLAGS, then at least
53+
// on ARM that step fails with a "Missing implementation for 32-bit
54+
// atomic operations" error. This is because no "-march" flag will be
55+
// passed to GCC, and then GCC won't define the
56+
// "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
57+
// select an atomic operation implementation.
58+
.env("CPPFLAGS", cflags.clone())
5059
.env("AR", &ar)
5160
.env("RANLIB", format!("{} s", ar.display()));
5261

src/liballoc_jemalloc/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ use libc::{c_int, c_void, size_t};
3636
#[cfg_attr(target_os = "android", link(name = "gcc"))]
3737
#[cfg_attr(all(not(windows),
3838
not(target_os = "android"),
39-
not(target_env = "musl")),
39+
not(target_env = "musl"),
40+
not(target_env = "musleabi"),
41+
not(target_env = "musleabihf")),
4042
link(name = "pthread"))]
4143
#[cfg(not(cargobuild))]
4244
extern {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use target::Target;
12+
13+
pub fn target() -> Target {
14+
let mut base = super::musl_base::opts();
15+
16+
// Most of these settings are copied from the arm_unknown_linux_gnueabi
17+
// target.
18+
base.features = "+v6".to_string();
19+
Target {
20+
// It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
21+
// to determine the calling convention and float ABI, and it doesn't
22+
// support the "musleabi" value.
23+
llvm_target: "arm-unknown-linux-gnueabi".to_string(),
24+
target_endian: "little".to_string(),
25+
target_pointer_width: "32".to_string(),
26+
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
27+
arch: "arm".to_string(),
28+
target_os: "linux".to_string(),
29+
target_env: "musleabi".to_string(),
30+
target_vendor: "unknown".to_string(),
31+
options: base,
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use target::Target;
12+
13+
pub fn target() -> Target {
14+
let mut base = super::musl_base::opts();
15+
16+
// Most of these settings are copied from the arm_unknown_linux_gnueabihf
17+
// target.
18+
base.features = "+v6,+vfp2".to_string();
19+
Target {
20+
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
21+
// uses it to determine the calling convention and float ABI, and it
22+
// doesn't support the "musleabihf" value.
23+
llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
24+
target_endian: "little".to_string(),
25+
target_pointer_width: "32".to_string(),
26+
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
27+
arch: "arm".to_string(),
28+
target_os: "linux".to_string(),
29+
target_env: "musleabi".to_string(),
30+
target_vendor: "unknown".to_string(),
31+
options: base,
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use target::Target;
12+
13+
pub fn target() -> Target {
14+
let mut base = super::musl_base::opts();
15+
16+
// Most of these settings are copied from the armv7_unknown_linux_gnueabihf
17+
// target.
18+
base.features = "+v7,+vfp3,+neon".to_string();
19+
base.cpu = "cortex-a8".to_string();
20+
Target {
21+
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
22+
// uses it to determine the calling convention and float ABI, and LLVM
23+
// doesn't support the "musleabihf" value.
24+
llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
25+
target_endian: "little".to_string(),
26+
target_pointer_width: "32".to_string(),
27+
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
28+
arch: "arm".to_string(),
29+
target_os: "linux".to_string(),
30+
target_env: "musleabi".to_string(),
31+
target_vendor: "unknown".to_string(),
32+
options: base,
33+
}
34+
}

src/librustc_back/target/i686_unknown_linux_musl.rs

+1-16
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,11 @@
1313
use target::Target;
1414

1515
pub fn target() -> Target {
16-
let mut base = super::linux_base::opts();
16+
let mut base = super::musl_base::opts();
1717
base.cpu = "pentium4".to_string();
1818
base.pre_link_args.push("-m32".to_string());
1919
base.pre_link_args.push("-Wl,-melf_i386".to_string());
2020

21-
base.pre_link_args.push("-nostdlib".to_string());
22-
base.pre_link_args.push("-static".to_string());
23-
base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string());
24-
25-
base.pre_link_args.push("-Wl,-(".to_string());
26-
base.post_link_args.push("-Wl,-)".to_string());
27-
28-
base.pre_link_objects_exe.push("crt1.o".to_string());
29-
base.pre_link_objects_exe.push("crti.o".to_string());
30-
base.post_link_objects.push("crtn.o".to_string());
31-
32-
base.dynamic_linking = false;
33-
base.has_rpath = false;
34-
base.position_independent_executables = false;
35-
3621
Target {
3722
llvm_target: "i686-unknown-linux-musl".to_string(),
3823
target_endian: "little".to_string(),

src/librustc_back/target/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ mod dragonfly_base;
5757
mod freebsd_base;
5858
mod linux_base;
5959
mod openbsd_base;
60+
mod musl_base;
6061
mod netbsd_base;
6162
mod solaris_base;
6263
mod windows_base;
@@ -98,7 +99,10 @@ supported_targets! {
9899
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
99100
("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
100101
("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
102+
("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi),
103+
("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf),
101104
("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf),
105+
("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf),
102106
("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu),
103107
("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
104108
("i686-unknown-linux-musl", i686_unknown_linux_musl),

src/librustc_back/target/musl_base.rs

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use target::TargetOptions;
12+
13+
pub fn opts() -> TargetOptions {
14+
let mut base = super::linux_base::opts();
15+
16+
// Make sure that the linker/gcc really don't pull in anything, including
17+
// default objects, libs, etc.
18+
base.pre_link_args.push("-nostdlib".to_string());
19+
base.pre_link_args.push("-static".to_string());
20+
21+
// At least when this was tested, the linker would not add the
22+
// `GNU_EH_FRAME` program header to executables generated, which is required
23+
// when unwinding to locate the unwinding information. I'm not sure why this
24+
// argument is *not* necessary for normal builds, but it can't hurt!
25+
base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string());
26+
27+
// There's a whole bunch of circular dependencies when dealing with MUSL
28+
// unfortunately. To put this in perspective libc is statically linked to
29+
// liblibc and libunwind is statically linked to libstd:
30+
//
31+
// * libcore depends on `fmod` which is in libc (transitively in liblibc).
32+
// liblibc, however, depends on libcore.
33+
// * compiler-rt has personality symbols that depend on libunwind, but
34+
// libunwind is in libstd which depends on compiler-rt.
35+
//
36+
// Recall that linkers discard libraries and object files as much as
37+
// possible, and with all the static linking and archives flying around with
38+
// MUSL the linker is super aggressively stripping out objects. For example
39+
// the first case has fmod stripped from liblibc (it's in its own object
40+
// file) so it's not there when libcore needs it. In the second example all
41+
// the unused symbols from libunwind are stripped (each is in its own object
42+
// file in libstd) before we end up linking compiler-rt which depends on
43+
// those symbols.
44+
//
45+
// To deal with these circular dependencies we just force the compiler to
46+
// link everything as a group, not stripping anything out until everything
47+
// is processed. The linker will still perform a pass to strip out object
48+
// files but it won't do so until all objects/archives have been processed.
49+
base.pre_link_args.push("-Wl,-(".to_string());
50+
base.post_link_args.push("-Wl,-)".to_string());
51+
52+
// When generating a statically linked executable there's generally some
53+
// small setup needed which is listed in these files. These are provided by
54+
// a musl toolchain and are linked by default by the `musl-gcc` script. Note
55+
// that `gcc` also does this by default, it just uses some different files.
56+
//
57+
// Each target directory for musl has these object files included in it so
58+
// they'll be included from there.
59+
base.pre_link_objects_exe.push("crt1.o".to_string());
60+
base.pre_link_objects_exe.push("crti.o".to_string());
61+
base.post_link_objects.push("crtn.o".to_string());
62+
63+
// MUSL support doesn't currently include dynamic linking, so there's no
64+
// need for dylibs or rpath business. Additionally `-pie` is incompatible
65+
// with `-static`, so we can't pass `-pie`.
66+
base.dynamic_linking = false;
67+
base.has_rpath = false;
68+
base.position_independent_executables = false;
69+
70+
return base;
71+
}
72+

src/librustc_back/target/x86_64_unknown_linux_musl.rs

+1-55
Original file line numberDiff line numberDiff line change
@@ -11,64 +11,10 @@
1111
use target::Target;
1212

1313
pub fn target() -> Target {
14-
let mut base = super::linux_base::opts();
14+
let mut base = super::musl_base::opts();
1515
base.cpu = "x86-64".to_string();
1616
base.pre_link_args.push("-m64".to_string());
1717

18-
// Make sure that the linker/gcc really don't pull in anything, including
19-
// default objects, libs, etc.
20-
base.pre_link_args.push("-nostdlib".to_string());
21-
base.pre_link_args.push("-static".to_string());
22-
23-
// At least when this was tested, the linker would not add the
24-
// `GNU_EH_FRAME` program header to executables generated, which is required
25-
// when unwinding to locate the unwinding information. I'm not sure why this
26-
// argument is *not* necessary for normal builds, but it can't hurt!
27-
base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string());
28-
29-
// There's a whole bunch of circular dependencies when dealing with MUSL
30-
// unfortunately. To put this in perspective libc is statically linked to
31-
// liblibc and libunwind is statically linked to libstd:
32-
//
33-
// * libcore depends on `fmod` which is in libc (transitively in liblibc).
34-
// liblibc, however, depends on libcore.
35-
// * compiler-rt has personality symbols that depend on libunwind, but
36-
// libunwind is in libstd which depends on compiler-rt.
37-
//
38-
// Recall that linkers discard libraries and object files as much as
39-
// possible, and with all the static linking and archives flying around with
40-
// MUSL the linker is super aggressively stripping out objects. For example
41-
// the first case has fmod stripped from liblibc (it's in its own object
42-
// file) so it's not there when libcore needs it. In the second example all
43-
// the unused symbols from libunwind are stripped (each is in its own object
44-
// file in libstd) before we end up linking compiler-rt which depends on
45-
// those symbols.
46-
//
47-
// To deal with these circular dependencies we just force the compiler to
48-
// link everything as a group, not stripping anything out until everything
49-
// is processed. The linker will still perform a pass to strip out object
50-
// files but it won't do so until all objects/archives have been processed.
51-
base.pre_link_args.push("-Wl,-(".to_string());
52-
base.post_link_args.push("-Wl,-)".to_string());
53-
54-
// When generating a statically linked executable there's generally some
55-
// small setup needed which is listed in these files. These are provided by
56-
// a musl toolchain and are linked by default by the `musl-gcc` script. Note
57-
// that `gcc` also does this by default, it just uses some different files.
58-
//
59-
// Each target directory for musl has these object files included in it so
60-
// they'll be included from there.
61-
base.pre_link_objects_exe.push("crt1.o".to_string());
62-
base.pre_link_objects_exe.push("crti.o".to_string());
63-
base.post_link_objects.push("crtn.o".to_string());
64-
65-
// MUSL support doesn't currently include dynamic linking, so there's no
66-
// need for dylibs or rpath business. Additionally `-pie` is incompatible
67-
// with `-static`, so we can't pass `-pie`.
68-
base.dynamic_linking = false;
69-
base.has_rpath = false;
70-
base.position_independent_executables = false;
71-
7218
Target {
7319
llvm_target: "x86_64-unknown-linux-musl".to_string(),
7420
target_endian: "little".to_string(),

src/libstd/build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn main() {
2828
}
2929

3030
if target.contains("linux") {
31-
if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
31+
if target.contains("musl") && !target.contains("mips") {
3232
println!("cargo:rustc-link-lib=static=unwind");
3333
} else if target.contains("android") {
3434
println!("cargo:rustc-link-lib=dl");

0 commit comments

Comments
 (0)