Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish Electron Support #271

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6aae9d0
Always download node headers on all platforms
adumbidiot Nov 1, 2020
cdccd3b
Use rustls in ureq to avoid depending on OpenSSL on Linux
adumbidiot Nov 1, 2020
9974398
Always download node headers on all platforms
adumbidiot Nov 1, 2020
1625ac5
Use rustls in ureq to avoid depending on OpenSSL on Linux
adumbidiot Nov 1, 2020
b208d25
Merge branch 'electron' of https://github.com/adumbidiot/napi-rs into…
adumbidiot Nov 2, 2020
0ac73d8
Require users to set minimum napi version
adumbidiot Nov 2, 2020
8e24635
Merge remote-tracking branch 'upstream/master' into electron
adumbidiot Nov 3, 2020
52cade2
Add ci-script to simplify testing
adumbidiot Nov 5, 2020
4db3ae4
Fix pre-commit hook on windows
adumbidiot Nov 5, 2020
b502337
Merge remote-tracking branch 'upstream/master' into electron
adumbidiot Nov 5, 2020
770c14b
Fix bad napi feature flag in js_value object
adumbidiot Nov 5, 2020
b378453
Fix `yarn-lint` on windows
adumbidiot Nov 5, 2020
e521728
Remove `--all` flag from napi3 `cargo check`
adumbidiot Nov 5, 2020
787fdd6
Add `--no-default-features` to napi3 napi crate build
adumbidiot Nov 5, 2020
c964aab
Set napi feature correctly in `napi-derive-example`
adumbidiot Nov 5, 2020
dcc22ad
Refactor napi3 ci to use utilize ci helper script to run `cargo check`
adumbidiot Nov 5, 2020
8639d43
Fix linux napi3 ci
adumbidiot Nov 5, 2020
936bb76
Update yarn.lock
adumbidiot Nov 5, 2020
ec7912b
Copy changes from napi3 to test workflow
adumbidiot Nov 5, 2020
3952c12
Fallback to local napi version on ci for test_module
adumbidiot Nov 5, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .github/workflows/napi3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,19 @@ jobs:
- name: 'Build TypeScript'
run: yarn --ignore-engines build

- name: 'Set USE_NAPI_VERSION env'
run: echo "USE_NAPI_VERSION=3" >> $GITHUB_ENV
shell: bash

- name: Check build
uses: actions-rs/cargo@v1
with:
command: check
args: --all --bins --examples --tests -vvv
run: node ./ci-scripts/index.js cargo-check-all

- name: Tests
uses: actions-rs/cargo@v1
timeout-minutes: 5
with:
command: test
args: -p napi-sys --lib -- --nocapture
args: --manifest-path sys/Cargo.toml -p napi-sys -- --nocapture

- name: Unit tests
run: |
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,12 @@ jobs:
- name: 'Build TypeScript'
run: yarn build

- name: 'Set USE_NAPI_VERSION env'
run: node -e "process.stdout.write('USE_NAPI_VERSION=' + process.versions.napi)" >> $GITHUB_ENV
shell: bash

- name: Check build
uses: actions-rs/cargo@v1
with:
command: check
args: --all --bins --examples --tests -vvv
run: node ./ci-scripts/index.js cargo-check-all

- name: Tests
uses: actions-rs/cargo@v1
Expand Down
6 changes: 3 additions & 3 deletions build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ version = "0.2.1"

[dependencies]
cfg-if = "1.0"

[target.'cfg(windows)'.dependencies]
ureq = { version = "1.5.0", default-features = false, features = [ "native-tls" ] }
flate2 = "1.0.18"
tar = "0.4.3"
ureq = "1.5.0"
63 changes: 41 additions & 22 deletions build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,54 @@ cfg_if::cfg_if! {
mod macos;
pub use macos::setup;
} else {
pub fn setup() {
setup_napi_feature();
}
pub fn setup() {}
}
}

use flate2::read::GzDecoder;
use std::io::Read;
use std::process::Command;

pub fn setup_napi_feature() {
let napi_version = String::from_utf8(
Command::new("node")
.args(&["-e", "console.log(process.versions.napi)"])
.output()
.unwrap()
.stdout,
)
.expect("Get NAPI version failed");
/// Try to get the node version from the env.
/// Falls back to the currently installed node's version.
/// Emits cargo metadata to recompile when the env changes.
pub fn get_target_node_version() -> Result<String, std::io::Error> {
// Recompile if node version changes.
println!("cargo:rerun-if-env-changed=NPM_CONFIG_TARGET");

let napi_version_number = napi_version.trim().parse::<u32>().unwrap();
std::env::var("NPM_CONFIG_TARGET").or_else(|_| {
let output = Command::new("node").arg("-v").output()?;
let stdout_str = String::from_utf8_lossy(&output.stdout);

if napi_version_number < 2 {
panic!("current napi version is too low");
}
// version should not have a leading "v" or trailing whitespace
Ok(stdout_str.trim().trim_start_matches('v').to_string())
})
}

if napi_version_number == 2 {
println!("cargo:rustc-cfg=napi{}", napi_version_number);
} else {
for version in 2..(napi_version_number + 1) {
println!("cargo:rustc-cfg=napi{}", version);
}
/// Try to get the dist url from the env.
/// Assume nodejs's dist url if not specified.
/// Emits cargo metadata to recompile when the env changes.
pub fn get_dist_url() -> String {
println!("cargo:rerun-if-env-changed=NPM_CONFIG_DISTURL");

std::env::var("NPM_CONFIG_DISTURL").unwrap_or_else(|_| "https://nodejs.org/dist".to_string())
}

/// Download the node headers from the given version and dist url and returns the decoded archive.
/// # Panics
/// Panics on failure.
pub fn download_node_headers(dist_url: &str, version: &str) -> tar::Archive<impl Read> {
let url = format!(
"{dist_url}/v{version}/node-v{version}-headers.tar.gz",
dist_url = dist_url,
version = version
);

let response = ureq::get(&url).call();
if let Some(error) = response.synthetic_error() {
panic!("Failed to download node headers: {:#?}", error);
}

let tar = GzDecoder::new(response.into_reader());
tar::Archive::new(tar)
}
1 change: 0 additions & 1 deletion build/src/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ pub fn setup() {
println!("cargo:rustc-cdylib-link-arg=-Wl");
println!("cargo:rustc-cdylib-link-arg=-undefined");
println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
setup_napi_feature();
}
24 changes: 2 additions & 22 deletions build/src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ use std::hash::{Hash, Hasher};
use std::io::Read;
use std::path::PathBuf;

fn get_node_version() -> std::io::Result<String> {
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<u8> {
// Assume windows since we know we are building on windows.
let url = format!(
Expand All @@ -36,15 +28,8 @@ fn download_node_lib(dist_url: &str, version: &str, arch: &str) -> Vec<u8> {

pub fn setup() {
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is not set");

// Assume nodejs if not specified.
let dist_url =
std::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 = std::env::var("NPM_CONFIG_TARGET")
.or_else(|_| get_node_version())
.expect("Failed to determine nodejs version");
let dist_url = get_dist_url();
let node_version = get_target_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.
Expand All @@ -64,9 +49,6 @@ pub fn setup() {
})
.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();

Expand Down Expand Up @@ -106,6 +88,4 @@ pub fn setup() {
);
println!("cargo:rustc-cdylib-link-arg=delayimp.lib");
println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe");

setup_napi_feature();
}
37 changes: 37 additions & 0 deletions ci-scripts/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const childProcess = require('child_process')
const yargs = require('yargs')
const toml = require('toml')
const fs = require('fs')

let napiVersion = process.env['USE_NAPI_VERSION'] || process.versions.napi

const argv = yargs
.command('build', 'Builds a module', {}, build)
.command(
'cargo-check-all',
'Runs cargo check on all crates',
{},
cargoCheckAll,
).argv

function build(args) {
childProcess.execSync(`cargo build --features=napi${napiVersion}`)
}

function cargoCheckAll(args) {
let topLevelTomlString = fs.readFileSync('./Cargo.toml')
let topLevelToml = toml.parse(topLevelTomlString)
let workspaceMembers = topLevelToml.workspace.members

for (let i = 0; i < workspaceMembers.length; i++) {
let member = workspaceMembers[i]
let command = `cargo check --manifest-path ${member}/Cargo.toml --bins --examples --tests -vvv`

if (member === './napi')
command += ` --no-default-features --features=napi${napiVersion}`

console.log('Running: ' + command)

childProcess.execSync(command)
}
}
2 changes: 1 addition & 1 deletion napi-derive-example/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ version = "0.1.0"
crate-type = ["cdylib"]

[dependencies]
napi = {path = "../napi"}
napi = { path = "../napi", default-features = false }
napi-derive = {path = "../napi-derive"}

[build-dependencies]
Expand Down
10 changes: 10 additions & 0 deletions napi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,21 @@ repository = "https://github.com/napi-rs/napi-rs"
version = "0.5.1"

[features]
default = [ "napi7" ]

latin1 = ["encoding_rs"]
libuv = ["futures"]
serde-json = ["serde", "serde_json"]
tokio_rt = ["futures", "tokio", "once_cell"]

napi7 = [ "napi6" ]
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if add a feature system-napi to compatible with the previous behavior? So that you don't need to change the build scripts on CI and people have more choice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to avoid that that since thats probably not what most people want, but I agree that it would simplify everything greatly and provide backwards compatibility. I'll make that change and document these features on the readme.

napi6 = [ "napi5" ]
napi5 = [ "napi4" ]
napi4 = [ "napi3" ]
napi3 = [ "napi2" ]
napi2 = [ "napi1" ]
napi1 = []

[dependencies]
napi-sys = {version = "0.4", path = "../sys"}

Expand Down
3 changes: 0 additions & 3 deletions napi/build.rs

This file was deleted.

36 changes: 18 additions & 18 deletions napi/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@ use crate::{sys, Error, NodeVersion, Result, Status};

#[cfg(all(feature = "serde-json"))]
use crate::js_values::{De, Ser};
#[cfg(all(any(feature = "libuv", feature = "tokio_rt"), napi4))]
#[cfg(all(any(feature = "libuv", feature = "tokio_rt"), feature = "napi4"))]
use crate::promise;
#[cfg(napi4)]
#[cfg(feature = "napi4")]
use crate::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction};
#[cfg(all(feature = "tokio_rt", napi4))]
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use crate::tokio_rt::{get_tokio_sender, Message};
#[cfg(all(feature = "libuv", napi4))]
#[cfg(all(feature = "libuv", feature = "napi4"))]
use crate::uv;
#[cfg(all(feature = "serde-json"))]
use serde::de::DeserializeOwned;
#[cfg(all(feature = "serde-json"))]
use serde::Serialize;
#[cfg(all(feature = "libuv", napi4))]
#[cfg(all(feature = "libuv", feature = "napi4"))]
use std::future::Future;
#[cfg(all(feature = "tokio_rt", napi4))]
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use tokio::sync::mpsc::error::TrySendError;

pub type Callback = extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
Expand Down Expand Up @@ -90,22 +90,22 @@ impl Env {
Ok(JsNumber::from_raw_unchecked(self.0, raw_value))
}

#[cfg(napi6)]
#[cfg(feature = "napi6")]
/// [n_api_napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64)
pub fn create_bigint_from_i64(&self, value: i64) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_bigint_int64(self.0, value, &mut raw_value) })?;
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
}

#[cfg(napi6)]
#[cfg(feature = "napi6")]
pub fn create_bigint_from_u64(&self, value: u64) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?;
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
}

#[cfg(napi6)]
#[cfg(feature = "napi6")]
pub fn create_bigint_from_i128(&self, value: i128) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut();
let sign_bit = if value > 0 { 0 } else { 1 };
Expand All @@ -116,15 +116,15 @@ impl Env {
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
}

#[cfg(napi6)]
#[cfg(feature = "napi6")]
pub fn create_bigint_from_u128(&self, value: u128) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut();
let words = &value as *const u128 as *const u64;
check_status(unsafe { sys::napi_create_bigint_words(self.0, 0, 2, words, &mut raw_value) })?;
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
}

#[cfg(napi6)]
#[cfg(feature = "napi6")]
/// [n_api_napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words)
/// The resulting BigInt will be negative when sign_bit is true.
pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec<u64>) -> Result<JsBigint> {
Expand Down Expand Up @@ -549,14 +549,14 @@ impl Env {
.map_err(|e| Error::new(Status::InvalidArg, format!("{}", e)))
}

#[cfg(napi2)]
#[cfg(feature = "napi2")]
pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> {
let mut uv_loop: *mut sys::uv_loop_s = ptr::null_mut();
check_status(unsafe { sys::napi_get_uv_event_loop(self.0, &mut uv_loop) })?;
Ok(uv_loop)
}

#[cfg(napi3)]
#[cfg(feature = "napi3")]
pub fn add_env_cleanup_hook<T, F>(
&mut self,
cleanup_data: T,
Expand All @@ -581,7 +581,7 @@ impl Env {
Ok(CleanupEnvHook(hook_ref))
}

#[cfg(napi3)]
#[cfg(feature = "napi3")]
pub fn remove_env_cleanup_hook<T>(&mut self, hook: CleanupEnvHook<T>) -> Result<()>
where
T: 'static,
Expand All @@ -591,7 +591,7 @@ impl Env {
})
}

#[cfg(napi4)]
#[cfg(feature = "napi4")]
pub fn create_threadsafe_function<
T: Send,
V: NapiValue,
Expand All @@ -605,7 +605,7 @@ impl Env {
ThreadsafeFunction::create(self.0, func, max_queue_size, callback)
}

#[cfg(all(feature = "libuv", napi4))]
#[cfg(all(feature = "libuv", feature = "napi4"))]
pub fn execute<
T: 'static + Send,
V: 'static + NapiValue,
Expand All @@ -629,7 +629,7 @@ impl Env {
Ok(JsObject::from_raw_unchecked(self.0, raw_promise))
}

#[cfg(all(feature = "tokio_rt", napi4))]
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
pub fn execute_tokio_future<
T: 'static + Send,
V: 'static + NapiValue,
Expand Down Expand Up @@ -664,7 +664,7 @@ impl Env {
Ok(JsObject::from_raw_unchecked(self.0, raw_promise))
}

#[cfg(napi5)]
#[cfg(feature = "napi5")]
pub fn create_date(&self, time: f64) -> Result<JsDate> {
let mut js_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_date(self.0, time, &mut js_value) })?;
Expand Down
Loading