#!/usr/bin/env bash # Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. # See LICENSE.md for license information. # SPDX-License-Identifier: MIT # # gcc2.sh - Haiku's gcc 2.95 cross compiler (component haikuGcc2, the # x86_gcc2 primary compiler, kept for BeOS binary compatibility) behind the # command line the shared build rules give a modern gcc, so make/hosted.mk # drives it unchanged. # # gcc2.sh ROOT gcc|g++|ar ARGS... # # ROOT is the component: cross/ holds the compiler, sysroot/ R1/beta6's # headers and libraries. With BE_R5_SYSROOT set (make beos: component # beosR5's sysroot) it builds for BeOS R5 instead, which the same ABI runs # on: R5's own header tree, start files and libraries in place of Haiku's. # Programs stay position-independent (-pie), as R5's own are (ET_DYN), but # their relocations are not combined (-z nocombreloc): the DT_RELCOUNT tag # that comes with combined ones is newer than R5, whose loader will not run # a program with a tag it does not know ("cannot execute binary file"). R5's # libroot leaves memcpy_internal and memset_internal to the loader, which # the driver already allows (--allow-shlib-undefined). The compiler was # built for /tools/cross-tools-x86_gcc2 and is not relocatable, so it is # pointed at its own programs (-B), and # gcc 2.95 has no --sysroot, so the headers it would find in # /boot/system/develop/headers on Haiku are named one by one. Its binutils # (ar too) find their shared libraries through LD_LIBRARY_PATH. As Haiku's # own gcc 2.95 does, the Be API's four-character constants ('BAPP') are not # warned about; strict aliasing stays off, and gcc2Attributes.h, beside this # script, is included first: the GCC attributes gcc 2.95 does not know. The # modern options are translated: # -Wextra is gcc 2.95's -W in C; in C++ it is left out, as -W warns # about the Be API's own headers # -MMD -MP gcc 2.95 has neither: the dependency file is made after a # successful compile by a second, -M, pass -- named and # targeted as a modern gcc would (X.d for -o X.o, NAME.d for a # program linked as -o NAME), every header also a target of # its own (-MP), so a deleted header does not stop make. The # toolchain's own headers are left out, as -MMD leaves out # system headers (gcc 2.95's -MM would leave out every #
, JoeyLib's own among them). set -euo pipefail root="$1" driver="$2" shift 2 machine="i586-pc-haiku" version="2.95.3-haiku-2017_07_20" cross="$root/cross" r5="${BE_R5_SYSROOT:-}" if [ -n "$r5" ]; then headerRoot="$r5/headers" # R5's gcc's include directories, under develop/headers. headerDirs="be be/app be/device be/drivers be/game be/interface be/kernel be/mail be/media be/midi be/midi2 be/net be/opengl be/storage be/support be/translation be/add-ons/graphics be/add-ons/input_server be/add-ons/screen_saver be/add-ons/tracker cpp gnu posix" libSetup=(-B"$r5/develop-lib/x86/" -L"$r5/develop-lib/x86" -L"$r5/system-lib") # What R5 lacks of C99's headers (stdint.h), beside this script, and # R5's gcc's system macro in place of Haiku's: the compiler says # __HAIKU__, as Haiku's own, where R5's said __BEOS__. compatSetup=(-isystem "$(dirname "$0")/r5" -U__HAIKU__ -D__BEOS__) # Where R5's libraries find each other's, when linking, and no combined # relocations (above). linkFlags=(-Wl,-rpath-link,"$r5/system-lib" -Wl,-z,nocombreloc) else develop="$root/sysroot/boot/system/develop" headerRoot="$develop/headers" # The include directories of Haiku's own gcc 2.95, in its order # (buildtools' legacy/gcc/gcc/config/i386/haiku.h), under develop/headers. headerDirs="os os/app os/device os/drivers os/game os/interface os/kernel os/locale os/mail os/media os/midi os/midi2 os/net os/opengl os/storage os/support os/translation os/add-ons/graphics os/add-ons/input_server os/add-ons/screen_saver os/add-ons/tracker os/be_apps/Deskbar os/be_apps/NetPositive os/be_apps/Tracker 3rdparty bsd glibc gnu posix" libSetup=(-B"$develop/lib/" -L"$develop/lib") compatSetup=() linkFlags=() fi export LD_LIBRARY_PATH="$cross/x86_64-unknown-linux-gnu/$machine/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" if [ "$driver" = ar ]; then exec "$cross/bin/$machine-ar" "$@" fi setup=(-B"$cross/lib/gcc-lib/$machine/$version/" -B"$cross/$machine/bin/" "${compatSetup[@]}") for dir in $headerDirs; do setup+=(-isystem "$headerRoot/$dir") done setup+=(-isystem "$headerRoot" -isystem "$headerRoot/c++" -include "$(dirname "$0")/gcc2Attributes.h") args=() # the compile, translated cppArgs=() # what the dependency pass needs: the preprocessor's options and the sources sources=() output="" compileOnly=0 depFile=0 while [ $# -gt 0 ]; do case "$1" in -Wextra) if [ "$driver" = gcc ]; then args+=(-W) fi ;; -MMD) depFile=1 ;; -MP) ;; -lm) # R5 keeps the math in libroot and has no libm. if [ -z "$r5" ]; then args+=(-lm) fi ;; -o) output="$2" args+=(-o "$2") shift ;; -c) compileOnly=1 args+=(-c) ;; -D*|-U*|-I*) args+=("$1") cppArgs+=("$1") ;; -isystem|-include|-imacros) args+=("$1" "$2") cppArgs+=("$1" "$2") shift ;; *.c|*.cc|*.cpp) args+=("$1") sources+=("$1") ;; *) args+=("$1") ;; esac shift done # After the caller's options: -Wall would turn the multi-character warning # back on. if [ "$compileOnly" = 1 ]; then linkFlags=() fi "$cross/bin/$machine-$driver" "${setup[@]}" "${libSetup[@]}" "${args[@]}" "${linkFlags[@]}" -Wno-multichar -fno-strict-aliasing if [ "$depFile" = 0 ] || [ ${#sources[@]} -eq 0 ] || [ -z "$output" ]; then exit 0 fi if [ "$compileOnly" = 1 ]; then dep="${output%.*}.d" else dep="$output.d" fi # One rule for the output from every source's rule, then each header as a # target of its own; nothing from the toolchain (or R5's sysroot). "$cross/bin/$machine-$driver" "${setup[@]}" -M "${cppArgs[@]}" "${sources[@]}" | awk -v target="$output" -v toolchain="$root/" -v sysroot="${r5:+$r5/}" ' { line = $0 sub(/\\$/, "", line) sub(/^[^:]*:/, "", line) count = split(line, words, " ") for (i = 1; i <= count; i++) { if (index(words[i], toolchain) != 1 && (sysroot == "" || index(words[i], sysroot) != 1) && !(words[i] in seen)) { seen[words[i]] = 1 order[++total] = words[i] } } } END { printf "%s:", target for (i = 1; i <= total; i++) { printf " %s", order[i] } printf "\n" for (i = 1; i <= total; i++) { if (order[i] !~ /\.(c|cc|cpp)$/) { printf "\n%s:\n", order[i] } } }' > "$dep"