#!/bin/bash set -e if [ -z "${CROSSCC_i686}" ]; then CROSSCC_i686=i686-elf-gcc fi if [ -z "${CROSSAS_i686}" ]; then CROSSAS_i686=i686-elf-as fi if [ -z "${CROSSCC_x8664}" ]; then CROSSCC_x8664=x86_64-elf-gcc fi if [ -z "${CROSSAS_x8664}" ]; then CROSSAS_x8664=x86_64-elf-as fi if [ -z "${CROSSLD_i686}" ]; then CROSSLD_i686=i686-elf-ld fi if [ -z "${CROSSLD_x8664}" ]; then CROSSLD_x8664=x86_64-elf-ld fi if [ -z "${STAGE1_DIR}" ]; then STAGE1_DIR="./stage1/" fi if [ -z "${STAGE2_DIR}" ]; then STAGE2_DIR="$(pwd)/stage2" fi if [ -z "${BUILD_DIR}" ]; then BUILD_DIR="$(pwd)/build" fi mkdir -p "${BUILD_DIR}" if [ -z "${TARGET}" ]; then TARGET="$(pwd)/bootloader" fi GLOBAL_CFLAGS=(-I./include -ffreestanding -m32 -nostdlib) LINKER_LD="linker.ld" # Stage 1 STAGE1_LD="${STAGE1_DIR}/linker.ld" STAGE1_C_FILES=$(find "${STAGE1_DIR}" -name "*.c") STAGE1_AS_FILES=$(find "${STAGE1_DIR}" -name "*.S") STAGE1_AS_TARGET="${BUILD_DIR}/stage1_as.o" STAGE1_CC_TARGET="${BUILD_DIR}/stage1_cc.o" STAGE1_TARGET="${BUILD_DIR}/stage1.bin" # Stage 2 STAGE2_LD="${STAGE1_DIR}/linker.ld" STAGE2_C_FILES=$(find "${STAGE2_DIR}" -name "*.c") STAGE2_AS_FILES=$(find "${STAGE2_DIR}" -name "*.S") STAGE2_AS_TARGET="${BUILD_DIR}/stage2_as.o" STAGE2_CC_TARGET="${BUILD_DIR}/stage2_cc.o" STAGE1_DIR="$(pwd)/stage1" STAGE2_DIR="$(pwd)/stage2" function usage { echo -e "Custom build system." echo -e "Available commands:" echo -e " ${0} all" echo -e " ${0} run" echo -e " ${0} build_drive" echo -e " ${0} clean" echo -e " ${0} stage1" } function build_lib { macro="$1" set -e local lib_cfiles=$(find "./lib/" -name "*.c") mkdir -p "${BUILD_DIR}/lib" for i in ${lib_cfiles[@]}; do "${CROSSCC_i686}" -m32 -c "$i" "${GLOBAL_CFLAGS[@]}" -o "${BUILD_DIR}/${i}.o" -D${macro} echo -e " [CC] ${i}" done echo "[LIB] Compiled libraries." } function stage1 { set -e if [[ -e "${BUILD_DIR}/${STAGE1_DIR}" ]] && [[ -f "${BUILD_DIR}/${STAGE1_DIR}" ]]; then mkdir -p "${BUILD_DIR}/${STAGE1_DIR}" echo -e "Creating the stage 1 build directory ${BUILD_DIR}/${STAGE1_DIR}" fi echo -e "Producing stage 1 binaries..." if [[ ${#STAGE1_AS_FILES[@]} -gt 0 ]] && [[ -n "${STAGE1_AS_FILES[@]}" ]]; then echo -e "[STAGE1] Found assembly files: " for i in ${STAGE1_AS_FILES[@]}; do mkdir -p "${BUILD_DIR}/${i}" "${CROSSAS_i686}" "$i" -o "${BUILD_DIR}/${i}.o" echo -e " [AS]: $i" done echo -e " [AS] Assembled stage 1." else echo -e "[STAGE1] No assembly files were found." fi if [[ ${#STAGE1_C_FILES[@]} -gt 0 ]] && [[ -n "${STAGE1_C_FILES[@]}" ]]; then echo -e "[STAGE1] Found C files: " for i in ${STAGE1_C_FILES[@]}; do "${CROSSCC_i686}" -c "$i" -o "${BUILD_DIR}/${i}.o" "${GLOBAL_CFLAGS[@]}" echo -e " [CC]: $i" done echo -e " [CC] Compiled stage 1." else echo -e "[STAGE1] No C files were found." fi if [[ ${#STAGE1_C_FILES[@]} -eq 0 ]] && [[ ${#STAGE1_AS_FILES[@]} -eq 0 ]]; then echo -e "[STAGE1] No stage1 files were found!" exit 1 fi echo -e "Stage 1 binaries completed." } function stage2 { if [[ -e "${BUILD_DIR}/${STAGE1_DIR}" ]] && [[ -f "${BUILD_DIR}/${STAGE1_DIR}" ]]; then mkdir -p "${BUILD_DIR}/${STAGE1_DIR}" fi ${CROSSAS_i686} "${STAGE2_AS_FILES}" -o "${STAGE2_AS_TARGET}" echo -e " [AS] Assembled stage 2." ${CROSSCC_x8664} "${STAGE2_C_FILES}" -o "${STAGE2_CC_TARGET}" echo -e " [CC] Compiled stage 2." } function link { set -e local linker_files=() echo -e "[LINK] Linking files..." for i in $(find "${BUILD_DIR}" -name "*.o"); do linker_files+=("$i") echo -e " [L] Added: $i" done "${CROSSLD_i686}" -T "${LINKER_LD}" "${linker_files[@]}" -o "${STAGE1_TARGET}" echo -e "[LINK] Linking complete." } function clean { if [[ -e "${BUILD_DIR}" && -d "${BUILD_DIR}" ]]; then echo -e "[CLEAN] Deleting build/ directory..." rm -rf "${BUILD_DIR}" fi if [[ -e "$(pwd)/disk.img" && -f "$(pwd)/disk.img" ]]; then echo -e "[CLEAN] Deleting disk.img..." rm "$(pwd)/disk.img" fi echo -e "[CLEAN] Project cleaned." } function build_image { dd if="${STAGE1_TARGET}" of="$(pwd)/disk.img" bs=512 count=15 } function run { qemu-system-x86_64 -drive format=raw,file="$(pwd)/disk.img" } function debug { qemu-system-x86_64 -drive format=raw,file="$(pwd)/disk.img" -S -s } function compile { echo "[COMPILE] Compiling and preparing the entire build." clean mkdir -p ./build/ build_lib "STAGE1" stage1 link build_image echo "[COMPILE] DONE" } function run { qemu-system-x86_64 -drive format=raw,file=disk.img } case "$1" in "all") compile ;; "run") compile && run ;; "debug") compile && debug ;; "stage1") stage1 ;; "build_drive") build_image ;; "clean") clean ;; "help"|"usage") usage exit 0 ;; "") echo -e "You must specify a command." echo -e "Type '${0} usage' or '${0} help' for more information." exit 1 ;; *) echo -e "Command not found: '${1}'" usage exit 1 ;; esac