Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Build with Alpine for static Linux binaries #42

Merged
merged 1 commit into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,14 @@ jobs:

name: Build ${{ matrix.os_name }} ${{ matrix.target_arch }}
runs-on: ${{ matrix.os }}
container:
image: ${{ matrix.container }}
# Access to the host filesystem is required to patch the environment for
# Alpine Linux support. See the first Alpine step below for details.
Comment on lines +103 to +106
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how things go when the matrix entry doesn't define a container? couldn't find it in github CI docs, but it seems to play nicely as we have green check marks on other platforms and the binaries are uploaded.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that it just doesn't run in a container when image is blank. So this works nicely with the build matrix, and allows us to put some builds in containers and others not.

volumes:
- /:/host

steps:
- uses: actions/checkout@v4
with:
path: repo-src
ref: ${{ github.event.pull_request.merge_commit_sha || github.event.push.head }}

- name: Add msys2 to the Windows path
if: runner.os == 'Windows'
run: |
Expand All @@ -116,6 +117,38 @@ jobs:
echo "C:\\msys64\\usr\\bin" >> "$GITHUB_PATH"
echo "C:\\msys64\\mingw64\\bin" >> "$GITHUB_PATH"

# This is how we convince GitHub Actions Runner to run an Alpine Linux
# container. We have to mask the fact that it's Alpine, install NodeJS,
# then patch the Alpine version of NodeJS in over the one that ships with
# GitHub Actions. This is because GitHub doesn't officially support
# Alpine and because they hard-code the path to NodeJS in Node-based
# actions.
# See https://github.com/actions/runner/issues/801#issuecomment-2394425757
- name: Patch native Alpine NodeJS into Runner environment
if: runner.os == 'Linux'
run: |
apk add nodejs
sed -i "s:^ID=alpine:ID=NotpineForGHA:" /etc/os-release
# The first path here is for GitHub-hosted workflows, while the
# second path is correct for our self-hosted workflows using the
# myoung34/github-runner container. The commands that follow this
# are correct so long as one of these paths exists.
cd /host/home/runner/runners/*/externals/ || cd /host/actions-runner/externals
rm -rf node20/*
mkdir node20/bin
ln -s /usr/bin/node node20/bin/node
shell: sh # No bash in Alpine by default

- name: Install Alpine Linux deps
if: runner.os == 'Linux'
run: apk add bash npm sudo
shell: sh # No bash in Alpine until after this command

- uses: actions/checkout@v4
with:
path: repo-src
ref: ${{ github.event.pull_request.merge_commit_sha || github.event.push.head }}

- name: Install OS packages
run: ./repo-src/build-scripts/00-packages.sh

Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ and you can verify that they haven't been tampered with. The sums in the
workflow logs, release notes, and the binaries should all match.
You can read the details in the [workflow source][workflow].

No third-party GitHub Actions have been used in this workflow, to protect
against supply-chain attacks.
Minimal third-party GitHub Actions have been used in this workflow, to protect
against supply-chain attacks. The following actions are used:

- mxschmitt/action-tmate: Used only on failure to debug failed builds, and
only if debug is configured at the repo level.


# Triggering a build
Expand Down
2 changes: 2 additions & 0 deletions build-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"hosted": [
{
"os": "ubuntu-latest",
"container": "alpine:3.20",
"os_name": "linux",
"target_arch": "x64",
"exe_ext": ""
Expand Down Expand Up @@ -33,6 +34,7 @@
"selfHosted": [
{
"os": "self-hosted-linux-arm64",
"container": "arm64v8/alpine:3.20",
"os_name": "linux",
"target_arch": "arm64",
"exe_ext": ""
Expand Down
46 changes: 33 additions & 13 deletions build-scripts/00-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,39 @@ set -x
if [[ "$RUNNER_OS" == "Linux" ]]; then
# Install missing packages on Linux.
#
# NOTE: Some of these are already on GitHub's VMs, but not our self-hosted
# runners.
sudo apt -y update
sudo apt -y upgrade
sudo apt -y install \
cmake \
curl \
nasm \
npm \
pkg-config \
yasm \
libffmpeg-nvenc-dev \
libvdpau-dev
# NOTE: In order to get a musl-based static build, we run our automated
# builds inside an Alpine Linux container, not directly on GitHub's Ubuntu
# VMs.
if repo-src/is-alpine.sh; then
sudo apk update
sudo apk upgrade
sudo apk add \
cmake \
curl \
diffutils \
g++ \
git \
libvdpau-dev \
linux-headers \
make \
nasm \
patch \
perl \
pkgconfig \
yasm
else
# This can be used by the developer on Ubuntu. The builds may or may not
# work portably on other platforms.
sudo apt -y update
sudo apt -y upgrade
sudo apt -y install \
cmake \
curl \
libvdpau-dev \
nasm \
pkg-config \
yasm
fi

# Use sudo in install commands on Linux.
echo "SUDO=sudo" >> "$GITHUB_ENV"
Expand Down
3 changes: 3 additions & 0 deletions build-scripts/03-x264.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ git clone https://code.videolan.org/videolan/x264.git
cd x264
git checkout "$tag"

# NOTE: disable OpenCL-based features because it uses dlopen and can interfere
# with static builds.
./configure \
--disable-opencl \
Comment on lines +25 to +28
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q, so builds with these configurations aren't static anymore or the does building fail all together?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They aren't really static, since it uses dlopen to find OpenCL at runtime. Also, OpenCL isn't necessary for the H264 software codec.

--enable-static

# Only build and install the static library.
Expand Down
26 changes: 26 additions & 0 deletions is-alpine.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/sh

# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Returns 0 if this is Alpine Linux.

OS_ID=$(cat /etc/os-release | grep ^ID= | cut -f 2 -d =)
if [ "$OS_ID" = "alpine" -o "$OS_ID" = "NotpineForGHA" ]; then
# It is Alpine or the modified version we have to trick GitHub.
exit 0
fi

# It is not Alpine.
exit 1
Loading