Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
Automatic generation of method export file for shared libraries (#5154)
Browse files Browse the repository at this point in the history
  • Loading branch information
tonerdo authored and jkotas committed Jan 2, 2018
1 parent a60adb8 commit d5a0166
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 18 deletions.
3 changes: 2 additions & 1 deletion src/BuildIntegration/Microsoft.NETCore.Native.Unix.props
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ See the LICENSE file in the project root for more information.
<LinkerArg Include="-luuid" Condition="'$(TargetOS)' != 'OSX'" />
<LinkerArg Include="-lrt" Condition="'$(TargetOS)' != 'OSX'" />
<LinkerArg Include="-licucore" Condition="'$(TargetOS)' == 'OSX'" />
<LinkerArg Include="-shared" Condition="'$(NativeLib)' == 'Shared'" />
<LinkerArg Include="-dynamiclib" Condition="'$(TargetOS)' == 'OSX' and '$(NativeLib)' == 'Shared'" />
<LinkerArg Include="-shared" Condition="'$(TargetOS)' != 'OSX' and '$(NativeLib)' == 'Shared'" />
</ItemGroup>
</Target>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ See the LICENSE file in the project root for more information.

<ItemGroup>
<LinkerArg Condition="$(NativeLib) == 'Shared'" Include="/DLL" />
<LinkerArg Condition="$(DefFile) != ''" Include="/DEF:$(DefFile)" />
<LinkerArg Include="@(NativeLibrary)" />
<LinkerArg Include="@(AdditionalNativeLibrary)" />
<LinkerArg Include="/NOLOGO /DEBUG /MANIFEST:NO" />
Expand Down
10 changes: 9 additions & 1 deletion src/BuildIntegration/Microsoft.NETCore.Native.targets
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ See the LICENSE file in the project root for more information.
<NativeObjectExt Condition="'$(TargetOS)' == 'Windows_NT'">.obj</NativeObjectExt>
<NativeObjectExt Condition="'$(TargetOS)' != 'Windows_NT'">.o</NativeObjectExt>
<NativeObjectExt Condition="'$(NativeCodeGen)' == 'wasm'">.bc</NativeObjectExt>

<LibFileExt Condition="'$(TargetOS)' == 'Windows_NT'">.lib</LibFileExt>
<LibFileExt Condition="'$(TargetOS)' != 'Windows_NT'">.a</LibFileExt>

Expand All @@ -48,8 +49,12 @@ See the LICENSE file in the project root for more information.
<NativeBinaryExt Condition="'$(OutputType)' != 'Exe' and '$(TargetOS)' != 'Windows_NT' and $(NativeLib) == 'Static'">.a</NativeBinaryExt>
<NativeBinaryExt Condition="'$(NativeCodeGen)' == 'wasm'">.html</NativeBinaryExt>

<ExportsFileExt Condition="'$(OutputType)' != 'Exe' and '$(TargetOS)' == 'Windows_NT' and '$(NativeLib)' == 'Shared'">.def</ExportsFileExt>
<ExportsFileExt Condition="'$(OutputType)' != 'Exe' and '$(TargetOS)' != 'Windows_NT' and '$(NativeLib)' == 'Shared'">.exports</ExportsFileExt>

<NativeObject>$(NativeIntermediateOutputPath)$(TargetName)$(NativeObjectExt)</NativeObject>
<NativeBinary>$(NativeOutputPath)$(TargetName)$(NativeBinaryExt)</NativeBinary>
<ExportsFile Condition="$(NativeLib) == 'Shared' and $(ExportsFile) == ''">$(NativeIntermediateOutputPath)$(TargetName)$(ExportsFileExt)</ExportsFile>

<IlcCompileOutput Condition="$(NativeCodeGen) == ''">$(NativeObject)</IlcCompileOutput>
<IlcCompileOutput Condition="$(NativeCodeGen) == 'cpp'">$(NativeIntermediateOutputPath)$(TargetName).cpp</IlcCompileOutput>
Expand Down Expand Up @@ -151,7 +156,8 @@ See the LICENSE file in the project root for more information.
<IlcArg Condition="$(DebugSymbols) == 'true'" Include="-g" />
<IlcArg Condition="$(IlcGenerateMapFile) == 'true'" Include="--map:$(NativeIntermediateOutputPath)%(ManagedBinary.Filename).map.xml" />
<IlcArg Condition="$(RdXmlFile) != ''" Include="--rdxml:$(RdXmlFile)" />
<IlcArg Condition="$(OutputType) == 'Library' and $(NativeLib) != ''" Include="--nativelib" />
<IlcArg Condition="$(OutputType) == 'Library' and $(NativeLib) != ''" Include="--nativelib" />
<IlcArg Condition="$(ExportsFile) != ''" Include="--exportsfile:$(ExportsFile)" />
<ILcArg Condition="'$(Platform)' == 'wasm'" Include="--wasm" />
</ItemGroup>

Expand Down Expand Up @@ -193,6 +199,8 @@ See the LICENSE file in the project root for more information.
<CustomLinkerArg Include="$(NativeObject)" />
<CustomLinkerArg Include="-o $(NativeBinary)" Condition="'$(OS)' != 'Windows_NT'" />
<CustomLinkerArg Include="/OUT:$(NativeBinary)" Condition="'$(OS)' == 'Windows_NT'" />
<CustomLinkerArg Include="/DEF:$(ExportsFile)" Condition="'$(OS)' == 'Windows_NT' and $(ExportsFile) != ''" />
<CustomLinkerArg Include="-exported_symbols_list $(ExportsFile)" Condition="'$(OS)' != 'Windows_NT' and $(ExportsFile) != ''" />
<CustomLinkerArg Include="@(LinkerArg)" />
</ItemGroup>

Expand Down
43 changes: 28 additions & 15 deletions src/ILCompiler.Compiler/src/Compiler/ExportedMethodsRootProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -18,27 +21,37 @@ public ExportedMethodsRootProvider(EcmaModule module)
_module = module;
}

public void AddCompilationRoots(IRootingServiceProvider rootProvider)
public IEnumerable<EcmaMethod> 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);
}
}
}
Expand Down
49 changes: 49 additions & 0 deletions src/ILCompiler.Compiler/src/Compiler/ExportsFileWriter.cs
Original file line number Diff line number Diff line change
@@ -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<EcmaMethod> _methods;
private TypeSystemContext _context;

public ExportsFileWriter(TypeSystemContext context, string exportsFile)
{
_exportsFile = exportsFile;
_context = context;
_methods = new List<EcmaMethod>();
}

public void AddExportedMethods(IEnumerable<EcmaMethod> 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()}");
}
}
}
}
}
1 change: 1 addition & 0 deletions src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@
<Compile Include="Compiler\NativeLibraryInitializerRootProvider.cs" />
<Compile Include="Compiler\NodeMangler.cs" />
<Compile Include="Compiler\ObjectDumper.cs" />
<Compile Include="Compiler\ExportsFileWriter.cs" />
<Compile Include="Compiler\PrecomputedMetadataManager.cs" />
<Compile Include="Compiler\ReadyToRun.cs" />
<Compile Include="Compiler\RyuJitCompilation.cs" />
Expand Down
13 changes: 13 additions & 0 deletions src/ILCompiler/src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit d5a0166

Please sign in to comment.