Files
mosh/macosx/build.sh
T
Alex Chernyakhovsky 4cd2da5202 Switch macOS multi-arch to x86_64+arm64
The previous CI attemtped to use Homebrew for builds, but
unfortunately Homebrew has dropped support for universal packages aka
multiarch (fat) binaries. This means that in order to build an arm64 +
x86_64 package, macports has to be used instead of homebrew.

Unlike Homebrew, MacPorts is not installed by default on the GitHub
Actions runners, so we need to install it ourselves. This means
managing our own instance of the cache, which itself produces
challenges as the `gtar` binary run by the action doesn't have enough
permissions to restore the MacPorts checkout. So we have to shim gtar
with a sudo wrapper.

With this commit, we produce a Mosh package that works on macOS 11.0
and newer, on both arm64 and x86_64 architectures. The protobuf
library is statically linked, but all other libraries are provided by
the system.
2022-08-03 13:52:18 -10:00

157 lines
4.7 KiB
Bash
Executable File

#!/bin/bash
#
# This script is known to work on:
# OS X 10.5.8, Xcode 3.1.2, SDK 10.5, MacPorts 2.3.3
# OS X 10.9.5, Xcode 5.1.1, SDK 10.9, MacPorts 2.3.2
# OS X 10.10.3, XCode 6.3.2, SDK 10.10, Homebrew 0.9.5/8da6986
#
# You may need to set PATH to include the location of your
# PackageMaker binary, if your system is old enough to need that.
# Setting MACOSX_DEPLOYMENT_TARGET will select an SDK as usual.
#
# If you are using Homebrew, you should install protobuf (and any
# other future Homebrew dependencies) with
# `--universal --build-bottle`.
# The first option should be fairly obvious; the second has the side
# effect of disabling Homebrew's overzealous processor optimization
# with (effectively) `-march=native`.
#
set -e
protobuf_LIBS=$(l=libprotobuf.a; for i in /opt/local/lib /usr/local/lib; do if [ -f $i/$l ]; then echo $i/$l; fi; done)
if [ -z "$protobuf_LIBS" ]; then echo "Can't find libprotobuf.a"; exit 1; fi
export protobuf_LIBS
if ! pkg-config --cflags protobuf > /dev/null 2>&1; then
protobuf_CFLAGS=-I$(for i in /opt /usr; do d=$i/local/include; if [ -d $d/google/protobuf ]; then echo $d; fi; done)
if [ "$protobuf_CFLAGS" = "-I" ]; then echo "Can't find protobuf includes"; exit 1; fi
export protobuf_CFLAGS
fi
echo "Building into prefix..."
#
# XXX This script abuses Configure's --prefix argument badly. It uses
# it as a $DESTDIR, but --prefix can also affect paths in generated
# objects. That is not *currently* a problem in mosh.
#
PREFIX="$(pwd)/prefix"
HOST="x86_64-apple-macosx${MACOSX_DEPLOYMENT_TARGET}"
ARCH_TRIPLES="x86_64-apple-macosx arm64-apple-macos"
pushd .. > /dev/null
if [ ! -f configure ];
then
echo "Running autogen."
PATH=/opt/local/bin:$PATH ./autogen.sh
fi
#
# Build archs one by one.
#
for triple in $ARCH_TRIPLES; do
arch=$(echo $triple | cut -d- -f1)
echo "Building for ${arch}..."
prefix="${PREFIX}_${arch}"
rm -rf "${prefix}"
mkdir "${prefix}"
if ./configure --prefix="${prefix}/local" --build="${triple}${MACOSX_DEPLOYMENT_TARGET}"\
--host="${HOST}" \
CC="cc -arch ${arch}" CPP="cc -arch ${arch} -E" CXX="c++ -arch ${arch}" \
TINFO_LIBS=-lncurses &&
make clean &&
make install -j8 V=1 &&
rm -f "${prefix}/etc"
then
# mosh-client built with Xcode 3.1.2 bus-errors if the binary is stripped.
# strip "${prefix}/local/bin/mosh-client" "${prefix}/local/bin/mosh-server"
BUILT_ARCHS="$BUILT_ARCHS $arch"
fi
done
if [ -z "$BUILT_ARCHS" ]; then
echo "No architectures built successfully"
exit 1
fi
echo "Building universal binaries for archs ${BUILT_ARCHS}..."
rm -rf "$PREFIX"
# Copy one architecture to get all files into place.
for arch in $BUILT_ARCHS; do
cp -Rp "${PREFIX}_${arch}" "${PREFIX}"
break
done
# Build fat binaries
# XXX will break with spaces in pathname
for prog in local/bin/mosh-client local/bin/mosh-server; do
archprogs=()
for arch in $BUILT_ARCHS; do
archprogs+=("${PREFIX}_${arch}/$prog")
done
lipo -create "${archprogs[@]}" -output "${PREFIX}/$prog"
done
perl -wlpi -e 's{#!/usr/bin/env perl}{#!/usr/bin/perl}' "$PREFIX/local/bin/mosh"
popd > /dev/null
PACKAGE_VERSION=$(cat ../VERSION)
OUTFILE="$PACKAGE_VERSION.pkg"
rm -f "$OUTFILE"
if which -s pkgbuild; then
# To replace PackageMaker, you:
# * make a bare package with the build products
# * essentially take the Distribution file that PackageMaker generated and
# use it as the --distribution input file for productbuild
echo "Preprocessing package description..."
PKGID=edu.mit.mosh.mosh.pkg
for file in Distribution; do
sed -e "s/@PACKAGE_VERSION@/${PACKAGE_VERSION}/g" ${file}.in > ${file}
done
echo "Running pkgbuild/productbuild..."
mkdir -p Resources/en.lproj
cp -p copying.rtf Resources/en.lproj/License
cp -p readme.rtf Resources/en.lproj/Readme
pkgbuild --root "$PREFIX" --identifier $PKGID $PKGID
productbuild --distribution Distribution \
--resources Resources \
--package-path . \
"$OUTFILE"
echo "Cleaning up..."
rm -rf $PKGID
else
echo "Preprocessing package description..."
INDIR=mosh-package.pmdoc.in
OUTDIR=mosh-package.pmdoc
mkdir -p "$OUTDIR"
pushd "$INDIR" > /dev/null
for file in *
do
sed -e 's/$PACKAGE_VERSION/'"$PACKAGE_VERSION"'/g' "$file" > "../$OUTDIR/$file"
done
popd > /dev/null
echo "Running PackageMaker..."
env PATH="/Applications/PackageMaker.app/Contents/MacOS:/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS:$PATH" PackageMaker -d mosh-package.pmdoc -o "$OUTFILE" -i edu.mit.mosh.mosh.pkg
echo "Cleaning up..."
rm -rf "$OUTDIR"
fi
if [ -f "$OUTFILE" ];
then
echo "Successfully built $OUTFILE with archs ${BUILT_ARCHS}."
else
echo "There was an error building $OUTFILE."
false
fi