2023-12-01 17:32:19 +00:00
|
|
|
# Copyright 2022 Google LLC
|
|
|
|
#
|
|
|
|
# Use of this source code is governed by a BSD-style
|
|
|
|
# license that can be found in the LICENSE file or at
|
|
|
|
# https://developers.google.com/open-source/licenses/bsd
|
|
|
|
|
|
|
|
# A reusable workflow to build and test Packager on every supported OS and
|
|
|
|
# architecture.
|
|
|
|
name: Build
|
|
|
|
|
|
|
|
# Runs when called from another workflow.
|
|
|
|
on:
|
|
|
|
workflow_call:
|
|
|
|
inputs:
|
|
|
|
ref:
|
|
|
|
required: true
|
|
|
|
type: string
|
|
|
|
# If true, start a debug SSH server on failures.
|
|
|
|
debug:
|
|
|
|
required: false
|
|
|
|
type: boolean
|
|
|
|
default: false
|
|
|
|
# If true, enable self-hosted runners in the build matrix.
|
|
|
|
self_hosted:
|
|
|
|
required: false
|
|
|
|
type: boolean
|
|
|
|
default: false
|
|
|
|
|
|
|
|
# By default, run all commands in a bash shell. On Windows, the default would
|
|
|
|
# otherwise be powershell.
|
|
|
|
defaults:
|
|
|
|
run:
|
|
|
|
shell: bash
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
# Configure the build matrix based on inputs. The list of objects in the
|
|
|
|
# build matrix contents can't be changed by conditionals, but it can be
|
|
|
|
# computed by another job and deserialized. This uses inputs.self_hosted to
|
|
|
|
# determine the build matrix, based on the metadata in build-matrix.json.
|
|
|
|
build_matrix_config:
|
|
|
|
name: Matrix configuration
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
outputs:
|
|
|
|
INCLUDE: ${{ steps.configure.outputs.INCLUDE }}
|
|
|
|
OS: ${{ steps.configure.outputs.OS }}
|
|
|
|
steps:
|
2024-03-05 17:28:51 +00:00
|
|
|
- uses: actions/checkout@v4
|
2023-12-01 17:32:19 +00:00
|
|
|
with:
|
|
|
|
ref: ${{ inputs.ref }}
|
|
|
|
|
|
|
|
- name: Configure Build Matrix
|
|
|
|
id: configure
|
|
|
|
shell: node {0}
|
|
|
|
run: |
|
|
|
|
const enableSelfHosted = ${{ inputs.self_hosted }};
|
|
|
|
|
|
|
|
// Use enableSelfHosted to decide what the build matrix below should
|
|
|
|
// include.
|
|
|
|
const {hosted, selfHosted} = require("${{ github.workspace }}/.github/workflows/build-matrix.json");
|
|
|
|
const include = enableSelfHosted ? hosted.concat(selfHosted) : hosted;
|
|
|
|
const os = include.map((config) => config.os);
|
|
|
|
|
|
|
|
// Output JSON objects consumed by the build matrix below.
|
|
|
|
const fs = require('fs');
|
|
|
|
fs.writeFileSync(process.env.GITHUB_OUTPUT,
|
|
|
|
[
|
|
|
|
`INCLUDE=${ JSON.stringify(include) }`,
|
|
|
|
`OS=${ JSON.stringify(os) }`,
|
|
|
|
].join('\n'),
|
|
|
|
{flag: 'a'});
|
|
|
|
|
|
|
|
// Log the outputs, for the sake of debugging this script.
|
|
|
|
console.log({enableSelfHosted, include, os});
|
|
|
|
|
|
|
|
build:
|
|
|
|
needs: build_matrix_config
|
|
|
|
strategy:
|
|
|
|
fail-fast: false
|
|
|
|
matrix:
|
|
|
|
include: ${{ fromJSON(needs.build_matrix_config.outputs.INCLUDE) }}
|
|
|
|
os: ${{ fromJSON(needs.build_matrix_config.outputs.OS) }}
|
|
|
|
build_type: ["Debug", "Release"]
|
|
|
|
lib_type: ["static", "shared"]
|
|
|
|
|
|
|
|
name: ${{ matrix.os_name }} ${{ matrix.target_arch }} ${{ matrix.build_type }} ${{ matrix.lib_type }}
|
|
|
|
runs-on: ${{ matrix.os }}
|
|
|
|
|
|
|
|
steps:
|
|
|
|
- name: Configure git to preserve line endings
|
|
|
|
# Otherwise, tests fail on Windows because "golden" test outputs will not
|
|
|
|
# have the correct line endings.
|
|
|
|
run: git config --global core.autocrlf false
|
|
|
|
|
|
|
|
- name: Checkout code
|
2024-03-05 17:28:51 +00:00
|
|
|
uses: actions/checkout@v4
|
2023-12-01 17:32:19 +00:00
|
|
|
with:
|
|
|
|
ref: ${{ inputs.ref }}
|
|
|
|
submodules: recursive
|
2024-03-12 20:09:38 +00:00
|
|
|
fetch-tags: true
|
2023-12-01 17:32:19 +00:00
|
|
|
|
|
|
|
- name: Install Linux deps
|
|
|
|
if: runner.os == 'Linux'
|
|
|
|
# NOTE: CMake is already installed in GitHub Actions VMs, but not
|
2024-02-14 21:59:18 +00:00
|
|
|
# necessarily in a self-hosted runner. We also need a minimum version
|
|
|
|
# that may be greater than what is available in Ubuntu, so we set up
|
|
|
|
# the official CMake PPA first.
|
2023-12-01 17:32:19 +00:00
|
|
|
run: |
|
2024-02-14 21:59:18 +00:00
|
|
|
kitware_key_url="https://apt.kitware.com/keys/kitware-archive-latest.asc"
|
|
|
|
kitware_key_path="/usr/share/keyrings/kitware-archive-keyring.gpg"
|
|
|
|
kitware_sources_path="/etc/apt/sources.list.d/kitware.list"
|
|
|
|
|
feat: Portable, fully-static release executables on Linux (#1351)
This adds the option FULLY_STATIC to create fully-static executables.
To create portable, fully-static release executables on Linux, we need
to use musl instead of glibc. Static executables from glibc are not
portable.
The popular musl-gcc wrapper does not support C++, so instead we use a
full musl cross-compiler toolchain in the build workflow.
To build FULLY_STATIC, the user must point to the appropriate
cross-compiler, as we do in the workflow. On systems where musl is the
native libc (such as Alpine Linux), this is not necessary.
I have also read that musl's allocator is not very fast in
multi-threaded applications. So when FULLY_STATIC is enabled, we will
also enable mimalloc, a replacement allocator that is very fast.
I tested a very basic packaging command to compare speeds of dynamic
glibc, static musl, and static musl+mimalloc:
dynamic glibc:
runs: 2.527, 2.798, 2.703, 2.756, 2.959
avg = 2.749, std dev = 0.156s
static musl:
runs: 2.813, 2.920, 3.129, 3.003, 2.738
avg = 2.921s, std dev = 0.154s
static musl+mimalloc:
runs: 2.291, 2.034, 2.415, 2.303, 2.265
avg = 2.262s, std dev = 0.140s
The mimalloc build is 82% faster than musl default allocator, 77% faster
than glibc, and has more consistent runtime characteristics (lower
standard deviation).
2024-02-27 18:47:04 +00:00
|
|
|
curl -sL "$kitware_key_url" | gpg --dearmor - \
|
2024-02-14 21:59:18 +00:00
|
|
|
| sudo tee "$kitware_key_path" >/dev/null
|
|
|
|
|
|
|
|
. /etc/lsb-release # Defines $DISTRIB_CODENAME (jammy, focal, etc)
|
|
|
|
|
|
|
|
echo "deb [signed-by=$kitware_key_path] https://apt.kitware.com/ubuntu/ $DISTRIB_CODENAME main" \
|
|
|
|
| sudo tee "$kitware_sources_path" >/dev/null
|
|
|
|
|
|
|
|
sudo apt update
|
|
|
|
sudo apt install -y \
|
2023-12-01 17:32:19 +00:00
|
|
|
cmake \
|
|
|
|
ninja-build
|
|
|
|
|
|
|
|
- name: Install Mac deps
|
|
|
|
if: runner.os == 'macOS'
|
|
|
|
# NOTE: GitHub Actions VMs on Mac do not install ninja by default.
|
|
|
|
run: |
|
|
|
|
brew install ninja
|
|
|
|
|
2024-03-04 22:02:39 +00:00
|
|
|
- name: Check Mac CPU architecture
|
|
|
|
if: runner.os == 'macOS'
|
|
|
|
# In case we get confused about GitHub's mac VM image labels,
|
|
|
|
# explicitly check that the CPU type matches our expectations.
|
|
|
|
run: |
|
|
|
|
if [[ "${{matrix.target_arch}}" == "arm64" ]]; then
|
|
|
|
CORRECT_LABEL="arm64"
|
|
|
|
else
|
|
|
|
CORRECT_LABEL="x86_64"
|
|
|
|
fi
|
|
|
|
|
|
|
|
LABEL=$(uname -m)
|
|
|
|
echo "Hardware label: \"$LABEL\""
|
|
|
|
|
|
|
|
if [[ "$LABEL" != "$CORRECT_LABEL" ]]; then
|
|
|
|
echo "Wrong hardware label \"$LABEL\", expecting \"$CORRECT_LABEL\"."
|
|
|
|
echo "Full uname string: $(uname -a)"
|
|
|
|
echo "Full sysctl CPU info:"
|
|
|
|
sysctl machdep.cpu
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
- name: Generate build files
|
|
|
|
run: |
|
|
|
|
mkdir -p build/
|
|
|
|
|
|
|
|
if [[ "${{ matrix.lib_type }}" == "shared" ]]; then
|
|
|
|
BUILD_SHARED_LIBS="ON"
|
|
|
|
else
|
|
|
|
BUILD_SHARED_LIBS="OFF"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# If set, override the default generator for the platform.
|
|
|
|
# Not every entry in the build matrix config defines this.
|
|
|
|
# If this is blank, CMake will choose the default generator.
|
|
|
|
export CMAKE_GENERATOR="${{ matrix.generator }}"
|
|
|
|
|
|
|
|
# If set, configure the build to restrict parallel operations.
|
|
|
|
# This helps us avoid the compiler failing due to a lack of RAM
|
|
|
|
# on our arm64 build devices (4GB RAM shared among 6 CPUs).
|
|
|
|
if [[ "${{ matrix.low_mem }}" != "" ]]; then
|
|
|
|
export PACKAGER_LOW_MEMORY_BUILD=yes
|
|
|
|
fi
|
|
|
|
|
feat: Portable, fully-static release executables on Linux (#1351)
This adds the option FULLY_STATIC to create fully-static executables.
To create portable, fully-static release executables on Linux, we need
to use musl instead of glibc. Static executables from glibc are not
portable.
The popular musl-gcc wrapper does not support C++, so instead we use a
full musl cross-compiler toolchain in the build workflow.
To build FULLY_STATIC, the user must point to the appropriate
cross-compiler, as we do in the workflow. On systems where musl is the
native libc (such as Alpine Linux), this is not necessary.
I have also read that musl's allocator is not very fast in
multi-threaded applications. So when FULLY_STATIC is enabled, we will
also enable mimalloc, a replacement allocator that is very fast.
I tested a very basic packaging command to compare speeds of dynamic
glibc, static musl, and static musl+mimalloc:
dynamic glibc:
runs: 2.527, 2.798, 2.703, 2.756, 2.959
avg = 2.749, std dev = 0.156s
static musl:
runs: 2.813, 2.920, 3.129, 3.003, 2.738
avg = 2.921s, std dev = 0.154s
static musl+mimalloc:
runs: 2.291, 2.034, 2.415, 2.303, 2.265
avg = 2.262s, std dev = 0.140s
The mimalloc build is 82% faster than musl default allocator, 77% faster
than glibc, and has more consistent runtime characteristics (lower
standard deviation).
2024-02-27 18:47:04 +00:00
|
|
|
# Do fully static release builds on Linux.
|
|
|
|
BUILD_CONFIG="${{ matrix.build_type }}-${{ matrix.lib_type }}"
|
|
|
|
if [[ "${{ runner.os }}" == "Linux" && \
|
|
|
|
"$BUILD_CONFIG" == "Release-static" ]]; then
|
|
|
|
# Enable build settings for fully-static.
|
|
|
|
FULLY_STATIC="ON"
|
|
|
|
|
|
|
|
# Use a musl toolchain, since glibc static executables are not
|
|
|
|
# portable.
|
|
|
|
if [[ "${{matrix.target_arch}}" == "arm64" ]]; then
|
|
|
|
MUSL_ARCH="aarch64"
|
|
|
|
else
|
|
|
|
MUSL_ARCH="x86_64"
|
|
|
|
fi
|
|
|
|
curl -LO https://musl.cc/"$MUSL_ARCH"-linux-musl-native.tgz
|
|
|
|
tar xf "$MUSL_ARCH"-linux-musl-native.tgz
|
|
|
|
export CC=`pwd`/"$MUSL_ARCH"-linux-musl-native/bin/"$MUSL_ARCH"-linux-musl-gcc
|
|
|
|
export CXX=`pwd`/"$MUSL_ARCH"-linux-musl-native/bin/"$MUSL_ARCH"-linux-musl-g++
|
|
|
|
else
|
|
|
|
FULLY_STATIC="OFF"
|
|
|
|
fi
|
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
cmake \
|
|
|
|
-DCMAKE_BUILD_TYPE="${{ matrix.build_type }}" \
|
|
|
|
-DBUILD_SHARED_LIBS="$BUILD_SHARED_LIBS" \
|
feat: Portable, fully-static release executables on Linux (#1351)
This adds the option FULLY_STATIC to create fully-static executables.
To create portable, fully-static release executables on Linux, we need
to use musl instead of glibc. Static executables from glibc are not
portable.
The popular musl-gcc wrapper does not support C++, so instead we use a
full musl cross-compiler toolchain in the build workflow.
To build FULLY_STATIC, the user must point to the appropriate
cross-compiler, as we do in the workflow. On systems where musl is the
native libc (such as Alpine Linux), this is not necessary.
I have also read that musl's allocator is not very fast in
multi-threaded applications. So when FULLY_STATIC is enabled, we will
also enable mimalloc, a replacement allocator that is very fast.
I tested a very basic packaging command to compare speeds of dynamic
glibc, static musl, and static musl+mimalloc:
dynamic glibc:
runs: 2.527, 2.798, 2.703, 2.756, 2.959
avg = 2.749, std dev = 0.156s
static musl:
runs: 2.813, 2.920, 3.129, 3.003, 2.738
avg = 2.921s, std dev = 0.154s
static musl+mimalloc:
runs: 2.291, 2.034, 2.415, 2.303, 2.265
avg = 2.262s, std dev = 0.140s
The mimalloc build is 82% faster than musl default allocator, 77% faster
than glibc, and has more consistent runtime characteristics (lower
standard deviation).
2024-02-27 18:47:04 +00:00
|
|
|
-DFULLY_STATIC="$FULLY_STATIC" \
|
2023-12-01 17:32:19 +00:00
|
|
|
-S . \
|
|
|
|
-B build/
|
|
|
|
|
|
|
|
- name: Build
|
|
|
|
# This is a universal build command, which will call make on Linux and
|
|
|
|
# Visual Studio on Windows. Note that the VS generator is what cmake
|
|
|
|
# calls a "multi-configuration" generator, and so the desired build
|
|
|
|
# type must be specified for Windows.
|
|
|
|
run: cmake --build build/ --config "${{ matrix.build_type }}" --parallel
|
|
|
|
|
|
|
|
- name: Test
|
|
|
|
run: ctest -C "${{ matrix.build_type }}" -V --test-dir build/
|
|
|
|
|
|
|
|
- name: Publish Test Report
|
2024-03-05 17:28:51 +00:00
|
|
|
uses: mikepenz/action-junit-report@v4
|
2023-12-01 17:32:19 +00:00
|
|
|
if: ${{ always() }}
|
|
|
|
with:
|
|
|
|
report_paths: 'junit-reports/TEST-*.xml'
|
|
|
|
|
|
|
|
- name: Prepare artifacts (static release only)
|
|
|
|
run: |
|
|
|
|
BUILD_CONFIG="${{ matrix.build_type }}-${{ matrix.lib_type }}"
|
|
|
|
if [[ "$BUILD_CONFIG" != "Release-static" ]]; then
|
|
|
|
echo "Skipping artifacts for $BUILD_CONFIG."
|
|
|
|
exit 0
|
|
|
|
fi
|
|
|
|
|
feat: Portable, fully-static release executables on Linux (#1351)
This adds the option FULLY_STATIC to create fully-static executables.
To create portable, fully-static release executables on Linux, we need
to use musl instead of glibc. Static executables from glibc are not
portable.
The popular musl-gcc wrapper does not support C++, so instead we use a
full musl cross-compiler toolchain in the build workflow.
To build FULLY_STATIC, the user must point to the appropriate
cross-compiler, as we do in the workflow. On systems where musl is the
native libc (such as Alpine Linux), this is not necessary.
I have also read that musl's allocator is not very fast in
multi-threaded applications. So when FULLY_STATIC is enabled, we will
also enable mimalloc, a replacement allocator that is very fast.
I tested a very basic packaging command to compare speeds of dynamic
glibc, static musl, and static musl+mimalloc:
dynamic glibc:
runs: 2.527, 2.798, 2.703, 2.756, 2.959
avg = 2.749, std dev = 0.156s
static musl:
runs: 2.813, 2.920, 3.129, 3.003, 2.738
avg = 2.921s, std dev = 0.154s
static musl+mimalloc:
runs: 2.291, 2.034, 2.415, 2.303, 2.265
avg = 2.262s, std dev = 0.140s
The mimalloc build is 82% faster than musl default allocator, 77% faster
than glibc, and has more consistent runtime characteristics (lower
standard deviation).
2024-02-27 18:47:04 +00:00
|
|
|
# Check static executables
|
|
|
|
if [[ "${{ runner.os }}" == "Linux" ]]; then
|
|
|
|
echo "::group::Check static executables"
|
|
|
|
for exe in build/packager/{packager,mpd_generator}; do
|
|
|
|
# Capture information about the executables, but also let it be
|
|
|
|
# logged to stdout.
|
|
|
|
ldd "$exe" | tee static.log
|
|
|
|
# The phrase "statically linked" means we got it right. Fail if
|
|
|
|
# we don't find it.
|
|
|
|
if ! cat static.log | grep -q statically; then
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
echo "::endgroup::"
|
|
|
|
fi
|
2023-12-01 17:32:19 +00:00
|
|
|
|
|
|
|
echo "::group::Prepare artifacts folder"
|
|
|
|
mkdir artifacts
|
|
|
|
ARTIFACTS="$GITHUB_WORKSPACE/artifacts"
|
|
|
|
if [[ "${{ runner.os }}" == "Windows" ]]; then
|
|
|
|
cd build/packager/Release
|
|
|
|
else
|
|
|
|
cd build/packager
|
|
|
|
fi
|
|
|
|
echo "::endgroup::"
|
|
|
|
|
|
|
|
echo "::group::Strip executables"
|
|
|
|
strip packager${{ matrix.exe_ext }}
|
|
|
|
strip mpd_generator${{ matrix.exe_ext }}
|
|
|
|
echo "::endgroup::"
|
|
|
|
|
|
|
|
SUFFIX="-${{ matrix.os_name }}-${{ matrix.target_arch }}"
|
|
|
|
EXE_SUFFIX="$SUFFIX${{ matrix.exe_ext}}"
|
|
|
|
|
|
|
|
echo "::group::Copy packager"
|
|
|
|
cp packager${{ matrix.exe_ext }} $ARTIFACTS/packager$EXE_SUFFIX
|
|
|
|
echo "::endgroup::"
|
|
|
|
|
|
|
|
echo "::group::Copy mpd_generator"
|
|
|
|
cp mpd_generator${{ matrix.exe_ext }} $ARTIFACTS/mpd_generator$EXE_SUFFIX
|
|
|
|
echo "::endgroup::"
|
|
|
|
|
|
|
|
# The pssh-box bundle is OS and architecture independent. So only do
|
|
|
|
# it on this one OS and architecture, and give it a more generic
|
|
|
|
# filename.
|
|
|
|
if [[ '${{ matrix.os_name }}' == 'linux' && '${{ matrix.target_arch }}' == 'x64' ]]; then
|
|
|
|
echo "::group::Tar pssh-box"
|
|
|
|
tar -czf $ARTIFACTS/pssh-box.py.tar.gz pssh-box.py pssh-box-protos
|
|
|
|
echo "::endgroup::"
|
|
|
|
fi
|
|
|
|
|
|
|
|
- name: Upload static release build artifacts
|
2024-03-05 17:28:51 +00:00
|
|
|
uses: actions/upload-artifact@v4
|
2023-12-01 17:32:19 +00:00
|
|
|
if: matrix.build_type == 'Release' && matrix.lib_type == 'static'
|
|
|
|
with:
|
|
|
|
name: artifacts-${{ matrix.os_name }}-${{ matrix.target_arch }}
|
|
|
|
path: artifacts/*
|
|
|
|
if-no-files-found: error
|
|
|
|
retention-days: 5
|
|
|
|
|
|
|
|
- name: Debug
|
2024-03-05 17:28:51 +00:00
|
|
|
uses: mxschmitt/action-tmate@v3.17
|
2023-12-01 17:32:19 +00:00
|
|
|
with:
|
|
|
|
limit-access-to-actor: true
|
|
|
|
if: failure() && inputs.debug
|