diff --git a/.github/actions/muslbuilder/.dockerignore b/.github/actions/muslbuilder/.dockerignore new file mode 100644 index 00000000000..d61c4dbc404 --- /dev/null +++ b/.github/actions/muslbuilder/.dockerignore @@ -0,0 +1,6 @@ +* # Ignore everything in the root context except for: + +!src/third-party/prqlc-c/ + +!.github/actions/muslbuilder/ +!.github/actions/muslbuilder/* diff --git a/.github/actions/muslbuilder/Dockerfile b/.github/actions/muslbuilder/Dockerfile index 69db402b6a0..c11b758ef66 100644 --- a/.github/actions/muslbuilder/Dockerfile +++ b/.github/actions/muslbuilder/Dockerfile @@ -161,9 +161,17 @@ RUN curl -sSL https://www.sqlite.org/2025/sqlite-autoconf-3490100.tar.gz | tar x make install && \ cd /extract && rm -rf * -FROM --platform=$TARGETPLATFORM alpine:latest +FROM --platform=$TARGETPLATFORM alpine:latest AS rust-builder -COPY --from=depsbuilder /fake.root /fake.root +RUN apk add --no-cache \ + cargo \ + g++ + +WORKDIR /build/prqlc-c +COPY src/third-party/prqlc-c . +RUN cargo build --release --package prqlc-c + +FROM --platform=$TARGETPLATFORM alpine:latest LABEL com.github.actions.name="C++ MUSL Builder Slim" LABEL com.github.actions.description="Provides a C++ MUSL environment" @@ -182,5 +190,13 @@ RUN apk add --no-cache \ rust \ zip -COPY entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] + +COPY --from=depsbuilder /fake.root /fake.root +COPY --from=rust-builder /build/prqlc-c/target/release/libprqlc_c.a /opt/prebuilt/libprqlc_c.a +ENV PRQLC_C_PATH=/opt/prebuilt/libprqlc_c.a +ENV LNAV_BUILD_STATIC=yes +ENV LNAV_BUILD_ENV=/fake.root +ENV PATH=/fake.root/bin:$PATH + +COPY .github/actions/muslbuilder/entrypoint.sh /usr/local/bin/entrypoint.sh +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/.github/actions/muslbuilder/entrypoint.sh b/.github/actions/muslbuilder/entrypoint.sh index 6f7e357279b..25df22b2207 100755 --- a/.github/actions/muslbuilder/entrypoint.sh +++ b/.github/actions/muslbuilder/entrypoint.sh @@ -1,24 +1,8 @@ #!/bin/sh -set -Eeuxo pipefail - -if [ -z ${GITHUB_WORKSPACE:-} ]; then - git clone --depth 1 https://github.com/tstack/lnav.git - cd lnav +# If arguments are provided, execute them; otherwise, open a shell. +if [ "$#" -gt 0 ]; then + exec "$@" else - cd ${GITHUB_WORKSPACE} + exec sh fi - -./autogen.sh -mkdir lbuild -cd lbuild -../configure \ - --with-libarchive=/fake.root \ - CFLAGS='-static -g1 -gz=zlib -no-pie -O2' \ - CXXFLAGS='-static -g1 -gz=zlib -U__unused -no-pie -O2' \ - LDFLAGS="-L/fake.root/lib" \ - CPPFLAGS="-I/fake.root/include -I/fake.root/include/ncursesw" \ - LIBS="-L/fake.root/lib -lssh2 -llzma -lssl -lcrypto -lz -llz4" \ - --enable-static \ - PATH="/fake.root/bin:${PATH}" -make -j2 diff --git a/.github/workflows/bins.yml b/.github/workflows/bins.yml index a1c9690f840..1aa6d7f23fe 100644 --- a/.github/workflows/bins.yml +++ b/.github/workflows/bins.yml @@ -60,7 +60,11 @@ jobs: - name: list run: find /fake.root - name: make - run: /entrypoint.sh + run: >- + ./autogen.sh + mkdir lbuild && cd lbuild && + ../configure --enable-release && + make -j$(nproc) - name: Build musl package if: ${{ inputs.lnav_version_number != '' }} run: >- @@ -111,8 +115,12 @@ jobs: uses: addnab/docker-run-action@v3 with: image: tstack/lnav-build:latest - options: -v ${{ github.workspace }}:/lnav -e GITHUB_WORKSPACE=/lnav --platform ${{ matrix.container-platform }} - run: /entrypoint.sh + options: -v ${{ github.workspace }}:/lnav --platform ${{ matrix.container-platform }} + run: >- + ./autogen.sh + mkdir lbuild && cd lbuild && + ../configure --enable-release && + make -j$(nproc) - name: Build musl package if: ${{ inputs.lnav_version_number != '' }} run: >- @@ -171,7 +179,7 @@ jobs: 'CFLAGS=-O2 -g2' \ "LDFLAGS=-L$(brew --prefix ncurses)/lib -L$(brew --prefix xz)/lib -L$(brew --prefix zstd)/lib/ -L$(brew --prefix lz4)/lib/ -L$(brew --prefix libunistring)/lib" \ --with-libarchive=$(brew --prefix libarchive) \ - "LIBS=-llzma -lzstd -liconv -llz4 -lbz2 -lz -lpcre2-8" + "LIBS= -lzstd -liconv -lbz2 -lz -lpcre2-8" - name: make run: make -j2 - name: Build macos package diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 7602b641e48..8f3e71c7b2b 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -147,11 +147,10 @@ jobs: export PREFIX=$PWD/lnav ../lnav/configure \ --enable-static \ - LDFLAGS="-static" \ CPPFLAGS="-I../src -I../../lnav/src -I../../lnav/src/fmtlib -O2 -DNCURSES_STATIC" \ CXXFLAGS="-fPIC" \ CFLAGS="-fPIC" \ - LIBS="-larchive -lssh2 -llzma -llz4 -lz -lzstd -lssl -lcrypto -liconv -lunistring -lbrotlicommon -lcrypt32" \ + LIBS="-larchive -lssh2 -lz -lzstd -lssl -lcrypto -liconv -lunistring -lbrotlicommon -lcrypt32" \ --sysconfdir=/etc \ --prefix=$PREFIX || cat config.log - name: '🚧 Make (do not use -j)' diff --git a/.github/workflows/musl-build-image.yml b/.github/workflows/musl-build-image.yml index 75b39a3d973..bab5ad160eb 100644 --- a/.github/workflows/musl-build-image.yml +++ b/.github/workflows/musl-build-image.yml @@ -37,7 +37,8 @@ jobs: name: Build and push uses: docker/build-push-action@v4 with: - context: ${{ github.workspace }}/.github/actions/muslbuilder/ + context: ${{ github.workspace }} + file: .github/actions/muslbuilder/Dockerfile platforms: linux/amd64, linux/arm/v7, linux/arm64 push: true tags: ${{ env.CONTAINER_TAG }} diff --git a/README.md b/README.md index e9ff72f75f4..031a9d76dcd 100644 --- a/README.md +++ b/README.md @@ -197,6 +197,16 @@ $ make $ sudo make install ``` +#### Build Using Docker + +To build lnav from your local source without installing all dependencies locally, use our Docker build environment by running: + +```console +$ ./docker-run.sh ./autogen.sh +$ ./docker-run.sh ./configure +$ ./docker-run.sh make -j4 +``` + ## See Also [Angle-grinder](https://github.com/rcoh/angle-grinder) is a tool to slice and dice log files on the command-line. diff --git a/configure.ac b/configure.ac index 8a7abd16dfa..0c574f90437 100644 --- a/configure.ac +++ b/configure.ac @@ -71,9 +71,77 @@ AC_CHECK_FUNC(mkostemp, AC_STRUCT_TIMEZONE +AC_ARG_ENABLE([release], + AS_HELP_STRING([--enable-release], + [Enable release features])) + AC_ARG_ENABLE([static], - AS_HELP_STRING([--enable-static], - [Enable static linking])) + AS_HELP_STRING([--enable-static], + [Enable static linking. Also accepts LNAV_BUILD_STATIC="yes" environment value]), + [], + [ + if test x"${LNAV_BUILD_STATIC}" = x"yes"; then + enable_static="yes" + fi + if test x"${enable_release}" = x"yes"; then + enable_static="yes" + fi + ] +) + +AC_ARG_WITH([build-env], + AS_HELP_STRING( + [--with-build-env=], + [Path for searching binaries, libraries, and includes. Also accepts LNAV_BUILD_ENV environment value] + ), + [ + + if test "x$with_build_env" = "xyes"; then + AC_MSG_ERROR([--with-build-env requires a path argument]) + else + if test "x$with_build_env" != "xno"; then + build_env="$with_build_env" + with_build_env="yes" + fi + fi + ], + [ + if test -n "$LNAV_BUILD_ENV"; then + AC_MSG_NOTICE([using LNAV_BUILD_ENV="$LNAV_BUILD_ENV"]) + build_env="$LNAV_BUILD_ENV" + with_build_env="yes" + fi + ] +) + +if test "x$with_build_env" = "xyes"; then + LDFLAGS="-L$build_env/lib $LDFLAGS" + CPPFLAGS="-I$build_env/include -I$build_env/include/ncursesw $CPPFLAGS" +fi + +if test x"${enable_release}" = x"yes"; then + CFLAGS="-g1 -gz=zlib -O2 $CFLAGS" + CXXFLAGS="-g1 -gz=zlib -O2 $CXXFLAGS" +fi + +if test x"${enable_static}" = x"yes"; then + case "$host_os" in + darwin*) + STATIC_LDFLAGS="$STATIC_LDFLAGS -Wl,-search_paths_first" + ;; + *) + LDFLAGS="-static $LDFLAGS" + case "$host_os" in + mingw*|cygwin*|msys*) + # Windows-like systems: do not add -no-pie. + ;; + *) + LDFLAGS="-no-pie $LDFLAGS" + ;; + esac + ;; + esac +fi AC_SEARCH_LIBS(openpty, util) AC_SEARCH_LIBS(gzseek, z, [], [AC_MSG_ERROR([libz required to build])]) @@ -151,7 +219,7 @@ AS_VAR_IF([ax_cv_curses],[yes],[], AC_MSG_ERROR([requires an X/Open-compatible Curses library with color])dnl ) -AX_PATH_LIB_ARCHIVE +AX_PATH_LIB_ARCHIVE([$enable_static]) AX_CHECK_PCRE2([8], [], [AC_MSG_ERROR([pcre2 is required to build])]) AX_CODE_COVERAGE @@ -214,12 +282,6 @@ AS_VAR_SET(static_lib_list, ["$static_lib_list librtmp.a libiconv.a liblz4.a liblber.a libunistring.a"]) if test x"${enable_static}" = x"yes"; then - case "$host_os" in - darwin*) - STATIC_LDFLAGS="$STATIC_LDFLAGS -Wl,-search_paths_first" - ;; - esac - AX_CHECK_LINK_FLAG([-static-libgcc], [STATIC_LDFLAGS="$STATIC_LDFLAGS -static-libgcc"]) STATIC_LDFLAGS="$STATIC_LDFLAGS -L`pwd`/src/static-libs" @@ -302,6 +364,22 @@ AS_IF([test $? -eq 0], AC_DEFINE_UNQUOTED([VCS_PACKAGE_STRING], ["$PACKAGE_STRING"], [VCS package string])) AM_CONDITIONAL(HAVE_CARGO, test x"$CARGO_CMD" != x"") +if test x"$CARGO_CMD" != x""; then + AC_ARG_VAR([PRQLC_C_PATH], [Path to prebuilt libprqlc_c.a]) + if test -n "$PRQLC_C_PATH" && test -f "$PRQLC_C_PATH"; then + rust_deps_libs_value="$PRQLC_C_PATH" + prebuilt_rust_deps=yes + else + rust_deps_libs_value="third-party/prqlc-c/target/release/libprqlc_c.a" + prebuilt_rust_deps=no + fi +else + rust_deps_libs_value="" +fi +AC_SUBST([rust_deps_libs_value]) +AM_CONDITIONAL([USE_PREBUILT_RUST_DEPS], [test "$prebuilt_rust_deps" = "yes"]) + + AM_CONDITIONAL(HAVE_LIBCURL, test x"$LIBCURL" != x"") AM_CONDITIONAL([CROSS_COMPILING], [ test x"$cross_compiling" != x"no" ]) AM_CONDITIONAL(HAVE_CHECK_JSONSCHEMA, test x"$CHECK_JSONSCHEMA" != x"") diff --git a/docker-run.sh b/docker-run.sh new file mode 100755 index 00000000000..46f3ec067a5 --- /dev/null +++ b/docker-run.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# This script executes the command passed to it inside lnav's Docker build environment. +# The repository root is mounted to the container, and the working directory inside +# the container matches the current directory on the host. +# +# Usage: +# ./docker-run.sh [args...] +# +# Examples: +# ./docker-run.sh ./autogen.sh # Run autogen.sh inside the container +# ./docker-run.sh ../configure --enable-release # Run configure script +# ./docker-run.sh make -j4 # Build the project +# ./docker-run.sh # Open an interactive shell in the container +# + +WORKSPACE_ROOT=$(cd "$(dirname "$0")" && pwd) +CONTAINER_WS="/lnav" + +# Compute the current directory's relative path to the workspace root. +RELATIVE_DIR=$(realpath --relative-to="$WORKSPACE_ROOT" "$(pwd)") +CONTAINER_WORKDIR="${CONTAINER_WS}/${RELATIVE_DIR}" + +docker run -it --rm \ + --user $(id -u):$(id -g) \ + --volume ${WORKSPACE_ROOT}:${CONTAINER_WS} \ + --workdir "${CONTAINER_WORKDIR}" \ + tstack/lnav-build \ + "$@" diff --git a/m4/lnav_with_libarchive.m4 b/m4/lnav_with_libarchive.m4 index a6fa4fded29..2bf5a173ff5 100644 --- a/m4/lnav_with_libarchive.m4 +++ b/m4/lnav_with_libarchive.m4 @@ -29,24 +29,23 @@ dnl dnl @file lnav_with_libarchive.m4 dnl AC_DEFUN([AX_PATH_LIB_ARCHIVE],[dnl -AC_MSG_CHECKING([lib archive]) AC_ARG_WITH(libarchive, [ --with-libarchive[[=prefix]]],, with_libarchive="yes") -if test ".$with_libarchive" = ".no" ; then - AC_MSG_RESULT([disabled]) - m4_ifval($2,$2) -else - AC_MSG_RESULT([(testing)]) + +libarchive_static=$1 +if test x"$libarchive_static" = x"yes" ; then + LIBARCHIVE_REQ_LIBS="-llzma -llz4" +fi + +if test ".$with_libarchive" != ".no" ; then AC_CHECK_LIB(archive, archive_read_new) AC_CHECK_HEADERS(archive.h) if test "$ac_cv_lib_archive_archive_read_new" = "yes" && \ - test "x$ac_cv_header_archive_h" = xyes; then - LIBARCHIVE_LIBS="-larchive" - AC_MSG_CHECKING([lib archive]) - AC_MSG_RESULT([$LIBARCHIVE_LIBS]) - m4_ifval($1,$1) + test "x$ac_cv_header_archive_h" = xyes ; then + LIBARCHIVE_LIBS="-larchive $LIBARCHIVE_REQ_LIBS" else + AC_MSG_NOTICE([checking libarchive with "$with_libarchive" path considered]) unset ac_cv_header_archive_h OLDLDFLAGS="$LDFLAGS" ; LDFLAGS="$LDFLAGS -L$with_libarchive/lib" OLDCPPFLAGS="$CPPFLAGS" ; CPPFLAGS="$CPPFLAGS -I$with_libarchive/include" @@ -56,20 +55,18 @@ else LDFLAGS="$OLDLDFLAGS" if test "$ac_cv_lib_archive_archive_read_new" = "yes" && \ test "x$ac_cv_header_archive_h" = xyes; then - AC_MSG_RESULT(.setting LIBARCHIVE_LIBS -L$with_libarchive/lib -larchive) LIBARCHIVE_LDFLAGS="-L$with_libarchive/lib" - LIBARCHIVE_LIBS="-larchive" + LIBARCHIVE_LIBS="-larchive $LIBARCHIVE_REQ_LIBS" test -d "$with_libarchive/include" && LIBARCHIVE_CFLAGS="-I$with_libarchive/include" - AC_MSG_CHECKING([lib archive]) - AC_MSG_RESULT([$LIBARCHIVE_LIBS]) - m4_ifval($1,$1) else - AC_MSG_CHECKING([lib archive]) - AC_MSG_RESULT([[no]]) - m4_ifval($2,$2) + AC_MSG_NOTICE([required libarchive files not found]) fi fi fi + +if test -n "$LIBARCHIVE_LIBS"; then + AC_MSG_NOTICE([.setting LIBARCHIVE_LIBS=$LIBARCHIVE_LIBS , LIBARCHIVE_LDFLAGS=$LIBARCHIVE_LDFLAGS , LIBARCHIVE_CFLAGS=$LIBARCHIVE_CFLAGS]) +fi AC_SUBST([LIBARCHIVE_LIBS]) AC_SUBST([LIBARCHIVE_LDFLAGS]) AC_SUBST([LIBARCHIVE_CFLAGS]) diff --git a/src/Makefile.am b/src/Makefile.am index 605bcbc92f7..5d666f99197 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -126,14 +126,17 @@ AM_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS) $(USER_CXXFLAGS) if HAVE_CARGO RUST_DEPS_CPPFLAGS = -DHAVE_RUST_DEPS=1 PRQLC_DIR = third-party/prqlc-c/target -RUST_DEPS_LIBS = $(PRQLC_DIR)/release/libprqlc_c.a +RUST_DEPS_LIBS = @rust_deps_libs_value@ RUST_DEPS_TRIGGER = $(PRQLC_DIR)/release/libprqlc_c.a.dep +if !USE_PREBUILT_RUST_DEPS $(RUST_DEPS_LIBS): $(srcdir)/third-party/prqlc-c/src/lib.rs $(srcdir)/third-party/prqlc-c/Cargo.toml mkdir -p $(PRQLC_DIR) env CARGO_TARGET_DIR=third-party/prqlc-c/target $(CARGO_CMD) build --manifest-path \ $(srcdir)/third-party/prqlc-c/Cargo.toml --package prqlc-c --release touch $(RUST_DEPS_LIBS) +endif + else RUST_DEPS =