Add Docker static-qt build support
ober
6f0467b64d16b118a7d50c26221cc9823fa9cd7a
new file mode 100644 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +.git +.bcache +build +**/build +**/target +test-artifacts +gui-snapshots.tar.gz +jerboa-browser +jerboa-browser-static-qt-linux-amd64.tar.gz +*.boot +*.so +*.wpo +jb-main.c +jb_*.h +.DS_Store --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ build/ # Native binary + Jerboa build artifacts (see build-binary.ss / Makefile) /jerboa-browser +jerboa-browser-static-qt-linux-amd64.tar.gz .bcache/ *.so *.wpo new file mode 100644 --- /dev/null +++ b/Dockerfile.qt @@ -0,0 +1,67 @@ +# Docker recipe for building the jerboa-browser Linux Qt artifact. +# +# This mirrors the jerboa-emacs static-qt workflow: build inside Docker, create a +# container, and copy the finished artifact from /out. Unlike jemacs-qt, this +# project uses Qt WebEngine, so the result is not a single fully static Qt +# executable. The tarball contains the native Jerboa browser binary plus the +# Qt WebEngine backend shared library and expects a system Qt 6 WebEngine +# runtime, matching packaging/linux/build-tarball.sh. +# +# Usage: +# docker build -f Dockerfile.qt -t jerboa-browser-qt-builder . +# id=$(docker create jerboa-browser-qt-builder) +# docker cp $id:/out/jerboa-browser-static-qt.tar.gz . && docker rm $id + +ARG JERBOA_IMAGE=jerboa21/jerboa +FROM ${JERBOA_IMAGE} AS builder + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + cmake \ + file \ + g++ \ + libgl1-mesa-dev \ + make \ + pkg-config \ + qt6-base-dev \ + qt6-webengine-dev \ + cargo \ + rustc \ + && rm -rf /var/lib/apt/lists/* + +RUN if ! command -v git >/dev/null 2>&1; then \ + apt-get update && apt-get install -y --no-install-recommends git && \ + rm -rf /var/lib/apt/lists/*; \ + fi && \ + if ! command -v jerbuild >/dev/null 2>&1; then \ + git clone --depth 1 https://git.sr.ht/~lisp/jerboa /tmp/jerboa && \ + cd /tmp/jerboa && \ + JERBOA_HOME=/tmp/jerboa SCHEME="$(command -v scheme)" sh support/build-jerbuild.sh && \ + install -m 0755 jerbuild /usr/local/bin/jerbuild; \ + fi && \ + command -v scheme && \ + command -v jerbuild && \ + jerbuild --jerboa-home >/dev/null + +COPY . /src +WORKDIR /src + +RUN SCHEME="$(command -v scheme)" bash packaging/linux/build-tarball.sh && \ + mkdir -p /out && \ + cp qt-webengine/build/jerboa-browser-*-linux-*.tar.gz \ + /out/jerboa-browser-static-qt.tar.gz && \ + tar tzf /out/jerboa-browser-static-qt.tar.gz | \ + grep -E '/bin/jerboa-browser$' >/dev/null && \ + tar tzf /out/jerboa-browser-static-qt.tar.gz | \ + grep -E '/lib/libjerboa_browser.so$' >/dev/null && \ + bin_path="$(tar tzf /out/jerboa-browser-static-qt.tar.gz | \ + grep -E '/bin/jerboa-browser$' | head -n 1)" && \ + tar xzf /out/jerboa-browser-static-qt.tar.gz -O \ + "$bin_path" > /tmp/jerboa-browser && \ + file /tmp/jerboa-browser + +FROM ubuntu:24.04 +COPY --from=builder /out/jerboa-browser-static-qt.tar.gz /out/jerboa-browser-static-qt.tar.gz +CMD ["cat", "/out/jerboa-browser-static-qt.tar.gz"] --- a/Makefile +++ b/Makefile @@ -3,10 +3,15 @@ # full Qt/WebKit GUI bundle additionally needs the native wrapper.) JERBUILD ?= jerbuild JH := $(shell $(JERBUILD) --jerboa-home 2>/dev/null) -ifeq ($(JH),) -$(error jerbuild not found on PATH (or '$(JERBUILD) --jerboa-home' failed). Install jerbuild, or set JERBUILD=/path/to/jerbuild) -endif JEXEC := $(JERBUILD) exec --libdirs $(CURDIR)/scheme:$(JH)/lib +JERBUILD_ERROR := "ERROR: jerbuild not found on PATH (or '$(JERBUILD) --jerboa-home' failed). Install jerbuild, or set JERBUILD=/path/to/jerbuild." + +DOCKER ?= docker +DOCKER_PLATFORM ?= linux/amd64 +DOCKER_BUILD_FLAGS ?= +JERBOA_IMAGE ?= jerboa21/jerboa +STATIC_QT_IMAGE ?= jerboa-browser-qt-builder +STATIC_QT_TARBALL ?= jerboa-browser-static-qt-linux-amd64.tar.gz # Modules that use (std crypto native-rust) need libjerboa_native dlopen-able # when run in the interpreter (jerbuild exec: tests, repl); the compiled binary @@ -17,7 +22,7 @@ SOEXT := $(if $(filter Darwin,$(shell uname -s)),dylib,so) # `make binary` links the static archive from a temp dir and leaves no shared # lib behind, so build the cdylib from jerbuild's bundled crate if it isn't # already cached, then symlink it where native-rust probes (./lib, CWD-relative). -lib/libjerboa_native.$(SOEXT): +lib/libjerboa_native.$(SOEXT): | check-jerbuild @mkdir -p lib @src="$(JH)/jerboa-native-rs/target/release/libjerboa_native.$(SOEXT)"; \ if [ ! -f "$$src" ] && [ -f "$(JH)/jerboa-native-rs/Cargo.toml" ]; then \ @@ -28,13 +33,20 @@ lib/libjerboa_native.$(SOEXT): if [ -f "$$src" ]; then ln -sf "$$src" "$@" && echo "staged $@ -> $$src"; \ else echo "note: libjerboa_native.$(SOEXT) unavailable; crypto tests may fail"; fi -.PHONY: all build binary run test test-keymap test-minibuffer test-commands test-keys test-nav test-hint test-pass test-polish test-securestore test-adblock test-gui test-buffers repl clean help +.PHONY: all build binary run test test-keymap test-minibuffer test-commands test-keys test-nav test-hint test-pass test-polish test-securestore test-adblock test-gui test-buffers repl clean help check-jerbuild check-docker static-qt docker-static-qt .DEFAULT_GOAL := help all: binary +check-jerbuild: + @test -n "$(JH)" || { echo $(JERBUILD_ERROR) >&2; exit 1; } + +check-docker: + @command -v $(DOCKER) >/dev/null 2>&1 || \ + { echo "ERROR: Docker executable '$(DOCKER)' not found. Install Docker or set DOCKER=/path/to/docker."; exit 1; } + # Build the self-contained native ./jerboa-browser via .jerbuild. -binary: +binary: check-jerbuild $(JERBUILD) build @echo "" && ls -lh jerboa-browser && file jerboa-browser @@ -46,6 +58,7 @@ run: binary # The crypto-using interpreter suites load (std crypto native-rust), so stage the # Rust crypto lib (rule above) as a prerequisite of each. test-securestore test-commands test-keys test-nav test-hint test-pass test-polish test-adblock: lib/libjerboa_native.$(SOEXT) +test test-keymap test-minibuffer test-gui test-buffers repl: check-jerbuild # Run the (browser) test suite in the interpreter (no binary needed). Depends on # the pure secure-store unit tests so they run as part of `make test`. @@ -122,8 +135,30 @@ test-buffers: repl: $(JEXEC) scheme/browser-repl.ss +# Docker wrapper matching the jerboa-emacs static-qt workflow. Qt WebEngine is +# not emitted as one fully static executable; the artifact is the existing Linux +# tarball shape with the native browser binary plus system-Qt WebEngine backend. +static-qt: docker-static-qt + +docker-static-qt: check-docker + @echo "=== Building jerboa-browser Linux Qt artifact with Docker ===" + $(DOCKER) pull $(JERBOA_IMAGE) + $(DOCKER) build $(DOCKER_BUILD_FLAGS) --platform $(DOCKER_PLATFORM) \ + --build-arg JERBOA_IMAGE="$(JERBOA_IMAGE)" \ + -f Dockerfile.qt -t $(STATIC_QT_IMAGE) . + @id=$$($(DOCKER) create $(STATIC_QT_IMAGE)) && \ + trap '$(DOCKER) rm $$id >/dev/null 2>&1 || true' EXIT INT TERM && \ + $(DOCKER) cp $$id:/out/jerboa-browser-static-qt.tar.gz ./$(STATIC_QT_TARBALL) + @echo "" + @ls -lh $(STATIC_QT_TARBALL) + @tar tzf $(STATIC_QT_TARBALL) | grep -E '/bin/jerboa-browser$$' >/dev/null || \ + { echo "ERROR: native binary missing from $(STATIC_QT_TARBALL)" >&2; exit 1; } + @tar tzf $(STATIC_QT_TARBALL) | grep -E '/lib/libjerboa_browser.so$$' >/dev/null || \ + { echo "ERROR: Qt WebEngine backend missing from $(STATIC_QT_TARBALL)" >&2; exit 1; } + clean: rm -f jerboa-browser jb-main.c jb-main.o jb_*.h jerboa-browser.boot + rm -f $(STATIC_QT_TARBALL) rm -rf .bcache test-artifacts find scheme -name '*.so' -delete 2>/dev/null || true find scheme -name '*.wpo' -delete 2>/dev/null || true @@ -132,6 +167,7 @@ help: @echo "jerboa-browser — programmable Qt WebEngine pane from the Jerboa REPL" @echo "" @echo " make binary build the self-contained native ./jerboa-browser" + @echo " make static-qt build the Linux Qt/WebEngine tarball via Docker" @echo " make test run the (browser) test suite (interpreter)" @echo " make test-gui offline Qt GUI/snapshot harness (offscreen, headless)" @echo " make repl REPL with (browser) preloaded (interpreter)" --- a/README.md +++ b/README.md @@ -83,11 +83,18 @@ and run `pcscd`. ```sh make binary # the self-contained native ./jerboa-browser +make static-qt # Linux Qt/WebEngine tarball via Docker (linux/amd64) make test # (browser) suite + secure-store unit tests; also test-{keymap,…,polish} make test-securestore # just the pure secure-store crypto/format unit tests make test-gui # offline Qt snapshot harness (offscreen, headless) ``` +`make static-qt` mirrors the jerboa-emacs Docker workflow and copies out +`jerboa-browser-static-qt-linux-amd64.tar.gz`. Because this backend is Qt +WebEngine, the artifact is a Linux tarball with the native browser binary plus +`libjerboa_browser.so`; it still expects a system Qt 6 WebEngine runtime rather +than a literal one-file static WebEngine executable. + The functional suites run offscreen (`QT_QPA_PLATFORM=offscreen`) and hermetic (`JWB_TEST_NO_NETWORK=1`), modeled on the jerboa-emacs Qt test harness. --- a/packaging/README.md +++ b/packaging/README.md @@ -96,18 +96,21 @@ Total ≈ 299 MB (dominated by QtWebEngineCore + ICU). ```sh packaging/linux/build-tarball.sh # → qt-webengine/build/jerboa-browser-<ver>-linux-<arch>.tar.gz +make static-qt # Docker build, copies ./jerboa-browser-static-qt-linux-amd64.tar.gz ``` -> **Status: not verified on this host.** Development is on macOS, so the Linux -> script is provided and reviewed but has not been executed end-to-end here. The -> tarball bundles the backend `libjerboa_browser.so`, the Jerboa `scheme/` -> sources, and `build-binary.ss` + `Makefile`. When the Jerboa toolchain (Chez + -> Jerboa stdlib) is present on the build host it also compiles and bundles the -> self-contained native `bin/jerboa-browser` — a Jerboa program with the Chez -> kernel, boot image, and the `(browser)` library all embedded (built by -> `build-binary.ss`, **not** a C/C++ launcher); otherwise unpack and run `make -> binary` to produce it. Either way it relies on a **system Qt 6 WebEngine** -> install (documented prerequisite) rather than vendoring Qt. +The tarball bundles the backend `libjerboa_browser.so`, the Jerboa `scheme/` +sources, and `build-binary.ss` + `Makefile`. When the Jerboa toolchain (Chez + +Jerboa stdlib) is present on the build host it also compiles and bundles the +self-contained native `bin/jerboa-browser` — a Jerboa program with the Chez +kernel, boot image, and the `(browser)` library all embedded (built by +`build-binary.ss`, **not** a C/C++ launcher); otherwise unpack and run `make +binary` to produce it. Either way it relies on a **system Qt 6 WebEngine** +install (documented prerequisite) rather than vendoring Qt. + +`make static-qt` wraps that Linux package path in Docker, using the +`jerboa21/jerboa` image plus Ubuntu Qt WebEngine packages, and has been verified +on `linux.cons.io` (`linux/amd64`). For a fully self-contained Linux artifact, run the bundle through [`linuxdeployqt`](https://github.com/probonopd/linuxdeployqt) to produce an --- a/qt-webengine/CMakeLists.txt +++ b/qt-webengine/CMakeLists.txt @@ -40,11 +40,18 @@ target_link_libraries(jerboa_browser option(JWB_ADBLOCK "Ad/tracker blocking via vendored adblock-rust (needs cargo)" ON) if(JWB_ADBLOCK) set(ADBLOCK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/adblock-rust-ffi) - set(ADBLOCK_LIB ${ADBLOCK_DIR}/target/release/libadblock.a) + set(ADBLOCK_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR}/adblock-rust-target) + set(ADBLOCK_LIB ${ADBLOCK_TARGET_DIR}/release/libadblock.a) find_program(CARGO_EXE cargo REQUIRED) + set(ADBLOCK_RANLIB_COMMAND) + if(CMAKE_RANLIB) + list(APPEND ADBLOCK_RANLIB_COMMAND COMMAND ${CMAKE_RANLIB} ${ADBLOCK_LIB}) + endif() add_custom_command( OUTPUT ${ADBLOCK_LIB} - COMMAND ${CARGO_EXE} build --release --manifest-path ${ADBLOCK_DIR}/Cargo.toml + COMMAND ${CMAKE_COMMAND} -E env CARGO_TARGET_DIR=${ADBLOCK_TARGET_DIR} + ${CARGO_EXE} build --release --manifest-path ${ADBLOCK_DIR}/Cargo.toml + ${ADBLOCK_RANLIB_COMMAND} COMMENT "Building vendored adblock-rust staticlib (cargo build --release)" VERBATIM) add_custom_target(adblock_rust DEPENDS ${ADBLOCK_LIB})