static void Main(string[] args) { var headerFile = Path.Combine(AppContext.BaseDirectory, "Headers", "renderdoc_app.h"); var options = new CppParserOptions { ParseMacros = true, Defines = { "_WIN32", } }; var compilation = CppParser.ParseFile(headerFile, options); // Print diagnostic messages if (compilation.HasErrors) { foreach (var message in compilation.Diagnostics.Messages) { Debug.WriteLine(message); } } else { string outputPath = "..\\..\\..\\..\\WaveEngine.Bindings.RenderDoc\\Generated"; CsCodeGenerator.Instance.Generate(compilation, outputPath); } }
static void Main(string[] args) { var flavors = new string[] { "Dawn", "Browser" }; foreach (var flavor in flavors) { var headerFile = Path.Combine(AppContext.BaseDirectory, "Headers", flavor, "webgpu.h"); var options = new CppParserOptions { ParseMacros = true, Defines = { "WGPU_SHARED_LIBRARY", "_WIN32", "WGPU_SKIP_PROCS" } }; var compilation = CppParser.ParseFile(headerFile, options); // Print diagnostic messages if (compilation.HasErrors) { foreach (var message in compilation.Diagnostics.Messages) { Debug.WriteLine(message); } } else { string basePath = "..\\..\\..\\..\\WaveEngine.Bindings.WebGPU"; CsCodeGenerator.Instance.Generate(compilation, basePath, flavor); } } }
private void ParseSkiaHeaders() { Log?.LogVerbose("Parsing skia headers..."); var options = new CppParserOptions(); foreach (var header in config.IncludeDirs) { var path = Path.Combine(SkiaRoot, header); options.IncludeFolders.Add(path); } var headers = new List <string>(); foreach (var header in config.Headers) { var path = Path.Combine(SkiaRoot, header.Key); options.IncludeFolders.Add(path); foreach (var filter in header.Value) { headers.AddRange(Directory.EnumerateFiles(path, filter)); } } compilation = CppParser.ParseFiles(headers, options); if (compilation == null || compilation.HasErrors) { Log?.LogError("Parsing headers failed."); throw new Exception("Parsing headers failed."); } }
private static CppCompilation Compile(GenerateConfig config, string directory) { Environment.CurrentDirectory = directory; Regex[] sourcePatterns = config.CompileConfig.Sources .Select(StringExtension.MakeWildcardPattern) .ToArray(); Regex[] sourceExcludePatterns = config.CompileConfig.SourceExcludes .Select(StringExtension.MakeWildcardPattern) .ToArray(); List <string> sources = Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories) .Select(f => Path.GetRelativePath(directory, f).Replace("\\", "/")) .Where(f => { if (!sourcePatterns.Any(p => p.IsMatch(f))) { return(false); } if (sourceExcludePatterns.Any(p => p.IsMatch(f))) { return(false); } return(true); }) .ToList(); var parserOptions = new CppParserOptions { ParseAsCpp = true, ParseMacros = true, ParseAttributes = true, ParseSystemIncludes = true, AdditionalArguments = { "--target=x86_64-apple-darwin19.5.0", "-Wall", "-Wno-unused-function", "-Wno-unused-value", "-Wno-unused-variable", "-fno-strict-aliasing", "-fwrapv", "-fPIC", "-Wno-nullability-completeness" } }; parserOptions.IncludeFolders.AddRange(GetGnuIncludes()); parserOptions.IncludeFolders.Add("./"); parserOptions.IncludeFolders.AddRange(config.CompileConfig.IncludeFolders); return(CppParser.ParseFiles(sources, parserOptions)); }
private static CppCompilation Parse(string vlcDir) { var parserOptions = new CppParserOptions { ParseComments = NoComment }; parserOptions.IncludeFolders.Add(Path.Combine(vlcDir, include)); return(CppParser.ParseFile(BuildPath(vlcDir, vlch), parserOptions)); }
public CppParserOptions ToParserOptions() { Validate(); AddSystemIncludes(); var opts = new CppParserOptions(); opts.Defines.AddRange(Defines); opts.IncludeFolders.AddRange(ToAbsolutePaths(IncludeFolders)); opts.SystemIncludeFolders.AddRange(SystemIncludeFolders); opts.AdditionalArguments.AddRange(AdditionalArguments); opts.AutoSquashTypedef = AutoSquashTypedef; opts.TargetSystem = TargetSystem; opts.ParseComments = ParseComments; return(opts); }
static CppCompilation Do(String file, ClConfig cfg) { var options = new CppParserOptions() { // Pass the defines -DMYDEFINE to the C++ parser Defines = { }, IncludeFolders = { }, TargetCpu = CppTargetCpu.X86_64, }; options.ParseSystemIncludes = false; options.ParseComments = false; options.AdditionalArguments.Add("-fno-complete-member-pointers"); options.AdditionalArguments.Add("/TC"); options.AdditionalArguments.Add("-std c99"); options.AdditionalArguments.Add("/c"); options.AdditionalArguments.Add("-fms-extensions"); options.AdditionalArguments.Add("-fms-compatibility"); options.AdditionalArguments.Add(" -fms-compatibility-version=19"); options.ParseAsCpp = false; options.EnableFunctionBodies(); foreach (KeyValuePair <string, string> kv in cfg.define) { String d = kv.Value == null ? (kv.Key) : (kv.Key + "=" + kv.Value); options.Defines.Add(d); } options.Defines.Add("CPP_AST_FIXED"); foreach (String include in cfg.include) { options.IncludeFolders.Add(include); } options.ConfigureForWindowsMsvc(); var compilation = CppParser.ParseFile(file, options); return(compilation); }
public void Process(string[] args) { var input_file = "test.cpp"; var input_text = File.ReadAllText(input_file, encoding: Encoding.UTF8); var options = new CppParserOptions(); //options.ParseAttributes = true; var compilation = CppParser.Parse(input_text, options); Context.Instance = new Context(); foreach (var cpp_class in compilation.Classes) { HandleClass(cpp_class); } }
static void Main(string[] args) { var headerFile = Path.Combine(AppContext.BaseDirectory, "ImGUI", "cimgui.h"); var options = new CppParserOptions { ParseMacros = true, Defines = { "CIMGUI_DEFINE_ENUMS_AND_STRUCTS" } }; var compilation = CppParser.ParseFile(headerFile, options); if (compilation.HasErrors) { foreach (var message in compilation.Diagnostics.Messages) { Console.WriteLine(message); } } CsCodeGenerator.Generate(compilation, "../../../../src/SharpImGUI/Generated/"); }
public static void Main(string[] args) { // In this sample we are going to bind a few C++ classes from https://github.com/lemire/simdjson // the library has "singleheader" file so we don't have to collect all needed files + includes // see https://github.com/lemire/simdjson/tree/master/singleheader string outputFolder = "../../../Output/"; if (!Directory.Exists(outputFolder)) { Directory.CreateDirectory(outputFolder); } Console.WriteLine("Downloading simdjson sources..."); HttpClient httpClient = new HttpClient(); string simdJsonSingleHeader = httpClient.GetStringAsync("https://raw.githubusercontent.com/lemire/simdjson/master/singleheader/simdjson.h").Result; File.WriteAllText(Path.Combine(outputFolder, @"simdjson.h"), simdJsonSingleHeader); Console.WriteLine("Downloaded! Parsing..."); var options = new CppParserOptions(); // TODO: test on macOS options.ConfigureForWindowsMsvc(CppTargetCpu.X86_64); options.AdditionalArguments.Add("-std=c++17"); CppCompilation compilation = CppParser.ParseFile(Path.Combine(outputFolder, @"simdjson.h"), options); if (compilation.DumpErrorsIfAny()) { Console.ReadKey(); return; } var mapper = new TypeMapper(compilation); // Register native types we don't want to bind (or any method with them in parameters) mapper.RegisterUnsupportedTypes( "simdjson", // it's empty - we don't need it "basic_string", // TODO: "basic_string_view", // TODO "basic_ostream"); // TODO: var templateManager = new TemplateManager(); // Add additional stuff we want to see in the bindings.c templateManager .AddToCHeader(@"#include ""simdjson.h""") .SetGlobalFunctionsClassName("GlobalFunctions"); PinvokeGenerator.Generate(mapper, templateManager, @namespace: "MyNamespace", dllImportPath: @"""simdjson.dll""", outCFile: Path.Combine(outputFolder, "Bindings.c"), outCsFile: Path.Combine(outputFolder, "Bindings.cs")); Console.WriteLine("Done. See Output folder."); }
private CppParserOptions(CppParserOptions.__Internal native, bool skipVTables = false) : this(__CopyValue(native), skipVTables) { __ownsNativeInstance = true; NativeToManagedMap[__Instance] = this; }
private static void* __CopyValue(CppParserOptions.__Internal native) { var ret = Marshal.AllocHGlobal(156); global::CppSharp.Parser.CppParserOptions.__Internal.cctor_2(ret, new global::System.IntPtr(&native)); return ret.ToPointer(); }
public static CppParserOptions __CreateInstance(CppParserOptions.__Internal native, bool skipVTables = false) { return new CppParserOptions(native, skipVTables); }
private static void GenerateFromCHeaders(string basePath, string outDirPath, bool onlyStdCall) { var options = new CppParserOptions(); var files = new List <string>(Directory.GetFiles(Path.Combine(basePath, "include", "capi"), "*.h")); files.Add(Path.Combine(basePath, "include", "cef_version.h")); files.Add(Path.Combine(basePath, "include", "cef_api_hash.h")); options.IncludeFolders.Add(ApplyHotPatch(basePath)); options.IncludeFolders.Add(basePath); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { options.IncludeFolders.Add("/usr/include/clang/8/include"); options.TargetAbi = "gnu"; options.TargetCpu = CppTargetCpu.X86_64; options.TargetSystem = "linux"; options.TargetVendor = "pc"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { options.Defines.Add("_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH"); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { //options.TargetCpu = CppTargetCpu.X86_64; options.TargetSystem = "darwin"; options.TargetVendor = "apple"; options.SystemIncludeFolders.Add("/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include"); options.SystemIncludeFolders.Add("/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1"); options.SystemIncludeFolders.Add("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include"); options.SystemIncludeFolders.Add("/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/11.0.0/include"); options.AdditionalArguments.Add("-stdlib=libc++"); } var nativeBuild = new NativeCefApiBuilder(onlyStdCall) { Namespace = "CefNet.CApi", BaseDirectory = basePath }; var enumBuild = new NativeCefApiBuilder(onlyStdCall) { Namespace = "CefNet", BaseDirectory = basePath }; CppCompilation compilation = CppParser.ParseFiles(files, options); if (compilation.HasErrors) { foreach (var msg in compilation.Diagnostics.Messages) { Console.WriteLine(msg); } Environment.Exit(-1); return; } var aliasResolver = new AliasResolver(compilation); nativeBuild.ResolveCefTypeDef += aliasResolver.HandleResolveEvent; enumBuild.ResolveCefTypeDef += aliasResolver.HandleResolveEvent; Func <string, string> resolveType = aliasResolver.ResolveNonFail; foreach (CppClass @class in compilation.Classes) { string source = @class.Span.Start.File; if (!source.Contains("capi") && !source.Contains("internal")) { continue; } if (IgnoreClasses.Contains(@class.Name)) { continue; } string fileName = aliasResolver.ResolveNonFail(@class.Name); using (var csfile = new StreamWriter(Path.Combine(outDirPath, "Native", "Types", fileName + ".cs"), false, Encoding.UTF8)) using (var ilfile = new StreamWriter(Path.Combine(outDirPath, "Native", "MSIL", fileName + ".il"), false, Encoding.UTF8)) { nativeBuild.Format(@class, csfile, ilfile); csfile.Flush(); ilfile.Flush(); } } foreach (CppTypedef typedef in compilation.Typedefs) { string name = typedef.Name; if (name.StartsWith("cef_string_") || name == "cef_color_t" //|| name == "cef_platform_thread_id_t" || name == "cef_platform_thread_handle_t") { var sb = new StringBuilder(); try { var w = new StringWriter(sb); nativeBuild.Format(typedef, w); w.Flush(); w.Dispose(); } catch (InvalidOperationException) { continue; } string fileName = aliasResolver.ResolveNonFail(typedef.Name); File.WriteAllText(Path.Combine(outDirPath, "Native", "Typedefs", fileName + ".cs"), sb.ToString(), Encoding.UTF8); } } foreach (CppEnum @enum in compilation.Enums) { string fileName = aliasResolver.ResolveNonFail(@enum.Name); using (var csfile = new StreamWriter(Path.Combine(outDirPath, "Managed", "Enums", fileName + ".cs"), false, Encoding.UTF8)) { enumBuild.Format(@enum, csfile); csfile.Flush(); } } var api = new CefApiClass("CefNativeApi") { Functions = compilation.Functions, ApiHash = GetApiHash(basePath) }; using (var csfile = new StreamWriter(Path.Combine(outDirPath, "Native", "CefNativeApi.cs"), false, Encoding.UTF8)) { nativeBuild.Format(api, csfile); csfile.Flush(); } }
public static int Main(string[] args) { string outputPath = AppContext.BaseDirectory; if (args.Length > 0) { outputPath = args[0]; } if (!Path.IsPathRooted(outputPath)) { outputPath = Path.Combine(AppContext.BaseDirectory, outputPath); } if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } string?headerFile = Path.Combine(AppContext.BaseDirectory, "vulkan", "vulkan.h"); var options = new CppParserOptions { ParseMacros = true, Defines = { "VK_USE_PLATFORM_ANDROID_KHR", "VK_USE_PLATFORM_IOS_MVK", "VK_USE_PLATFORM_MACOS_MVK", "VK_USE_PLATFORM_METAL_EXT", "VK_USE_PLATFORM_VI_NN", //"VK_USE_PLATFORM_WAYLAND_KHR", //"VK_USE_PLATFORM_WIN32_KHR", //"VK_USE_PLATFORM_SCREEN_QNX", "VK_ENABLE_BETA_EXTENSIONS" } }; var compilation = CppParser.ParseFile(headerFile, options); // Print diagnostic messages if (compilation.HasErrors) { foreach (var message in compilation.Diagnostics.Messages) { if (message.Type == CppLogMessageType.Error) { var currentColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(message); Console.ForegroundColor = currentColor; } } return(0); } bool generateFuncFile = false; if (generateFuncFile) { File.Delete("Vk.txt"); foreach (var func in compilation.Functions) { var signature = new System.Text.StringBuilder(); var argSignature = CsCodeGenerator.GetParameterSignature(func, true); signature .Append(func.ReturnType.GetDisplayName()) .Append(" ") .Append(func.Name) .Append("(") .Append(argSignature) .Append(")"); File.AppendAllText("Vk.txt", signature.ToString() + Environment.NewLine); } } CsCodeGenerator.Generate(compilation, outputPath); return(0); }
public static void Main(string[] args) { // input (single header) string headerPath = Path.Combine(Environment.CurrentDirectory, "../../src/BindingsForNativeLib/SimdJsonNative/simdjson.h"); // output string cgluePath = Path.Combine(Environment.CurrentDirectory, "../../src/BindingsForNativeLib/SimdJsonNative/bindings.cpp"); string bindingsPath = Path.Combine(Environment.CurrentDirectory, "../../src/BindingsForNativeLib/SimdJsonSharp.Bindings/Bindings.Generated.cs"); var options = new CppParserOptions(); // TODO: test on macOS options.ConfigureForWindowsMsvc(CppTargetCpu.X86_64); options.AdditionalArguments.Add("-std=c++17"); CppCompilation compilation = CppParser.ParseFile(headerPath, options); if (compilation.DumpErrorsIfAny()) { Console.ReadKey(); return; } var mapper = new TypeMapper(compilation); mapper.RenamingForApi += (nativeName, isMethod) => { if (nativeName == "iterator") { return("ParsedJsonIteratorN"); } if (!isMethod) { return(nativeName + "N"); // SimdJsonSharp has two C# APIs: 1) managed 2) bindings - postfixed with 'N' } if (nativeName == "get_type") { return("GetTokenType"); } if (nativeName == "get_string") { return("GetUtf8String"); } return(nativeName); }; // init_state_machine requires external linkage (impl) mapper.RegisterUnsupportedMethod(null, "init_state_machine"); // Register native types we don't want to bind (or any method with them in parameters) mapper.RegisterUnsupportedTypes( "simdjson", // it's empty - we don't need it "__m128i", "simd_input", "utf8_checking_state", "basic_string", // TODO: "basic_string_view", // TODO "basic_ostream"); // TODO: var templateManager = new TemplateManager(); // Add additional stuff we want to see in the bindings.c templateManager .AddToCHeader(@"#include ""simdjson.h""") .AddToCHeader(@"using namespace simdjson;") .SetGlobalFunctionsClassName("SimdJsonN"); PinvokeGenerator.Generate(mapper, templateManager, @namespace: "SimdJsonSharp", dllImportPath: @"SimdJsonN.NativeLib", outCFile: cgluePath, outCsFile: bindingsPath); Console.WriteLine("Done."); }
public void ParseAssert(string text, Action <CppCompilation> assertCompilation, CppParserOptions options = null, bool asFile = true) { if (assertCompilation == null) { throw new ArgumentNullException(nameof(assertCompilation)); } options = options ?? new CppParserOptions(); var currentDirectory = Environment.CurrentDirectory; var headerFilename = $"{TestContext.CurrentContext.Test.FullName}-{TestContext.CurrentContext.Test.ID}.h"; var headerFile = Path.Combine(currentDirectory, headerFilename); // Parse in memory var compilation = CppParser.Parse(text, options, headerFilename); foreach (var diagnosticsMessage in compilation.Diagnostics.Messages) { Console.WriteLine(diagnosticsMessage); } assertCompilation(compilation); if (asFile) { // Parse single file from disk File.WriteAllText(headerFile, text); compilation = CppParser.ParseFile(headerFile, options); assertCompilation(compilation); } }
public static DNA Create( List <string> include, List <string> exclude, bool includeByRef, List <string> headers, string dnaVersion, bool verbose ) { var options = new CppParserOptions(); // options.ParseAsCpp = false; var compilation = CppParser.ParseFiles(headers, options); foreach (var message in compilation.Diagnostics.Messages) { if (message.Type == CppLogMessageType.Error || verbose) { Console.Error.WriteLine(message); } } var dna = new DNA { Version = dnaVersion, Entities = new Dictionary <string, Entity>() }; // TODO: Support enums somehow - e.g. CustomDataType that can change between DNA versions // https://github.com/sobotka/blender/blob/master/source/blender/makesdna/DNA_customdata_types.h#L90 foreach (var cenum in compilation.Enums) { //Console.WriteLine(cenum); } // Print all structs with all fields foreach (var cstruct in compilation.Classes) { var name = cstruct.Name; // Skip non structs if (cstruct.ClassKind != CppClassKind.Struct) { if (include != null && include.Contains(name)) { throw new Exception( $"Required include [{name}] is not a supported type. Found [{cstruct.ClassKind}]." ); } continue; } // If it's on the include list OR we don't have one and it's not in the exclusions, add. if ((include != null && include.Contains(name)) || (include == null && exclude != null && !exclude.Contains(name)) || (include == null && exclude == null) ) { AddEntity(dna, cstruct, includeByRef); } } // Check - make sure all entities in the include list were found. if (include != null) { var missing = new List <string>(); foreach (var name in include) { if (!dna.Entities.ContainsKey(name)) { missing.Add(name); } } if (missing.Count > 0) { throw new Exception("Could not load required names: " + string.Join(", ", missing)); } } return(dna); }
private async Task <int> OnExecuteAsync(CommandLineApplication app, CancellationToken cancellationToken = default) { var outputDir = Path.IsPathFullyQualified(OutputProjectDir) ? OutputProjectDir : Path.GetFullPath(OutputProjectDir); Directory.CreateDirectory(outputDir); var workspace = new AdhocWorkspace(); var projectId = ProjectId.CreateNewId(); var projectInfo = ProjectInfo.Create(projectId, VersionStamp.Create(), "XP.SDK", "XP.SDK", LanguageNames.CSharp) .WithDefaultNamespace("XP.SDK"); var project = workspace.AddProject(projectInfo); var typeMap = new TypeMap(BuildTypeCallback); _enumBuilder = new EnumBuilder(workspace, projectId, outputDir, typeMap) .Map("xpMainWindowStyle_MainWindow", "MainWindowType") .Map("xpProperty_MainWindowType", "MainWindowProperty") .Map("xpMessage_CloseButtonPushed", "MainWindowMessage") .Map("xpSubWindowStyle_SubWindow", "SubWindowType") .Map("xpProperty_SubWindowType", "SubWindowProperty") .Map("xpPushButton", "ButtonType") .Map("xpButtonBehaviorPushButton", "ButtonBehavior") .Map("xpProperty_ButtonType", "ButtonProperty") .Map("xpMsg_PushButtonPressed", "ButtonMessage") .Map("xpTextEntryField", "TextFieldType") .Map("xpProperty_EditFieldSelStart", "TextFieldProperty") .Map("xpMsg_TextFieldChanged", "TextFieldMessage") .Map("xpScrollBarTypeScrollBar", "ScrollBarType") .Map("xpProperty_ScrollBarSliderPosition", "ScrollBarProperty") .Map("xpMsg_ScrollBarSliderPositionChanged", "ScrollBarMessage") .Map("xpProperty_CaptionLit", "CaptionProperty") .Map("xpShip", "GeneralGraphicsType") .Map("xpProperty_GeneralGraphicsType", "GeneralGraphicsProperty") .Map("xpProperty_ProgressPosition", "ProgressBarProperty"); _handleBuilder = new HandleBuilder(workspace, projectId, outputDir, typeMap); _delegateBuilder = new DelegateBuilder(workspace, projectId, outputDir, typeMap); _structBuilder = new StructBuilder(workspace, projectId, outputDir, typeMap); var functionBuilder = new FunctionBuilder(workspace, projectId, outputDir, typeMap); var xplmHeadersPath = Path.Combine(SdkRoot, "CHeaders", "XPLM"); if (!Directory.Exists(xplmHeadersPath)) { throw new DirectoryNotFoundException($"Directory '{xplmHeadersPath}' does not exist."); } var xmplHeaders = Directory.EnumerateFiles(xplmHeadersPath, "*.h"); var xpWidgetsHeadersPath = Path.Combine(SdkRoot, "CHeaders", "Widgets"); if (!Directory.Exists(xpWidgetsHeadersPath)) { throw new DirectoryNotFoundException($"Directory '{xpWidgetsHeadersPath}' does not exist."); } var xpWidgetsHeaders = Directory.EnumerateFiles(xpWidgetsHeadersPath, "*.h"); var headers = xmplHeaders.Concat(xpWidgetsHeaders) /*.Where(x => Path.GetFileName(x) != "XPStandardWidgets.h")*/; var parserOptions = new CppParserOptions { Defines = { "IBM", "XPLM303", "XPLM302", "XPLM301", "XPLM300", "XPLM210", "XPLM200" }, ParseSystemIncludes = false, TargetCpu = CppTargetCpu.X86_64, IncludeFolders = { xplmHeadersPath }, }; var compilation = CppParser.ParseFiles(headers.ToList(), parserOptions); foreach (var child in compilation.Children().OfType <CppType>()) { await BuildTypeAsync(child); } var functionsByHeader = compilation .Functions .ToLookup(x => x.Span.Start.File); foreach (var functionsInHeader in functionsByHeader) { await functionBuilder.BuildAsync(functionsInHeader); } foreach (var document in workspace.CurrentSolution.Projects.SelectMany(p => p.Documents)) { var text = await document.GetTextAsync(cancellationToken); await using var writer = new StreamWriter(document.FilePath, false); text.Write(writer, cancellationToken); } return(0); async Task BuildTypeCallback(dynamic item) { using (Log.PushIdent()) { await BuildTypeAsync(item); } } }
public static unsafe void Main(string[] args) { // input (single header) string headerPath = Path.Combine(Environment.CurrentDirectory, "../../src/BindingsForNativeLib/SimdJsonNative/simdjson.h"); // output string cgluePath = Path.Combine(Environment.CurrentDirectory, "../../src/BindingsForNativeLib/SimdJsonNative/bindings.cpp"); string bindingsPath = Path.Combine(Environment.CurrentDirectory, "../../src/BindingsForNativeLib/SimdJsonSharp.Bindings/Bindings.Generated.cs"); var options = new CppParserOptions(); options.ConfigureForWindowsMsvc(CppTargetCpu.X86_64); options.EnableMacros(); options.AdditionalArguments.Add("-std=c++17"); // TODO: test on macOS CppCompilation compilation = CppParser.ParseFile(headerPath, options); var csSb = new StringBuilder(); csSb.AppendLine("// THIS FILE IS AUTOGENERATED!"); csSb.AppendLine(); csSb.AppendLine("using System;"); csSb.AppendLine("using System.Runtime.InteropServices;"); csSb.AppendLine(); csSb.Append($"namespace {Namespace}\n{{"); // Since we bind C++ we need to generate a DllImport-friendly C glue var cSb = new StringBuilder(); cSb.AppendLine("// THIS FILE IS AUTOGENERATED!"); cSb.AppendLine("#include \"simdjson.h\""); cSb.AppendLine(); cSb.AppendLine("#if (defined WIN32 || defined _WIN32)"); cSb.AppendLine("#define EXPORTS(returntype) extern \"C\" __declspec(dllexport) returntype __cdecl"); cSb.AppendLine("#else"); cSb.AppendLine("#define EXPORTS(returntype) extern \"C\" __attribute__((visibility(\"default\"))) returntype"); cSb.AppendLine("#endif"); List <CppClass> allClasses = compilation.GetAllClassesRecursively(); _allClassNames = allClasses.Select(c => c.GetDisplayName()).ToList(); foreach (CppClass cppClass in allClasses) { var csApiMethodsSb = new StringBuilder(); var csDllImportsSb = new StringBuilder(); string className = cppClass.Name; if (cppClass.Parent is CppClass parentClass) { className = $"{parentClass.Name}::{className}"; } if (_typesToIgnore.Contains(className)) { continue; } // prefix for all members string prefix = cppClass.Name + "_"; cSb.AppendLine(); cSb.AppendLine($"/* {className} */"); IEnumerable <CppFunction> allFunctions = cppClass.Constructors.Take(1 /* HACK: take only first available ctors for now :) */).Concat(cppClass.Functions); foreach (CppFunction cppFunc in allFunctions) { var argDefinitions = new List <string>(); var argInvocations = new List <string>(); // skip operators for now if (cppFunc.IsOperator()) { continue; } bool isStatic = cppFunc.StorageQualifier == CppStorageQualifier.Static; string funcPrefix = prefix; // Class_function() if (isStatic) { funcPrefix += "s_"; // Class_s_staticFunction() } if (!cppFunc.IsConstructor && !isStatic) { argDefinitions.Add($"{className}* target"); } foreach (CppParameter cppParam in cppFunc.Parameters) { var type = cppParam.Type.GetDisplayName(); // method contains a parameter of type we don't support - skip the whole method (goto) if (_typesToIgnore.Any(t => type.Contains(t))) { goto SKIP_FUNC; } string invocation = cppParam.Name; // HACK: replace references with pointers (for classes) if (type.EndsWith("&")) { type = type.Remove(type.Length - 1) + "*"; invocation = "*" + invocation; } argDefinitions.Add($"{type} {cppParam.Name}"); argInvocations.Add(invocation); } string funcReturnType = cppFunc.IsConstructor ? $"{className}*" : cppFunc.ReturnType.GetDisplayName(); string finalFuncName = $"{funcPrefix}{cppFunc.Name}"; // Func declaration cSb.Append($"EXPORTS({funcReturnType}) {finalFuncName}({argDefinitions.AsCommaSeparatedStr()})"); cSb.Append(" {"); // Body if (cppFunc.IsConstructor) { cSb.Append($" return new {className}({argInvocations.AsCommaSeparatedStr()});"); } else { string returnStr = cppFunc.ReturnType.IsVoid() ? " " : " return "; string invokeTarget = "target->"; if (isStatic) { invokeTarget = className + "::"; } cSb.Append($"{returnStr}{invokeTarget}{cppFunc.Name}({argInvocations.AsCommaSeparatedStr()});"); } cSb.Append(" }"); cSb.AppendLine(); var(dllImports, apiMethods) = GenerateMethodCSharp(cppFunc, finalFuncName); csDllImportsSb.AppendLine(dllImports); csApiMethodsSb.AppendLine(apiMethods); SKIP_FUNC: continue; } // destructor cSb.Append($"EXPORTS(void) {prefix}Dispose({className}* target) {{ delete target; }}"); cSb.AppendLine(); // generate C# for this method: csSb.AppendLine(GenerateClassCSharp(cppClass, csDllImportsSb.ToString(), csApiMethodsSb.ToString())); } csSb.Append("}"); // end of namespace File.WriteAllText(cgluePath, cSb.ToString()); File.WriteAllText(bindingsPath, csSb.ToString()); }
public void TestBodySimple() { var opt = new CppParserOptions().EnableFunctionBodies(); opt.ParseSystemIncludes = false; ParseAssert(@" void function0(); int function1(int a, float b); float function2(int); int function3(int args_a, bool args_b){ int local_b = 1234; float b = function2(args_a); local_b = function1(local_b, b); return local_b; } ", compilation => { Assert.False(compilation.HasErrors); Assert.AreEqual(4, compilation.Functions.Count); { var cppFunction = compilation.Functions[0]; Assert.AreEqual("function0", cppFunction.Name); Assert.AreEqual(0, cppFunction.Parameters.Count); Assert.AreEqual("void", cppFunction.ReturnType.ToString()); var cppFunction1 = compilation.FindByName <CppFunction>("function0"); Assert.AreEqual(cppFunction, cppFunction1); } { var cppFunction = compilation.Functions[1]; Assert.AreEqual("function1", cppFunction.Name); Assert.AreEqual(2, cppFunction.Parameters.Count); Assert.AreEqual("a", cppFunction.Parameters[0].Name); Assert.AreEqual(CppTypeKind.Primitive, cppFunction.Parameters[0].Type.TypeKind); Assert.AreEqual(CppPrimitiveKind.Int, ((CppPrimitiveType)cppFunction.Parameters[0].Type).Kind); Assert.AreEqual("b", cppFunction.Parameters[1].Name); Assert.AreEqual(CppTypeKind.Primitive, cppFunction.Parameters[1].Type.TypeKind); Assert.AreEqual(CppPrimitiveKind.Float, ((CppPrimitiveType)cppFunction.Parameters[1].Type).Kind); Assert.AreEqual("int", cppFunction.ReturnType.ToString()); var cppFunction1 = compilation.FindByName <CppFunction>("function1"); Assert.AreEqual(cppFunction, cppFunction1); } { var cppFunction = compilation.Functions[2]; Assert.AreEqual("function2", cppFunction.Name); Assert.AreEqual(1, cppFunction.Parameters.Count); Assert.AreEqual(string.Empty, cppFunction.Parameters[0].Name); Assert.AreEqual(CppTypeKind.Primitive, cppFunction.Parameters[0].Type.TypeKind); Assert.AreEqual(CppPrimitiveKind.Int, ((CppPrimitiveType)cppFunction.Parameters[0].Type).Kind); Assert.AreEqual("float", cppFunction.ReturnType.ToString()); var cppFunction1 = compilation.FindByName <CppFunction>("function2"); Assert.AreEqual(cppFunction, cppFunction1); } { var cppFunction = compilation.Functions[3]; Assert.AreEqual("function3", cppFunction.Name); Assert.AreEqual(2, cppFunction.Parameters.Count); Assert.AreEqual("args_a", cppFunction.Parameters[0].Name); Assert.AreEqual(CppTypeKind.Primitive, cppFunction.Parameters[0].Type.TypeKind); Assert.AreEqual(CppPrimitiveKind.Int, ((CppPrimitiveType)cppFunction.Parameters[0].Type).Kind); Assert.AreEqual("int", cppFunction.ReturnType.ToString()); var cppFunction1 = compilation.FindByName <CppFunction>("function3"); Assert.AreEqual(cppFunction, cppFunction1); } } , opt, false); }