2024-10-15 16:46:01 -04:00
|
|
|
FROM --platform=$BUILDPLATFORM ghcr.io/crazy-max/osxcross:14.5-debian AS osxcross
|
|
|
|
|
|
|
|
|
|
########################################################################################################################
|
2025-07-20 13:36:46 -04:00
|
|
|
### Build xx (original image: tonistiigi/xx)
|
2026-08-30 14:25:36 -04:00
|
|
|
FROM --platform=$BUILDPLATFORM alpine:3.22 AS xx-build
|
2024-10-15 16:46:01 -04:00
|
|
|
|
2025-12-15 14:10:34 -05:00
|
|
|
# v1.9.0
|
|
|
|
|
ENV XX_VERSION=a5592eab7a57895e8d385394ff12241bc65ecd50
|
2024-10-15 16:46:01 -04:00
|
|
|
|
|
|
|
|
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
|
ci: pull base images through mirror.gcr.io instead of ECR Public (#5997)
CI builds were failing at random with:
buildx failed with: toomanyrequests: Rate exceeded
The 429 comes from public.ecr.aws, not Docker Hub. AWS caps unauthenticated
ECR Public pulls at 1 per second per source IP (authenticated: 10/s). The
build matrix starts 11 jobs at once and each resolves 4 base images, so
roughly 44 anonymous pulls land in a couple of seconds — from GitHub runner
IPs that are shared with every other GitHub customer.
Measured against public.ecr.aws with an anonymous token, 60 requests at
concurrency 30 returned 31x 429 in 0.48s.
The same probe against mirror.gcr.io (Google's Docker Hub pull-through
cache) returned zero errors: 750 manifest requests up to ~141 req/s, plus
120 layer blob requests at concurrency 60. Google publishes no rate limit
for it, so this is measured headroom, not a contract — but it is roughly
10x the pipeline's peak rate, and cached pulls do not count against Docker
Hub's limits either.
Authenticating to ECR Public was the alternative. It was rejected because
10 pulls/s is still under the ~44-pull burst, it needs an AWS account plus
a secret, and secrets never reach fork pull requests — so forks would keep
failing. The mirror fixes forks too.
Verified buildkit honours the mirror block by routing a build through a
local logging registry: all 6 requests (manifests and blobs) hit the mirror,
none went to Docker Hub directly. Confirmed mirror.gcr.io answers 200 for
buildkit's "?ns=docker.io" query form on all four images, for both GET and
HEAD. Confirmed buildkit falls back to Docker Hub when the mirror is
unreachable — the build still succeeds, but the resolve takes ~30s instead
of ~0.3s, so a mirror outage means slow builds, not broken ones. The
existing Docker Hub login covers that fallback on main-repo runs.
msitools.dockerfile is only used by the local `make docker-msi` target, but
is switched over too so no ECR Public reference is left behind.
2026-08-20 10:02:04 -04:00
|
|
|
FROM --platform=$BUILDPLATFORM node:lts-alpine AS ui
|
2024-10-15 16:46:01 -04:00
|
|
|
WORKDIR /app
|
|
|
|
|
|
|
|
|
|
# Install node dependencies
|
|
|
|
|
COPY ui/package.json ui/package-lock.json ./
|
2024-11-30 10:33:16 -05:00
|
|
|
COPY ui/bin/ ./bin/
|
2024-10-15 16:46:01 -04:00
|
|
|
RUN npm ci
|
|
|
|
|
|
|
|
|
|
# Build bundle
|
|
|
|
|
COPY ui/ ./
|
|
|
|
|
RUN npm run build -- --outDir=/build
|
|
|
|
|
|
|
|
|
|
FROM scratch AS ui-bundle
|
|
|
|
|
COPY --from=ui /build /build
|
|
|
|
|
|
|
|
|
|
########################################################################################################################
|
feat(artwork): enable native libwebp encoding in Docker image (#5350)
* feat(docker): add musl build stage for native libwebp support
Add a new build-alpine stage using Alpine/musl with xx cross-compilation,
producing a dynamically-linked musl binary for the Docker image. The
runtime image now installs libwebp, libwebpdemux, and libwebpmux and
creates .so symlinks so gen2brain/webp can detect native libwebp via
purego/dlopen at startup and use it automatically.
The existing Debian/glibc 'build' stage is kept for standalone binary
distribution (darwin, windows, and glibc linux binaries); the Docker
image now ships the musl build from build-alpine instead.
* fix(docker): use dynamic symlinks for libwebp libraries
Avoid hardcoding SONAME versions (.so.7, .so.2, .so.3) which break
on Alpine version bumps. Also fix misleading comment: the musl build
is dynamic (required for purego dlopen), not static.
* feat(docker): enable WebP encoding in Docker environment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(docker): pin build-alpine stage to Go 1.25 to match base stage
Align the new build-alpine stage with the existing glibc 'base' stage,
both pinned to Go 1.25. Bumping build-alpine independently would create
a version skew between the Docker image binary and the standalone
binaries, which should be avoided unless there is a specific reason.
* fix(docker): harden build-alpine stage (musl pin, -latomic, dynamic-link check)
Address review feedback on the build-alpine stage:
- Pin Go builder to golang:1.25-alpine3.20 so the musl version used at
build time matches the alpine:3.20 runtime image, eliminating any
potential musl ABI skew between builder and runtime.
- Add -extldflags '-latomic' so SQLite's 64-bit atomics resolve when
cross-compiling for 32-bit arm targets (arm/v6, arm/v7).
- Add a build-time check that the produced binary is dynamically
linked (using 'file' from Alpine), failing the build if it is not.
A fully-static binary cannot dlopen libwebp and would silently fall
back to the WASM encoder, defeating the whole point of this stage.
* fix(docker): revert to unpinned golang:1.25-alpine builder
The golang:1.25-alpine3.20 tag suggested during review does not exist on
public.ecr.aws (only 3.21, 3.22, 3.23, and unpinned 'alpine' are
published). Revert to the unpinned 'golang:1.25-alpine' tag so the
Docker build can resolve the base image.
This means the builder's Alpine version can drift relative to the
alpine:3.20 runtime, but in practice musl's backward compatibility
covers this for Navidrome's small dlopen surface (a few libwebp
symbols, no direct libc calls from the dlopen path). If a skew ever
manifests, we can pin both builder and runtime to the same specific
Alpine release in a follow-up.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-04-13 13:30:05 -04:00
|
|
|
### Build Navidrome binary for Docker image (dynamic musl, enables native libwebp via dlopen)
|
chore(deps): upgrade to Go 1.27 (#5990)
* build: upgrade to Go 1.27
Bumps the toolchain in go.mod, both golang base images in the Dockerfile, and
the devcontainer VARIANT. CI needs no change, as the workflows resolve the
version through go-version-file: go.mod.
Tests, race tests, build and vet all pass on go1.27.0.
* build: upgrade golangci-lint to v2.13.0
v2.13.0 is the first release built with Go 1.27, so it can lint a module whose go
directive is 1.27. It also enables gosec's G404 on math/rand/v2, which flags the
three rand.Shuffle call sites. Shuffle order is not a security decision, and the
crypto-backed alternative in utils/random costs 25x and allocates per swap, so the
call sites are annotated rather than the rule excluded, keeping G404 active for the
cases where it would matter.
* chore(deps): update Go dependencies to latest versions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: bump golangci-lint to v2.13.2
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-08-30 12:43:15 -04:00
|
|
|
FROM --platform=$BUILDPLATFORM golang:1.27-alpine AS build-alpine
|
feat(artwork): enable native libwebp encoding in Docker image (#5350)
* feat(docker): add musl build stage for native libwebp support
Add a new build-alpine stage using Alpine/musl with xx cross-compilation,
producing a dynamically-linked musl binary for the Docker image. The
runtime image now installs libwebp, libwebpdemux, and libwebpmux and
creates .so symlinks so gen2brain/webp can detect native libwebp via
purego/dlopen at startup and use it automatically.
The existing Debian/glibc 'build' stage is kept for standalone binary
distribution (darwin, windows, and glibc linux binaries); the Docker
image now ships the musl build from build-alpine instead.
* fix(docker): use dynamic symlinks for libwebp libraries
Avoid hardcoding SONAME versions (.so.7, .so.2, .so.3) which break
on Alpine version bumps. Also fix misleading comment: the musl build
is dynamic (required for purego dlopen), not static.
* feat(docker): enable WebP encoding in Docker environment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(docker): pin build-alpine stage to Go 1.25 to match base stage
Align the new build-alpine stage with the existing glibc 'base' stage,
both pinned to Go 1.25. Bumping build-alpine independently would create
a version skew between the Docker image binary and the standalone
binaries, which should be avoided unless there is a specific reason.
* fix(docker): harden build-alpine stage (musl pin, -latomic, dynamic-link check)
Address review feedback on the build-alpine stage:
- Pin Go builder to golang:1.25-alpine3.20 so the musl version used at
build time matches the alpine:3.20 runtime image, eliminating any
potential musl ABI skew between builder and runtime.
- Add -extldflags '-latomic' so SQLite's 64-bit atomics resolve when
cross-compiling for 32-bit arm targets (arm/v6, arm/v7).
- Add a build-time check that the produced binary is dynamically
linked (using 'file' from Alpine), failing the build if it is not.
A fully-static binary cannot dlopen libwebp and would silently fall
back to the WASM encoder, defeating the whole point of this stage.
* fix(docker): revert to unpinned golang:1.25-alpine builder
The golang:1.25-alpine3.20 tag suggested during review does not exist on
public.ecr.aws (only 3.21, 3.22, 3.23, and unpinned 'alpine' are
published). Revert to the unpinned 'golang:1.25-alpine' tag so the
Docker build can resolve the base image.
This means the builder's Alpine version can drift relative to the
alpine:3.20 runtime, but in practice musl's backward compatibility
covers this for Navidrome's small dlopen surface (a few libwebp
symbols, no direct libc calls from the dlopen path). If a skew ever
manifests, we can pin both builder and runtime to the same specific
Alpine release in a follow-up.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-04-13 13:30:05 -04:00
|
|
|
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
|
fix(build): prevent 32-bit startup crash (segfault/SIGILL) in downloads binaries (#5739)
* 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.
2026-07-09 06:30:44 -04:00
|
|
|
BUILD_TAGS=$(./release/build-tags.sh)
|
feat(artwork): enable native libwebp encoding in Docker image (#5350)
* feat(docker): add musl build stage for native libwebp support
Add a new build-alpine stage using Alpine/musl with xx cross-compilation,
producing a dynamically-linked musl binary for the Docker image. The
runtime image now installs libwebp, libwebpdemux, and libwebpmux and
creates .so symlinks so gen2brain/webp can detect native libwebp via
purego/dlopen at startup and use it automatically.
The existing Debian/glibc 'build' stage is kept for standalone binary
distribution (darwin, windows, and glibc linux binaries); the Docker
image now ships the musl build from build-alpine instead.
* fix(docker): use dynamic symlinks for libwebp libraries
Avoid hardcoding SONAME versions (.so.7, .so.2, .so.3) which break
on Alpine version bumps. Also fix misleading comment: the musl build
is dynamic (required for purego dlopen), not static.
* feat(docker): enable WebP encoding in Docker environment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(docker): pin build-alpine stage to Go 1.25 to match base stage
Align the new build-alpine stage with the existing glibc 'base' stage,
both pinned to Go 1.25. Bumping build-alpine independently would create
a version skew between the Docker image binary and the standalone
binaries, which should be avoided unless there is a specific reason.
* fix(docker): harden build-alpine stage (musl pin, -latomic, dynamic-link check)
Address review feedback on the build-alpine stage:
- Pin Go builder to golang:1.25-alpine3.20 so the musl version used at
build time matches the alpine:3.20 runtime image, eliminating any
potential musl ABI skew between builder and runtime.
- Add -extldflags '-latomic' so SQLite's 64-bit atomics resolve when
cross-compiling for 32-bit arm targets (arm/v6, arm/v7).
- Add a build-time check that the produced binary is dynamically
linked (using 'file' from Alpine), failing the build if it is not.
A fully-static binary cannot dlopen libwebp and would silently fall
back to the WASM encoder, defeating the whole point of this stage.
* fix(docker): revert to unpinned golang:1.25-alpine builder
The golang:1.25-alpine3.20 tag suggested during review does not exist on
public.ecr.aws (only 3.21, 3.22, 3.23, and unpinned 'alpine' are
published). Revert to the unpinned 'golang:1.25-alpine' tag so the
Docker build can resolve the base image.
This means the builder's Alpine version can drift relative to the
alpine:3.20 runtime, but in practice musl's backward compatibility
covers this for Navidrome's small dlopen surface (a few libwebp
symbols, no direct libc calls from the dlopen path). If a skew ever
manifests, we can pin both builder and runtime to the same specific
Alpine release in a follow-up.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-04-13 13:30:05 -04:00
|
|
|
# -latomic is required on 32-bit arm (arm/v6, arm/v7) so SQLite's 64-bit atomics resolve.
|
fix(build): prevent 32-bit startup crash (segfault/SIGILL) in downloads binaries (#5739)
* 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.
2026-07-09 06:30:44 -04:00
|
|
|
go build -tags="${BUILD_TAGS}" -ldflags="-w -s \
|
feat(artwork): enable native libwebp encoding in Docker image (#5350)
* feat(docker): add musl build stage for native libwebp support
Add a new build-alpine stage using Alpine/musl with xx cross-compilation,
producing a dynamically-linked musl binary for the Docker image. The
runtime image now installs libwebp, libwebpdemux, and libwebpmux and
creates .so symlinks so gen2brain/webp can detect native libwebp via
purego/dlopen at startup and use it automatically.
The existing Debian/glibc 'build' stage is kept for standalone binary
distribution (darwin, windows, and glibc linux binaries); the Docker
image now ships the musl build from build-alpine instead.
* fix(docker): use dynamic symlinks for libwebp libraries
Avoid hardcoding SONAME versions (.so.7, .so.2, .so.3) which break
on Alpine version bumps. Also fix misleading comment: the musl build
is dynamic (required for purego dlopen), not static.
* feat(docker): enable WebP encoding in Docker environment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(docker): pin build-alpine stage to Go 1.25 to match base stage
Align the new build-alpine stage with the existing glibc 'base' stage,
both pinned to Go 1.25. Bumping build-alpine independently would create
a version skew between the Docker image binary and the standalone
binaries, which should be avoided unless there is a specific reason.
* fix(docker): harden build-alpine stage (musl pin, -latomic, dynamic-link check)
Address review feedback on the build-alpine stage:
- Pin Go builder to golang:1.25-alpine3.20 so the musl version used at
build time matches the alpine:3.20 runtime image, eliminating any
potential musl ABI skew between builder and runtime.
- Add -extldflags '-latomic' so SQLite's 64-bit atomics resolve when
cross-compiling for 32-bit arm targets (arm/v6, arm/v7).
- Add a build-time check that the produced binary is dynamically
linked (using 'file' from Alpine), failing the build if it is not.
A fully-static binary cannot dlopen libwebp and would silently fall
back to the WASM encoder, defeating the whole point of this stage.
* fix(docker): revert to unpinned golang:1.25-alpine builder
The golang:1.25-alpine3.20 tag suggested during review does not exist on
public.ecr.aws (only 3.21, 3.22, 3.23, and unpinned 'alpine' are
published). Revert to the unpinned 'golang:1.25-alpine' tag so the
Docker build can resolve the base image.
This means the builder's Alpine version can drift relative to the
alpine:3.20 runtime, but in practice musl's backward compatibility
covers this for Navidrome's small dlopen surface (a few libwebp
symbols, no direct libc calls from the dlopen path). If a skew ever
manifests, we can pin both builder and runtime to the same specific
Alpine release in a follow-up.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-04-13 13:30:05 -04:00
|
|
|
-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 .
|
fix(build): prevent 32-bit startup crash (segfault/SIGILL) in downloads binaries (#5739)
* 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.
2026-07-09 06:30:44 -04:00
|
|
|
# Fail the build if native libwebp (purego) leaked into a 32-bit binary (issue #5738).
|
|
|
|
|
./release/verify-binary.sh /out/navidrome
|
feat(artwork): enable native libwebp encoding in Docker image (#5350)
* feat(docker): add musl build stage for native libwebp support
Add a new build-alpine stage using Alpine/musl with xx cross-compilation,
producing a dynamically-linked musl binary for the Docker image. The
runtime image now installs libwebp, libwebpdemux, and libwebpmux and
creates .so symlinks so gen2brain/webp can detect native libwebp via
purego/dlopen at startup and use it automatically.
The existing Debian/glibc 'build' stage is kept for standalone binary
distribution (darwin, windows, and glibc linux binaries); the Docker
image now ships the musl build from build-alpine instead.
* fix(docker): use dynamic symlinks for libwebp libraries
Avoid hardcoding SONAME versions (.so.7, .so.2, .so.3) which break
on Alpine version bumps. Also fix misleading comment: the musl build
is dynamic (required for purego dlopen), not static.
* feat(docker): enable WebP encoding in Docker environment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(docker): pin build-alpine stage to Go 1.25 to match base stage
Align the new build-alpine stage with the existing glibc 'base' stage,
both pinned to Go 1.25. Bumping build-alpine independently would create
a version skew between the Docker image binary and the standalone
binaries, which should be avoided unless there is a specific reason.
* fix(docker): harden build-alpine stage (musl pin, -latomic, dynamic-link check)
Address review feedback on the build-alpine stage:
- Pin Go builder to golang:1.25-alpine3.20 so the musl version used at
build time matches the alpine:3.20 runtime image, eliminating any
potential musl ABI skew between builder and runtime.
- Add -extldflags '-latomic' so SQLite's 64-bit atomics resolve when
cross-compiling for 32-bit arm targets (arm/v6, arm/v7).
- Add a build-time check that the produced binary is dynamically
linked (using 'file' from Alpine), failing the build if it is not.
A fully-static binary cannot dlopen libwebp and would silently fall
back to the WASM encoder, defeating the whole point of this stage.
* fix(docker): revert to unpinned golang:1.25-alpine builder
The golang:1.25-alpine3.20 tag suggested during review does not exist on
public.ecr.aws (only 3.21, 3.22, 3.23, and unpinned 'alpine' are
published). Revert to the unpinned 'golang:1.25-alpine' tag so the
Docker build can resolve the base image.
This means the builder's Alpine version can drift relative to the
alpine:3.20 runtime, but in practice musl's backward compatibility
covers this for Navidrome's small dlopen surface (a few libwebp
symbols, no direct libc calls from the dlopen path). If a skew ever
manifests, we can pin both builder and runtime to the same specific
Alpine release in a follow-up.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-04-13 13:30:05 -04:00
|
|
|
# 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)
|
chore(deps): upgrade to Go 1.27 (#5990)
* build: upgrade to Go 1.27
Bumps the toolchain in go.mod, both golang base images in the Dockerfile, and
the devcontainer VARIANT. CI needs no change, as the workflows resolve the
version through go-version-file: go.mod.
Tests, race tests, build and vet all pass on go1.27.0.
* build: upgrade golangci-lint to v2.13.0
v2.13.0 is the first release built with Go 1.27, so it can lint a module whose go
directive is 1.27. It also enables gosec's G404 on math/rand/v2, which flags the
three rand.Shuffle call sites. Shuffle order is not a security decision, and the
crypto-backed alternative in utils/random costs 25x and allocates per swap, so the
call sites are annotated rather than the rule excluded, keeping G404 active for the
cases where it would matter.
* chore(deps): update Go dependencies to latest versions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: bump golangci-lint to v2.13.2
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-08-30 12:43:15 -04:00
|
|
|
FROM --platform=$BUILDPLATFORM golang:1.27-trixie AS base
|
2024-10-15 16:46:01 -04:00
|
|
|
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
|
|
|
|
|
|
feat(bfr): Big Refactor: new scanner, lots of new fields and tags, improvements and DB schema changes (#2709)
* fix(server): more race conditions when updating artist/album from external sources
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scanner): add .gitignore syntax to .ndignore. Resolves #1394
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): null
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): pass configfile option to child process
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): resume interrupted fullScans
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): remove old scanner code
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): rename old metadata package
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): move old metadata package
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: tests
Signed-off-by: Deluan <deluan@navidrome.org>
* chore(deps): update Go to 1.23.4
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: logs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(test):
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: log level
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add config for scanner watcher
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: children playlists
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: replace `interface{}` with `any`
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: smart playlists with genres
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: allow any tags in smart playlists
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: artist names in playlists
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: smart playlist's sort by tags
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add moods to child
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add moods to AlbumID3
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(subsonic): use generic JSONArray for OS arrays
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(subsonic): use https in test
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add releaseTypes to AlbumID3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add recordLabels to AlbumID3
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(subsonic): rename JSONArray to Array
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add artists to AlbumID3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add artists to Child
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): do not pre-populate smart playlists
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): implement a simplified version of ArtistID3.
See https://github.com/opensubsonic/open-subsonic-api/discussions/120
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add artists to album child
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add contributors to mediafile Child
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add albumArtists to mediafile Child
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add displayArtist and displayAlbumArtist
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add displayComposer to Child
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add roles to ArtistID3
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(subsonic): use " • " separator for displayComposer
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor:
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(subsonic):
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(subsonic): respect `PreferSortTags` config option
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(subsonic):
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: optimize purging non-unused tags
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: don't run 'refresh artist stats' concurrently with other transactions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor:
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Scanner.ScanOnStartup config option, default true
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: better json parsing error msg when importing NSPs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: don't update album's imported_time when updating external_metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle interrupted scans and full scans after migrations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: run `analyze` when migration requires a full rescan
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: run `PRAGMA optimize` at the end of the scan
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: don't update artist's updated_at when updating external_metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: handle multiple artists and roles in smart playlists
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): dim missing tracks
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: album missing logic
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: error encoding in gob
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: separate warnings from errors
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: mark albums as missing if they were contained in a deleted folder
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: add participant names to media_file and album tables
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: use participations in criteria, instead of m2m relationship
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename participations to participants
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add moods to album child
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: albumartist role case
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scanner): run scanner as an external process by default
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): show albumArtist names
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): dim out missing albums
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: flaky test
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(server): scrobble buffer mapping. fix #3583
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: more participations renaming
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: listenbrainz scrobbling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: send release_group_mbid to listenbrainz
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): implement OpenSubsonic explicitStatus field (#3597)
* feat: implement OpenSubsonic explicitStatus field
* fix(subsonic): fix failing snapshot tests
* refactor: create helper for setting explicitStatus
* fix: store smaller values for explicit-status on database
* test: ToAlbum explicitStatus
* refactor: rename explicitStatus helper function
---------
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
* fix: handle album and track tags in the DB based on the mappings.yaml file
Signed-off-by: Deluan <deluan@navidrome.org>
* save similar artists as JSONB
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: getAlbumList byGenre
Signed-off-by: Deluan <deluan@navidrome.org>
* detect changes in PID configuration
Signed-off-by: Deluan <deluan@navidrome.org>
* set default album PID to legacy_pid
Signed-off-by: Deluan <deluan@navidrome.org>
* fix tests
Signed-off-by: Deluan <deluan@navidrome.org>
* fix SIGSEGV
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: don't lose album stars/ratings when migrating
Signed-off-by: Deluan <deluan@navidrome.org>
* store full PID conf in properties
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: keep album annotations when changing PID.Album config
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: reassign album annotations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: use (display) albumArtist and add links to each artist
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: not showing albums by albumartist
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: error msgs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: hide PID from Native API
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: album cover art resolution
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: trim participant names
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: reduce watcher log spam
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: panic when initializing the watcher
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: various artists
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: don't store empty lyrics in the DB
Signed-off-by: Deluan <deluan@navidrome.org>
* remove unused methods
Signed-off-by: Deluan <deluan@navidrome.org>
* drop full_text indexes, as they are not being used by SQLite
Signed-off-by: Deluan <deluan@navidrome.org>
* keep album created_at when upgrading
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): null pointer
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: album artwork cache
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: don't expose missing files in Subsonic API
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: searchable interface
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: filter out missing items from subsonic search
* fix: filter out missing items from playlists
* fix: filter out missing items from shares
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): add filter by artist role
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): only return albumartists in getIndexes and getArtists endpoints
Signed-off-by: Deluan <deluan@navidrome.org>
* sort roles alphabetically
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: artist playcounts
Signed-off-by: Deluan <deluan@navidrome.org>
* change default Album PID conf
Signed-off-by: Deluan <deluan@navidrome.org>
* fix albumartist link when it does not match any albumartists values
Signed-off-by: Deluan <deluan@navidrome.org>
* fix `Ignoring filter not whitelisted` (role) message
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: trim any names/titles being imported
Signed-off-by: Deluan <deluan@navidrome.org>
* remove unused genre code
Signed-off-by: Deluan <deluan@navidrome.org>
* serialize calls to Last.fm's getArtist
Signed-off-by: Deluan <deluan@navidrome.org>
xxx
Signed-off-by: Deluan <deluan@navidrome.org>
* add counters to genres
Signed-off-by: Deluan <deluan@navidrome.org>
* nit: fix migration `notice` message
Signed-off-by: Deluan <deluan@navidrome.org>
* optimize similar artists query
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: last.fm.getInfo when mbid does not exist
Signed-off-by: Deluan <deluan@navidrome.org>
* ui only show missing items for admins
Signed-off-by: Deluan <deluan@navidrome.org>
* don't allow interaction with missing items
Signed-off-by: Deluan <deluan@navidrome.org>
* Add Missing Files view (WIP)
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: merged tag_counts into tag table
Signed-off-by: Deluan <deluan@navidrome.org>
* add option to completely disable automatic scanner
Signed-off-by: Deluan <deluan@navidrome.org>
* add delete missing files functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: playlists not showing for regular users
Signed-off-by: Deluan <deluan@navidrome.org>
* reduce updateLastAccess frequency to once every minute
Signed-off-by: Deluan <deluan@navidrome.org>
* reduce update player frequency to once every minute
Signed-off-by: Deluan <deluan@navidrome.org>
* add timeout when updating player
Signed-off-by: Deluan <deluan@navidrome.org>
* remove dead code
Signed-off-by: Deluan <deluan@navidrome.org>
* fix duplicated roles in stats
Signed-off-by: Deluan <deluan@navidrome.org>
* add `; ` to artist splitters
Signed-off-by: Deluan <deluan@navidrome.org>
* fix stats query
Signed-off-by: Deluan <deluan@navidrome.org>
* more logs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: support legacy clients (DSub) by removing OpenSubsonic extra fields - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: support legacy clients (DSub) by removing OpenSubsonic extra fields - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: support legacy clients (DSub) by removing OpenSubsonic extra fields - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: support legacy clients (DSub) by removing OpenSubsonic extra fields - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* add record label filter
Signed-off-by: Deluan <deluan@navidrome.org>
* add release type filter
Signed-off-by: Deluan <deluan@navidrome.org>
* fix purgeUnused tags
Signed-off-by: Deluan <deluan@navidrome.org>
* add grouping filter to albums
Signed-off-by: Deluan <deluan@navidrome.org>
* allow any album tags to be used in as filters in the API
Signed-off-by: Deluan <deluan@navidrome.org>
* remove empty tags from album info
Signed-off-by: Deluan <deluan@navidrome.org>
* comments in the migration
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: Cannot read properties of undefined
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: listenbrainz scrobbling (#3640)
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove duplicated tag values
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: don't ignore the taglib folder!
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: show track subtitle tag
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: show artists stats based on selected role
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: inspect
Signed-off-by: Deluan <deluan@navidrome.org>
* add media type to album info/filters
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: change format of subtitle in the UI
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: subtitle in Subsonic API and search
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: subtitle in UI's player
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: split strings should be case-insensitive
Signed-off-by: Deluan <deluan@navidrome.org>
* disable ScanSchedule
Signed-off-by: Deluan <deluan@navidrome.org>
* increase default sessiontimeout
Signed-off-by: Deluan <deluan@navidrome.org>
* add sqlite command line tool to docker image
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: resources override
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: album PID conf
Signed-off-by: Deluan <deluan@navidrome.org>
* change migration to mark current artists as albumArtists
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): Allow filtering on multiple genres (#3679)
* feat(ui): Allow filtering on multiple genres
Signed-off-by: Henrik Nordvik <henrikno@gmail.com>
Signed-off-by: Deluan <deluan@navidrome.org>
* add multi-genre filter in Album list
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Henrik Nordvik <henrikno@gmail.com>
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Henrik Nordvik <henrikno@gmail.com>
* add more multi-valued tag filters to Album and Song views
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): unselect missing files after removing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): song filter
Signed-off-by: Deluan <deluan@navidrome.org>
* fix sharing tracks. fix #3687
Signed-off-by: Deluan <deluan@navidrome.org>
* use rowids when using search for sync (ex: Symfonium)
Signed-off-by: Deluan <deluan@navidrome.org>
* fix "Report Real Paths" option for subsonic clients
Signed-off-by: Deluan <deluan@navidrome.org>
* fix "Report Real Paths" option for subsonic clients for search
Signed-off-by: Deluan <deluan@navidrome.org>
* add libraryPath to Native API /songs endpoint
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add album version
Signed-off-by: Deluan <deluan@navidrome.org>
* made all tags lowercase as they are case-insensitive anyways.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): Show full paths, extended properties for album/song (#3691)
* feat(ui): Show full paths, extended properties for album/song
- uses library path + os separator + path
- show participants (album/song) and tags (song)
- make album/participant clickable in show info
* add source to path
* fix pathSeparator in UI
Signed-off-by: Deluan <deluan@navidrome.org>
* fix local artist artwork (#3695)
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: parse vorbis performers
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: clean function into smaller functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix translations for en and pt
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace log to show annotations reassignment
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace log to show annotations reassignment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: allow performers without instrument/subrole
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: metadata clean function again
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: optimize split function
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: split function is now a method of TagConf
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: humanize Artist total size
Signed-off-by: Deluan <deluan@navidrome.org>
* add album version to album details
Signed-off-by: Deluan <deluan@navidrome.org>
* don't display album-level tags in SongInfo
Signed-off-by: Deluan <deluan@navidrome.org>
* fix genre clicking in Album Page
Signed-off-by: Deluan <deluan@navidrome.org>
* don't use mbids in Last.fm api calls.
From https://discord.com/channels/671335427726114836/704303730660737113/1337574018143879248:
With MBID:
```
GET https://ws.audioscrobbler.com/2.0/?api_key=XXXX&artist=Van+Morrison&format=json&lang=en&mbid=a41ac10f-0a56-4672-9161-b83f9b223559&method=artist.getInfo
{
artist: {
name: "Bee Gees",
mbid: "bf0f7e29-dfe1-416c-b5c6-f9ebc19ea810",
url: "https://www.last.fm/music/Bee+Gees",
}
```
Without MBID:
```
GET https://ws.audioscrobbler.com/2.0/?api_key=XXXX&artist=Van+Morrison&format=json&lang=en&method=artist.getInfo
{
artist: {
name: "Van Morrison",
mbid: "a41ac10f-0a56-4672-9161-b83f9b223559",
url: "https://www.last.fm/music/Van+Morrison",
}
```
Signed-off-by: Deluan <deluan@navidrome.org>
* better logging for when the artist folder is not found
Signed-off-by: Deluan <deluan@navidrome.org>
* fix various issues with artist image resolution
Signed-off-by: Deluan <deluan@navidrome.org>
* hide "Additional Tags" header if there are none.
Signed-off-by: Deluan <deluan@navidrome.org>
* simplify tag rendering
Signed-off-by: Deluan <deluan@navidrome.org>
* enhance logging for artist folder detection
Signed-off-by: Deluan <deluan@navidrome.org>
* make folderID consistent for relative and absolute folderPaths
Signed-off-by: Deluan <deluan@navidrome.org>
* handle more folder paths scenarios
Signed-off-by: Deluan <deluan@navidrome.org>
* filter out other roles when SubsonicArtistParticipations = true
Signed-off-by: Deluan <deluan@navidrome.org>
* fix "Cannot read properties of undefined"
Signed-off-by: Deluan <deluan@navidrome.org>
* fix lyrics and comments being truncated (#3701)
* fix lyrics and comments being truncated
* specifically test for lyrics and comment length
* reorder assertions
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* fix(server): Expose library_path for playlist (#3705)
Allows showing absolute path for UI, and makes "report real path" work for playlists (Subsonic)
* fix BFR on Windows (#3704)
* fix potential reflected cross-site scripting vulnerability
Signed-off-by: Deluan <deluan@navidrome.org>
* hack to make it work on Windows
* ignore windows executables
* try fixing the pipeline
Signed-off-by: Deluan <deluan@navidrome.org>
* allow MusicFolder in other drives
* move windows local drive logic to local storage implementation
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* increase pagination sizes for missing files
Signed-off-by: Deluan <deluan@navidrome.org>
* reduce level of "already scanning" watcher log message
Signed-off-by: Deluan <deluan@navidrome.org>
* only count folders with audio files in it
See https://github.com/navidrome/navidrome/discussions/3676#discussioncomment-11990930
Signed-off-by: Deluan <deluan@navidrome.org>
* add album version and catalog number to search
Signed-off-by: Deluan <deluan@navidrome.org>
* add `organization` alias for `recordlabel`
Signed-off-by: Deluan <deluan@navidrome.org>
* remove mbid from Last.fm agent
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: support inspect in ui (#3726)
* inspect in ui
* address round 1
* add catalogNum to AlbumInfo
Signed-off-by: Deluan <deluan@navidrome.org>
* remove dependency on metadata_old (deprecated) package
Signed-off-by: Deluan <deluan@navidrome.org>
* add `RawTags` to model
Signed-off-by: Deluan <deluan@navidrome.org>
* support parsing MBIDs for roles (from the https://github.com/kgarner7/picard-all-mbids plugin) (#3698)
* parse standard roles, vorbis/m4a work for now
* fix djmixer
* working roles, use DJ-mix
* add performers to file
* map mbids
* add a few more tests
* add test
Signed-off-by: Deluan <deluan@navidrome.org>
* try to simplify the performers logic
Signed-off-by: Deluan <deluan@navidrome.org>
* stylistic changes
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* remove param mutation
Signed-off-by: Deluan <deluan@navidrome.org>
* run automated SQLite optimizations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix playlists import/export on Windows
* fix import playlists
* fix export playlists
* better handling of Windows volumes
Signed-off-by: Deluan <deluan@navidrome.org>
* handle more album ID reassignments
Signed-off-by: Deluan <deluan@navidrome.org>
* allow adding/overriding tags in the config file
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): Fix playlist track id, handle missing tracks better (#3734)
- Use `mediaFileId` instead of `id` for playlist tracks
- Only fetch if the file is not missing
- If extractor fails to get the file, also error (rather than panic)
* optimize DB after each scan.
Signed-off-by: Deluan <deluan@navidrome.org>
* remove sortable from AlbumSongs columns
Signed-off-by: Deluan <deluan@navidrome.org>
* simplify query to get missing tracks
Signed-off-by: Deluan <deluan@navidrome.org>
* mark Scanner.Extractor as deprecated
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Henrik Nordvik <henrikno@gmail.com>
Co-authored-by: Caio Cotts <caio@cotts.com.br>
Co-authored-by: Henrik Nordvik <henrikno@gmail.com>
Co-authored-by: Kendall Garner <17521368+kgarner7@users.noreply.github.com>
2025-02-19 17:35:17 -08:00
|
|
|
ARG GIT_SHA
|
|
|
|
|
ARG GIT_TAG
|
|
|
|
|
|
2024-10-15 16:46:01 -04:00
|
|
|
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 \
|
refactor(scanner): remove C++ taglib adapter (#5349)
* refactor(build): remove CPP taglib adapter
Remove the CGO-based TagLib adapter (adapters/taglib/) and all
cross-taglib build infrastructure. The WASM-based go-taglib adapter
(adapters/gotaglib/) is now the sole metadata extractor.
- Delete adapters/taglib/ (CPP/CGO wrapper)
- Delete .github/actions/download-taglib/
- Remove CROSS_TAGLIB_VERSION, CGO_CFLAGS_ALLOW, and all taglib-related
references from Dockerfile, Makefile, CI pipeline, and devcontainer
* fix(scanner): gracefully fallback to default extractor instead of crashing
Replace log.Fatal with a graceful fallback when the configured scanner
extractor is not found. Instead of terminating the process, the code now
warns and falls back to the default taglib extractor using the existing
consts.DefaultScannerExtractor constant. A fatal log is retained only for
the case where the default extractor itself is not registered, which
indicates a broken build.
* test(scanner): cover default extractor fallback and suppress redundant warn
Address review feedback on the extractor fallback in newLocalStorage:
- Only log the "using default" warning when the configured extractor
differs from the default, so a broken build (default extractor itself
missing) logs only the fatal — not a misleading "falling back" warn
followed immediately by the fatal.
- Add a unit test that registers a mock under consts.DefaultScannerExtractor,
sets the configured extractor to an unknown name, and asserts the local
storage is constructed using the default extractor's constructor.
2026-04-12 21:52:29 -04:00
|
|
|
--mount=type=cache,target=/go/pkg/mod <<EOT
|
fix(build): prevent 32-bit startup crash (segfault/SIGILL) in downloads binaries (#5739)
* 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.
2026-07-09 06:30:44 -04:00
|
|
|
set -e
|
2024-10-15 16:46:01 -04:00
|
|
|
|
|
|
|
|
# Setup CGO cross-compilation environment
|
|
|
|
|
xx-go --wrap
|
|
|
|
|
export CGO_ENABLED=1
|
fix(build): prevent 32-bit startup crash (segfault/SIGILL) in downloads binaries (#5739)
* 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.
2026-07-09 06:30:44 -04:00
|
|
|
cat "$(go env GOENV)" 2>/dev/null || true
|
2024-10-15 16:46:01 -04:00
|
|
|
|
|
|
|
|
# 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
|
fix(build): prevent 32-bit startup crash (segfault/SIGILL) in downloads binaries (#5739)
* 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.
2026-07-09 06:30:44 -04:00
|
|
|
# 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
|
2024-10-15 16:46:01 -04:00
|
|
|
if [ "$(xx-info os)" = "windows" ]; then
|
|
|
|
|
export EXT=".exe"
|
|
|
|
|
fi
|
|
|
|
|
|
fix(build): prevent 32-bit startup crash (segfault/SIGILL) in downloads binaries (#5739)
* 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.
2026-07-09 06:30:44 -04:00
|
|
|
BUILD_TAGS=$(./release/build-tags.sh)
|
|
|
|
|
go build -tags="${BUILD_TAGS}" -ldflags="${LD_EXTRA} -w -s \
|
2024-10-15 16:46:01 -04:00
|
|
|
-X github.com/navidrome/navidrome/consts.gitSha=${GIT_SHA} \
|
|
|
|
|
-X github.com/navidrome/navidrome/consts.gitTag=${GIT_TAG}" \
|
|
|
|
|
-o /out/navidrome${EXT} .
|
fix(build): prevent 32-bit startup crash (segfault/SIGILL) in downloads binaries (#5739)
* 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.
2026-07-09 06:30:44 -04:00
|
|
|
# Fail the build if native libwebp (purego) leaked into a 32-bit binary (issue #5738).
|
|
|
|
|
./release/verify-binary.sh /out/navidrome*
|
2024-10-15 16:46:01 -04:00
|
|
|
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 /
|
|
|
|
|
|
2026-08-30 14:25:36 -04:00
|
|
|
########################################################################################################################
|
|
|
|
|
### Build no-op stubs for mpv's video-output libraries
|
|
|
|
|
# mpv links libEGL/libgbm for video output only; Navidrome drives it headless, for audio.
|
|
|
|
|
# Real mesa pulls in LLVM + gallium (+218MB uncompressed), so ship stubs it never calls.
|
|
|
|
|
FROM --platform=$BUILDPLATFORM alpine:3.22 AS mpv-stubs
|
|
|
|
|
COPY --from=xx / /
|
|
|
|
|
RUN apk add --no-cache clang lld binutils mesa-egl mesa-gbm
|
|
|
|
|
ARG TARGETPLATFORM
|
|
|
|
|
RUN xx-apk add --no-cache musl-dev
|
|
|
|
|
RUN <<EOT
|
|
|
|
|
set -e
|
|
|
|
|
mkdir -p /out
|
|
|
|
|
for so in libEGL.so.1 libgbm.so.1; do
|
|
|
|
|
readelf -sW /usr/lib/$so \
|
|
|
|
|
| awk '$5 == "GLOBAL" && $7 != "UND" { print $8 }' \
|
|
|
|
|
| sed 's/@.*//' \
|
|
|
|
|
| grep -vE '^(_init|_fini|_edata|_end|__bss_start|_GLOBAL_OFFSET_TABLE_)$' \
|
|
|
|
|
| sort -u \
|
|
|
|
|
| awk '{ print "void " $1 "(void) {}" }' > /tmp/stub.c
|
|
|
|
|
test -s /tmp/stub.c
|
|
|
|
|
xx-clang -shared -nostdlib -fPIC -Wl,-soname,$so -o /out/$so /tmp/stub.c
|
|
|
|
|
xx-verify /out/$so
|
|
|
|
|
done
|
|
|
|
|
EOT
|
|
|
|
|
|
2024-10-15 16:46:01 -04:00
|
|
|
########################################################################################################################
|
|
|
|
|
### Build Final Image
|
2026-08-30 14:25:36 -04:00
|
|
|
FROM alpine:3.22 AS final
|
2024-10-15 16:46:01 -04:00
|
|
|
LABEL maintainer="deluan@navidrome.org"
|
2024-12-19 22:56:33 +01:00
|
|
|
LABEL org.opencontainers.image.source="https://github.com/navidrome/navidrome"
|
2024-10-15 16:46:01 -04:00
|
|
|
|
feat(artwork): enable native libwebp encoding in Docker image (#5350)
* feat(docker): add musl build stage for native libwebp support
Add a new build-alpine stage using Alpine/musl with xx cross-compilation,
producing a dynamically-linked musl binary for the Docker image. The
runtime image now installs libwebp, libwebpdemux, and libwebpmux and
creates .so symlinks so gen2brain/webp can detect native libwebp via
purego/dlopen at startup and use it automatically.
The existing Debian/glibc 'build' stage is kept for standalone binary
distribution (darwin, windows, and glibc linux binaries); the Docker
image now ships the musl build from build-alpine instead.
* fix(docker): use dynamic symlinks for libwebp libraries
Avoid hardcoding SONAME versions (.so.7, .so.2, .so.3) which break
on Alpine version bumps. Also fix misleading comment: the musl build
is dynamic (required for purego dlopen), not static.
* feat(docker): enable WebP encoding in Docker environment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(docker): pin build-alpine stage to Go 1.25 to match base stage
Align the new build-alpine stage with the existing glibc 'base' stage,
both pinned to Go 1.25. Bumping build-alpine independently would create
a version skew between the Docker image binary and the standalone
binaries, which should be avoided unless there is a specific reason.
* fix(docker): harden build-alpine stage (musl pin, -latomic, dynamic-link check)
Address review feedback on the build-alpine stage:
- Pin Go builder to golang:1.25-alpine3.20 so the musl version used at
build time matches the alpine:3.20 runtime image, eliminating any
potential musl ABI skew between builder and runtime.
- Add -extldflags '-latomic' so SQLite's 64-bit atomics resolve when
cross-compiling for 32-bit arm targets (arm/v6, arm/v7).
- Add a build-time check that the produced binary is dynamically
linked (using 'file' from Alpine), failing the build if it is not.
A fully-static binary cannot dlopen libwebp and would silently fall
back to the WASM encoder, defeating the whole point of this stage.
* fix(docker): revert to unpinned golang:1.25-alpine builder
The golang:1.25-alpine3.20 tag suggested during review does not exist on
public.ecr.aws (only 3.21, 3.22, 3.23, and unpinned 'alpine' are
published). Revert to the unpinned 'golang:1.25-alpine' tag so the
Docker build can resolve the base image.
This means the builder's Alpine version can drift relative to the
alpine:3.20 runtime, but in practice musl's backward compatibility
covers this for Navidrome's small dlopen surface (a few libwebp
symbols, no direct libc calls from the dlopen path). If a skew ever
manifests, we can pin both builder and runtime to the same specific
Alpine release in a follow-up.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-04-13 13:30:05 -04:00
|
|
|
# Install runtime dependencies
|
|
|
|
|
# - libwebp + symlinks: enables native WebP encoding via purego/dlopen
|
2026-08-30 14:25:36 -04:00
|
|
|
# The mesa/LLVM stack mpv pulls in for video output is dropped in this same layer,
|
|
|
|
|
# otherwise the deleted bytes still ship in the image.
|
2026-09-09 16:38:59 +01:00
|
|
|
RUN apk add -U --no-cache curl ffmpeg mpv sqlite libwebp libwebpdemux libwebpmux && \
|
feat(artwork): enable native libwebp encoding in Docker image (#5350)
* feat(docker): add musl build stage for native libwebp support
Add a new build-alpine stage using Alpine/musl with xx cross-compilation,
producing a dynamically-linked musl binary for the Docker image. The
runtime image now installs libwebp, libwebpdemux, and libwebpmux and
creates .so symlinks so gen2brain/webp can detect native libwebp via
purego/dlopen at startup and use it automatically.
The existing Debian/glibc 'build' stage is kept for standalone binary
distribution (darwin, windows, and glibc linux binaries); the Docker
image now ships the musl build from build-alpine instead.
* fix(docker): use dynamic symlinks for libwebp libraries
Avoid hardcoding SONAME versions (.so.7, .so.2, .so.3) which break
on Alpine version bumps. Also fix misleading comment: the musl build
is dynamic (required for purego dlopen), not static.
* feat(docker): enable WebP encoding in Docker environment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(docker): pin build-alpine stage to Go 1.25 to match base stage
Align the new build-alpine stage with the existing glibc 'base' stage,
both pinned to Go 1.25. Bumping build-alpine independently would create
a version skew between the Docker image binary and the standalone
binaries, which should be avoided unless there is a specific reason.
* fix(docker): harden build-alpine stage (musl pin, -latomic, dynamic-link check)
Address review feedback on the build-alpine stage:
- Pin Go builder to golang:1.25-alpine3.20 so the musl version used at
build time matches the alpine:3.20 runtime image, eliminating any
potential musl ABI skew between builder and runtime.
- Add -extldflags '-latomic' so SQLite's 64-bit atomics resolve when
cross-compiling for 32-bit arm targets (arm/v6, arm/v7).
- Add a build-time check that the produced binary is dynamically
linked (using 'file' from Alpine), failing the build if it is not.
A fully-static binary cannot dlopen libwebp and would silently fall
back to the WASM encoder, defeating the whole point of this stage.
* fix(docker): revert to unpinned golang:1.25-alpine builder
The golang:1.25-alpine3.20 tag suggested during review does not exist on
public.ecr.aws (only 3.21, 3.22, 3.23, and unpinned 'alpine' are
published). Revert to the unpinned 'golang:1.25-alpine' tag so the
Docker build can resolve the base image.
This means the builder's Alpine version can drift relative to the
alpine:3.20 runtime, but in practice musl's backward compatibility
covers this for Navidrome's small dlopen surface (a few libwebp
symbols, no direct libc calls from the dlopen path). If a skew ever
manifests, we can pin both builder and runtime to the same specific
Alpine release in a follow-up.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-04-13 13:30:05 -04:00
|
|
|
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; \
|
2026-08-30 14:25:36 -04:00
|
|
|
done && \
|
|
|
|
|
rm -rf /usr/lib/gallium-pipe /usr/lib/dri \
|
|
|
|
|
/usr/lib/libEGL.so* /usr/lib/libgbm.so* /usr/lib/libgallium*.so /usr/lib/libLLVM.so* \
|
|
|
|
|
/usr/lib/libGL.so* /usr/lib/libGLESv2.so* /usr/lib/libglapi.so*
|
|
|
|
|
|
|
|
|
|
COPY --from=mpv-stubs /out/ /usr/lib/
|
|
|
|
|
RUN mpv --no-video --ao=null --version > /dev/null
|
2024-10-15 16:46:01 -04:00
|
|
|
|
feat(artwork): enable native libwebp encoding in Docker image (#5350)
* feat(docker): add musl build stage for native libwebp support
Add a new build-alpine stage using Alpine/musl with xx cross-compilation,
producing a dynamically-linked musl binary for the Docker image. The
runtime image now installs libwebp, libwebpdemux, and libwebpmux and
creates .so symlinks so gen2brain/webp can detect native libwebp via
purego/dlopen at startup and use it automatically.
The existing Debian/glibc 'build' stage is kept for standalone binary
distribution (darwin, windows, and glibc linux binaries); the Docker
image now ships the musl build from build-alpine instead.
* fix(docker): use dynamic symlinks for libwebp libraries
Avoid hardcoding SONAME versions (.so.7, .so.2, .so.3) which break
on Alpine version bumps. Also fix misleading comment: the musl build
is dynamic (required for purego dlopen), not static.
* feat(docker): enable WebP encoding in Docker environment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(docker): pin build-alpine stage to Go 1.25 to match base stage
Align the new build-alpine stage with the existing glibc 'base' stage,
both pinned to Go 1.25. Bumping build-alpine independently would create
a version skew between the Docker image binary and the standalone
binaries, which should be avoided unless there is a specific reason.
* fix(docker): harden build-alpine stage (musl pin, -latomic, dynamic-link check)
Address review feedback on the build-alpine stage:
- Pin Go builder to golang:1.25-alpine3.20 so the musl version used at
build time matches the alpine:3.20 runtime image, eliminating any
potential musl ABI skew between builder and runtime.
- Add -extldflags '-latomic' so SQLite's 64-bit atomics resolve when
cross-compiling for 32-bit arm targets (arm/v6, arm/v7).
- Add a build-time check that the produced binary is dynamically
linked (using 'file' from Alpine), failing the build if it is not.
A fully-static binary cannot dlopen libwebp and would silently fall
back to the WASM encoder, defeating the whole point of this stage.
* fix(docker): revert to unpinned golang:1.25-alpine builder
The golang:1.25-alpine3.20 tag suggested during review does not exist on
public.ecr.aws (only 3.21, 3.22, 3.23, and unpinned 'alpine' are
published). Revert to the unpinned 'golang:1.25-alpine' tag so the
Docker build can resolve the base image.
This means the builder's Alpine version can drift relative to the
alpine:3.20 runtime, but in practice musl's backward compatibility
covers this for Navidrome's small dlopen surface (a few libwebp
symbols, no direct libc calls from the dlopen path). If a skew ever
manifests, we can pin both builder and runtime to the same specific
Alpine release in a follow-up.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-04-13 13:30:05 -04:00
|
|
|
# Copy navidrome binary (musl build for Docker, enables native libwebp)
|
|
|
|
|
COPY --from=build-alpine /out/navidrome /app/
|
2024-10-15 16:46:01 -04:00
|
|
|
|
|
|
|
|
VOLUME ["/data", "/music"]
|
|
|
|
|
ENV ND_MUSICFOLDER=/music
|
|
|
|
|
ENV ND_DATAFOLDER=/data
|
2025-03-22 17:33:56 -04:00
|
|
|
ENV ND_CONFIGFILE=/data/navidrome.toml
|
2024-10-15 16:46:01 -04:00
|
|
|
ENV ND_PORT=4533
|
2024-12-19 17:54:19 -05:00
|
|
|
RUN touch /.nddockerenv
|
2024-10-15 16:46:01 -04:00
|
|
|
|
|
|
|
|
EXPOSE ${ND_PORT}
|
|
|
|
|
WORKDIR /app
|
2026-04-30 16:55:10 -04:00
|
|
|
ENV PATH="/app:${PATH}"
|
2024-10-15 16:46:01 -04:00
|
|
|
|
|
|
|
|
ENTRYPOINT ["/app/navidrome"]
|
|
|
|
|
|