Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
error() { echo "[ERROR] $*" >&2; exit 1; }
source ${sourceRoot}/scripts/lib/native-modules.sh
patch_better_sqlite3_for_v8_external_pointer_api "$PWD/node_modules/better-sqlite3"
apply_v8_nullptr_t_workaround_if_needed "$TMPDIR/native-nullptr-workaround"

node "$PWD/node_modules/@electron/rebuild/lib/cli.js" \
-v ${electronVersion} \
Expand Down
45 changes: 45 additions & 0 deletions scripts/lib/native-modules.sh
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,50 @@ prune_native_module_build_artifacts() {
find "$module_dir" -type f -name "*.target.mk" -delete 2>/dev/null || true
}

apply_v8_nullptr_t_workaround_if_needed() {
local build_dir="$1"
local probe_source="$build_dir/.v8-nullptr-probe.cc"
local nullptr_fix="$build_dir/.v8-nullptr-fix.h"
local cxx_wrapper="$build_dir/.cxx-v8-nullptr"
local -a cxx_command

mkdir -p "$build_dir"

# CXX is conventionally a command plus optional leading arguments, e.g.
# "ccache g++". Preserve that common form when wrapping the compiler.
# shellcheck disable=SC2206
cxx_command=( ${CXX:-c++} )
if [ "${#cxx_command[@]}" -eq 0 ]; then
cxx_command=(c++)
fi

command -v "${cxx_command[0]}" >/dev/null 2>&1 || error "C++ compiler not found: ${cxx_command[0]}"

cat > "$probe_source" <<'CPP'
#include <cstddef>
nullptr_t x = nullptr;
CPP

if "${cxx_command[@]}" -x c++ -std=c++20 -fsyntax-only "$probe_source" >/dev/null 2>&1; then
return 0
fi

printf '#include <cstddef>\nusing std::nullptr_t;\n' > "$nullptr_fix"
{
printf '#!/bin/bash\n'
printf 'exec'
local arg
for arg in "${cxx_command[@]}"; do
printf ' %q' "$arg"
done
printf ' -include %q "$@"\n' "$nullptr_fix"
} > "$cxx_wrapper"
chmod +x "$cxx_wrapper"

export CXX="$cxx_wrapper"
info "Applied GCC 16+ nullptr_t compatibility workaround"
}

build_native_modules() {
local app_extracted="$1"

Expand Down Expand Up @@ -168,6 +212,7 @@ build_native_modules() {
info "Compiling for Electron v$ELECTRON_VERSION (this takes ~1 min)..."
info "Using Electron headers: $ELECTRON_HEADERS_URL"
[ -f "$build_dir/node_modules/@electron/rebuild/lib/cli.js" ] || error "electron-rebuild CLI not found in native build toolchain"
apply_v8_nullptr_t_workaround_if_needed "$build_dir"
npm_config_disturl="$ELECTRON_HEADERS_URL" \
NPM_CONFIG_DISTURL="$ELECTRON_HEADERS_URL" \
node "$build_dir/node_modules/@electron/rebuild/lib/cli.js" -v "$ELECTRON_VERSION" --force --dist-url "$ELECTRON_HEADERS_URL" 2>&1 >&2
Expand Down
92 changes: 92 additions & 0 deletions tests/scripts_smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,96 @@ CPP
assert_contains "$output_log" "already applied"
}

test_v8_nullptr_workaround_skips_when_included_probe_succeeds() {
info "Checking V8 nullptr_t workaround probe stays inactive when not needed"
local workspace="$TMP_DIR/v8-nullptr-workaround-skip"
local fake_bin="$workspace/bin"
local cxx_log="$workspace/cxx.log"
local cxx_state="$workspace/cxx-state.log"
local output_log="$workspace/output.log"

mkdir -p "$fake_bin" "$workspace/work"
cat > "$fake_bin/c++" <<'SCRIPT'
#!/usr/bin/env bash
set -euo pipefail
printf 'argv:%s\n' "$*" >> "$NATIVE_CXX_LOG"
for arg in "$@"; do
if [ -f "$arg" ]; then
cat "$arg" >> "$NATIVE_CXX_LOG"
fi
done
exit 0
SCRIPT
chmod +x "$fake_bin/c++"

(
CXX="$fake_bin/c++"
NATIVE_CXX_LOG="$cxx_log"
export CXX NATIVE_CXX_LOG
info() { echo "[INFO] $*" >&2; }
warn() { echo "[WARN] $*" >&2; }
error() { echo "[ERROR] $*" >&2; exit 1; }
# shellcheck disable=SC1091
source "$REPO_DIR/scripts/lib/native-modules.sh"
apply_v8_nullptr_t_workaround_if_needed "$workspace/work"
printf 'CXX=%s\n' "$CXX" > "$cxx_state"
) > "$output_log" 2>&1

assert_contains "$cxx_log" "#include <cstddef>"
assert_contains "$cxx_log" "nullptr_t x = nullptr;"
assert_contains "$cxx_state" "CXX=$fake_bin/c++"
assert_not_contains "$output_log" "Applied GCC 16+ nullptr_t compatibility workaround"
}

test_v8_nullptr_workaround_wraps_when_included_probe_fails() {
info "Checking V8 nullptr_t workaround wraps CXX only when needed"
local workspace="$TMP_DIR/v8-nullptr-workaround-wrap"
local fake_bin="$workspace/bin"
local cxx_log="$workspace/cxx.log"
local cxx_state="$workspace/cxx-state.log"
local output_log="$workspace/output.log"

mkdir -p "$fake_bin" "$workspace/work"
cat > "$fake_bin/c++" <<'SCRIPT'
#!/usr/bin/env bash
set -euo pipefail
printf 'argv:%s\n' "$*" >> "$NATIVE_CXX_LOG"
for arg in "$@"; do
if [ -f "$arg" ]; then
cat "$arg" >> "$NATIVE_CXX_LOG"
fi
case "$arg" in
*.v8-nullptr-probe.cc) exit 1 ;;
esac
done
exit 0
SCRIPT
chmod +x "$fake_bin/c++"
printf '%s\n' 'int main() { return 0; }' > "$workspace/dummy.cc"

(
CXX="$fake_bin/c++"
NATIVE_CXX_LOG="$cxx_log"
export CXX NATIVE_CXX_LOG
info() { echo "[INFO] $*" >&2; }
warn() { echo "[WARN] $*" >&2; }
error() { echo "[ERROR] $*" >&2; exit 1; }
# shellcheck disable=SC1091
source "$REPO_DIR/scripts/lib/native-modules.sh"
apply_v8_nullptr_t_workaround_if_needed "$workspace/work"
"$CXX" -x c++ -fsyntax-only "$workspace/dummy.cc"
printf 'CXX=%s\n' "$CXX" > "$cxx_state"
) > "$output_log" 2>&1

assert_file_exists "$workspace/work/.v8-nullptr-fix.h"
assert_file_exists "$workspace/work/.cxx-v8-nullptr"
assert_contains "$workspace/work/.v8-nullptr-fix.h" "using std::nullptr_t;"
assert_contains "$cxx_state" "CXX=$workspace/work/.cxx-v8-nullptr"
assert_contains "$cxx_log" "-include"
assert_contains "$cxx_log" ".v8-nullptr-fix.h"
assert_contains "$output_log" "Applied GCC 16+ nullptr_t compatibility workaround"
}

test_native_module_rebuild_uses_local_electron_rebuild_toolchain() {
info "Checking native module rebuild uses local Electron rebuild toolchain"
local workspace="$TMP_DIR/native-module-rebuild-toolchain"
Expand Down Expand Up @@ -4700,6 +4790,8 @@ main() {
test_port_validation_rejects_oversized_numeric_values
test_managed_node_runtime_source_install
test_better_sqlite3_electron_42_source_patch
test_v8_nullptr_workaround_skips_when_included_probe_succeeds
test_v8_nullptr_workaround_wraps_when_included_probe_fails
test_native_module_rebuild_uses_local_electron_rebuild_toolchain
test_native_module_rebuild_accepts_prebuilt_source
test_bundled_plugin_builders_accept_prebuilt_binaries
Expand Down
Loading