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

Automatic generation of method export file for shared libraries #5154

Merged
merged 23 commits into from
Jan 2, 2018
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9f615d8
add ExportedDefinitionsWriter (#4986)
tonerdo Dec 20, 2017
0d17711
add automatic location of auto-generated definition file to build scr…
tonerdo Dec 20, 2017
655be26
add support for generating OSX symbol export files (#4986)
tonerdo Dec 24, 2017
ea9e84c
rename ExportedDefinitionsWriter to ExportsWriter (#4986)
tonerdo Dec 24, 2017
cb11f1f
update buildscripts for OSX exports file location (#4986)
tonerdo Dec 24, 2017
7443e76
rename ExportsWriter to ExportedMethodsWriter (#4986)
tonerdo Dec 25, 2017
f8106e1
restructure ExportedMethodsWriter class (#4986)
tonerdo Dec 25, 2017
0fad626
remove exporting of internal nativecallable methods (#4986)
tonerdo Dec 25, 2017
996bea2
only generate exports file during native library build (#4986)
tonerdo Dec 25, 2017
b5050e6
add generation and location of version-script on linux (#4986)
tonerdo Dec 26, 2017
99435e1
make linux version script generation the default case (#4986)
tonerdo Dec 26, 2017
2dbde95
move exported methods emission to ExportedMethodsRootProvider class (…
tonerdo Dec 26, 2017
50b0686
set ExportsFile variable if not user defined and it's a shared lib bu…
tonerdo Dec 27, 2017
7fc2d0d
make optimizations to exports file emission code (#4986)
tonerdo Dec 27, 2017
3bad6d1
remove redundant info from exported definition files (#4986)
tonerdo Dec 27, 2017
0c00f1a
ensure definition file is overwritten (#4986)
tonerdo Dec 27, 2017
4f80359
add DefFileWriter class (#4986)
tonerdo Dec 27, 2017
b46e2c0
fix wasm build error caused by merge (#4986)
tonerdo Dec 28, 2017
4b7424b
rename DefFileWriter to ExportsFileWriter (#4986)
tonerdo Dec 28, 2017
7f7e1d7
restructure ExportedMethodsRootProvider class (#4986)
tonerdo Dec 31, 2017
9d581df
refactor ExportedMethodsRootProvider class (#4986)
tonerdo Dec 31, 2017
a062443
improve performance of ExportedMethods property (#4986)
tonerdo Dec 31, 2017
f085583
fix typo (#4986)
tonerdo Jan 2, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -70,7 +70,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'" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I though that -shared works on OSX too. Just for my education - why did you change this to -dynamiclib?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah I know it works. I guess I was just trying to be as platform accurate as possible, most Apple docs use -dynamiclib

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that's fine.

<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>

<ExportsFiletExt Condition="'$(OutputType)' != 'Exe' and '$(TargetOS)' == 'Windows_NT' and '$(NativeLib)' == 'Shared'">.def</ExportsFiletExt>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: typo: Filet -> File

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

<NativeObject>$(NativeIntermediateOutputPath)$(TargetName)$(NativeObjectExt)</NativeObject>
<NativeBinary>$(NativeOutputPath)$(TargetName)$(NativeBinaryExt)</NativeBinary>
<ExportsFile Condition="$(NativeLib) == 'Shared' and $(ExportsFile) == ''">$(NativeIntermediateOutputPath)$(TargetName)$(ExportsFiletExt)</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
48 changes: 48 additions & 0 deletions src/ILCompiler.Compiler/src/Compiler/DefFileWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// 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 Internal.TypeSystem;
using Internal.TypeSystem.Ecma;

namespace ILCompiler
{
public class DefFileWriter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is called ExportsFile everywhere else in this change. This should be called ExportsFileWriter to match.

{
private string _exportsFile;
private List<EcmaMethod> _methods;
private TypeSystemContext _context;

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

public void AddExportedMethods(IEnumerable<EcmaMethod> methods)
=> _methods.AddRange(methods);

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()}");
}
}
}
}
}
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 @@ -12,10 +15,20 @@ namespace ILCompiler
public class ExportedMethodsRootProvider : ICompilationRootProvider
{
private EcmaModule _module;
private List<EcmaMethod> _methods;

public ExportedMethodsRootProvider(EcmaModule module)
{
_module = module;
_methods = new List<EcmaMethod>();
}

public IEnumerable<EcmaMethod> ExportedMethods
{
get
{
return _methods;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you factor this class in a way that we can't get different results depending on when ExportedMethods is accessed? It's not a problem right now, but I can see someone getting burned by this at some point.

}
}

public void AddCompilationRoots(IRootingServiceProvider rootProvider)
Expand All @@ -36,8 +49,13 @@ public void AddCompilationRoots(IRootingServiceProvider rootProvider)
if (ecmaMethod.IsNativeCallable)
{
string nativeCallableExportName = ecmaMethod.GetNativeCallableExportName();

if (nativeCallableExportName != null)
{
if (ecmaMethod.Module != _module.Context.SystemModule)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skipping exports from the system module is a policy decision. This class should ideally be policy-free (some other component might want this list too and a filtered list might not be what they intended). Could we filter in DefFileWriter.cs?

_methods.Add(ecmaMethod);
rootProvider.AddCompilationRoot(method, "Native callable", nativeCallableExportName);
}
}
}
}
Expand Down
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\DefFileWriter.cs" />
<Compile Include="Compiler\PrecomputedMetadataManager.cs" />
<Compile Include="Compiler\ReadyToRun.cs" />
<Compile Include="Compiler\RyuJitCompilation.cs" />
Expand Down
25 changes: 23 additions & 2 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 @@ -302,7 +304,11 @@ private int Run(string[] args)
entrypointModule = module;
}

compilationRoots.Add(new ExportedMethodsRootProvider(module));
// TODO: Wasm fails to compile some of the exported methods due to missing opcodes
if (!_isWasmCodegen)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This coming back looks like a bad merge.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. Been trying to fix the Windows build error

{
compilationRoots.Add(new ExportedMethodsRootProvider(module));
}
}

if (entrypointModule != null)
Expand Down Expand Up @@ -341,7 +347,11 @@ private int Run(string[] args)
if (entrypointModule == null && !_nativeLib)
throw new Exception("No entrypoint module");

compilationRoots.Add(new ExportedMethodsRootProvider((EcmaModule)typeSystemContext.SystemModule));
// TODO: Wasm fails to compile some of the xported methods due to missing opcodes
if (!_isWasmCodegen)
{
compilationRoots.Add(new ExportedMethodsRootProvider((EcmaModule)typeSystemContext.SystemModule));
}

compilationGroup = new SingleFileCompilationModuleGroup(typeSystemContext);
}
Expand Down Expand Up @@ -446,6 +456,17 @@ private int Run(string[] args)
ObjectDumper dumper = _mapFileName != null ? new ObjectDumper(_mapFileName) : null;

CompilationResults compilationResults = compilation.Compile(_outputFilePath, dumper);
if (_nativeLib)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition should be _exportsFile != null.

{
DefFileWriter defFileWriter = new DefFileWriter(typeSystemContext, _exportsFile);
foreach (var compilationRoot in compilationRoots)
{
if (compilationRoot is ExportedMethodsRootProvider)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: You can use new C# features to avoid the cast.

 if (compilationRoot is ExportedMethodsRootProvider provider)
     defFileWriter.AddExportedMethod(provider);

defFileWriter.AddExportedMethods(((ExportedMethodsRootProvider)compilationRoot).ExportedMethods);
}

defFileWriter.EmitExportedMethods();
}

if (_dgmlLogFileName != null)
compilationResults.WriteDependencyLog(_dgmlLogFileName);
Expand Down