C#和C/C++混合编程系列3-绑定自动生成代码
在C++导出native code绑定到C#时,大量代码是可以进行自动生成的。
这里 生成工具是利用C#和反射RTTI信息来生成。通过一些标签来告知生成器。
需要吧自动生成的cs代码的 InternalCall 进行打标签。
自动生成的cpp文件。
BuildTool.cs
/* * Author: caoshanshan * Email: me@dreamyouxi.com */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace StickEngine.Build { [System.AttributeUsage(AttributeTargets.All)] public class NativeClassAttribute : System.Attribute { public string class_name; public NativeClassAttribute(string class_name) { this.class_name = class_name; } } [System.AttributeUsage(AttributeTargets.All)] public class NativePropertiesAttribute : System.Attribute { public enum MethodType { getter_setter = 0, } public string cpp_set_method_name; public string cpp_get_method_name; public int gen_type = (int)MethodType.getter_setter; public NativePropertiesAttribute(int gen_type, string cpp_set_method_name, string cpp_get_method_name) { this.gen_type = gen_type; this.cpp_set_method_name = cpp_set_method_name; this.cpp_get_method_name = cpp_get_method_name; } } //自动生成 绑定脚本 public static class BindingsFileAutoGenerator { } public static class BuildEntry { public static string GetTypeCode(Type cls, PropertyInfo pro, NativePropertiesAttribute attr, ref string _add_call) { // Debug.Log(pro.GetGetMethod().Name); //getter if (pro.GetGetMethod().Name.IndexOf("get_") >= 0) { string return_type_name = "Vector3f"; var returntype = pro.GetGetMethod().ReturnType; if (returntype == typeof(Vector3)) { return_type_name = "Vector3f"; } else if (returntype == typeof(Quaternion)) { return_type_name = "Quaternionf"; } var text_get = @" inline void NATIVE_CLASS_NAME_internal_IMPL_METHOD_NAME(MonoObject* _this, RETURN_TYPE_NAME *ptr) { auto * obj = NativePtrCast<NATIVE_CLASS_NAME>(_this); if (obj) { *ptr = obj->NATIVE_CPP_METHOD(); } } "; text_get = text_get.Replace("NATIVE_CPP_METHOD", attr.cpp_get_method_name); text_get = text_get.Replace("NATIVE_CLASS_NAME", cls.Name); text_get = text_get.Replace("IMPL_METHOD_NAME", pro.GetGetMethod().Name); text_get = text_get.Replace("RETURN_TYPE_NAME", return_type_name); var text_set = @" inline void NATIVE_CLASS_NAME_internal_IMPL_METHOD_NAME(MonoObject* _this, RETURN_TYPE_NAME *ptr) { auto * obj = NativePtrCast<NATIVE_CLASS_NAME>(_this); if (obj) { obj->NATIVE_CPP_METHOD(*ptr); } } "; text_set = text_set.Replace("NATIVE_CPP_METHOD", attr.cpp_set_method_name); text_set = text_set.Replace("NATIVE_CLASS_NAME", cls.Name); text_set = text_set.Replace("IMPL_METHOD_NAME", pro.GetGetMethod().Name.Replace("get_", "set_")); text_set = text_set.Replace("RETURN_TYPE_NAME", return_type_name); // mono_add_internal_call("StickEngine.Transform::internal_get_position", &internal_get_position); _add_call = string.Format(" mono_add_internal_call(\"{0}:internal_{1}\", &{2}_internal_{1});", cls.FullName, pro.GetGetMethod().Name, cls.Name); _add_call += "\n"; _add_call += string.Format(" mono_add_internal_call(\"{0}::internal_{1}\", &{2}_internal_{1});\n", cls.FullName, pro.GetGetMethod().Name.Replace("get_", "set_"), cls.Name); // Debug.Log(_add_call); return text_get + text_set; } return ""; } public static void Gen() { System.Console.WriteLine("StickEngine.BuildTool gen bindings files BEGIN"); var assembly = StickEngine.CppEntry.CurrentAssembly; StringBuilder output = new StringBuilder(); { output.Append("#include\"auto_gen_bindings.h\"\n"); output.Append("//this file was auto generate by BuildTool.cs do not modify\n"); output.Append("//this file manual."); } string code_2 = "";//mono_add_xxxx foreach (var cls in assembly.GetTypes()) { if (cls.IsDefined(typeof(NativeClassAttribute), false)) { NativeClassAttribute cls_attr = null; foreach (var p in cls.GetCustomAttributes(false)) { if (p.GetType() == typeof(NativeClassAttribute)) { cls_attr = (NativeClassAttribute)p; break; } } if (cls_attr == null) continue; Debug.Log("#Scanning:" + cls); string code_1 = "";//function foreach (var pro in cls.GetProperties()) { { NativePropertiesAttribute method_attr = null; foreach (var p in pro.GetCustomAttributes(false)) { if (p.GetType() == typeof(NativePropertiesAttribute)) { method_attr = (NativePropertiesAttribute)p; break; } } if (method_attr == null) continue; if (method_attr.gen_type == (int)NativePropertiesAttribute.MethodType.getter_setter) { string oil = ""; code_1 += GetTypeCode(cls, pro, method_attr, ref oil); code_2 += oil; } } } output.Append(code_1); } } { output.Append("\n\nvoid AutoGenBindings::Bind()\n"); output.Append("{\n"); output.Append(code_2); output.Append("}\n"); } File.WriteAllText("../src/stick_engine/mono/auto_gen_bindings.cpp", output.ToString(), Encoding.UTF8); System.Console.WriteLine("StickEngine.BuildTool gen bindings files DONE"); System.Console.ReadKey(); } } }