Skip to content

Commit d8ec154

Browse files
committed
workflows: Build Alpine musl cross compiler images
1 parent 2e36912 commit d8ec154

File tree

11 files changed

+425
-0
lines changed

11 files changed

+425
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: Build cross Docker containers
2+
3+
on:
4+
push:
5+
paths:
6+
- alpine-docker/config-aarch64.mak
7+
- alpine-docker/config-arm.mak
8+
- alpine-docker/config-armhf.mak
9+
- alpine-docker/config-base.mak
10+
- alpine-docker/config-powerpc64le.mak
11+
- alpine-docker/config-riscv64.mak
12+
- alpine-docker/docker-bake.hcl
13+
- alpine-docker/save-versions.py
14+
- alpine-docker/universal.Dockerfile
15+
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.ref }}
18+
cancel-in-progress: true
19+
20+
jobs:
21+
build:
22+
runs-on: ubuntu-24.04
23+
name: Build container
24+
25+
permissions:
26+
contents: read
27+
packages: write
28+
attestations: write
29+
id-token: write
30+
31+
strategy:
32+
matrix:
33+
arch: [aarch64, arm, armhf, powerpc64le, riscv64]
34+
35+
env:
36+
IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/musl-cross-make-alpine-${{ matrix.arch }}
37+
38+
steps:
39+
- name: Set up Docker Buildx
40+
# v3.11.1
41+
# The hash below **must** be kept up-to-date with the 'Build and push' action
42+
# below.
43+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
44+
45+
- name: Log in to the Container registry
46+
# v3.4.0
47+
# The hash below **must** be kept up-to-date with the 'Build and push' action
48+
# below.
49+
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
50+
with:
51+
registry: ghcr.io
52+
username: ${{ github.actor }}
53+
password: ${{ secrets.GITHUB_TOKEN }}
54+
55+
- name: Extract metadata (tags, labels) for Docker
56+
id: meta
57+
# v5.7.0
58+
# The hash below **must** be kept up-to-date with the 'Build and push' action
59+
# below.
60+
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804
61+
with:
62+
images: ${{ env.IMAGE_NAME }}
63+
tags: |
64+
type=raw,value=latest,enable={{is_default_branch}}
65+
type=raw,value={{date 'YYYY-MM-DD'}},enable={{is_default_branch}},priority=1000
66+
67+
- uses: actions/checkout@v4
68+
69+
- name: Build and push
70+
# v6.8.0
71+
# The hash below **must** be kept up-to-date with the 'Build and push' action
72+
# below.
73+
uses: docker/bake-action@37816e747588cb137173af99ab33873600c46ea8
74+
with:
75+
# The default git source pulls all submodules too, so use v6.8.0 instead.
76+
source: .
77+
workdir: alpine-docker
78+
files: |
79+
./docker-bake.hcl
80+
cwd://${{ steps.meta.outputs.bake-file }}
81+
targets: ${{ matrix.arch }}
82+
# The hashes below **must** be kept up-to-date with the hashes above.
83+
set: |
84+
*.args.DOCKER_SETUP_BUILDX_ACTION_VERSION=e468171a9de216ec08956ac3ada2f0791b6bd435
85+
*.args.DOCKER_LOGIN_ACTION_VERSION=74a5d142397b4f367a81961eba4e8cd7edddf772
86+
*.args.DOCKER_METADATA_ACTION_VERSION=902fa8ec7d6ecbf8d84d538b9b233a880e428804
87+
*.args.DOCKER_BAKE_ACTION_VERSION=37816e747588cb137173af99ab33873600c46ea8
88+
push: true
89+
90+
# - name: Generate artifact attestation
91+
# uses: actions/attest-build-provenance@v2
92+
# with:
93+
# subject-name: ${{ env.IMAGE_NAME }}
94+
# # I don't know how to get the subject digest. See
95+
# # https://github.com/docker/bake-action/issues/99
96+
# subject-digest: 'sha256:fedcba0...'
97+
# push-to-registry: true

alpine-docker/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
This directory includes Dockerfiles and auxiliary helper files used to build
2+
Alpine Linux Docker containers which contain Linux cross-compilers used to build
3+
release artifacts.
4+
5+
See `.github/workflows/` which includes workflows for building the containers
6+
(which are hosted on ghcr.io) and building the release artifacts themselves.

alpine-docker/config-aarch64.mak

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TARGET = aarch64-linux-musl

alpine-docker/config-arm.mak

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TARGET = arm-linux-musleabi

alpine-docker/config-armhf.mak

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TARGET = arm-linux-musleabihf

alpine-docker/config-base.mak

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#
2+
# config.mak.dist - sample musl-cross-make configuration
3+
#
4+
# Copy to config.mak and edit as desired.
5+
#
6+
7+
# There is no default TARGET; you must select one here or on the make
8+
# command line. Some examples:
9+
10+
# TARGET = i486-linux-musl
11+
# TARGET = x86_64-linux-musl
12+
# TARGET = arm-linux-musleabi
13+
# TARGET = arm-linux-musleabihf
14+
# TARGET = sh2eb-linux-muslfdpic
15+
# ...
16+
17+
# By default, cross compilers are installed to ./output under the top-level
18+
# musl-cross-make directory and can later be moved wherever you want them.
19+
# To install directly to a specific location, set it here. Multiple targets
20+
# can safely be installed in the same location. Some examples:
21+
22+
# OUTPUT = /opt/cross
23+
OUTPUT = /usr/local
24+
25+
# By default, latest supported release versions of musl and the toolchain
26+
# components are used. You can override those here, but the version selected
27+
# must be supported (under hashes/ and patches/) to work. For musl, you
28+
# can use "git-refname" (e.g. git-master) instead of a release. Setting a
29+
# blank version for gmp, mpc, mpfr and isl will suppress download and
30+
# in-tree build of these libraries and instead depend on pre-installed
31+
# libraries when available (isl is optional and not set by default).
32+
# Setting a blank version for linux will suppress installation of kernel
33+
# headers, which are not needed unless compiling programs that use them.
34+
35+
# BINUTILS_VER = 2.25.1
36+
# GCC_VER = 5.2.0
37+
# MUSL_VER = git-master
38+
# GMP_VER =
39+
# MPC_VER =
40+
# MPFR_VER =
41+
# ISL_VER =
42+
# LINUX_VER =
43+
44+
# By default source archives are downloaded with wget. curl is also an option.
45+
46+
# DL_CMD = wget -c -O
47+
# DL_CMD = curl -C - -L -o
48+
49+
# Check sha-1 hashes of downloaded source archives. On gnu systems this is
50+
# usually done with sha1sum.
51+
52+
# SHA1_CMD = sha1sum -c
53+
# SHA1_CMD = sha1 -c
54+
# SHA1_CMD = shasum -a 1 -c
55+
56+
# Something like the following can be used to produce a static-linked
57+
# toolchain that's deployable to any system with matching arch, using
58+
# an existing musl-targeted cross compiler. This only works if the
59+
# system you build on can natively (or via binfmt_misc and qemu) run
60+
# binaries produced by the existing toolchain (in this example, i486).
61+
62+
# COMMON_CONFIG += CC="i486-linux-musl-gcc -static --static" CXX="i486-linux-musl-g++ -static --static"
63+
64+
# Recommended options for smaller build for deploying binaries:
65+
66+
# COMMON_CONFIG += CFLAGS="-g0 -Os" CXXFLAGS="-g0 -Os" LDFLAGS="-s"
67+
68+
# Options you can add for faster/simpler build at the expense of features:
69+
70+
COMMON_CONFIG += --disable-nls
71+
# GCC_CONFIG += --disable-libquadmath --disable-decimal-float
72+
# GCC_CONFIG += --disable-libitm
73+
# GCC_CONFIG += --disable-fixed-point
74+
# GCC_CONFIG += --disable-lto
75+
76+
# By default C and C++ are the only languages enabled, and these are
77+
# the only ones tested and known to be supported. You can uncomment the
78+
# following and add other languages if you want to try getting them to
79+
# work too.
80+
81+
# GCC_CONFIG += --enable-languages=c,c++
82+
83+
# You can keep the local build path out of your toolchain binaries and
84+
# target libraries with the following, but then gdb needs to be told
85+
# where to look for source files.
86+
87+
# COMMON_CONFIG += --with-debug-prefix-map=$(CURDIR)=
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TARGET = powerpc64le-linux-musl

alpine-docker/config-riscv64.mak

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TARGET = riscv64-linux-musl

alpine-docker/docker-bake.hcl

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# https://github.com/docker/metadata-action?tab=readme-ov-file#bake-definition
2+
target "docker-metadata-action" {}
3+
4+
target "_common" {
5+
args = {
6+
ALPINE_VERSION = "3.22"
7+
# A fairly recent version of musl-cross-make is needed. There are multiple
8+
# features added in newer commits, for example
9+
# 5b3b4ea504c8b71764d815de76e35c8bc2aaa507, which adds support for Linux
10+
# kernel 6.15.7. Linux v6 added support for powerpc64 kernel headers.
11+
# android-tools need kernel headers, so this commit adds support for
12+
# powerpc64 android-tools.
13+
MUSL_CROSS_MAKE_VERSION = "3635262e4524c991552789af6f36211a335a77b3"
14+
BINUTILS_VERSION = "2.44"
15+
GCC_VERSION = "14.2.0"
16+
MUSL_VERSION = "1.2.5"
17+
GMP_VERSION = "6.3.0"
18+
MPC_VERSION = "1.3.1"
19+
MPFR_VERSION = "4.2.2"
20+
LINUX_VERSION = "6.15.7"
21+
ISL_VERSION = "0.27"
22+
}
23+
dockerfile = "universal.Dockerfile"
24+
}
25+
26+
target "aarch64" {
27+
inherits = ["docker-metadata-action", "_common"]
28+
args = {
29+
TARGET_MAK_FILE = "config-aarch64.mak"
30+
}
31+
# tags = ["alpine-cross-aarch64"]
32+
}
33+
34+
target "armhf" {
35+
inherits = ["docker-metadata-action", "_common"]
36+
args = {
37+
TARGET_MAK_FILE = "config-armhf.mak"
38+
}
39+
# tags = ["alpine-cross-armhf"]
40+
}
41+
42+
target "arm" {
43+
inherits = ["docker-metadata-action", "_common"]
44+
args = {
45+
TARGET_MAK_FILE = "config-arm.mak"
46+
}
47+
# tags = ["alpine-cross-arm"]
48+
}
49+
50+
target "powerpc64le" {
51+
inherits = ["docker-metadata-action", "_common"]
52+
args = {
53+
TARGET_MAK_FILE = "config-powerpc64le.mak"
54+
}
55+
# tags = ["alpine-cross-powerpc64le"]
56+
}
57+
58+
target "riscv64" {
59+
inherits = ["docker-metadata-action", "_common"]
60+
args = {
61+
TARGET_MAK_FILE = "config-riscv64.mak"
62+
}
63+
# tags = ["alpine-cross-riscv64"]
64+
}

alpine-docker/save-versions.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2025 meator
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
"""Save the versions of components used into a machine-readable file.
18+
19+
This script is run from each Alpine musl cross-compiler Dockerfile to store info about
20+
the cross-compiler into the image itself. This info is also stored in the resulting
21+
container's labels, but Docker labels can be harder to work with from inside the
22+
container.
23+
"""
24+
25+
import argparse
26+
import json
27+
import sys
28+
import typing
29+
30+
31+
class _VersionInfo(typing.NamedTuple):
32+
version_flag_base: str
33+
34+
35+
if __name__ == "__main__":
36+
_VI = _VersionInfo
37+
result_mapping = {
38+
"alpine": _VI("alpine"),
39+
"musl-cross-make": _VI("musl-cross-make"),
40+
"binutils": _VI("binutils"),
41+
"gcc": _VI("gcc"),
42+
"musl": _VI("musl"),
43+
"gmp": _VI("gmp"),
44+
"mpc": _VI("mpc"),
45+
"mpfr": _VI("mpfr"),
46+
"linux": _VI("linux"),
47+
"isl": _VI("isl"),
48+
"docker/setup-buildx-action": _VI("setup-buildx-action"),
49+
"docker/login-action": _VI("login-action"),
50+
"docker/metadata-action": _VI("metadata-action"),
51+
"docker/bake-action": _VI("bake-action"),
52+
}
53+
54+
parser = argparse.ArgumentParser()
55+
56+
for key_name, flag_base in result_mapping.items():
57+
parser.add_argument(
58+
f"--{flag_base.version_flag_base}-version", required=True, dest=key_name
59+
)
60+
61+
args = parser.parse_args()
62+
63+
result = {}
64+
65+
for key_name, flag_base in result_mapping.items():
66+
version = getattr(args, key_name)
67+
if not version:
68+
sys.exit(
69+
f"Flag --{flag_base.version_flag_base}-version must not have empty "
70+
"version!"
71+
)
72+
result[key_name] = version
73+
74+
json.dump(result, sys.stdout)

0 commit comments

Comments
 (0)