Browse Source

Fix generated wrappers so tests run correctly given current state of runtime component.

+ Tweak access modifiers
+ Add inline method policy option
+ Remove alloc ctor and add native ctor
+ Remove "native_layout" field (now unnecessary with next commit)
+ Correctly add ByVal attribute to return type if applicable
pull/1/head
Alex Corrado 14 years ago
parent
commit
fcdb41de33
  1. 8
      src/Mono.VisualC.Interop/Interfaces.cs
  2. 60
      src/generator/Class.cs
  3. 26
      src/generator/Generator.cs
  4. 17
      src/generator/Method.cs
  5. 10
      tests/Makefile.am

8
src/Mono.VisualC.Interop/Interfaces.cs

@ -31,7 +31,13 @@ using Mono.VisualC.Interop.ABI; @@ -31,7 +31,13 @@ using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Interop {
// Part of the contract for ICppObject is a public constructor that takes CppInstancePtr (native constructor)
// The contract for ICppObject requires implementations to have the following constructors:
// + A public constructor that takes CppInstancePtr (native constructor)
// + A public constructor that takes CppTypeInfo, and as its sole operation,
// calls AddBase on that passed CppTypeInfo, passing its own typeinfo (subclass constructor)
// NOTE: It is important that the subclass constructor have no side effects.
// All constructors for wrappers of native subclasses must call the subclass constructor for the
// wrappers of their base class(es).
public interface ICppObject : IDisposable {
CppInstancePtr Native { get; }
}

60
src/generator/Class.cs

@ -76,61 +76,63 @@ class Class @@ -76,61 +76,63 @@ class Class
public CodeTypeDeclaration GenerateClass (Generator g, CodeTypeDeclaration libDecl, string libFieldName) {
var decl = new CodeTypeDeclaration (Name);
var hasBase = BaseClasses.Count > 0;
decl.IsPartial = true;
if (BaseClasses.Count > 0)
if (hasBase)
decl.BaseTypes.Add (new CodeTypeReference (BaseClasses [0].Name));
else
decl.BaseTypes.Add (new CodeTypeReference ("ICppObject"));
bool hasBase = BaseClasses.Count > 0;
var layout = new CodeTypeDeclaration ("_" + Name);
layout.IsStruct = true;
layout.TypeAttributes = TypeAttributes.NotPublic;
var layout = new CodeTypeDeclaration ("_" + Name) {
IsStruct = true,
TypeAttributes = TypeAttributes.NotPublic
};
decl.Members.Add (layout);
foreach (var f in Fields) {
CodeMemberField field = new CodeMemberField { Name = f.Name, Type = g.CppTypeToCodeDomType (f.Type) };
var field = new CodeMemberField {
Name = f.Name,
Type = g.CppTypeToCodeDomType (f.Type),
Attributes = MemberAttributes.Public
};
layout.Members.Add (field);
}
var iface = new CodeTypeDeclaration ("I" + Name);
iface.IsInterface = true;
layout.TypeAttributes = TypeAttributes.NotPublic;
iface.BaseTypes.Add (new CodeTypeReference ("ICppClassOverridable", new CodeTypeReference [] { new CodeTypeReference (decl.Name) }));
decl.Members.Add (iface);
var layoutField = new CodeMemberField (new CodeTypeReference (typeof (Type)), "native_layout");
layoutField.Attributes = MemberAttributes.Private|MemberAttributes.Static;
layoutField.InitExpression = new CodeTypeOfExpression (layout.Name);
decl.Members.Add (layoutField);
var implField = new CodeMemberField (new CodeTypeReference (iface.Name), "impl");
implField.Attributes = MemberAttributes.Private|MemberAttributes.Static;
var implField = new CodeMemberField (new CodeTypeReference (iface.Name), "impl") {
Attributes = MemberAttributes.Private | MemberAttributes.Static
};
var getclass = new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (libDecl.Name), libFieldName), "GetClass", new CodeTypeReference [] { new CodeTypeReference (iface.Name), new CodeTypeReference (layout.Name), new CodeTypeReference (decl.Name) });
implField.InitExpression = new CodeMethodInvokeExpression (getclass, new CodeExpression [] { new CodePrimitiveExpression (Name) });
decl.Members.Add (implField);
//private static IClass impl = global::CppTests.Libs.Test.GetClass <IClass, _Class, Class>("Class");
if (!hasBase) {
var ptrField = new CodeMemberField (new CodeTypeReference ("CppInstancePtr"), "native_ptr");
ptrField.Attributes = MemberAttributes.Family;
var ptrField = new CodeMemberField (new CodeTypeReference ("CppInstancePtr"), "native_ptr") {
Attributes = MemberAttributes.Family
};
decl.Members.Add (ptrField);
}
var allocCtor = new CodeConstructor () {
};
allocCtor.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppLibrary"), "dummy"));
allocCtor.Statements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (null, "native_ptr"), new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), "Alloc"), new CodeExpression [] { new CodeThisReferenceExpression () })));
var nativeCtor = new CodeConstructor () {
Attributes = MemberAttributes.Public
};
nativeCtor.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppInstancePtr"), "native"));
nativeCtor.Statements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (null, "native_ptr"), new CodeArgumentReferenceExpression ("native")));
if (hasBase) {
var implTypeInfo = new CodeFieldReferenceExpression (new CodeFieldReferenceExpression { FieldName = "impl" }, "TypeInfo");
allocCtor.BaseConstructorArgs.Add (implTypeInfo);
nativeCtor.BaseConstructorArgs.Add (implTypeInfo);
}
decl.Members.Add (allocCtor);
decl.Members.Add (nativeCtor);
var subclassCtor = new CodeConstructor () {
Attributes = MemberAttributes.Family
};
Attributes = MemberAttributes.Public
};
subclassCtor.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppTypeInfo"), "subClass"));
subclassCtor.Statements.Add (new CodeExpressionStatement (new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeArgumentReferenceExpression ("subClass"), "AddBase"), new CodeExpression [] { new CodeFieldReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), "TypeInfo") })));
if (hasBase) {
@ -141,10 +143,10 @@ class Class @@ -141,10 +143,10 @@ class Class
if (!hasBase) {
var nativeProperty = new CodeMemberProperty () {
Name = "Native",
Type = new CodeTypeReference ("CppInstancePtr"),
Attributes = MemberAttributes.Public|MemberAttributes.Final
};
Name = "Native",
Type = new CodeTypeReference ("CppInstancePtr"),
Attributes = MemberAttributes.Public|MemberAttributes.Final
};
nativeProperty.GetStatements.Add (new CodeMethodReturnStatement (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "native_ptr")));
decl.Members.Add (nativeProperty);
}

26
src/generator/Generator.cs

@ -25,6 +25,7 @@ public class Generator @@ -25,6 +25,7 @@ public class Generator
string LibBaseName;
string InputFileName;
string FilterFile;
InlineMethods InlinePolicy;
CodeDomProvider Provider;
CodeGeneratorOptions CodeGenOptions;
@ -43,10 +44,11 @@ public class Generator @@ -43,10 +44,11 @@ public class Generator
var p = new OptionSet {
{ "h|?|help", "Show this help message", v => help = v != null },
{ "o=", "Set the output directory", v => OutputDir = v },
{ "o=|out=", "Set the output directory", v => OutputDir = v },
{ "ns=|namespace=", "Set the namespace of the generated code", v => Namespace = v },
{ "lib=", "The base name of the C++ library, i.e. 'qt' for libqt.so", v =>LibBaseName = v },
{ "filters=", "A file containing filter directives for filtering classes", v => FilterFile = v }
{ "filters=", "A file containing filter directives for filtering classes", v => FilterFile = v },
{ "inline=", "Inline methods in lib are: notpresent (default), present, surrogatelib (present in %lib%-inline)", v => InlinePolicy = (InlineMethods)Enum.Parse (typeof (InlineMethods), v, true) }
};
try {
@ -241,6 +243,9 @@ public class Generator @@ -241,6 +243,9 @@ public class Generator
IsDestructor = dtor
};
if (dtor)
method.GenWrapperMethod = false;
bool skip = false;
CppType retType;
@ -395,7 +400,7 @@ public class Generator @@ -395,7 +400,7 @@ public class Generator
else
return CppTypes.Unknown;
}
return modifiers.CopyTypeFrom (new CppType (CppTypes.Class, NodeToClass [n].Name));
return modifiers.CopyTypeFrom (new CppType (n.Type == "Class"? CppTypes.Class : CppTypes.Struct, NodeToClass [n].Name));
default:
return CppTypes.Unknown;
}
@ -411,7 +416,7 @@ public class Generator @@ -411,7 +416,7 @@ public class Generator
byref = false;
Type mtype = t.ToManagedType ();
if (mtype != null) {
if (mtype != null && mtype != typeof (ICppObject)) {
if (mtype.IsByRef) {
byref = true;
mtype = mtype.GetElementType ();
@ -419,9 +424,12 @@ public class Generator @@ -419,9 +424,12 @@ public class Generator
return new CodeTypeReference (mtype);
}
if (t.Modifiers.Count > 0 && t.ElementType != CppTypes.Void && t.ElementType != CppTypes.Class)
return null;
// Why is this here?
//if (t.Modifiers.Count > 0 && t.ElementType != CppTypes.Void && t.ElementType != CppTypes.Class)
// return null;
switch (t.ElementType) {
// These cases should all be handled by ToManagedType, no?
/*
case CppTypes.Void:
if (t.Modifiers.Count > 0) {
if (t.Modifiers.Count == 1 && t.Modifiers [0] == CppModifiers.Pointer)
@ -447,7 +455,9 @@ public class Generator @@ -447,7 +455,9 @@ public class Generator
case CppTypes.Char:
rtype = new CodeTypeReference (typeof (char));
break;
*/
case CppTypes.Class:
case CppTypes.Struct:
// FIXME: Full name
rtype = new CodeTypeReference (t.ElementTypeName);
break;
@ -483,7 +493,7 @@ public class Generator @@ -483,7 +493,7 @@ public class Generator
var field = new CodeMemberField (new CodeTypeReference ("CppLibrary"), LibBaseName);
field.Attributes = MemberAttributes.Public|MemberAttributes.Static;
field.InitExpression = new CodeObjectCreateExpression (new CodeTypeReference ("CppLibrary"), new CodeExpression [] { new CodePrimitiveExpression (LibBaseName) });
field.InitExpression = new CodeObjectCreateExpression (new CodeTypeReference ("CppLibrary"), new CodeExpression [] { new CodePrimitiveExpression (LibBaseName), new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (typeof (InlineMethods).Name), InlinePolicy.ToString ()) });
decl.Members.Add (field);
ns.Types.Add (decl);
@ -512,7 +522,7 @@ public class Generator @@ -512,7 +522,7 @@ public class Generator
//Provider.GenerateCodeFromCompileUnit(cu, Console.Out, CodeGenOptions);
using (TextWriter w = File.CreateText (Path.Combine (OutputDir, klass.Name + ".cs"))) {
// These are reported for the fields of the native layout structures
Provider.GenerateCodeFromCompileUnit (new CodeSnippetCompileUnit("#pragma warning disable 0414, 0169"), w, CodeGenOptions);
//Provider.GenerateCodeFromCompileUnit (new CodeSnippetCompileUnit("#pragma warning disable 0414, 0169"), w, CodeGenOptions);
Provider.GenerateCodeFromCompileUnit(cu, w, CodeGenOptions);
}
}

17
src/generator/Method.cs

@ -108,13 +108,20 @@ class Method @@ -108,13 +108,20 @@ class Method
public CodeMemberMethod GenerateIFaceMethod (Generator g) {
var method = new CodeMemberMethod () {
Name = Name
};
};
if (!IsStatic)
method.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppInstancePtr"), "this"));
CodeTypeReference rtype = g.CppTypeToCodeDomType (ReturnType);
method.ReturnType = rtype;
if ((ReturnType.ElementType == CppTypes.Class || ReturnType.ElementType == CppTypes.Struct) &&
!ReturnType.Modifiers.Contains (CppModifiers.Pointer) &&
!ReturnType.Modifiers.Contains (CppModifiers.Reference) &&
!ReturnType.Modifiers.Contains (CppModifiers.Array))
{
method.ReturnTypeCustomAttributes.Add (new CodeAttributeDeclaration ("ByVal"));
}
foreach (var p in Parameters) {
CppType ptype = p.Type;
@ -125,9 +132,13 @@ class Method @@ -125,9 +132,13 @@ class Method
param.Direction = FieldDirection.Ref;
if (!IsVirtual && !ptype.ToString ().Equals (string.Empty))
param.CustomAttributes.Add (new CodeAttributeDeclaration ("MangleAsAttribute", new CodeAttributeArgument (new CodePrimitiveExpression (ptype.ToString ()))));
// FIXME: Structs too
if (ptype.ElementType == CppTypes.Class && !ptype.Modifiers.Contains (CppModifiers.Reference) && !ptype.Modifiers.Contains (CppModifiers.Pointer))
if ((ptype.ElementType == CppTypes.Class || ptype.ElementType == CppTypes.Struct) &&
!ptype.Modifiers.Contains (CppModifiers.Pointer) &&
!ptype.Modifiers.Contains (CppModifiers.Reference) &&
!ptype.Modifiers.Contains (CppModifiers.Array))
{
param.CustomAttributes.Add (new CodeAttributeDeclaration ("ByVal"));
}
method.Parameters.Add (param);
}

10
tests/Makefile.am

@ -28,20 +28,20 @@ test.xml: $(HDR) @@ -28,20 +28,20 @@ test.xml: $(HDR)
gccxml -fxml=$@ --gccxml-cxxflags -c $(HDR)
$(BUILD_DIR)/libTest.so: $(HEADERS) $(NATIVE)
g++ -fPIC --shared -o $@ $(NATIVE)
g++ -fPIC --shared -m32 -o $@ $(NATIVE)
$(BUILD_DIR)/libTest-inline.so: $(HEADERS) $(NATIVE)
g++ -fPIC --shared -fkeep-inline-functions -o $@ $(NATIVE)
g++ -fPIC --shared -m32 -fkeep-inline-functions -o $@ $(NATIVE)
generated: test.xml
$(RM) -r generated
mono --debug $(BUILD_DIR)/generator.exe -o=$@ -ns=Tests -lib=Test test.xml
mono --debug $(BUILD_DIR)/generator.exe -o=$@ -ns=Tests -lib=Test -inline=surrogatelib test.xml
$(TEST_DLL): generated $(MANAGED) $(BUILD_DIR)/libTest.so $(BUILD_DIR)/libTest-inline.so
mcs -out:$@ -target:library -unsafe $(REFERENCES) -r:$(INTEROP_DLL) generated/*.cs $(MANAGED)
mcs -debug -out:$@ -target:library -unsafe $(REFERENCES) -r:$(INTEROP_DLL) generated/*.cs $(MANAGED)
clean:
$(RM) -rf $(TEST_DLL) generated $(BUILD_DIR)/libTest.so $(BUILD_DIR)/libTest-inline.so test.xml
run: $(TEST_DLL)
nunit-console -nologo $(TEST_DLL)
nunit-console -nologo $(TEST_DLL)

Loading…
Cancel
Save