Skip to content

Commit

Permalink
make release: add cross-build
Browse files Browse the repository at this point in the history
This implements cross-build for "make release", moving the build into a
container. This way we can support arm, arm64, ppc, and whatnot.

* script/seccomp.sh: separate out of script/release.sh, amend to support
  cross-compile and save needed environment variables to a file.

* Dockerfile: add installing libseccomp from source, as this is needed
  for release builds.

* script/release.sh: amend to support more architectures in addition to
  the native build. Additional arches can be added by specifying
  "-a <arch>" argument (can be specified multiple times), or
  "make RELEASE_ARGS="-a arm64" release" if called via make.
  All supported architectures can be enabled via "make releaseall".

* Makefile: move "release" target to "localrelease", add "release" and
  "releaseall" targets to build via the Dockerfile. This is done because
  most distros (including Fedora and openSUSE) lack cross-glibc, which is
  needed to cross-compile libseccomp.

* Makefile: remove 'cross' and 'localcross' targets, as this is now done
  by the release script.

* .github/workflows/validate.yum: amend the release CI job to cross-build
  for supported architectures, remove cross job.

Signed-off-by: Kir Kolyshkin <[email protected]>
  • Loading branch information
kolyshkin committed Sep 20, 2021
1 parent 23d79aa commit f30244e
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 78 deletions.
42 changes: 15 additions & 27 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,27 +124,6 @@ jobs:
error: 'Subject too long (max 72)'


cross:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
# We have to run this under Docker as Ubuntu (host) does not support all
# the architectures we want to compile test against, and Dockerfile uses
# Debian (which does).
#
# XXX: as currently this is the only job that is using Docker, we are
# building and using the runcimage locally. In case more jobs running
# under Docker will emerge, it will be good to have a separate make
# runcimage job and share its result (the docker image) with whoever
# needs it.
- uses: satackey/[email protected]
continue-on-error: true
- name: build docker image
run: make runcimage
- name: cross
run: make cross


cfmt:
runs-on: ubuntu-20.04
steps:
Expand All @@ -169,12 +148,21 @@ jobs:
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: install deps
run: |
sudo apt -qq update
sudo apt -qq install gperf
- name: make release
run: make release
# We have to run this under Docker as Ubuntu (host) does not support all
# the architectures we want to compile test against, and Dockerfile uses
# Debian (which does).
#
# XXX: as currently this is the only job that is using Docker, we are
# building and using the runcimage locally. In case more jobs running
# under Docker will emerge, it will be good to have a separate make
# runcimage job and share its result (the docker image) with whoever
# needs it.
- uses: satackey/[email protected]
continue-on-error: true
- name: build docker image
run: make runcimage
- name: make releaseall
run: make releaseall
- name: upload artifacts
uses: actions/upload-artifact@v2
with:
Expand Down
14 changes: 8 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
ARG GO_VERSION=1.17
ARG BATS_VERSION=v1.3.0
ARG LIBSECCOMP_VERSION=2.5.1

FROM golang:${GO_VERSION}-bullseye
ARG DEBIAN_FRONTEND=noninteractive
Expand All @@ -21,15 +22,10 @@ RUN echo 'deb https://download.opensuse.org/repositories/devel:/tools:/criu/Debi
curl \
gawk \
gcc \
gperf \
iptables \
jq \
kmod \
libseccomp-dev \
libseccomp-dev:arm64 \
libseccomp-dev:armel \
libseccomp-dev:armhf \
libseccomp-dev:ppc64el \
libseccomp2 \
pkg-config \
python3-minimal \
sudo \
Expand All @@ -52,4 +48,10 @@ RUN cd /tmp \
&& ./install.sh /usr/local \
&& rm -rf /tmp/bats-core

# install libseccomp
ARG LIBSECCOMP_VERSION
COPY script/* /tmp/script/
RUN mkdir -p /usr/local/src/libseccomp \
&& /tmp/script/seccomp.sh "$LIBSECCOMP_VERSION" /usr/local/src/libseccomp /usr/local/src/libseccomp/.env-file arm64 armel armhf ppc64le

WORKDIR /go/src/github.com/opencontainers/runc
34 changes: 17 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,17 @@ recvtty sd-helper seccompagent:
static:
$(GO_BUILD_STATIC) -o runc .

release:
script/release.sh -r release/$(VERSION) -v $(VERSION)
releaseall: RELEASE_ARGS := "-a arm64 -a armel -a armhf -a ppc64le"
releaseall: release

release: runcimage
$(CONTAINER_ENGINE) run $(CONTAINER_ENGINE_RUN_FLAGS) \
--rm -v $(CURDIR):/go/src/$(PROJECT) \
-e RELEASE_ARGS=$(RELEASE_ARGS) \
$(RUNC_IMAGE) make localrelease

localrelease:
script/release.sh -r release/$(VERSION) -v $(VERSION) $(RELEASE_ARGS)

dbuild: runcimage
$(CONTAINER_ENGINE) run $(CONTAINER_ENGINE_RUN_FLAGS) \
Expand Down Expand Up @@ -119,7 +128,9 @@ cfmt:
indent -linux -l120 -il0 -ppi2 -cp1 -T size_t -T jmp_buf $(C_SRC)

shellcheck:
shellcheck tests/integration/*.bats tests/integration/*.sh tests/integration/*.bash tests/*.sh script/release.sh
shellcheck tests/integration/*.bats tests/integration/*.sh \
tests/integration/*.bash tests/*.sh \
script/release.sh script/seccomp.sh script/lib.sh
# TODO: add shellcheck for more sh files

shfmt:
Expand All @@ -136,20 +147,9 @@ verify-dependencies: vendor
|| (echo -e "git status:\n $$(git status -- go.mod go.sum vendor/)\nerror: vendor/, go.mod and/or go.sum not up to date. Run \"make vendor\" to update"; exit 1) \
&& echo "all vendor files are up to date."

cross: runcimage
$(CONTAINER_ENGINE) run $(CONTAINER_ENGINE_RUN_FLAGS) \
-e BUILDTAGS="$(BUILDTAGS)" --rm \
-v $(CURDIR):/go/src/$(PROJECT) \
$(RUNC_IMAGE) make localcross

localcross:
CGO_ENABLED=1 GOARCH=arm GOARM=6 CC=arm-linux-gnueabi-gcc $(GO_BUILD) -o runc-armel .
CGO_ENABLED=1 GOARCH=arm GOARM=7 CC=arm-linux-gnueabihf-gcc $(GO_BUILD) -o runc-armhf .
CGO_ENABLED=1 GOARCH=arm64 CC=aarch64-linux-gnu-gcc $(GO_BUILD) -o runc-arm64 .
CGO_ENABLED=1 GOARCH=ppc64le CC=powerpc64le-linux-gnu-gcc $(GO_BUILD) -o runc-ppc64le .

.PHONY: runc all recvtty sd-helper seccompagent static release dbuild lint man runcimage \
.PHONY: runc all recvtty sd-helper seccompagent static releaseall release \
localrelease dbuild lint man runcimage \
test localtest unittest localunittest integration localintegration \
rootlessintegration localrootlessintegration shell install install-bash \
install-man clean cfmt shfmt shellcheck \
vendor verify-dependencies cross localcross
vendor verify-dependencies
36 changes: 36 additions & 0 deletions script/lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash

# set_cross_vars sets a few environment variables used for cross-compiling,
# based on the architecture specified in $1.
function set_cross_vars() {
GOARCH="$1" # default, may be overridden below
unset GOARM

case $1 in
arm64)
HOST=aarch64-linux-gnu
;;
armel)
HOST=arm-linux-gnueabi
GOARCH=arm
GOARM=6
;;
armhf)
HOST=arm-linux-gnueabihf
GOARCH=arm
GOARM=7
;;
ppc64le)
HOST=powerpc64le-linux-gnu
;;
*)
echo "set_cross_vars: unsupported architecture: $1" >&2
exit 1
;;
esac

CC=$HOST-gcc
STRIP=$HOST-strip

export HOST GOARM GOARCH CC STRIP
}
95 changes: 67 additions & 28 deletions script/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,36 @@ set -e
project="runc"
root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")"

# shellcheck source=./script/lib.sh
source "$root/script/lib.sh"

# This function takes an output path as an argument, where the built
# (preferably static) binary should be placed.
# Parameters:
# $1 -- destination directory to place build artefacts to.
# $2 -- native architecture (a .suffix for a native binary file name).
# $@ -- additional architectures to cross-build for.
function build_project() {
local libseccomp_version=2.5.1
local builddir
builddir="$(dirname "$1")"

# Due to libseccomp being LGPL we must include its sources,
# so download, install and build against it.

local libseccomp_ver='2.5.1'
local tarball="libseccomp-${libseccomp_ver}.tar.gz"
local prefix
prefix="$(mktemp -d)"
wget "https://github.com/seccomp/libseccomp/releases/download/v${libseccomp_ver}/${tarball}"{,.asc}
tar xf "$tarball"
(
cd "libseccomp-${libseccomp_ver}"
./configure --prefix="$prefix" --libdir="$prefix/lib" \
--enable-static --disable-shared
make install
)
mv "$tarball"{,.asc} "$builddir"
shift
local native_arch="$1"
shift
local arches=("$@")

# Assume that if /usr/local/src/libseccomp/.env-file exists, then
# we are run via Dockerfile, and seccomp is already built.
if [ -r /usr/local/src/libseccomp/.env-file ]; then
# shellcheck disable=SC1091
source /usr/local/src/libseccomp/.env-file
# Copy the source tarball.
cp /usr/local/src/libseccomp/* "$builddir"
else
"$root/script/seccomp.sh" "$libseccomp_version" "$builddir" "./env-file" "${arches[@]}"
# shellcheck disable=SC1091
source ./env-file
fi

# For reproducible builds, add these to EXTRA_LDFLAGS:
# -w to disable DWARF generation;
Expand All @@ -52,18 +60,40 @@ function build_project() {
# Add -a to go build flags to make sure it links against
# the provided libseccomp, not the system one (otherwise
# it can reuse cached pkg-config results).
make -C "$root" PKG_CONFIG_PATH="${prefix}/lib/pkgconfig" COMMIT_NO= EXTRA_FLAGS="-a" EXTRA_LDFLAGS="${ldflags}" static
rm -rf "$prefix"
local make_args=(COMMIT_NO= EXTRA_FLAGS="-a" EXTRA_LDFLAGS="${ldflags}" static)

# Build natively.
make -C "$root" \
PKG_CONFIG_PATH="${LIBSECCOMP_PREFIX}/lib/pkgconfig" \
LD_LIBRARY_PATH="${LIBSECCOMP_PREFIX}/lib" \
"${make_args[@]}"
strip "$root/$project"
mv "$root/$project" "$1"
mv "$root/$project" "$builddir/$project.$native_arch"
rm -rf "${LIBSECCOMP_PREFIX}"

# Cross-build for for other architectures.
local prefix arch
for arch in "${arches[@]}"; do
eval prefix=\$"LIBSECCOMP_PREFIX_$arch"
if [ -z "$prefix" ]; then
echo "LIBSECCOMP_PREFIX_$arch is empty (unsupported arch?)" >&2
exit 1
fi
set_cross_vars "$arch"
make -C "$root" \
PKG_CONFIG_PATH="${prefix}/lib/pkgconfig" "${make_args[@]}"
"$STRIP" "$root/$project"
mv "$root/$project" "$builddir/$project.$arch"
rm -rf "$prefix"
done
}

# End of the easy-to-configure portion.
## <---

# Print usage information.
function usage() {
echo "usage: release.sh [-S <gpg-key-id>] [-c <commit-ish>] [-r <release-dir>] [-v <version>]" >&2
echo "usage: release.sh [-S <gpg-key-id>] [-c <commit-ish>] [-r <release-dir>] [-v <version>] [-a <cross-arch>]" >&2
exit 1
}

Expand Down Expand Up @@ -91,7 +121,9 @@ commit="HEAD"
version=""
releasedir=""
hashcmd=""
while getopts "S:c:r:v:h:" opt; do
declare -a add_arches

while getopts "S:c:r:v:h:a:" opt; do
case "$opt" in
S)
keyid="$OPTARG"
Expand All @@ -108,6 +140,9 @@ while getopts "S:c:r:v:h:" opt; do
h)
hashcmd="$OPTARG"
;;
a)
add_arches+=("$OPTARG")
;;
:)
echo "Missing argument: -$OPTARG" >&2
usage
Expand All @@ -122,7 +157,9 @@ done
version="${version:-$(<"$root/VERSION")}"
releasedir="${releasedir:-release/$version}"
hashcmd="${hashcmd:-sha256sum}"
goarch="$(go env GOARCH || echo "amd64")"
native_arch="$(go env GOARCH || echo "amd64")"
# Suffixes of files to checksum/sign.
suffixes=("$native_arch" "${add_arches[@]}" tar.xz)

log "creating $project release in '$releasedir'"
log " version: $version"
Expand All @@ -137,15 +174,16 @@ set -x
rm -rf "$releasedir" && mkdir -p "$releasedir"

# Build project.
build_project "$releasedir/$project.$goarch"
build_project "$releasedir/$project" "$native_arch" "${add_arches[@]}"

# Generate new archive.
git archive --format=tar --prefix="$project-$version/" "$commit" | xz >"$releasedir/$project.tar.xz"

# Generate sha256 checksums for both.
# Generate sha256 checksums for binaries and libseccomp tarball.
(
cd "$releasedir"
"$hashcmd" "$project".{"$goarch",tar.xz} >"$project.$hashcmd"
# Add $project. prefix to all suffixes.
"$hashcmd" "${suffixes[@]/#/$project.}" >"$project.$hashcmd"
)

# Set up the gpgflags.
Expand All @@ -154,8 +192,9 @@ gpgflags=()
gpg_cansign "${gpgflags[@]}" || bail "Could not find suitable GPG key, skipping signing step."

# Sign everything.
gpg "${gpgflags[@]}" --detach-sign --armor "$releasedir/$project.$goarch"
gpg "${gpgflags[@]}" --detach-sign --armor "$releasedir/$project.tar.xz"
for sfx in "${suffixes[@]}"; do
gpg "${gpgflags[@]}" --detach-sign --armor "$releasedir/$project.$sfx"
done
gpg "${gpgflags[@]}" --clear-sign --armor \
--output "$releasedir/$project.$hashcmd"{.tmp,} &&
mv "$releasedir/$project.$hashcmd"{.tmp,}
Loading

0 comments on commit f30244e

Please sign in to comment.