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();
}
}
}