Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save cl91/bb927df2525738502131 to your computer and use it in GitHub Desktop.
Save cl91/bb927df2525738502131 to your computer and use it in GitHub Desktop.
From f5908efac9f55216d5aabdee72687b2b47f1c89c Mon Sep 17 00:00:00 2001
From: Chang Liu <cliu712@aucklanduni.ac.nz>
Date: Mon, 13 Apr 2015 09:36:31 +0000
Subject: [PATCH] Add support for linux-musl in build system. Fix glibc
assumptions in code.
---
autoconf/config.sub | 7 +++++--
lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp | 2 +-
lib/Support/DynamicLibrary.cpp | 4 ++--
lib/Support/Unix/Signals.inc | 2 +-
utils/unittest/googletest/src/gtest.cc | 1 +
5 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/autoconf/config.sub b/autoconf/config.sub
index 612bff3..9521f7c 100755
--- a/autoconf/config.sub
+++ b/autoconf/config.sub
@@ -125,8 +125,8 @@ esac
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
- linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
- knetbsd*-gnu* | netbsd*-gnu* | \
+ linux-uclibc* | linux-musl* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
@@ -1381,6 +1381,9 @@ case $os in
-linux-dietlibc)
os=-linux-dietlibc
;;
+ -linux-musl)
+ os=-linux-musl
+ ;;
-linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
diff --git a/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp b/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
index 2a5e4f8..091a0bb 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
@@ -33,7 +33,7 @@ namespace llvm {
RTDyldMemoryManager::~RTDyldMemoryManager() {}
// Determine whether we can register EH tables.
-#if (defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__ia64__) && \
+#if (defined(__GLIBC__) && !defined(__ARM_EABI__) && !defined(__ia64__) && \
!defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__))
#define HAVE_EHTABLE_SUPPORT 1
#else
diff --git a/lib/Support/DynamicLibrary.cpp b/lib/Support/DynamicLibrary.cpp
index d2b551e..a178dcb 100644
--- a/lib/Support/DynamicLibrary.cpp
+++ b/lib/Support/DynamicLibrary.cpp
@@ -138,12 +138,12 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
// This macro returns the address of a well-known, explicit symbol
#define EXPLICIT_SYMBOL(SYM) \
- if (!strcmp(symbolName, #SYM)) return &SYM
+ if (!strcmp(symbolName, #SYM)) return (void *) &SYM
// On linux we have a weird situation. The stderr/out/in symbols are both
// macros and global variables because of standards requirements. So, we
// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
-#if defined(__linux__) and !defined(__ANDROID__)
+#if defined(__GLIBC__)
{
EXPLICIT_SYMBOL(stderr);
EXPLICIT_SYMBOL(stdout);
diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc
index e8f4643..8a320ef 100644
--- a/lib/Support/Unix/Signals.inc
+++ b/lib/Support/Unix/Signals.inc
@@ -416,7 +416,7 @@ static bool printSymbolizedStackTrace(void **StackTrace, int Depth, FILE *FD) {
// On glibc systems we have the 'backtrace' function, which works nicely, but
// doesn't demangle symbols.
void llvm::sys::PrintStackTrace(FILE *FD) {
-#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
+#if defined(__GLIBC__) && defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
static void* StackTrace[256];
// Use backtrace() to output a backtrace on Linux systems with glibc.
int depth = backtrace(StackTrace,
diff --git a/utils/unittest/googletest/src/gtest.cc b/utils/unittest/googletest/src/gtest.cc
index bf850c6..e0ca633 100644
--- a/utils/unittest/googletest/src/gtest.cc
+++ b/utils/unittest/googletest/src/gtest.cc
@@ -120,6 +120,7 @@
#if GTEST_CAN_STREAM_RESULTS_
# include <arpa/inet.h> // NOLINT
+# include <sys/socket.h>
# include <netdb.h> // NOLINT
#endif
--
2.3.5
From 38878593679e9b5a24a66fd1d1730fa12fdaa9a1 Mon Sep 17 00:00:00 2001
From: Chang Liu <cliu712@aucklanduni.ac.nz>
Date: Mon, 13 Apr 2015 09:39:32 +0000
Subject: [PATCH] Add target x86_64-unknown-linux-musl
---
mk/cfg/x86_64-unknown-linux-musl.mk | 28 +++++++++++++++++++++
mk/crates.mk | 3 ++-
mk/llvm.mk | 4 +--
mk/main.mk | 1 +
mk/rustllvm.mk | 2 +-
src/librustc_back/target/mod.rs | 2 ++
.../target/x86_64_unknown_linux_musl.rs | 29 ++++++++++++++++++++++
src/llvm | 2 +-
8 files changed, 66 insertions(+), 5 deletions(-)
create mode 100644 mk/cfg/x86_64-unknown-linux-musl.mk
create mode 100644 src/librustc_back/target/x86_64_unknown_linux_musl.rs
diff --git a/mk/cfg/x86_64-unknown-linux-musl.mk b/mk/cfg/x86_64-unknown-linux-musl.mk
new file mode 100644
index 0000000..9493989
--- /dev/null
+++ b/mk/cfg/x86_64-unknown-linux-musl.mk
@@ -0,0 +1,28 @@
+# x86_64-unknown-linux-musl configuration
+CROSS_PREFIX_x86_64-unknown-linux-musl=x86_64-linux-musl-
+CC_x86_64-unknown-linux-musl=$(CC)
+CXX_x86_64-unknown-linux-musl=$(CXX)
+CPP_x86_64-unknown-linux-musl=$(CPP)
+AR_x86_64-unknown-linux-musl=$(AR)
+CFG_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).so
+CFG_STATIC_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).a
+CFG_LIB_GLOB_x86_64-unknown-linux-musl=lib$(1)-*.so
+CFG_LIB_DSYM_GLOB_x86_64-unknown-linux-musl=lib$(1)-*.dylib.dSYM
+CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-musl := -m64
+CFG_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -Wall -Werror -g -fPIC -m64
+CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-musl := -fno-rtti
+CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-musl := -shared -fPIC -ldl -pthread -lrt -g -m64 -Wl,-s
+CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-musl := -Wl,--export-dynamic,--dynamic-list=
+CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-linux-musl := -Wl,-whole-archive
+CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-linux-musl := -Wl,-no-whole-archive
+CFG_DEF_SUFFIX_x86_64-unknown-linux-musl := .linux.def
+CFG_LLC_FLAGS_x86_64-unknown-linux-musl :=
+CFG_INSTALL_NAME_x86_64-unknown-linux-musl =
+CFG_EXE_SUFFIX_x86_64-unknown-linux-musl =
+CFG_WINDOWSY_x86_64-unknown-linux-musl :=
+CFG_UNIXY_x86_64-unknown-linux-musl := 1
+CFG_PATH_MUNGE_x86_64-unknown-linux-musl := true
+CFG_LDPATH_x86_64-unknown-linux-musl :=
+CFG_RUN_x86_64-unknown-linux-musl=$(2)
+CFG_RUN_TARG_x86_64-unknown-linux-musl=$(call CFG_RUN_x86_64-unknown-linux-musl,,$(2))
+CFG_GNU_TRIPLE_x86_64-unknown-linux-musl := x86_64-unknown-linux-musl
diff --git a/mk/crates.mk b/mk/crates.mk
index f594a6a..55c2457 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -56,7 +56,8 @@ TARGET_CRATES := libc std flate arena term \
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
-CRATES := $(TARGET_CRATES) $(HOST_CRATES)
+TARGET_CRATES += $(HOST_CRATES)
+CRATES := $(TARGET_CRATES)
TOOLS := compiletest rustdoc rustc rustbook
DEPS_core :=
diff --git a/mk/llvm.mk b/mk/llvm.mk
index 1861dd3..00adbbd 100644
--- a/mk/llvm.mk
+++ b/mk/llvm.mk
@@ -28,7 +28,7 @@ LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp
$$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS) $$(LLVM_STAMP_$(1))
@$$(call E, make: llvm)
- $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV_$(1)) ONLY_TOOLS="$$(LLVM_TOOLS)"
+ #$$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV_$(1)) ONLY_TOOLS="$$(LLVM_TOOLS)"
$$(Q)touch $$(LLVM_CONFIG_$(1))
endif
@@ -39,7 +39,7 @@ endif
$$(LLVM_STAMP_$(1)): $(S)src/rustllvm/llvm-auto-clean-trigger
@$$(call E, make: cleaning llvm)
$(Q)touch $$@.start_time
- $(Q)$(MAKE) clean-llvm$(1)
+ #$(Q)$(MAKE) clean-llvm$(1)
@$$(call E, make: done cleaning llvm)
touch -r $$@.start_time $$@ && rm $$@.start_time
diff --git a/mk/main.mk b/mk/main.mk
index b9f2cf1..b2d4d68 100644
--- a/mk/main.mk
+++ b/mk/main.mk
@@ -305,6 +305,7 @@ endef
$(foreach host,$(CFG_HOST), \
$(eval $(call DEF_LLVM_VARS,$(host))))
+$(eval $(call DEF_LLVM_VARS,x86_64-unknown-linux-musl))
######################################################################
# Exports for sub-utilities
diff --git a/mk/rustllvm.mk b/mk/rustllvm.mk
index 4422502..7db7f3a 100644
--- a/mk/rustllvm.mk
+++ b/mk/rustllvm.mk
@@ -44,5 +44,5 @@ $(1)/rustllvm/%.o: $(S)src/rustllvm/%.cpp $$(MKFILE_DEPS) $$(LLVM_CONFIG_$(1))
endef
# Instantiate template for all stages
-$(foreach host,$(CFG_HOST), \
+$(foreach host,$(CFG_TARGET), \
$(eval $(call DEF_RUSTLLVM_TARGETS,$(host))))
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 07528df..e6d1869 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -83,6 +83,7 @@ mod x86_64_unknown_freebsd;
mod x86_64_unknown_dragonfly;
mod x86_64_unknown_bitrig;
mod x86_64_unknown_linux_gnu;
+mod x86_64_unknown_linux_musl;
mod x86_64_unknown_openbsd;
/// Everything `rustc` knows about how to compile for a specific target.
@@ -351,6 +352,7 @@ impl Target {
load_specific!(
x86_64_unknown_linux_gnu,
+ x86_64_unknown_linux_musl,
i686_unknown_linux_gnu,
mips_unknown_linux_gnu,
mipsel_unknown_linux_gnu,
diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_back/target/x86_64_unknown_linux_musl.rs
new file mode 100644
index 0000000..357ed3c
--- /dev/null
+++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs
@@ -0,0 +1,29 @@
+// Copyright 2014 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::linux_base::opts();
+ base.cpu = "x86-64".to_string();
+ base.pre_link_args.push("-m64".to_string());
+
+ Target {
+ data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
+ f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
+ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
+ llvm_target: "x86_64-unknown-linux-musl".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ arch: "x86_64".to_string(),
+ target_os: "linux".to_string(),
+ options: base,
+ }
+}
diff --git a/src/llvm b/src/llvm
index bff6907..f5908ef 160000
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit bff69076975642c64e76dbeaa53476bfa7212086
+Subproject commit f5908efac9f55216d5aabdee72687b2b47f1c89c
--
2.3.5
From f4551f46ac6f0a465c7a2ebe29e5acbab0c05dc1 Mon Sep 17 00:00:00 2001
From: Chang Liu <cliu712@aucklanduni.ac.nz>
Date: Fri, 10 Apr 2015 14:01:14 +0000
Subject: [PATCH] Fix namespace pollution of preprocessor macros
Several preprocessor macros defined in stdio.h and sys/stat.h don't play
nicely with C++ namespaces.
For instance, in stdio.h, fopen64 is defined as
#define fopen64 fopen
The following valid C++ code will fail to compile
namespace example {
enum func {
fopen, fopen64
}
}
if the code includes <stdio.h> either directly or indirectly, because of
duplicated definitions of the same identifier.
This is to fix compilation of LLVM where the target info library defines
enumerations of the target library symbols to generate, which coincide with
preprocessor symbols defined in musl.
---
include/fcntl.h | 30 +++++++++++++++++++++++++++++-
include/stdio.h | 45 +++++++++++++++++++++++++++++++++++++++++++--
include/sys/stat.h | 34 ++++++++++++++++++++++++++++++----
3 files changed, 102 insertions(+), 7 deletions(-)
diff --git a/include/fcntl.h b/include/fcntl.h
index ebd5c30..0e15fd8 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -171,14 +171,42 @@ ssize_t tee(int, int, size_t, unsigned);
#define F_GETLK64 F_GETLK
#define F_SETLK64 F_SETLK
#define F_SETLKW64 F_SETLKW
+#define off64_t off_t
#define flock64 flock
+#ifdef __cplusplus
+/* This is less than ideal as the preprocessor is unaware of C++'s namespaces.
+ * However, as we don't have the va_arg versions of open() and openat()
+ * this is the only way that we can pass variadic arguments in.
+ */
+#define open64(path, oflag, ...) open(path, oflag, __VA_ARGS__)
+#define openat64(fd, path, oflag, ...) openat(fd, path, oflag, __VA_ARGS)
+inline int creat64(const char *path, mode_t mode)
+{
+ return creat(path, mode);
+}
+
+inline int lockf64(int fd, int cmd, off64_t len)
+{
+ return lockf(fd, cmd, len);
+}
+
+inline int posix_fadvise64(int fd, off64_t offset, off64_t len, int advice)
+{
+ return posix_fadvise(fd, offset, len, advice);
+}
+
+inline int posix_fallocate64(int fd, off64_t offset, off64_t len)
+{
+ return posix_fallocate(fd, offset, len);
+}
+#else
#define open64 open
#define openat64 openat
#define creat64 creat
#define lockf64 lockf
#define posix_fadvise64 posix_fadvise
#define posix_fallocate64 posix_fallocate
-#define off64_t off_t
+#endif
#endif
#ifdef __cplusplus
diff --git a/include/stdio.h b/include/stdio.h
index 884d2e6..78ef3f5 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -185,6 +185,47 @@ int fputs_unlocked(const char *, FILE *);
#endif
#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+
+#define fpos64_t fpos_t
+#define off64_t off_t
+
+#ifdef __cplusplus
+inline FILE *tmpfile64(void)
+{
+ return tmpfile();
+}
+
+inline FILE *fopen64(const char *__restrict path, const char *__restrict mode)
+{
+ return fopen(path, mode);
+}
+
+inline FILE *freopen64(const char *__restrict path,
+ const char *__restrict mode, FILE *__restrict stream)
+{
+ return freopen(path, mode, stream);
+}
+
+inline int fseeko64(FILE *file, off64_t offset, int whence)
+{
+ return fseeko(file, offset, whence);
+}
+
+inline off64_t ftello64(FILE *file)
+{
+ return ftello(file);
+}
+
+inline int fgetpos64(FILE *__restrict file, fpos64_t *__restrict pos)
+{
+ return fgetpos(file, pos);
+}
+
+inline int fsetpos64(FILE *file, const fpos64_t *pos)
+{
+ return fsetpos(file, pos);
+}
+#else
#define tmpfile64 tmpfile
#define fopen64 fopen
#define freopen64 freopen
@@ -192,8 +233,8 @@ int fputs_unlocked(const char *, FILE *);
#define ftello64 ftello
#define fgetpos64 fgetpos
#define fsetpos64 fsetpos
-#define fpos64_t fpos_t
-#define off64_t off_t
+#endif
+
#endif
#ifdef __cplusplus
diff --git a/include/sys/stat.h b/include/sys/stat.h
index 82a6490..f22288d 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -96,15 +96,41 @@ int lchmod(const char *, mode_t);
#endif
#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
-#define stat64 stat
-#define fstat64 fstat
-#define lstat64 lstat
-#define fstatat64 fstatat
+
#define blkcnt64_t blkcnt_t
#define fsblkcnt64_t fsblkcnt_t
#define fsfilcnt64_t fsfilcnt_t
#define ino64_t ino_t
#define off64_t off_t
+
+#ifdef __cplusplus
+inline int stat64(const char *__restrict path, struct stat *__restrict buf)
+{
+ return stat(path, buf);
+}
+
+inline int fstat64(int fd, struct stat *buf)
+{
+ return fstat(fd, buf);
+}
+
+inline int lstat64(const char *__restrict path, struct stat *__restrict buf)
+{
+ return lstat(path, buf);
+}
+
+inline int fstatat64(int dirfd, const char *__restrict path,
+ struct stat *__restrict buf, int flags)
+{
+ return fstatat(dirfd, path, buf, flags);
+}
+#else
+#define stat64 stat
+#define fstat64 fstat
+#define lstat64 lstat
+#define fstatat64 fstatat
+#endif
+
#endif
#ifdef __cplusplus
--
2.3.2
diff --git a/config.sub b/config.sub
index de11910..e4abfbe 100755
--- a/config.sub
+++ b/config.sub
@@ -125,9 +125,8 @@ esac
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
- linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
- knetbsd*-gnu* | netbsd*-gnu* | \
- kopensolaris*-gnu* | \
+ linux-uclibc* | linux-musl* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
@@ -1352,6 +1351,9 @@ case $os in
-linux-dietlibc)
os=-linux-dietlibc
;;
+ -linux-musl)
+ os=-linux-musl
+ ;;
-linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
From 86e83f2880cb6dd116f32982c5208e26d45571e3 Mon Sep 17 00:00:00 2001
From: Chang Liu <cliu712@aucklanduni.ac.nz>
Date: Thu, 23 Apr 2015 16:43:44 +0000
Subject: [PATCH] build: Add support for target triple *-linux-musl
---
configfsf.sub | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/configfsf.sub b/configfsf.sub
index a649350..3b57126 100755
--- a/configfsf.sub
+++ b/configfsf.sub
@@ -120,7 +120,7 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | linux-musl* | \
uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
@@ -1262,7 +1262,7 @@ case $os in
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* | -linux-musl* \
| -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
--
2.3.5
From 452965fe496cc152541894166b70007c1ab2fc3a Mon Sep 17 00:00:00 2001
From: Chang Liu <cliu712@aucklanduni.ac.nz>
Date: Thu, 23 Apr 2015 17:15:01 +0000
Subject: [PATCH] build: Add support for target triple *-linux-musl
---
config.sub | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/config.sub b/config.sub
index eb0389a..8f6e773 100755
--- a/config.sub
+++ b/config.sub
@@ -120,7 +120,7 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | linux-musl* | \
uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
@@ -1282,7 +1282,7 @@ case $os in
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* | -linux-musl* \
| -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
--
2.3.5

Linking rust programs against musl statically

The end goal of this experiment is to produce a statically-linked rust executable on Linux that has absolutely no dependencies (other than the kernel interfaces). We cannot do this on a glibc-based system because glibc does not support being statically linked. We need to link against musl (musl-libc.org) which supports being statically linked (and also has a smaller footprint than glibc).

The Plan

From the reasoning above, the first step we need to do is to produce a toolchain that targets musl. As we are running under a glibc-based distro, we will need a cross toolchain that runs on host triple x86_64-unknown-linux-gnu and generates binaries for the target triple x86_64-unknown-linux-musl.

The second step is to patch rustc to generate binaries for the target triple x86_64-unknown-linux-musl. As rustc depends on LLVM to do most of the heavylifting, we need to patch LLVM as well. These patches are pretty trivial though (mostly just to patch the build system to recognize the new target triple), because musl and glibc are mostly compatible (on a source level, not on a binary level).

The next step is to build rustc that targets x86_64-unknown-linux-musl. rustc itself is inherently a cross compiler, meaning that one rustc is able to generate binaries for all supported targets. However, the standard libraries are usually only compiled for the host triple (because it simply takes too much time to compile for each and every supported target triples). The rustc build system will need to be changed slightly in order for us to do this.

Now that we've built a rustc that can target x86_64-unknown-linux-musl, to generate a musl-linked executable we simply invoke rustc and specify the required target triple. However, the executable generated this way will be linked against musl dynamically. It appears that when invoking the system linker (in our case, x86_64-unknown-linux-musl-gcc), rustc always tells it to linked to libc dynamically.

There are two ways to fix this. We can modify the rust compiler so that it calls the system linker to link against libc statically. Or we can just manually invoke the system linker ourselves. For this quick exercise the latter approach suffices. So this is what we are going to do.

Preparing Cross Toolchain

The easiest way to get a cross compiler that targets musl is the musl-cross script (https://github.com/GregorR/musl-cross). Clone this repo (which appears to be more actively maintained than the other one mentioned in the readme file):

git clone https://github.com/GregorR/musl-cross

If you just run the ./build.sh script now it will happily run and produce a musl-targeting cross toolchain. However, it will fail to compile some of the LLVM libraries because of an issue in musl's implementation of the standard C headers (stdio.h and sys/stat.h). The issue is that some of the preprocessor symbols defined in said C headers pollute the LLVM namespace.

To fix this you need to apply the following patch to musl:

https://gist.githubusercontent.com/cl91/bb927df2525738502131/raw/b16eeab3d855986b294ae80fc4cbfc7630b45932/0001-Fix-namespace-pollution-of-preprocessor-macros.patch

Apply this to the latest musl master (I believe any version after 1.1.6 will work, although I have not tested them.). You can clone musl from git://git.musl-libc.org/musl.

The build system of LLVM expects to find cross toolchain with prefix x86_64-unknown-linux-musl if we are building for said target. The cross prefix that the musl-cross script creates is slightly different: x86_64-linux-musl. To fix this we modify the build script to symlink the cross toolchain to the correct cross prefix:

https://gist.githubusercontent.com/cl91/bb927df2525738502131/raw/cf6b243b7454fd1d29c9d42b134d16d73774e147/0001-Symlink-to-cross-prefix-x86_64-unknown-linux-musl.patch

Now run the build script ./build.sh. You might want to modify CC_BASE_PREFIX in both config.sh and config-static.sh to something other than /opt/cross if you want your cross toolchain to be installed somewhere else. In my case, I set it to $HOME/cross.

Rustc links to libedit which is a library for command line editing. To build rustc for the target triple we need libedit and all its dependencies built for x86_64-unknown-linux-musl. libedit depends on ncurses. Therefore the next step is to cross compile ncurses and libedit for the target triple.

Get ncurses from here:

https://ftp.gnu.org/gnu/ncurses/ncurses-5.9.tar.gz

Once you downloaded it, untar it and cd into the source directory.

I am assuming that the cross toolchain is installed into $HOME/cross.

export CROSS_TOOLS=$HOME/cross
export PATH=$PATH:$CROSS_TOOLS/x86_64-linux-musl/bin

You need to modify this accordingly.

Before compiling ncurses you need to modify the config.sub script to recognize our target triple.

wget https://gist.githubusercontent.com/cl91/bb927df2525738502131/raw/f5e6bc9485d5d48bc7466623c310f5b64f950656/config-sub-musl.patch
patch -p1 < config-sub-musl.patch

We now build ncurses for the cross architecture:

./configure --prefix=$CROSS_TOOLS/x86_64-linux-musl/x86_64-linux-musl --host=x86_64-unknown-linux-musl
make && make install

Note that if you are hitting the tic error, you need to make sure that the host $PATH comes before the cross tools.

Now we need to build libedit. It appears that the build system for libedit has already been patched to recognize musl. We simply configure it and build it:

wget http://www.thrysoee.dk/editline/libedit-20141030-3.1.tar.gz
cd libedit-20141029-3.1
./configure --prefix=$CROSS_TOOLS/x86_64-linux-musl/x86_64-linux-musl --host=x86_64-unknown-linux-musl
make && make install

The object files that rustc generates uses symbols from libgcc for exception handling. It appears that the build script for the cross toolchain only copies the dynamic version of this library but not the static ones. We need to copy them manually:

cd <path-to-musl-cross>/gcc-4.9.2/build2
cp x86_64-linux-musl/libgcc/libgcc*.a $CROSS_TOOLS/x86_64-linux-musl/x86_64-linux-musl/lib

Preparing Rustc Source

From now on I mostly followed http://github.jfet.org/Rust_cross_bootstrapping.html with all occurrences of arm-unknown-linux-gnueabi replaced by x86_64-unknown-linux-musl. First of all, both the build system and the compiler code need to be patched to recognize our new target triple. Also, the build system needs to be tweaked slightly according to the article.

git clone https://github.com/rust-lang/rust
cd rust
git submodule update --init
git checkout dd6c4a8f15bc04dae7720af69d4a534d93c85c0a
git checkout -b musl

You need the patch from https://gist.githubusercontent.com/cl91/bb927df2525738502131/raw/87ada1d66e6129d3c104c16ed48b0891f36c124c/0001-Add-target-x86_64-unknown-linux-musl.patch for rustc and https://gist.githubusercontent.com/cl91/bb927df2525738502131/raw/e695ab47dca4d4d91fe880499ca16e17b2c688f1/0001-Add-support-for-linux-musl-in-build-system.-Fix-glib.patch for llvm.

cd src/llvm
git apply ~/0001-Add-support-for-linux-musl-in-build-system.-Fix-glib.patch
git commit -a -m "Add musl support"
cd ../..
git apply ~/0001-Add-target-x86_64-unknown-linux-musl.patch
git add .
git commit -a -m "Add musl support"

Configuring Rustc

Now we configure rustc:

mkdir -p $CROSS_TOOLS/rust/{var/lib,etc}
./configure --prefix=$CROSS_TOOLS/rust --host=x86_64-unknown-linux-gnu --disable-llvm-assertions --target=x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl --localstatedir=$CROSS_TOOLS/rust/var/lib --sysconfdir=$CROSS_TOOLS/rust/etc

We need to tweak the build system slightly so that it knows where to find our LLVM built for the target triple:

chmod 0644 config.mk
sed 's/x86_64\(.\)unknown.linux.gnu/[chang@arch rust]$ grep 'CFG_LLVM_[BI]' \
     sed 's/x86_64\(.\)unknown.linux.gnu/x86_64\1unknown\1linux\1musl/g'    \
  >> config.mk

Building LLVM

We need to build LLVM for both the host and the cross target. We first build it for the host triple:

cd x86_64-unknown-linux-gnu/llvm
../../src/llvm/configure --enable-target=x86_64 --enable-optimized --disable-assertions --disable-docs --enable-bindings=none --disable-terminfo --disable-zlib --disable-libffi --with-python=/usr/bin/python2.7
make -j$(nproc)

And then for the target triple:

cd x86_64-unknown-linux-musl
mkdir rustllvm	# you need this for rustc build system to work
mkdir llvm
cd llvm
../../src/llvm/configure --enable-target=x86_64 --enable-optimized --disable-assertions --disable-docs --enable-bindings=none --disable-terminfo --disable-zlib --disable-libffi --with-python=/usr/bin/python2.7 --host=x86_64-unknown-linux-musl --target=x86_64-unknown-linux-musl
make -j$(nproc)

According to the article, you need to manually tweak the build system to invoke the llvm-config tool built for the host triple rather than the target triple:

cd Release/bin
mv llvm-config llvm-config-musl
ln -s ../../BuildTools/Release/bin/llvm-config .
# (Now test to be sure this works.)
./llvm-config --cxxflags
# (You should see some CXX flags printed out here!)

Building Rustc

Finally, we are ready to build rustc. This takes a long long time. So you may need to grab some coffee, or do some squats to kill the time.

cd ../../../.. # this brings us back to the rust source directory
make -j$(nproc)

Generating Statically Linked Musl Executables

By default, when generating executables, rustc will statically link all rust dependencies but dynamically link all external dependencies, including system libraries such as libc and libgcc (on gcc-based systems).

Therefore we need to manually invoke the cross linker to link against musl statically. As a test, let's build the hello world program:

fn main() {
	println!("hello, world!");
}

We first compile it into object file:

export RUSTSRC=$HOME/src/rust-lang
export RUSTLIB=$RUSTSRC/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-musl/lib
export RUSTEXE=$RUSTSRC/x86_64-unknown-linux-gnu/stage2/bin/rustc
LD_LIBRARY_PATH=$RUSTLIB $RUSTEXE -C opt-level=3 -C lto --target=x86_64-unknown-linux-musl --emit=obj -o a.o a.rs

You need to modify the $RUSTSRC accordingly.

We then invoke the cross linker directly:

x86_64-unknown-linux-musl-gcc a.o -nodefaultlibs -Wl,-s -Wl,-Bstatic $RUSTLIB/liballoc-4e7c5e5c.rlib $RUSTLIB/libstd-4e7c5e5c.rlib $RUSTLIB/libmorestack.a $RUSTLIB/libcompiler-rt.a -lgcc_eh -lc

The -nodefaultlibs tells the cross linker to not link against libc. We then manually add libc and other dependencies into the executable. We use -Wl,-Bstatic to tell the linker to link statically.

Hooray! We have now built a rusc program that is statically linked against libc and all dependencies, and therefore has absolutely no dependencies. To verify this:

ldd a.out

You should be able to see not a dynamic executable. Run it:

a.out
=> hello, world!

Bootstra rustc in native musl environment

Following this path, it is actually possible to produce a statically-linked rustc. However, the resulting compiler is not functional as the compiler plugins require dynamic linking.

The dynamically linked compiler does work. From the cross rustc built above, we can bootstrap a native rustc that runs on a musl-based environment.

LD_LIBRARY_PATH=$RUSTLIB $RUSTEXE --cfg stage2 -O -cfg rtopt		       \
    -C linker=x86_64-unknown-linux-musl-g++ -C ar=x86_64-unknown-linux-musl-ar \
    --cfg debug -C prefer-dynamic --target=x86_64-unknown-linux-musl	       \
    -o x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-musl/bin/rustc --cfg rustc ./src/driver/driver.rs
LD_LIBRARY_PATH=$RUSTLIB $RUSTEXE --cfg stage2 -O -cfg rtopt		       \
    -C linker=x86_64-unknown-linux-musl-g++ -C ar=x86_64-unknown-linux-musl-ar \
    --cfg debug -C prefer-dynamic --target=x86_64-unknown-linux-musl	       \
    -o x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-musl/bin/rustdoc --cfg rustdoc ./src/driver/driver.rs

Tar them up according to the directory structure of a standard rustc distribution, and then copy it into a musl-native environment (for instance, Alpine Linux).

You then need a native musl toolchain. You can get it from a musl-based distro such as Alpine Linux, or you can build for yourself. The musl-cross script can be modified very slightly to do this. All you need to do is to modify the --host and --target passed to the configure script in binutils and gcc to be x86_64-unknown-linux-musl. You may need to patch gmp, mpr, and mpfr (patches are in this gist repo).

You can then use the native rustc to boostrap a rustc build in a musl environment. To have a reasonable assurity that the resulting compiler indeed works, I ran the test suite for the compiler and the standard library. Stack overflow detection tests failed, but all other compiler tests are successful. The logs can be seen at https://gist.github.com/cl91/d24bb5b75248b0214fa3

@whitequark
Copy link

Why do you build LLVM with musl? It would make most sense to just use the host rustc.

As a side note, some distributions (like Debian derivatives) offer a musl-gcc package, which is more convenient to use if invoking linker manually. You're saved from building your own musl as well.

@cl91
Copy link
Author

cl91 commented May 5, 2015

@whitequark Sorry didn't see this comment when you posted it. The reason that I went through hoops to build llvm is because I want to build the compiler against musl statically. As rustc depends on llvm which depends on libstdc++, you need a hosted c++ compiler which targets musl natively. The simple musl-gcc wrapper is not sufficient here.

I didn't quite get it working though, as the compiler depends on dynamic linking for compiler plugin support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment