mirror of https://github.com/mono/CppSharp.git
c-sharpdotnetmonobindingsbridgecclangcpluspluscppsharpglueinteropparserparsingpinvokeswigsyntax-treevisitorsxamarinxamarin-bindings
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
361 lines
12 KiB
361 lines
12 KiB
using CppSharp.AST; |
|
using CppSharp.Generators; |
|
using CppSharp.Generators.CLI; |
|
using CppSharp.Generators.CSharp; |
|
using CppSharp.Passes; |
|
using CppSharp.Types; |
|
using System; |
|
using System.Collections.Generic; |
|
using System.IO; |
|
|
|
namespace CppSharp |
|
{ |
|
public class Driver |
|
{ |
|
public delegate Generator CreateGeneratorDelegate(Driver driver); |
|
public static Dictionary<LanguageGeneratorKind, CreateGeneratorDelegate> |
|
Generators; |
|
|
|
static Driver() |
|
{ |
|
Generators = new Dictionary<LanguageGeneratorKind, |
|
CreateGeneratorDelegate>(); |
|
Generators[LanguageGeneratorKind.CSharp] = driver => |
|
new CSharpGenerator(driver); |
|
Generators[LanguageGeneratorKind.CLI] = driver => |
|
new CLIGenerator(driver); |
|
} |
|
|
|
public DriverOptions Options { get; private set; } |
|
public IDiagnosticConsumer Diagnostics { get; private set; } |
|
public Parser Parser { get; private set; } |
|
public TypeMapDatabase TypeDatabase { get; private set; } |
|
public PassBuilder<TranslationUnitPass> TranslationUnitPasses { get; private set; } |
|
public PassBuilder<GeneratorOutputPass> GeneratorOutputPasses { get; private set; } |
|
public Generator Generator { get; private set; } |
|
|
|
public Library Library { get; private set; } |
|
public Library LibrarySymbols { get; private set; } |
|
|
|
public Driver(DriverOptions options, IDiagnosticConsumer diagnostics) |
|
{ |
|
Options = options; |
|
Diagnostics = diagnostics; |
|
Parser = new Parser(Options); |
|
Parser.OnHeaderParsed += OnFileParsed; |
|
Parser.OnLibraryParsed += OnFileParsed; |
|
TypeDatabase = new TypeMapDatabase(); |
|
TranslationUnitPasses = new PassBuilder<TranslationUnitPass>(this); |
|
GeneratorOutputPasses = new PassBuilder<GeneratorOutputPass>(this); |
|
} |
|
|
|
static void ValidateOptions(DriverOptions options) |
|
{ |
|
if (!Generators.ContainsKey(options.GeneratorKind)) |
|
throw new InvalidOptionException(); |
|
|
|
if (string.IsNullOrWhiteSpace(options.LibraryName)) |
|
throw new InvalidOptionException(); |
|
|
|
for (var i = 0; i < options.IncludeDirs.Count; i++) |
|
options.IncludeDirs[i] = Path.GetFullPath(options.IncludeDirs[i]); |
|
|
|
for (var i = 0; i < options.LibraryDirs.Count; i++) |
|
options.LibraryDirs[i] = Path.GetFullPath(options.LibraryDirs[i]); |
|
|
|
if (string.IsNullOrWhiteSpace(options.OutputNamespace)) |
|
options.OutputNamespace = options.LibraryName; |
|
} |
|
|
|
public void Setup() |
|
{ |
|
ValidateOptions(Options); |
|
|
|
Generator = Generators[Options.GeneratorKind](this); |
|
TypeDatabase.SetupTypeMaps(); |
|
} |
|
|
|
void OnFileParsed(string file, ParserResult result) |
|
{ |
|
switch (result.Kind) |
|
{ |
|
case ParserResultKind.Success: |
|
Diagnostics.EmitMessage(DiagnosticId.ParseResult, |
|
"Parsed '{0}'", file); |
|
break; |
|
case ParserResultKind.Error: |
|
Diagnostics.EmitError(DiagnosticId.ParseResult, |
|
"Error parsing '{0}'", file); |
|
break; |
|
case ParserResultKind.FileNotFound: |
|
Diagnostics.EmitError(DiagnosticId.ParseResult, |
|
"File '{0}' was not found", file); |
|
break; |
|
} |
|
|
|
foreach (var diag in result.Diagnostics) |
|
{ |
|
if (Options.IgnoreParseWarnings |
|
&& diag.Level == ParserDiagnosticLevel.Warning) |
|
continue; |
|
|
|
Diagnostics.EmitMessage(DiagnosticId.ParserDiagnostic, |
|
"{0}({1},{2}): {3}: {4}", diag.FileName, diag.LineNumber, |
|
diag.ColumnNumber, diag.Level.ToString().ToLower(), |
|
diag.Message); |
|
} |
|
} |
|
|
|
public bool ParseCode() |
|
{ |
|
if (!Parser.ParseHeaders(Options.Headers)) |
|
return false; |
|
|
|
Library = Parser.Library; |
|
|
|
return true; |
|
} |
|
|
|
public bool ParseLibraries() |
|
{ |
|
if (!Parser.ParseLibraries(Options.Libraries)) |
|
return false; |
|
|
|
LibrarySymbols = Parser.Library; |
|
|
|
return true; |
|
} |
|
|
|
public void SetupPasses(ILibrary library) |
|
{ |
|
TranslationUnitPasses.AddPass(new CleanUnitPass(Options)); |
|
TranslationUnitPasses.AddPass(new SortDeclarationsPass()); |
|
TranslationUnitPasses.AddPass(new ResolveIncompleteDeclsPass()); |
|
TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass()); |
|
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); |
|
TranslationUnitPasses.AddPass(new GenerateInlinesCodePass()); |
|
|
|
library.SetupPasses(this); |
|
|
|
TranslationUnitPasses.AddPass(new FindSymbolsPass()); |
|
TranslationUnitPasses.AddPass(new MoveOperatorToClassPass()); |
|
TranslationUnitPasses.AddPass(new CheckOperatorsOverloadsPass()); |
|
TranslationUnitPasses.AddPass(new CheckVirtualOverrideReturnCovariance()); |
|
TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions()); |
|
|
|
Generator.SetupPasses(); |
|
TranslationUnitPasses.AddPass(new FieldToPropertyPass()); |
|
TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass()); |
|
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); |
|
TranslationUnitPasses.AddPass(new CheckFlagEnumsPass()); |
|
TranslationUnitPasses.AddPass(new CheckDuplicatedNamesPass()); |
|
if (Options.GenerateAbstractImpls) |
|
TranslationUnitPasses.AddPass(new GenerateAbstractImplementationsPass()); |
|
} |
|
|
|
public void ProcessCode() |
|
{ |
|
TranslationUnitPasses.RunPasses(pass => pass.VisitLibrary(Library)); |
|
Generator.Process(); |
|
} |
|
|
|
public List<GeneratorOutput> GenerateCode() |
|
{ |
|
return Generator.Generate(); |
|
} |
|
|
|
public void WriteCode(List<GeneratorOutput> outputs) |
|
{ |
|
var outputPath = Options.OutputDir; |
|
|
|
if (!Directory.Exists(outputPath)) |
|
Directory.CreateDirectory(outputPath); |
|
|
|
foreach (var output in outputs) |
|
{ |
|
var fileBase = output.TranslationUnit.FileNameWithoutExtension; |
|
|
|
if (Options.GenerateName != null) |
|
fileBase = Options.GenerateName(output.TranslationUnit); |
|
|
|
foreach (var template in output.Templates) |
|
{ |
|
var fileName = string.Format("{0}.{1}", fileBase, template.FileExtension); |
|
Diagnostics.EmitMessage(DiagnosticId.FileGenerated, "Generated '{0}'", fileName); |
|
|
|
var filePath = Path.Combine(outputPath, fileName); |
|
File.WriteAllText(Path.GetFullPath(filePath), template.Generate()); |
|
} |
|
} |
|
} |
|
|
|
public void AddTranslationUnitPass(TranslationUnitPass pass) |
|
{ |
|
TranslationUnitPasses.AddPass(pass); |
|
} |
|
|
|
public void AddGeneratorOutputPass(GeneratorOutputPass pass) |
|
{ |
|
GeneratorOutputPasses.AddPass(pass); |
|
} |
|
} |
|
|
|
public class DriverOptions |
|
{ |
|
public DriverOptions() |
|
{ |
|
Defines = new List<string>(); |
|
IncludeDirs = new List<string>(); |
|
SystemIncludeDirs = new List<string>(); |
|
Headers = new List<string>(); |
|
|
|
OutputDir = Directory.GetCurrentDirectory(); |
|
|
|
var platform = Environment.OSVersion.Platform; |
|
var isUnix = platform == PlatformID.Unix || platform == PlatformID.MacOSX; |
|
MicrosoftMode = !isUnix; |
|
Abi = isUnix ? CppAbi.Itanium : CppAbi.Microsoft; |
|
|
|
LibraryDirs = new List<string>(); |
|
Libraries = new List<string>(); |
|
CheckSymbols = true; |
|
|
|
GeneratorKind = LanguageGeneratorKind.CSharp; |
|
GenerateLibraryNamespace = true; |
|
GeneratePartialClasses = true; |
|
OutputInteropIncludes = true; |
|
MaxIndent = 80; |
|
CommentPrefix = "///"; |
|
} |
|
|
|
// General options |
|
public bool Verbose; |
|
public bool Quiet; |
|
public bool ShowHelpText; |
|
public bool OutputDebug; |
|
|
|
// Parser options |
|
public List<string> Defines; |
|
public List<string> IncludeDirs; |
|
public List<string> SystemIncludeDirs; |
|
public List<string> Headers; |
|
public bool NoStandardIncludes; |
|
public bool NoBuiltinIncludes; |
|
public bool MicrosoftMode; |
|
public string TargetTriple; |
|
public int ToolsetToUse; |
|
public bool IgnoreParseWarnings; |
|
public bool IgnoreParseErrors; |
|
public CppAbi Abi; |
|
public bool IsItaniumAbi { get { return Abi == CppAbi.Itanium; } } |
|
public bool IsMicrosoftAbi { get { return Abi == CppAbi.Microsoft; } } |
|
|
|
// Library options |
|
public List<string> LibraryDirs; |
|
public List<string> Libraries; |
|
public bool CheckSymbols; |
|
public string SharedLibraryName; |
|
|
|
// Generator options |
|
public LanguageGeneratorKind GeneratorKind; |
|
public string OutputNamespace; |
|
public string OutputDir; |
|
public string LibraryName; |
|
public bool OutputInteropIncludes; |
|
public bool GenerateLibraryNamespace; |
|
public bool GenerateFunctionTemplates; |
|
public bool GeneratePartialClasses; |
|
public bool GenerateVirtualTables; |
|
public bool GenerateAbstractImpls; |
|
public bool GenerateInternalImports; |
|
public string IncludePrefix; |
|
public bool WriteOnlyWhenChanged; |
|
public Func<TranslationUnit, string> GenerateName; |
|
public int MaxIndent; |
|
public string CommentPrefix; |
|
|
|
private string inlinesLibraryName; |
|
public string InlinesLibraryName |
|
{ |
|
get |
|
{ |
|
if (string.IsNullOrEmpty(inlinesLibraryName)) |
|
{ |
|
return string.Format("{0}-inlines", OutputNamespace); |
|
} |
|
return inlinesLibraryName; |
|
} |
|
set { inlinesLibraryName = value; } |
|
} |
|
|
|
public bool IsCSharpGenerator |
|
{ |
|
get { return GeneratorKind == LanguageGeneratorKind.CSharp; } |
|
} |
|
|
|
public bool IsCLIGenerator |
|
{ |
|
get { return GeneratorKind == LanguageGeneratorKind.CLI; } |
|
} |
|
|
|
public bool Is32Bit { get { return true; } } |
|
} |
|
|
|
public class InvalidOptionException : Exception |
|
{ |
|
} |
|
|
|
public static class ConsoleDriver |
|
{ |
|
public static void Run(ILibrary library) |
|
{ |
|
var options = new DriverOptions(); |
|
var driver = new Driver(options, new TextDiagnosticPrinter()); |
|
library.Setup(driver); |
|
driver.Setup(); |
|
|
|
if (!options.Quiet) |
|
Console.WriteLine("Parsing libraries..."); |
|
|
|
if (!driver.ParseLibraries()) |
|
return; |
|
|
|
if (!options.Quiet) |
|
Console.WriteLine("Indexing library symbols..."); |
|
|
|
driver.LibrarySymbols.IndexSymbols(); |
|
|
|
if (!options.Quiet) |
|
Console.WriteLine("Parsing code..."); |
|
|
|
if (!driver.ParseCode()) |
|
return; |
|
|
|
if (!options.Quiet) |
|
Console.WriteLine("Processing code..."); |
|
|
|
library.Preprocess(driver, driver.Library); |
|
|
|
driver.SetupPasses(library); |
|
|
|
driver.ProcessCode(); |
|
library.Postprocess(driver.Library); |
|
|
|
if (!options.Quiet) |
|
Console.WriteLine("Generating code..."); |
|
|
|
var outputs = driver.GenerateCode(); |
|
|
|
foreach (var output in outputs) |
|
{ |
|
foreach (var pass in driver.GeneratorOutputPasses.Passes) |
|
{ |
|
pass.Driver = driver; |
|
pass.VisitGeneratorOutput(output); |
|
} |
|
} |
|
|
|
driver.WriteCode(outputs); |
|
} |
|
} |
|
} |