diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..566c245 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +toolchain/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7febc5b --- /dev/null +++ b/Makefile @@ -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: + diff --git a/README.md b/README.md index ad6af18..054ecea 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/activate b/activate new file mode 100755 index 0000000..989ee69 --- /dev/null +++ b/activate @@ -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 diff --git a/util/build_toolchain.sh b/util/build_toolchain.sh new file mode 100755 index 0000000..d2096f9 --- /dev/null +++ b/util/build_toolchain.sh @@ -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 "${@}" diff --git a/util/helpers.sh b/util/helpers.sh new file mode 100755 index 0000000..6cefbb3 --- /dev/null +++ b/util/helpers.sh @@ -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 diff --git a/util/toolchain_helpers.sh b/util/toolchain_helpers.sh new file mode 100644 index 0000000..773a176 --- /dev/null +++ b/util/toolchain_helpers.sh @@ -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" + +}