diff --git a/.docker/core-wasm.bake.Dockerfile b/.docker/core-wasm.bake.Dockerfile index e1602acda5..20a9816cc6 100644 --- a/.docker/core-wasm.bake.Dockerfile +++ b/.docker/core-wasm.bake.Dockerfile @@ -8,7 +8,7 @@ # ============================================================================== #### CORE WASM #### -FROM emscripten/emsdk:3.1.48 AS core-wasm +FROM emscripten/emsdk:5.0.4 AS core-wasm ARG BUILD_ROOT ARG CACHE_BUST ARG NUGET_SOURCE_PATH diff --git a/Common/3dParty/boost/hashes.txt b/Common/3dParty/boost/hashes.txt index 6115d5e55a..f581529f3e 100644 --- a/Common/3dParty/boost/hashes.txt +++ b/Common/3dParty/boost/hashes.txt @@ -1 +1,2 @@ 1.72|x64-linux-dynamic|c3e6bcec18bbfbd31529d63fdf4214c6cee72044fdb8a617121e7ebbb18f2d53a7026477e1f7566153469b52a2a065c865537c31120caa66299eb61ea6c8e322 +1.72|arm64-linux-dynamic|6261c6f97632af02e92c5401e8757919c82f0a1a204ef54342e601c8b4af92492c7c4faa55b1f7ac8c2e2e097dd339a989fb7939866adf83a00b7e5c0de38234 diff --git a/Common/3dParty/boost/tools/1.72/arm64-linux-dynamic b/Common/3dParty/boost/tools/1.72/arm64-linux-dynamic new file mode 120000 index 0000000000..d7fc53bd40 --- /dev/null +++ b/Common/3dParty/boost/tools/1.72/arm64-linux-dynamic @@ -0,0 +1 @@ +x64-linux-dynamic/ \ No newline at end of file diff --git a/Common/3dParty/v8/hashes.txt b/Common/3dParty/v8/hashes.txt index c842bf293e..4ad667f740 100644 --- a/Common/3dParty/v8/hashes.txt +++ b/Common/3dParty/v8/hashes.txt @@ -1 +1,2 @@ 8.9|x64-linux-dynamic|60a740e3818c3d430920e0938ba4974458fe687d819353020334f63ecbbd59fbbc59077d0ba9e4df00deb2abc2eaf5bcabdeddc9ddf010e4609992022692a9ca +8.9|arm64-linux-dynamic|ed40470e3ea7fd23d127bb2ab1ec396848c8449bf29e5c31c76bdfffffa84faa4b1177ad07f69fe5952baa023a4305e90a04965b54a8564c27de5c59c852daea diff --git a/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/Dockerfile b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/Dockerfile new file mode 100644 index 0000000000..c45828d1f5 --- /dev/null +++ b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/Dockerfile @@ -0,0 +1,89 @@ +FROM ubuntu:22.04 AS v8-builder + ENV DEBIAN_FRONTEND=noninteractive + ENV CC=clang-13 + ENV CXX=clang++-13 + + # 1. Install system dependencies and Python 3.11 + RUN apt-get update && apt-get install -y software-properties-common && \ + add-apt-repository ppa:deadsnakes/ppa && \ + apt-get update && apt-get install -y \ + bash \ + git \ + python3.11 \ + python3.11-dev \ + python3.11-distutils \ + python3.11-venv \ + lsb-release \ + sudo \ + curl \ + wget \ + xz-utils \ + pkg-config \ + build-essential \ + ninja-build \ + libstdc++6 \ + libglib2.0-dev + + # 2. Install Pip specifically for Python 3.11 + RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.11 + + # 3. Install httplib2 for Python 3.11 + RUN python3.11 -m pip install httplib2 + + # 4. Set Python 3.11 as the default 'python' and 'python3' command + RUN ln -sf /usr/bin/python3.11 /usr/bin/python3 && \ + ln -sf /usr/bin/python3.11 /usr/bin/python + + # Install clang-13 and LLVM tools for V8 9.x build + RUN mkdir -p /etc/apt/keyrings && \ + wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor -o /etc/apt/keyrings/llvm-snapshot.gpg && \ + echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-13 main" \ + > /etc/apt/sources.list.d/llvm-13.list && \ + apt-get update && apt-get install -y \ + clang-13 lld-13 llvm-13-dev llvm-13 \ + libc++-13-dev libc++abi-13-dev \ + qemu-user-static binfmt-support && \ + rm -rf /var/lib/apt/lists/* + + + # Set clang-13 as default + RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-13 100 && \ + update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-13 100 && \ + update-alternatives --install /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-13 100 && \ + update-alternatives --install /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-13 100 && \ + update-alternatives --install /usr/bin/llvm-ranlib llvm-ranlib /usr/bin/llvm-ranlib-13 100 && \ + update-alternatives --install /usr/bin/lld lld /usr/bin/lld-13 100 && \ + update-alternatives --set clang /usr/bin/clang-13 && \ + update-alternatives --set clang++ /usr/bin/clang++-13 && \ + update-alternatives --set lld /usr/bin/lld-13 && \ + update-alternatives --set llvm-ar /usr/bin/llvm-ar-13 && \ + update-alternatives --set llvm-nm /usr/bin/llvm-nm-13 && \ + update-alternatives --set llvm-ranlib /usr/bin/llvm-ranlib-13 + + # Verify clang version + RUN clang-13 --version && \ + clang --version && \ + clang-13 --version | head -n1 | grep -q "clang version 13" || exit 1 && \ + clang --version | head -n1 | grep -q "clang version 13" || exit 1 + + # 2. Set up working directories + WORKDIR /build-context + COPY nc-build.sh nc-build.sh + + COPY ./jinja2.patch jinja2.patch + COPY ./gclient_paths.patch gclient_paths.patch + COPY ./buildgn.patch buildgn.patch + COPY ./bootstrap.patch bootstrap.patch + + # Ensure the script is executable + RUN chmod +x ./nc-build.sh + + # 3. Run the build script + # Arguments: /tmp/v8_work (temp build files) and /opt/v8 (final destination) + RUN ./nc-build.sh /tmp/v8_work /build/v8 + + + RUN tar -cjf /v8_binary.tar.bz2 /build/v8 + +FROM scratch AS artifacts + COPY --from=v8-builder /v8_binary.tar.bz2 / diff --git a/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/bootstrap.patch b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/bootstrap.patch new file mode 100644 index 0000000000..63ea886763 --- /dev/null +++ b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/bootstrap.patch @@ -0,0 +1,56 @@ +diff --git a/bootstrap/bootstrap.py b/bootstrap/bootstrap.py +index 8d9592938..7eb53dbd1 100644 +--- a/bootstrap/bootstrap.py ++++ b/bootstrap/bootstrap.py +@@ -200,7 +200,8 @@ def _check_call(argv, stdin_input=None, **kwargs): + proc = subprocess.Popen(argv, **kwargs) + stdout, stderr = proc.communicate(input=stdin_input) + if proc.returncode: +- raise subprocess.CalledProcessError(proc.returncode, argv, None) ++ # raise subprocess.CalledProcessError(proc.returncode, argv, None) ++ return + return stdout, stderr + + +@@ -461,7 +462,7 @@ def git_postprocess(template): + os.path.join(ROOT_DIR, stub_name)) + + # Bootstrap the git global config. +- _win_git_bootstrap_config() ++ # _win_git_bootstrap_config() + + + def main(argv): +diff --git a/bootstrap/manifest.txt b/bootstrap/manifest.txt +index 61fcb267c..3a6e39bed 100644 +--- a/bootstrap/manifest.txt ++++ b/bootstrap/manifest.txt +@@ -1,21 +1,10 @@ +-# CIPD manifest for bootstrapping tools. +-# +-# We must install anything that we want included on PATH to a different +-# subdirectory than Git, as Git's msys bash strips its root directory +-# from PATH, hence the subdirs. +-# +-# If any paths or package layouts change, updates will be required in +-# "win_tools.bat", "bootstrap.py" and "../bootstrap_python3" templates. +-# +-# "win_tools.bat" has a hard requirement that the Python packages contain the +-# string "cpython3/" for Python 3, and ends with the CIPD tag "version:VERSION". +-# It uses this to extract VERSION. +-# +-# "bootstrap_python3" has a hard requirement that the Python package contains +-# the string "cpython3/" and ends with the CIPD tag "version:VERSION". +-# It uses this to extract VERSION. +- + $VerifiedPlatform windows-amd64 windows-arm64 linux-amd64 mac-amd64 mac-arm64 + ++@Subdir python ++infra/3pp/tools/cpython/${platform} version:2@2.7.18.chromium.39 ++ + @Subdir python3 +-infra/3pp/tools/cpython3/${platform} version:2@3.11.8.chromium.35 ++infra/3pp/tools/cpython3/${platform} version:2@3.8.10.chromium.23 ++ ++@Subdir git ++infra/3pp/tools/git/${platform} version:2@2.41.0.chromium.11 diff --git a/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/buildgn.patch b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/buildgn.patch new file mode 100644 index 0000000000..f0d1992789 --- /dev/null +++ b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/buildgn.patch @@ -0,0 +1,13 @@ +diff --git a/BUILD.gn b/BUILD.gn +index f39529a3a95..d4781238201 100644 +--- a/BUILD.gn ++++ b/BUILD.gn +@@ -714,7 +714,7 @@ config("toolchain") { + visibility = [ "./*" ] + + defines = [] +- cflags = [] ++ cflags = ["-include", "cstdint"] + ldflags = [] + + if (v8_current_cpu == "arm") { diff --git a/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/gclient_paths.patch b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/gclient_paths.patch new file mode 100644 index 0000000000..9ad45c8823 --- /dev/null +++ b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/gclient_paths.patch @@ -0,0 +1,40 @@ +diff --git a/gclient_paths.py b/gclient_paths.py +index bd4d05b15..6cfe2118e 100644 +--- a/gclient_paths.py ++++ b/gclient_paths.py +@@ -20,7 +20,7 @@ import subprocess2 + # pylint: disable=line-too-long + + +-@functools.lru_cache ++ + def FindGclientRoot(from_dir, filename='.gclient'): + """Tries to find the gclient root.""" + real_from_dir = os.path.abspath(from_dir) +@@ -73,7 +73,7 @@ def FindGclientRoot(from_dir, filename='.gclient'): + return None + + +-@functools.lru_cache ++ + def _GetPrimarySolutionPathInternal(cwd): + gclient_root = FindGclientRoot(cwd) + if gclient_root: +@@ -107,7 +107,7 @@ def GetPrimarySolutionPath(from_dir=None): + return _GetPrimarySolutionPathInternal(from_dir) + + +-@functools.lru_cache ++ + def _GetBuildtoolsPathInternal(cwd, override): + if override is not None: + return override +@@ -162,7 +162,7 @@ def GetExeSuffix(): + return '' + + +-@functools.lru_cache ++ + def _GetGClientSolutions(gclient_root_dir_path): + gclient_config_file = os.path.join(gclient_root_dir_path, '.gclient') + gclient_config_contents = gclient_utils.FileRead(gclient_config_file) diff --git a/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/jinja2.patch b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/jinja2.patch new file mode 100644 index 0000000000..a10bcb8201 --- /dev/null +++ b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/jinja2.patch @@ -0,0 +1,16 @@ +diff --git a/tests.py b/tests.py +index 0adc3d4..56ed431 100644 +--- a/tests.py ++++ b/tests.py +@@ -10,7 +10,10 @@ + """ + import operator + import re +-from collections import Mapping ++try: ++ from collections.abc import Mapping ++except ImportError: ++ from collections import Mapping + from jinja2.runtime import Undefined + from jinja2._compat import text_type, string_types, integer_types + import decimal diff --git a/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/nc-build.sh b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/nc-build.sh new file mode 100755 index 0000000000..3c796dbbc9 --- /dev/null +++ b/Common/3dParty/v8/tools/8.9/arm64-linux-dynamic/nc-build.sh @@ -0,0 +1,453 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +if [ $# -lt 2 ]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +work_dir="$1" +install_dir="$2" +TARGETARCH="arm64" + +script_dir="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" +patches_dir="$script_dir" + +log() { echo "[v8-build] $*"; } +abort_op() { echo "v8 aborted: $1" >&2; exit 1; } + +retry() { + local tries=$1; shift + local n=1 + until "$@"; do + if (( n >= tries )); then + echo "Command failed after $n attempts: $*" >&2 + return 1 + fi + sleep $((n*5)) + ((n++)) + done +} + +# ---------- System Check ---------- +log "Checking system requirements..." + +if ! command -v git &> /dev/null; then + abort_op "git not found - install with: apt-get install git" +fi + +if ! command -v python3 &> /dev/null; then + abort_op "python3 not found - install with: apt-get install python3" +fi + +if ! command -v clang &> /dev/null; then + abort_op "clang not found - install with: apt-get install clang lld" +fi + +if ! command -v ninja &> /dev/null; then + abort_op "ninja not found - install with: apt-get install ninja-build" +fi + +mkdir -p "$work_dir" "$install_dir" +cd "$work_dir" + +# ---------- Force bash as shell ---------- +export SHELL=/bin/bash +export CONFIG_SHELL=/bin/bash + +# ---------- depot_tools ---------- +export DEPOT_TOOLS="$work_dir/depot_tools" +export PATH="$DEPOT_TOOLS:$PATH" +export VPYTHON_BYPASS="manually managed python not supported by chrome operations" +export GCLIENT_SUPPRESS_GIT_VERSION_WARNING=1 +export GYP_CHROMIUM_NO_ACTION=1 + +if [ ! -d "$DEPOT_TOOLS" ]; then + log "Cloning depot_tools..." + retry 3 git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git "$DEPOT_TOOLS" \ + || abort_op "clone depot_tools failed" +fi + +# Update depot_tools +cd "$DEPOT_TOOLS" +git pull origin main || log "depot_tools update failed (non-fatal)" +cd "$work_dir" + +# ---------- fetch V8 ---------- +V8_ROOT="$work_dir/v8" +V8_SRC="$V8_ROOT/v8" + +mkdir -p "$V8_ROOT" +cd "$V8_ROOT" + +# Clean up previous gclient state +rm -f .gclient .gclient_entries +rm -rf _bad_scm chromium.googlesource.com + +if [ ! -d "v8" ]; then + log "Cloning V8 8.9.45 (for Euro-Office)..." + retry 3 git clone https://chromium.googlesource.com/v8/v8.git v8 \ + || abort_op "git clone v8 failed" + cd v8 + git checkout 8.9.45 || abort_op "Failed to checkout V8 8.9.45" + cd .. +else + log "V8 directory exists, resetting to clean state..." + cd v8 + git reset --hard + git clean -fdx + git fetch origin + git checkout 8.9.45 || abort_op "Failed to checkout V8 8.9.45" + cd .. +fi + +# Create .gclient configuration +cat > .gclient <<'EOF' +solutions = [ + { + "name": "v8", + "url": "https://chromium.googlesource.com/v8/v8.git", + "deps_file": "DEPS", + "managed": False, + "custom_deps": {}, + }, +] +target_os = ["linux"] +EOF + +log "Syncing V8 dependencies..." + +# Clean any uncommitted changes before sync +if [ -d "$V8_SRC" ]; then + log "Cleaning V8 directories before sync..." + git -C "$V8_SRC" reset --hard 2>/dev/null || true + git -C "$V8_SRC" clean -fd 2>/dev/null || true +fi + +if [ -d "$V8_SRC/third_party/jinja2" ]; then + git -C "$V8_SRC/third_party/jinja2" reset --hard 2>/dev/null || true + git -C "$V8_SRC/third_party/jinja2" clean -fd 2>/dev/null || true +fi + +if [ -d "$DEPOT_TOOLS" ]; then + git -C "$DEPOT_TOOLS" reset --hard 2>/dev/null || true + git -C "$DEPOT_TOOLS" clean -fd 2>/dev/null || true +fi + +retry 3 gclient sync --no-history --shallow \ + || abort_op "gclient sync failed" + +cd "$V8_SRC" + +# ---------- apply patches AFTER gclient sync ---------- +apply_patch() { + local dir="$1" + local patch="$2" + + [ -f "$patch" ] || { log "Patch not found: $patch (skipping)"; return 0; } + + if git -C "$dir" apply --check "$patch" >/dev/null 2>&1; then + log "Applying patch: $patch" + git -C "$dir" apply "$patch" + else + log "Patch already applied or not applicable: $patch" + fi +} + +if [ -f "$patches_dir/gclient_paths.patch" ]; then + apply_patch "$DEPOT_TOOLS" "$patches_dir/gclient_paths.patch" +fi + +if [ -f "$patches_dir/jinja2.patch" ]; then + apply_patch "$V8_SRC/third_party/jinja2" "$patches_dir/jinja2.patch" +fi + +if [ -f "$patches_dir/buildgn.patch" ]; then + apply_patch "$V8_SRC" "$patches_dir/buildgn.patch" +fi + +# ---------- Disable gmock to avoid visibility errors ---------- +log "Disabling gmock to avoid visibility errors..." + +GMOCK_BUILD="$V8_SRC/testing/gmock/BUILD.gn" +if [ -f "$GMOCK_BUILD" ]; then + # Replace the problematic source_set with an empty group + cat > "$GMOCK_BUILD" <<'GMOCK_EOF' +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Disabled to avoid visibility issues with gtest_config +# V8 monolithic build doesn't need gmock + +import("//build_overrides/build.gni") + +group("gmock") { + testonly = true +} + +group("gmock_main") { + testonly = true +} +GMOCK_EOF + log "Disabled gmock target" +fi + +# ---------- Disable cppgc to avoid build errors ---------- +log "Disabling cppgc build..." + +CPPGC_BUILD="$V8_SRC/src/heap/cppgc/BUILD.gn" +if [ -f "$CPPGC_BUILD" ]; then + # Replace with minimal stub + cat > "$CPPGC_BUILD" <<'CPPGC_EOF' +# Copyright 2020 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Disabled to avoid ARM64 toolchain issues + +import("//build/config/sanitizers/sanitizers.gni") +import("../../gni/v8.gni") + +group("cppgc_base") { + visibility = [ ":*" ] +} + +group("cppgc_base_for_testing") { + testonly = true + visibility = [ ":*" ] +} +CPPGC_EOF + log "Replaced cppgc BUILD.gn with stub" +fi + +# ---------- GN Setup ---------- +log "Building GN from source (finding compatible commit)..." + +GN_SRC="$work_dir/gn-source" +rm -rf "$GN_SRC" +git clone https://gn.googlesource.com/gn "$GN_SRC" \ + || abort_op "Failed to clone GN" +cd "$GN_SRC" + +# Finde letzten Commit ohne C++20 Features (starts_with, ends_with, ranges::) +log "Searching for last C++17-compatible GN commit..." +GN_BIN="" +while IFS= read -r commit; do + git checkout -q "$commit" 2>/dev/null || continue + if ! grep -rq \ + "std::ranges::\|\.starts_with(\|\.ends_with(\|std::span\b" \ + src/gn/*.cc src/gn/*.h 2>/dev/null; then + log "Found compatible commit: $commit ($(git log -1 --format='%ci' $commit))" + break + fi +done < <(git log --format="%H" --before="2022-01-01") + +CC=clang-13 CXX=clang++-13 python3 build/gen.py --no-last-commit-position + +# Der Compiler sucht last_commit_position.h via -I. (= out/ Verzeichnis) +mkdir -p out +cat > out/last_commit_position.h <<'LCHEOF' +#pragma once +#define LAST_COMMIT_POSITION_NUM 0 +#define LAST_COMMIT_POSITION "0 (unknown)" +LCHEOF + +CC=clang-13 CXX=clang++-13 ninja -C out \ + || abort_op "Failed to build GN" + +mkdir -p "$V8_SRC/buildtools/linux64" +cp out/gn "$V8_SRC/buildtools/linux64/gn-built" \ + || abort_op "GN binary not found after build" +GN_BIN="$V8_SRC/buildtools/linux64/gn-built" +log "Successfully built GN: $($GN_BIN --version)" + +cd "$V8_SRC" + +log "Using GN: $GN_BIN (version: $($GN_BIN --version 2>/dev/null || echo 'unknown'))" + +log "Building for TARGETARCH: $TARGETARCH" + +# ---------- Detect Clang ---------- +CLANG_PATH=$(which clang) +CLANG_DIR=$(dirname "$(dirname "$CLANG_PATH")") + +log "Detected Clang at: $CLANG_DIR" +log "Clang version: $(clang --version | head -n1)" + +# ---------- GN ARGS ---------- +GN_ARGS=" +target_os=\"linux\" +target_cpu=\"$TARGETARCH\" +v8_target_cpu=\"$TARGETARCH\" + +is_debug=false +is_component_build=false +is_official_build=false + +is_clang=true +clang_base_path=\"$CLANG_DIR\" +clang_use_chrome_plugins=false + +# Explicit compiler paths +cc=\"clang\" +cxx=\"clang++\" + +use_sysroot=false +use_custom_libcxx=false + +# Symbol and debug settings +symbol_level=0 +strip_debug_info=true +enable_dsyms=false +treat_warnings_as_errors=false + +# V8 core settings +v8_monolithic=true +v8_use_external_startup_data=false +v8_enable_i18n_support=false +v8_enable_webassembly=false +v8_enable_pointer_compression=true +v8_enable_sandbox=false + +# Disable cppgc to avoid build issues +cppgc_enable_caged_heap=false +v8_enable_conservative_stack_scanning=false +cppgc_is_standalone=false + +# Disable all testing infrastructure - CRITICAL for avoiding gmock/gtest issues +v8_enable_test_features=false +v8_enable_verify_heap=false +v8_enable_verify_predictable=false +build_with_chromium=false + +# Explicitly disable test targets +v8_enable_backtrace=false +v8_enable_disassembler=false +v8_enable_object_print=false + +# Additional stability flags +v8_use_snapshot=true +v8_enable_lazy_source_positions=false +v8_enable_gdbjit=false +v8_enable_vtunejit=false +v8_enable_handle_zapping=false + +# Use system toolchain properly +use_gold=false +use_lld=true +" + +OUTPUT_DIR="$V8_SRC/out.gn/${TARGETARCH}.release" + +log "Resetting build directory: $OUTPUT_DIR" +rm -rf "$OUTPUT_DIR" + +log "Generating GN files..." +log "GN command: $GN_BIN gen $OUTPUT_DIR" + +"$GN_BIN" gen "$OUTPUT_DIR" --args="$GN_ARGS" || abort_op "gn gen failed" + +log "Build configuration generated successfully" +log "Checking generated ninja files..." + +if [ ! -f "$OUTPUT_DIR/build.ninja" ]; then + abort_op "build.ninja not generated" +fi + +log "Building v8_monolith..." + +# Set up LLVM toolchain +export AR=llvm-ar +export NM=llvm-nm +export RANLIB=llvm-ranlib +export CC=clang +export CXX=clang++ +export SHELL=/bin/bash + +# Verify tools exist +for tool in llvm-ar llvm-nm llvm-ranlib clang clang++; do + if ! command -v $tool &> /dev/null; then + abort_op "$tool not found - install llvm and clang" + fi +done + +log "Toolchain:" +log " CC=$CC ($(clang --version | head -n1))" +log " CXX=$CXX" +log " AR=$AR" +log " SHELL=$SHELL" + +# Build with reasonable parallelism +NJOBS=$(nproc 2>/dev/null || echo 4) +log "Building with $NJOBS parallel jobs..." + +# Force ninja to use bash instead of sh +export NINJA_STATUS="[%f/%t] " + +/bin/bash -c "ninja -C '$OUTPUT_DIR' -j '$NJOBS' v8_monolith" || abort_op "ninja build failed" + +# ---------- Verify Build ---------- +if [ ! -f "$OUTPUT_DIR/obj/libv8_monolith.a" ]; then + abort_op "Build completed but libv8_monolith.a not found" +fi + +LIBSIZE=$(du -h "$OUTPUT_DIR/obj/libv8_monolith.a" | cut -f1) +log "Built libv8_monolith.a (size: $LIBSIZE)" + +# ---------- INSTALL ---------- +log "Installing artifacts to: $install_dir" +mkdir -p "$install_dir" +mkdir -p "$install_dir/v8/include" + +# CMakeLists.txt erwartet: +# ${V8_INSTALL_DIR}/libv8_monolith.a +# ${V8_INSTALL_DIR}/v8/ (include path 1) +# ${V8_INSTALL_DIR}/v8/include/ (include path 2, wo v8.h liegt) + +cp "$OUTPUT_DIR/obj/libv8_monolith.a" "$install_dir/" \ + || abort_op "Failed to copy monolith library" + +cp -r "$V8_SRC/include/"* "$install_dir/v8/include/" \ + || abort_op "Failed to copy public headers" + +# OnlyOffice braucht auch interne V8 Headers (src/base/sys-info.h etc.) +# Nur .h Dateien kopieren, keine .cc/.o Dateien +mkdir -p "$install_dir/v8/src" +find "$V8_SRC/src" -name "*.h" | while read -r f; do + rel="${f#$V8_SRC/src/}" + dest="$install_dir/v8/src/$rel" + mkdir -p "$(dirname "$dest")" + cp "$f" "$dest" +done +log "Copied internal V8 headers" + +# Create pkg-config file +cat > "$install_dir/v8.pc" <