joeylib2/make/support/be/gcc2.sh
2026-10-13 14:01:46 -05:00

181 lines
7.1 KiB
Bash
Executable file

#!/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
# <header>, 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 maths 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"