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
https://github.com/rust-lang/compiler-rt/pull/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).
This commit is contained in:
Timon Van Overveldt 2016-04-27 18:02:31 -07:00 committed by Jorge Aparicio
parent 57cad5722d
commit f7247d1071
15 changed files with 210 additions and 9 deletions

2
configure vendored
View File

@ -1192,7 +1192,7 @@ do
;; ;;
x86_64-*-musl) x86_64-*-musl | arm-*-musleabi)
if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ] if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ]
then then
err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found" err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"

View File

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

View File

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

View File

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

View File

@ -92,8 +92,7 @@ pub fn std_link(build: &Build,
} }
add_to_sysroot(&out_dir, &libdir); add_to_sysroot(&out_dir, &libdir);
if target.contains("musl") && if target.contains("musl") && !target.contains("mips") {
(target.contains("x86_64") || target.contains("i686")) {
copy_third_party_objects(build, target, &libdir); copy_third_party_objects(build, target, &libdir);
} }
} }

View File

@ -109,7 +109,7 @@ pub fn check(build: &mut Build) {
} }
// Make sure musl-root is valid if specified // Make sure musl-root is valid if specified
if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { if target.contains("musl") && !target.contains("mips") {
match build.config.musl_root { match build.config.musl_root {
Some(ref root) => { Some(ref root) => {
if fs::metadata(root.join("lib/libc.a")).is_err() { if fs::metadata(root.join("lib/libc.a")).is_err() {

View File

@ -73,7 +73,16 @@ fn main() {
.replace("\\", "/")) .replace("\\", "/"))
.current_dir(&build_dir) .current_dir(&build_dir)
.env("CC", compiler.path()) .env("CC", compiler.path())
.env("EXTRA_CFLAGS", cflags) .env("EXTRA_CFLAGS", cflags.clone())
// jemalloc generates Makefile deps using GCC's "-MM" flag. This means
// that GCC will run the preprocessor, and only the preprocessor, over
// jemalloc's source files. If we don't specify CPPFLAGS, then at least
// on ARM that step fails with a "Missing implementation for 32-bit
// atomic operations" error. This is because no "-march" flag will be
// passed to GCC, and then GCC won't define the
// "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
// select an atomic operation implementation.
.env("CPPFLAGS", cflags.clone())
.env("AR", &ar) .env("AR", &ar)
.env("RANLIB", format!("{} s", ar.display())); .env("RANLIB", format!("{} s", ar.display()));

View File

@ -36,7 +36,9 @@ use libc::{c_int, c_void, size_t};
#[cfg_attr(target_os = "android", link(name = "gcc"))] #[cfg_attr(target_os = "android", link(name = "gcc"))]
#[cfg_attr(all(not(windows), #[cfg_attr(all(not(windows),
not(target_os = "android"), not(target_os = "android"),
not(target_env = "musl")), not(target_env = "musl"),
not(target_env = "musleabi"),
not(target_env = "musleabihf")),
link(name = "pthread"))] link(name = "pthread"))]
#[cfg(not(cargobuild))] #[cfg(not(cargobuild))]
extern "C" {} extern "C" {}

View File

@ -0,0 +1,33 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use target::Target;
pub fn target() -> Target {
let mut base = super::musl_base::opts();
// Most of these settings are copied from the arm_unknown_linux_gnueabi
// target.
base.features = "+v6".to_string();
Target {
// It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
// to determine the calling convention and float ABI, and it doesn't
// support the "musleabi" value.
llvm_target: "arm-unknown-linux-gnueabi".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
arch: "arm".to_string(),
target_os: "linux".to_string(),
target_env: "musleabi".to_string(),
target_vendor: "unknown".to_string(),
options: base,
}
}

View File

@ -0,0 +1,33 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use target::Target;
pub fn target() -> Target {
let mut base = super::musl_base::opts();
// Most of these settings are copied from the arm_unknown_linux_gnueabihf
// target.
base.features = "+v6,+vfp2".to_string();
Target {
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
// uses it to determine the calling convention and float ABI, and it
// doesn't support the "musleabihf" value.
llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
arch: "arm".to_string(),
target_os: "linux".to_string(),
target_env: "musleabi".to_string(),
target_vendor: "unknown".to_string(),
options: base,
}
}

View File

@ -0,0 +1,34 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use target::Target;
pub fn target() -> Target {
let mut base = super::musl_base::opts();
// Most of these settings are copied from the armv7_unknown_linux_gnueabihf
// target.
base.features = "+v7,+vfp3,+neon".to_string();
base.cpu = "cortex-a8".to_string();
Target {
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
// uses it to determine the calling convention and float ABI, and LLVM
// doesn't support the "musleabihf" value.
llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
arch: "arm".to_string(),
target_os: "linux".to_string(),
target_env: "musleabi".to_string(),
target_vendor: "unknown".to_string(),
options: base,
}
}

View File

@ -59,6 +59,7 @@ mod freebsd_base;
mod linux_base; mod linux_base;
mod linux_musl_base; mod linux_musl_base;
mod openbsd_base; mod openbsd_base;
mod musl_base;
mod netbsd_base; mod netbsd_base;
mod solaris_base; mod solaris_base;
mod windows_base; mod windows_base;
@ -134,7 +135,10 @@ supported_targets! {
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi),
("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf),
("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf),
("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf),
("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu),
("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl), ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
("i686-unknown-linux-musl", i686_unknown_linux_musl), ("i686-unknown-linux-musl", i686_unknown_linux_musl),

View File

@ -0,0 +1,72 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use target::TargetOptions;
pub fn opts() -> TargetOptions {
let mut base = super::linux_base::opts();
// Make sure that the linker/gcc really don't pull in anything, including
// default objects, libs, etc.
base.pre_link_args.push("-nostdlib".to_string());
base.pre_link_args.push("-static".to_string());
// At least when this was tested, the linker would not add the
// `GNU_EH_FRAME` program header to executables generated, which is required
// when unwinding to locate the unwinding information. I'm not sure why this
// argument is *not* necessary for normal builds, but it can't hurt!
base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string());
// There's a whole bunch of circular dependencies when dealing with MUSL
// unfortunately. To put this in perspective libc is statically linked to
// liblibc and libunwind is statically linked to libstd:
//
// * libcore depends on `fmod` which is in libc (transitively in liblibc).
// liblibc, however, depends on libcore.
// * compiler-rt has personality symbols that depend on libunwind, but
// libunwind is in libstd which depends on compiler-rt.
//
// Recall that linkers discard libraries and object files as much as
// possible, and with all the static linking and archives flying around with
// MUSL the linker is super aggressively stripping out objects. For example
// the first case has fmod stripped from liblibc (it's in its own object
// file) so it's not there when libcore needs it. In the second example all
// the unused symbols from libunwind are stripped (each is in its own object
// file in libstd) before we end up linking compiler-rt which depends on
// those symbols.
//
// To deal with these circular dependencies we just force the compiler to
// link everything as a group, not stripping anything out until everything
// is processed. The linker will still perform a pass to strip out object
// files but it won't do so until all objects/archives have been processed.
base.pre_link_args.push("-Wl,-(".to_string());
base.post_link_args.push("-Wl,-)".to_string());
// When generating a statically linked executable there's generally some
// small setup needed which is listed in these files. These are provided by
// a musl toolchain and are linked by default by the `musl-gcc` script. Note
// that `gcc` also does this by default, it just uses some different files.
//
// Each target directory for musl has these object files included in it so
// they'll be included from there.
base.pre_link_objects_exe.push("crt1.o".to_string());
base.pre_link_objects_exe.push("crti.o".to_string());
base.post_link_objects.push("crtn.o".to_string());
// MUSL support doesn't currently include dynamic linking, so there's no
// need for dylibs or rpath business. Additionally `-pie` is incompatible
// with `-static`, so we can't pass `-pie`.
base.dynamic_linking = false;
base.has_rpath = false;
base.position_independent_executables = false;
return base;
}

View File

@ -19,7 +19,9 @@
// //
// On Linux, librt and libdl are indirect dependencies via std, // On Linux, librt and libdl are indirect dependencies via std,
// and binutils 2.22+ won't add them automatically // and binutils 2.22+ won't add them automatically
#[cfg(all(target_os = "linux", not(target_env = "musl")))] #[cfg(all(target_os = "linux", not(any(target_env = "musl",
target_env = "musleabi",
target_env = "musleabihf"))))]
#[link(name = "dl")] #[link(name = "dl")]
#[link(name = "pthread")] #[link(name = "pthread")]
extern {} extern {}

View File

@ -171,7 +171,9 @@ impl Drop for Thread {
} }
} }
#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))), #[cfg(all(not(all(target_os = "linux", not(any(target_env = "musl",
target_env = "musleabi",
target_env = "musleabihf")))),
not(target_os = "freebsd"), not(target_os = "freebsd"),
not(target_os = "macos"), not(target_os = "macos"),
not(target_os = "bitrig"), not(target_os = "bitrig"),
@ -185,7 +187,9 @@ pub mod guard {
} }
#[cfg(any(all(target_os = "linux", not(target_env = "musl")), #[cfg(any(all(target_os = "linux", not(any(target_env = "musl",
target_env = "musleabi",
target_env = "musleabihf"))),
target_os = "freebsd", target_os = "freebsd",
target_os = "macos", target_os = "macos",
target_os = "bitrig", target_os = "bitrig",