diff --git a/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props b/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props index 5ed981fedd4..5303d99c4f2 100644 --- a/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props +++ b/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props @@ -70,7 +70,8 @@ See the LICENSE file in the project root for more information. - + + diff --git a/src/BuildIntegration/Microsoft.NETCore.Native.Windows.props b/src/BuildIntegration/Microsoft.NETCore.Native.Windows.props index 2214b342372..9949a24ec02 100644 --- a/src/BuildIntegration/Microsoft.NETCore.Native.Windows.props +++ b/src/BuildIntegration/Microsoft.NETCore.Native.Windows.props @@ -61,7 +61,6 @@ See the LICENSE file in the project root for more information. - diff --git a/src/BuildIntegration/Microsoft.NETCore.Native.targets b/src/BuildIntegration/Microsoft.NETCore.Native.targets index 03b5366cb00..4a334e6244d 100644 --- a/src/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/BuildIntegration/Microsoft.NETCore.Native.targets @@ -31,6 +31,7 @@ See the LICENSE file in the project root for more information. .obj .o .bc + .lib .a @@ -48,8 +49,12 @@ See the LICENSE file in the project root for more information. .a .html + .def + .exports + $(NativeIntermediateOutputPath)$(TargetName)$(NativeObjectExt) $(NativeOutputPath)$(TargetName)$(NativeBinaryExt) + $(NativeIntermediateOutputPath)$(TargetName)$(ExportsFileExt) $(NativeObject) $(NativeIntermediateOutputPath)$(TargetName).cpp @@ -151,7 +156,8 @@ See the LICENSE file in the project root for more information. - + + @@ -193,6 +199,8 @@ See the LICENSE file in the project root for more information. + + diff --git a/src/ILCompiler.Compiler/src/Compiler/ExportedMethodsRootProvider.cs b/src/ILCompiler.Compiler/src/Compiler/ExportedMethodsRootProvider.cs index 11fa9c01f19..fcedbe2553b 100644 --- a/src/ILCompiler.Compiler/src/Compiler/ExportedMethodsRootProvider.cs +++ b/src/ILCompiler.Compiler/src/Compiler/ExportedMethodsRootProvider.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; + +using Internal.TypeSystem; using Internal.TypeSystem.Ecma; namespace ILCompiler @@ -18,27 +21,37 @@ public ExportedMethodsRootProvider(EcmaModule module) _module = module; } - public void AddCompilationRoots(IRootingServiceProvider rootProvider) + public IEnumerable ExportedMethods { - foreach (var type in _module.GetAllTypes()) + get { - foreach (var method in type.GetMethods()) + foreach (var type in _module.GetAllTypes()) { - EcmaMethod ecmaMethod = (EcmaMethod)method; - - if (ecmaMethod.IsRuntimeExport) + foreach (var method in type.GetMethods()) { - string runtimeExportName = ecmaMethod.GetRuntimeExportName(); - if (runtimeExportName != null) - rootProvider.AddCompilationRoot(method, "Runtime export", runtimeExportName); + EcmaMethod ecmaMethod = (EcmaMethod)method; + if (ecmaMethod.IsRuntimeExport || ecmaMethod.IsNativeCallable) + yield return ecmaMethod; } + } + } + } - if (ecmaMethod.IsNativeCallable) - { - string nativeCallableExportName = ecmaMethod.GetNativeCallableExportName(); - if (nativeCallableExportName != null) - rootProvider.AddCompilationRoot(method, "Native callable", nativeCallableExportName); - } + public void AddCompilationRoots(IRootingServiceProvider rootProvider) + { + foreach (var ecmaMethod in ExportedMethods) + { + if (ecmaMethod.IsRuntimeExport) + { + string runtimeExportName = ecmaMethod.GetRuntimeExportName(); + if (runtimeExportName != null) + rootProvider.AddCompilationRoot((MethodDesc)ecmaMethod, "Runtime export", runtimeExportName); + } + else if (ecmaMethod.IsNativeCallable) + { + string nativeCallableExportName = ecmaMethod.GetNativeCallableExportName(); + if (nativeCallableExportName != null) + rootProvider.AddCompilationRoot((MethodDesc)ecmaMethod, "Native callable", nativeCallableExportName); } } } diff --git a/src/ILCompiler.Compiler/src/Compiler/ExportsFileWriter.cs b/src/ILCompiler.Compiler/src/Compiler/ExportsFileWriter.cs new file mode 100644 index 00000000000..9935a4dbeac --- /dev/null +++ b/src/ILCompiler.Compiler/src/Compiler/ExportsFileWriter.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILCompiler +{ + public class ExportsFileWriter + { + private string _exportsFile; + private List _methods; + private TypeSystemContext _context; + + public ExportsFileWriter(TypeSystemContext context, string exportsFile) + { + _exportsFile = exportsFile; + _context = context; + _methods = new List(); + } + + public void AddExportedMethods(IEnumerable methods) + => _methods.AddRange(methods.Where(m => m.Module != _context.SystemModule)); + + public void EmitExportedMethods() + { + FileStream fileStream = new FileStream(_exportsFile, FileMode.Create); + using (StreamWriter streamWriter = new StreamWriter(fileStream)) + { + if (_context.Target.IsWindows) + { + streamWriter.WriteLine("EXPORTS"); + foreach (var method in _methods) + streamWriter.WriteLine($" {method.GetNativeCallableExportName()}"); + } + else + { + foreach (var method in _methods) + streamWriter.WriteLine($"_{method.GetNativeCallableExportName()}"); + } + } + } + } +} \ No newline at end of file diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj index 7df0a8e4dff..a29a5cd10f7 100644 --- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj +++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj @@ -332,6 +332,7 @@ + diff --git a/src/ILCompiler/src/Program.cs b/src/ILCompiler/src/Program.cs index 0599756d504..e869f7540dc 100644 --- a/src/ILCompiler/src/Program.cs +++ b/src/ILCompiler/src/Program.cs @@ -40,6 +40,7 @@ internal class Program private string _systemModuleName = "System.Private.CoreLib"; private bool _multiFile; private bool _nativeLib; + private string _exportsFile; private bool _useSharedGenerics; private bool _useScanner; private bool _noScanner; @@ -134,6 +135,7 @@ private ArgumentSyntax ParseCommandLine(string[] args) syntax.DefineOption("cpp", ref _isCppCodegen, "Compile for C++ code-generation"); syntax.DefineOption("wasm", ref _isWasmCodegen, "Compile for WebAssembly code-generation"); syntax.DefineOption("nativelib", ref _nativeLib, "Compile as static or shared library"); + syntax.DefineOption("exportsfile", ref _exportsFile, "File to write exported method definitions"); syntax.DefineOption("dgmllog", ref _dgmlLogFileName, "Save result of dependency analysis as DGML"); syntax.DefineOption("fulllog", ref _generateFullDgmlLog, "Save detailed log of dependency analysis"); syntax.DefineOption("scandgmllog", ref _scanDgmlLogFileName, "Save result of scanner dependency analysis as DGML"); @@ -446,6 +448,17 @@ private int Run(string[] args) ObjectDumper dumper = _mapFileName != null ? new ObjectDumper(_mapFileName) : null; CompilationResults compilationResults = compilation.Compile(_outputFilePath, dumper); + if (_exportsFile != null) + { + ExportsFileWriter defFileWriter = new ExportsFileWriter(typeSystemContext, _exportsFile); + foreach (var compilationRoot in compilationRoots) + { + if (compilationRoot is ExportedMethodsRootProvider provider) + defFileWriter.AddExportedMethods(provider.ExportedMethods); + } + + defFileWriter.EmitExportedMethods(); + } if (_dgmlLogFileName != null) compilationResults.WriteDependencyLog(_dgmlLogFileName);