Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143422949
D51087.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D51087.diff
View Options
Index: tools/build/cross-build-macos.sh
===================================================================
--- /dev/null
+++ tools/build/cross-build-macos.sh
@@ -0,0 +1,357 @@
+#!/bin/sh
+# Copyright (c) Mar 2025 Wolfram Schneider <wosch@FreeBSD.org>
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# cross-build-macos.sh - build FreeBSD/arm64 from source on macOS
+# for macOS 14.x and later. Supported FreeBSD branches are
+# stable/15 or later and main.
+#
+# Note: you need to install a new compiler and linker
+# with Homebrew first:
+# brew install llvm lld
+#
+# or with a specific clang version as LLVM20:
+# brew install llvm@20 lld@20
+#
+# Homebrew will install the Command Line Tools for Xcode as well.
+# If not, you can install them with: xcode-select --install
+#
+# get the FreeBSD source:
+# git clone https://codeberg.org/freebsd/freebsd-src
+# cd freebsd-src && ./tools/build/cross-build-macos.sh
+#
+# DEV examples:
+# fresh build (obj cleanup), without OPENSSL compiled, on 9 CPUs,
+# make in silend mode, for the targets buildworld + buildkernel + packages + ftp tarballs
+#
+# env ncpu=9 build_clean=YES build_targets_opt="-s MK_OPENSSL=no" debug=1 TAR_XZ_CMD=tar PKG_FORMAT=tgz \
+# build_targets="buildworld; buildkernel;packages;-C./release obj;-C./release ftp" ./tools/build/cross-build-macos.sh
+#
+
+set -e
+
+: ${debug:="1"}
+
+# homebrew LLVM version, e.g. for version 19: "@19"
+: ${homebrew_llvm_version="@20"}
+
+if [ "$(uname -m)" = "arm64" ]; then
+ # arm64 (Apple M1 ...)
+ : ${homebrew_home="/opt/homebrew"}
+ : ${TARGET:="arm64"}
+ : ${TARGET_ARCH:="aarch64"}
+else
+ # x86_64 (AMD64)
+ : ${homebrew_home="/usr/local"}
+ : ${TARGET:="amd64"}
+ : ${TARGET_ARCH:="amd64"}
+fi
+
+HOMEBREW_PATH="$homebrew_home/opt/llvm${homebrew_llvm_version}/bin:$homebrew_home/opt/lld${homebrew_llvm_version}/bin:$homebrew_home/bin"
+PATH="$HOMEBREW_PATH:/usr/local/bin:/usr/local/sbin:/bin:/usr/bin:/sbin:/usr/sbin"; export PATH
+clt_sdk_dir="/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"
+
+# the cross build directories as "bmake-build" need a seperate sub-directory for multiple
+# builds on the same machine
+_cwd_string=$(pwd | sed -e 's,/,,' -e 's,/,-,g')
+
+: ${TMPDIR:="/tmp"}
+: ${MAKEOBJDIRPREFIX:="$TMPDIR/freebsd-obj/${_cwd_string}"}; export MAKEOBJDIRPREFIX
+: ${nice_cmd="nice -n10 time"}
+
+# A list of targets to build.
+# If a target requires additional parameters, use a semicolon (";") for spaces
+# e.g. "-C release obj; -C release ftp"
+# or "-C usr.bin/locate"
+#
+
+# everything up to ftp tarballs
+: ${build_targets_release="buildworld;buildkernel;packages;-C./release obj;-C./release ftp"}
+
+if [ "$1" = "full" ]; then
+ build_targets="$build_targets_release"
+ shift
+elif [ "$1" = "buildworld" -o "$1" = "buildkernel" -o "$1" = "packages" ]; then
+ : ${build_targets="$1"}
+ shift
+elif [ "$1" = "release-ftp" ]; then
+ : ${build_targets="-C./release obj;-C./release ftp"}
+ shift
+else
+ : ${build_targets="buildworld;buildkernel"}
+fi
+
+# without clang TOOLCHAIN & debug: NO | YES
+: ${build_fast="YES"}
+
+# other make flags, e.g. "-s" or makefile variable as WITHOUT_MITKRB5=1
+if [ $build_fast = "YES" ]; then
+ : ${build_targets_opt="__MAKE_CONF=/dev/null WITHOUT_TOOLCHAIN=yes WITHOUT_DEBUG_FILES=yes"}
+
+ # due some bugs in bsdtar/xz and share/mk tarball can be really slow
+ : ${TAR_XZ_CMD="tar -Z"}
+ : ${PKG_FORMAT="tgz"}
+ export TAR_XZ_CMD PKG_FORMAT
+else
+ : ${build_targets_opt=""}
+fi
+
+# cleanup objdir for a fresh build (aka `make distclean')
+: ${build_clean="NO"}
+
+# by default show disk usage only for buildworld
+case $build_targets in
+ *buildworld* ) : ${build_show_du="YES"} ;;
+ * ) : ${build_show_du="NO"} ;;
+esac
+
+: ${ncpu:=$(sysctl -n hw.ncpu 2>/dev/null || nproc 2>/dev/null || echo 1)}
+: ${logrotate_max="32"}
+
+if [ "$1" = "help" ]; then
+
+cat <<EOF
+$0 [ help | full | buildworld | buildkernel | packages | release-ftp ]
+
+homebrew_llvm_version="${homebrew_llvm_version}" # LLVM version in homebrew, e.g. "@19" or "@20"
+build_targets="${build_targets}" # make targets to run, separated by semicolon ';'
+build_clean="${build_clean}" # cleanup objdir for a fresh build: "NO" | "YES"
+build_fast="${build_fast}" # without clang TOOLCHAIN & debug: "NO" | "YES"
+build_targets_opt="${build_targets_opt}" # other make flags, e.g.: "-s MK_OPENSSL=no"
+
+debug="${debug}" # 0 | 1
+nice_cmd="${nice_cmd}"
+ncpu="${ncpu}" # empty or number of CPUs to use
+logrotate_max="${logrotate_max}" # number of logfiles 1..N
+
+TARGET="${TARGET}"
+TARGET_ARCH="${TARGET_ARCH}"
+TMPDIR="${TMPDIR}"
+MAKEOBJDIRPREFIX="${MAKEOBJDIRPREFIX}"
+EOF
+
+ exit 0
+fi
+
+if [ ! -e Makefile.inc1 ]; then
+ echo "Makefile.inc1 missing, please run inside a fresh FreeBSD source checkout as /usr/src" >&2
+ exit 1
+fi
+
+if [ -z "$build_targets" ]; then
+ echo "env variable 'build_targets' is empty, nothing to do - give up" >&2
+ exit 1
+fi
+
+for i in clang clang++ clang-cpp ld.lld python3
+do
+ if ! env PATH=$HOMEBREW_PATH /usr/bin/which $i >/dev/null; then
+ echo "missing program: $i for PATH=$HOMEBREW_PATH" >&2
+ exit 1
+ fi
+done
+
+# https://wiki.freebsd.org/ExternalToolchain
+export CPP="clang-cpp"
+export CC="clang"
+export CXX="clang++"
+export XCC="clang"
+
+# due a bug in share/mk the XLD/LD value must be a full path
+#export XLD="ld.lld"
+export XLD="$homebrew_home/opt/lld${homebrew_llvm_version}/bin/ld.lld"
+export XCPP="clang-cpp"
+export XCXX="clang++"
+
+logrotate ()
+{
+ local file="$1"
+
+ if [ "$logrotate_max" = "" ]; then
+ return
+ elif [ "$logrotate_max" -le 0 ]; then
+ return
+ fi
+
+ for number in $(seq $logrotate_max 0)
+ do
+ next=$(($number + 1))
+ if [ -e "$file.$number.gz" -a $next -lt $logrotate_max ]; then
+ mv -f "$file.$number.gz" "$file.$next.gz"
+ fi
+ done
+ if [ -e "$file" ]; then
+ mv "$file" "$file.0"
+ gzip -f "$file.0"
+ fi
+}
+
+decho() {
+ local message="$1"
+ # -1 | 0 | 1 - use -1 to always show error messages
+ local d="$2"
+ # log to stdout and the logfile
+ local stdout="$3"
+
+ if [ -z "$d" ]; then
+ d="0"
+ fi
+
+ # debug messages to stderr
+ if [ $debug -gt $d ]; then
+ echo "-- $message" >&2
+ fi
+
+ # debug messages to logfile
+ if [ -n "$stdout" ]; then
+ echo "$message"
+ fi
+}
+
+: ${build_clean_delay=4}
+if [ "$build_clean" = "YES" ]; then
+ decho "cleanup obj files in ${build_clean_delay} seconds"
+ decho "MAKEOBJDIRPREFIX=$MAKEOBJDIRPREFIX"
+
+ # last change to hit ^C
+ for i in $(seq 1 ${build_clean_delay})
+ do
+ printf "."; sleep 1
+ done
+ echo ""
+
+ rm -rf $MAKEOBJDIRPREFIX
+else
+ decho "set MAKEOBJDIRPREFIX=$MAKEOBJDIRPREFIX"
+fi
+mkdir -p $MAKEOBJDIRPREFIX
+
+logrotate "macos.setup"
+# log infos about macOS setup
+(
+echo "Start time: $(date)"
+sysctl machdep.cpu.brand_string
+sysctl kern.osproductversion
+echo "$(sysctl hw.physicalcpu) / P-cores: $(sysctl hw.perflevel0.physicalcpu) / E-cores: $(sysctl hw.perflevel1.physicalcpu)"
+sysctl hw.memsize | awk '{ printf("%s %2.1f GB\n", $1, $2/1024/1024/1024) }'
+
+echo "Xcode path: $(xcode-select -p)"
+echo "Xcode version: $(pkgutil --pkg-info=com.apple.pkg.CLTools_Executables | grep '^version: ')"
+
+if [ -d $clt_sdk_dir ]; then
+ echo "SDK version: $(ls -l $clt_sdk_dir)"
+fi
+
+if [ -d .git ]; then
+ decho "local git branch: $(git branch | grep '^\*' | sed -e 's/^\* //')" 0 stdout
+ decho "last git commit: $(git log --oneline | head -n1)" 0 stdout
+fi
+
+# program version
+cat <<EOF
+
+PATH=$PATH
+
+clang path: $(which clang)
+installed at $(ls -lL $(which clang))
+$(clang --version)
+
+linker path: $(which ld.lld)
+installed at $(ls -lL $(which ld.lld))
+$(ld.lld -v 2>&1)
+EOF
+
+# env variables for cross compiling
+cat <<EOF
+
+TARGET=$TARGET TARGET_ARCH=$TARGET_ARCH
+
+CC=$CC
+CXX=$CXX
+CPP=$CPP
+XCC=$XCC
+XCXX=$XCXX
+XCPP=$XCPP
+XLD=$XLD
+EOF
+
+if [ -n "$TAR_XZ_CMD" -o -n "$PKG_FORMAT" ]; then
+ echo "TAR_XZ_CMD=$TAR_XZ_CMD"
+ echo "PKG_FORMAT=$PKG_FORMAT"
+fi
+
+case $homebrew_llvm_version in
+ @19 | @20) ;;
+ *) decho "warning: unsupported homebrew_llvm_version='$homebrew_llvm_version', only '@19' and '@20' are supported" 0 x;;
+esac
+
+if [ "$build_show_du" = "YES" ]; then
+ echo ""
+ echo "current MAKEOBJDIRPREFIX disk usage: $(du -hs $MAKEOBJDIRPREFIX)"
+fi
+echo "ncpu=$ncpu"
+
+echo ""
+if [ -n "$build_targets_opt" ]; then
+ decho "build_fast=$build_fast with make parameters: $build_targets_opt" 0 stdout
+fi
+echo ""
+decho "now run for ${TARGET}/${TARGET_ARCH} build_targets=\"${build_targets}\"" 0 stdout
+) > macos.setup
+
+#
+# build FreeBSD world and kernel
+#
+# expected runtime without TOOLCHAIN (build_fast="YES") for
+# iMac (Intel Core i5, 2019, 6-cores) ca. 119min
+# MacBook Air (M1, 2020, 4P/4E cores) ca. 42min
+# MacBook Pro (M1, 2021, 8P/2E cores) ca. 21min
+#
+# with TOOLCHAIN (build_fast="NO") it will be 2x slower
+#
+(
+set -e
+
+OLD_IFS=$IFS
+IFS=";"
+
+for target in $build_targets
+do
+ IFS=$OLD_IFS
+ log=$(echo $target | sed -E -e 's/[ ]?\-[^ ]+[ ]//; s/ /-/g; s/\//-/g')
+
+ # keep logs from previous run
+ logrotate "macos.$log"
+
+ decho "start target '$target' at $(date)" 0 x >> macos.setup
+
+ # cross compiling
+ if $nice_cmd ./tools/build/make.py -j$ncpu TARGET=$TARGET TARGET_ARCH=$TARGET_ARCH $build_targets_opt $target > macos.$log 2>&1; then
+ :
+ else
+ exit=$?
+
+ # keep track of bad git commits
+ git log --oneline | head -n1 > ".cross-build-macos-git-bad"
+
+ decho "make target '$target' failed with exit status: $exit - see the log file ./macos.$log" -1 x >> macos.setup
+ exit $exit
+ fi
+done
+)
+
+(
+ if [ "$build_show_du" = "YES" ]; then
+ echo ""
+ echo "MAKEOBJDIRPREFIX disk usage:"
+ du -hs $MAKEOBJDIRPREFIX
+ fi
+
+ # keep track of good git commits
+ git log --oneline | head -n1 > ".cross-build-macos-git-good"
+
+ echo ""
+ decho ">>> Build of target(s) $build_targets were successfully executed at $(date) <<<" 0 stdout
+) >> macos.setup
+
+#EOF
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 31, 7:42 AM (7 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28109841
Default Alt Text
D51087.diff (9 KB)
Attached To
Mode
D51087: cross-build-macos.sh - build FreeBSD/arm64 from source on MacOS for MacOS 14.x and later
Attached
Detach File
Event Timeline
Log In to Comment