Build static dependency libdirs for Docker Qt

ober

7cc6ceea84fe156d0e913ad4391b23383a304c71

diff --git a/Dockerfile.qt b/Dockerfile.qt
index 140f75e..c4b5d81 100644
--- a/Dockerfile.qt
+++ b/Dockerfile.qt
@@ -258,6 +258,7 @@ FROM ${JERBOA_IMAGE} AS builder
 RUN apt-get update && apt-get install -y --no-install-recommends \
     g++ \
     libncurses-dev \
+    libpcre2-dev \
     uuid-dev \
     libssl-dev \
     pkg-config \
diff --git a/Makefile b/Makefile
index b25f353..c1c7b8a 100644
--- a/Makefile
+++ b/Makefile
@@ -1309,6 +1309,8 @@ MUSL_DEPS ?= $(VENDOR)
 MUSL_JERBOA ?= $(MUSL_DEPS)/jerboa
 MUSL_PCRE2 ?= $(MUSL_DEPS)/jerboa-pcre2
 MUSL_SCINTILLA ?= $(MUSL_DEPS)/jerboa-scintilla
+MUSL_PCRE2_LIBDIR ?= /tmp/jemacs-build/jerboa-pcre2
+MUSL_SCINTILLA_LIBDIR ?= /tmp/jemacs-build/jerboa-scintilla
 MUSL_JSH_ROOT ?= $(MUSL_DEPS)/jerboa-shell
 MUSL_JSH ?= $(MUSL_JSH_ROOT)/src
 MUSL_SCI_VENDOR ?= $(SCINTILLA_VENDOR)
@@ -1340,14 +1342,24 @@ linux-tui-local: vendor-deps
 	  | $(MUSL_SCHEME) --libdirs $(MUSL_JERBOA)/lib -q
 	rm -f $(MUSL_JERBOA)/lib/jerboa/*.wpo
 	$(MUSL_SCHEME) --libdirs $(MUSL_JERBOA)/lib --script $(MUSL_JERBOA)/jerbuild.ss src/ lib/
-	cp support/vendor-overrides/jerboa-pcre2-ffi-static.ss $(MUSL_PCRE2)/jerboa-pcre2/ffi.ss
-	$(MUSL_SCHEME) --libdirs $(MUSL_PCRE2) \
+	rm -rf $(MUSL_PCRE2_LIBDIR) $(MUSL_SCINTILLA_LIBDIR)
+	mkdir -p $(MUSL_PCRE2_LIBDIR) $(MUSL_SCINTILLA_LIBDIR)
+	cp $(MUSL_PCRE2)/jerboa_pcre2_shim.c $(MUSL_PCRE2_LIBDIR)/pcre2_shim.c
+	PCRE2_CFLAGS=$$(pkg-config --cflags libpcre2-8 2>/dev/null || echo "") && \
+	  gcc -shared -fPIC -O2 -o $(MUSL_PCRE2_LIBDIR)/jerboa_pcre2_shim.so \
+	    $(MUSL_PCRE2_LIBDIR)/pcre2_shim.c $$PCRE2_CFLAGS -lpcre2-8
+	$(MUSL_SCHEME) --libdirs $(MUSL_JERBOA)/lib \
+	  --script $(MUSL_JERBOA)/jerbuild.ss $(MUSL_PCRE2)/src $(MUSL_PCRE2_LIBDIR) --force
+	$(MUSL_SCHEME) --libdirs $(MUSL_JERBOA)/lib \
+	  --script $(MUSL_JERBOA)/jerbuild.ss $(MUSL_SCINTILLA)/src $(MUSL_SCINTILLA_LIBDIR) --force
+	scripts/patch-static-load-shared.sh $(MUSL_PCRE2_LIBDIR)
+	scripts/patch-static-load-shared.sh $(MUSL_SCINTILLA_LIBDIR)
+	JEMACS_STATIC=1 JERBOA_PCRE2_LIB=$(MUSL_PCRE2_LIBDIR) $(MUSL_SCHEME) --libdirs $(MUSL_PCRE2_LIBDIR):$(MUSL_JERBOA)/lib \
 	  --compile-imported-libraries --script support/vendor-overrides/jerboa-pcre2-compile-libs.ss
-	rm -f $(MUSL_PCRE2)/jerboa-pcre2/*.wpo
-	cp support/vendor-overrides/jerboa-scintilla-ffi-static.sls $(MUSL_SCINTILLA)/src/jerboa-scintilla/ffi.sls
-	JEMACS_STATIC=1 $(MUSL_SCHEME) --libdirs $(MUSL_SCINTILLA)/src \
+	rm -f $(MUSL_PCRE2_LIBDIR)/jerboa-pcre2/*.wpo
+	JEMACS_STATIC=1 $(MUSL_SCHEME) --libdirs $(MUSL_SCINTILLA_LIBDIR):$(MUSL_JERBOA)/lib \
 	  --compile-imported-libraries --script support/vendor-overrides/jerboa-scintilla-compile-libs.ss
-	rm -f $(MUSL_SCINTILLA)/src/jerboa-scintilla/*.wpo
+	rm -f $(MUSL_SCINTILLA_LIBDIR)/jerboa-scintilla/*.wpo
 	cp support/vendor-overrides/jerboa-net-tcp-static.sls $(MUSL_JERBOA)/lib/std/net/tcp.sls
 	cp support/vendor-overrides/jerboa-net-tcp-raw-static.sls $(MUSL_JERBOA)/lib/std/net/tcp-raw.sls
 	cp support/vendor-overrides/jerboa-net-uri.sls $(MUSL_JERBOA)/lib/std/net/uri.sls
@@ -1381,11 +1393,11 @@ linux-tui-local: vendor-deps
 	CHEZ_DIR=$(MUSL_CHEZ_DIR) \
 	JERBOA_DIR=$(MUSL_JERBOA)/lib \
 	JSH_DIR=$(MUSL_JSH) \
-	JERBOA_PCRE2_DIR=$(MUSL_PCRE2) \
-	JERBOA_SCINTILLA_DIR=$(MUSL_SCINTILLA)/src \
+	JERBOA_PCRE2_DIR=$(MUSL_PCRE2_LIBDIR) \
+	JERBOA_SCINTILLA_DIR=$(MUSL_SCINTILLA_LIBDIR) \
 	SCI_VENDOR_DIR=$(MUSL_SCI_VENDOR) \
 	$(MUSL_SCHEME) \
-	  --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(MUSL_PCRE2):$(MUSL_SCINTILLA)/src \
+	  --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(MUSL_PCRE2_LIBDIR):$(MUSL_SCINTILLA_LIBDIR) \
 	  --script build-binary.ss
 	@echo ""
 	@echo "=== jemacs static TUI binary built ==="
@@ -1442,14 +1454,24 @@ linux-qt-local: vendor-deps
 	JEMACS_STATIC=1 $(MUSL_SCHEME) --libdirs /tmp/jemacs-build/jerboa-qt/lib:$(MUSL_JERBOA)/lib \
 	  --compile-imported-libraries --script /tmp/jemacs-build/jerboa-qt/compile-libs.ss
 	rm -f /tmp/jemacs-build/jerboa-qt/lib/jerboa-qt/*.wpo
-	cp support/vendor-overrides/jerboa-pcre2-ffi-static.ss $(MUSL_PCRE2)/jerboa-pcre2/ffi.ss
-	$(MUSL_SCHEME) --libdirs $(MUSL_PCRE2) \
+	rm -rf $(MUSL_PCRE2_LIBDIR) $(MUSL_SCINTILLA_LIBDIR)
+	mkdir -p $(MUSL_PCRE2_LIBDIR) $(MUSL_SCINTILLA_LIBDIR)
+	cp $(MUSL_PCRE2)/jerboa_pcre2_shim.c $(MUSL_PCRE2_LIBDIR)/pcre2_shim.c
+	PCRE2_CFLAGS=$$(pkg-config --cflags libpcre2-8 2>/dev/null || echo "") && \
+	  gcc -shared -fPIC -O2 -o $(MUSL_PCRE2_LIBDIR)/jerboa_pcre2_shim.so \
+	    $(MUSL_PCRE2_LIBDIR)/pcre2_shim.c $$PCRE2_CFLAGS -lpcre2-8
+	$(MUSL_SCHEME) --libdirs $(MUSL_JERBOA)/lib \
+	  --script $(MUSL_JERBOA)/jerbuild.ss $(MUSL_PCRE2)/src $(MUSL_PCRE2_LIBDIR) --force
+	$(MUSL_SCHEME) --libdirs $(MUSL_JERBOA)/lib \
+	  --script $(MUSL_JERBOA)/jerbuild.ss $(MUSL_SCINTILLA)/src $(MUSL_SCINTILLA_LIBDIR) --force
+	scripts/patch-static-load-shared.sh $(MUSL_PCRE2_LIBDIR)
+	scripts/patch-static-load-shared.sh $(MUSL_SCINTILLA_LIBDIR)
+	JEMACS_STATIC=1 JERBOA_PCRE2_LIB=$(MUSL_PCRE2_LIBDIR) $(MUSL_SCHEME) --libdirs $(MUSL_PCRE2_LIBDIR):$(MUSL_JERBOA)/lib \
 	  --compile-imported-libraries --script support/vendor-overrides/jerboa-pcre2-compile-libs.ss
-	rm -f $(MUSL_PCRE2)/jerboa-pcre2/*.wpo
-	cp support/vendor-overrides/jerboa-scintilla-ffi-static.sls $(MUSL_SCINTILLA)/src/jerboa-scintilla/ffi.sls
-	JEMACS_STATIC=1 $(MUSL_SCHEME) --libdirs $(MUSL_SCINTILLA)/src \
+	rm -f $(MUSL_PCRE2_LIBDIR)/jerboa-pcre2/*.wpo
+	JEMACS_STATIC=1 $(MUSL_SCHEME) --libdirs $(MUSL_SCINTILLA_LIBDIR):$(MUSL_JERBOA)/lib \
 	  --compile-imported-libraries --script support/vendor-overrides/jerboa-scintilla-compile-libs.ss
-	rm -f $(MUSL_SCINTILLA)/src/jerboa-scintilla/*.wpo
+	rm -f $(MUSL_SCINTILLA_LIBDIR)/jerboa-scintilla/*.wpo
 	cp support/vendor-overrides/jerboa-net-tcp-static.sls $(MUSL_JERBOA)/lib/std/net/tcp.sls
 	cp support/vendor-overrides/jerboa-net-tcp-raw-static.sls $(MUSL_JERBOA)/lib/std/net/tcp-raw.sls
 	cp support/vendor-overrides/jerboa-net-uri.sls $(MUSL_JERBOA)/lib/std/net/uri.sls
@@ -1512,8 +1534,8 @@ linux-qt-local: vendor-deps
 	CHEZ_DIR=$(MUSL_CHEZ_DIR) \
 	JERBOA_DIR=$(MUSL_JERBOA)/lib \
 	JSH_DIR=$(MUSL_JSH) \
-	JERBOA_PCRE2_DIR=$(MUSL_PCRE2) \
-	JERBOA_SCINTILLA_DIR=$(MUSL_SCINTILLA)/src \
+	JERBOA_PCRE2_DIR=$(MUSL_PCRE2_LIBDIR) \
+	JERBOA_SCINTILLA_DIR=$(MUSL_SCINTILLA_LIBDIR) \
 	JERBOA_QT_DIR=/tmp/jemacs-build/jerboa-qt/lib \
 	JERBOA_QT_SHIM_DIR=$(QT_STATIC_SHIM_DIR) \
 	JSH_COREUTILS_LIB=support/vendor-overrides/libjsh_coreutils_stub.a \
@@ -1525,7 +1547,7 @@ linux-qt-local: vendor-deps
 	TREE_SITTER_QUERIES_OBJ=/tmp/jemacs-build/treesitter_queries.o \
 	PKG_CONFIG_PATH=$(QT_STATIC_PREFIX)/lib/pkgconfig \
 	$(MUSL_SCHEME) \
-	  --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(MUSL_PCRE2):$(MUSL_SCINTILLA)/src:/tmp/jemacs-build/jerboa-qt/lib$(AWS_LOCAL_STATIC_LIBDIRS) \
+	  --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(MUSL_PCRE2_LIBDIR):$(MUSL_SCINTILLA_LIBDIR):/tmp/jemacs-build/jerboa-qt/lib$(AWS_LOCAL_STATIC_LIBDIRS) \
 	  --script build-binary-qt.ss
 	@echo ""
 	@echo "=== jemacs-qt static binary built ==="
diff --git a/scripts/patch-jerboa-qt-compat.sh b/scripts/patch-jerboa-qt-compat.sh
index de19c6b..15cedb2 100755
--- a/scripts/patch-jerboa-qt-compat.sh
+++ b/scripts/patch-jerboa-qt-compat.sh
@@ -22,11 +22,18 @@ repo="${1:-.}"
 compile="$repo/vendor/jerboa-qt/compile-libs.ss"
 qtsls="$repo/vendor/jerboa-qt/lib/jerboa-qt/qt.sls"
 
+sed_in_place() {
+  file="$1"
+  shift
+  tmp="$file.tmp.$$"
+  sed "$@" "$file" > "$tmp"
+  mv "$tmp" "$file"
+}
+
 if [ -f "$compile" ] && grep -q '(import (chez-qt ffi) (chez-qt qt))' "$compile"; then
-  sed -i \
+  sed_in_place "$compile" \
     -e 's/Compile chez-qt libraries/Compile jerboa-qt libraries/' \
-    -e 's/(import (chez-qt ffi) (chez-qt qt))/(import (jerboa-qt ffi) (jerboa-qt qt))/' \
-    "$compile"
+    -e 's/(import (chez-qt ffi) (chez-qt qt))/(import (jerboa-qt ffi) (jerboa-qt qt))/'
   echo "patch-jerboa-qt-compat: compile-libs.ss imports jerboa-qt"
 fi
 
@@ -39,10 +46,9 @@ fi
 # string-split/string-join excepted from prelude).
 if grep -q 'make-date make-time meta atom?' "$qtsls" \
    && grep -q '(except (jerboa prelude) string-split string-join)' "$qtsls"; then
-  sed -i \
+  sed_in_place "$qtsls" \
     -e 's/make-date make-time meta atom?/make-date meta atom?/' \
-    -e 's/(except (jerboa prelude) string-split string-join)/(except (jerboa prelude) string-split string-join make-time)/' \
-    "$qtsls"
+    -e 's/(except (jerboa prelude) string-split string-join)/(except (jerboa prelude) string-split string-join make-time)/'
   echo "patch-jerboa-qt-compat: qt-app-exec! sleep now uses Chez make-time"
 else
   echo "patch-jerboa-qt-compat: qt.sls not in expected form; left unchanged" >&2
diff --git a/scripts/patch-static-load-shared.sh b/scripts/patch-static-load-shared.sh
index 889a753..54c50d6 100755
--- a/scripts/patch-static-load-shared.sh
+++ b/scripts/patch-static-load-shared.sh
@@ -52,6 +52,16 @@ find "$dir" \( -name '*.ss' -o -name '*.sls' \) -print | while IFS= read -r f; d
     "$f"
 done
 
+# Computed shim paths used by dependency libraries. pcre2 still needs to load
+# its shim during the compile step when the static binary symbols are not
+# present, but must skip dlopen once the symbols are linked into jemacs.
+find "$dir" \( -name '*.ss' -o -name '*.sls' \) -print | while IFS= read -r f; do
+  perl -0777 -pi \
+    -e 's/\(def shim-loaded\s+\(load-shared-object\s+\(let \(\[env \(getenv "JERBOA_PCRE2_LIB"\)\]\)\s+\(if env\s+\(string-append env "\/jerboa_pcre2_shim\." shlib-ext\)\s+\(string-append "jerboa_pcre2_shim\." shlib-ext\)\)\)\)\)/(def shim-loaded\n    (if (foreign-entry? "jerboa_pcre2_compile")\n        #t\n        (load-shared-object\n          (let ([env (getenv "JERBOA_PCRE2_LIB")])\n            (if env\n                (string-append env "\/jerboa_pcre2_shim." shlib-ext)\n                (string-append "jerboa_pcre2_shim." shlib-ext))))))/gs;' \
+    -e 's{\(load-shared-object\s+\(format "~a/jerboa_scintilla_shim\.~a" shim-dir shlib-ext\)\)}{(if (getenv "JEMACS_STATIC") #f (load-shared-object (format "~a/jerboa_scintilla_shim.~a" shim-dir shlib-ext)))}gs' \
+    "$f"
+done
+
 # Variable-argument init-time loads the literal patterns miss. These iterate a
 # list whose first element is #f / a libc path (std os errno) or take the path
 # from a macro pattern var (std foreign bind). Wrap each so it is skipped when
diff --git a/support/vendor-overrides/jerboa-pcre2-compile-libs.ss b/support/vendor-overrides/jerboa-pcre2-compile-libs.ss
new file mode 100644
index 0000000..909bdb1
--- /dev/null
+++ b/support/vendor-overrides/jerboa-pcre2-compile-libs.ss
@@ -0,0 +1 @@
+(import (jerboa-pcre2 pcre2))
diff --git a/support/vendor-overrides/jerboa-scintilla-compile-libs.ss b/support/vendor-overrides/jerboa-scintilla-compile-libs.ss
new file mode 100644
index 0000000..b492ae9
--- /dev/null
+++ b/support/vendor-overrides/jerboa-scintilla-compile-libs.ss
@@ -0,0 +1,5 @@
+(import (jerboa-scintilla constants)
+        (jerboa-scintilla ffi)
+        (jerboa-scintilla scintilla)
+        (jerboa-scintilla style)
+        (jerboa-scintilla tui))