mirror of
https://github.com/aphrody-labs/rusty_v8.git
synced 2026-10-13 20:15:52 +00:00
Jitless aarch64-apple-ios builds (#2011)
* spike: build V8 from source for iOS (sim) + jitless smoke test - build.rs: add iOS branch for bindgen clang args (iphoneos/iphonesimulator sysroot + arm64-apple-ios[-simulator] target triple). - iOS gn build driven via GN_ARGS (target_os=ios, target_environment, ios_deployment_target, v8_enable_webassembly=false to satisfy torque). - examples/ios_jitless.rs: forces --jitless and runs recursive JS; verified on the iOS simulator (fib(25)=75025). * Add iOS (device + simulator) build support Build V8 from source for aarch64-apple-ios and aarch64-apple-ios-sim, and publish the static libs from CI like the other targets. - build.rs: select iOS settings automatically per target (no extra GN args). The simulator keeps the JIT; the device build is jitless -- iOS denies the JIT entitlement to non-WebKit apps -- which requires V8's optimizing tiers (Sparkplug/Maglev/Turbofan) and WebAssembly disabled. bindgen is pointed at the iphoneos/iphonesimulator SDK with the matching clang target triple. - ci.yml: add aarch64-apple-ios and aarch64-apple-ios-sim (release) to the matrix; iOS is cross-compiled so it gets a build-only step instead of the test/clippy steps, and the existing publish step uploads the gzipped lib. - README: document the iOS build. - examples/ios_jitless.rs: forces --jitless and runs recursive JS; verified on the iOS simulator (fib(25)=75025). Verified locally: V8 builds from source for both iOS targets (arm64); the v8 crate links against the simulator lib and runs JS on the simulator, including in --jitless mode. The device lib builds with compile-time jitless. CI rows are best-effort (no iOS runner available to self-test). * ci(ios): build iOS with simdutf (the variant downstream consumers need)
This commit is contained in:
1 parent
1f9be2ee7d
commit
951fe30362
4 files changed
+132
-1
No files matched your search
@@ -75,6 +75,25 @@ jobs:
|
||||
v8_enable_pointer_compression: true
|
||||
cargo: cargo
|
||||
|
||||
# iOS: built from source. The simulator keeps the JIT; the device
|
||||
# build is jitless (no JIT entitlement on device) -- see build.rs.
|
||||
# Cross-compiled, so the test suite is not run on the runner.
|
||||
# Built with simdutf (the variant downstream consumers like Deno
|
||||
# need); WebAssembly is disabled (Torque can't build it jitless).
|
||||
- os: macos-15
|
||||
target: aarch64-apple-ios-sim
|
||||
variant: release
|
||||
v8_enable_pointer_compression: false
|
||||
simdutf: true
|
||||
cargo: cargo
|
||||
|
||||
- os: macos-15
|
||||
target: aarch64-apple-ios
|
||||
variant: release
|
||||
v8_enable_pointer_compression: false
|
||||
simdutf: true
|
||||
cargo: cargo
|
||||
|
||||
- os: ${{ github.repository == 'denoland/rusty_v8' && 'ubuntu-22.04-xl' || 'ubuntu-22.04' }}
|
||||
target: x86_64-unknown-linux-gnu
|
||||
variant: debug
|
||||
@@ -277,6 +296,10 @@ jobs:
|
||||
echo "CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=/usr/bin/riscv64-linux-gnu-gcc-10" >> ${GITHUB_ENV}
|
||||
echo "QEMU_LD_PREFIX=/usr/riscv64-linux-gnu" >> ${GITHUB_ENV}
|
||||
|
||||
- name: Install iOS target
|
||||
if: contains(matrix.config.target, 'ios')
|
||||
run: rustup target add ${{ matrix.config.target }}
|
||||
|
||||
- name: Write git_submodule_status.txt
|
||||
run: git submodule status --recursive > git_submodule_status.txt
|
||||
|
||||
@@ -313,6 +336,9 @@ jobs:
|
||||
# Unlike aarch64, the riscv64 sccache binary is not static, so use the host architecture one.
|
||||
"riscv64gc-unknown-linux-gnu" = "x86_64-unknown-linux-musl"
|
||||
"x86_64-pc-windows-msvc" = "x86_64-pc-windows-msvc"
|
||||
# iOS cross-compiles on the arm64 macOS runner, so use the host sccache binary.
|
||||
"aarch64-apple-ios" = "aarch64-apple-darwin"
|
||||
"aarch64-apple-ios-sim" = "aarch64-apple-darwin"
|
||||
}['${{ matrix.config.target }}']
|
||||
$basename = "sccache-$version-$platform"
|
||||
$url = "https://github.com/mozilla/sccache/releases/download/$version/$basename.tar.gz"
|
||||
@@ -346,13 +372,24 @@ jobs:
|
||||
run: |
|
||||
clang-format-19 --verbose --Werror --dry-run src/*.cc src/*.hpp src/*.h
|
||||
|
||||
# iOS targets cross-compile and cannot run on the runner, so they get a
|
||||
# build-only step (which also produces gn_out/obj/librusty_v8.a for the
|
||||
# publish step below) instead of the test + clippy steps.
|
||||
- name: Build (iOS)
|
||||
if: contains(matrix.config.target, 'ios')
|
||||
env:
|
||||
SCCACHE_IDLE_TIMEOUT: 0
|
||||
V8_FROM_SOURCE: 1
|
||||
run: ${{ matrix.config.cargo }} build -v --locked --target ${{ matrix.config.target }} ${{ env.CARGO_VARIANT_FLAG }} ${{ env.CARGO_FEATURE_FLAGS }}
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
SCCACHE_IDLE_TIMEOUT: 0
|
||||
if: matrix.config.variant == 'debug' || matrix.config.variant == 'release'
|
||||
if: (matrix.config.variant == 'debug' || matrix.config.variant == 'release') && !contains(matrix.config.target, 'ios')
|
||||
run: ${{ matrix.config.cargo }} nextest run -v --cargo-verbose --cargo-verbose --all-targets --locked --target ${{ matrix.config.target }} ${{ env.CARGO_VARIANT_FLAG }} ${{ env.CARGO_FEATURE_FLAGS }}
|
||||
|
||||
- name: Clippy
|
||||
if: ${{ !contains(matrix.config.target, 'ios') }}
|
||||
run: ${{ matrix.config.cargo }} clippy --all-targets --locked --target ${{ matrix.config.target }} ${{ env.CARGO_VARIANT_FLAG }} ${{ env.CARGO_FEATURE_FLAGS }} -- -D clippy::all
|
||||
|
||||
- name: Prepare binary publish
|
||||
|
||||
@@ -145,6 +145,18 @@ docker build --build-arg CROSS_BASE_IMAGE=ghcr.io/cross-rs/aarch64-linux-android
|
||||
V8_FROM_SOURCE=1 cross build -vv --target aarch64-linux-android
|
||||
```
|
||||
|
||||
For iOS builds: cross compile from an arm64 macOS host. The simulator target
|
||||
keeps the JIT; the device target (`aarch64-apple-ios`) is built jitless, since
|
||||
iOS denies the JIT entitlement to non-WebKit apps (WebAssembly is also disabled
|
||||
in this configuration). `build.rs` selects these settings automatically per
|
||||
target — no extra GN args required:
|
||||
|
||||
```bash
|
||||
rustup target add aarch64-apple-ios-sim # simulator
|
||||
rustup target add aarch64-apple-ios # device (jitless)
|
||||
V8_FROM_SOURCE=1 cargo build -vv --target aarch64-apple-ios-sim
|
||||
```
|
||||
|
||||
The build depends on several binary tools: `gn`, `ninja` and `clang`. The tools
|
||||
will automatically be downloaded, if they are not detected in the environment.
|
||||
|
||||
|
||||
@@ -212,6 +212,30 @@ fn build_binding() {
|
||||
clang_args.push(format!("-isystem{}/include", resource_dir.trim()));
|
||||
}
|
||||
}
|
||||
} else if target_os == "ios" {
|
||||
// iOS: point bindgen at the iOS (device) or iOS-simulator SDK and set the
|
||||
// matching clang target triple so the V8 headers parse correctly.
|
||||
let target_triple = env::var("TARGET").unwrap();
|
||||
let is_sim = target_triple.ends_with("-sim")
|
||||
|| target_triple.starts_with("x86_64-apple-ios");
|
||||
let sdk = if is_sim {
|
||||
"iphonesimulator"
|
||||
} else {
|
||||
"iphoneos"
|
||||
};
|
||||
let output = Command::new("xcrun")
|
||||
.args(["--sdk", sdk, "--show-sdk-path"])
|
||||
.output()
|
||||
.unwrap();
|
||||
let sdk_path = String::from_utf8(output.stdout).unwrap();
|
||||
clang_args.push("-isysroot".to_string());
|
||||
clang_args.push(sdk_path.trim().to_string());
|
||||
let clang_target = if is_sim {
|
||||
"arm64-apple-ios-simulator"
|
||||
} else {
|
||||
"arm64-apple-ios"
|
||||
};
|
||||
clang_args.push(format!("--target={clang_target}"));
|
||||
}
|
||||
|
||||
let bindings = bindgen::Builder::default()
|
||||
@@ -453,6 +477,34 @@ fn build_v8(is_asan: bool) {
|
||||
);
|
||||
}
|
||||
|
||||
// iOS / iOS-simulator. iOS denies the JIT entitlement to non-WebKit apps, so
|
||||
// a device build must be jitless -- which in turn requires V8's optimizing
|
||||
// tiers (Sparkplug/Maglev/Turbofan) and WebAssembly to be disabled. The
|
||||
// simulator runs on the host and could keep the JIT, but WebAssembly is
|
||||
// disabled there too because Torque can't generate the Wasm builtins in this
|
||||
// configuration. `target_cpu="arm64"` is already set above for aarch64.
|
||||
// Pass an explicit `target_os="ios"` in GN_ARGS to fully override this.
|
||||
if target_os == "ios" && !gn_args_env.contains(r#"target_os="ios""#) {
|
||||
let is_sim = target_triple.ends_with("-sim")
|
||||
|| target_triple.starts_with("x86_64-apple-ios");
|
||||
gn_args.push(r#"target_os="ios""#.to_string());
|
||||
gn_args.push(format!(
|
||||
r#"target_environment="{}""#,
|
||||
if is_sim { "simulator" } else { "device" }
|
||||
));
|
||||
gn_args.push(r#"ios_deployment_target="14.0""#.to_string());
|
||||
gn_args.push("ios_enable_code_signing=false".to_string());
|
||||
gn_args.push("treat_warnings_as_errors=false".to_string());
|
||||
gn_args.push("v8_enable_webassembly=false".to_string());
|
||||
if !is_sim {
|
||||
// Device: no JIT permitted -> jitless build, all tiers off.
|
||||
gn_args.push("v8_jitless=true".to_string());
|
||||
gn_args.push("v8_enable_sparkplug=false".to_string());
|
||||
gn_args.push("v8_enable_maglev=false".to_string());
|
||||
gn_args.push("v8_enable_turbofan=false".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
if target_triple.starts_with("i686-") {
|
||||
gn_args.push(r#"target_cpu="x86""#.to_string());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Minimal jitless smoke test for the iOS spike: force V8 into jitless mode
|
||||
// (the mode required on a real iOS device, which denies the JIT entitlement)
|
||||
// and run a little recursive JS to confirm the Ignition interpreter executes.
|
||||
|
||||
fn main() {
|
||||
let platform = v8::new_default_platform(0, false).make_shared();
|
||||
v8::V8::initialize_platform(platform);
|
||||
// The flag a real device build needs: no runtime codegen / no RWX pages.
|
||||
v8::V8::set_flags_from_string("--jitless");
|
||||
v8::V8::initialize();
|
||||
|
||||
{
|
||||
let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
|
||||
v8::scope!(let handle_scope, isolate);
|
||||
let context = v8::Context::new(handle_scope, Default::default());
|
||||
let scope = &v8::ContextScope::new(handle_scope, context);
|
||||
|
||||
let src = "const fib=(n)=>n<2?n:fib(n-1)+fib(n-2); `fib(25)=${fib(25)}`";
|
||||
let code = v8::String::new(scope, src).unwrap();
|
||||
let script = v8::Script::compile(scope, code, None).unwrap();
|
||||
let result = script.run(scope).unwrap();
|
||||
let result = result.to_string(scope).unwrap();
|
||||
println!("JITLESS OK: {}", result.to_rust_string_lossy(scope));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
v8::V8::dispose();
|
||||
}
|
||||
v8::V8::dispose_platform();
|
||||
}
|
||||
Reference in new issue
Block a user