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.
311 lines
11 KiB
311 lines
11 KiB
using CppSharp.AST; |
|
using CppSharp.Generators; |
|
using CppSharp.Parser; |
|
using CppSharp.Passes; |
|
using System; |
|
using System.Collections.Generic; |
|
using System.IO; |
|
using System.Linq; |
|
using System.Text; |
|
using CppAbi = CppSharp.Parser.AST.CppAbi; |
|
|
|
namespace CppSharp |
|
{ |
|
class Generator : ILibrary |
|
{ |
|
private Options options = null; |
|
private string triple = ""; |
|
private CppAbi abi = CppAbi.Microsoft; |
|
|
|
public Generator(Options options) |
|
{ |
|
if (options == null) |
|
throw new ArgumentNullException(nameof(options)); |
|
|
|
this.options = options; |
|
} |
|
|
|
static TargetPlatform GetCurrentPlatform() |
|
{ |
|
if (Platform.IsWindows) |
|
return TargetPlatform.Windows; |
|
|
|
if (Platform.IsMacOS) |
|
return TargetPlatform.MacOS; |
|
|
|
if (Platform.IsLinux) |
|
return TargetPlatform.Linux; |
|
|
|
throw new System.NotImplementedException("Unknown host platform"); |
|
} |
|
|
|
void SetupTargetTriple() |
|
{ |
|
var tripleBuilder = new StringBuilder(); |
|
|
|
if (options.Architecture == TargetArchitecture.x64) |
|
tripleBuilder.Append("x86_64-"); |
|
else if(options.Architecture == TargetArchitecture.x86) |
|
tripleBuilder.Append("i686-"); |
|
|
|
if (options.Platform == TargetPlatform.Windows) |
|
{ |
|
tripleBuilder.Append("pc-win32-msvc"); |
|
abi = CppAbi.Microsoft; |
|
} |
|
else if (options.Platform == TargetPlatform.MacOS) |
|
{ |
|
tripleBuilder.Append("apple-darwin12.4.0"); |
|
abi = CppAbi.Itanium; |
|
} |
|
else if (options.Platform == TargetPlatform.Linux) |
|
{ |
|
tripleBuilder.Append("linux-gnu"); |
|
abi = CppAbi.Itanium; |
|
|
|
if(options.Cpp11ABI) |
|
tripleBuilder.Append("-cxx11abi"); |
|
} |
|
|
|
triple = tripleBuilder.ToString(); |
|
} |
|
|
|
public bool ValidateOptions(List<string> messages) |
|
{ |
|
if (!options.Platform.HasValue) |
|
options.Platform = GetCurrentPlatform(); |
|
|
|
if (Platform.IsWindows && options.Platform != TargetPlatform.Windows) |
|
{ |
|
messages.Add("Cannot create bindings for a platform other that Windows from a Windows host."); |
|
return false; |
|
} |
|
else if (Platform.IsMacOS && options.Platform != TargetPlatform.MacOS) |
|
{ |
|
messages.Add("Cannot create bindings for a platform other that macOS from a macOS host."); |
|
return false; |
|
} |
|
else if (Platform.IsLinux && options.Platform != TargetPlatform.Linux) |
|
{ |
|
messages.Add("Cannot create bindings for a platform other that Linux from a Linux host."); |
|
return false; |
|
} |
|
|
|
if (options.Platform != TargetPlatform.Windows && options.Kind != GeneratorKind.CSharp) |
|
{ |
|
messages.Add("Cannot create bindings for languages other than C# from a non-Windows host."); |
|
return false; |
|
} |
|
|
|
if (options.Platform == TargetPlatform.Linux && options.Architecture != TargetArchitecture.x64) |
|
{ |
|
messages.Add("Cannot create bindings for architectures other than x64 for Linux targets."); |
|
return false; |
|
} |
|
|
|
if (options.HeaderFiles.Count == 0) |
|
{ |
|
messages.Add("No source header file has been given to generate bindings from."); |
|
return false; |
|
} |
|
|
|
if (string.IsNullOrEmpty(options.OutputNamespace)) |
|
{ |
|
messages.Add("Output namespace not specified (see --outputnamespace option)."); |
|
return false; |
|
} |
|
|
|
if (string.IsNullOrEmpty(options.OutputFileName)) |
|
{ |
|
messages.Add("Output directory not specified (see --output option)."); |
|
return false; |
|
} |
|
|
|
if (string.IsNullOrEmpty(options.InputLibraryName) && !options.CheckSymbols) |
|
{ |
|
messages.Add("Input library name not specified and check symbols option not enabled.\nEither set the input library name (see or the check symbols flag."); |
|
return false; |
|
} |
|
|
|
if (string.IsNullOrEmpty(options.InputLibraryName) && options.CheckSymbols && options.Libraries.Count == 0) |
|
{ |
|
messages.Add("Input library name not specified and check symbols is enabled but no libraries were given.\nEither set the input library name or add at least one library."); |
|
return false; |
|
} |
|
|
|
SetupTargetTriple(); |
|
|
|
|
|
return true; |
|
} |
|
|
|
public void Setup(Driver driver) |
|
{ |
|
var parserOptions = driver.ParserOptions; |
|
parserOptions.TargetTriple = triple; |
|
parserOptions.Abi = abi; |
|
parserOptions.Verbose = options.Verbose; |
|
|
|
var driverOptions = driver.Options; |
|
driverOptions.GeneratorKind = options.Kind; |
|
var module = driverOptions.AddModule(options.OutputFileName); |
|
|
|
if(!string.IsNullOrEmpty(options.InputLibraryName)) |
|
module.SharedLibraryName = options.InputLibraryName; |
|
|
|
module.Headers.AddRange(options.HeaderFiles); |
|
module.Libraries.AddRange(options.Libraries); |
|
module.OutputNamespace = options.OutputNamespace; |
|
|
|
if (abi == CppAbi.Microsoft) |
|
parserOptions.MicrosoftMode = true; |
|
|
|
if (triple.Contains("apple")) |
|
SetupMacOptions(parserOptions); |
|
|
|
if (triple.Contains("linux")) |
|
SetupLinuxOptions(parserOptions); |
|
|
|
foreach (string s in options.Arguments) |
|
parserOptions.AddArguments(s); |
|
|
|
foreach (string s in options.IncludeDirs) |
|
parserOptions.AddIncludeDirs(s); |
|
|
|
foreach (string s in options.LibraryDirs) |
|
parserOptions.AddLibraryDirs(s); |
|
|
|
foreach (KeyValuePair<string, string> d in options.Defines) |
|
{ |
|
if(string.IsNullOrEmpty(d.Value)) |
|
parserOptions.AddDefines(d.Key); |
|
else |
|
parserOptions.AddDefines(d.Key + "=" + d.Value); |
|
} |
|
|
|
driverOptions.GenerateDebugOutput = options.Debug; |
|
driverOptions.CompileCode = options.Compile; |
|
driverOptions.OutputDir = options.OutputDir; |
|
driverOptions.CheckSymbols = options.CheckSymbols; |
|
driverOptions.UnityBuild = options.UnityBuild; |
|
driverOptions.Verbose = options.Verbose; |
|
} |
|
|
|
private void SetupLinuxOptions(ParserOptions parserOptions) |
|
{ |
|
parserOptions.MicrosoftMode = false; |
|
parserOptions.NoBuiltinIncludes = true; |
|
|
|
var headersPath = string.Empty; |
|
|
|
// Search for the available GCC versions on the provided headers. |
|
var versions = Directory.EnumerateDirectories(Path.Combine(headersPath, "usr/include/c++")); |
|
|
|
if (versions.Count() == 0) |
|
throw new Exception("No valid GCC version found on system include paths"); |
|
|
|
string gccVersionPath = versions.First(); |
|
string gccVersion = gccVersionPath.Substring(gccVersionPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); |
|
|
|
string[] systemIncludeDirs = { |
|
Path.Combine("usr", "include", "c++", gccVersion), |
|
Path.Combine("usr", "include", "x86_64-linux-gnu", "c++", gccVersion), |
|
Path.Combine("usr", "include", "c++", gccVersion, "backward"), |
|
Path.Combine("usr", "lib", "gcc", "x86_64-linux-gnu", gccVersion, "include"), |
|
Path.Combine("usr", "include", "x86_64-linux-gnu"), |
|
Path.Combine("usr", "include") |
|
}; |
|
|
|
foreach (var dir in systemIncludeDirs) |
|
parserOptions.AddSystemIncludeDirs(Path.Combine(headersPath, dir)); |
|
|
|
parserOptions.AddDefines("_GLIBCXX_USE_CXX11_ABI=" + (options.Cpp11ABI ? "1" : "0")); |
|
} |
|
|
|
private static void SetupMacOptions(ParserOptions options) |
|
{ |
|
options.MicrosoftMode = false; |
|
options.NoBuiltinIncludes = true; |
|
|
|
if (Platform.IsMacOS) |
|
{ |
|
var headersPaths = new List<string> { |
|
"/usr/include" |
|
}; |
|
|
|
foreach (var header in headersPaths) |
|
options.AddSystemIncludeDirs(header); |
|
} |
|
|
|
options.AddArguments("-stdlib=libc++"); |
|
} |
|
|
|
public void SetupPasses(Driver driver) |
|
{ |
|
driver.Context.TranslationUnitPasses.AddPass(new FunctionToInstanceMethodPass()); |
|
driver.Context.TranslationUnitPasses.AddPass(new MarshalPrimitivePointersAsRefTypePass()); |
|
} |
|
|
|
public void Preprocess(Driver driver, ASTContext ctx) |
|
{ |
|
} |
|
|
|
public void Postprocess(Driver driver, ASTContext ctx) |
|
{ |
|
} |
|
|
|
public void Run() |
|
{ |
|
StringBuilder messageBuilder = new StringBuilder(); |
|
messageBuilder.Append("Generating "); |
|
|
|
switch(options.Kind) |
|
{ |
|
case GeneratorKind.CLI: |
|
messageBuilder.Append("C++/CLI"); |
|
break; |
|
case GeneratorKind.CSharp: |
|
messageBuilder.Append("C#"); |
|
break; |
|
} |
|
|
|
messageBuilder.Append(" bindings for "); |
|
|
|
switch (options.Platform) |
|
{ |
|
case TargetPlatform.Linux: |
|
messageBuilder.Append("Linux"); |
|
break; |
|
case TargetPlatform.MacOS: |
|
messageBuilder.Append("OSX"); |
|
break; |
|
case TargetPlatform.Windows: |
|
messageBuilder.Append("Windows"); |
|
break; |
|
} |
|
|
|
messageBuilder.Append(" "); |
|
|
|
switch (options.Architecture) |
|
{ |
|
case TargetArchitecture.x86: |
|
messageBuilder.Append("x86"); |
|
break; |
|
case TargetArchitecture.x64: |
|
messageBuilder.Append("x64"); |
|
break; |
|
} |
|
|
|
if(options.Cpp11ABI) |
|
messageBuilder.Append(" (GCC C++11 ABI)"); |
|
|
|
messageBuilder.Append("..."); |
|
|
|
Console.WriteLine(messageBuilder.ToString()); |
|
|
|
ConsoleDriver.Run(this); |
|
|
|
Console.WriteLine(); |
|
} |
|
} |
|
}
|
|
|