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.
427 lines
15 KiB
427 lines
15 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Diagnostics; |
|
using System.Globalization; |
|
using System.IO; |
|
using System.Linq; |
|
using System.Reflection; |
|
using System.Text.RegularExpressions; |
|
using LanguageVersion = CppSharp.Parser.LanguageVersion; |
|
|
|
namespace CppSharp.Parser |
|
{ |
|
public enum LanguageVersion |
|
{ |
|
/// <summary> |
|
/// C programming language (year 1999). |
|
/// </summary> |
|
C99, |
|
/// <summary> |
|
/// C programming language (year 1999, GNU variant). |
|
/// </summary> |
|
C99_GNU, |
|
/// <summary> |
|
/// C++ programming language (year 1998). |
|
/// </summary> |
|
CPP98, |
|
/// <summary> |
|
/// C++ programming language (year 1998, GNU variant). |
|
/// </summary> |
|
CPP98_GNU, |
|
/// <summary> |
|
/// C++ programming language (year 2011). |
|
/// </summary> |
|
CPP11, |
|
/// <summary> |
|
/// C++ programming language (year 2011, GNU variant). |
|
/// </summary> |
|
CPP11_GNU, |
|
/// <summary> |
|
/// C++ programming language (year 2014). |
|
/// </summary> |
|
CPP14, |
|
/// <summary> |
|
/// C++ programming language (year 2014, GNU variant). |
|
/// </summary> |
|
CPP14_GNU, |
|
/// <summary> |
|
/// C++ programming language (year 2017). |
|
/// </summary> |
|
CPP17, |
|
/// <summary> |
|
/// C++ programming language (year 2017, GNU variant). |
|
/// </summary> |
|
CPP17_GNU, |
|
} |
|
|
|
public class ParserOptions : CppParserOptions |
|
{ |
|
public ParserOptions() |
|
{ |
|
MicrosoftMode = !Platform.IsUnixPlatform; |
|
} |
|
|
|
public ParserOptions(ParserOptions options) |
|
{ |
|
ToolSetToUse = options.ToolSetToUse; |
|
TargetTriple = options.TargetTriple; |
|
NoStandardIncludes = options.NoStandardIncludes; |
|
NoBuiltinIncludes = options.NoBuiltinIncludes; |
|
MicrosoftMode = options.MicrosoftMode; |
|
Verbose = options.Verbose; |
|
EnableRTTI = options.EnableRTTI; |
|
LanguageVersion = options.LanguageVersion; |
|
UnityBuild = options.UnityBuild; |
|
SkipPrivateDeclarations = options.SkipPrivateDeclarations; |
|
SkipFunctionBodies = options.SkipFunctionBodies; |
|
SkipLayoutInfo = options.SkipLayoutInfo; |
|
ForceClangToolchainLookup = options.ForceClangToolchainLookup; |
|
} |
|
|
|
public bool IsItaniumLikeAbi => !IsMicrosoftAbi; |
|
public bool IsMicrosoftAbi => TargetTriple.Contains("win32") || |
|
TargetTriple.Contains("windows") || TargetTriple.Contains("msvc"); |
|
|
|
public bool EnableRTTI { get; set; } |
|
public LanguageVersion? LanguageVersion { get; set; } |
|
|
|
/// <summary> |
|
/// This option forces the driver code to use Clang's toolchain code |
|
/// to lookup the location of system headers and library locations. |
|
/// At the moment, it only makes a difference for MSVC targets. |
|
/// If its true, then we opt to use Clang's MSVC lookup logic. |
|
/// </summary> |
|
public bool ForceClangToolchainLookup = true; |
|
|
|
public ParserOptions BuildForSourceFile( |
|
IEnumerable<CppSharp.AST.Module> modules, string file = null) |
|
{ |
|
var options = new ParserOptions(this); |
|
|
|
// This eventually gets passed to Clang's MSCompatibilityVersion, which |
|
// is in turn used to derive the value of the built-in define _MSC_VER. |
|
// It used to receive a 4-digit based identifier but now expects a full |
|
// version MSVC digit, so check if we still have the old version and |
|
// convert to the right format. |
|
|
|
if (ToolSetToUse.ToString(CultureInfo.InvariantCulture).Length == 4) |
|
ToolSetToUse *= 100000; |
|
|
|
for (uint i = 0; i < ArgumentsCount; ++i) |
|
{ |
|
var arg = GetArguments(i); |
|
options.AddArguments(arg); |
|
} |
|
|
|
for (uint i = 0; i < IncludeDirsCount; ++i) |
|
{ |
|
var include = GetIncludeDirs(i); |
|
options.AddIncludeDirs(include); |
|
} |
|
|
|
for (uint i = 0; i < SystemIncludeDirsCount; ++i) |
|
{ |
|
var include = GetSystemIncludeDirs(i); |
|
options.AddSystemIncludeDirs(include); |
|
} |
|
|
|
for (uint i = 0; i < DefinesCount; ++i) |
|
{ |
|
var define = GetDefines(i); |
|
options.AddDefines(define); |
|
} |
|
|
|
for (uint i = 0; i < UndefinesCount; ++i) |
|
{ |
|
var define = GetUndefines(i); |
|
options.AddUndefines(define); |
|
} |
|
|
|
for (uint i = 0; i < LibraryDirsCount; ++i) |
|
{ |
|
var lib = GetLibraryDirs(i); |
|
options.AddLibraryDirs(lib); |
|
} |
|
|
|
foreach (var module in modules.Where( |
|
m => file == null || m.Headers.Contains(file))) |
|
{ |
|
foreach (var include in module.IncludeDirs) |
|
options.AddIncludeDirs(include); |
|
|
|
foreach (var define in module.Defines) |
|
options.AddDefines(define); |
|
|
|
foreach (var undefine in module.Undefines) |
|
options.AddUndefines(undefine); |
|
|
|
foreach (var libraryDir in module.LibraryDirs) |
|
options.AddLibraryDirs(libraryDir); |
|
} |
|
|
|
return options; |
|
} |
|
|
|
public void SetupMSVC() |
|
{ |
|
var vsVersion = VisualStudioVersion.Latest; |
|
|
|
// Silence "warning CS0162: Unreachable code detected" |
|
#pragma warning disable 162 |
|
|
|
switch (BuildConfig.Choice) |
|
{ |
|
case "vs2012": |
|
vsVersion = VisualStudioVersion.VS2012; |
|
break; |
|
case "vs2013": |
|
vsVersion = VisualStudioVersion.VS2013; |
|
break; |
|
case "vs2015": |
|
vsVersion = VisualStudioVersion.VS2015; |
|
break; |
|
case "vs2017": |
|
vsVersion = VisualStudioVersion.VS2017; |
|
break; |
|
|
|
#pragma warning restore 162 |
|
|
|
} |
|
|
|
SetupMSVC(vsVersion); |
|
} |
|
|
|
/// <summary> |
|
/// Sets up the parser options to work with the given Visual Studio toolchain. |
|
/// </summary> |
|
/// <param name="vsVersion">The version of Visual Studio to look for.</param> |
|
public void SetupMSVC(VisualStudioVersion vsVersion) |
|
{ |
|
MicrosoftMode = true; |
|
|
|
var clVersion = MSVCToolchain.GetCLVersion(vsVersion); |
|
ToolSetToUse = clVersion.Major * 10000000 + clVersion.Minor * 100000; |
|
|
|
if (!ForceClangToolchainLookup) |
|
{ |
|
NoStandardIncludes = true; |
|
NoBuiltinIncludes = true; |
|
|
|
AddSystemIncludeDirs(BuiltinsDir); |
|
|
|
vsVersion = MSVCToolchain.FindVSVersion(vsVersion); |
|
foreach (var include in MSVCToolchain.GetSystemIncludes(vsVersion)) |
|
AddSystemIncludeDirs(include); |
|
} |
|
|
|
// do not remove the CppSharp prefix becase the Mono C# compiler breaks |
|
if (!LanguageVersion.HasValue) |
|
LanguageVersion = CppSharp.Parser.LanguageVersion.CPP14_GNU; |
|
|
|
AddArguments("-fms-extensions"); |
|
AddArguments("-fms-compatibility"); |
|
AddArguments("-fdelayed-template-parsing"); |
|
} |
|
|
|
/// <summary> |
|
/// Set to true to opt for Xcode Clang builtin headers |
|
/// </summary> |
|
public bool UseXcodeBuiltins; |
|
|
|
public void SetupXcode() |
|
{ |
|
var cppIncPath = XcodeToolchain.GetXcodeCppIncludesFolder(); |
|
AddSystemIncludeDirs(cppIncPath); |
|
|
|
var builtinsPath = XcodeToolchain.GetXcodeBuiltinIncludesFolder(); |
|
AddSystemIncludeDirs(UseXcodeBuiltins ? builtinsPath : BuiltinsDir); |
|
|
|
var includePath = XcodeToolchain.GetXcodeIncludesFolder(); |
|
AddSystemIncludeDirs(includePath); |
|
|
|
NoBuiltinIncludes = true; |
|
NoStandardIncludes = true; |
|
|
|
AddArguments("-stdlib=libc++"); |
|
} |
|
|
|
private void GetUnixCompilerInfo(string headersPath, out string compiler, |
|
out string longVersion, out string shortVersion) |
|
{ |
|
if (!Platform.IsLinux) |
|
{ |
|
compiler = "gcc"; |
|
|
|
// 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(); |
|
longVersion = shortVersion = gccVersionPath.Substring( |
|
gccVersionPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); |
|
|
|
return; |
|
} |
|
|
|
var info = new ProcessStartInfo(Environment.GetEnvironmentVariable("CXX") ?? "gcc", "-v"); |
|
info.RedirectStandardError = true; |
|
info.CreateNoWindow = true; |
|
info.UseShellExecute = false; |
|
|
|
var process = Process.Start(info); |
|
if (process == null) |
|
throw new SystemException("GCC compiler was not found."); |
|
|
|
process.WaitForExit(); |
|
|
|
var output = process.StandardError.ReadToEnd(); |
|
var match = Regex.Match(output, "(gcc|clang) version (([0-9]+\\.[0-9]+)\\.[0-9]+)"); |
|
if (!match.Success) |
|
throw new SystemException("GCC compiler was not found."); |
|
|
|
compiler = match.Groups[1].ToString(); |
|
longVersion = match.Groups[2].ToString(); |
|
shortVersion = match.Groups[3].ToString(); |
|
} |
|
|
|
public void SetupLinux(string headersPath = "") |
|
{ |
|
MicrosoftMode = false; |
|
NoBuiltinIncludes = true; |
|
NoStandardIncludes = true; |
|
|
|
string compiler, longVersion, shortVersion; |
|
GetUnixCompilerInfo(headersPath, out compiler, out longVersion, out shortVersion); |
|
|
|
AddSystemIncludeDirs(BuiltinsDir); |
|
|
|
string[] versions = { longVersion, shortVersion }; |
|
string[] triples = { "x86_64-linux-gnu", "x86_64-pc-linux-gnu" }; |
|
if (compiler == "gcc") |
|
{ |
|
foreach (var version in versions) |
|
{ |
|
AddSystemIncludeDirs($"{headersPath}/usr/include/c++/{version}"); |
|
AddSystemIncludeDirs($"{headersPath}/usr/include/c++/{version}/backward"); |
|
|
|
foreach (var triple in triples) |
|
{ |
|
AddSystemIncludeDirs($"{headersPath}/usr/include/{triple}/c++/{version}"); |
|
AddSystemIncludeDirs($"{headersPath}/usr/include/c++/{version}/{triple}"); |
|
} |
|
} |
|
} |
|
|
|
foreach (var triple in triples) |
|
{ |
|
foreach (var version in versions) |
|
{ |
|
AddSystemIncludeDirs($"{headersPath}/usr/lib/{compiler}/{triple}/{version}/include"); |
|
AddSystemIncludeDirs($"{headersPath}/usr/lib/{compiler}/{triple}/{version}/include/c++"); |
|
AddSystemIncludeDirs($"{headersPath}/usr/lib/{compiler}/{triple}/{version}/include/c++/{triple}"); |
|
} |
|
|
|
AddSystemIncludeDirs($"{headersPath}/usr/include/{triple}"); |
|
} |
|
|
|
AddSystemIncludeDirs($"{headersPath}/usr/include"); |
|
AddSystemIncludeDirs($"{headersPath}/usr/include/linux"); |
|
} |
|
|
|
public void Setup() |
|
{ |
|
SetupArguments(); |
|
|
|
if (!NoBuiltinIncludes) |
|
SetupIncludes(); |
|
} |
|
|
|
private void SetupArguments() |
|
{ |
|
// do not remove the CppSharp prefix becase the Mono C# compiler breaks |
|
if (!LanguageVersion.HasValue) |
|
LanguageVersion = CppSharp.Parser.LanguageVersion.CPP14_GNU; |
|
|
|
switch (LanguageVersion) |
|
{ |
|
case CppSharp.Parser.LanguageVersion.C99: |
|
case CppSharp.Parser.LanguageVersion.C99_GNU: |
|
AddArguments("-xc"); |
|
break; |
|
default: |
|
AddArguments("-xc++"); |
|
break; |
|
} |
|
|
|
switch (LanguageVersion) |
|
{ |
|
case CppSharp.Parser.LanguageVersion.C99: |
|
AddArguments("-std=c99"); |
|
break; |
|
case CppSharp.Parser.LanguageVersion.C99_GNU: |
|
AddArguments("-std=gnu99"); |
|
break; |
|
case CppSharp.Parser.LanguageVersion.CPP98: |
|
AddArguments("-std=c++98"); |
|
break; |
|
case CppSharp.Parser.LanguageVersion.CPP98_GNU: |
|
AddArguments("-std=gnu++98"); |
|
break; |
|
case CppSharp.Parser.LanguageVersion.CPP11: |
|
AddArguments("-std=c++11"); |
|
break; |
|
case CppSharp.Parser.LanguageVersion.CPP11_GNU: |
|
AddArguments("-std=gnu++11"); |
|
break; |
|
case CppSharp.Parser.LanguageVersion.CPP14: |
|
AddArguments("-std=c++14"); |
|
break; |
|
case CppSharp.Parser.LanguageVersion.CPP14_GNU: |
|
AddArguments("-std=gnu++14"); |
|
break; |
|
case CppSharp.Parser.LanguageVersion.CPP17: |
|
AddArguments("-std=c++1z"); |
|
break; |
|
case CppSharp.Parser.LanguageVersion.CPP17_GNU: |
|
AddArguments("-std=gnu++1z"); |
|
break; |
|
} |
|
|
|
if (!EnableRTTI) |
|
AddArguments("-fno-rtti"); |
|
} |
|
|
|
public string BuiltinsDir |
|
{ |
|
get |
|
{ |
|
var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); |
|
var builtinsDir = Path.Combine(assemblyDir, "lib", "clang", ClangVersion, "include"); |
|
return builtinsDir; |
|
} |
|
} |
|
|
|
private void SetupIncludes() |
|
{ |
|
// Check that the builtin includes folder exists. |
|
if (!Directory.Exists(BuiltinsDir)) |
|
throw new Exception($"Clang resource folder 'lib/clang/{ClangVersion}/include' was not found."); |
|
|
|
switch (Platform.Host) |
|
{ |
|
case TargetPlatform.Windows: |
|
SetupMSVC(); |
|
break; |
|
case TargetPlatform.MacOS: |
|
SetupXcode(); |
|
break; |
|
case TargetPlatform.Linux: |
|
SetupLinux(); |
|
break; |
|
} |
|
} |
|
} |
|
}
|
|
|