#!/usr/bin/env bash # Cross-compiles the service inside a container, for hosts that cannot run the # NDK directly. The openlgtv buildroot SDK is a Linux toolchain, so on macOS or # Windows this is the only way to build the native part. # # ./tools/docker-build.sh # build the service into build/native/ # ./tools/docker-build.sh shell # a prompt inside the SDK, for poking about # ./tools/docker-build.sh clean # drop the image # # The SDK is baked into an image, so it is downloaded once (~350 MB) and every # build after the first starts instantly. There are aarch64 and x86_64 builds # of the SDK and the image picks the one matching the container, so this runs # natively on Apple Silicon rather than under emulation. # # NDK_RELEASE pins the SDK release; DOCKER is podman if you prefer. set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" DOCKER="${DOCKER:-docker}" NDK_RELEASE="${NDK_RELEASE:-webos-a38c582}" IMAGE="${IMAGE:-lgtv-audiocap-sdk:$NDK_RELEASE}" SDK=/opt/webos-sdk TOOLCHAIN="$SDK/share/buildroot/toolchainfile.cmake" BUILD_DIR=build/native say() { printf '%s\n' "$*"; } step() { printf '\n== %s\n' "$*"; } die() { printf 'error: %s\n' "$*" >&2; exit 1; } command -v "$DOCKER" >/dev/null 2>&1 || die "$DOCKER is not installed" build_image() { if "$DOCKER" image inspect "$IMAGE" >/dev/null 2>&1; then return fi step "Building the SDK image (once, ~350 MB download)" # The arch is resolved inside the build so the image is right for whatever # the daemon runs, without the caller having to know. "$DOCKER" build --tag "$IMAGE" - <&2; exit 1 ;; \\ esac \\ && mkdir -p $SDK \\ && curl -fL "https://github.com/openlgtv/buildroot-nc4/releases/download/$NDK_RELEASE/arm-webos-linux-gnueabi_sdk-buildroot-\$arch.tar.gz" \\ | tar xz -C $SDK --strip-components=1 \\ && $SDK/relocate-sdk.sh EOF } # --user keeps build/ owned by the caller instead of root. HOME has to point # somewhere writable or cmake complains about its package registry. run() { "$DOCKER" run --rm \ --volume "$ROOT:/src" \ --workdir /src \ --user "$(id -u):$(id -g)" \ --env HOME=/tmp \ "$@" } compile() { build_image # A cache from a differently placed toolchain cannot be reused. if [ -f "$BUILD_DIR/CMakeCache.txt" ] \ && ! grep -q "CMAKE_TOOLCHAIN_FILE:.*=$TOOLCHAIN" "$BUILD_DIR/CMakeCache.txt"; then say "discarding a cmake cache from a different toolchain" rm -rf "$BUILD_DIR" fi step "Cross-compiling the service" run --interactive=false "$IMAGE" sh -c " set -e cmake -S native -B $BUILD_DIR \ -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN \ -DCMAKE_BUILD_TYPE=Release cmake --build $BUILD_DIR --parallel file $BUILD_DIR/audiocap-service " [ -f "$BUILD_DIR/audiocap-service" ] || die "the build produced no binary" say "" say "built $BUILD_DIR/audiocap-service" say "now: ./tools/build.sh package" } case "${1:-build}" in build) compile ;; shell) build_image step "A shell in the SDK image; the toolchain is at $SDK" run --interactive --tty "$IMAGE" bash ;; clean) "$DOCKER" image rm "$IMAGE" 2>/dev/null && say "removed $IMAGE" || say "no image to remove" ;; -h|--help) awk 'NR == 1 { next } /^#/ { sub(/^# ?/, ""); print; next } { exit }' "$0" ;; *) die "unknown command '$1' (try --help)" ;; esac