Commit 553daa9e authored by jan.koester's avatar jan.koester
Browse files

test

parent ad3fe73f
Loading
Loading
Loading
Loading
+21 −6
Original line number Diff line number Diff line
@@ -3,12 +3,27 @@ Section: web
Priority: optional
Maintainer: Jan Koester <jan.koester@tuxist.de>
Build-Depends: debhelper-compat (= 13), cmake (>= 3.18),
 libhttppp-dev, libnetplus-dev, libjson-c-dev, libparitypp-dev,
 libuuidplus-dev, libauthorize-dev, libconfplus-dev, libcmdplus-dev,
 libdbpp-dev, libbrotli-dev, libtinyxml2-dev, libsmtpclient-dev,
 libhtmlpp-dev, libgameinfoplus-dev, pkg-config,
 qt6-base-dev, qt6-declarative-dev, qt6-webengine-dev,
 qml6-module-qtquick-controls, qml6-module-qtquick-layouts
 ninja-build,
 libhttppp-dev <!profile.nspawn>,
 libnetplus-dev <!profile.nspawn>,
 libjson-c-dev,
 libparitypp-dev <!profile.nspawn>,
 libuuidplus-dev <!profile.nspawn>,
 libauthorize-dev <!profile.nspawn>,
 libconfplus-dev <!profile.nspawn>,
 libcmdplus-dev <!profile.nspawn>,
 libdbpp-dev <!profile.nspawn>,
 libbrotli-dev,
 libtinyxml2-dev,
 libsmtpclient-dev <!profile.nspawn>,
 libhtmlpp-dev <!profile.nspawn>,
 libgameinfoplus-dev <!profile.nspawn>,
 pkg-config,
 qt6-base-dev <!profile.nspawn>,
 qt6-declarative-dev <!profile.nspawn>,
 qt6-webengine-dev <!profile.nspawn>,
 qml6-module-qtquick-controls <!profile.nspawn>,
 qml6-module-qtquick-layouts <!profile.nspawn>
Standards-Version: 4.6.2
Rules-Requires-Root: no

+19 −0
Original line number Diff line number Diff line
@@ -5,12 +5,31 @@ export DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
%:
	dh $@ --buildsystem=cmake

TOOLCHAIN_FILE = /usr/local/musl/share/musl-llvm-toolchain.cmake
IS_NSPAWN = $(filter nspawn,$(DEB_BUILD_PROFILES))

override_dh_auto_configure:
ifneq ($(IS_NSPAWN),)
	dh_auto_configure -- \
		-DCMAKE_TOOLCHAIN_FILE=$(TOOLCHAIN_FILE) \
		-DCMAKE_INSTALL_PREFIX=/usr \
		-DCMAKE_INSTALL_LIBDIR=lib/$(DEB_HOST_MULTIARCH) \
		-DCMAKE_BUILD_TYPE=Release \
		-DBUILD_EDITOR=OFF
else
	dh_auto_configure -- \
		-DCMAKE_INSTALL_PREFIX=/usr \
		-DCMAKE_INSTALL_LIBDIR=lib/$(DEB_HOST_MULTIARCH) \
		-DCMAKE_BUILD_TYPE=Release \
		-DBUILD_EDITOR=ON
endif

override_dh_shlibdeps:
ifneq ($(IS_NSPAWN),)
	dh_shlibdeps -- --ignore-missing-info
else
	dh_shlibdeps
endif

override_dh_install:
	dh_install
+325 −0
Original line number Diff line number Diff line
#!/bin/bash
#
# build-nspawn.sh — Build blogi .deb package using systemd-nspawn
# with a musl/LLVM/libc++/compiler-rt toolchain in a chroot.
#
# Usage: ./packaging/build-nspawn.sh [--clean] [--arch amd64]
#
# Requires: systemd-container, debootstrap, wget
#
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

# Configuration
ARCH="${ARCH:-amd64}"
CHROOT_BASE="/var/lib/blogi-buildroot"
CHROOT_DIR="$CHROOT_BASE/rootfs"
BUILD_DIR="/build"
OUTPUT_DIR="$PROJECT_DIR/packaging/output"
MUSL_VERSION="1.2.5"
LLVM_VERSION="18"

# Git repositories for custom libraries
GIT_BASE="https://git.tuxist.de/git"
declare -A LIBS=(
    [libcmdplus]="$GIT_BASE/jan.koester/libcmdplus.git"
    [uuidplus]="$GIT_BASE/tuxist/uuidplus.git"
    [libnetplus]="$GIT_BASE/jan.koester/libnetplus.git"
    [libhtmlpp]="$GIT_BASE/jan.koester/libhtmlpp.git"
    [libhttppp]="$GIT_BASE/jan.koester/libhttppp.git"
    [libconfplus]="$GIT_BASE/jan.koester/libconfplus.git"
    [libdbpp]="$GIT_BASE/jan.koester/libdbpp.git"
    [libgameinfoplus]="$GIT_BASE/jan.koester/libgameinfoplus.git"
    [libparitypp]="$GIT_BASE/tuxist/libparitypp.git"
    [authdb]="$GIT_BASE/tuxist/authdb.git"
    [mediadb]="$GIT_BASE/tuxist/mediadb.git"
    [smtpclient]="https://github.com/Tuxist/CPP-SMTPClient-library.git"
)

# Build order (dependency-sorted)
LIB_ORDER=(
    libcmdplus
    uuidplus
    libnetplus
    libhtmlpp
    libhttppp
    libconfplus
    libdbpp
    libgameinfoplus
    libparitypp
    authdb
    mediadb
    smtpclient
)

# Parse arguments
CLEAN=0
while [[ $# -gt 0 ]]; do
    case "$1" in
        --clean) CLEAN=1; shift ;;
        --arch) ARCH="$2"; shift 2 ;;
        *) echo "Unknown option: $1"; exit 1 ;;
    esac
done

if [[ $EUID -ne 0 ]]; then
    echo "This script must be run as root (for nspawn)."
    echo "Usage: sudo $0 [--clean]"
    exit 1
fi

# ─────────────────────────────────────────────────────────────
# Phase 1: Create minimal Debian chroot
# ─────────────────────────────────────────────────────────────
setup_chroot() {
    if [[ $CLEAN -eq 1 ]] && [[ -d "$CHROOT_DIR" ]]; then
        echo "==> Cleaning existing chroot..."
        rm -rf "$CHROOT_DIR"
    fi

    if [[ -d "$CHROOT_DIR/usr/bin" ]]; then
        echo "==> Chroot already exists, skipping bootstrap"
        return
    fi

    echo "==> Creating Debian chroot at $CHROOT_DIR ..."
    mkdir -p "$CHROOT_DIR"
    debootstrap --variant=minbase --arch="$ARCH" bookworm "$CHROOT_DIR" http://deb.debian.org/debian

    # Install minimal build dependencies in the chroot
    systemd-nspawn -D "$CHROOT_DIR" --pipe -- bash -c '
        apt-get update
        apt-get install -y --no-install-recommends \
            ca-certificates wget git cmake ninja-build pkg-config \
            libyaml-dev libjson-c-dev libbrotli-dev libtinyxml2-dev \
            libsqlite3-dev libpq-dev uuid-dev \
            xz-utils python3 file dpkg-dev fakeroot debhelper \
            libffmpeg-nvenc-dev ffmpeg
    '
}

# ─────────────────────────────────────────────────────────────
# Phase 2: Install LLVM toolchain + musl + libc++ + compiler-rt
# ─────────────────────────────────────────────────────────────
setup_toolchain() {
    if [[ -f "$CHROOT_DIR/usr/local/musl/bin/musl-clang" ]]; then
        echo "==> Toolchain already set up, skipping"
        return
    fi

    echo "==> Setting up LLVM ${LLVM_VERSION} + musl + libc++ toolchain..."

    systemd-nspawn -D "$CHROOT_DIR" --pipe -- bash -c "
        set -e

        # Install LLVM/Clang
        apt-get install -y --no-install-recommends \
            clang-${LLVM_VERSION} lld-${LLVM_VERSION} \
            llvm-${LLVM_VERSION}-dev \
            libc++-${LLVM_VERSION}-dev libc++abi-${LLVM_VERSION}-dev \
            libunwind-${LLVM_VERSION}-dev \
            compiler-rt-${LLVM_VERSION}

        # Set up symlinks
        update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 100
        update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_VERSION} 100
        update-alternatives --install /usr/bin/lld lld /usr/bin/lld-${LLVM_VERSION} 100
        update-alternatives --install /usr/bin/ld.lld ld.lld /usr/bin/ld.lld-${LLVM_VERSION} 100
        ln -sf /usr/bin/clang-${LLVM_VERSION} /usr/bin/cc
        ln -sf /usr/bin/clang++-${LLVM_VERSION} /usr/bin/c++

        # Build musl from source
        cd /tmp
        wget -q https://musl.libc.org/releases/musl-${MUSL_VERSION}.tar.gz
        tar xf musl-${MUSL_VERSION}.tar.gz
        cd musl-${MUSL_VERSION}
        CC=clang-${LLVM_VERSION} ./configure --prefix=/usr/local/musl --syslibdir=/usr/local/musl/lib
        make -j\$(nproc)
        make install

        # Create musl-clang wrapper that uses libc++ and compiler-rt
        cat > /usr/local/musl/bin/musl-clang++ << 'WRAPPER'
#!/bin/sh
exec clang++ \
    --target=x86_64-linux-musl \
    --sysroot=/usr/local/musl \
    -isystem /usr/local/musl/include \
    -isystem /usr/include/c++/v1 \
    -nostdinc++ \
    -stdlib=libc++ \
    -rtlib=compiler-rt \
    -fuse-ld=lld \
    -L/usr/local/musl/lib \
    -L/usr/lib/llvm-${LLVM_VERSION}/lib \
    -lc++abi \
    -lunwind \
    -static \
    \"\$@\"
WRAPPER
        chmod +x /usr/local/musl/bin/musl-clang++

        cat > /usr/local/musl/bin/musl-clang << 'WRAPPER'
#!/bin/sh
exec clang \
    --target=x86_64-linux-musl \
    --sysroot=/usr/local/musl \
    -isystem /usr/local/musl/include \
    -rtlib=compiler-rt \
    -fuse-ld=lld \
    -L/usr/local/musl/lib \
    -static \
    \"\$@\"
WRAPPER
        chmod +x /usr/local/musl/bin/musl-clang

        # Create CMake toolchain file
        mkdir -p /usr/local/musl/share
        cat > /usr/local/musl/share/musl-llvm-toolchain.cmake << 'CMAKE'
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x86_64)

set(CMAKE_C_COMPILER /usr/local/musl/bin/musl-clang)
set(CMAKE_CXX_COMPILER /usr/local/musl/bin/musl-clang++)

set(CMAKE_C_FLAGS_INIT \"-fPIC\")
set(CMAKE_CXX_FLAGS_INIT \"-fPIC -stdlib=libc++\")
set(CMAKE_EXE_LINKER_FLAGS_INIT \"-static -stdlib=libc++ -lc++abi -lunwind -rtlib=compiler-rt -fuse-ld=lld\")
set(CMAKE_SHARED_LINKER_FLAGS_INIT \"-stdlib=libc++ -lc++abi -lunwind -rtlib=compiler-rt -fuse-ld=lld\")

set(CMAKE_FIND_ROOT_PATH /usr/local/musl /usr/local)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
CMAKE

        echo '==> Toolchain setup complete'
    "
}

# ─────────────────────────────────────────────────────────────
# Phase 3: Build all dependency libraries
# ─────────────────────────────────────────────────────────────
build_libraries() {
    echo "==> Building dependency libraries inside nspawn..."

    # Bind-mount nothing yet, clone inside
    systemd-nspawn -D "$CHROOT_DIR" --pipe -- bash -c "
        set -e
        TOOLCHAIN=/usr/local/musl/share/musl-llvm-toolchain.cmake
        PREFIX=/usr/local

        mkdir -p /build/libs && cd /build/libs

        build_lib() {
            local name=\$1
            local url=\$2
            local extra_args=\${3:-}

            if [ -f /build/libs/.\${name}.done ]; then
                echo \"  [skip] \$name already built\"
                return
            fi

            echo \"  [build] \$name\"
            if [ ! -d \$name ]; then
                git clone --depth 1 \$url \$name
            fi
            mkdir -p \$name/build && cd \$name/build
            cmake .. -G Ninja \
                -DCMAKE_TOOLCHAIN_FILE=\$TOOLCHAIN \
                -DCMAKE_INSTALL_PREFIX=\$PREFIX \
                -DCMAKE_BUILD_TYPE=Release \
                -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
                \$extra_args
            ninja
            ninja install
            cd /build/libs
            touch .\${name}.done
        }

        build_lib libcmdplus '${LIBS[libcmdplus]}'
        build_lib uuidplus '${LIBS[uuidplus]}'
        build_lib libnetplus '${LIBS[libnetplus]}'
        build_lib libhtmlpp '${LIBS[libhtmlpp]}'
        build_lib libhttppp '${LIBS[libhttppp]}'
        build_lib libconfplus '${LIBS[libconfplus]}'
        build_lib libdbpp '${LIBS[libdbpp]}'
        build_lib libgameinfoplus '${LIBS[libgameinfoplus]}'
        build_lib libparitypp '${LIBS[libparitypp]}'
        build_lib authdb '${LIBS[authdb]}' '-DBUILD_BINDINGS=OFF'
        build_lib mediadb '${LIBS[mediadb]}'
        build_lib smtpclient '${LIBS[smtpclient]}' '-DCMAKE_INSTALL_LIBDIR=/usr/local/lib -DCMAKE_INSTALL_INCLUDEDIR=/usr/local/include'

        echo '==> All libraries built successfully'
    "
}

# ─────────────────────────────────────────────────────────────
# Phase 4: Build blogi and create .deb
# ─────────────────────────────────────────────────────────────
build_blogi() {
    echo "==> Building blogi package..."

    # Bind-mount the source tree read-only
    systemd-nspawn -D "$CHROOT_DIR" \
        --bind-ro="$PROJECT_DIR:$BUILD_DIR/blogi-src" \
        --pipe -- bash -c "
        set -e
        TOOLCHAIN=/usr/local/musl/share/musl-llvm-toolchain.cmake

        # Copy source (we don't modify the bind mount)
        rm -rf $BUILD_DIR/blogi
        cp -a $BUILD_DIR/blogi-src $BUILD_DIR/blogi
        cd $BUILD_DIR/blogi

        # Build
        mkdir -p build && cd build
        cmake .. -G Ninja \
            -DCMAKE_TOOLCHAIN_FILE=\$TOOLCHAIN \
            -DCMAKE_INSTALL_PREFIX=/usr \
            -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu \
            -DCMAKE_BUILD_TYPE=Release \
            -DBUILD_EDITOR=OFF
        ninja

        # Package via dpkg-buildpackage
        cd $BUILD_DIR/blogi
        dpkg-buildpackage -us -uc -b --build-profiles=nspawn

        # Collect .deb files
        mkdir -p $BUILD_DIR/output
        mv ../*.deb $BUILD_DIR/output/ 2>/dev/null || true
        mv ../*.changes $BUILD_DIR/output/ 2>/dev/null || true
        mv ../*.buildinfo $BUILD_DIR/output/ 2>/dev/null || true

        echo '==> Package build complete'
        ls -la $BUILD_DIR/output/
    "

    # Copy output to host
    mkdir -p "$OUTPUT_DIR"
    cp "$CHROOT_DIR/$BUILD_DIR/output/"*.deb "$OUTPUT_DIR/" 2>/dev/null || true
    cp "$CHROOT_DIR/$BUILD_DIR/output/"*.changes "$OUTPUT_DIR/" 2>/dev/null || true
    cp "$CHROOT_DIR/$BUILD_DIR/output/"*.buildinfo "$OUTPUT_DIR/" 2>/dev/null || true

    echo "==> Packages available in: $OUTPUT_DIR"
    ls -la "$OUTPUT_DIR/"
}

# ─────────────────────────────────────────────────────────────
# Main
# ─────────────────────────────────────────────────────────────
echo "╔══════════════════════════════════════════════════════════╗"
echo "║  blogi nspawn build — musl + LLVM libc++ + compiler-rt  ║"
echo "╚══════════════════════════════════════════════════════════╝"
echo ""

setup_chroot
setup_toolchain
build_libraries
build_blogi

echo ""
echo "==> Done. Packages in $OUTPUT_DIR"