Skip to content

Commit

Permalink
Add macOS builds
Browse files Browse the repository at this point in the history
  • Loading branch information
wojtekmach committed Aug 2, 2024
1 parent f03ce04 commit 48471f9
Show file tree
Hide file tree
Showing 3 changed files with 236 additions and 10 deletions.
97 changes: 89 additions & 8 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Build macOS
on:
schedule:
# Run every 5 minute
- cron: '*/5 * * * *'
# Run nightly at 00:00
- cron: '0 0 * * *'

workflow_dispatch:
inputs:
Expand All @@ -11,10 +11,14 @@ on:
otp-ref:
openssl-version:
default: "3.1.6"

# TODO: remove push: before merging
push:
concurrency: builds_txt
jobs:
schedule:
name: "Schedule nightly"
if: github.event.schedule
name: "Schedule"
runs-on: ubuntu-latest
steps:
- run: |
Expand All @@ -24,10 +28,87 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build:
name: "Build OTP macOS ${{ matrix.arch }}"
if: github.event.inputs
name: "Build OTP macOS"
runs-on: ubuntu-latest
runs-on: macos-latest
env:
# TODO: Remove ` || ...` before merging.
OTP_REF_NAME: ${{ inputs.otp-ref-name || 'OTP-27.0.1' }}
OPENSSL_VERSION: ${{ inputs.openssl-version || '3.1.6' }}
OTP_DIR: /tmp/builds/otp-${{ inputs.otp-ref-name || 'OTP-27.0.1' }}-openssl-${{ inputs.openssl-version || '3.1.6' }}-macos-${{ matrix.arch }}
# TODO: use {{ github.sha }}
OTP_REF: ${{ inputs.otp-ref || 'ee9628e7ed09ef02e767994a6da5b7a225316aaa' }}
strategy:
matrix:
arch: [amd64, arm64]
steps:
- run: |
echo ${{ inputs.otp-ref-name }}
echo ${{ inputs.otp-ref }}
- uses: actions/checkout@v4

- uses: actions/cache@v4
with:
path: /tmp/builds/openssl-${{ env.OPENSSL_VERSION }}-macos-${{ matrix.arch }}
key: openssl-${{ env.OPENSSL_VERSION }}-macos-${{ matrix.arch }}

- uses: actions/cache@v4
with:
path: ${{ env.OTP_DIR }}
key: otp-${{ env.OTP_REF_NAME }}-openssl-${{ env.OPENSSL_VERSION }}-macos-${{ matrix.arch }}

- name: Build
run: |
sh priv/scripts/otp/build_otp_macos.sh "${{ env.OTP_REF_NAME }}" "${{ env.OTP_REF_NAME }}" "${{ matrix.arch }}"
- name: Upload
run: |
function purge_key() {
curl \
--fail \
--retry 10 \
-X POST \
-H "Fastly-Key: ${FASTLY_KEY}" \
-H "Accept: application/json" \
-H "Content-Length: 0" \
"https://api.fastly.com/service/${FASTLY_SERVICE_ID}/purge/$1"
}
ref_name=${{ env.OTP_REF_NAME }}
tgz=${{ env.OTP_REF_NAME }}.tar.gz
tar czf ${tgz} --cd ${{ env.OTP_DIR }} .
s3_base_url="s3://${{ env.AWS_S3_BUCKET }}/builds/otp/${{ matrix.arch }}/macos"
# Upload tar.gz
surrogate_key="builds/otp/${{ matrix.arch }}/macos/${{ env.OTP_REF_NAME }}"
aws s3 cp \
${tgz} \
"${s3_base_url}/${tgz}" \
--cache-control "public,max-age=3600" \
--metadata '{"surrogate-key":"builds builds/otp ${surrogate_key}","surrogate-control":"public,max-age=604800"}'
purge_key ${surrogate_key}
# Upload builds.txt
date=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
build_sha256=$(shasum -a 256 $tgz | cut -d ' ' -f 1)
aws s3 cp ${s3_base_url}/builds.txt builds.txt || true
touch builds.txt
sed -i.bak "/^${ref_name} /d" builds.txt
echo -e "${ref_name} ${{ env.OTP_REF }} ${date} ${build_sha256}\n$(cat builds.txt)" > builds.txt
sort -u -k1,1 -o builds.txt builds.txt
surrogate_key="builds/otp/${{ matrix.arch }}/macos/builds.txt"
aws s3 cp \
builds.txt \
${s3_base_url}/builds.txt \
--cache-control "public,max-age=3600" \
--metadata '{"surrogate-key":"builds builds/otp ${surrogate_key}","surrogate-control":"public,max-age=604800"}'
purge_key ${surrogate_key}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.BUILDS_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.BUILDS_AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.BUILDS_AWS_REGION }}
AWS_S3_BUCKET: ${{ secrets.BUILDS_AWS_S3_BUCKET }}
FASTLY_SERVICE_ID: ${{ secrets.BUILDS_FASTLY_SERVICE_ID }}
FASTLY_KEY: ${{ secrets.BUILDS_FASTLY_KEY }}
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ Documentation tarballs are also uploaded to `https://repo.hex.pm/docs/{APPLICATI

## Erlang builds

Erlang builds compiled on Ubuntu LTS versions are built periodically. Bob checks for new tagged releases every 15 minutes and builds any new versions it discovers. The "master" and "maint*" branches are built once a day.
Erlang builds compiled on Ubuntu LTS versions and macOS are built periodically. Bob checks for new tagged releases every 15 minutes and builds any new versions it discovers. The "master" and "maint*" branches are built once a day.

> [!WARNING]
> macOS builds are currently in beta and can change anytime. Only OTP 27+ is supported. Builds are triggered manually at the moment.
After the builds complete they will be available at `https://builds.hex.pm/builds/otp/${ARCH}/${OS_VER}/${REF}.tar.gz` where `${ARCH}` is the CPU architecture, `${OS_VER}` is the OS name and version, and `${REF}` is the name of the git tag or branch.

Expand All @@ -42,28 +45,33 @@ Supported architectures:
* `amd64`
* `arm64`

Supported OS versions:
Supported OS/versions:

* `ubuntu-20.04`
* `ubuntu-22.04`
* `ubuntu-24.04`
* `macos`

Examples of URLs are:

* https://builds.hex.pm/builds/otp/amd64/ubuntu-20.04/master.tar.gz
* https://builds.hex.pm/builds/otp/arm64/ubuntu-22.04/OTP-26.0.tar.gz
* https://builds.hex.pm/builds/otp/amd64/ubuntu-24.04/maint.tar.gz
* https://builds.hex.pm/builds/otp/arm64/macos/OTP-27.0.1.tar.gz

For lists of builds see:

* `amd64`:
* https://builds.hex.pm/builds/otp/amd64/ubuntu-20.04/builds.txt
* https://builds.hex.pm/builds/otp/amd64/ubuntu-22.04/builds.txt
* https://builds.hex.pm/builds/otp/amd64/ubuntu-24.04/builds.txt
* https://builds.hex.pm/builds/otp/amd64/macos/builds.txt

* `arm64`:
* https://builds.hex.pm/builds/otp/arm64/ubuntu-20.04/builds.txt
* https://builds.hex.pm/builds/otp/arm64/ubuntu-22.04/builds.txt
* https://builds.hex.pm/builds/otp/arm64/ubuntu-24.04/builds.txt
* https://builds.hex.pm/builds/otp/arm64/macos/builds.txt

## Docker images

Expand Down
137 changes: 137 additions & 0 deletions priv/scripts/otp/build_otp_macos.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#!/bin/bash

set -euox pipefail

main() {
if [ $# -ne 3 ]; then
cat <<EOF
Usage:
build_otp_macos.sh ref_name ref arch
EOF
exit 1
fi

local ref_name=$1
local ref=$2
local arch=$3
: "${OPENSSL_VERSION:=3.1.6}"
: "${OPENSSL_DIR:=/tmp/builds/openssl-${OPENSSL_VERSION}-macos-${arch}}"
: "${OTP_DIR:=/tmp/builds/otp-${ref_name}-openssl-${OPENSSL_VERSION}-macos-${arch}}"
export MAKEFLAGS=-j$(nproc)
export CFLAGS="-Os -fno-common -mmacosx-version-min=11.0"

case "${arch}" in
amd64) ;;
arm64) ;;
*)
echo "bad arch ${arch}"
exit 1
esac

build_openssl "${OPENSSL_VERSION}" "${arch}"
build_otp "${ref_name}" "${arch}"
}

build_openssl() {
local version=$1
local arch=$2
local rel_dir=${OPENSSL_DIR}
local src_dir=/tmp/builds/src-openssl-${version}

if [ -d "${rel_dir}/bin" ]; then
echo "${rel_dir}/bin already exists, skipping build"
${rel_dir}/bin/openssl version
return
fi

case "${arch}" in
amd64) arch=x86_64 ;;
arm64) ;;
esac

ref=openssl-${version}
url=https://github.com/openssl/openssl

if [ ! -d ${src_dir} ]; then
git clone --depth 1 ${url} --branch ${ref} ${src_dir}
fi

(
cd ${src_dir}
git clean -dfx
./Configure "darwin64-${arch}-cc" --prefix=${rel_dir} ${CFLAGS}
make clean
make
make install_sw
)

if ! ${rel_dir}/bin/openssl version; then
rm -rf ${rel_dir}
fi
}

build_otp() {
local ref_name=$1
local arch=$2
local rel_dir=${OTP_DIR}
local src_dir=/tmp/builds/src-otp-${ref_name}
local test_cmd="erl -noshell -eval 'io:format(\"~s~s~n\", [erlang:system_info(system_version), erlang:system_info(system_architecture)]), ok = crypto:start(), io:format(\"crypto ok~n\"), halt().'"

if [[ "$ref_name" == *maint-* || "$ref_name" == *master* ]]; then
rm -rf ${rel_dir} ${src_dir}
fi

if [ -d "${rel_dir}/bin" ]; then
echo "${rel_dir}/bin already exists, skipping build"
eval ${rel_dir}/bin/${test_cmd}
return
fi

case "${arch}" in
amd64) arch=x86_64 ;;
arm64) ;;
esac

url=https://github.com/erlang/otp

if [ ! -d ${src_dir} ]; then
git clone --depth 1 ${url} --branch ${ref_name} ${src_dir}
fi

(
cd $src_dir
git clean -dfx
export ERL_TOP=$PWD
export ERLC_USE_SERVER=true
xcrun="xcrun -sdk macosx"
sysroot=`$xcrun --show-sdk-path`

./otp_build configure --enable-bootstrap-only

erl_xcomp_sysroot=$sysroot \
CC="$xcrun cc -arch $arch" \
CFLAGS="$CFLAGS" \
CXX="$xcrun c++ -arch $arch" \
CXXFLAGS="$CFLAGS" \
LD="$xcrun ld" \
LDFLAGS="-lc++" \
RANLIB="$xcrun ranlib" \
./otp_build configure \
--build=`erts/autoconf/config.guess` \
--host="$arch-apple-darwin" \
--with-ssl=${OPENSSL_DIR} \
--disable-dynamic-ssl-lib \
--without-{javac,odbc,wx,observer,debugger,et}

./otp_build boot -a
./otp_build release -a ${rel_dir}
cd ${rel_dir}
./Install -cross -sasl $PWD
)

if ! eval ${rel_dir}/bin/erl ${test_cmd}; then
rm -rf ${rel_dir}
fi
}

main $@

0 comments on commit 48471f9

Please sign in to comment.