Skip to content

Ubuntu 20.04 Focal build with TagLib 2.2 (Qt 6 from artifact) #10

Ubuntu 20.04 Focal build with TagLib 2.2 (Qt 6 from artifact)

Ubuntu 20.04 Focal build with TagLib 2.2 (Qt 6 from artifact) #10

# yaml-language-server: $schema=https://json.schemastore.org/github-workflow
name: Ubuntu 20.04 Focal build with TagLib 2.2 / 1.11 (Qt 6 from artifact)
# Manual trigger, and automatic on pushes to the mkv/webm taglib-2.2 test branch.
on:
workflow_dispatch:
push:
branches:
- mkv-webm-taglib22-ci
permissions:
contents: read
actions: read
env:
QT_VERSION: 6.10.3
QT_PREFIX: /opt/qt/6.10.3
jobs:
build:
name: Ubuntu 20.04 (Focal) compile against TagLib ${{ matrix.taglib_version }}
strategy:
fail-fast: false
matrix:
include:
- taglib_version: "2.2"
taglib_prefix: /opt/taglib/2.2
taglib_pkgconfig: /opt/taglib/2.2/lib/pkgconfig
build_taglib_from_source: true
artifact_tag: taglib22
- taglib_version: "1.11"
taglib_prefix: /usr
taglib_pkgconfig: /usr/local/lib/pkgconfig:/usr/lib/x86_64-linux-gnu/pkgconfig
build_taglib_from_source: false
artifact_tag: taglib111
runs-on: ubuntu-24.04
container: ubuntu:20.04
env:
DEBIAN_FRONTEND: noninteractive
TZ: Etc/UTC
CMAKE_VERSION: 3.31.8
TAGLIB_VERSION: ${{ matrix.taglib_version }}
TAGLIB_PREFIX: ${{ matrix.taglib_prefix }}
steps:
- name: Check out repository
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Prepare Focal build environment
shell: bash
run: |
set -o pipefail
mkdir -p logs build
{
echo '=== OS ==='
cat /etc/os-release
echo
echo '=== Kernel ==='
uname -a
echo
echo '=== CPU ==='
nproc
echo
echo '=== APT sources ==='
grep -RhsE '^[[:space:]]*deb([[:space:]]|$)' /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null || true
} | tee logs/00-environment.log
apt-get update 2>&1 | tee logs/01-apt-update.log
apt-get install -y --no-install-recommends \
bash ca-certificates git wget curl xz-utils file pkg-config unzip \
ninja-build build-essential python3 python3-pip sudo gdb \
zlib1g-dev \
2>&1 | tee logs/02-base-packages.log
- name: Install CMake
shell: bash
run: |
set -o pipefail
wget -qO- "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz" \
| tar -xz -C /opt
ln -sf "/opt/cmake-${CMAKE_VERSION}-linux-x86_64/bin/cmake" /usr/local/bin/cmake
ln -sf "/opt/cmake-${CMAKE_VERSION}-linux-x86_64/bin/ctest" /usr/local/bin/ctest
cmake --version 2>&1 | tee logs/03-cmake-version.log
- name: Install Mixxx build dependencies (Focal-compatible, no Qt)
shell: bash
run: |
set -o pipefail
export DEBIAN_FRONTEND=noninteractive
cp tools/debian_buildenv.sh /tmp/debian_buildenv-focal.sh
apt-get install -y --no-install-recommends software-properties-common 2>&1 | tee logs/04-ppatools.log
add-apt-repository -y ppa:ubuntu-toolchain-r/test 2>&1 | tee logs/04-ppa.log
apt-get update 2>&1 | tee logs/04-ppa-update.log
apt-get install -y --no-install-recommends gcc-12 g++-12 2>&1 | tee logs/04-focal-toolchain.log
apt-get install -y --no-install-recommends libxkbcommon-dev libxkbcommon-x11-dev 2>&1 | tee logs/04-xkbcommon.log
apt-get install -y --no-install-recommends libdbus-1-3 2>&1 | tee logs/04-dbus.log
sed -i \
-e '/libpipewire-0.3-dev/d' \
-e '/libspa-0.2-dev/d' \
-e '/libqt6/d' \
-e '/^ *qt6-/d' \
-e '/^ *qtkeychain-qt6-dev/d' \
-e '/^ *qml6-/d' \
-e '/qt6-shadertools-dev/d' \
-e '/qt6-5compat-dev/d' \
-e 's/sudo apt-get/apt-get/g' \
/tmp/debian_buildenv-focal.sh
chmod +x /tmp/debian_buildenv-focal.sh
/tmp/debian_buildenv-focal.sh setup 2>&1 | tee logs/04-mixxx-buildenv.log
# Focal ships TagLib 1.11.1 (libtag1-dev), which has no Matroska
# support. The 2.2 leg overrides it by putting /opt/taglib/2.2 first
# in PKG_CONFIG_PATH; the 1.11 leg uses the system package and thus
# exercises the FFmpeg metadata fallback path.
# The 1.11 leg's PKG_CONFIG_PATH puts /usr/local/lib/pkgconfig first
# so the freshly built hidapi 0.14.0 .pc wins over the apt one
# (0.9.0) that /usr/lib/x86_64-linux-gnu/pkgconfig would otherwise
# shadow; /usr/local has no taglib.pc, so system TagLib 1.11 still
# resolves from the second entry.
- name: Build hidapi 0.14.0 (Focal ships 0.9.0)
shell: bash
run: |
set -o pipefail
wget -q "https://github.com/libusb/hidapi/archive/refs/tags/hidapi-0.14.0.tar.gz" -O /tmp/hidapi.tar.gz
tar -xzf /tmp/hidapi.tar.gz -C /tmp
cmake -S /tmp/hidapi-hidapi-0.14.0 -B /tmp/hidapi-build \
-DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DHIDAPI_BUILD_HIDTEST=OFF \
2>&1 | tee logs/05-hidapi-configure.log
cmake --build /tmp/hidapi-build -j"$(nproc)" 2>&1 | tee logs/05-hidapi-build.log
cmake --install /tmp/hidapi-build 2>&1 | tee logs/05-hidapi-install.log
ldconfig
nm -D /usr/local/lib/libhidapi-hidraw.so.0 | grep -q ' hid_get_report_descriptor$'
- name: Build TagLib ${TAGLIB_VERSION} from source (native Matroska/WebM)
if: matrix.build_taglib_from_source
shell: bash
run: |
set -o pipefail
wget -q "https://github.com/taglib/taglib/releases/download/v${TAGLIB_VERSION}/taglib-${TAGLIB_VERSION}.tar.gz" -O /tmp/taglib.tar.gz
tar -xzf /tmp/taglib.tar.gz -C /tmp
cmake -S "/tmp/taglib-${TAGLIB_VERSION}" -B /tmp/taglib-build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="${TAGLIB_PREFIX}" \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BINDINGS=OFF \
2>&1 | tee logs/06-taglib-configure.log
cmake --build /tmp/taglib-build -j"$(nproc)" 2>&1 | tee logs/06-taglib-build.log
cmake --install /tmp/taglib-build 2>&1 | tee logs/06-taglib-install.log
ldconfig
echo '=== TagLib version + Matroska module ==='
PKG_CONFIG_PATH="${TAGLIB_PREFIX}/lib/pkgconfig" pkg-config --modversion taglib
test -f "${TAGLIB_PREFIX}/include/taglib/matroskafile.h" && echo "matroskafile.h present"
grep -E 'TAGLIB_(MAJOR|MINOR|PATCH)_VERSION' "${TAGLIB_PREFIX}/include/taglib/taglib.h"
grep -q 'TAGLIB_WITH_MATROSKA 1' "${TAGLIB_PREFIX}/include/taglib/taglib_config.h" && echo "TAGLIB_WITH_MATROSKA=1"
- name: Find Qt artifact build
id: find-qt
uses: actions/github-script@v9
with:
script: |
const { data } = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'qt6-focal.yml',
status: 'success',
per_page: 1,
});
if (data.total_count === 0) {
core.setFailed('No successful qt6-focal.yml run found; run that workflow first.');
}
const run = data.workflow_runs[0];
core.setOutput('run_id', String(run.id));
console.log(`Using Qt build run ${run.id}`);
- name: Download Qt artifact
id: download-qt
uses: actions/github-script@v9
env:
RUN_ID: ${{ steps.find-qt.outputs.run_id }}
with:
script: |
const fs = require('fs');
const dir = '/tmp/qt-artifact';
fs.mkdirSync(dir, { recursive: true });
const artifactName = `qt-${process.env.QT_VERSION}-ubuntu20.04`;
const { data: list } = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: Number(process.env.RUN_ID),
});
const artifact = list.artifacts.find(a => a.name === artifactName);
if (!artifact) {
core.setFailed(`Artifact ${artifactName} not found on run ${process.env.RUN_ID}`);
return;
}
const { data } = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: 'zip',
});
fs.writeFileSync(`${dir}/qt.zip`, Buffer.from(data));
console.log(`Downloaded ${artifactName} (${artifact.size_in_bytes} bytes) from run ${process.env.RUN_ID}`);
- name: Install Qt artifact
shell: bash
run: |
set -o pipefail
cd /tmp/qt-artifact
unzip -o qt.zip
expected=$(awk '{print $1}' "qt-${QT_VERSION}-ubuntu20.04.tar.xz.sha256")
actual=$(sha256sum "qt-${QT_VERSION}-ubuntu20.04.tar.xz" | awk '{print $1}')
echo "expected: ${expected}"
echo "actual: ${actual}"
test "${expected}" = "${actual}" || { echo "Qt artifact checksum mismatch" >&2; exit 1; }
mkdir -p /opt/qt
tar -C /opt/qt -xJf "qt-${QT_VERSION}-ubuntu20.04.tar.xz" 2>&1 | tee "${GITHUB_WORKSPACE}/logs/05-qt-install.log"
"${QT_PREFIX}/bin/qmake" --version 2>&1 | tee -a "${GITHUB_WORKSPACE}/logs/05-qt-install.log"
- name: Configure (Release, against TagLib ${TAGLIB_VERSION})
shell: bash
env:
CMAKE_PREFIX_PATH: /opt/qt/6.10.3:/usr/local:${{ env.TAGLIB_PREFIX }}
PKG_CONFIG_PATH: ${{ matrix.taglib_pkgconfig }}
LD_LIBRARY_PATH: /opt/qt/6.10.3/lib:/usr/local/lib:${{ env.TAGLIB_PREFIX }}/lib
CC: gcc-12
CXX: g++-12
run: |
set -o pipefail
export PATH=/opt/qt/6.10.3/bin:$PATH
cmake \
-S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DQT6=ON \
-DQML=ON \
-DBULK=ON \
-DFFMPEG=ON \
-DLOCALECOMPARE=ON \
-DMAD=ON \
-DMODPLUG=ON \
-DWAVPACK=ON \
-DBUILD_BENCH=OFF \
-DQTKEYCHAIN=OFF \
-DINSTALL_USER_UDEV_RULES=OFF \
2>&1 | tee logs/07-cmake-configure.log
echo '=== TagLib resolved by Mixxx ==='
grep -iE 'TagLib' build/CMakeCache.txt || true
grep -E 'Found TagLib|suitable version' logs/07-cmake-configure.log || true
- name: Build (Release)
shell: bash
env:
CMAKE_PREFIX_PATH: /opt/qt/6.10.3:/usr/local:${{ env.TAGLIB_PREFIX }}
PKG_CONFIG_PATH: ${{ matrix.taglib_pkgconfig }}
LD_LIBRARY_PATH: /opt/qt/6.10.3/lib:/usr/local/lib:${{ env.TAGLIB_PREFIX }}/lib
CC: gcc-12
CXX: g++-12
run: |
set -o pipefail
export PATH=/opt/qt/6.10.3/bin:$PATH
cmake --build build -j"$(nproc)" 2>&1 | tee logs/08-cmake-build.log
- name: Verify linked TagLib version
shell: bash
run: |
set -o pipefail
lib=$(ldd build/mixxx 2>/dev/null | awk '/libtag\.so/{print $3}' | head -1)
lib_real=$(realpath -e "${lib}" 2>/dev/null || echo "${lib}")
echo "libtag resolved to: ${lib} (canonical: ${lib_real})"
ldd build/mixxx 2>&1 | grep -i 'libtag' | tee logs/09-taglib-linkage.log
case "${lib_real}" in
${TAGLIB_PREFIX}/*)
echo "OK: mixxx links TagLib ${TAGLIB_VERSION} from ${TAGLIB_PREFIX}"
;;
*)
echo "FAIL: libtag is not from ${TAGLIB_PREFIX} (resolved: ${lib_real})" >&2
exit 1
;;
esac
- name: Install Mixxx runtime tree
shell: bash
env:
CMAKE_PREFIX_PATH: /opt/qt/6.10.3:/usr/local:${{ env.TAGLIB_PREFIX }}
PKG_CONFIG_PATH: ${{ matrix.taglib_pkgconfig }}
LD_LIBRARY_PATH: /opt/qt/6.10.3/lib:/usr/local/lib:${{ env.TAGLIB_PREFIX }}/lib
CC: gcc-12
CXX: g++-12
run: |
set -o pipefail
export PATH=/opt/qt/6.10.3/bin:$PATH
rm -rf "/opt/mixxx-${{ matrix.artifact_tag }}"
cmake --install build --prefix "/opt/mixxx-${{ matrix.artifact_tag }}" \
2>&1 | tee logs/10-cmake-install.log
echo '=== Installed runtime tree ==='
find "/opt/mixxx-${{ matrix.artifact_tag }}" -type f -printf '%P\n' \
| sort | tee logs/10-install-tree.log
- name: Package Mixxx runtime (TagLib ${TAGLIB_VERSION})
shell: bash
run: |
set -o pipefail
tar czf "/tmp/mixxx-${{ matrix.artifact_tag }}-runtime.tar.gz" -C "/opt/mixxx-${{ matrix.artifact_tag }}" .
ls -lh "/tmp/mixxx-${{ matrix.artifact_tag }}-runtime.tar.gz"
- name: Upload Mixxx runtime artifact
uses: actions/upload-artifact@v4
with:
name: mixxx-${{ matrix.artifact_tag }}-runtime-${{ github.run_number }}
path: /tmp/mixxx-${{ matrix.artifact_tag }}-runtime.tar.gz
if-no-files-found: error
- name: Collect diagnostics
if: always()
shell: bash
run: |
set -o pipefail
{
echo '=== Git status ==='
git status --short 2>/dev/null || true
echo
echo '=== CMake cache ==='
grep -E '^(CMAKE_(BUILD_TYPE|CXX_COMPILER|C_COMPILER):|QT6:|FFMPEG:|TagLib|PC_TagLib)' build/CMakeCache.txt 2>/dev/null || true
echo
echo '=== Version strings ==='
grep -E 'MIXXX_VERSION|VERSION_PRERELEASE' CMakeLists.txt | head -5
echo
echo '=== TagLib install ==='
ls -la "${TAGLIB_PREFIX}/lib/" 2>/dev/null | grep -i 'libtag' || true
ls "${TAGLIB_PREFIX}/include/taglib/" 2>/dev/null | grep -i matroska || true
} | tee logs/99-diagnostics.log
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ubuntu-20.04-qt6-taglib22-build-${{ matrix.artifact_tag }}-${{ github.run_number }}
path: logs/
if-no-files-found: warn
retention-days: 14