[TOOLCHAIN] Building cross compiler, debugger and bootloader

This commit is contained in:
Thomas Lovén 2016-07-22 20:49:27 +02:00
parent 0ffcf4316d
commit 94999611d4
7 changed files with 315 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
toolchain/

10
Makefile Normal file
View File

@ -0,0 +1,10 @@
# Check that the build environment is setup
# Idea taken from https://github.com/klange/toaruos
ifeq ($(MITTOS64),)
$(error Build environment is not activated. Please source activate)
endif
.PHONY: all
all:

View File

@ -2,3 +2,20 @@ MITTOS64
========
By Thomas Lovén - 2016
For development, start by sourcing `activate.sh`
source ./activate.sh
Running `make` will automatically download and compile a cross compiler
toolchain and the grub bootloader.
It will also download and build objconv, which is required for building grub
under OSX. This will probably fail if you're not on a mac.
Building the cross compiler requires a c compiler as well as gmp, mpfr and mpc.
The c compiler installed by xcode command line tools will do. It's installed
automatically if you install homebrew. The rest of the packages can be
installed with homebrew. You'll also want homebrews ctags.
homebrew install gmp mpfr libmpc ctags

24
activate Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
# This file should be sourced before building mittos64:
# $ source ./activate
export MITTOS64=mittos64
. util/helpers.sh
export BUILDROOT=`pwd`
export TOOLCHAIN=${BUILDROOT}/toolchain
export PATH=${TOOLCHAIN}/bin:${PATH}
export TARGET=x86_64-elf
# shortcuts for some useful tools
alias dbg="x86_64-elf-linux-gdb"
alias objd="${TARGET}-objdump"
function decomp()
{
${TARGET}-objdump -S $1 | vim - -R
}
export PS1="(mittos64)${PS1}"
util/build_toolchain.sh -c || util/build_toolchain.sh

107
util/build_toolchain.sh Executable file
View File

@ -0,0 +1,107 @@
#!/usr/bin/env bash
. util/toolchain_helpers.sh
bindir=${TOOLCHAIN}/bin
packages=(binutils gcc gdb)
if [[ `uname` == 'Darwin' ]]; then
packages=("${packages[@]}" objconv)
fi
packages=("${packages[@]}" grub)
# Binutils 2.26
# Build with --with-sysroot for use in the future
binutils_checkfile=${bindir}/${TARGET}-ld
binutils_filename=binutils-2.26
binutils_url=ftp://ftp.gnu.org/gnu/binutils/${binutils_filename}.tar.gz
binutils_config="--target=${TARGET} \
--with-sysroot \
--disable-nls \
--disable-werror"
# GCC 6.1.0
# Build with --without-headers for now - this will be replaced later
gcc_checkfile=${bindir}/${TARGET}-gcc
gcc_filename=gcc-6.1.0
gcc_url=ftp://ftp.gnu.org/gnu/gcc/${gcc_filename}/${gcc_filename}.tar.gz
gcc_config="--target=${TARGET} \
--disable-nls \
--enable-languages=c,c++ \
--without-headers"
gcc_make="all-gcc all-target-libgcc"
gcc_install="install-gcc install-target-libgcc"
# GDB 7.12
gdb_checkfile=${bindir}/x86_64-elf-linux-gdb
gdb_filename=gdb-7.12
gdb_url=ftp://ftp.gnu.org/gnu/gdb/${gdb_filename}.tar.gz
gdb_config="--target=x86_64-elf-linux \
--disable-debug \
--disable-dependency-tracking \
--with-python=/usr"
# objconv
# This is required for building grub on OSX
objconv_checkfile=${bindir}/objconv
objconv_filename=objconv
objconv_url=git://github.com/vertis/objconv.git
function objconv_install() {
# Download and build objconv
local package=objconv
pushd ${STASH}/${package} >/dev/null
echo "Compiling"
g++ -o ${TOOLCHAIN}/bin/objconv -O2 src/*.cpp \
>/dev/null 2>>"${STASH}/error-${package}.log" || fail
popd >/dev/null
}
# GRUB
# The target x86_64-elf is close enough to what we want
# Make sure to use the right target compiler chains
grub_checkfile=${bindir}/grub-mkimage
grub_filename=grub
grub_url=git://git.savannah.gnu.org/grub.git
grub_config="--target=x86_64-elf \
--disable-werror \
TARGET_CC=${TARGET}-gcc \
TARGET_OBJCOPY=${TARGET}-objcopy \
TARGET_STRIP=${TARGET}-strip \
TARGET_NM=${TARGET}-nm \
TARGET_RANLIB=${TARGET}-ranlib"
grub_patchcmd="autogen.sh"
function checkall() {
for package in "${packages[@]}"
do
check ${package} || return 1
done
return 0
}
function main() {
# If called with -c the script will check if a rebuild is necessary
while getopts "c" OPTION
do
case ${OPTION} in
c)
checkall
exit $?
;;
esac
done
print_info "Preparing toolchain"
mkdir -p "${STASH}"
PATH=${TOOLCHAIN}/bin:${PATH}
for package in "${packages[@]}"
do
build_package ${package} || return 1
done
}
main "${@}"

36
util/helpers.sh Executable file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env bash
function print_info() {
echo -e "[\\033[36mINFO\\033[0m] $@"
}
function print_ok() {
echo -e "[\\033[32mOK\\033[0m] $@"
}
function print_warning() {
echo -e "[\\033[33mWARNING\\033[0m] $@"
}
function print_error() {
echo -e "[\\033[31mERROR\\033[0m] $@"
}
function die() {
print_error $@
exit 1
}
function check_toolchain() {
if [[ -z ${MITTOS64+x} ]]; then
die "TOOLCHAIN is not set. Please source activate"
exit 1
fi
}
check_toolchain
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
# Test output functions
print_info "This is an information message"
print_ok "This is OK"
print_warning "Be careful"
print_error "Something bad happened"
fi

120
util/toolchain_helpers.sh Normal file
View File

@ -0,0 +1,120 @@
#!/usr/bin/env bash
. util/helpers.sh
# check_toolchain
readonly STASH=${TOOLCHAIN}/stash
readonly PREFIX=${TOOLCHAIN}
function fail() {
print_error "Something went wrong"
print_info "You may be able to find some information about what in ${STASH}/error-PACKAGE"
die "Building toolchain failed"
}
function download() {
# download url
# Downloads the file at url unless cached
# Return true if a file was downloaded
local url=$1
pushd "${STASH}" >/dev/null
if [[ ${url} == git* ]]; then
local filename=$(basename "${url}" .git)
if [[ ! -d ${filename} ]]; then
echo "Cloning" "${filename}"
/usr/bin/env git clone --depth 1 "${url}" \
>/dev/null 2>&1 || fail
print_ok "Clone complete"
return 0
else
print_ok "Using cached ${filename}"
return 1
fi
else
local filename=$(basename "${url}")
if [[ ! -f ${filename} ]]; then
echo "Downloading" "${filename}"
/usr/bin/env curl -# -O "${url}" || fail
/usr/bin/env tar -xf "${filename}" || fail
print_ok "Download complete"
return 0
else
print_ok "Using cached" "${filename}"
return 1
fi
fi
popd >/dev/null
}
function check() {
# check package
# Check if a package is installed
# Returns true if installed
local package=$1
local file=${package}_checkfile
if [[ -f ${!file} ]]; then
return 0
fi
return 1
}
function config_make_install() {
local package=$1
local filename=${package}_filename
local config=${package}_config
local make=${package}_make
local install=${package}_install
mkdir -p "${STASH}/build-${package}"
pushd "${STASH}/build-${package}" >/dev/null || fail
rm -rf ./*
echo "Configuring"
../${!filename}/configure \
--prefix=${PREFIX} \
${!config-} \
>/dev/null 2>>"${STASH}/error-${package}.log" || fail
echo "Building"
make --jobs=100 ${!make-all} \
>/dev/null 2>>"${STASH}/error-${package}.log" || fail
echo "Installing"
make ${!install-install} \
>/dev/null 2>>"${STASH}/error-${package}.log" || fail
popd >/dev/null
}
function build_package() {
local package=$1
local filename=${package}_filename
local url=${package}_url
local patch=${package}_patchcmd
if check ${package}; then
print_ok "Package ${package} already built"
return 0
fi
print_info "Building ${package}"
echo "Downloading"
if download ${!url}; then
pushd "${STASH}/${!filename}" >/dev/null || fail
echo "Applying patches / preparing to build"
eval ${!patch}
popd >/dev/null
fi
echo "Building and installing"
if type -t "${package}_install" >/dev/null; then
eval "${package}_install"
else
config_make_install ${package}
fi
print_ok "Build complete"
}