wiki:PortingRust

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:

  1. On the supported build platform, create a cross-compiler that can generate binaries for the Haiku platform.
  2. 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-, and i586-pc-haiku-clang does 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

...

Last modified 4 years ago Last modified on Apr 11, 2015, 8:25:40 PM

Attachments (1)

Download all attachments as: .zip