FROM ubuntu:22.04 LABEL org.opencontainers.image.description="Dusk Engine — Sega Saturn build environment (sh2eb-elf cross-compiler + Yaul SDK)" ENV DEBIAN_FRONTEND=noninteractive ENV YAUL_INSTALL_ROOT=/opt/yaul # All variables required by Yaul's env.mk ENV YAUL_ARCH_SH_PREFIX=sh2eb-elf ENV YAUL_PROG_SH_PREFIX=sh2eb-elf ENV YAUL_ARCH_M68K_PREFIX=m68keb-elf ENV YAUL_BUILD_ROOT=/tmp/yaul-build ENV YAUL_BUILD=build ENV YAUL_OPTION_MALLOC_IMPL=tlsf ENV PATH="${YAUL_INSTALL_ROOT}/bin:${PATH}" # Toolchain source versions ARG BINUTILS_VER=2.40 ARG GCC_VER=12.3.0 # --------------------------------------------------------------------------- # 1. Host build tools # --------------------------------------------------------------------------- RUN apt-get update && apt-get install -y \ build-essential \ cmake \ git \ wget \ curl \ xz-utils \ python3 \ python3-pip \ python3-polib \ python3-pil \ python3-dotenv \ texinfo \ bison \ flex \ libgmp-dev \ libmpfr-dev \ libmpc-dev \ && rm -rf /var/lib/apt/lists/* RUN mkdir -p "${YAUL_INSTALL_ROOT}" # --------------------------------------------------------------------------- # 2. Download cross-compiler sources # --------------------------------------------------------------------------- RUN cd /tmp && \ wget -q "https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VER}.tar.xz" && \ wget -q "https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VER}/gcc-${GCC_VER}.tar.xz" && \ tar xf "binutils-${BINUTILS_VER}.tar.xz" && \ tar xf "gcc-${GCC_VER}.tar.xz" && \ rm "binutils-${BINUTILS_VER}.tar.xz" "gcc-${GCC_VER}.tar.xz" # Download GCC prerequisites (gmp, mpfr, mpc if not packaged) RUN cd /tmp/gcc-${GCC_VER} && contrib/download_prerequisites # --------------------------------------------------------------------------- # 3. sh2eb-elf binutils (SH-2 big-endian) # --------------------------------------------------------------------------- RUN mkdir -p /tmp/build-sh-binutils && cd /tmp/build-sh-binutils && \ /tmp/binutils-${BINUTILS_VER}/configure \ --target=sh2eb-elf \ --prefix="${YAUL_INSTALL_ROOT}" \ --disable-nls \ --disable-multilib \ --disable-werror \ && make -j"$(nproc)" && make install && \ rm -rf /tmp/build-sh-binutils # --------------------------------------------------------------------------- # 4. sh2eb-elf GCC stage 1 (compiler only, no C library yet) # --------------------------------------------------------------------------- RUN mkdir -p /tmp/build-sh-gcc1 && cd /tmp/build-sh-gcc1 && \ /tmp/gcc-${GCC_VER}/configure \ --target=sh2eb-elf \ --prefix="${YAUL_INSTALL_ROOT}" \ --enable-languages=c,c++ \ --without-headers \ --with-newlib \ --disable-nls \ --disable-shared \ --disable-multilib \ --disable-decimal-float \ --disable-threads \ --disable-libatomic \ --disable-libgomp \ --disable-libquadmath \ --disable-libssp \ --disable-libvtv \ --disable-libstdcxx \ && make -j"$(nproc)" all-gcc all-target-libgcc \ && make install-gcc install-target-libgcc && \ rm -rf /tmp/build-sh-gcc1 # Newlib does not recognise the sh2eb CPU name, and Yaul ships its own C # runtime in libyaul/libc/ anyway. Stage 1 (compiler + libgcc) is all # we need; Yaul's specs file overrides *startfile:/*endfile:/*lib: to empty # so nothing from a host C library is linked in. # --------------------------------------------------------------------------- # 7. m68k-elf binutils (Saturn 68EC000 sound CPU) # --------------------------------------------------------------------------- RUN mkdir -p /tmp/build-m68k-binutils && cd /tmp/build-m68k-binutils && \ /tmp/binutils-${BINUTILS_VER}/configure \ --target=m68k-elf \ --prefix="${YAUL_INSTALL_ROOT}" \ --disable-nls \ --disable-multilib \ --disable-werror \ && make -j"$(nproc)" && make install && \ rm -rf /tmp/build-m68k-binutils # --------------------------------------------------------------------------- # 8. m68k-elf GCC (compiler only; Yaul provides its own sound startup) # --------------------------------------------------------------------------- RUN mkdir -p /tmp/build-m68k-gcc && cd /tmp/build-m68k-gcc && \ /tmp/gcc-${GCC_VER}/configure \ --target=m68k-elf \ --prefix="${YAUL_INSTALL_ROOT}" \ --enable-languages=c \ --without-headers \ --with-newlib \ --disable-nls \ --disable-shared \ --disable-multilib \ --disable-libssp \ && make -j"$(nproc)" all-gcc && make install-gcc && \ rm -rf /tmp/build-m68k-gcc # Clean up source tarballs/trees RUN rm -rf /tmp/binutils-${BINUTILS_VER} /tmp/gcc-${GCC_VER} # --------------------------------------------------------------------------- # 9. Create m68keb-elf symlinks # Yaul expects YAUL_ARCH_M68K_PREFIX=m68keb-elf but we built m68k-elf. # m68k is always big-endian, so m68k-elf == m68keb-elf semantically. # --------------------------------------------------------------------------- RUN for tool in "${YAUL_INSTALL_ROOT}/bin/m68k-elf-"*; do \ base="$(basename "$tool")"; \ newname="${YAUL_INSTALL_ROOT}/bin/m68keb-elf-${base#m68k-elf-}"; \ ln -sf "$tool" "$newname"; \ done # --------------------------------------------------------------------------- # 10. Clone and install libyaul # --------------------------------------------------------------------------- RUN git clone --depth 1 --recurse-submodules \ https://github.com/yaul-org/libyaul.git /tmp/yaul && \ cd /tmp/yaul && \ YAUL_INSTALL_ROOT="${YAUL_INSTALL_ROOT}" \ YAUL_ARCH_SH_PREFIX=sh2eb-elf \ YAUL_PROG_SH_PREFIX=sh2eb-elf \ YAUL_ARCH_M68K_PREFIX=m68keb-elf \ YAUL_BUILD_ROOT=/tmp/yaul-build \ YAUL_BUILD=build \ YAUL_OPTION_MALLOC_IMPL=tlsf \ make install && \ rm -rf /tmp/yaul /tmp/yaul-build # --------------------------------------------------------------------------- # 11. Cross-compile zlib for sh2eb-elf via CMake # Using CMake (not ./configure) so we can set # CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY and skip link tests that # the bare-metal cross-compiler can't satisfy. # Install into ${YAUL_INSTALL_ROOT}/sh2eb-elf/ (Yaul sysroot layout). # --------------------------------------------------------------------------- RUN printf '%s\n' \ 'set(CMAKE_SYSTEM_NAME Generic)' \ 'set(CMAKE_SYSTEM_PROCESSOR sh2)' \ "set(CMAKE_C_COMPILER \"${YAUL_INSTALL_ROOT}/bin/sh2eb-elf-gcc\")" \ "set(CMAKE_AR \"${YAUL_INSTALL_ROOT}/bin/sh2eb-elf-ar\")" \ "set(CMAKE_RANLIB \"${YAUL_INSTALL_ROOT}/bin/sh2eb-elf-ranlib\")" \ 'set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)' \ 'set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)' \ 'set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)' \ 'set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)' \ > /tmp/sat-xc.cmake RUN wget -q https://zlib.net/zlib-1.3.1.tar.gz -O /tmp/zlib.tar.gz && \ tar xf /tmp/zlib.tar.gz -C /tmp && \ cmake -S /tmp/zlib-1.3.1 -B /tmp/zlib-build \ -DCMAKE_TOOLCHAIN_FILE=/tmp/sat-xc.cmake \ -DCMAKE_INSTALL_PREFIX="${YAUL_INSTALL_ROOT}/sh2eb-elf" \ -DCMAKE_C_FLAGS="-m2 -mb -fno-builtin -O2" \ -DBUILD_SHARED_LIBS=OFF \ && cmake --build /tmp/zlib-build -- -j"$(nproc)" \ && cmake --install /tmp/zlib-build \ && rm -rf /tmp/zlib-1.3.1 /tmp/zlib.tar.gz /tmp/zlib-build # --------------------------------------------------------------------------- # 12. Cross-compile libzip for sh2eb-elf (reuses /tmp/sat-xc.cmake above) # --------------------------------------------------------------------------- RUN wget -q https://libzip.org/download/libzip-1.10.1.tar.gz -O /tmp/libzip.tar.gz && \ tar xf /tmp/libzip.tar.gz -C /tmp && \ cmake -S /tmp/libzip-1.10.1 -B /tmp/libzip-build \ -DCMAKE_TOOLCHAIN_FILE=/tmp/sat-xc.cmake \ -DCMAKE_INSTALL_PREFIX="${YAUL_INSTALL_ROOT}/sh2eb-elf" \ -DCMAKE_FIND_ROOT_PATH="${YAUL_INSTALL_ROOT}/sh2eb-elf" \ -DCMAKE_C_FLAGS="-m2 -mb -fno-builtin -O2" \ -DZLIB_LIBRARY="${YAUL_INSTALL_ROOT}/sh2eb-elf/lib/libz.a" \ -DZLIB_INCLUDE_DIR="${YAUL_INSTALL_ROOT}/sh2eb-elf/include" \ -DENABLE_BZIP2=OFF \ -DENABLE_LZMA=OFF \ -DENABLE_ZSTD=OFF \ -DENABLE_OPENSSL=OFF \ -DENABLE_GNUTLS=OFF \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_EXAMPLES=OFF \ -DBUILD_DOCUMENTATION=OFF \ -DBUILD_REGRESS=OFF \ -DBUILD_TOOLS=OFF \ && cmake --build /tmp/libzip-build -- -j"$(nproc)" \ && cmake --install /tmp/libzip-build \ && rm -rf /tmp/libzip-1.10.1 /tmp/libzip.tar.gz /tmp/libzip-build /tmp/sat-xc.cmake /tmp/zlib.tar.gz 2>/dev/null || true WORKDIR /workdir VOLUME ["/workdir"]