
#!/usr/bin/env bash
#
# Title:        NKC m68k GCC SDK Installer
# Description:  Builds a complete m68k-elf bare-metal toolchain using
#               binutils 2.24, GCC 4.8.0 (C only) and Newlib 2.5.0 with
#               float printf support. Installs NKC SysGCC-delta runtime,
#               nkc-common and examples.
# Date:         2025-12-29
# Version:      0.99
# Usage:        ./install-m68k-gcc-4.8.0-nkc.sh
# Bash version: >= 4.2
# Notes:        No libgloss, bare-metal only
#

set -euo pipefail;

#######################################
# Global variables
#######################################
declare -r HomeDir="${HOME}";

declare -r Prefix="${HomeDir}/working/m68k-gcc";
declare -r BuildRoot="${HomeDir}/gcc-build";
declare -r SrcDir="${BuildRoot}/src";


declare -r Target="m68k-elf";

declare -r BinutilsVer="2.24";
declare -r GccVer="4.8.0";
declare -r NewlibVer="2.0.0";

declare -r BinutilsUrl="https://ftp.gnu.org/gnu/binutils/binutils-${BinutilsVer}.tar.bz2";
declare -r GccUrl="https://ftp.gnu.org/gnu/gcc/gcc-${GccVer}/gcc-${GccVer}.tar.bz2";
declare -r NewlibUrl="https://sourceware.org/pub/newlib/newlib-${NewlibVer}.tar.gz";
declare -r NkRepoUrl="https://github.com/avg67/nkc.git";

declare -r LockFile="/tmp/install-m68k-gcc-nkc.lock";

#######################################
# Lock handling
#######################################
function acquire_lock() {
    if [[ -f "${LockFile}" ]];
    then
        echo "Installer already running.";
        exit 1;
    fi;
    touch "${LockFile}";
}

function release_lock() {
    rm -f "${LockFile}";
}

#######################################
# Prepare directories
#######################################
function prepare_directories() {
    printf "\nPrepare directories....\n";

    mkdir -p "${Prefix}";
    mkdir -p "${BuildRoot}";
    mkdir -p "${SrcDir}";
    #mkdir -p "${ExamplesDir}";
}

#######################################
# Download sources
#######################################
function download_sources() {
    printf "\nDownload sources....\n";

    cd "${SrcDir}";
    printf "\nDownload binutils...\n";

    [[ -f "binutils-${BinutilsVer}.tar.bz2" ]] || wget "${BinutilsUrl}";
    printf "\nDownload gcc...\n";
    [[ -f "gcc-${GccVer}.tar.bz2" ]]      || wget "${GccUrl}";
    printf  "\nDownload Newlib...\n";
    [[ -f "newlib-${NewlibVer}.tar.gz" ]] || wget "${NewlibUrl}";
}

#######################################
# Extract sources
#######################################
function extract_sources() {
    printf "\nExtract sources....\n";
    cd "${SrcDir}";
    printf "\nExtract binutils....\n";

    [[ -d "binutils-${BinutilsVer}" ]] || tar xf "binutils-${BinutilsVer}.tar.bz2";

    if [[ ! -d "gcc-${GccVer}" ]];
    then
        printf "\nExtract gcc....\n";
        tar xf "gcc-${GccVer}.tar.bz2";
        cd "gcc-${GccVer}";
        ./contrib/download_prerequisites;
    fi;

    cd "${SrcDir}";
    printf "\nExtract newlib....\n";
    [[ -d "newlib-${NewlibVer}" ]] || tar xf "newlib-${NewlibVer}.tar.gz";
}

#######################################
# Build binutils
#######################################
        #--with-sysroot \


function build_binutils() {
    printf "\nBuild binutils....\n";

    mkdir -p "${BuildRoot}/binutils";
    cd "${BuildRoot}/binutils";

    "${SrcDir}/binutils-${BinutilsVer}/configure" \
        --target="${Target}" \
        --prefix="${Prefix}" \
        --disable-nls \
        --disable-werror;

    #make -j"$(nproc)";
    make -j2;
    make install;
}

#######################################
# Build GCC stage 1 (C only)
#######################################
    #export CC_FOR_BUILD="${Prefix}/bin/gcc";
    #export CFLAGS_FOR_BUILD="-O2 -D_GNU_SOURCE";
    #export CXXFLAGS_FOR_BUILD="-O2 -D_GNU_SOURCE";
    #export CPPFLAGS_FOR_BUILD="-D_GNU_SOURCE";
    #export CC="/usr/bin/gcc-12";
    #export CXX="/usr/bin/g++-12";

#        --with-arch=m68000 \
#        --with-cpu=68000 \
#        --disable-multilib \


function build_gcc_stage1() {
    printf "\nBuild gcc stage 1....\n";

    export CFLAGS="-fcommon -Wno-error";
    export CXXFLAGS="-fcommon -Wno-error -std=gnu++98";
    export CC_FOR_BUILD="/usr/bin/gcc-12";
    export CXX_FOR_BUILD="/usr/bin/g++-12";

    export MAKEINFO=true;

    export PATH="/usr/bin:/bin";

    mkdir -p "${BuildRoot}/gcc-stage1";
    cd "${BuildRoot}/gcc-stage1";

    "${SrcDir}/gcc-${GccVer}/configure" \
        --target="${Target}" \
        --prefix="${Prefix}" \
        --enable-languages=c \
        --without-headers \
        --with-newlib \
        --disable-nls \
        --disable-shared \
        --disable-threads \
        --disable-libssp \
        --disable-libmudflap \
        --disable-libquadmath \
        --disable-libatomic \
        --without-isl;

    #make -j"$(nproc)" all-gcc MAKEINFO=true;
    make all-gcc -j1 MAKEINFO=true;
    make install-gcc;
}

#######################################
# Build Newlib with float printf support
#######################################
#        --enable-newlib-io-long-double \
#        --enable-newlib-io-long-long \
#        --enable-newlib-register-fini \

function build_newlib() {
    printf "\nBuild newlib....\n";

    export PATH="${Prefix}/bin:${PATH}"
    export CFLAGS_FOR_TARGET="-mcpu=68000 -msoft-float";
    export CXXFLAGS_FOR_TARGET="-mcpu=68000 -msoft-float";
    export CC_FOR_TARGET="${HOME}/working/m68k-gcc/bin/m68k-elf-gcc";
    export AR_FOR_TARGET="${HOME}/working/m68k-gcc/bin/m68k-elf-ar";
    export RANLIB_FOR_TARGET="${HOME}/working/m68k-gcc/bin/m68k-elf-ranlib";

    mkdir -p "${BuildRoot}/newlib";
    cd "${BuildRoot}/newlib";

    "${SrcDir}/newlib-${NewlibVer}/configure" \
        --target="${Target}" \
        --prefix="${Prefix}" \
        --disable-nls \
        --disable-newlib-supplied-syscalls \
        --enable-newlib-io-float \
        --enable-newlib-io-c99-formats \
        --disable-libgloss;

    #make -j"$(nproc)";
    ## Parallele Prozesse
    make -j1;
    make install;
}

#######################################
# Build final GCC (C only)
#######################################
function build_gcc_final() {
    printf "\nBuild gcc final....\n";

    export CXXFLAGS="-std=gnu++98 -fpermissive";
    export CXX="/usr/bin/g++";
    export PATH="${Prefix}/bin:${PATH}";
    export MAKEINFO=true;

    mkdir -p "${BuildRoot}/gcc-final";
    cd "${BuildRoot}/gcc-final";

    "${SrcDir}/gcc-${GccVer}/configure" \
        --target="${Target}" \
        --prefix="${Prefix}" \
        --enable-languages=c \
        --disable-libstdcxx \
        --with-newlib \
        --disable-nls \
        --disable-shared \
        --disable-threads \
        --disable-libssp \
        --disable-libmudflap \
        --disable-libgomp \
        --disable-isl \
        --without-isl;

    #make -j"$(nproc)";
    make -j1 all-gcc MAKEINFO=true;
    make install-gcc;
    # Dann fehlt noch die Laufzeitibliothek libgcc.a
    make -j1 all-target-libgcc
    make install-target-libgcc
}

#######################################
# Install NKC SysGCC-delta components
#######################################
function install_nkc_components() {
    printf "\nInstall nkc_common....\n";
    declare TmpNkDir="${BuildRoot}/nkc-tmp";
    declare DeltaDir;

    declare -r ExamplesDir="${Prefix}/m68k-elf/Examples"; #m68k-elf/Examples/
    
    declare -r DstDeltaDir="${Prefix}";

    rm -rf "${TmpNkDir}";
    git clone --depth 1 "${NkRepoUrl}" "${TmpNkDir}";
    #exit 0;

    echo "Prefix: ${Prefix}"
    echo "ExamplesDir: ${ExamplesDir}"
    echo "DstDeltaDir: ${DstDeltaDir}"


    # Hier aufgehört und manuell weitergemacht



    DeltaDir="${TmpNkDir}/SW/SysGCC-delta";

    # Install examples and nkc-common
    #cp -r "${DeltaDir}/m68k-elf/Examples"   "${ExamplesDir}";
    #cp -r "${DeltaDir}/m68k-elf/nkc-common" "${Prefix}/m68k-elf/";
    #cp -r "${SrcDeltaDir}/m68k-elf"   "${DstDeltaDir}/";
    cp -rf "${DeltaDir}/m68k-elf/*"   "${DstDeltaDir}/";

    # Build NKC runtime
    cd "${DeltaDir}/m68k-elf";

    export PATH="${Prefix}/bin:${PATH}";

    make \
        CC=m68k-elf-gcc \
        AR=m68k-elf-ar \
        AS=m68k-elf-as;

    mkdir -p "${Prefix}/lib";
    mkdir -p "${Prefix}/include";

    cp crt/crt0.o        "${Prefix}/lib/";
    cp sys/libnkc.a      "${Prefix}/lib/";
    cp ld/nkc.ld         "${Prefix}/lib/";
    cp -r include/nkc    "${Prefix}/include/";

    rm -rf "${TmpNkDir}";
}



#######################################
# Main
#######################################
function main() {
    acquire_lock;
    trap release_lock EXIT;

#    export PATH="${Prefix}/bin:${PATH}";

    prepare_directories;
    download_sources;
    extract_sources;

    build_binutils;
    build_gcc_stage1;
    build_newlib;
    build_gcc_final;
    install_nkc_components;

    echo "NKC m68k GCC 4.8.0 SDK installation completed successfully.";
}

main;

exit 0;

## PYTHON3 mit pyserial




#######################################
# Install NKC SysGCC-delta components. Alternative
#######################################
function build_nkc_runtime() {
    printf "\nInstall nkc_common (alternate)....\n";
    declare TmpNkDir="${BuildDir}/nkc-tmp";
    declare SrcDeltaDir;
    declare DstDeltaDir;

    SrcDeltaDir="${TmpNkDir}/SW/SysGCC-delta";
    DstDeltaDir="${Prefix}";

    rm -rf "${TmpNkDir}";
    git clone --depth 1 "${NkRepoUrl}" "${TmpNkDir}";

    # Copy required SysGCC-delta directories
    cp -r "${SrcDeltaDir}/examples"   "${DstDeltaDir}/";
    cp -r "${SrcDeltaDir}/nkc-common" "${DstDeltaDir}/";
    cp -r "${SrcDeltaDir}/m68k-elf"   "${DstDeltaDir}/";

    # Build m68k-elf runtime
    cd "${DstDeltaDir}/m68k-elf";

    export PATH="${Prefix}/bin:${PATH}";

    make \
        CC=m68k-elf-gcc \
        AR=m68k-elf-ar \
        AS=m68k-elf-as;

    mkdir -p "${Prefix}/lib";
    mkdir -p "${Prefix}/include";

    cp crt/crt0.o        "${Prefix}/lib/";
    cp sys/libnkc.a      "${Prefix}/lib/";
    cp ld/nkc.ld         "${Prefix}/lib/";
    cp -r include/nkc    "${Prefix}/include/";

    rm -rf "${TmpNkDir}";
}


