diff --git a/.github/workflows/windows-arm.yml b/.github/workflows/windows-arm.yml new file mode 100644 index 00000000..4788e255 --- /dev/null +++ b/.github/workflows/windows-arm.yml @@ -0,0 +1,76 @@ +name: Windows arm64 + +env: + DEBUG: 'napi:*' + +on: + push: + branches: + - main + pull_request: + +jobs: + build_and_test: + name: stable - windows-latest - arm64 - node@14 + runs-on: windows-latest + + steps: + - uses: actions/checkout@v2 + + - name: Setup node + uses: actions/setup-node@v1 + with: + node-version: 14 + + - name: Cache NPM dependencies + uses: actions/cache@v1 + with: + path: node_modules + key: npm-cache-windows-arm64-node@lts-${{ hashFiles('yarn.lock') }} + + - name: 'Install dependencies' + run: yarn install --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000 + + - name: 'Build TypeScript' + run: yarn build + + - name: Install + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Install arm64 toolchain + run: rustup target add aarch64-pc-windows-msvc + + - name: Generate Cargo.lock + uses: actions-rs/cargo@v1 + with: + command: generate-lockfile + + - name: Cache cargo registry + uses: actions/cache@v1 + with: + path: ~/.cargo/registry + key: stable-windows-arm64-node@lts-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo index + uses: actions/cache@v1 + with: + path: ~/.cargo/git + key: stable-windows-arm64-node@lts-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }} + + - name: Check build + uses: actions-rs/cargo@v1 + with: + command: check + args: --all --bins --examples --tests --target aarch64-pc-windows-msvc -vvv + + - name: Build release target + run: cargo build --release --target aarch64-pc-windows-msvc + + - name: Clear the cargo caches + run: | + cargo install cargo-cache --no-default-features --features ci-autoclean + cargo-cache diff --git a/.gitignore b/.gitignore index 440b7098..38cb791f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ target/ .DS_Store Cargo.lock node_modules -napi/src/sys/bindings.rs *.node build/LICENSE napi/LICENSE diff --git a/README.md b/README.md index c7d8bc60..a37a7b70 100644 --- a/README.md +++ b/README.md @@ -20,17 +20,20 @@ A minimal library for building compiled `Node.js` add-ons in `Rust`. ![Linux-armv7](https://github.com/napi-rs/napi-rs/workflows/Linux-armv7/badge.svg) ![macOS-Android](https://github.com/napi-rs/napi-rs/workflows/macOS-Android/badge.svg) ![Windows i686](https://github.com/napi-rs/napi-rs/workflows/Windows%20i686/badge.svg) +[![Windows arm64](https://github.com/napi-rs/napi-rs/actions/workflows/windows-arm.yml/badge.svg)](https://github.com/napi-rs/napi-rs/actions/workflows/windows-arm.yml) [![FreeBSD](https://api.cirrus-ci.com/github/napi-rs/napi-rs.svg)](https://cirrus-ci.com/github/napi-rs/napi-rs?branch=main) | | node12 | node14 | node16 | | --------------------- | ------ | ------ | ------ | | Windows x64 | ✓ | ✓ | ✓ | | Windows x86 | ✓ | ✓ | ✓ | +| Windows arm64 | ✓ | ✓ | ✓ | | macOS x64 | ✓ | ✓ | ✓ | | macOS aarch64 | ✓ | ✓ | ✓ | | Linux x64 gnu | ✓ | ✓ | ✓ | | Linux x64 musl | ✓ | ✓ | ✓ | | Linux aarch64 gnu | ✓ | ✓ | ✓ | +| Linux aarch64 musl | ✓ | ✓ | ✓ | | Linux arm gnueabihf | ✓ | ✓ | ✓ | | Linux aarch64 android | ✓ | ✓ | ✓ | | FreeBSD x64 | ✓ | ✓ | ✓ | diff --git a/bench/Cargo.toml b/bench/Cargo.toml index 495b6c8e..d77b69ae 100644 --- a/bench/Cargo.toml +++ b/bench/Cargo.toml @@ -13,10 +13,10 @@ napi-derive = {path = "../napi-derive"} serde = "1" serde_json = "1" -[target.'cfg(all(unix, not(target_env = "musl"), not(target_arch = "aarch64")))'.dependencies] +[target.'cfg(all(unix, not(target_env = "musl"), not(target_arch = "aarch64"), not(target_arch = "arm")))'.dependencies] jemallocator = {version = "0.3", features = ["disable_initial_exec_tls"]} -[target.'cfg(windows)'.dependencies] +[target.'cfg(all(windows, not(target_arch = "aarch64")))'.dependencies] mimalloc = {version = "0.1"} [build-dependencies] diff --git a/bench/src/lib.rs b/bench/src/lib.rs index 196a6fdf..501b0640 100644 --- a/bench/src/lib.rs +++ b/bench/src/lib.rs @@ -7,7 +7,7 @@ use napi::{Env, JsObject, Result}; #[global_allocator] static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; -#[cfg(windows)] +#[cfg(all(windows, not(target_arch = "aarch64")))] #[global_allocator] static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; diff --git a/build/Cargo.toml b/build/Cargo.toml index 084eca87..0af42423 100644 --- a/build/Cargo.toml +++ b/build/Cargo.toml @@ -2,15 +2,10 @@ authors = ["LongYinan "] description = "N-API build support" edition = "2018" +include = ["src/**/*", "Cargo.toml", "README.md", "LICENSE"] keywords = ["NodeJS", "FFI", "NAPI", "n-api"] license = "MIT" name = "napi-build" readme = "README.md" repository = "https://github.com/napi-rs/napi-rs" version = "1.0.2" - -[dependencies] -cfg-if = "1" - -[target.'cfg(not(target_env = "musl"))'.dependencies] -ureq = "2" diff --git a/build/src/lib.rs b/build/src/lib.rs index 7a4e51b1..72046f9d 100644 --- a/build/src/lib.rs +++ b/build/src/lib.rs @@ -1,23 +1,10 @@ mod macos; - -cfg_if::cfg_if! { - if #[cfg(not(target_env = "musl"))] { - mod windows; - } -} +mod windows; pub fn setup() { match std::env::var("CARGO_CFG_TARGET_OS").as_deref() { Ok("macos") => macos::setup(), - Ok("windows") => { - cfg_if::cfg_if! { - if #[cfg(not(target_env = "musl"))] { - windows::setup() - } else { - eprintln!("Cross compiling to windows-msvc is not supported from *-musl hosts") - } - } - } + Ok("windows") => windows::setup(), _ => {} } } diff --git a/build/src/libs/node-arm64.lib b/build/src/libs/node-arm64.lib new file mode 100644 index 00000000..bf058776 Binary files /dev/null and b/build/src/libs/node-arm64.lib differ diff --git a/build/src/libs/node-x64.lib b/build/src/libs/node-x64.lib new file mode 100644 index 00000000..f9ca6c60 Binary files /dev/null and b/build/src/libs/node-x64.lib differ diff --git a/build/src/libs/node-x86.lib b/build/src/libs/node-x86.lib new file mode 100644 index 00000000..dcf9f592 Binary files /dev/null and b/build/src/libs/node-x86.lib differ diff --git a/build/src/windows.rs b/build/src/windows.rs index ae34ca10..362ccc53 100644 --- a/build/src/windows.rs +++ b/build/src/windows.rs @@ -1,54 +1,20 @@ #![allow(clippy::expect_fun_call)] -use std::collections::hash_map::DefaultHasher; use std::env; use std::fs::{metadata, write}; -use std::hash::{Hash, Hasher}; -use std::io::Read; use std::path::PathBuf; -use std::process::Command; -fn get_node_version() -> std::io::Result { - let output = Command::new("node").arg("-v").output()?; - let stdout_str = String::from_utf8_lossy(&output.stdout); - - // version should not have a leading "v" or trailing whitespace - Ok(stdout_str.trim().trim_start_matches('v').to_string()) -} - -fn download_node_lib(dist_url: &str, version: &str, arch: &str) -> Vec { - // Assume windows since we know we are building on windows. - let url = format!( - "{dist_url}/v{version}/win-{arch}/node.lib", - dist_url = dist_url, - version = version, - arch = arch - ); - - match ureq::get(&url).call() { - Ok(response) => { - let mut reader = response.into_reader(); - let mut bytes = vec![]; - reader.read_to_end(&mut bytes).unwrap(); - bytes - } - Err(error) => { - panic!("Failed to download node.lib: {:#?}", error); - } +fn copy_node_lib(arch: &str) -> Vec { + match arch { + "x64" => include_bytes!("libs/node-x64.lib").to_vec(), + "x86" => include_bytes!("libs/node-x86.lib").to_vec(), + "arm64" => include_bytes!("libs/node-arm64.lib").to_vec(), + _ => unreachable!(), } } pub fn setup() { let out_dir = env::var("OUT_DIR").expect("OUT_DIR is not set"); - // Assume nodejs if not specified. - let dist_url = - env::var("NPM_CONFIG_DISTURL").unwrap_or_else(|_| "https://nodejs.org/dist".to_string()); - - // Try to get local nodejs version if not specified. - let node_version = env::var("NPM_CONFIG_TARGET") - .or_else(|_| get_node_version()) - .expect("Failed to determine nodejs version"); - // NPM also gives us an arch var, but let's trust cargo more. // We translate from cargo's arch env format into npm/gyps's. // See https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch for rust env values. @@ -62,37 +28,23 @@ pub fn setup() { "x86_64" => "x64", // https://github.com/nodejs/node/issues/25998 // actually not supported for now - // because we can not get `node.lib` file for `aarch64` device + // but we can get it from https://unofficial-builds.nodejs.org/download/release + // just set the `NPM_CONFIG_DISTURL` to `https://unofficial-builds.nodejs.org/download/release` "aarch64" => "arm64", arch => panic!("Unsupported CPU Architecture: {}", arch), }) .expect("Failed to determine target arch"); - println!("cargo:rerun-if-env-changed=NPM_CONFIG_DISTURL"); - println!("cargo:rerun-if-env-changed=NPM_CONFIG_TARGET"); - let mut node_lib_file_path = PathBuf::from(out_dir); let link_search_dir = node_lib_file_path.clone(); - // Hash the dist_url and store it in the node lib file name. - let dist_url_hash = { - let mut hasher = DefaultHasher::new(); - dist_url.hash(&mut hasher); - hasher.finish() - }; - - // Encode version, arch, and dist_url to detect and reaquire node.lib when these 3 change. - let node_lib_file_name = format!( - "node-{version}-{arch}-{dist_url_hash}.lib", - version = node_version, - arch = arch, - dist_url_hash = dist_url_hash - ); + // Encode arch to detect and require node.lib. + let node_lib_file_name = format!("node-{arch}.lib", arch = arch,); node_lib_file_path.push(&node_lib_file_name); // If file does not exist, download it. if metadata(&node_lib_file_path).is_err() { - let node_lib = download_node_lib(&dist_url, &node_version, &arch); + let node_lib = copy_node_lib(&arch); write(&node_lib_file_path, &node_lib).expect(&format!( "Could not save file to {}",