diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index 77ec17437b8a1e..a122b1b40d0829 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -861,9 +861,24 @@ extends:
jobParameters:
timeoutInMinutes: 120
nameSuffix: CLR_Tools_Tests
+ # Depend on the browser-wasm libraries built below so the wasm crossgen2 R2R test
+ # (ILCompiler.ReadyToRun.Tests) can compile against real browser-wasm references.
+ dependsOn:
+ - build_browser_wasm_linux_Release_CLR_Tools_Tests_WasmLibs
buildArgs: -s clr.aot+clr.iltools+clr.corelib+clr.nativecorelib+libs.sfx+clr.toolstests+tools.cdac+tools.cdactests -c $(_BuildConfig) -test
enablePublishTestResults: true
testResultsFormat: 'xunit'
+ preBuildSteps:
+ # Lay the browser-wasm libraries into artifacts/bin so TestPaths' WasmRuntimePackDir
+ # resolves and the wasm R2R test compiles against real browser-wasm references.
+ - template: /eng/pipelines/common/download-artifact-step.yml
+ parameters:
+ artifactName: CLR_Tools_Tests_WasmLibs_BuildArtifacts_browser_wasm_Release
+ artifactFileName: CLR_Tools_Tests_WasmLibs_BuildArtifacts_browser_wasm_Release$(archiveExtension)
+ unpackFolder: $(Build.SourcesDirectory)/artifacts/bin
+ cleanUnpackFolder: false
+ overwriteExistingFiles: true
+ displayName: Browser-Wasm Libraries
# We want to run AOT tests when illink changes because there's share code and tests from illink which are used by AOT
condition: >-
or(
@@ -871,6 +886,36 @@ extends:
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true),
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_cdac.containsChange'], true),
eq(variables['isRollingBuild'], true))
+
+ # Build the browser-wasm managed runtime pack that the CLR_Tools_Tests job uses
+ # as crossgen2 references for the wasm ReadyToRun test. Native runtime and host
+ # assets are omitted because the test only consumes managed assemblies.
+ - template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ buildConfig: Release
+ platforms:
+ - browser_wasm
+ jobParameters:
+ nameSuffix: CLR_Tools_Tests_WasmLibs
+ buildArgs: -s clr.corelib+libs+libs.pretest -c Release /p:IncludeStaticLibrariesInPack=false
+ timeoutInMinutes: 120
+ postBuildSteps:
+ - template: /eng/pipelines/common/upload-artifact-step.yml
+ parameters:
+ rootFolder: $(Build.SourcesDirectory)/artifacts/bin
+ includeRootFolder: false
+ archiveType: $(archiveType)
+ archiveExtension: $(archiveExtension)
+ tarCompression: $(tarCompression)
+ artifactName: CLR_Tools_Tests_WasmLibs_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)
+ displayName: Browser-Wasm Libraries
+ condition: >-
+ or(
+ eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true),
+ eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true),
+ eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_cdac.containsChange'], true),
+ eq(variables['isRollingBuild'], true))
#
# Build CrossDacs
#
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj
index e3f0ab6ea0cd15..7d99e13fac1471 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj
@@ -12,6 +12,7 @@
Debug;Release;Checked
true
-notrait category=failing
+ false
@@ -19,92 +20,97 @@
+
+
+
+
+
+
-
-
- CopyAllJitLibrariesToAotCompilerOutput=true
- Configuration=$(CoreCLRConfiguration);CopyAllJitLibrariesToAotCompilerOutput=true
+
+ Configuration=$(CoreCLRConfiguration);CopyAllJitLibrariesToAotCompilerOutput=true
-
- <_BuildJitsCrossArch Condition="'$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)' or '$(HostOS)' != '$(TargetOS)' or '$(EnableNativeSanitizers)' != ''">true
- <_BuildJitsProperties>ClrAllJitsSubset=true;ClrWasmJitSubset=true;Configuration=$(CoreCLRConfiguration)
- <_BuildJitsProperties Condition="!$([MSBuild]::IsOsPlatform(Windows))">$(_BuildJitsProperties);Ninja=true
- <_BuildJitsProperties Condition="'$(_BuildJitsCrossArch)' == 'true'">$(_BuildJitsProperties);HostArchitecture=$(BuildArchitecture);HostCrossOS=$(HostOS);CrossBuild=false;BuildSubdirectory=$(BuildArchitecture);CMakeArgs=$(CMakeArgs) -DCLR_CROSS_COMPONENTS_BUILD=1;PgoInstrument=false;NoPgoOptimize=true
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'microsoft.netcore.app.runtime.browser-wasm'))
+ $([MSBuild]::NormalizeDirectory('$(WasmRuntimePackRoot)', '$(LibrariesConfiguration)', 'runtimes', 'browser-wasm', 'lib', '$(NetCoreAppCurrent)'))
+ $([MSBuild]::NormalizeDirectory('$(WasmRuntimePackRoot)', '$(LibrariesConfiguration)', 'runtimes', 'browser-wasm', 'native'))
+ $([MSBuild]::NormalizeDirectory('$(WasmRuntimePackRoot)', 'Release', 'runtimes', 'browser-wasm', 'lib', '$(NetCoreAppCurrent)'))
+ $([MSBuild]::NormalizeDirectory('$(WasmRuntimePackRoot)', 'Release', 'runtimes', 'browser-wasm', 'native'))
+
+
+
+ <_BuildJitsCrossArch Condition="'$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)' or '$(HostOS)' != '$(TargetOS)' or '$(EnableNativeSanitizers)' != ''">true
+ <_BuildJitsProperties>ClrAllJitsSubset=true;ClrWasmJitSubset=true;Configuration=$(CoreCLRConfiguration)
+ <_BuildJitsProperties Condition="!$([MSBuild]::IsOsPlatform(Windows))">$(_BuildJitsProperties);Ninja=true
+ <_BuildJitsProperties Condition="'$(_BuildJitsCrossArch)' == 'true'">$(_BuildJitsProperties);HostArchitecture=$(BuildArchitecture);HostCrossOS=$(HostOS);CrossBuild=false;BuildSubdirectory=$(BuildArchitecture);CMakeArgs=$(CMakeArgs) -DCLR_CROSS_COMPONENTS_BUILD=1;PgoInstrument=false;NoPgoOptimize=true
+
+
-
- <_WasmJitCrossHostArchSubdir Condition="'$(_BuildJitsCrossArch)' == 'true'">$(BuildArchitecture)/
- <_WasmJitFileName>$(HostLibPrefix)clrjit_universal_wasm_$(BuildArchitecture)$(HostLibSuffix)
- <_WasmJitSourcePath>$(CoreCLRArtifactsPath)$(_WasmJitCrossHostArchSubdir)$(_WasmJitFileName)
- <_Crossgen2InbuildPublishDir>$(CoreCLRArtifactsPath)$(BuildArchitecture)/crossgen2/
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
-
-
-
- $(CoreCLRArtifactsPath)/$(BuildArchitecture)/crossgen2
-
-
- $(MicrosoftNetCoreAppRuntimePackRidLibTfmDir)
-
-
- $(MicrosoftNetCoreAppRuntimePackNativeDir)
-
-
- $(MicrosoftNetCoreAppRefPackRefDir)
-
-
- $(CoreCLRArtifactsPath)
-
-
- $(TargetArchitecture)
-
-
- $(TargetOS)
-
-
- $(CoreCLRConfiguration)
-
-
+
+
+ @(Crossgen2InbuildOutputItems->WithMetadataValue('Filename', 'crossgen2')->WithMetadataValue('Extension', '$(ExeSuffix)')->'%(RootDir)%(Directory)')
+
+
+ $(MicrosoftNetCoreAppRuntimePackRidLibTfmDir)
+
+
+ $(MicrosoftNetCoreAppRuntimePackNativeDir)
+
+
+
+ $(RequireWasmReferences)
+
+
+ $(WasmRuntimePackDir)
+
+
+ $(WasmRuntimePackNativeDir)
+
+
+
+
+ $(CoreCLRConfiguration)
+
+
+
+
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs
index e29a57c61cccc2..4c92350b7fe581 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs
@@ -76,13 +76,10 @@ public void WasmWebcilModule()
new(nameof(WasmWebcilModule), [new CrossgenAssembly(wasmWebcilModule)])
{
OutputFileExtension = ".wasm",
- AdditionalArgs =
- {
- "--targetarch",
- "wasm",
- "--targetos",
- "browser",
- },
+ // Reference the real browser-wasm framework assemblies when they are available
+ // (e.g. the wasm tools-test job downloads them); otherwise the runner falls back
+ // to host references so this test still runs everywhere.
+ TargetRid = TargetRid.BrowserWasm,
Validate = Validate,
},
]));
@@ -153,7 +150,12 @@ static void Validate(ReadyToRunReader reader)
}
}
- [Fact]
+ // Note: The arm tests compile for an arm32 target, but they are compiled with the host Corelib. If there are
+ // load-bearing dependencies in the arm32 corelib (that aren't present in the host corelib) that crossgen2 requires,
+ // these tests may fail. Wasm tests are similar, but since it doesn't require a special cross-build setup, they use
+ // a wasm corelib in CI. arm32 tests could be similarly set up, but it hasn't been done yet.
+
+ [ConditionalFact(typeof(TestPaths), nameof(TestPaths.ArmOnHostOSSupported))]
public void ArmThumbBitRelocationTargets()
{
var inlineableLib = new CompiledAssembly
@@ -177,7 +179,7 @@ public void ArmThumbBitRelocationTargets()
new CrossgenAssembly(inlineableLib) { Kind = Crossgen2InputKind.Reference },
])
{
- Options = [Crossgen2Option.TargetArchArm],
+ TargetRid = TargetRid.HostArm,
Validate = Validate,
},
]));
@@ -190,7 +192,7 @@ static void Validate(ReadyToRunReader reader)
}
// JitStressProcedureSplitting is only available in Debug/Checked JIT builds.
- [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotReleaseCoreCLR))]
+ [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotReleaseCoreCLR), nameof(TestPaths.ArmOnHostOSSupported))]
public void ArmThumbBitHotColdRuntimeFunctions()
{
var hotColdSplitting = new CompiledAssembly
@@ -204,9 +206,9 @@ public void ArmThumbBitHotColdRuntimeFunctions()
[
new(nameof(ArmThumbBitHotColdRuntimeFunctions), [new CrossgenAssembly(hotColdSplitting)])
{
+ TargetRid = TargetRid.HostArm,
Options =
[
- Crossgen2Option.TargetArchArm,
Crossgen2Option.Optimize,
Crossgen2Option.HotColdSplitting,
],
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RDriver.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RDriver.cs
index a359f7bfa45d05..c598f917dc0787 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RDriver.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RDriver.cs
@@ -32,7 +32,6 @@ internal enum Crossgen2Option
InputBubble,
HotColdSplitting,
Optimize,
- TargetArchArm,
StripILBodies,
}
@@ -59,7 +58,6 @@ internal static class Crossgen2OptionsExtensions
Crossgen2Option.InputBubble => $"--input-bubble",
Crossgen2Option.HotColdSplitting => $"--hot-cold-splitting",
Crossgen2Option.Optimize => $"--optimize",
- Crossgen2Option.TargetArchArm => $"--targetarch:arm",
Crossgen2Option.StripILBodies => $"--strip-il-bodies",
_ => throw new ArgumentOutOfRangeException(nameof(kind)),
};
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs
index 33b4ed1d743516..f7f11d6f5c5369 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs
@@ -1194,11 +1194,15 @@ public static bool MethodILIsPresent(string msilFilePath, string declaringType,
///
internal sealed class SimpleAssemblyResolver : IAssemblyResolver
{
- private readonly TestPaths _paths;
+ private readonly Dictionary _assemblyPaths;
- public SimpleAssemblyResolver(TestPaths paths)
+ public SimpleAssemblyResolver(IEnumerable referencePaths)
{
- _paths = paths;
+ _assemblyPaths = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ foreach (string referencePath in referencePaths)
+ {
+ _assemblyPaths[Path.GetFileNameWithoutExtension(referencePath)] = referencePath;
+ }
}
public IAssemblyMetadata? FindAssembly(MetadataReader metadataReader, AssemblyReferenceHandle assemblyReferenceHandle, string parentFile)
@@ -1217,10 +1221,12 @@ public SimpleAssemblyResolver(TestPaths paths)
string candidate = Path.Combine(dir, simpleName + ".dll");
if (!File.Exists(candidate))
- candidate = Path.Combine(_paths.RuntimePackDir, simpleName + ".dll");
+ {
+ if (!_assemblyPaths.TryGetValue(simpleName, out string? referencePath) || referencePath is null)
+ return null;
- if (!File.Exists(candidate))
- return null;
+ candidate = referencePath;
+ }
return new SimpleAssemblyMetadata(candidate);
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestCaseCompiler.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestCaseCompiler.cs
index 7bd12c8887fe59..816801c96cdc6c 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestCaseCompiler.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestCaseCompiler.cs
@@ -19,26 +19,13 @@ internal sealed class R2RTestCaseCompiler
{
private readonly List _frameworkReferences;
- public R2RTestCaseCompiler(TestPaths paths)
+ public R2RTestCaseCompiler(List references)
{
_frameworkReferences = new List();
- // Add reference assemblies from the ref pack (needed for Roslyn compilation)
- string refPackDir = paths.RefPackDir;
- if (Directory.Exists(refPackDir))
+ foreach (string refPath in references)
{
- foreach (string refPath in Directory.EnumerateFiles(refPackDir, "*.dll"))
- {
- _frameworkReferences.Add(MetadataReference.CreateFromFile(refPath));
- }
- }
- else
- {
- // Fallback to runtime pack implementation assemblies
- foreach (string refPath in paths.GetFrameworkReferencePaths())
- {
- _frameworkReferences.Add(MetadataReference.CreateFromFile(refPath));
- }
+ _frameworkReferences.Add(MetadataReference.CreateFromFile(refPath));
}
}
@@ -85,7 +72,7 @@ public string CompileAssembly(
syntaxTrees,
references,
new CSharpCompilationOptions(outputKind)
- .WithOptimizationLevel(OptimizationLevel.Release)
+ .WithOptimizationLevel(OptimizationLevel.Debug)
.WithAllowUnsafe(true)
.WithNullableContextOptions(NullableContextOptions.Enable));
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs
index c6a2e26649671e..e8c1704bd3fd58 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs
@@ -11,6 +11,13 @@
namespace ILCompiler.ReadyToRun.Tests.TestCasesRunner;
+enum TargetRid
+{
+ Host,
+ HostArm,
+ BrowserWasm
+}
+
///
/// Describes an assembly compiled by Roslyn as part of a test case.
///
@@ -94,6 +101,8 @@ internal sealed class CrossgenCompilation(string name, List as
///
public Action? Validate { get; init; }
+ public TargetRid TargetRid { get; init; } = TargetRid.Host;
+
public string Name => name;
public bool IsComposite => Options.Contains(Crossgen2Option.Composite);
@@ -205,10 +214,18 @@ public void Run(R2RTestCase testCase)
// Step 2: Run each crossgen2 compilation and validate
var driver = new R2RDriver(_output, _paths);
- var refPaths = BuildReferencePaths();
+ List hostRefPaths = BuildReferencePaths(useWasmReferences: false);
+ List? wasmRefPaths = null;
foreach(var compilation in testCase.Compilations)
{
+ List refPaths = hostRefPaths;
+ if (compilation.TargetRid == TargetRid.BrowserWasm)
+ {
+ wasmRefPaths ??= BuildReferencePaths(useWasmReferences: true);
+ refPaths = wasmRefPaths;
+ }
+
string outputPath = RunCrossgenCompilation(
testCase.Name, compilation, driver, compilation.FilePath, refPaths, assemblyPaths);
@@ -216,7 +233,7 @@ public void Run(R2RTestCase testCase)
{
Assert.True(File.Exists(outputPath), $"R2R image not found: {outputPath}");
_output.WriteLine($" Validating R2R image: {outputPath}");
- var reader = new ReadyToRunReader(new SimpleAssemblyResolver(_paths), outputPath);
+ var reader = new ReadyToRunReader(new SimpleAssemblyResolver(refPaths), outputPath);
compilation.Validate(reader);
}
}
@@ -234,9 +251,11 @@ public void Run(R2RTestCase testCase)
private Dictionary CompileAllAssemblies(
IEnumerable assemblies)
{
- var compiler = new R2RTestCaseCompiler(_paths);
var paths = new Dictionary();
+ // Tests shouldn't require a platform-specific runtime/ref pack for Roslyn compilation
+ var defaultReferences = BuildReferencePaths(useWasmReferences: false);
+ var compiler = new R2RTestCaseCompiler(defaultReferences);
foreach (var asm in assemblies)
{
var sources = asm.SourceResourceNames
@@ -252,7 +271,7 @@ private Dictionary CompileAllAssemblies(
additionalReferences: asm.References.Select(r => r.FilePath).ToList(),
features: asm.Features.Count > 0 ? asm.Features : null);
paths[asm.AssemblyName] = ilPath;
- _output.WriteLine($" Roslyn compiled '{asm.AssemblyName}' -> {ilPath}");
+ _output.WriteLine($"Roslyn compiled '{asm.AssemblyName}' -> {ilPath}");
}
return paths;
@@ -307,6 +326,14 @@ private static string RunCrossgenCompilation(
foreach (var option in compilation.Options)
args.Add(option.ToArg());
+ args.AddRange(compilation.TargetRid switch
+ {
+ TargetRid.Host => [],
+ TargetRid.HostArm => ["--targetarch", "arm"],
+ TargetRid.BrowserWasm => ["--targetos", "browser", "--targetarch", "wasm"],
+ _ => throw new InvalidOperationException($"Unknown target RID: {compilation.TargetRid}")
+ });
+
// Caller-supplied raw args (for options that take values, e.g. --determinism-stress=N)
args.AddRange(compilation.AdditionalArgs);
@@ -335,32 +362,49 @@ private static void AddRefArgs(List args, List refPaths)
}
}
- private List BuildReferencePaths()
+ ///
+ /// Runtime packs are used as references for both Roslyn compilation and crossgen2 compilation. This method builds the reference paths for both.
+ ///
+ /// Whether to try to use browser-wasm references. The host references are used as a fallback if browser-wasm references are not available.
+ private List BuildReferencePaths(bool useWasmReferences)
{
- var paths = new List();
+ List paths;
- paths.Add(Path.Combine(_paths.RuntimePackDir, "*.dll"));
-
- // SPCL lives in the runtime pack native/ dir in full builds (placed by
- // externals.csproj BinPlace during libs.pretest). In partial CI builds
- // that skip libs.pretest, the runtime pack layout may not exist, but the
- // CoreCLR artifacts directory always has SPCL after clr.nativecorelib.
- string spcl = Path.Combine(_paths.RuntimePackNativeDir, "System.Private.CoreLib.dll");
- if (!File.Exists(spcl))
+ if (useWasmReferences)
{
- string fallback = Path.Combine(_paths.CoreCLRArtifactsDir, "System.Private.CoreLib.dll");
- if (File.Exists(fallback))
+ string? wasmRuntimePackDir = _paths.WasmRuntimePackDir;
+ string? wasmCoreLibPath = _paths.WasmRuntimePackNativeDir is null
+ ? null
+ : Path.Combine(_paths.WasmRuntimePackNativeDir, "System.Private.CoreLib.dll");
+
+ if (wasmRuntimePackDir is not null && wasmCoreLibPath is not null
+ && File.Exists(wasmCoreLibPath) && Directory.Exists(wasmRuntimePackDir))
{
- _output.WriteLine($"[R2RTestRunner] SPCL not found at '{spcl}'; using CoreCLR artifacts fallback '{fallback}'");
- spcl = fallback;
+ _output.WriteLine($"Using browser-wasm runtime pack references from '{wasmRuntimePackDir}'");
+ paths =
+ [
+ ..Directory.GetFiles(wasmRuntimePackDir, "*.dll"),
+ wasmCoreLibPath
+ ];
+ return paths;
+ }
+ else
+ {
+ Assert.False(
+ _paths.RequireWasmReferences,
+ "Browser-wasm framework references are required, but the browser-wasm runtime pack was not found.");
+ _output.WriteLine($"Browser-wasm runtime pack references not available. Falling back to host references.");
}
}
- Assert.True(File.Exists(spcl),
- $"System.Private.CoreLib.dll not found at '{spcl}'. " +
- $"Searched RuntimePackNativeDir='{_paths.RuntimePackNativeDir}' and " +
- $"CoreCLRArtifactsDir='{_paths.CoreCLRArtifactsDir}'");
- paths.Add(spcl);
+ string coreLibPath = Path.Combine(_paths.RuntimePackNativeDir, "System.Private.CoreLib.dll");
+ Assert.True(File.Exists(coreLibPath), $"System.Private.CoreLib.dll not found: {coreLibPath}");
+ Assert.True(Directory.Exists(_paths.RuntimePackDir), $"Runtime pack directory not found: {_paths.RuntimePackDir}");
+
+ paths = [
+ ..Directory.GetFiles(_paths.RuntimePackDir, "*.dll"),
+ coreLibPath
+ ];
return paths;
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/TestPaths.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/TestPaths.cs
index be18b5ff9aeb91..71661567fe2daf 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/TestPaths.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/TestPaths.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
@@ -29,76 +28,19 @@ private static string GetRequiredConfig(string key)
?? throw new InvalidOperationException($"Missing RuntimeHostConfigurationOption '{key}'. Was the project built with the correct properties?");
}
- ///
- /// Tries to find an existing directory by swapping the build configuration path segment
- /// (Debug, Release, Checked) in the path. Returns the first match, or the original
- /// path if no fallback exists.
- ///
- private string ProbeConfigFallback(string dir)
+ private static string? GetOptionalConfig(string key)
{
- if (Directory.Exists(dir))
- return dir;
-
- foreach (string fallbackConfig in new[] { "Release", "Checked", "Debug" })
- {
- string fallback = Regex.Replace(
- dir, @"(?<=[/\\])(Debug|Release|Checked)(?=[/\\])", fallbackConfig);
- if (fallback != dir && Directory.Exists(fallback))
- {
- _output.WriteLine($"[TestPaths] '{dir}' not found; falling back to '{fallback}'");
- return fallback;
- }
- }
-
- return dir;
- }
-
- ///
- /// Like but for paths where the configuration name
- /// is embedded in a dot-delimited segment (e.g. linux.x64.Checked).
- ///
- private string ProbeDottedConfigFallback(string dir)
- {
- if (Directory.Exists(dir))
- return dir;
-
- foreach (string fallbackConfig in new[] { "Checked", "Release", "Debug" })
- {
- string fallback = Regex.Replace(
- dir, @"\.(Debug|Release|Checked)([/\\])", $".{fallbackConfig}$2");
- if (fallback != dir && Directory.Exists(fallback))
- {
- _output.WriteLine($"[TestPaths] '{dir}' not found; falling back to '{fallback}'");
- return fallback;
- }
- }
-
- return dir;
+ string? value = AppContext.GetData(key) as string;
+ return string.IsNullOrEmpty(value) ? null : value;
}
///
/// Path to the crossgen2 output directory (contains the self-contained crossgen2 executable and clrjit).
/// e.g. artifacts/bin/coreclr/linux.x64.Checked/x64/crossgen2/
- /// Falls back to Checked or Release if the configured path doesn't exist.
///
- public string Crossgen2Dir
- {
- get
- {
- string dir = GetRequiredConfig("R2RTest.Crossgen2Dir");
- if (!File.Exists(Path.Combine(dir, Crossgen2ExeName)))
- {
- string fallback = ProbeDottedConfigFallback(dir);
- if (File.Exists(Path.Combine(fallback, Crossgen2ExeName)))
- return fallback;
- }
+ public string Crossgen2Dir => GetRequiredConfig("R2RTest.Crossgen2Dir");
- return dir;
- }
- }
-
- private static string Crossgen2ExeName =>
- RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "crossgen2.exe" : "crossgen2";
+ private static string Crossgen2ExeName => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "crossgen2.exe" : "crossgen2";
///
/// Path to the self-contained crossgen2 executable (from crossgen2_inbuild).
@@ -106,97 +48,38 @@ public string Crossgen2Dir
public string Crossgen2Exe => Path.Combine(Crossgen2Dir, Crossgen2ExeName);
///
- /// Path to the runtime pack managed assemblies directory.
- /// e.g. artifacts/bin/microsoft.netcore.app.runtime.linux-x64/Release/runtimes/linux-x64/lib/net11.0/
- /// Falls back to a different build configuration if the path doesn't exist.
+ /// Path to the host runtime pack managed assemblies directory.
///
- public string RuntimePackDir
- {
- get
- {
- string dir = GetRequiredConfig("R2RTest.RuntimePackDir");
- return ProbeConfigFallback(dir);
- }
- }
+ public string RuntimePackDir => GetRequiredConfig("R2RTest.RuntimePackDir");
///
- /// Path to the runtime pack native directory (contains System.Private.CoreLib.dll and native runtime).
- /// e.g. artifacts/bin/microsoft.netcore.app.runtime.linux-x64/Release/runtimes/linux-x64/native/
- /// Falls back to a different build configuration if the path doesn't exist.
+ /// Path to the host runtime pack native directory.
///
- public string RuntimePackNativeDir
- {
- get
- {
- string dir = GetRequiredConfig("R2RTest.RuntimePackNativeDir");
- return ProbeConfigFallback(dir);
- }
- }
+ public string RuntimePackNativeDir => GetRequiredConfig("R2RTest.RuntimePackNativeDir");
///
- /// Path to the CoreCLR artifacts directory (contains native bits like corerun).
- /// e.g. artifacts/bin/coreclr/linux.x64.Checked/
- /// Falls back to Checked or Release if the configured path doesn't exist.
+ /// Path to the browser-wasm runtime pack managed assemblies directory, or null when the
+ /// browser-wasm runtime pack has not been built/downloaded (e.g. in the default linux-x64 tools
+ /// test job). When present, the wasm crossgen2 compilation references these real browser-wasm
+ /// framework assemblies instead of the host runtime pack.
+ /// e.g. artifacts/bin/microsoft.netcore.app.runtime.browser-wasm/Release/runtimes/browser-wasm/lib/net11.0/
///
- public string CoreCLRArtifactsDir
- {
- get
- {
- string dir = GetRequiredConfig("R2RTest.CoreCLRArtifactsDir");
- return ProbeDottedConfigFallback(dir);
- }
- }
-
- public static string TargetArchitecture => GetRequiredConfig("R2RTest.TargetArchitecture");
- public static string TargetOS => GetRequiredConfig("R2RTest.TargetOS");
- public static string CoreCLRConfiguration => GetRequiredConfig("R2RTest.CoreCLRConfiguration");
- public static bool IsReleaseCoreCLR => string.Equals(CoreCLRConfiguration, "Release", StringComparison.OrdinalIgnoreCase);
- public static bool IsNotReleaseCoreCLR => !IsReleaseCoreCLR;
-
- ///
- /// Path to the reference assembly pack (for Roslyn compilation).
- /// e.g. artifacts/bin/microsoft.netcore.app.ref/ref/net11.0/
- ///
- public string RefPackDir
- {
- get
- {
- string dir = GetRequiredConfig("R2RTest.RefPackDir");
- if (!Directory.Exists(dir))
- {
- // Try the artifacts/bin/ref/net* fallback
- string artifactsBin = Path.GetFullPath(Path.Combine(CoreCLRArtifactsDir, "..", ".."));
- string refDir = Path.Combine(artifactsBin, "ref");
- if (Directory.Exists(refDir))
- {
- foreach (string subDir in Directory.GetDirectories(refDir, "net*"))
- {
- if (File.Exists(Path.Combine(subDir, "System.Runtime.dll")))
- {
- _output.WriteLine($"[TestPaths] '{dir}' not found; falling back to '{subDir}'");
- return subDir;
- }
- }
- }
- }
-
- return dir;
- }
- }
+ public string? WasmRuntimePackDir => GetOptionalConfig("R2RTest.WasmRuntimePackDir");
///
- /// Returns the target triple string for crossgen2 (e.g. "linux-x64").
+ /// Path to the browser-wasm runtime pack native directory (contains the wasm
+ /// System.Private.CoreLib.dll), or null when not available.
+ /// e.g. artifacts/bin/microsoft.netcore.app.runtime.browser-wasm/Release/runtimes/browser-wasm/native/
///
- public static string TargetTriple => $"{TargetOS.ToLowerInvariant()}-{TargetArchitecture.ToLowerInvariant()}";
+ public string? WasmRuntimePackNativeDir => GetOptionalConfig("R2RTest.WasmRuntimePackNativeDir");
- ///
- /// Returns all framework reference assembly paths (*.dll in the runtime pack).
- ///
- public IEnumerable GetFrameworkReferencePaths()
- {
- if (!Directory.Exists(RuntimePackDir))
- throw new DirectoryNotFoundException($"Runtime pack directory not found: {RuntimePackDir}");
+ public bool RequireWasmReferences => string.Equals(
+ GetOptionalConfig("R2RTest.RequireWasmReferences"),
+ bool.TrueString,
+ StringComparison.OrdinalIgnoreCase);
- return Directory.EnumerateFiles(RuntimePackDir, "*.dll");
- }
+ public static string CoreCLRConfiguration => GetRequiredConfig("R2RTest.CoreCLRConfiguration");
+ public static bool IsReleaseCoreCLR => string.Equals(CoreCLRConfiguration, "Release", StringComparison.OrdinalIgnoreCase);
+ public static bool IsNotReleaseCoreCLR => !IsReleaseCoreCLR;
+ public static bool ArmOnHostOSSupported => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
}
diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj
index 45a5d877f608a9..61dcef292c508d 100644
--- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj
+++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj
@@ -15,7 +15,7 @@
true
true
- true
+ true