From d1d6a5b963caec333efe60164c42e1243a9b161b Mon Sep 17 00:00:00 2001 From: LongYinan Date: Fri, 9 Oct 2020 21:37:14 +0800 Subject: [PATCH] refactor(build): use node to download .lib file on Windows --- .github/workflows/test.yaml | 2 +- build/Cargo.toml | 13 +++----- build/src/lib.rs | 61 +++++++++++++++++++------------------ sys/Cargo.toml | 21 +++++-------- sys/build.rs | 31 +++++++++---------- 5 files changed, 58 insertions(+), 70 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 75e04921..e6478f8c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,7 +30,7 @@ jobs: - name: Set llvm path if: matrix.os == 'windows-latest' - uses: allenevans/set-env@v1.0.0 + uses: allenevans/set-env@v1.1.0 with: LIBCLANG_PATH: 'C:\Program Files\LLVM\bin' diff --git a/build/Cargo.toml b/build/Cargo.toml index 0b91bdab..d05b0d32 100644 --- a/build/Cargo.toml +++ b/build/Cargo.toml @@ -1,16 +1,13 @@ [package] -name = "napi-build" -version = "0.2.1" authors = ["LongYinan "] -edition = "2018" description = "N-API build support" +edition = "2018" +keywords = ["NodeJS", "FFI", "NAPI", "n-api"] +license = "MIT" +name = "napi-build" readme = "README.md" repository = "https://github.com/napi-rs/napi-rs" -license = "MIT" -keywords = ["NodeJS", "FFI", "NAPI", "n-api"] +version = "0.2.1" [dependencies] cfg-if = "1.0" - -[target.'cfg(windows)'.dependencies] -reqwest = { version = "0.10", features = ["native-tls", "blocking"] } diff --git a/build/src/lib.rs b/build/src/lib.rs index d919ee11..11fa666f 100644 --- a/build/src/lib.rs +++ b/build/src/lib.rs @@ -1,6 +1,4 @@ extern crate cfg_if; -#[cfg(windows)] -extern crate reqwest; use std::process::Command; @@ -8,54 +6,57 @@ use cfg_if::cfg_if; cfg_if! { if #[cfg(windows)] { - use std::env::var; - use std::fs::{File, create_dir}; - use std::io::copy; + use std::fs::{create_dir, metadata, write}; use std::path::PathBuf; + fn download_node_lib() -> Vec { + let script = format!(" + require('https').get('https://nodejs.org/dist/' + process.version + '/win-x64/node.lib', (res) => {{ + res.pipe(process.stdout) + }})"); + + Command::new("node") + .arg("-e") + .arg(script) + .output() + .expect("Download node.lib failed") + .stdout + } + pub fn setup() { let node_full_version = String::from_utf8(Command::new("node").arg("-v").output().unwrap().stdout).unwrap(); + let trim_node_full_version = node_full_version.trim_end(); + let mut node_lib_file_dir = + PathBuf::from(String::from_utf8(Command::new("node").arg("-e").arg("console.log(require('os').homedir())").output().unwrap().stdout).unwrap().trim_end().to_owned()); - let dev_dir: PathBuf = [ - &var("HOMEDRIVE").expect("Get env HOMEDRIVE failed"), - &var("HOMEPATH").expect("Get env HOMEDRIVE failed"), - ".napi-rs" - ].iter().collect(); + node_lib_file_dir.push(".napi-rs"); - match create_dir(&dev_dir) { + match create_dir(&node_lib_file_dir) { Ok(_) => {}, Err(err) => { if err.kind() != std::io::ErrorKind::AlreadyExists { - panic!("create ~/.napi-rs folder failed: {}", err) + panic!("create {} folder failed: {}", node_lib_file_dir.to_str().unwrap(), err) } }, } - let node_lib_file_dir = dev_dir.join(format!("node-{}.lib", node_full_version.trim_end())); - if !node_lib_file_dir.exists() { - let lib_file_download_url = format!( - "https://nodejs.org/dist/{}/win-x64/node.lib", - node_full_version - ); - let mut resp = - reqwest::blocking::get(&lib_file_download_url).expect("Download node.lib file failed"); - let mut node_lib_file = File::create(&node_lib_file_dir).unwrap(); - copy(&mut resp, &mut node_lib_file).expect("Save node.lib file failed"); + let link_search_dir = node_lib_file_dir.clone(); + + node_lib_file_dir.push(format!("node-{}.lib", trim_node_full_version)); + + if let Err(_) = metadata(&node_lib_file_dir) { + let node_lib = download_node_lib(); + write(&node_lib_file_dir, &node_lib).expect(&format!("Could not save file to {}", node_lib_file_dir.to_str().unwrap())); } println!( "cargo:rustc-link-lib={}", &node_lib_file_dir.file_stem().unwrap().to_str().unwrap() ); - println!("cargo:rustc-link-search={}", dev_dir.to_str().unwrap()); + println!("cargo:rustc-link-search=native={}", link_search_dir.to_str().unwrap()); // Link `win_delay_load_hook.obj` for windows electron - let node_runtime_env = "npm_config_runtime"; - println!("cargo:rerun-if-env-changed={}", node_runtime_env); - if var(node_runtime_env).map(|s| s == "electron") == Ok(true) { - println!("cargo:rustc-cdylib-link-arg=win_delay_load_hook.obj"); - println!("cargo:rustc-cdylib-link-arg=delayimp.lib"); - println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe"); - } + println!("cargo:rustc-cdylib-link-arg=delayimp.lib"); + println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe"); setup_napi_feature(); } } else if #[cfg(target_os = "macos")] { diff --git a/sys/Cargo.toml b/sys/Cargo.toml index 9af143eb..5948f892 100644 --- a/sys/Cargo.toml +++ b/sys/Cargo.toml @@ -1,23 +1,16 @@ [package] -name = "napi-sys" -version = "0.4.7" authors = ["LongYinan "] -edition = "2018" -readme = "README.md" description = "NodeJS N-API raw binding" -repository = "https://github.com/napi-rs/napi-rs" -license = "MIT" -keywords = ["NodeJS", "FFI", "NAPI", "n-api"] +edition = "2018" include = ["src/**/*", "Cargo.toml", "build.rs", ".node-headers/**/*"] +keywords = ["NodeJS", "FFI", "NAPI", "n-api"] +license = "MIT" +name = "napi-sys" +readme = "README.md" +repository = "https://github.com/napi-rs/napi-rs" +version = "0.4.7" [target.'cfg(windows)'.build-dependencies] -flate2 = "1.0" -reqwest = { version = "0.10", features = ["native-tls", "blocking"] } -tar = "0.4" - -[target.x86_64-unknown-linux-gnu.build-dependencies] -flate2 = "1.0" -reqwest = { version = "0.10", features = ["native-tls", "blocking"] } tar = "0.4" [build-dependencies] diff --git a/sys/build.rs b/sys/build.rs index 85d4d948..7959c3c8 100644 --- a/sys/build.rs +++ b/sys/build.rs @@ -1,9 +1,5 @@ extern crate bindgen; -#[cfg(target_os = "windows")] -extern crate flate2; extern crate glob; -#[cfg(target_os = "windows")] -extern crate reqwest; extern crate semver; #[cfg(target_os = "windows")] extern crate tar; @@ -40,12 +36,12 @@ fn main() { let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut sys_bindigs_path = PathBuf::from("src"); - sys_bindigs_path.push("bindings.h"); + let mut sys_bindings_path = PathBuf::from("src"); + sys_bindings_path.push("bindings.h"); bindgen::Builder::default() .derive_default(true) - .header(sys_bindigs_path.to_str().unwrap().to_owned()) + .header(sys_bindings_path.to_str().unwrap().to_owned()) .clang_arg(String::from("-I") + node_include_path.to_str().unwrap()) .rustified_enum("(napi_|uv_).+") .whitelist_function("(napi_|uv_|extras_).+") @@ -66,16 +62,17 @@ fn find_node_include_path(node_full_version: &str) -> PathBuf { header_dist_path.push("include"); header_dist_path.push("node"); if !header_dist_path.exists() { - let header_file_download_url = String::from_utf8( - Command::new("node") - .args(vec!["-e", "console.log(process.release.headersUrl)"]) - .output() - .unwrap() - .stdout, - ) - .unwrap(); - let resp = reqwest::blocking::get(&header_file_download_url).expect("request failed"); - tar::Archive::new(flate2::read::GzDecoder::new(resp)) + let script = r#"require('https').get(process.release.headersUrl, function (res) { + res.pipe(require('zlib').createUnzip()).pipe(process.stdout) + })"#; + + let tar_binary = Command::new("node") + .arg("-e") + .arg(script) + .output() + .expect("Download headers file failed") + .stdout; + tar::Archive::new(tar_binary.as_slice()) .unpack(&unpack_path) .expect("Unpack headers file failed"); };