joeylib2/make/support/macos/cc.sh

106 lines
3.6 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
#
# The macOS port's C compiler (make/macos.mk; the installer builds SDL with
# it too): zig cc once for each architecture in MACOS_ARCHS -- by default
# Apple silicon and Intel -- with the results joined into one universal file
# by llvm-lipo, as Apple's own clang does when given two -arch flags. It
# takes what a C compiler takes: with -c it makes a universal object, else a
# universal program. The first architecture's run is exactly the call it was
# given, so its dependency file (-MMD) comes out as a plain compiler's; the
# other runs leave theirs out. With one architecture, or with no -o (a
# preprocessing run), it is zig cc for the first architecture alone.
#
# Programs run on macOS MACOS_MIN or newer: Ventura, which every Apple
# silicon Mac runs and the Intel ones from 2017 on.
#
# From the environment (toolchains/config.mk, which make exports): ZIG and
# its cache folders, MACOS_SDK and MACOS_LIPO.
#
# Usage: cc.sh COMPILER-ARGUMENTS...
# cc.sh --minimum prints MACOS_MIN (for an Info.plist)
set -euo pipefail
MACOS_MIN=13.0
read -r -a archs <<< "${MACOS_ARCHS:-aarch64 x86_64}"
if [[ "${1:-}" == --minimum ]]; then
printf '%s\n' "$MACOS_MIN"
exit 0
fi
if [[ -z "${ZIG:-}" || -z "${MACOS_SDK:-}" || -z "${MACOS_LIPO:-}" ]]; then
echo "$0: ZIG, MACOS_SDK or MACOS_LIPO is not set; run ./install.sh install toolchain:macos" >&2
exit 1
fi
out=""
compile=0
preprocess=0
prev=""
for arg in "$@"; do
if [[ "$prev" == -o ]]; then
out="$arg"
fi
case "$arg" in
-c) compile=1 ;;
-E) preprocess=1 ;;
esac
prev="$arg"
done
# zig brings the C library's headers and libSystem's stubs; the SDK the
# rest, after them (so the caller's own come first): its other headers, its
# frameworks, and, for a link, the stub libraries beside them. zig cc
# builds for UBSan unless told not to, and would then want its runtime; and
# it warns, as no other port's compiler does, at __DATE__ and __TIME__ (a
# build that uses them cannot be reproduced), which -Werror would make fatal.
flags=(-fno-sanitize=undefined -Wno-date-time -idirafter "$MACOS_SDK/usr/include" -F"$MACOS_SDK/System/Library/Frameworks")
if [[ $compile -eq 0 && $preprocess -eq 0 ]]; then
flags+=(-L"$MACOS_SDK/usr/lib")
fi
# zig refuses a target with a version for a run that only preprocesses (a
# build system asking what the compiler defines), and the version makes no
# difference to that.
target() {
if [[ $preprocess -eq 1 ]]; then
printf '%s-macos\n' "$1"
else
printf '%s-macos.%s\n' "$1" "$MACOS_MIN"
fi
}
if [[ ${#archs[@]} -eq 1 || -z "$out" ]]; then
exec "$ZIG" cc -target "$(target "${archs[0]}")" "$@" "${flags[@]}"
fi
slices=()
trap 'rm -f "${slices[@]}"' EXIT
for arch in "${archs[@]}"; do
slice="$out.$arch"
slices+=("$slice")
if [[ ${#slices[@]} -eq 1 ]]; then
"$ZIG" cc -target "$(target "$arch")" "$@" "${flags[@]}"
mv -f "$out" "$slice"
continue
fi
args=()
skip=0
for arg in "$@"; do
if [[ $skip -eq 1 ]]; then
skip=0
continue
fi
case "$arg" in
-o) args+=(-o "$slice"); skip=1 ;;
-MD|-MMD|-MP) ;;
-MF|-MT|-MQ) skip=1 ;;
*) args+=("$arg") ;;
esac
done
"$ZIG" cc -target "$(target "$arch")" "${args[@]}" "${flags[@]}"
done
"$MACOS_LIPO" -create "${slices[@]}" -output "$out"