diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e7a4492c3..8af406da0 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -30,9 +30,16 @@ jobs: uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} + - name: Install libclang + uses: KyleMayes/install-llvm-action@7770802 + with: + version: "10" + directory: ${{ runner.temp }}/llvm # - name: update node-gyp to latest # # https://github.com/nodejs/node-gyp/issues/1933#issuecomment-586915535 # run: npm install -g node-gyp@latest - run: npm config set msvs_version 2019 - name: run cargo test run: cargo test --release + env: + LIBCLANG_PATH: ${{ runner.temp }}/llvm/bin diff --git a/crates/neon-build/src/lib.rs b/crates/neon-build/src/lib.rs index 1280bc30f..9c0cba543 100644 --- a/crates/neon-build/src/lib.rs +++ b/crates/neon-build/src/lib.rs @@ -31,6 +31,79 @@ cfg_if! { println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe"); } } + } else if #[cfg(windows)] { + // ^ automatically not neon-sys + use std::io::{Error, ErrorKind, Write, Result}; + use std::process::Command; + use std::path::Path; + + fn node_version() -> Result { + let output = Command::new("node").arg("-v").output()?; + if !output.status.success() { + let _ = std::io::stderr().write_all(&output.stderr); + panic!("Could not download node.lib. There is likely more information from stderr above."); + } + let stdout = String::from_utf8(output.stdout).map_err(|error| { + Error::new(ErrorKind::InvalidData, error) + })?; + Ok(stdout.trim().to_string()) + } + + fn download_node_lib(version: &str, arch: &str) -> Result> { + let script = r#" + var url = process.argv[1] + require("https").get(url, function (res) { + res.pipe(process.stdout); + }); + "#; + let url = format!("https://nodejs.org/dist/{version}/win-{arch}/node.lib", version = version, arch = arch); + + let output = Command::new("node") + .arg("-e").arg(script) + .arg(url) + .output()?; + + Ok(output.stdout) + } + + /// Set up the build environment by setting Cargo configuration variables. + pub fn setup() { + // If the user specified a node.lib path, we do not need to download + if let Some(node_lib_path) = std::env::var_os("NEON_NODE_LIB") { + let node_lib_path = Path::new(&node_lib_path); + // Clearing the file name returns the root+directory name + let dir = node_lib_path.with_file_name(""); + let basename = node_lib_path.file_stem().expect("Could not parse lib name from NEON_NODE_LIB. Does the path include the full file name?"); + + println!("cargo:rustc-link-search=native={}", dir.display()); + // `basename` is an OsStr, we can output it anyway by re-wrapping it in a Path + // Both `dir` and `basename` will be mangled (contain replacement characters) if + // they are not UTF-8 paths. If we don't mangle them though, Cargo will: so + // non-UTF-8 paths are simply not supported. + println!("cargo:rustc-link-lib={}", Path::new(basename).display()); + return; + } + + let version = std::env::var("npm_config_target") + .or_else(|_| node_version()) + .expect("Could not determine Node.js version"); + let arch = if std::env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "x86" { + "x86" + } else { + "x64" + }; + + let node_lib_store_path = format!(r"{}/node-{}.lib", env!("OUT_DIR"), arch); + + // Download node.lib if it does not exist + if let Err(_) = std::fs::metadata(&node_lib_store_path) { + let node_lib = download_node_lib(&version, arch).expect("Could not download `node.lib`"); + std::fs::write(&node_lib_store_path, &node_lib).expect("Could not save `node.lib`"); + } + + println!("cargo:rustc-link-search=native={}", env!("OUT_DIR")); + println!("cargo:rustc-link-lib=node-{}", arch); + } } else if #[cfg(target_os = "macos")] { /// Set up the build environment by setting Cargo configuration variables. pub fn setup() { diff --git a/src/lib.rs b/src/lib.rs index e4bfb1516..c17e7af66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -383,7 +383,7 @@ mod tests { }; eprintln!("Running Neon test: {} {} {}", shell, command_flag, cmd); - + assert!(Command::new(&shell) .current_dir(dir) .args(&[&command_flag, cmd]) @@ -495,11 +495,10 @@ mod tests { if std::env::var("CI") == Ok("true".to_string()) { run("cargo package", &test_package); } else { - run("cargo package --allow-dirty", &test_package); + run("cargo package --allow-dirty", &test_package); } } - #[cfg(not(windows))] #[test] fn napi_test() { let _guard = TEST_MUTEX.lock();