Generate ABI compatible structures to avoid needing glue code.
This commit is contained in:
parent
44d2af717a
commit
4d513324cd
15 changed files with 259 additions and 24 deletions
|
@ -39,6 +39,9 @@ namespace GtkSharp.Generation {
|
|||
protected IList<string> managed_interfaces = new List<string>();
|
||||
protected IList<Ctor> ctors = new List<Ctor>();
|
||||
|
||||
protected IList<StructABIField> abi_fields = new List<StructABIField> ();
|
||||
protected bool abi_fields_valid; // false if the instance structure contains a bitfield or fields of unknown types
|
||||
|
||||
private bool ctors_initted = false;
|
||||
private Dictionary<string, Ctor> clash_map;
|
||||
private bool deprecated = false;
|
||||
|
@ -71,10 +74,24 @@ namespace GtkSharp.Generation {
|
|||
|
||||
deprecated = elem.GetAttributeAsBoolean ("deprecated");
|
||||
isabstract = elem.GetAttributeAsBoolean ("abstract");
|
||||
abi_fields_valid = true;
|
||||
bool has_parent = Elem.GetAttribute("parent") != "";
|
||||
|
||||
int num_abi_fields = 0;
|
||||
foreach (XmlNode node in elem.ChildNodes) {
|
||||
if (!(node is XmlElement)) continue;
|
||||
XmlElement member = (XmlElement) node;
|
||||
StructABIField abi_field = null;
|
||||
|
||||
// Make sure ABI fields are taken into account, even when hidden.
|
||||
if (node.Name == "field") {
|
||||
num_abi_fields += 1;
|
||||
if (num_abi_fields != 1 || !has_parent) { // Skip instance parent struct
|
||||
abi_field = new StructABIField (member, this);
|
||||
abi_fields.Add (abi_field);
|
||||
}
|
||||
}
|
||||
|
||||
if (member.GetAttributeAsBoolean ("hidden"))
|
||||
continue;
|
||||
|
||||
|
@ -98,7 +115,10 @@ namespace GtkSharp.Generation {
|
|||
name = member.GetAttribute("name");
|
||||
while (fields.ContainsKey (name))
|
||||
name += "mangled";
|
||||
fields.Add (name, new ObjectField (member, this));
|
||||
|
||||
var field = new ObjectField (member, this);
|
||||
field.abi_field = abi_field;
|
||||
fields.Add (name, field);
|
||||
break;
|
||||
|
||||
case "implements":
|
||||
|
@ -120,6 +140,89 @@ namespace GtkSharp.Generation {
|
|||
}
|
||||
}
|
||||
|
||||
protected virtual bool CanGenerateABIStruct {
|
||||
get {
|
||||
return (abi_fields_valid);
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckABIStructParent(LogWriter log, out string cs_parent_struct) {
|
||||
cs_parent_struct = null;
|
||||
if (!CanGenerateABIStruct)
|
||||
return false;
|
||||
|
||||
var parent = SymbolTable.Table[Elem.GetAttribute("parent")];
|
||||
string cs_parent = SymbolTable.Table.GetCSType(Elem.GetAttribute("parent"));
|
||||
var parent_can_generate = true;
|
||||
|
||||
cs_parent_struct = null;
|
||||
if (parent != null) {
|
||||
// FIXME Add that information to ManualGen and use it.
|
||||
if (parent.CName == "GInitiallyUnowned" || parent.CName == "GObject") {
|
||||
cs_parent_struct = "GLib.Object.GObject";
|
||||
} else {
|
||||
parent_can_generate = false;
|
||||
var _parent = parent as ClassBase;
|
||||
|
||||
if (_parent != null) {
|
||||
string tmp;
|
||||
parent_can_generate = _parent.CheckABIStructParent(log, out tmp);
|
||||
}
|
||||
|
||||
if (parent_can_generate) {
|
||||
cs_parent_struct = cs_parent + "._" + parent.CName + "ABI";
|
||||
}
|
||||
}
|
||||
|
||||
if (!parent_can_generate) {
|
||||
log.Warn("Can't generate ABI structrure as the parent structure '" +
|
||||
parent.CName + "' can't be generated.");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
cs_parent_struct = "";
|
||||
}
|
||||
return parent_can_generate;
|
||||
}
|
||||
|
||||
protected virtual void WriteInstanceOffsetMethod(StreamWriter sw,
|
||||
string cs_parent_struct) {
|
||||
if (cs_parent_struct == "")
|
||||
sw.WriteLine ("\t\tpublic virtual uint instance_offset { get { return 0; }}");
|
||||
else
|
||||
sw.WriteLine ("\t\tpublic override uint instance_offset {{ get {{ return ((uint) Marshal.SizeOf(typeof ({0})) + base.instance_offset); }} }}", cs_parent_struct);
|
||||
}
|
||||
|
||||
protected void GenerateStructureABI (GenerationInfo gen_info)
|
||||
{
|
||||
string cs_parent_struct = null;
|
||||
|
||||
LogWriter log = new LogWriter (QualifiedName);
|
||||
if (!CheckABIStructParent (log, out cs_parent_struct))
|
||||
return;
|
||||
|
||||
StreamWriter sw = gen_info.Writer;
|
||||
|
||||
var _new = "";
|
||||
if (cs_parent_struct != "")
|
||||
_new = "new";
|
||||
|
||||
WriteInstanceOffsetMethod(sw, cs_parent_struct);
|
||||
sw.WriteLine ();
|
||||
sw.WriteLine ("\t\tpublic " + _new + " unsafe uint GetFieldOffset(string field) {");
|
||||
sw.WriteLine ("\t\t\treturn (uint) (instance_offset + (uint) Marshal.OffsetOf(typeof({0}), field));",
|
||||
(QualifiedName + "._" + CName + "ABI"));
|
||||
sw.WriteLine ("\t\t}");
|
||||
sw.WriteLine ();
|
||||
|
||||
sw.WriteLine ("\t\t[StructLayout (LayoutKind.Sequential)]");
|
||||
sw.WriteLine ("\t\tpublic struct _" + CName + "ABI" + " {");
|
||||
foreach (StructABIField field in abi_fields)
|
||||
field.Generate (gen_info, "\t\t\t");
|
||||
sw.WriteLine ("\t\t}");
|
||||
sw.WriteLine ();
|
||||
}
|
||||
|
||||
public override bool Validate ()
|
||||
{
|
||||
LogWriter log = new LogWriter (QualifiedName);
|
||||
|
@ -136,6 +239,11 @@ namespace GtkSharp.Generation {
|
|||
}
|
||||
}
|
||||
|
||||
foreach (StructABIField abi_field in abi_fields) {
|
||||
if (!abi_field.Validate(log))
|
||||
abi_fields_valid = false;
|
||||
}
|
||||
|
||||
ArrayList invalids = new ArrayList ();
|
||||
|
||||
foreach (Property prop in props.Values) {
|
||||
|
|
|
@ -108,6 +108,7 @@ PropertyBase: Abstract base class for property-like elements
|
|||
FieldBase: Abstract base class for field-like elements
|
||||
ObjectField: Handles <field> elements in objects
|
||||
StructField: Handles <field> elements in structs
|
||||
StructABIField: Handles <fields> to generate ABI compatible structures
|
||||
ClassField: Handles <field> elements in classes
|
||||
Property: Handles <property> elements
|
||||
ChildProperty: Handles <childprop> elements
|
||||
|
|
|
@ -26,7 +26,13 @@ namespace GtkSharp.Generation {
|
|||
using System.Xml;
|
||||
|
||||
public abstract class FieldBase : PropertyBase {
|
||||
public FieldBase abi_field = null;
|
||||
|
||||
public FieldBase (XmlElement elem, ClassBase container_type) : base (elem, container_type) {}
|
||||
public FieldBase (XmlElement elem, ClassBase container_type, FieldBase abi_field) : base (elem, container_type) {
|
||||
abi_field = abi_field;
|
||||
}
|
||||
|
||||
|
||||
public virtual bool Validate (LogWriter log)
|
||||
{
|
||||
|
@ -60,7 +66,7 @@ namespace GtkSharp.Generation {
|
|||
|
||||
protected abstract string DefaultAccess { get; }
|
||||
|
||||
internal string Access {
|
||||
protected virtual string Access {
|
||||
get {
|
||||
return elem.HasAttribute ("access") ? elem.GetAttribute ("access") : DefaultAccess;
|
||||
}
|
||||
|
@ -90,15 +96,30 @@ namespace GtkSharp.Generation {
|
|||
}
|
||||
}
|
||||
|
||||
string getterName, setterName;
|
||||
string getOffsetName, offsetName;
|
||||
private bool UseABIStruct(GenerationInfo gen_info) {
|
||||
return (abi_field != null && abi_field.getOffsetName != null &&
|
||||
gen_info.GlueWriter == null);
|
||||
}
|
||||
|
||||
void CheckGlue ()
|
||||
string getterName, setterName;
|
||||
protected string getOffsetName, offsetName;
|
||||
|
||||
void CheckGlue (GenerationInfo gen_info)
|
||||
{
|
||||
getterName = setterName = getOffsetName = null;
|
||||
if (Access != "public")
|
||||
return;
|
||||
|
||||
if (UseABIStruct(gen_info)) {
|
||||
getOffsetName = abi_field.getOffsetName;
|
||||
offsetName = "GetFieldOffset(\"" + ((StructField)abi_field).EqualityName + "\")";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (gen_info.GlueWriter == null)
|
||||
return;
|
||||
|
||||
string prefix = (container_type.NS + "Sharp_" + container_type.NS + "_" + container_type.Name).Replace(".", "__").ToLower ();
|
||||
|
||||
if (IsBitfield) {
|
||||
|
@ -119,17 +140,22 @@ namespace GtkSharp.Generation {
|
|||
StreamWriter sw = gen_info.Writer;
|
||||
SymbolTable table = SymbolTable.Table;
|
||||
|
||||
if (gen_info.GlueWriter == null) {
|
||||
base.GenerateImports(gen_info, indent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (getterName != null) {
|
||||
sw.WriteLine (indent + "[DllImport (\"{0}\")]", gen_info.GluelibName);
|
||||
sw.WriteLine (indent + "extern static {0} {1} ({2} raw);",
|
||||
table.GetMarshalType (CType), getterName,
|
||||
container_type.MarshalType);
|
||||
table.GetMarshalType (CType), getterName,
|
||||
container_type.MarshalType);
|
||||
}
|
||||
|
||||
if (setterName != null) {
|
||||
sw.WriteLine (indent + "[DllImport (\"{0}\")]", gen_info.GluelibName);
|
||||
sw.WriteLine (indent + "extern static void {0} ({1} raw, {2} value);",
|
||||
setterName, container_type.MarshalType, table.GetMarshalType (CType));
|
||||
setterName, container_type.MarshalType, table.GetMarshalType (CType));
|
||||
}
|
||||
|
||||
if (getOffsetName != null) {
|
||||
|
@ -147,15 +173,15 @@ namespace GtkSharp.Generation {
|
|||
if (Ignored || Hidden)
|
||||
return;
|
||||
|
||||
CheckGlue ();
|
||||
if ((getterName != null || setterName != null || getOffsetName != null) && gen_info.GlueWriter == null) {
|
||||
LogWriter log = new LogWriter (container_type.QualifiedName);
|
||||
log.Member = Name;
|
||||
log.Warn ("needs glue for field access. Specify --glue-filename");
|
||||
CheckGlue (gen_info);
|
||||
|
||||
GenerateImports (gen_info, indent);
|
||||
|
||||
if (Getter == null && getterName == null && offsetName == null &&
|
||||
Setter == null && setterName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GenerateImports (gen_info, indent);
|
||||
|
||||
SymbolTable table = SymbolTable.Table;
|
||||
IGeneratable gen = table [CType];
|
||||
|
@ -222,7 +248,7 @@ namespace GtkSharp.Generation {
|
|||
sw.WriteLine (indent + "}");
|
||||
sw.WriteLine ("");
|
||||
|
||||
if (getterName != null || setterName != null || getOffsetName != null)
|
||||
if ((getterName != null || setterName != null || getOffsetName != null) && gen_info.GlueWriter != null)
|
||||
GenerateGlue (gen_info);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ sources = \
|
|||
SimpleGen.cs \
|
||||
Statistics.cs \
|
||||
StructBase.cs \
|
||||
StructABIField.cs \
|
||||
StructField.cs \
|
||||
StructGen.cs \
|
||||
SymbolTable.cs \
|
||||
|
|
|
@ -187,6 +187,21 @@ namespace GtkSharp.Generation {
|
|||
}
|
||||
}
|
||||
|
||||
protected override bool CanGenerateABIStruct {
|
||||
get {
|
||||
if (!abi_fields_valid) {
|
||||
Console.WriteLine("invalid fields");
|
||||
return false;
|
||||
}
|
||||
|
||||
// No instance structure for interfaces
|
||||
if (is_interface)
|
||||
return false;
|
||||
|
||||
return class_struct_name != null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void GenerateClassStruct (GenerationInfo gen_info)
|
||||
{
|
||||
if (class_struct_name == null || !CanGenerateClassStruct) return;
|
||||
|
|
|
@ -26,8 +26,12 @@ namespace GtkSharp.Generation {
|
|||
|
||||
public class ObjectField : FieldBase {
|
||||
|
||||
public ObjectField (XmlElement elem, ClassBase container_type) : base (elem, container_type)
|
||||
{
|
||||
public ObjectField (XmlElement elem, ClassBase container_type) : base (elem, container_type){
|
||||
if (CType == "char*" || CType == "gchar*")
|
||||
ctype = "const-" + CType;
|
||||
}
|
||||
|
||||
public ObjectField (XmlElement elem, ClassBase container_type, FieldBase abi_field) : base (elem, container_type) {
|
||||
if (CType == "char*" || CType == "gchar*")
|
||||
ctype = "const-" + CType;
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ namespace GtkSharp.Generation {
|
|||
|
||||
if (dirs.ContainsKey (dir)) {
|
||||
result = dirs [dir];
|
||||
if (result.assembly_name != assembly_name) {
|
||||
if (result.assembly_name != assembly_name) {
|
||||
Console.WriteLine ("Can't put multiple assemblies in one directory.");
|
||||
return null;
|
||||
}
|
||||
|
@ -175,6 +175,7 @@ namespace GtkSharp.Generation {
|
|||
sw.WriteLine (" {");
|
||||
sw.WriteLine ();
|
||||
|
||||
GenerateStructureABI (gen_info);
|
||||
GenCtors (gen_info);
|
||||
GenProperties (gen_info, null);
|
||||
GenFields (gen_info);
|
||||
|
@ -285,7 +286,7 @@ namespace GtkSharp.Generation {
|
|||
|
||||
ObjectGen child_ancestor = Parent as ObjectGen;
|
||||
while (child_ancestor.CName != "GtkContainer" &&
|
||||
child_ancestor.childprops.Count == 0)
|
||||
child_ancestor.childprops.Count == 0)
|
||||
child_ancestor = child_ancestor.Parent as ObjectGen;
|
||||
|
||||
sw.WriteLine ("\t\tpublic class " + Name + "Child : " + child_ancestor.NS + "." + child_ancestor.Name + "." + child_ancestor.Name + "Child {");
|
||||
|
|
|
@ -80,6 +80,7 @@ namespace GtkSharp.Generation {
|
|||
sw.WriteLine (" {");
|
||||
sw.WriteLine ();
|
||||
|
||||
GenerateStructureABI(gen_info);
|
||||
GenConstants (gen_info);
|
||||
GenFields (gen_info);
|
||||
GenMethods (gen_info, null, null);
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace GtkSharp.Generation {
|
|||
}
|
||||
}
|
||||
|
||||
public bool Hidden {
|
||||
public virtual bool Hidden {
|
||||
get {
|
||||
return elem.GetAttributeAsBoolean ("hidden");
|
||||
}
|
||||
|
|
57
generator/StructABIField.cs
Normal file
57
generator/StructABIField.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
namespace GtkSharp.Generation {
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
public class StructABIField : StructField {
|
||||
protected new ClassBase container_type;
|
||||
|
||||
public StructABIField (XmlElement elem, ClassBase container_type) : base (elem, container_type) {
|
||||
this.container_type = container_type;
|
||||
this.getOffsetName = null;
|
||||
}
|
||||
|
||||
public override void Generate (GenerationInfo gen_info, string indent) {
|
||||
this.getOffsetName = "Get" + CName + "Offset";
|
||||
base.Generate(gen_info, indent);
|
||||
}
|
||||
|
||||
// All field are visible and private
|
||||
// as the goal is to respect the ABI
|
||||
protected override string Access {
|
||||
get {
|
||||
return "private";
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Hidden {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Validate (LogWriter log)
|
||||
{
|
||||
string cstype = SymbolTable.Table.GetCSType(CType, true);
|
||||
|
||||
if (cstype == null || cstype == "") {
|
||||
Console.WriteLine("(" + container_type.CName + ") VOOM " + CName + " " + CType + "=> " + cstype);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!base.Validate (log))
|
||||
return false;
|
||||
|
||||
if (IsBitfield) {
|
||||
log.Warn ("bitfields are not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,6 +60,13 @@ namespace GtkSharp.Generation {
|
|||
}
|
||||
}
|
||||
|
||||
protected override void WriteInstanceOffsetMethod(StreamWriter sw, string cs_parent_struct) {
|
||||
if (cs_parent_struct == "")
|
||||
sw.WriteLine ("\t\tpublic uint instance_offset { get { return 0; }}");
|
||||
else
|
||||
sw.WriteLine ("\t\tpublic override uint instance_offset {{ get {{ return ((uint) Marshal.SizeOf(typeof ({0})) + base.instance_offset); }} }}", cs_parent_struct);
|
||||
}
|
||||
|
||||
public override string DefaultValue {
|
||||
get {
|
||||
return QualifiedName + ".Zero";
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace GtkSharp.Generation {
|
|||
|
||||
StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name, NS);
|
||||
base.Generate (gen_info);
|
||||
GenerateStructureABI(gen_info);
|
||||
if (GetMethod ("GetType") == null && GetMethod ("GetGType") == null) {
|
||||
sw.WriteLine ("\t\tprivate static GLib.GType GType {");
|
||||
sw.WriteLine ("\t\t\tget { return GLib.GType.Pointer; }");
|
||||
|
|
|
@ -245,12 +245,22 @@ namespace GtkSharp.Generation {
|
|||
return gen.FromNative (val);
|
||||
}
|
||||
|
||||
public string GetCSType(string c_type)
|
||||
public string GetCSType(string c_type, bool default_pointer)
|
||||
{
|
||||
IGeneratable gen = this[c_type];
|
||||
if (gen == null)
|
||||
return "";
|
||||
return gen.QualifiedName;
|
||||
if (gen == null) {
|
||||
if (c_type.EndsWith("*") && default_pointer)
|
||||
return "UintPtr";
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
return gen.QualifiedName;
|
||||
}
|
||||
|
||||
public string GetCSType(string c_type)
|
||||
{
|
||||
return GetCSType(c_type, false);
|
||||
}
|
||||
|
||||
public string GetName(string c_type)
|
||||
|
|
|
@ -41,6 +41,7 @@ gapi_codegen = executable('gapi_codegen',
|
|||
'Method.cs',
|
||||
'NativeStructGen.cs',
|
||||
'ObjectField.cs',
|
||||
'StructABIField.cs',
|
||||
'ObjectBase.cs',
|
||||
'ObjectGen.cs',
|
||||
'OpaqueGen.cs',
|
||||
|
|
|
@ -823,6 +823,8 @@ namespace GLib {
|
|||
public IntPtr g_class;
|
||||
}
|
||||
|
||||
public virtual uint instance_offset { get { return 0; }}
|
||||
public uint GetFieldOffset(string field) { throw new NotImplementedException(); return 0; }
|
||||
public struct GObject {
|
||||
public GTypeInstance type_instance;
|
||||
public uint ref_count;
|
||||
|
|
Loading…
Reference in a new issue