diff --git a/src/Uno.Wasm.Bootstrap/ShellTask.cs b/src/Uno.Wasm.Bootstrap/ShellTask.cs index 00e81c287..c5008aa69 100644 --- a/src/Uno.Wasm.Bootstrap/ShellTask.cs +++ b/src/Uno.Wasm.Bootstrap/ShellTask.cs @@ -776,7 +776,13 @@ private void RunPackager() DirectoryCreateDirectory(workAotPath); - var referencePathsParameter = string.Join(" ", _referencedAssemblies.Select(Path.GetDirectoryName).Distinct().Select(r => $"--search-path=\"{AlignPath(r)}\"")); + var referencePathsParameter = string.Join( + " " + , _referencedAssemblies.Select(Path.GetDirectoryName).Distinct().Select(r => $"--search-path=\"{AlignPath(r)}\"")); + + var referenceAssembliesParameter = string.Join( + " " + , _referencedAssemblies.Distinct().Select(r => $"--asm-ref=\"{AlignPath(r)}\"")); var metadataUpdaterPath = Path.Combine(BuildTaskBasePath, "..", "tools", "support", "Uno.Wasm.MetadataUpdater.dll"); @@ -824,7 +830,7 @@ private void RunPackager() var enableICUParam = EnableNetCoreICU ? "--icu" : ""; var monovmparams = $"--framework=net5 --runtimepack-dir=\"{AlignPath(MonoWasmSDKPath)}\" {enableICUParam} {pthreadPoolSizeParam} --illinker-path=\"{_linkerBinPath}\""; - var pass1ResponseContent = $"{runtimeConfigurationParam} {appDirParm} {monovmparams} --zlib {debugOption} {referencePathsParameter} \"{AlignPath(TryConvertLongPath(Path.GetFullPath(Assembly)))}\""; + var pass1ResponseContent = $"{runtimeConfigurationParam} {appDirParm} {monovmparams} --zlib {debugOption} {referenceAssembliesParameter} {referencePathsParameter} \"{AlignPath(TryConvertLongPath(Path.GetFullPath(Assembly)))}\""; var packagerPass1ResponseFile = Path.Combine(workAotPath, "packager-pass1.rsp"); File.WriteAllText(packagerPass1ResponseFile, pass1ResponseContent); @@ -935,6 +941,7 @@ private void RunPackager() packagerParams.Add(EmccLinkOptimization ? "--emcc-link-optimization" : ""); packagerParams.Add(MonoILLinker ? "--linker --link-mode=all" : ""); packagerParams.Add(referencePathsParameter); + packagerParams.Add(referenceAssembliesParameter); packagerParams.Add(GenerateAOTProfile ? "--profile=aot" : ""); packagerParams.Add(EnableLogProfiler ? "--profile=log" : ""); packagerParams.Add(!string.IsNullOrEmpty(WasmTunerBinPath) ? $"\"--wasm-tuner-path={AlignPath(Path.GetFullPath(WasmTunerBinPath))}\"" : ""); @@ -1008,6 +1015,11 @@ private void RunPackager() var assemblyPath = Path.Combine(linkerInput, Path.GetFileName(Assembly)); + // Use explicit assemby references first + var referenceAssemblyPaths = _referencedAssemblies.Distinct().Select(p => $"-reference \"{p}\" "); + linkerParams.AddRange(referenceAssemblyPaths); + + // Then search for other known paths var linkerSearchPaths = _referencedAssemblies.Select(Path.GetDirectoryName).Distinct().Select(p => $"-d \"{p}\" "); linkerParams.AddRange(linkerSearchPaths); linkerParams.Add($"-d \"{_bclPath}\""); diff --git a/src/Uno.Wasm.Packager/CapturingAssemblyResolver.cs b/src/Uno.Wasm.Packager/CapturingAssemblyResolver.cs index 658ab85eb..5d45f9776 100644 --- a/src/Uno.Wasm.Packager/CapturingAssemblyResolver.cs +++ b/src/Uno.Wasm.Packager/CapturingAssemblyResolver.cs @@ -10,6 +10,12 @@ class CapturingAssemblyResolver : DefaultAssemblyResolver { private List> _files; + private List _assembly_references; + + public CapturingAssemblyResolver(List assembly_references) + { + _assembly_references = assembly_references; + } protected override AssemblyDefinition SearchDirectory(AssemblyNameReference name, IEnumerable directories, ReaderParameters parameters) { @@ -19,6 +25,24 @@ protected override AssemblyDefinition SearchDirectory(AssemblyNameReference name // paying the cost of File.Exists _files = new List>(); + + // Fill all the known references first, so they get resolved + // using compilation paths. + var explicitAssembliesPaths = new Dictionary(); + foreach (var asmReferencePath in _assembly_references) + { + if (Path.GetFileNameWithoutExtension(asmReferencePath) is { } asmName) + { + if (!explicitAssembliesPaths.ContainsKey(asmName)) + { + explicitAssembliesPaths.Add(asmName, asmReferencePath); + } + } + } + + _files.Add(explicitAssembliesPaths); + + // Use all other search paths string[] extensions = new[] { ".winmd", ".dll", ".exe", ".dll" }; foreach (var directory in directories.Where(Directory.Exists)) diff --git a/src/Uno.Wasm.Packager/packager.cs b/src/Uno.Wasm.Packager/packager.cs index 26a61ffb8..49593947e 100644 --- a/src/Uno.Wasm.Packager/packager.cs +++ b/src/Uno.Wasm.Packager/packager.cs @@ -61,6 +61,7 @@ class Driver { static List file_list = new List (); static HashSet assemblies_with_dbg_info = new HashSet (); static List root_search_paths = new List(); + static List assembly_references = new List(); static CapturingAssemblyResolver resolver; const string BINDINGS_ASM_NAME_MONO = "WebAssembly.Bindings"; @@ -278,7 +279,7 @@ static void Import (string ra, AssemblyKind kind) { if (resolver == null) { - resolver = new CapturingAssemblyResolver(); + resolver = new CapturingAssemblyResolver(assembly_references); root_search_paths.ForEach(resolver.AddSearchDirectory); foreach (var prefix in bcl_prefixes) resolver.AddSearchDirectory(prefix); @@ -554,6 +555,7 @@ int Run (string[] args) { { "template=", s => runtimeTemplate = s }, { "asset=", s => assets.Add(s) }, { "search-path=", s => root_search_paths.Add(s) }, + { "asm-ref=", s => assembly_references.Add(s) }, { "profile=", s => profilers.Add (s) }, { "copy=", s => copyTypeParm = s }, { "aot-assemblies=", s => aot_assemblies = s }, @@ -1584,6 +1586,7 @@ int Run (string[] args) { ninja.WriteLine ("rule linker"); var linkerBin = "dotnet \'$linker_dir/illink.dll\'"; + var assemblyRefPaths = assembly_references.Distinct().Select(p => $"-reference \"{p}\" "); var linkerSearchPaths = root_search_paths.Concat(bcl_prefixes).Distinct().Select(p => $"-d \"{p}\" "); var tunerBinary = string.IsNullOrEmpty(wasm_tuner_path) @@ -1597,6 +1600,7 @@ int Run (string[] args) { linker_args.Add($"-out ./linker-out --deterministic --disable-opt unreachablebodies"); linker_args.Add($"--strip-link-attributes"); linker_args.Add(extra_linkerflags); + linker_args.AddRange(assemblyRefPaths); linker_args.AddRange(linkerSearchPaths); ninja.WriteLine ($" command = {tools_shell_prefix} {linkerBin} \'@{linkerResponse}\' {exitCommand}; {tunerCommand} --gen-empty-assemblies \'@$builddir/tuner.rsp\'");