mirror of https://github.com/mono/CppSharp.git
4 changed files with 241 additions and 88 deletions
@ -1,87 +0,0 @@ |
|||||||
using System.Collections.Generic; |
|
||||||
using System.IO; |
|
||||||
using System.Linq; |
|
||||||
using CppSharp.AST; |
|
||||||
|
|
||||||
namespace CppSharp.Passes |
|
||||||
{ |
|
||||||
public class GenerateInlinesCodePass : TranslationUnitPass |
|
||||||
{ |
|
||||||
public GenerateInlinesCodePass() |
|
||||||
{ |
|
||||||
VisitOptions.VisitClassBases = false; |
|
||||||
VisitOptions.VisitClassFields = false; |
|
||||||
VisitOptions.VisitEventParameters = false; |
|
||||||
VisitOptions.VisitFunctionParameters = false; |
|
||||||
VisitOptions.VisitFunctionReturnType = false; |
|
||||||
VisitOptions.VisitNamespaceEnums = false; |
|
||||||
VisitOptions.VisitNamespaceEvents = false; |
|
||||||
VisitOptions.VisitNamespaceTemplates = false; |
|
||||||
VisitOptions.VisitNamespaceTypedefs = false; |
|
||||||
VisitOptions.VisitNamespaceVariables = false; |
|
||||||
VisitOptions.VisitTemplateArguments = false; |
|
||||||
} |
|
||||||
|
|
||||||
public override bool VisitASTContext(ASTContext context) |
|
||||||
{ |
|
||||||
var result = base.VisitASTContext(context); |
|
||||||
WriteInlines(); |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
private void WriteInlines() |
|
||||||
{ |
|
||||||
foreach (var module in Options.Modules.Where(m => inlinesCodeGenerators.ContainsKey(m))) |
|
||||||
{ |
|
||||||
var inlinesCodeGenerator = inlinesCodeGenerators[module]; |
|
||||||
var cpp = $"{module.InlinesLibraryName}.{inlinesCodeGenerator.FileExtension}"; |
|
||||||
Directory.CreateDirectory(Options.OutputDir); |
|
||||||
var path = Path.Combine(Options.OutputDir, cpp); |
|
||||||
File.WriteAllText(path, inlinesCodeGenerator.Generate()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public override bool VisitFunctionDecl(Function function) |
|
||||||
{ |
|
||||||
if (!base.VisitFunctionDecl(function) || !NeedsSymbol(function)) |
|
||||||
return false; |
|
||||||
|
|
||||||
var module = function.TranslationUnit.Module; |
|
||||||
var inlinesCodeGenerator = GetInlinesCodeGenerator(module); |
|
||||||
|
|
||||||
if (module == Options.SystemModule) |
|
||||||
return false; |
|
||||||
|
|
||||||
return function.Visit(inlinesCodeGenerator); |
|
||||||
} |
|
||||||
|
|
||||||
private bool NeedsSymbol(Function function) |
|
||||||
{ |
|
||||||
var mangled = function.Mangled; |
|
||||||
var method = function as Method; |
|
||||||
return function.IsGenerated && !function.IsDeleted && !function.IsDependent && |
|
||||||
!function.IsPure && (!string.IsNullOrEmpty(function.Body) || function.IsImplicit) && |
|
||||||
// we don't need symbols for virtual functions anyway
|
|
||||||
(method == null || (!method.IsVirtual && !method.IsSynthetized && |
|
||||||
(!method.IsConstructor || !((Class) method.Namespace).IsAbstract))) && |
|
||||||
// we cannot handle nested anonymous types
|
|
||||||
(!(function.Namespace is Class) || !string.IsNullOrEmpty(function.Namespace.OriginalName)) && |
|
||||||
!Context.Symbols.FindSymbol(ref mangled); |
|
||||||
} |
|
||||||
|
|
||||||
InlinesCodeGenerator GetInlinesCodeGenerator(Module module) |
|
||||||
{ |
|
||||||
if (inlinesCodeGenerators.ContainsKey(module)) |
|
||||||
return inlinesCodeGenerators[module]; |
|
||||||
|
|
||||||
var inlinesCodeGenerator = new InlinesCodeGenerator(Context, module.Units); |
|
||||||
inlinesCodeGenerators[module] = inlinesCodeGenerator; |
|
||||||
inlinesCodeGenerator.Process(); |
|
||||||
|
|
||||||
return inlinesCodeGenerator; |
|
||||||
} |
|
||||||
|
|
||||||
private Dictionary<Module, InlinesCodeGenerator> inlinesCodeGenerators = |
|
||||||
new Dictionary<Module, InlinesCodeGenerator>(); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,187 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Parser; |
||||||
|
using CppSharp.Utils; |
||||||
|
|
||||||
|
namespace CppSharp.Passes |
||||||
|
{ |
||||||
|
public class GenerateInlinesPass : TranslationUnitPass |
||||||
|
{ |
||||||
|
public GenerateInlinesPass() |
||||||
|
{ |
||||||
|
VisitOptions.VisitClassBases = false; |
||||||
|
VisitOptions.VisitClassFields = false; |
||||||
|
VisitOptions.VisitEventParameters = false; |
||||||
|
VisitOptions.VisitFunctionParameters = false; |
||||||
|
VisitOptions.VisitFunctionReturnType = false; |
||||||
|
VisitOptions.VisitNamespaceEnums = false; |
||||||
|
VisitOptions.VisitNamespaceEvents = false; |
||||||
|
VisitOptions.VisitNamespaceTemplates = false; |
||||||
|
VisitOptions.VisitNamespaceTypedefs = false; |
||||||
|
VisitOptions.VisitNamespaceVariables = false; |
||||||
|
VisitOptions.VisitTemplateArguments = false; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitASTContext(ASTContext context) |
||||||
|
{ |
||||||
|
var result = base.VisitASTContext(context); |
||||||
|
var findSymbolsPass = Context.TranslationUnitPasses.FindPass<FindSymbolsPass>(); |
||||||
|
findSymbolsPass.Wait = true; |
||||||
|
GenerateInlines(); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler<InlinesCodeEventArgs> InlinesCodeGenerated; |
||||||
|
|
||||||
|
private void GenerateInlines() |
||||||
|
{ |
||||||
|
var modules = (from module in Options.Modules |
||||||
|
where inlinesCodeGenerators.ContainsKey(module) |
||||||
|
select module).ToList(); |
||||||
|
remainingCompilationTasks = modules.Count; |
||||||
|
foreach (var module in modules) |
||||||
|
{ |
||||||
|
var inlinesCodeGenerator = inlinesCodeGenerators[module]; |
||||||
|
var cpp = $"{module.InlinesLibraryName}.{inlinesCodeGenerator.FileExtension}"; |
||||||
|
Directory.CreateDirectory(Options.OutputDir); |
||||||
|
var path = Path.Combine(Options.OutputDir, cpp); |
||||||
|
File.WriteAllText(path, inlinesCodeGenerator.Generate()); |
||||||
|
|
||||||
|
var e = new InlinesCodeEventArgs(module); |
||||||
|
InlinesCodeGenerated?.Invoke(this, e); |
||||||
|
if (string.IsNullOrEmpty(e.CustomCompiler)) |
||||||
|
RemainingCompilationTasks--; |
||||||
|
else |
||||||
|
InvokeCompiler(e.CustomCompiler, e.CompilerArguments, |
||||||
|
e.OutputDir, module.InlinesLibraryName); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
if (!base.VisitFunctionDecl(function)) |
||||||
|
return false; |
||||||
|
|
||||||
|
var module = function.TranslationUnit.Module; |
||||||
|
if (module == Options.SystemModule) |
||||||
|
{ |
||||||
|
GetInlinesCodeGenerator(module); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (!NeedsSymbol(function)) |
||||||
|
return false; |
||||||
|
|
||||||
|
var inlinesCodeGenerator = GetInlinesCodeGenerator(module); |
||||||
|
return function.Visit(inlinesCodeGenerator); |
||||||
|
} |
||||||
|
|
||||||
|
public class InlinesCodeEventArgs : EventArgs |
||||||
|
{ |
||||||
|
public InlinesCodeEventArgs(Module module) |
||||||
|
{ |
||||||
|
this.Module = module; |
||||||
|
} |
||||||
|
|
||||||
|
public Module Module { get; set; } |
||||||
|
public string CustomCompiler { get; set; } |
||||||
|
public string CompilerArguments { get; set; } |
||||||
|
public string OutputDir { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
private bool NeedsSymbol(Function function) |
||||||
|
{ |
||||||
|
var mangled = function.Mangled; |
||||||
|
var method = function as Method; |
||||||
|
return function.IsGenerated && !function.IsDeleted && !function.IsDependent && |
||||||
|
!function.IsPure && (!string.IsNullOrEmpty(function.Body) || function.IsImplicit) && |
||||||
|
// we don't need symbols for virtual functions anyway
|
||||||
|
(method == null || (!method.IsVirtual && !method.IsSynthetized && |
||||||
|
(!method.IsConstructor || !((Class) method.Namespace).IsAbstract))) && |
||||||
|
// we cannot handle nested anonymous types
|
||||||
|
(!(function.Namespace is Class) || !string.IsNullOrEmpty(function.Namespace.OriginalName)) && |
||||||
|
!Context.Symbols.FindSymbol(ref mangled); |
||||||
|
} |
||||||
|
|
||||||
|
private InlinesCodeGenerator GetInlinesCodeGenerator(Module module) |
||||||
|
{ |
||||||
|
if (inlinesCodeGenerators.ContainsKey(module)) |
||||||
|
return inlinesCodeGenerators[module]; |
||||||
|
|
||||||
|
var inlinesCodeGenerator = new InlinesCodeGenerator(Context, module.Units); |
||||||
|
inlinesCodeGenerators[module] = inlinesCodeGenerator; |
||||||
|
inlinesCodeGenerator.Process(); |
||||||
|
|
||||||
|
return inlinesCodeGenerator; |
||||||
|
} |
||||||
|
|
||||||
|
private void InvokeCompiler(string compiler, string arguments, string outputDir, string inlines) |
||||||
|
{ |
||||||
|
new Thread(() => |
||||||
|
{ |
||||||
|
int error; |
||||||
|
string errorMessage; |
||||||
|
ProcessHelper.Run(compiler, arguments, out error, out errorMessage); |
||||||
|
if (string.IsNullOrEmpty(errorMessage)) |
||||||
|
CollectInlinedSymbols(outputDir, inlines); |
||||||
|
else |
||||||
|
Diagnostics.Error(errorMessage); |
||||||
|
RemainingCompilationTasks--; |
||||||
|
}).Start(); |
||||||
|
} |
||||||
|
|
||||||
|
private void CollectInlinedSymbols(string outputDir, string inlines) |
||||||
|
{ |
||||||
|
using (var parserOptions = new ParserOptions()) |
||||||
|
{ |
||||||
|
parserOptions.AddLibraryDirs(outputDir); |
||||||
|
var output = Path.GetFileName($@"{(Platform.IsWindows ?
|
||||||
|
string.Empty : "lib")}{inlines}.{ |
||||||
|
(Platform.IsMacOS ? "dylib" : Platform.IsWindows ? "dll" : "so")}");
|
||||||
|
parserOptions.LibraryFile = output; |
||||||
|
using (var parserResult = Parser.ClangParser.ParseLibrary(parserOptions)) |
||||||
|
{ |
||||||
|
if (parserResult.Kind == ParserResultKind.Success) |
||||||
|
{ |
||||||
|
var nativeLibrary = ClangParser.ConvertLibrary(parserResult.Library); |
||||||
|
lock (@lock) |
||||||
|
{ |
||||||
|
Context.Symbols.Libraries.Add(nativeLibrary); |
||||||
|
Context.Symbols.IndexSymbols(); |
||||||
|
} |
||||||
|
parserResult.Library.Dispose(); |
||||||
|
} |
||||||
|
else |
||||||
|
Diagnostics.Error($"Parsing of {Path.Combine(outputDir, output)} failed."); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private int RemainingCompilationTasks |
||||||
|
{ |
||||||
|
get { return remainingCompilationTasks; } |
||||||
|
set |
||||||
|
{ |
||||||
|
if (remainingCompilationTasks != value) |
||||||
|
{ |
||||||
|
remainingCompilationTasks = value; |
||||||
|
if (remainingCompilationTasks == 0) |
||||||
|
{ |
||||||
|
var findSymbolsPass = Context.TranslationUnitPasses.FindPass<FindSymbolsPass>(); |
||||||
|
findSymbolsPass.Wait = false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private int remainingCompilationTasks; |
||||||
|
private static readonly object @lock = new object(); |
||||||
|
|
||||||
|
private Dictionary<Module, InlinesCodeGenerator> inlinesCodeGenerators = |
||||||
|
new Dictionary<Module, InlinesCodeGenerator>(); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,53 @@ |
|||||||
|
using System; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Text; |
||||||
|
|
||||||
|
namespace CppSharp.Utils |
||||||
|
{ |
||||||
|
public class ProcessHelper |
||||||
|
{ |
||||||
|
public static string Run(string path, string args, out int error, out string errorMessage) |
||||||
|
{ |
||||||
|
using (Process process = new Process()) |
||||||
|
{ |
||||||
|
process.StartInfo.FileName = path; |
||||||
|
process.StartInfo.Arguments = args; |
||||||
|
process.StartInfo.UseShellExecute = false; |
||||||
|
process.StartInfo.RedirectStandardOutput = true; |
||||||
|
process.StartInfo.RedirectStandardError = true; |
||||||
|
|
||||||
|
var reterror = new StringBuilder(); |
||||||
|
var retout = new StringBuilder(); |
||||||
|
process.OutputDataReceived += (sender, outargs) => |
||||||
|
{ |
||||||
|
if (!string.IsNullOrEmpty(outargs.Data)) |
||||||
|
{ |
||||||
|
if (retout.Length > 0) |
||||||
|
retout.AppendLine(); |
||||||
|
retout.Append(outargs.Data); |
||||||
|
} |
||||||
|
}; |
||||||
|
process.ErrorDataReceived += (sender, errargs) => |
||||||
|
{ |
||||||
|
if (!string.IsNullOrEmpty(errargs.Data)) |
||||||
|
{ |
||||||
|
if (reterror.Length > 0) |
||||||
|
reterror.AppendLine(); |
||||||
|
reterror.Append(errargs.Data); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
process.Start(); |
||||||
|
process.BeginOutputReadLine(); |
||||||
|
process.BeginErrorReadLine(); |
||||||
|
process.WaitForExit(); |
||||||
|
process.CancelOutputRead(); |
||||||
|
process.CancelErrorRead(); |
||||||
|
|
||||||
|
error = process.ExitCode; |
||||||
|
errorMessage = reterror.ToString(); |
||||||
|
return retout.ToString(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue