mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-11-21 15:04:33 -05:00
Add aarch64-linux-android support (#860)
This commit is contained in:
parent
b3e09e69a0
commit
a29740df6b
14 changed files with 1719 additions and 12 deletions
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[target.aarch64-linux-android]
|
||||
linker = "./third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++"
|
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
|
@ -24,30 +24,42 @@ jobs:
|
|||
- os: macOS-latest
|
||||
target: x86_64-apple-darwin
|
||||
variant: debug
|
||||
cargo: cargo
|
||||
|
||||
- os: macOS-latest
|
||||
target: x86_64-apple-darwin
|
||||
variant: release
|
||||
cargo: cargo
|
||||
|
||||
- os: ${{ github.repository == 'denoland/rusty_v8' && 'ubuntu-latest-xl' || 'ubuntu-18.04' }}
|
||||
target: x86_64-unknown-linux-gnu
|
||||
variant: debug
|
||||
cargo: cargo
|
||||
|
||||
- os: ${{ github.repository == 'denoland/rusty_v8' && 'ubuntu-latest-xl' || 'ubuntu-18.04' }}
|
||||
target: x86_64-unknown-linux-gnu
|
||||
variant: release
|
||||
cargo: cargo
|
||||
|
||||
- os: windows-2019
|
||||
target: x86_64-pc-windows-msvc
|
||||
variant: release # Note: we do not support windows debug builds.
|
||||
cargo: cargo
|
||||
|
||||
- os: ${{ github.repository == 'denoland/rusty_v8' && 'ubuntu-latest-xl' || 'ubuntu-18.04' }}
|
||||
target: aarch64-unknown-linux-gnu
|
||||
variant: debug
|
||||
cargo: cargo
|
||||
|
||||
- os: ${{ github.repository == 'denoland/rusty_v8' && 'ubuntu-latest-xl' || 'ubuntu-18.04' }}
|
||||
target: aarch64-unknown-linux-gnu
|
||||
variant: release
|
||||
cargo: cargo
|
||||
|
||||
- os: ${{ github.repository == 'denoland/rusty_v8' && 'ubuntu-latest-xl' || 'ubuntu-18.04' }}
|
||||
target: aarch64-linux-android
|
||||
variant: release # Note: v8 debug builds on QEMU is buggy.
|
||||
cargo: cross
|
||||
|
||||
env:
|
||||
V8_FROM_SOURCE: true
|
||||
|
@ -158,14 +170,24 @@ jobs:
|
|||
. $basename/sccache --start-server
|
||||
echo "$(pwd)/$basename" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
|
||||
- name: Install cross
|
||||
if: matrix.config.target == 'aarch64-linux-android'
|
||||
run: cargo install cross
|
||||
|
||||
- name: Build cross docker image
|
||||
if: matrix.config.target == 'aarch64-linux-android'
|
||||
run: docker build -t cross:aarch64-linux-android-0.2.1 .
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
SCCACHE_IDLE_TIMEOUT: 0
|
||||
run:
|
||||
cargo test -vv --all-targets --locked ${{ env.CARGO_VARIANT_FLAG }}
|
||||
${{ matrix.config.cargo }} test -vv --all-targets --locked ${{ env.CARGO_VARIANT_FLAG }}
|
||||
--target ${{ matrix.config.target }}
|
||||
|
||||
- name: Clippy
|
||||
run:
|
||||
cargo clippy --all-targets --locked ${{ env.CARGO_VARIANT_FLAG }}
|
||||
${{ matrix.config.cargo }} clippy --all-targets --locked ${{ env.CARGO_VARIANT_FLAG }}
|
||||
--target ${{ matrix.config.target }} -- -D clippy::all
|
||||
|
||||
- name: Rustfmt
|
||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -6,3 +6,8 @@
|
|||
/.cache
|
||||
/target/
|
||||
/compile_commands.json
|
||||
|
||||
third_party/android_ndk
|
||||
third_party/android_platform
|
||||
third_party/catapult
|
||||
third_party/llvm-build
|
||||
|
|
1358
Cargo.lock
generated
1358
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
14
Cargo.toml
14
Cargo.toml
|
@ -5,7 +5,7 @@ description = "Rust bindings to V8"
|
|||
readme = "README.md"
|
||||
authors = ["the Deno authors"]
|
||||
license = "MIT"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/denoland/rusty_v8"
|
||||
|
||||
exclude = [
|
||||
|
@ -84,9 +84,15 @@ which = "4.1.0"
|
|||
fslock = "0.1.6"
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild = "1.0.42"
|
||||
trybuild = "1.0.53"
|
||||
align-data = "0.1.0"
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
winit = "0.26"
|
||||
pixels = "0.8.0"
|
||||
ndk = "0.3.0"
|
||||
ndk-glue = { version = "0.5.0", features = ["logger"] }
|
||||
|
||||
[[example]]
|
||||
name = "hello_world"
|
||||
|
||||
|
@ -95,3 +101,7 @@ name = "shell"
|
|||
|
||||
[[example]]
|
||||
name = "process"
|
||||
|
||||
[[example]]
|
||||
name = "android_fractal"
|
||||
crate-type = ["cdylib"]
|
||||
|
|
11
Cross.toml
Normal file
11
Cross.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[target.aarch64-linux-android]
|
||||
image = "cross:aarch64-linux-android-0.2.1"
|
||||
|
||||
[build.env]
|
||||
passthrough = [
|
||||
"V8_FROM_SOURCE",
|
||||
"SCCACHE_ERROR_LOG",
|
||||
"SCCACHE_LOG",
|
||||
"SCCACHE_DIR",
|
||||
"SCCACHE_IDLE_TIMEOUT"
|
||||
]
|
20
Dockerfile
Normal file
20
Dockerfile
Normal file
|
@ -0,0 +1,20 @@
|
|||
FROM rustembedded/cross:aarch64-linux-android-0.2.1
|
||||
|
||||
RUN apt update && \
|
||||
apt install -y curl && \
|
||||
curl -L https://github.com/mozilla/sccache/releases/download/v0.2.15/sccache-v0.2.15-x86_64-unknown-linux-musl.tar.gz | tar xzf -
|
||||
|
||||
ENV TZ=Etc/UTC
|
||||
COPY ./build/*.sh /chromium_build/
|
||||
RUN \
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
|
||||
&& apt-get update && apt-get install -y lsb-release sudo \
|
||||
&& /chromium_build/install-build-deps-android.sh \
|
||||
&& rm -rf /chromium_build \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN chmod +x /sccache-v0.2.15-x86_64-unknown-linux-musl/sccache
|
||||
|
||||
ENV SCCACHE=/sccache-v0.2.15-x86_64-unknown-linux-musl/sccache
|
||||
ENV SCCACHE_DIR=./target/sccache
|
58
build.rs
58
build.rs
|
@ -103,6 +103,7 @@ fn build_v8() {
|
|||
|
||||
// On windows, rustc cannot link with a V8 debug build.
|
||||
let mut gn_args = if is_debug() && !cfg!(target_os = "windows") {
|
||||
// Note: When building for Android aarch64-qemu, use release instead of debug.
|
||||
vec!["is_debug=true".to_string()]
|
||||
} else {
|
||||
vec!["is_debug=false".to_string()]
|
||||
|
@ -125,8 +126,14 @@ fn build_v8() {
|
|||
// we can't use chromiums clang plugins with a system clang
|
||||
gn_args.push("clang_use_chrome_plugins=false".to_string());
|
||||
} else {
|
||||
println!("using Chromiums clang");
|
||||
let clang_base_path = clang_download();
|
||||
gn_args.push(format!("clang_base_path={:?}", clang_base_path));
|
||||
|
||||
if cfg!(target_os = "android") && cfg!(target_arch = "aarch64") {
|
||||
gn_args.push("clang_use_chrome_plugins=false".to_string());
|
||||
gn_args.push("treat_warnings_as_errors=false".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(p) = env::var_os("SCCACHE") {
|
||||
|
@ -151,12 +158,43 @@ fn build_v8() {
|
|||
// check if the target triple describes a non-native environment
|
||||
if target_triple != env::var("HOST").unwrap() {
|
||||
// cross-compilation setup
|
||||
if target_triple == "aarch64-unknown-linux-gnu" {
|
||||
if target_triple == "aarch64-unknown-linux-gnu"
|
||||
|| target_triple == "aarch64-linux-android"
|
||||
{
|
||||
gn_args.push(r#"target_cpu="arm64""#.to_string());
|
||||
gn_args.push("use_sysroot=true".to_string());
|
||||
maybe_install_sysroot("arm64");
|
||||
maybe_install_sysroot("amd64");
|
||||
};
|
||||
|
||||
if target_triple == "aarch64-linux-android" {
|
||||
gn_args.push("is_component_build=false".to_string());
|
||||
gn_args.push(r#"v8_target_cpu="arm64""#.to_string());
|
||||
gn_args.push(r#"target_os="android""#.to_string());
|
||||
|
||||
gn_args.push("treat_warnings_as_errors=false".to_string());
|
||||
|
||||
// NDK 23 and above removes libgcc entirely.
|
||||
// https://github.com/rust-lang/rust/pull/85806
|
||||
maybe_clone_repo(
|
||||
"./third_party/android_ndk",
|
||||
"https://github.com/denoland/android_ndk.git",
|
||||
);
|
||||
|
||||
static CHROMIUM_URI: &str = "https://chromium.googlesource.com";
|
||||
|
||||
maybe_clone_repo(
|
||||
"./third_party/android_platform",
|
||||
&format!(
|
||||
"{}/chromium/src/third_party/android_platform.git",
|
||||
CHROMIUM_URI
|
||||
),
|
||||
);
|
||||
maybe_clone_repo(
|
||||
"./third_party/catapult",
|
||||
&format!("{}/catapult.git", CHROMIUM_URI),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
if target_triple.starts_with("i686-") {
|
||||
|
@ -171,6 +209,19 @@ fn build_v8() {
|
|||
build("rusty_v8", None);
|
||||
}
|
||||
|
||||
fn maybe_clone_repo(dest: &str, repo: &str) {
|
||||
if !Path::new(&dest).exists() {
|
||||
assert!(Command::new("git")
|
||||
.arg("clone")
|
||||
.arg("--depth=1")
|
||||
.arg(repo)
|
||||
.arg(dest)
|
||||
.status()
|
||||
.unwrap()
|
||||
.success());
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_install_sysroot(arch: &str) {
|
||||
let sysroot_path = format!("build/linux/debian_sid_{}-sysroot", arch);
|
||||
if !PathBuf::from(sysroot_path).is_dir() {
|
||||
|
@ -387,6 +438,10 @@ fn is_compatible_clang_version(clang_path: &Path) -> bool {
|
|||
}
|
||||
|
||||
fn find_compatible_system_clang() -> Option<PathBuf> {
|
||||
if cfg!(target_os = "android") {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Ok(p) = env::var("CLANG_BASE_PATH") {
|
||||
let base_path = Path::new(&p);
|
||||
let clang_path = base_path.join("bin").join("clang");
|
||||
|
@ -395,7 +450,6 @@ fn find_compatible_system_clang() -> Option<PathBuf> {
|
|||
}
|
||||
}
|
||||
|
||||
println!("using Chromiums clang");
|
||||
None
|
||||
}
|
||||
|
||||
|
|
69
examples/android_fractal.js
Normal file
69
examples/android_fractal.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
||||
function DrawFrame(frameLen) {
|
||||
const u8 = new Uint8Array(frameLen);
|
||||
const width = 800;
|
||||
const height = 800;
|
||||
|
||||
let x = y = 0;
|
||||
|
||||
for (let i = 0; i < u8.byteLength; i += 4) {
|
||||
if (x == width) {
|
||||
y++;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
x += 1;
|
||||
let r = Math.floor(0.3 * x);
|
||||
let b = Math.floor(0.3 * y);
|
||||
|
||||
u8.set([r, 0x00, b, 0xff], i);
|
||||
}
|
||||
|
||||
let scale_x = 3.0 / width;
|
||||
let scale_y = 3.0 / height;
|
||||
|
||||
for (let x = 0; x < width; x++) {
|
||||
for (let y = 0; y < height; y++) {
|
||||
let cx = y * scale_x - 1.5;
|
||||
let cy = x * scale_y - 1.5;
|
||||
|
||||
let c = new Complex(-0.4, 0.6);
|
||||
let z = new Complex(cx, cy);
|
||||
|
||||
let i = 0;
|
||||
while (i < 100 && z.abs() < 2) {
|
||||
z = z.mul(z).add(c);
|
||||
i++;
|
||||
}
|
||||
|
||||
u8.set([0x00, i, 0x00, 0xff], (y * width + x) * 4);
|
||||
}
|
||||
}
|
||||
|
||||
return u8.buffer;
|
||||
}
|
||||
|
||||
class Complex {
|
||||
constructor(real, imag) {
|
||||
this.real = real;
|
||||
this.imag = imag;
|
||||
}
|
||||
|
||||
mul(other) {
|
||||
return new Complex(
|
||||
this.real * other.real - this.imag * other.imag,
|
||||
this.real * other.imag + this.imag * other.real,
|
||||
);
|
||||
}
|
||||
|
||||
add(other) {
|
||||
return new Complex(
|
||||
this.real + other.real,
|
||||
this.imag + other.imag,
|
||||
);
|
||||
}
|
||||
|
||||
abs() {
|
||||
return Math.sqrt(this.real * this.real + this.imag * this.imag);
|
||||
}
|
||||
}
|
153
examples/android_fractal.rs
Normal file
153
examples/android_fractal.rs
Normal file
|
@ -0,0 +1,153 @@
|
|||
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
// Don't run on non-Android targets.
|
||||
#![cfg(target_os = "android")]
|
||||
// Don't run this as a test in `--all-targets` mode.
|
||||
#![cfg(not(test))]
|
||||
|
||||
use pixels::Pixels;
|
||||
use pixels::SurfaceTexture;
|
||||
use std::cell::Cell;
|
||||
use winit::platform::run_return::EventLoopExtRunReturn;
|
||||
|
||||
#[ndk_glue::main(
|
||||
backtrace = "on",
|
||||
logger(level = "debug", tag = "android_fractal")
|
||||
)]
|
||||
fn main() {
|
||||
let mut event_loop = winit::event_loop::EventLoop::new();
|
||||
let window = winit::window::WindowBuilder::new()
|
||||
.with_title("rusty_v8 android_fractal")
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
|
||||
// Initialize V8.
|
||||
let platform = v8::new_default_platform(0, false).make_shared();
|
||||
v8::V8::initialize_platform(platform);
|
||||
v8::V8::initialize();
|
||||
|
||||
let mut isolate = v8::Isolate::new(v8::CreateParams::default());
|
||||
let mut scope = v8::HandleScope::new(&mut isolate);
|
||||
let source =
|
||||
v8::String::new(&mut scope, include_str!("android_fractal.js")).unwrap();
|
||||
|
||||
let context = v8::Context::new(&mut scope);
|
||||
let mut context_scope = v8::ContextScope::new(&mut scope, context);
|
||||
|
||||
execute_script(&mut context_scope, source);
|
||||
|
||||
let draw_str = v8::String::new(&mut context_scope, "DrawFrame").unwrap();
|
||||
let draw_fn = context
|
||||
.global(&mut context_scope)
|
||||
.get(&mut context_scope, draw_str.into())
|
||||
.expect("missing function DrawFrame");
|
||||
|
||||
let draw_fn =
|
||||
v8::Local::<v8::Function>::try_from(draw_fn).expect("function expected");
|
||||
|
||||
let mut allowed = false;
|
||||
|
||||
loop {
|
||||
event_loop.run_return(|event, _, control_flow| {
|
||||
*control_flow = winit::event_loop::ControlFlow::Wait;
|
||||
match event {
|
||||
winit::event::Event::WindowEvent {
|
||||
event: winit::event::WindowEvent::CloseRequested,
|
||||
..
|
||||
} => *control_flow = winit::event_loop::ControlFlow::Exit,
|
||||
// Drawing on android must only happen before Event::Suspended and
|
||||
// after Event::Resumed.
|
||||
//
|
||||
// https://github.com/rust-windowing/winit/issues/1588
|
||||
winit::event::Event::Resumed => {
|
||||
allowed = true;
|
||||
}
|
||||
winit::event::Event::Suspended => {
|
||||
allowed = false;
|
||||
}
|
||||
winit::event::Event::RedrawRequested(_) => {
|
||||
if !allowed {
|
||||
return;
|
||||
}
|
||||
let surface_texture = SurfaceTexture::new(800, 800, &window);
|
||||
let mut pixels = Pixels::new(800, 800, surface_texture).unwrap();
|
||||
|
||||
draw(&mut context_scope, draw_fn, pixels.get_frame());
|
||||
|
||||
if pixels.render().is_err() {
|
||||
*control_flow = winit::event_loop::ControlFlow::Exit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
window.request_redraw();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_script(
|
||||
context_scope: &mut v8::ContextScope<v8::HandleScope>,
|
||||
script: v8::Local<v8::String>,
|
||||
) {
|
||||
let scope = &mut v8::HandleScope::new(context_scope);
|
||||
let try_catch = &mut v8::TryCatch::new(scope);
|
||||
|
||||
let script = v8::Script::compile(try_catch, script, None)
|
||||
.expect("failed to compile script");
|
||||
|
||||
if script.run(try_catch).is_none() {
|
||||
let exception_string = try_catch
|
||||
.stack_trace()
|
||||
.or_else(|| try_catch.exception())
|
||||
.map(|value| value.to_rust_string_lossy(try_catch))
|
||||
.unwrap_or_else(|| "no stack trace".into());
|
||||
|
||||
panic!("{}", exception_string);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(
|
||||
context_scope: &mut v8::ContextScope<v8::HandleScope>,
|
||||
draw_fn: v8::Local<v8::Function>,
|
||||
frame: &mut [u8],
|
||||
) {
|
||||
let scope = &mut v8::HandleScope::new(context_scope);
|
||||
let recv = v8::undefined(scope);
|
||||
let try_catch = &mut v8::TryCatch::new(scope);
|
||||
|
||||
let len = frame.len();
|
||||
let frame_len = v8::Integer::new(try_catch, len as i32);
|
||||
|
||||
let ab = match draw_fn.call(try_catch, recv.into(), &[frame_len.into()]) {
|
||||
Some(ab) => ab,
|
||||
None => {
|
||||
let exception_string = try_catch
|
||||
.stack_trace()
|
||||
.or_else(|| try_catch.exception())
|
||||
.map(|value| value.to_rust_string_lossy(try_catch))
|
||||
.unwrap_or_else(|| "no stack trace".into());
|
||||
|
||||
panic!("{}", exception_string);
|
||||
}
|
||||
};
|
||||
|
||||
let ab =
|
||||
v8::Local::<v8::ArrayBuffer>::try_from(ab).expect("array buffer expected");
|
||||
let bs = ab.get_backing_store();
|
||||
|
||||
let js_frame = unsafe { get_backing_store_slice(&bs, 0, len) };
|
||||
frame.copy_from_slice(js_frame.as_ref());
|
||||
}
|
||||
|
||||
unsafe fn get_backing_store_slice(
|
||||
backing_store: &v8::SharedRef<v8::BackingStore>,
|
||||
byte_offset: usize,
|
||||
byte_length: usize,
|
||||
) -> &[u8] {
|
||||
let cells: *const [Cell<u8>] =
|
||||
&backing_store[byte_offset..byte_offset + byte_length];
|
||||
let bytes = cells as *const [u8];
|
||||
&*bytes
|
||||
}
|
|
@ -121,7 +121,6 @@ pub struct CompiledWasmModule(*mut InternalCompiledWasmModule);
|
|||
impl CompiledWasmModule {
|
||||
/// Get the (wasm-encoded) wire bytes that were used to compile this module.
|
||||
pub fn get_wire_bytes_ref(&self) -> &[u8] {
|
||||
use std::convert::TryInto;
|
||||
let mut len = 0isize;
|
||||
unsafe {
|
||||
let ptr = v8__CompiledWasmModule__GetWireBytesRef(self.0, &mut len);
|
||||
|
|
|
@ -857,6 +857,9 @@ fn thread_safe_handle_drop_after_isolate() {
|
|||
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 0);
|
||||
}
|
||||
|
||||
// QEMU doesn't like when we spawn threads
|
||||
// This works just fine on real hardware
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[test]
|
||||
fn terminate_execution() {
|
||||
let _setup_guard = setup();
|
||||
|
@ -4838,6 +4841,8 @@ fn value_serializer_not_implemented() {
|
|||
);
|
||||
}
|
||||
|
||||
// Flaky on aarch64-qemu (Stack corruption).
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[test]
|
||||
fn clear_kept_objects() {
|
||||
let _setup_guard = setup();
|
||||
|
@ -5529,6 +5534,7 @@ fn counter_lookup_callback() {
|
|||
assert_ne!(count, 0);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[test]
|
||||
fn compiled_wasm_module() {
|
||||
let _setup_guard = setup();
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// This is flaky on cross (QEMU bug)
|
||||
// but otherwise works fine on real device.
|
||||
#![cfg(not(target_os = "android"))]
|
||||
|
||||
use std::iter::repeat_with;
|
||||
use std::thread;
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::env;
|
||||
|
||||
// Don't run UI tests on emulated environment.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[test]
|
||||
fn ui() {
|
||||
// This environment variable tells build.rs that we're running trybuild tests,
|
||||
|
|
Loading…
Reference in a new issue