diff --git a/cli/src/build.ts b/cli/src/build.ts index e118c18b..02268fa7 100644 --- a/cli/src/build.ts +++ b/cli/src/build.ts @@ -1,4 +1,5 @@ import { execSync } from 'child_process' +import { createHash } from 'crypto' import { existsSync, mkdirSync } from 'fs' import { tmpdir } from 'os' import { join, parse, sep } from 'path' @@ -289,7 +290,6 @@ export class BuildCommand extends Command { additionalEnv['XWIN_ARCH'] = 'x86' } const cargoCommand = `${cargo} build ${externalFlags}` - const intermediateTypeFile = join(tmpdir(), `type_def.${Date.now()}.tmp`) debug(`Run ${chalk.green(cargoCommand)}`) const rustflags = process.env.RUSTFLAGS @@ -439,32 +439,7 @@ export class BuildCommand extends Command { PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${process.env.PATH}`, }) } - try { - execSync(cargoCommand, { - env: { - ...process.env, - ...additionalEnv, - TYPE_DEF_TMP_PATH: intermediateTypeFile, - }, - stdio: 'inherit', - cwd, - }) - } catch (e) { - if (cargo === 'cargo-xwin') { - console.warn( - `You are cross compiling ${chalk.underline( - triple.raw, - )} target on ${chalk.green(process.platform)} host`, - ) - } else if (isCrossForLinux || isCrossForMacOS) { - console.warn( - `You are cross compiling ${chalk.underline( - triple.raw, - )} on ${chalk.green(process.platform)} host`, - ) - } - throw e - } + const { binaryName, packageName } = getNapiConfig(this.configFileName) let cargoArtifactName = this.cargoName if (!cargoArtifactName) { @@ -494,6 +469,42 @@ export class BuildCommand extends Command { debug(`Dylib name: ${chalk.greenBright(cargoArtifactName)}`) } + const intermediateTypeFile = join( + tmpdir(), + `${cargoArtifactName}-${createHash('sha256') + .update(process.cwd()) + .digest('hex') + .substring(0, 8)}.napi_type_def.tmp`, + ) + debug(`intermediate type def file: ${intermediateTypeFile}`) + + try { + execSync(cargoCommand, { + env: { + ...process.env, + ...additionalEnv, + TYPE_DEF_TMP_PATH: intermediateTypeFile, + }, + stdio: 'inherit', + cwd, + }) + } catch (e) { + if (cargo === 'cargo-xwin') { + console.warn( + `You are cross compiling ${chalk.underline( + triple.raw, + )} target on ${chalk.green(process.platform)} host`, + ) + } else if (isCrossForLinux || isCrossForMacOS) { + console.warn( + `You are cross compiling ${chalk.underline( + triple.raw, + )} on ${chalk.green(process.platform)} host`, + ) + } + throw e + } + const platform = triple.platform let libExt = '' @@ -787,7 +798,6 @@ async function processIntermediateTypeFile( }\n` : '' - await unlinkAsync(source) await writeFileAsync( target, dtsHeader + externalDef + topLevelDef + namespaceDefs, diff --git a/crates/macro/src/lib.rs b/crates/macro/src/lib.rs index 889d3e1c..9e8293f0 100644 --- a/crates/macro/src/lib.rs +++ b/crates/macro/src/lib.rs @@ -11,6 +11,7 @@ extern crate quote; #[cfg(not(feature = "noop"))] use std::env; +use std::sync::atomic::{AtomicBool, Ordering}; #[cfg(all(feature = "type-def", not(feature = "noop")))] use std::{ fs, @@ -35,6 +36,17 @@ use syn::Item; #[cfg(feature = "compat-mode")] use syn::{fold::Fold, parse_macro_input, ItemFn}; +/// a flag indicate whether or never at least one `napi` macro has been expanded. +/// ```ignore +/// if BUILT_FLAG +/// .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) +/// .is_ok() { +/// // logic on first macro expansion +/// } +/// +/// ``` +static BUILT_FLAG: AtomicBool = AtomicBool::new(false); + /// ```ignore /// #[napi] /// fn test(ctx: CallContext, name: String) { @@ -44,6 +56,20 @@ use syn::{fold::Fold, parse_macro_input, ItemFn}; #[cfg(not(feature = "noop"))] #[proc_macro_attribute] pub fn napi(attr: RawStream, input: RawStream) -> RawStream { + if BUILT_FLAG + .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) + .is_ok() + { + // logic on first macro expansion + #[cfg(feature = "type-def")] + if let Ok(type_def_file) = env::var("TYPE_DEF_TMP_PATH") { + if let Err(_e) = fs::remove_file(type_def_file) { + // should only input in debug mode + // println!("Failed to manipulate type def file: {:?}", e); + } + } + } + match expand(attr.into(), input.into()) { Ok(tokens) => { if env::var("DEBUG_GENERATED_CODE").is_ok() {