diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index e9865f060db..3d6a99cfef8 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -1,5 +1,7 @@ //! Create a standalone native executable for a given Wasm file. +use self::utils::normalize_atom_name; + use super::ObjectFormat; use crate::common::normalize_path; use crate::store::CompilerOptions; @@ -531,7 +533,7 @@ impl PrefixMapCompilation { return Ok(Self { input_hashes: atoms .iter() - .map(|(name, bytes)| (name.clone(), Self::hash_for_bytes(bytes))) + .map(|(name, bytes)| (normalize_atom_name(name), Self::hash_for_bytes(bytes))) .collect(), manual_prefixes: BTreeMap::new(), compilation_objects: BTreeMap::new(), @@ -540,10 +542,10 @@ impl PrefixMapCompilation { // if prefixes are specified, have to match the atom names exactly if prefixes.len() != atoms.len() { - return Err(anyhow::anyhow!( - "invalid mapping of prefix and atoms: expected prefixes for {} atoms, got {} prefixes", + println!( + "WARNING: invalid mapping of prefix and atoms: expected prefixes for {} atoms, got {} prefixes", atoms.len(), prefixes.len() - )); + ); } let available_atoms = atoms.iter().map(|(k, _)| k.clone()).collect::>(); @@ -560,11 +562,11 @@ impl PrefixMapCompilation { [atom, prefix, path] => { if only_validate_prefixes { // only insert the prefix in order to not error out of the fs::read(path) - manual_prefixes.insert(atom.to_string(), prefix.to_string()); + manual_prefixes.insert(normalize_atom_name(atom), prefix.to_string()); } else { let atom_hash = atoms .iter() - .find_map(|(name, _)| if name.as_str() == atom.as_str() { Some(prefix.to_string()) } else { None }) + .find_map(|(name, _)| if normalize_atom_name(name) == normalize_atom_name(atom) { Some(prefix.to_string()) } else { None }) .ok_or_else(|| anyhow::anyhow!("no atom {atom:?} found, for prefix {p:?}, available atoms are {available_atoms:?}"))?; let current_dir = std::env::current_dir().unwrap().canonicalize().unwrap(); @@ -573,17 +575,17 @@ impl PrefixMapCompilation { anyhow::anyhow!("could not read file for atom {atom:?} (prefix {p}, path {} in dir {}): {e}", path.display(), current_dir.display()) })?; - compilation_objects.insert(atom.to_string(), bytes); - manual_prefixes.insert(atom.to_string(), atom_hash.to_string()); + compilation_objects.insert(normalize_atom_name(atom), bytes); + manual_prefixes.insert(normalize_atom_name(atom), atom_hash.to_string()); } } // atom + path, but default SHA256 prefix [atom, path] => { let atom_hash = atoms .iter() - .find_map(|(name, bytes)| if name.as_str() == atom.as_str() { Some(Self::hash_for_bytes(bytes)) } else { None }) + .find_map(|(name, bytes)| if normalize_atom_name(name) == normalize_atom_name(atom) { Some(Self::hash_for_bytes(bytes)) } else { None }) .ok_or_else(|| anyhow::anyhow!("no atom {atom:?} found, for prefix {p:?}, available atoms are {available_atoms:?}"))?; - manual_prefixes.insert(atom.to_string(), atom_hash.to_string()); + manual_prefixes.insert(normalize_atom_name(atom), atom_hash.to_string()); if !only_validate_prefixes { let current_dir = std::env::current_dir().unwrap().canonicalize().unwrap(); @@ -591,12 +593,12 @@ impl PrefixMapCompilation { let bytes = std::fs::read(&path).map_err(|e| { anyhow::anyhow!("could not read file for atom {atom:?} (prefix {p}, path {} in dir {}): {e}", path.display(), current_dir.display()) })?; - compilation_objects.insert(atom.to_string(), bytes); + compilation_objects.insert(normalize_atom_name(atom), bytes); } } // only prefix if atoms.len() == 1 [prefix] if atoms.len() == 1 => { - manual_prefixes.insert(atoms[0].0.clone(), prefix.to_string()); + manual_prefixes.insert(normalize_atom_name(&atoms[0].0), prefix.to_string()); } _ => { return Err(anyhow::anyhow!("invalid --precompiled-atom {p:?} - correct format is ATOM:PREFIX:PATH or ATOM:PATH")); @@ -735,7 +737,7 @@ fn compile_atoms( let mut module_infos = BTreeMap::new(); for (a, data) in atoms { let prefix = prefixes - .get_prefix_for_atom(a) + .get_prefix_for_atom(&normalize_atom_name(a)) .ok_or_else(|| anyhow::anyhow!("no prefix given for atom {a}"))?; let atom_name = utils::normalize_atom_name(a); let output_object_path = output_dir.join(format!("{atom_name}.o")); diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index 07289b1f9ec..069d8b887da 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -371,6 +371,73 @@ fn create_exe_works_multi_command_args_handling() -> anyhow::Result<()> { Ok(()) } +/// Tests that create-exe works with underscores and dashes in command names +// Ignored because of -lunwind linker issue on Windows +// see https://github.com/wasmerio/wasmer/issues/3459 +#[cfg_attr(target_os = "windows", ignore)] +#[test] +fn create_exe_works_underscore_module_name() -> anyhow::Result<()> { + let temp_dir = tempfile::tempdir()?; + let operating_dir: PathBuf = temp_dir.path().to_owned(); + let wasm_path = operating_dir.join(create_exe_wabt_path()); + + let atoms = &[ + "wabt", + "wasm-interp", + "wasm-strip", + "wasm-validate", + "wasm2wat", + "wast2json", + "wat2wasm", + ]; + + let mut create_exe_flags = Vec::new(); + + for a in atoms.iter() { + let object_path = operating_dir.as_path().join(&format!("{a}.o")); + let output: Vec = WasmerCreateObj { + current_dir: operating_dir.clone(), + wasm_path: wasm_path.clone(), + output_object_path: object_path.clone(), + compiler: Compiler::Cranelift, + extra_cli_flags: vec!["--atom".to_string(), a.to_string()], + ..Default::default() + } + .run() + .context("Failed to create-obj wasm with Wasmer")?; + + assert!( + object_path.exists(), + "create-obj successfully completed but object output file `{}` missing", + object_path.display() + ); + + create_exe_flags.push("--precompiled-atom".to_string()); + create_exe_flags.push(format!( + "{a}:{}", + object_path.canonicalize().unwrap().display() + )); + } + + #[cfg(not(windows))] + let executable_path = operating_dir.join("multicommand.out"); + #[cfg(windows)] + let executable_path = operating_dir.join("multicommand.exe"); + + WasmerCreateExe { + current_dir: operating_dir.clone(), + wasm_path, + native_executable_path: executable_path.clone(), + compiler: Compiler::Cranelift, + extra_cli_flags: create_exe_flags, + ..Default::default() + } + .run() + .context("Failed to create-exe wasm with Wasmer")?; + + Ok(()) +} + // Ignored because of -lunwind linker issue on Windows // see https://github.com/wasmerio/wasmer/issues/3459 #[cfg_attr(target_os = "windows", ignore)]