Implement resource lookup in satellite assemblies (#86689)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Mon, 29 May 2023 23:58:32 +0000 (08:58 +0900)
committerGitHub <noreply@github.com>
Mon, 29 May 2023 23:58:32 +0000 (08:58 +0900)
Fixes #86651.

This was implemented in .NET Native so we just need to resurface it from the compiler.

Note that this is not full support for satellite assemblies (in the assembly binder, etc.) that never existed and nobody ever asked for and I don't even know what it entails.

12 files changed:
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs
src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DependencyGraphTests.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ModuleMetadataNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
src/coreclr/tools/aot/ILCompiler/ILCompiler.props
src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
src/coreclr/tools/aot/ILCompiler/Program.cs
src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerDriver.cs
src/coreclr/tools/aot/crossgen2/crossgen2.props
src/libraries/System.Resources.ResourceManager/tests/ResourceManagerTests.cs

index 6f67291..69b7b1f 100644 (file)
@@ -5,6 +5,8 @@
           DependsOnTargets="$(IlcDynamicBuildPropertyDependencies)">
     <ItemGroup>
       <IlcReference Include="@(_ManagedResolvedAssembliesToPublish)" />
+      <IlcSatelliteAssembly Include="@(_SatelliteAssembliesToPublish)" />
+      <IlcSatelliteAssembly Include="@(IntermediateSatelliteAssembliesWithTargetPath)" />
     </ItemGroup>
   </Target>
 
@@ -82,6 +84,7 @@
       FrameworkAssemblies="@(FrameworkAssemblies)">
 
       <Output TaskParameter="ManagedAssemblies" ItemName="_ManagedResolvedAssembliesToPublish" />
+      <Output TaskParameter="SatelliteAssemblies" ItemName="_SatelliteAssembliesToPublish" />
       <Output TaskParameter="AssembliesToSkipPublish" ItemName="_AssembliesToSkipPublish" />
     </ComputeManagedAssembliesToCompileToNative>
 
index 6070287..5736aa8 100644 (file)
@@ -194,6 +194,7 @@ The .NET Foundation licenses this file to you under the MIT license.
       <IlcArg Include="@(IlcCompileInput)" />
       <IlcArg Include="-o:$(NativeIntermediateOutputPath)%(ManagedBinary.Filename)$(IlcOutputFileExt)" />
       <IlcArg Include="@(IlcReference->'-r:%(Identity)')" />
+      <IlcArg Include="@(IlcSatelliteAssembly->'--satellite:%(Identity)')" />
       <IlcArg Include="@(MibcFile->'--mibc:%(Identity)')" />
       <IlcArg Condition="$(IlcGenerateMetadataLog) == 'true'" Include="--metadatalog:$(NativeIntermediateOutputPath)%(ManagedBinary.Filename).metadata.csv" />
       <IlcArg Condition="$(_targetOS) != ''" Include="--targetos:$(_targetOS)" />
@@ -262,7 +263,7 @@ The .NET Foundation licenses this file to you under the MIT license.
   </Target>
 
   <Target Name="IlcCompile"
-      Inputs="@(IlcCompileInput);@(IlcReference);@(RdXmlFile);%(ManagedBinary.IlcRspFile)"
+      Inputs="@(IlcCompileInput);@(IlcReference);@(IlcSatelliteAssembly);@(RdXmlFile);%(ManagedBinary.IlcRspFile)"
       Outputs="%(ManagedBinary.IlcOutputFile)"
       DependsOnTargets="WriteIlcRspFileForCompilation;$(IlcCompileDependsOn)">
     <Message Text="Generating native code" Importance="high" />
index ee68181..60084f4 100644 (file)
@@ -81,6 +81,13 @@ namespace Build.Tasks
         }
 
         [Output]
+        public ITaskItem[] SatelliteAssemblies
+        {
+            get;
+            set;
+        }
+
+        [Output]
         public ITaskItem[] AssembliesToSkipPublish
         {
             get;
@@ -91,6 +98,7 @@ namespace Build.Tasks
         {
             var list = new List<ITaskItem>();
             var assembliesToSkipPublish = new List<ITaskItem>();
+            var satelliteAssemblies = new List<ITaskItem>();
             var nativeAotFrameworkAssembliesToUse = new HashSet<string>();
 
             foreach (ITaskItem taskItem in SdkAssemblies)
@@ -164,11 +172,16 @@ namespace Build.Tasks
                                 string culture = moduleMetadataReader.GetString(moduleMetadataReader.GetAssemblyDefinition().Culture);
 
                                 assembliesToSkipPublish.Add(taskItem);
+
+                                // Split satellite assemblies from normal assemblies
                                 if (culture == "" || culture.Equals("neutral", StringComparison.OrdinalIgnoreCase))
                                 {
-                                    // NativeAOT doesn't consume resource assemblies yet so skip them
                                     list.Add(taskItem);
                                 }
+                                else
+                                {
+                                    satelliteAssemblies.Add(taskItem);
+                                }
                             }
                         }
                     }
@@ -180,6 +193,7 @@ namespace Build.Tasks
 
             ManagedAssemblies = list.ToArray();
             AssembliesToSkipPublish = assembliesToSkipPublish.ToArray();
+            SatelliteAssemblies = satelliteAssemblies.ToArray();
 
             return true;
         }
index b05ed63..01cbbc5 100644 (file)
@@ -73,7 +73,7 @@ namespace ILCompiler.Compiler.Tests
                 new FullyBlockedMetadataBlockingPolicy(), new FullyBlockedManifestResourceBlockingPolicy(),
                 null, new NoStackTraceEmissionPolicy(), new NoDynamicInvokeThunkGenerationPolicy(),
                 new ILLink.Shared.TrimAnalysis.FlowAnnotations(Logger.Null, ilProvider, compilerGeneratedState), UsageBasedMetadataGenerationOptions.None,
-                default, Logger.Null, Array.Empty<KeyValuePair<string, bool>>(), Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>());
+                default, Logger.Null, Array.Empty<KeyValuePair<string, bool>>(), Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>());
 
             CompilationBuilder builder = new RyuJitCompilationBuilder(context, compilationGroup)
                 .UseILProvider(ilProvider);
index cc703cd..ef1e8e9 100644 (file)
@@ -44,7 +44,14 @@ namespace ILCompiler.DependencyAnalysis
                 dependencies.Add(factory.ReflectedMethod(entrypoint), "Reflectable entrypoint");
             }
 
-            CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, (EcmaAssembly)_module);
+            EcmaAssembly ecmaAssembly = (EcmaAssembly)_module;
+
+            CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, ecmaAssembly);
+
+            foreach (EcmaModule satelliteModule in ((UsageBasedMetadataManager)factory.MetadataManager).GetSatelliteAssemblies(ecmaAssembly))
+            {
+                dependencies.Add(factory.ModuleMetadata(satelliteModule), "Satellite assembly");
+            }
 
             return dependencies;
         }
index 84eb949..c8c49f2 100644 (file)
@@ -63,6 +63,7 @@ namespace ILCompiler
 
         private readonly HashSet<string> _rootEntireAssembliesModules;
         private readonly HashSet<string> _trimmedAssemblies;
+        private readonly List<string> _satelliteAssemblyFiles;
 
         internal FlowAnnotations FlowAnnotations { get; }
 
@@ -83,7 +84,8 @@ namespace ILCompiler
             IEnumerable<KeyValuePair<string, bool>> featureSwitchValues,
             IEnumerable<string> rootEntireAssembliesModules,
             IEnumerable<string> additionalRootedAssemblies,
-            IEnumerable<string> trimmedAssemblies)
+            IEnumerable<string> trimmedAssemblies,
+            IEnumerable<string> satelliteAssemblyFilePaths)
             : base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy, invokeThunkGenerationPolicy, options)
         {
             _compilationModuleGroup = group;
@@ -98,6 +100,20 @@ namespace ILCompiler
             _rootEntireAssembliesModules = new HashSet<string>(rootEntireAssembliesModules);
             _rootEntireAssembliesModules.UnionWith(additionalRootedAssemblies);
             _trimmedAssemblies = new HashSet<string>(trimmedAssemblies);
+            _satelliteAssemblyFiles = new List<string>(satelliteAssemblyFilePaths);
+        }
+
+        public IEnumerable<EcmaModule> GetSatelliteAssemblies(EcmaAssembly module)
+        {
+            string expectedSimpleName = module.GetName().Name + ".resources";
+            foreach (string filePath in _satelliteAssemblyFiles)
+            {
+                string simpleName = Path.GetFileNameWithoutExtension(filePath);
+                if (simpleName == expectedSimpleName)
+                {
+                    yield return _typeSystemContext.GetMetadataOnlyModuleFromPath(filePath);
+                }
+            }
         }
 
         protected override void Graph_NewMarkedNode(DependencyNodeCore<NodeFactory> obj)
index 87abaa5..e1279e4 100644 (file)
@@ -15,7 +15,6 @@
     <ServerGarbageCollection>true</ServerGarbageCollection>
     <TieredCompilation>false</TieredCompilation>
     <EventSourceSupport>true</EventSourceSupport>
-    <InvariantGlobalization>true</InvariantGlobalization>
     <OptimizationPreference>Speed</OptimizationPreference>
   </PropertyGroup>
 
index a417d22..f6f81e8 100644 (file)
@@ -28,6 +28,8 @@ namespace ILCompiler
             new(new[] { "--optimize-time", "--Ot" }, "Enable optimizations, favor code speed");
         public Option<string[]> MibcFilePaths { get; } =
             new(new[] { "--mibc", "-m" }, Array.Empty<string>, "Mibc file(s) for profile guided optimization");
+        public Option<string[]> SatelliteFilePaths { get; } =
+            new(new[] { "--satellite" }, Array.Empty<string>, "Satellite assemblies associated with inputs/references");
         public Option<bool> EnableDebugInfo { get; } =
             new(new[] { "--debug", "-g" }, "Emit debugging information");
         public Option<bool> UseDwarf5 { get; } =
@@ -173,6 +175,7 @@ namespace ILCompiler
             AddOption(OptimizeSpace);
             AddOption(OptimizeTime);
             AddOption(MibcFilePaths);
+            AddOption(SatelliteFilePaths);
             AddOption(EnableDebugInfo);
             AddOption(UseDwarf5);
             AddOption(NativeLib);
index 7fc33c7..485539c 100644 (file)
@@ -391,7 +391,8 @@ namespace ILCompiler
                     featureSwitches,
                     Get(_command.ConditionallyRootedAssemblies),
                     rootedAssemblies,
-                    Get(_command.TrimmedAssemblies));
+                    Get(_command.TrimmedAssemblies),
+                    Get(_command.SatelliteFilePaths));
 
             InteropStateManager interopStateManager = new InteropStateManager(typeSystemContext.GeneratedAssembly);
             InteropStubManager interopStubManager = new UsageBasedInteropStubManager(interopStateManager, pinvokePolicy, logger);
index d5fa880..16d2e42 100644 (file)
@@ -111,7 +111,8 @@ namespace Mono.Linker.Tests.TestCasesRunner
                                Array.Empty<KeyValuePair<string, bool>> (),
                                Array.Empty<string> (),
                                options.AdditionalRootAssemblies.ToArray (),
-                               options.TrimAssemblies.ToArray ());
+                               options.TrimAssemblies.ToArray (),
+                               Array.Empty<string> ());
 
                        PInvokeILEmitterConfiguration pinvokePolicy = new ILCompilerTestPInvokePolicy ();
                        InteropStateManager interopStateManager = new InteropStateManager (typeSystemContext.GeneratedAssembly);
index 012c9ec..765c784 100644 (file)
@@ -15,7 +15,6 @@
     <Configurations>Debug;Release;Checked</Configurations>
     <ServerGarbageCollection>true</ServerGarbageCollection>
     <EventSourceSupport>true</EventSourceSupport>
-    <InvariantGlobalization>true</InvariantGlobalization>
     <OptimizationPreference>Speed</OptimizationPreference>
     <RunAnalyzers>false</RunAnalyzers>
   </PropertyGroup>
index 9a0bae5..6bb68cb 100644 (file)
@@ -87,7 +87,6 @@ namespace System.Resources.Tests
 
         [Theory]
         [MemberData(nameof(CultureResourceData))]
-        [ActiveIssue("https://github.com/dotnet/runtimelab/issues/155", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] // satellite assemblies
         public static void GetString_CultureFallback(string key, string cultureName, string expectedValue)
         {
             Type resourceType = typeof(Resources.TestResx);
@@ -98,7 +97,6 @@ namespace System.Resources.Tests
         }
 
         [Fact]
-        [ActiveIssue("https://github.com/dotnet/runtimelab/issues/155", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] //satellite assemblies
         public static void GetString_FromTestClassWithoutNeutralResources()
         {
             // This test is designed to complement the GetString_FromCulutureAndResourceType "fr" & "fr-CA" cases