Notes about porting
I have documented the porting process, so that others are able to follow it. Either because they want to build rust for Haiku from scratch (like I did), or you want to get started on porting rust to another platform and you would like some hints on how to get started.
What you should know in advance
The rust compiler (rustc) is written in rust. That means that it requires a prebuilt rust compiler to compile the source. This means that in case you want to port Rust to another platform, you will always have to start off by creating an initial (or: stage0) compiler for the new platform.
The basic steps are:
- On the supported build platform, create a cross-compiler that can generate binaries for the Haiku platform.
- Using this cross-compiler, create a native compiler for Haiku.
In my case the host platform was Mac OS X Yosemite, but it should work on any platform that supports building Rust and building Haiku.
This brings me to another thing... cross-compiling is a bit of a maze. Now I built for Haiku, which has excellent support for cross-compiling the whole OS on platforms like Mac OS X, Linux and FreeBSD. That means that a GCC cross-compiler is built, as well as important libraries and glue code that is needed to create native binaries.
NOTE: it is absolutely important that you understand that your target platform is itself cross compilable from your build platform. You cannot cross-compile for another platform without a cross-compiling toolchain and important OS glue code.
Step 1: creating a cross-compiler
When cross-compiling, you always deal with three things:
- the build platform where you build your tools
- the host platform which will run your compiled code
- the target platform that the binary on the host platform will generate code for.
While in theory all three platforms can be different, in this (and most) cases one will build and run (host) _rustc_ on a single platform.
Remember: the goal is to create a cross-compiler that will be able to create binaries for the i686-unknown-haiku platform. That makes our configuration as follows:
CFG_BUILD := x86_64-apple-darwin
CFG_HOST := x86_64-apple-darwin
CFG_TARGET := x86_64-apple-darwin i686-unknown-haiku
Step 1.1: building Haiku
The first thing you should do is make sure you have compiled Haiku, with a GCC 4 compiler. The latter is important since Haiku in principle is built with GCC2. So the best point to get started is to configure the Haiku build, and run it to create at least a basic image so that some of the base libraries (like libroot.so) is ready.
Step 1.2: preparing Haiku's gcc 4 cross-compiler
So let's say we built Haiku on a location we call $(HAIKU_BUILD_PATH). The gcc and binutil cross-compilers then live in $(HAIKU_BUILD_PATH)/cross-tools-x86. The compiler will look for standard headers in $(HAIKU_BUILD_PATH)/cross-tools-x86/i586-pc-haiku/include. The compiler will look for standard libraries in $(HAIKU_BUILD_PATH)/cross-tools-x86/i586-pc-haiku/lib/. Let's say we have the source of the Haiku trunk in $(HAIKU_SOURCE_PATH)
We should then perform the following steps to set up our compiler for success:
cd $(HAIKU_BUILD_PATH)
cp objects/haiku/x86/release/system/glue/init_term_dyn.o cross-tools-x86/i586-pc-haiku/lib/
cp objects/haiku/x86/release/system/glue/arch/x86/crti.o cross-tools-x86/i586-pc-haiku/lib/
cp objects/haiku/x86/release/system/glue/arch/x86/crtn.o cross-tools-x86/i586-pc-haiku/lib/
cp objects/haiku/x86/release/system/glue/start_dyn.o cross-tools-x86/i586-pc-haiku/lib/
cp -r $(HAIKU_SOURCE_PATH)/headers/posix/* cross-tools-x86/i586-pc-haiku/include/
cp $(HAIKU_SOURCE_PATH)/headers/os/BeBuild.h cross-tools-x86/i586-pc-haiku/include/
cp $(HAIKU_SOURCE_PATH)/headers/support/Errors.h cross-tools-x86/i586-pc-haiku/include/
cp $(HAIKU_SOURCE_PATH)/headers/support/SupportDefs.h cross-tools-x86/i586-pc-haiku/include/
cp $(HAIKU_SOURCE_PATH)/headers/storage/StorageDefs.h cross-tools-x86/i586-pc-haiku/include/
cp $(HAIKU_SOURCE_PATH)/headers/kernel/OS.h cross-tools-x86/i586-pc-haiku/include/
cp -r $(HAIKU_SOURCE_PATH)/headers/kernel cross-tools-x86/i586-pc-haiku/include/
Lastly, we should edit the file $(HAIKU_BUILD_PATH)/cross-tools-x86/lib/gcc/i586-pc-haiku/4.8.3/include-fixed/syslimits.h, and comment out the line _GCC_NEXT_LIMITS_H.
Step 1.3: building the cross-compiler.
Don't forget to get the source from https://github.com/nielx/rust.
Then do your build:
CC=gcc ./configure --host=x86_64-apple-darwin --target=i686-unknown-haiku --disable-jemalloc
PATH=$PATH:$(HAIKU_BUILD_PATH)/cross-tools-x86/bin/ make
NOTE 1: On MacOS X the default is clang. We need to tell configure explicitly we want to build with gcc. This is still clang on OS X, but rust's build system will prefix Haiku's cross-compiler with
i586-pc-haiku-, andi586-pc-haiku-clangdoes not exist
NOTE 2: jemalloc is disabled for now. I did not test it. It might work.
Step 2: creating a stage0 compiler
The next series of steps are about using the freshly baked cross-compiler to create a stage0 compiler that will run on Haiku.
Rust's build system either does not support doing this automatically, or the process is broken. As such what I did is basically looked through the compiler output of what the Rust compiler does, and then to perform these steps manually to create the libraries needed to create the compiler.
Step 2.1: setting up the build directory and environment
I like to work in a clean directory, outside of the build tree. So I do the following. I create a new root folder, in which I build the various modules.
Set the following:
export PATH=$PATH:$(HAIKU_BUILD_PATH)/cross-tools-x86/bin/
export CFG_COMPILER_HOST_TRIPLE=i686-unknown-haiku
mkdir $(RUST_HAIKU_STAGE0)
Step 2.2: building llvm
cd $(RUST_HAIKU_STAGE0)
mkdir llvm
cd llvm
CC=i586-pc-haiku-gcc CPP=i586-pc-haiku-cpp CXX=i586-pc-haiku-g++ AR=i586-pc-haiku-ar RANLIB=i586-pc-haiku-ranlib NM_PATH=i586-pc-haiku-ranlib $(RUST_SOURCE_DIR)/src/llvm/configure --enable-targets=x86,x86_64,arm,aarch64,mips,powerpc --enable-optimized --enable-assertions --disable-docs --enable-bindings=none --disable-terminfo --disable-zlib --disable-libffi --enable-libcpp --build=x86_64-apple-darwin --host=i686-unknown-haiku --target=i686-unknown-haiku --with-python=/usr/bin/python2.7 --disable-libcpp
make ONLY_TOOLS="bugpoint llc llvm-ar llvm-as llvm-dis llvm-mc opt llvm-extract"
Notes:
- In the configure stage we need to set the various haiku build apps, like CC, CPP, CXX, NM, RANLIB and AR. If the last three are not explicitly set, the build system will use the host’s tools, which in my case were incompatible with the output of haiku’s gcc.
- —disable-libcpp: it might be because I am building on MacOS X where gcc is an alias for clang, but llvm wants to build with its own standard c library instead of with gcc’s. This becomes an issue during the build, as the build system will try to instruct gcc to use libc++, which is invalid.
- The ONLY_TOOLS are from rust’s build system make command
- The build process requires some tools that needed to be built and run during the build. In the configure stage you set the proper flags (build is darwin, host is haiku and target is haiku). After issuing make, the build system will invoke another instance of configure to properly build these host tools (where build, host and target are darwin).
Step 2.2: compiler-rt
cd $(RUST_HAIKU_STAGE0)
mkdir -p rt/compiler-rt
make -C "$(RUST_SOURCE_DIR)/src/compiler-rt" ProjSrcRoot="$(RUST_SOURCE_DIR)/src/compiler-rt" ProjObjRoot="$(RUST_HAIKU_STAGE0)/rt/compiler-rt" CC="i586-pc-haiku-gcc" AR="i586-pc-haiku-ar" RANLIB="i586-pc-haiku-ar s" CFLAGS="-Wall -Werror -g -fPIC -m32 " TargetTriple=i686-unknown-haiku triple-builtins
cp rt/compiler-rt/triple/builtins/libcompiler_rt.a rt/libcompiler-rt.a
Step 2.3: llvmdeps.rs
The build of the module rustc_llvm depends on a generated file. This file is generated by mklldeps.py that can be found in the Rust source. This script has to run on the target-platform, and it needs llvm-config compiled for that target platform.
For me, running the script outright did not work. So instead I copied by built llvm-config to Haiku, run the command that is used in the script, and manually built up the file. I have attached my llvmdeps.rs file to this page, for your reference. Place this file in a known place, for example in the rt folder of the $(RUST_HAIKU_STAGE0) directory.
Step 2.4: rustrt
$(RUST_SOURCE_DIR)/x86_64-apple-darwin/llvm/Release+Asserts/bin/llc -filetype=obj -mtriple=i686-unknown-haiku -relocation-model=pic -o rt/rust_try.o $(RUST_SOURCE_DIR)/src/rt/rust_try.ll
i586-pc-haiku-gcc -E -E -MMD -MP -MT rt/arch/i386/record_sp.o -MF rt/arch/i386/record_sp.d $(RUST_SOURCE_DIR)/src/rt/arch/i386/record_sp.S | $(RUST_SOURCE_DIR)/x86_64-apple-darwin/llvm/Release+Asserts/bin/llvm-mc -assemble -filetype=obj -triple=i686-unknown-haiku -o=rt/arch/i386/record_sp.o
i586-pc-haiku-ar rcs rt/librustrt_native.a rt/rust_try.o rt/arch/i386/record_sp.o
i586-pc-haiku-gcc -DRUST_DEBUG -O2 -Wall -Werror -g -fPIC -m32 -MMD -MP -MT rt/rust_builtin.o -MF rt/rust_builtin.d -c -o rt/rust_builtin.o -I $(RUST_SOURCE_DIR)/src/rt/hoedown/src -I $(RUST_SOURCE_DIR)/src/rt $(RUST_SOURCE_DIR)/src/rt/rust_builtin.c
i586-pc-haiku-gcc -DRUST_DEBUG -O2 -Wall -Werror -g -fPIC -m32 -MMD -MP -MT rt/rust_android_dummy.o -MF rt/rust_android_dummy.d -c -o rt/rust_android_dummy.o -I $(RUST_SOURCE_DIR)/src/rt/hoedown/src -I $(RUST_SOURCE_DIR)/src/rt $(RUST_SOURCE_DIR)/src/rt/rust_android_dummy.c
i586-pc-haiku-ar rcs rt/librust_builtin.a rt/rust_builtin.o rt/rust_android_dummy.o
Note about above:
- The rust build system generates the rust_android_dummy.o using
touch. Haiku's ar did not like that as input though, so the file had to be generated with gcc. - Note that this command depends on that a native build for the build platform exists in $(RUST_SOURCE_DIR).
Step 2.5: libbacktrace
mkdir -p rt/libbacktrace
(cd rt/libbacktrace && CC="i586-pc-haiku-gcc" AR="i586-pc-haiku-ar" RANLIB="i586-pc-haiku-ar s" CFLAGS="-Wall -g -fPIC -m32 -fno-stack-protector" $(RUST_SOURCE_DIR)/src/libbacktrace/configure --target=i686-unknown-haiku --host=x86_64-apple-darwin)
make -C rt/libbacktrace INCDIR=$(RUST_SOURCE_DIR)/src/libbacktrace
cp rt/libbacktrace/.libs/libbacktrace.a rt/libbacktrace.a
Step 2.6: copy the existing cross-compiler
The basis for the new stage 0 compiler will be the existing cross-compiler. This cross-compiler already generates haiku-binaries, and it also contains various dependencies for the compiler, such as libstd. The following command copies the bin/ and lib/ folders with our cross-compiler.
cp -R $(RUST_SOURCE_DIR)/x86_64-apple-darwin/stage2/* .
Step 2.7 Compiling function
In the next steps we will use the existing cross-compiler to build our native compiler. In order to get all the commands right, I make a shell function.
function compile_rust_lib {
DYLD_LIBRARY_PATH=$(RUST_HAIKU_STAGE0)/lib:$DYLD_LIBRARY_PATH $(RUST_HAIKU_STAGE0)/bin/rustc --cfg stage0 -O --cfg rtopt --cfg debug --target=i686-unknown-haiku -C linker=i586-pc-haiku-gcc -C prefer-dynamic -W warnings -L "rt" -L "$(RUST_HAIKU_STAGE0)/llvm/Release+Asserts/lib" -L "" --out-dir lib/rustlib/i686-unknown-haiku/lib -C extra-filename=-4e7c5e5c $(RUST_SOURCE_DIR)/src/lib$1/lib.rs
}
Step 2.8: compiling the libs
compile_rust_lib fmt_macros
compile_rust_lib syntax
mkdir rustllvm
i586-pc-haiku-c++ -DRUST_DEBUG -O2 -Wall -Werror -g -fPIC -m32 -fno-rtti -MMD -MP -MT rustllvm/ExecutionEngineWrapper.o -MF rustllvm/ExecutionEngineWrapper.d -c -o rustllvm/ExecutionEngineWrapper.o -iquote $(RUST_SOURCE_DIR)/src/llvm/include -iquote $(RUST_HAIKU_STAGE0)/llvm/include -D_DEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -O3 -std=c++11 -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -fno-common -Wcast-qual -iquote $(RUST_SOURCE_DIR)/src/llvm/include -iquote $(RUST_SOURCE_DIR)/src/rustllvm/include $(RUST_SOURCE_DIR)/src/rustllvm/ExecutionEngineWrapper.cpp
i586-pc-haiku-c++ -DRUST_DEBUG -O2 -Wall -Werror -g -fPIC -m32 -fno-rtti -MMD -MP -MT rustllvm/RustWrapper.o -MF rustllvm/RustWrapper.d -c -o rustllvm/RustWrapper.o -iquote $(RUST_SOURCE_DIR)/src/llvm/include -iquote $(RUST_HAIKU_STAGE0)/llvm/include -D_DEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -O3 -std=c++11 -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -fno-common -Wcast-qual -iquote $(RUST_SOURCE_DIR)/src/llvm/include -iquote $(RUST_SOURCE_DIR)/src/rustllvm/include $(RUST_SOURCE_DIR)/src/rustllvm/RustWrapper.cpp
i586-pc-haiku-c++ -DRUST_DEBUG -O2 -Wall -Werror -g -fPIC -m32 -fno-rtti -MMD -MP -MT rustllvm/PassWrapper.o -MF rustllvm/PassWrapper.d -c -o rustllvm/PassWrapper.o -iquote $(RUST_SOURCE_DIR)/src/llvm/include -iquote $(RUST_HAIKU_STAGE0)/llvm/include -D_DEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -O3 -std=c++11 -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -fno-common -Wcast-qual -iquote $(RUST_SOURCE_DIR)/src/llvm/include -iquote $(RUST_SOURCE_DIR)/src/rustllvm/include $(RUST_SOURCE_DIR)/src/rustllvm/PassWrapper.cpp
i586-pc-haiku-ar rcs rt/librustllvm.a rustllvm/RustWrapper.o rustllvm/PassWrapper.o rustllvm/ExecutionEngineWrapper.o
CFG_LLVM_LINKAGE_FILE=$(PATH_TO_LLVMDEPS_DIRECTORY)/llvmdeps.rs compile_rust_lib rustc_llvm
compile_rust_lib rustc_back
compile_rust_lib rustc
compile_rust_lib rustc_borrowck
compile_rust_lib rustc_typeck
compile_rust_lib rustc_resolve
compile_rust_lib rustc_trans
compile_rust_lib rustc_privacy
compile_rust_lib rustc_driver
Note that in a certain step we use the llvmdeps.rs file.
Step 2.9: creating the binary
mkdir -p lib/rustlib/i686-unknown-haiku/bin/ DYLD_LIBRARY_PATH=$(RUST_HAIKU_STAGE0)/lib:$DYLD_LIBRARY_PATH $(RUST_HAIKU_STAGE0)/bin/rustc --cfg stage0 -O --cfg rtopt --cfg debug -Z no-landing-pads --target=i686-unknown-haiku -C linker=i586-pc-haiku-gcc -o lib/rustlib/i686-unknown-haiku/bin/rustc $(RUST_SOURCE_DIR)/src/driver/driver.rs --cfg rustc
Step 3: using the binary to compile the source
...
Attachments (1)
-
llvmdeps.rs (3.9 KB) - added by 4 years ago.
LLVM dependencies (semi-auto-generated) for rust-haiku-2015-03-09
Download all attachments as: .zip
