mirror of
https://github.com/navidrome/navidrome.git
synced 2026-07-09 17:18:45 +00:00
Some checks are pending
Pipeline: Test, Lint, Build / Get version info (push) Waiting to run
Pipeline: Test, Lint, Build / Lint Go code (push) Waiting to run
Pipeline: Test, Lint, Build / Test Go code (push) Waiting to run
Pipeline: Test, Lint, Build / Test Go code (Windows) (push) Waiting to run
Pipeline: Test, Lint, Build / Test JS code (push) Waiting to run
Pipeline: Test, Lint, Build / Lint i18n files (push) Waiting to run
Pipeline: Test, Lint, Build / Check Docker configuration (push) Waiting to run
Pipeline: Test, Lint, Build / Build (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-1 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-2 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-3 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-4 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-5 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-6 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-7 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-8 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-9 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-10 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Push to GHCR (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build Windows installers (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Package/Release (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Blocked by required conditions
* fix(build): force nodynamic webp tag on 32-bit standalone binaries gen2brain/webp's native libwebp backend links ebitengine/purego, whose reverse callbacks are unsupported on 32-bit ARM and x86. purego registers its callback in package init(), so the binary crashes at startup (SIGSEGV or SIGILL) before any Navidrome code runs. The nodynamic build tag from #5606 forces the safe WASM path, but it was only applied to the Docker-image build stage. The standalone build stage, which produces the downloads-page tarballs and the deb/rpm packages, still linked purego, so the armv7/v6/v5 and 386 downloads crashed on launch (#5738, #5735). Move the tag decision into release/build-tags.sh, shared by both build stages so they can no longer drift, and add release/verify-binary.sh as a build-time guard that fails if a 32-bit binary links purego. * fix(build): harden webp build-tag scripts per review - verify-binary.sh: fail loudly when the target binary is missing (e.g. an unmatched glob) instead of letting `go version -m` fail inside a pipeline and silently pass, which would bypass the guard. - build-tags.sh / verify-binary.sh: fall back to `go env GOARCH` when xx-info is unavailable, so the scripts stay correct outside the xx build image. (Not `uname -m`, which reports the build host, not the cross target.) - Dockerfile: use `set -e` in the standalone build block and drop the redundant `|| exit 1` suffixes; keep the debug GOENV dump non-fatal. * chore(build): quote -tags argument in both build stages Defensive quoting per review; the value comes from release/build-tags.sh and contains no whitespace today, but quoting prevents word-splitting if it ever does. * fix(build): link 32-bit arm binaries with LLD to fix startup crash The standalone armv7/v6/v5 binaries of 0.63.0 crash before main() with SIGSEGV/SIGILL (issues #5738, #5735). Root cause, established from a core dump of the crashing binary under qemu: GNU ld emits corrupt R_ARM_IRELATIVE addends for libatomic's ifunc resolvers (wrong address and missing Thumb bit) once .text outgrows the 16MB Thumb branch range. glibc's static-init ifunc resolution then does `blx` into ARM-mode garbage and the process dies before any log output. v0.62.0 was unaffected only because its .text was still under 16MB (15.1MB); v0.63.0 crossed the line (17.5MB), so every 0.63.0 32-bit arm build crashes regardless of Go or dependency versions. Link 32-bit arm with LLD (already installed in the build stage), which emits correct IRELATIVE addends. Verified under qemu: the armv7 artifact built by the unchanged pipeline now boots to "Navidrome server is ready" with SQLite migrations working, where the previous binary segfaulted at startup. Also add a CI smoke test that runs each cross-compiled linux binary under binfmt/qemu right after building it, so any future crashes-at-startup-on-some-arch regression fails the pipeline instead of shipping in a release.
184 lines
6.6 KiB
Docker
184 lines
6.6 KiB
Docker
FROM --platform=$BUILDPLATFORM ghcr.io/crazy-max/osxcross:14.5-debian AS osxcross
|
|
|
|
########################################################################################################################
|
|
### Build xx (original image: tonistiigi/xx)
|
|
FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/alpine:3.20 AS xx-build
|
|
|
|
# v1.9.0
|
|
ENV XX_VERSION=a5592eab7a57895e8d385394ff12241bc65ecd50
|
|
|
|
RUN apk add -U --no-cache git
|
|
RUN git clone https://github.com/tonistiigi/xx && \
|
|
cd xx && \
|
|
git checkout ${XX_VERSION} && \
|
|
mkdir -p /out && \
|
|
cp src/xx-* /out/
|
|
|
|
RUN cd /out && \
|
|
ln -s xx-cc /out/xx-clang && \
|
|
ln -s xx-cc /out/xx-clang++ && \
|
|
ln -s xx-cc /out/xx-c++ && \
|
|
ln -s xx-apt /out/xx-apt-get
|
|
|
|
# xx mimics the original tonistiigi/xx image
|
|
FROM scratch AS xx
|
|
COPY --from=xx-build /out/ /usr/bin/
|
|
|
|
########################################################################################################################
|
|
### Build Navidrome UI
|
|
FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/node:lts-alpine AS ui
|
|
WORKDIR /app
|
|
|
|
# Install node dependencies
|
|
COPY ui/package.json ui/package-lock.json ./
|
|
COPY ui/bin/ ./bin/
|
|
RUN npm ci
|
|
|
|
# Build bundle
|
|
COPY ui/ ./
|
|
RUN npm run build -- --outDir=/build
|
|
|
|
FROM scratch AS ui-bundle
|
|
COPY --from=ui /build /build
|
|
|
|
########################################################################################################################
|
|
### Build Navidrome binary for Docker image (dynamic musl, enables native libwebp via dlopen)
|
|
FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/golang:1.26-alpine AS build-alpine
|
|
COPY --from=xx / /
|
|
|
|
ARG TARGETPLATFORM
|
|
|
|
RUN apk add --no-cache clang lld file git
|
|
RUN xx-apk add --no-cache gcc musl-dev zlib-dev
|
|
RUN xx-verify --setup
|
|
|
|
WORKDIR /workspace
|
|
|
|
RUN --mount=type=bind,source=. \
|
|
--mount=type=cache,target=/root/.cache \
|
|
--mount=type=cache,target=/go/pkg/mod \
|
|
go mod download
|
|
|
|
ARG GIT_SHA
|
|
ARG GIT_TAG
|
|
|
|
RUN --mount=type=bind,source=. \
|
|
--mount=from=ui,source=/build,target=./ui/build,ro \
|
|
--mount=type=cache,target=/root/.cache \
|
|
--mount=type=cache,target=/go/pkg/mod <<EOT
|
|
set -e
|
|
xx-go --wrap
|
|
export CGO_ENABLED=1
|
|
BUILD_TAGS=$(./release/build-tags.sh)
|
|
# -latomic is required on 32-bit arm (arm/v6, arm/v7) so SQLite's 64-bit atomics resolve.
|
|
go build -tags="${BUILD_TAGS}" -ldflags="-w -s \
|
|
-linkmode=external -extldflags '-latomic' \
|
|
-X github.com/navidrome/navidrome/consts.gitSha=${GIT_SHA} \
|
|
-X github.com/navidrome/navidrome/consts.gitTag=${GIT_TAG}" \
|
|
-o /out/navidrome .
|
|
# Fail the build if native libwebp (purego) leaked into a 32-bit binary (issue #5738).
|
|
./release/verify-binary.sh /out/navidrome
|
|
# Fail the build if the binary is accidentally statically linked: dlopen (and
|
|
# therefore native libwebp detection) only works with a dynamic interpreter.
|
|
file /out/navidrome | grep -q "dynamically linked" || { echo "ERROR: /out/navidrome is not dynamically linked"; file /out/navidrome; exit 1; }
|
|
EOT
|
|
|
|
########################################################################################################################
|
|
### Build Navidrome binary for standalone distribution (static glibc, cross-compiled)
|
|
FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/golang:1.26-trixie AS base
|
|
RUN apt-get update && apt-get install -y clang lld
|
|
COPY --from=xx / /
|
|
WORKDIR /workspace
|
|
|
|
FROM --platform=$BUILDPLATFORM base AS build
|
|
|
|
# Install build dependencies for the target platform
|
|
ARG TARGETPLATFORM
|
|
|
|
RUN xx-apt install -y binutils gcc g++ libc6-dev zlib1g-dev
|
|
RUN xx-verify --setup
|
|
|
|
RUN --mount=type=bind,source=. \
|
|
--mount=type=cache,target=/root/.cache \
|
|
--mount=type=cache,target=/go/pkg/mod \
|
|
go mod download
|
|
|
|
ARG GIT_SHA
|
|
ARG GIT_TAG
|
|
|
|
RUN --mount=type=bind,source=. \
|
|
--mount=from=ui,source=/build,target=./ui/build,ro \
|
|
--mount=from=osxcross,src=/osxcross/SDK,target=/xx-sdk,ro \
|
|
--mount=type=cache,target=/root/.cache \
|
|
--mount=type=cache,target=/go/pkg/mod <<EOT
|
|
set -e
|
|
|
|
# Setup CGO cross-compilation environment
|
|
xx-go --wrap
|
|
export CGO_ENABLED=1
|
|
cat "$(go env GOENV)" 2>/dev/null || true
|
|
|
|
# Only Darwin (macOS) requires clang (default), Windows requires gcc, everything else can use any compiler.
|
|
# So let's use gcc for everything except Darwin.
|
|
if [ "$(xx-info os)" != "darwin" ]; then
|
|
export CC=$(xx-info)-gcc
|
|
export CXX=$(xx-info)-g++
|
|
export LD_EXTRA="-extldflags '-static -latomic'"
|
|
fi
|
|
# GNU ld corrupts the R_ARM_IRELATIVE addends of libatomic's ifunc resolvers
|
|
# (wrong address, Thumb bit lost) once .text outgrows the 16MB Thumb branch
|
|
# range, making static arm binaries jump to garbage inside glibc's ifunc
|
|
# resolution and crash before main() (issue #5738). Link 32-bit arm with LLD,
|
|
# which emits correct addends.
|
|
if [ "$(xx-info arch)" = "arm" ]; then
|
|
export LD_EXTRA="-extldflags '-static -latomic -fuse-ld=lld'"
|
|
fi
|
|
if [ "$(xx-info os)" = "windows" ]; then
|
|
export EXT=".exe"
|
|
fi
|
|
|
|
BUILD_TAGS=$(./release/build-tags.sh)
|
|
go build -tags="${BUILD_TAGS}" -ldflags="${LD_EXTRA} -w -s \
|
|
-X github.com/navidrome/navidrome/consts.gitSha=${GIT_SHA} \
|
|
-X github.com/navidrome/navidrome/consts.gitTag=${GIT_TAG}" \
|
|
-o /out/navidrome${EXT} .
|
|
# Fail the build if native libwebp (purego) leaked into a 32-bit binary (issue #5738).
|
|
./release/verify-binary.sh /out/navidrome*
|
|
EOT
|
|
|
|
# Verify if the binary was built for the correct platform and it is statically linked
|
|
RUN xx-verify --static /out/navidrome*
|
|
|
|
FROM scratch AS binary
|
|
COPY --from=build /out /
|
|
|
|
########################################################################################################################
|
|
### Build Final Image
|
|
FROM public.ecr.aws/docker/library/alpine:3.20 AS final
|
|
LABEL maintainer="deluan@navidrome.org"
|
|
LABEL org.opencontainers.image.source="https://github.com/navidrome/navidrome"
|
|
|
|
# Install runtime dependencies
|
|
# - libwebp + symlinks: enables native WebP encoding via purego/dlopen
|
|
RUN apk add -U --no-cache ffmpeg mpv sqlite libwebp libwebpdemux libwebpmux && \
|
|
for lib in libwebp libwebpdemux libwebpmux; do \
|
|
target=$(ls /usr/lib/$lib.so.* 2>/dev/null | head -1) && \
|
|
[ -n "$target" ] && ln -sf "$target" /usr/lib/$lib.so; \
|
|
done
|
|
|
|
# Copy navidrome binary (musl build for Docker, enables native libwebp)
|
|
COPY --from=build-alpine /out/navidrome /app/
|
|
|
|
VOLUME ["/data", "/music"]
|
|
ENV ND_MUSICFOLDER=/music
|
|
ENV ND_DATAFOLDER=/data
|
|
ENV ND_CONFIGFILE=/data/navidrome.toml
|
|
ENV ND_PORT=4533
|
|
RUN touch /.nddockerenv
|
|
|
|
EXPOSE ${ND_PORT}
|
|
WORKDIR /app
|
|
ENV PATH="/app:${PATH}"
|
|
|
|
ENTRYPOINT ["/app/navidrome"]
|
|
|