Skip to content

Commit 91ec974

Browse files
committed
feat: update build scripts for native JRE creation and improve Dockerfile for Linux compatibility
1 parent e8d008e commit 91ec974

5 files changed

Lines changed: 71 additions & 69 deletions

File tree

bindings/python/docs/development/build-architecture.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ arcadedb-ha-raft-*.jar
179179

180180
1. `.github/workflows/test-python-bindings.yml` (download-jars job)
181181
2. `bindings/python/scripts/Dockerfile.build` (Docker builds)
182-
3. `bindings/python/scripts/setup_jars.py` (documentation/validation)
182+
3. `bindings/python/scripts/build-native.sh` (native builds)
183183

184184
**Result:** The wheel excludes optional Java components that are not part of the default Python distribution.
185185

@@ -189,7 +189,6 @@ arcadedb-ha-raft-*.jar
189189

190190
- `scripts/build-native.sh`: Filtered with bash on macOS
191191
- `scripts/Dockerfile.build`: Filtered with bash on Linux
192-
- `scripts/setup_jars.py`: Filtered with Python glob
193192
- **Problem:** Glob patterns varied across shells, causing duplication and inconsistency
194193

195194
**After (Fixed):** Single upstream filter
@@ -264,22 +263,27 @@ else
264263
download_jars_from_docker
265264
fi
266265

267-
# 2. Create platform-specific JRE via jlink
266+
# 2. Apply jar_exclusions.txt (CRLF-safe on Windows)
267+
268+
# 3. Create platform-specific JRE via jlink
268269
jlink --output jre \
269270
--add-modules "$MODULES" \
270271
--strip-debug \
271272
--no-man-pages \
272273
--no-header-files \
273274
--compress zip-6
274275

275-
# 3. Copy JARs and JRE to package
276-
python scripts/setup_jars.py
276+
# 4. Remove Windows-only non-runtime artifacts when needed
277+
278+
# 5. Stage JRE into src/arcadedb_embedded/jre
277279

278-
# 4. Build wheel
280+
# 6. Build wheel
279281
python -m build --wheel
280282
```
281283

282-
**Simplification:** Removed ~30 lines of JAR filtering logic (now uses pre-filtered artifact)
284+
**Current behavior:** Native builds prefer the pre-filtered JAR artifact from CI, but still
285+
re-apply `jar_exclusions.txt` locally so fallback Docker downloads and Windows checkouts remain
286+
consistent.
283287

284288
## GitHub ARM64 Runners (linux/arm64)
285289

bindings/python/docs/development/contributing.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ arcadedb/bindings/python/
173173

174174
```bash
175175
# Build the current package
176-
./scripts/build.sh base
176+
./scripts/build.sh
177177

178178
# Output: dist/*.whl
179179
```
@@ -182,18 +182,19 @@ arcadedb/bindings/python/
182182

183183
1. Extracts ArcadeDB version from parent `pom.xml`
184184
2. Downloads appropriate JAR files with custom filtering
185-
3. Packages Python code with optimized JARs (see `scripts/jar_exclusions.txt`)
185+
3. Creates a bundled platform-specific JRE and stages optimized JARs (see `scripts/jar_exclusions.txt`)
186186
4. Runs tests in isolated Docker environment
187187
5. Creates wheel file in `dist/`
188188

189189
### Local Build
190190

191191
```bash
192-
# Download JARs with custom filtering
193-
python scripts/setup_jars.py
192+
# Build for the current platform
193+
./scripts/build.sh
194194

195-
# Build wheel
196-
python -m build
195+
# Or target a specific supported platform on matching native hardware
196+
./scripts/build.sh darwin/arm64 3.12
197+
./scripts/build.sh windows/amd64 3.12
197198

198199
# Install locally
199200
uv pip install dist/*.whl

bindings/python/scripts/Dockerfile.build

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
# PYTHON_VERSION - Python version for wheel (e.g., 3.11, 3.12, 3.13, 3.14)
77
# PACKAGE_NAME - always: arcadedb-embedded
88
# PACKAGE_DESCRIPTION - package description
9-
# TARGET_PLATFORM - target platform for JRE (e.g., linux-x64, linux-arm64, darwin-x64)
9+
# TARGET_PLATFORM - Linux target platform for bundled JRE (linux-x64, linux-arm64)
1010

1111
ARG PYTHON_VERSION=3.12
1212
ARG PACKAGE_NAME=arcadedb-embedded
1313
ARG PACKAGE_DESCRIPTION="ArcadeDB embedded multi-model database with bundled JRE - no Java installation required"
14-
ARG ARCADEDB_TAG
14+
ARG ARCADEDB_TAG=latest
1515
ARG TARGET_PLATFORM=linux-x64
1616
# When set to 1, prefer jars provided in bindings/python/local-jars/lib from the build context.
1717
# If no local jars are present, the build fails fast to avoid silently falling back.
@@ -25,6 +25,7 @@ FROM arcadedata/arcadedb:${ARCADEDB_TAG} AS java-builder
2525
# nothing to do here; jars will be copied from /home/arcadedb/lib in the python-builder stage
2626

2727
# Stage 2: Build minimal JRE with jlink
28+
# Docker builds are Linux-only. macOS/Windows JREs must be created on matching native hosts.
2829
FROM amazoncorretto:25 AS jre-builder
2930

3031
# Install required tooling (findutils for jar exclusion, binutils for jlink)
@@ -34,6 +35,11 @@ ARG TARGET_PLATFORM
3435
ARG USE_LOCAL_JARS
3536
ARG LOCAL_JARS_HASH
3637

38+
RUN case "$TARGET_PLATFORM" in \
39+
linux-x64|linux-arm64) ;; \
40+
*) echo "❌ Dockerfile.build only supports Linux TARGET_PLATFORM values (got: $TARGET_PLATFORM)" && exit 1 ;; \
41+
esac
42+
3743
WORKDIR /build
3844

3945
# Stash upstream jars from the ArcadeDB image
@@ -145,8 +151,6 @@ FROM python:${PYTHON_VERSION}-slim AS python-builder
145151
RUN apt-get update && apt-get install -y \
146152
build-essential \
147153
curl \
148-
file \
149-
patchelf \
150154
&& rm -rf /var/lib/apt/lists/*
151155

152156
# Install uv for faster, deterministic installs
@@ -156,7 +160,6 @@ RUN curl -LsSf https://astral.sh/uv/install.sh | sh && uv --version
156160
WORKDIR /build
157161

158162
# Copy filtered JARs from jre-builder (already has exclusions applied)
159-
RUN mkdir -p /build/jars
160163
COPY --from=jre-builder /build/jars /build/jars/
161164

162165
# Copy JRE from jre-builder stage
@@ -170,15 +173,14 @@ COPY bindings/python/scripts/setup_jars.py ./scripts/
170173
COPY bindings/python/scripts/extract_version.py ./scripts/
171174
COPY bindings/python/scripts/write_version.py ./scripts/
172175
COPY bindings/python/scripts/verify_wheel_platform_tag.py ./scripts/
173-
COPY bindings/python/scripts/jar_exclusions.txt .
174176
COPY bindings/python/pyproject.toml ./
175177
COPY bindings/python/README.md ./
176178

177179
# Also copy repository pom.xml so scripts/extract_version.py can read it
178180
COPY ../../pom.xml /arcadedb/pom.xml
179181

180182
# Install Python build dependencies
181-
RUN uv pip install --system build wheel setuptools jpype1 auditwheel
183+
RUN uv pip install --system build wheel setuptools jpype1
182184

183185
# Re-declare build args for this stage (required after FROM)
184186
ARG PACKAGE_NAME

bindings/python/scripts/build-native.sh

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ apply_jar_exclusions() {
5757
echo -e "${CYAN}📋 JAR count before exclusion: ${YELLOW}$(count_jars "$jars_dir")${NC}"
5858

5959
while IFS= read -r pattern; do
60+
pattern="${pattern%$'\r'}"
61+
6062
if [[ -z "$pattern" ]] || [[ "${pattern#\#}" != "$pattern" ]]; then
6163
continue
6264
fi
@@ -113,33 +115,6 @@ shutil.copytree(src, dest, symlinks=True)
113115
PY
114116
}
115117

116-
print_windows_jre_diagnostics() {
117-
local jre_dir="$1"
118-
local python_bin="$2"
119-
local label="$3"
120-
121-
echo -e "${CYAN}🔎 Windows JRE diagnostics (${label})...${NC}"
122-
123-
"$python_bin" - "$jre_dir" << 'PY'
124-
import os
125-
import sys
126-
from pathlib import Path
127-
128-
jre_dir = Path(sys.argv[1])
129-
files = [path for path in jre_dir.rglob('*') if path.is_file()]
130-
symlinks = [path for path in jre_dir.rglob('*') if path.is_symlink()]
131-
132-
print(f" Files: {len(files)}")
133-
print(f" Symlinks: {len(symlinks)}")
134-
135-
largest = sorted(files, key=lambda path: path.stat().st_size, reverse=True)[:15]
136-
for path in largest:
137-
size_mb = path.stat().st_size / 1024 / 1024
138-
rel_path = path.relative_to(jre_dir)
139-
print(f" {size_mb:8.1f} MB {rel_path}")
140-
PY
141-
}
142-
143118
# Check for Java (needed for jlink and JPype build)
144119
if ! command -v java &> /dev/null; then
145120
echo -e "${RED}❌ Java not found${NC}"
@@ -292,21 +267,14 @@ if [[ "$PLATFORM" == windows/* ]]; then
292267
prune_windows_jre_artifacts "$PY_BINDINGS_DIR/temp_jre"
293268
JRE_SIZE=$(du -sh "$PY_BINDINGS_DIR/temp_jre" | cut -f1)
294269
echo -e "${CYAN}📊 JRE size after Windows cleanup: ${YELLOW}${JRE_SIZE}${NC}"
295-
print_windows_jre_diagnostics "$PY_BINDINGS_DIR/temp_jre" "$PYTHON_WITH_BUILD" "temp_jre"
296270
fi
297271

298272
# Step 3: Copy JRE to package (JARs already filtered in place)
299273
echo -e "${CYAN}📦 Preparing package...${NC}"
300274

301275
# Build and copy JRE
302-
rm -rf "$PY_BINDINGS_DIR/src/arcadedb_embedded/jre"
303-
mkdir -p "$PY_BINDINGS_DIR/src/arcadedb_embedded/jre"
304276
copy_tree_with_symlinks "$PY_BINDINGS_DIR/temp_jre" "$PY_BINDINGS_DIR/src/arcadedb_embedded/jre" "$PYTHON_WITH_BUILD"
305277

306-
if [[ "$PLATFORM" == windows/* ]]; then
307-
print_windows_jre_diagnostics "$PY_BINDINGS_DIR/src/arcadedb_embedded/jre" "$PYTHON_WITH_BUILD" "staged package jre"
308-
fi
309-
310278
JAR_COUNT=$(ls -1 "$JARS_DIR"/*.jar | wc -l)
311279
echo -e "${GREEN}✅ Package prepared (${JAR_COUNT} JARs + JRE)${NC}"
312280

bindings/python/scripts/build.sh

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ JAR_LIB_DIR="${3:-}"
3333

3434
print_header() {
3535
echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
36-
echo -e "${BLUE}║ 🎮 ArcadeDB Python Package - Docker Build Script ║${NC}"
36+
echo -e "${BLUE}║ 🎮 ArcadeDB Python Package - Build Script ${NC}"
3737
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
3838
echo ""
3939
}
@@ -60,7 +60,7 @@ print_usage() {
6060
echo " If omitted, JARs are pulled from arcadedata/arcadedb:<version>"
6161
echo ""
6262
echo "Build Methods:"
63-
echo " Native: macOS builds natively on its platform"
63+
echo " Native: macOS/Windows build on matching native host architecture"
6464
echo " Docker: Linux uses Docker for manylinux compliance"
6565
echo ""
6666
echo "Examples:"
@@ -74,10 +74,24 @@ print_usage() {
7474
echo " ✅ Bundled platform-specific JRE (no Java required)"
7575
echo " ✅ Optimized JAR selection (see scripts/jar_exclusions.txt)"
7676
echo " ✅ Multi-platform support (4 platforms)"
77-
echo " 📦 Size: ~215MB (compressed), ~289MB (installed)"
77+
echo " 📦 Size varies by platform/version; see CI summaries for current numbers"
7878
echo ""
7979
}
8080

81+
normalize_arch() {
82+
case "$1" in
83+
x86_64 | amd64)
84+
echo "amd64"
85+
;;
86+
aarch64 | arm64)
87+
echo "arm64"
88+
;;
89+
*)
90+
echo "$1"
91+
;;
92+
esac
93+
}
94+
8195
# Check for help flag
8296
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
8397
print_header
@@ -176,15 +190,35 @@ fi
176190
# Use native build if we're already on the target platform
177191
CURRENT_OS="$(uname -s)"
178192
CURRENT_ARCH="$(uname -m)"
193+
CURRENT_ARCH_NORMALIZED="$(normalize_arch "$CURRENT_ARCH")"
194+
TARGET_OS="${PLATFORM%%/*}"
195+
TARGET_ARCH="${PLATFORM##*/}"
179196

180197
USE_NATIVE=false
181-
if [[ "$PLATFORM" == "darwin/"* ]] && [[ "$CURRENT_OS" == "Darwin" ]]; then
198+
if [[ "$TARGET_OS" == "darwin" ]]; then
199+
if [[ "$CURRENT_OS" != "Darwin" ]]; then
200+
echo -e "${RED}${PLATFORM} builds require a native macOS host${NC}"
201+
echo -e "${YELLOW}💡 jlink can only create a macOS JRE when run on macOS${NC}"
202+
exit 1
203+
fi
204+
if [[ "$CURRENT_ARCH_NORMALIZED" != "$TARGET_ARCH" ]]; then
205+
echo -e "${RED}${PLATFORM} builds require a matching native macOS architecture${NC}"
206+
echo -e "${YELLOW}💡 Host architecture: ${CURRENT_ARCH_NORMALIZED}; target architecture: ${TARGET_ARCH}${NC}"
207+
exit 1
208+
fi
182209
USE_NATIVE=true
183-
elif [[ "$PLATFORM" == "windows/"* ]] && [[ "$CURRENT_OS" == MINGW* || "$CURRENT_OS" == MSYS* || "$CURRENT_OS" == CYGWIN* ]]; then
210+
elif [[ "$TARGET_OS" == "windows" ]]; then
211+
if [[ "$CURRENT_OS" != MINGW* && "$CURRENT_OS" != MSYS* && "$CURRENT_OS" != CYGWIN* ]]; then
212+
echo -e "${RED}${PLATFORM} builds require a native Windows host${NC}"
213+
echo -e "${YELLOW}💡 jlink can only create a Windows JRE when run on Windows${NC}"
214+
exit 1
215+
fi
216+
if [[ "$CURRENT_ARCH_NORMALIZED" != "$TARGET_ARCH" ]]; then
217+
echo -e "${RED}${PLATFORM} builds require a matching native Windows architecture${NC}"
218+
echo -e "${YELLOW}💡 Host architecture: ${CURRENT_ARCH_NORMALIZED}; target architecture: ${TARGET_ARCH}${NC}"
219+
exit 1
220+
fi
184221
USE_NATIVE=true
185-
elif [[ "$PLATFORM" == "linux/amd64" ]] && [[ "$CURRENT_OS" == "Linux" ]] && [[ "$CURRENT_ARCH" == "x86_64" ]]; then
186-
# For Linux, still use Docker for reproducibility (manylinux compliance)
187-
USE_NATIVE=false
188222
fi
189223

190224
BUILD_METHOD="Docker"
@@ -258,13 +292,6 @@ else
258292
# Determine Docker build platform (always Linux for cross-compilation)
259293
# We build ON linux/amd64 or linux/arm64, but FOR any target platform
260294
DOCKER_PLATFORM="${PLATFORM}"
261-
if [[ "$PLATFORM" == darwin/* ]] || [[ "$PLATFORM" == windows/* ]]; then
262-
# Cross-compiling for macOS/Windows - build on Linux
263-
DOCKER_PLATFORM="linux/amd64"
264-
echo -e "${CYAN}🔧 Cross-compiling: Building on linux/amd64 for ${YELLOW}${PLATFORM}${NC}"
265-
echo ""
266-
fi
267-
268295
# Build Docker image
269296
echo -e "${CYAN}📦 Building Docker image...${NC}"
270297

0 commit comments

Comments
 (0)