Beispiel #1
0
        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 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.");
        }
Beispiel #3
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.");
        }
Beispiel #4
0
        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());
        }