diff --git a/src/Mono.VisualC.Interop/Interfaces.cs b/src/Mono.VisualC.Interop/Interfaces.cs index 792262a5..a5a73b28 100644 --- a/src/Mono.VisualC.Interop/Interfaces.cs +++ b/src/Mono.VisualC.Interop/Interfaces.cs @@ -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; } } diff --git a/src/generator/Class.cs b/src/generator/Class.cs index 5337c0eb..f129aebf 100644 --- a/src/generator/Class.cs +++ b/src/generator/Class.cs @@ -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 ("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 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); } diff --git a/src/generator/Generator.cs b/src/generator/Generator.cs index b2f14944..f2b4b06d 100644 --- a/src/generator/Generator.cs +++ b/src/generator/Generator.cs @@ -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 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 IsDestructor = dtor }; + if (dtor) + method.GenWrapperMethod = false; + bool skip = false; CppType retType; @@ -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 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 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 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 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 //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); } } diff --git a/src/generator/Method.cs b/src/generator/Method.cs index 0b75b11b..6f3d36ac 100644 --- a/src/generator/Method.cs +++ b/src/generator/Method.cs @@ -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 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); } diff --git a/tests/Makefile.am b/tests/Makefile.am index cfb64006..b8d61182 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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) \ No newline at end of file + nunit-console -nologo $(TEST_DLL)