Browse files

Moved deprecated library

svn path=/old-code/; revision=152783
  • Loading branch information...
1 parent 9c3b69d commit b6200d1c0cdd82aaa34b81643267845cfc0543fe @migueldeicaza migueldeicaza committed Mar 2, 2010
Showing with 1,980 additions and 0 deletions.
  1. +4 −0 cilc/.cvsignore
  2. +170 −0 cilc/ChangeLog
  3. +112 −0 cilc/CodeWriter.cs
  4. +35 −0 cilc/Makefile
  5. +53 −0 cilc/README
  6. +49 −0 cilc/TODO
  7. +105 −0 cilc/Test.cs
  8. +1,350 −0 cilc/cilc.cs
  9. +2 −0 cilc/cilc.exe.sources
  10. +54 −0 cilc/demo.c
  11. +46 −0 cilc/res-Makefile
View
4 cilc/.cvsignore
@@ -0,0 +1,4 @@
+Test.dll
+Test.pdb
+cilc.pdb
+*.mdb
View
170 cilc/ChangeLog
@@ -0,0 +1,170 @@
+2009-10-23 Alp Toker <alp@nuanti.com>
+
+ * cilc.cs: Introduce and start to make use of disable_glib.
+
+2007-03-13 Alp Toker <alp@atoker.com>
+
+ * cilc.exe.sources:
+ * cilc.cs:
+ * CodeWriter.cs: Split out CodeWriter class.
+
+2007-03-13 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Use String.Empty.
+
+2006-08-23 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Relicense from GPL to MIT License
+
+2006-08-23 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Add more GInterface support, both defining and implementing
+
+2005-12-27 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Start work on GInterface support
+ * Test.cs: Update tests
+
+2005-12-24 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Fix generation of mono method signature a bit (still needs work),
+ Make JIT parse default config files before init
+
+2005-12-22 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Add support for string return types and properties, begin work to
+ improve GObject tie-in
+ * Test.cs, demo.c: Update tests
+
+2005-12-22 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Add support for char, sbyte, byte and double
+ * Test.cs, demo.c: Update tests
+
+2005-05-08 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Add null check to NsToC and fix warnings.
+
+2005-01-20 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Name the glib handle getter helper method by namespace for now to
+ fully support assemblies with multiple namespaces. Would be better to
+ generate a toplevel Cindex file in future.
+
+2004-12-13 Alp Toker <alp@atoker.com>
+
+ * cilc.cs:
+ Use the GObject of the object if it already has one, rather than creating a
+ new GObject instance of our own. Store the reference to the MonoObject in
+ a GObject data field.
+ Explicit casts in generated code to avoid compiler warnings.
+
+2004-12-12 Alp Toker <alp@atoker.com>
+
+ * cilc.cs:
+ * Test.cs:
+ * demo.c:
+ First stab at return values, and associated updates to the demo.
+ Consider types registered ByVal but not in main registry as unregistered.
+ Mark out some more ByVal types.
+ * cilc.cs:
+ Initial support for namespaceless assemblies.
+ C keyword avoidance.
+
+2004-12-11 Alp Toker <alp@atoker.com>
+
+ * cilc.cs:
+ First stab at initialising delegates using method pointers.
+ Convert the type registry management and reporting methods to use strings,
+ making way for tie-in with native GObject hierarchies.
+ Recursive conflict avoidance for the GObject class struct etc.
+ Add check to see if a registered type IsExternal
+ Treat byref values properly.
+ Support tie-in with existing GObject hierarchy.
+ Use argc parity to decide the generation mode.
+ Update usage help string.
+ * res-Makefile:
+ Use passed CFLAGS.
+ Only rebuild modified targets if bundle is defined, not everything.
+ * README:
+ More usage examples.
+
+2004-12-10 Alp Toker <alp@atoker.com>
+
+ * cilc.cs:
+ The generated makefile now optionally uses mkbundle to include the assembly
+ into the generated library (when 'bundle' is defined for make).
+ The assembly is automatically copied into the generated directory.
+ Use a resource for the static makefile
+ If only one argument is given, generate sources to a temporary directory,
+ build them (as bundle), and install them to the current directory.
+ Otherwise, the old behaviour applies.
+ Don't indent the __cplusplus ifdef block in generated headers.
+ Include the Mono headers in the sources, not the headers.
+ Identify and report disparity in the order of type registration.
+ Start support for some more primitive types.
+ Fix with/and separator logic in overloaded method generation.
+ Generate enums.
+ Cleanups.
+ * README:
+ Update with details of the new bundle feature and single-argument operation.
+ * Makefile:
+ We no longer need to copy the assembly to the generated directory manually.
+ Include res-Makefile as a resource for cilc.exe
+ * res-Makefile:
+ The static makefile resource
+ Tweak the library output directory.
+
+2004-12-09 Alp Toker <alp@atoker.com>
+
+ * cilc.cs:
+ Support inheritance (within a single namespace).
+ Enhance CodeWriter.
+ Handle nested namespaces properly.
+ Generate forward type declarations.
+ Use the real type, not MonoObject, for function parameters.
+ Ignore non-public types for now.
+ Handle multiple namespaces in a single assembly.
+ Name the generated .so according to the input assembly name.
+ Code generator access modifier cleanups.
+ Use base name of input as default output target directory.
+ Report missed type registry hits after generation, using FullName if needed.
+ Reduce verbosity.
+ * Makefile:
+ Build Demo.dll, not Test.dll.
+
+2004-12-08 Alp Toker <alp@atoker.com>
+
+ * cilc.cs:
+ Produce genuine GObjects.
+ Start support for events/signals and enums.
+ Handle overloaded methods.
+ Report ignored types, warn on potentially incorrect code generation.
+ More conflict avoidance.
+ Cleaned up warnings.
+ * README: Update test instructions.
+
+2004-12-06 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Update to new embedding API: use mono_assembly_get_image()
+ Avoid conflicting parameter and internal variable names.
+ Use intermediary object files before linking.
+
+2004-06-09 Raja R Harinath <rharinath@novell.com>
+
+ * Makefile (HAS_TEST): Remove.
+ (run-test-local): Move rules to and depend on ...
+ (run-cilc-test): ... this.
+
+2003-05-02 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Print usage info
+
+2003-05-01 Alp Toker <alp@atoker.com>
+
+ * cilc.cs: Support arguments, clean up some gcc warnings
+ * Test.cs, demo.c: More extensive test
+
+2003-04-25 Alp Toker <alp@atoker.com>
+
+ * Initial release of cilc
View
112 cilc/CodeWriter.cs
@@ -0,0 +1,112 @@
+// cilc -- a CIL-to-C binding generator
+// Copyright (C) 2003, 2004, 2005, 2006, 2007 Alp Toker <alp@atoker.com>
+// Licensed under the terms of the MIT License
+
+using System;
+using System.IO;
+
+class CodeWriter
+{
+ private StreamWriter w;
+
+ public CodeWriter (string fname)
+ {
+ Init (fname);
+ }
+
+ public bool IsDuplicate = false;
+
+ void Init (string fname)
+ {
+ if (File.Exists (fname)) {
+ string newfname = fname + ".x";
+ //Console.WriteLine ("Warning: File " + fname + " already exists, using " + newfname);
+ IsDuplicate = true;
+ Init (newfname);
+ return;
+ }
+
+ FileStream fs = new FileStream (fname, FileMode.OpenOrCreate, FileAccess.Write);
+ w = new StreamWriter (fs);
+ }
+
+ public string Indenter = " ";
+ string cur_indent = String.Empty;
+ int level = 0;
+
+ public void Indent ()
+ {
+ level++;
+ cur_indent = String.Empty;
+ for (int i = 0; i != level ; i++) cur_indent += Indenter;
+ }
+
+ public void Outdent ()
+ {
+ level--;
+ cur_indent = String.Empty;
+ for (int i = 0; i != level ; i++) cur_indent += Indenter;
+ }
+
+ public void Write (string text)
+ {
+ w.Write (text);
+ }
+
+ public void WriteLine (string text)
+ {
+ WriteLine (text, true);
+ }
+
+ public void WriteLine (string text, bool autoindent)
+ {
+ char[] opentags = {'{', '('};
+ char[] closetags = {'}', ')'};
+
+ if (autoindent && text.TrimStart (closetags) != text)
+ Outdent ();
+
+ w.Write (cur_indent);
+ w.WriteLine (text);
+
+ if (autoindent && text.TrimEnd (opentags) != text)
+ Indent ();
+ }
+
+ public void WriteLine (string text, CodeWriter cc)
+ {
+ WriteLine (text, String.Empty, cc, String.Empty);
+ }
+
+ public void WriteLine (string text, CodeWriter cc, string suffix)
+ {
+ WriteLine (text, String.Empty, cc, suffix);
+ }
+
+ public void WriteLine (string text, string prefix, CodeWriter cc)
+ {
+ WriteLine (text, prefix, cc, String.Empty);
+ }
+
+ public void WriteLine (string text, string prefix, CodeWriter cc, string suffix)
+ {
+ WriteLine (text);
+ cc.WriteLine (prefix + text + suffix);
+ }
+
+ public void WriteComment (string text)
+ {
+ w.WriteLine ("/* " + text + " */");
+ }
+
+ public void WriteLine ()
+ {
+ w.WriteLine (String.Empty);
+ }
+
+ public void Close ()
+ {
+ w.Flush ();
+ w.Close ();
+ }
+}
View
35 cilc/Makefile
@@ -0,0 +1,35 @@
+thisdir = tools/cilc
+SUBDIRS =
+include ../../build/rules.make
+
+PROGRAM = cilc.exe
+
+# fixme: make clean doesn't know to rm -rf generated.
+# and we can't extend the make clean target.
+
+CLEAN_FILES = generated Demo.dll Demo.pdb
+
+OTHER_RES = res-Makefile
+
+RESOURCE_FILES = $(OTHER_RES)
+
+EXTRA_DISTFILES = demo.c README TODO Test.cs $(RESOURCE_FILES)
+
+include ../../build/executable.make
+
+LOCAL_MCS_FLAGS=-r:Mono.Posix.dll $(OTHER_RES:%=-resource:%)
+
+cilc.exe: $(RESOURCE_FILES)
+
+test-local: Demo.dll
+
+run-test-local: run-cilc-test
+
+run-cilc-test: cilc.exe Demo.dll
+ rm -rf generated
+ $(RUNTIME) $(RUNTIME_FLAGS) cilc.exe Demo.dll generated
+ $(MAKE) -C generated
+ $(CCOMPILE) -Wall `pkg-config --cflags --libs glib-2.0 mono` -Igenerated -Lgenerated -ldemo demo.c -o generated/demo
+
+Demo.dll: Test.cs
+ $(CSCOMPILE) /target:library /out:$@ $^
View
53 cilc/README
@@ -0,0 +1,53 @@
+cilc
+====
+
+cilc is a CIL-to-C binding generator. It can be used to expose any CIL library
+to the C (and C++) world using the GObject object model and coding style. This
+should be of particular interest to GNOME developers who wish to make use of
+libraries developed in C#, perhaps Gtk# widgets, within their own C
+applications. Developers who use a generated binding need no specific knowledge
+pertaining to Mono and runtime embedding -- almost everything is done behind
+the scenes.
+
+Right now, cilc is in an early stage of development. See TODO for a list of
+pending tasks.
+
+For a demonstration, see Test.cs and demo.c to get an idea of what's going on.
+Then run:
+
+$ make run-test-local
+$ cd generated
+$ ./demo
+
+To make a redistributable shared object that includes the assembly, you can
+then:
+
+$ make clean
+$ make bundle=true
+$ rm *.dll
+$ ./demo
+
+Note that you must have Mono's mkbundle tool installed to use the bundle
+feature.
+
+If all you want to do is generate a binding for an assembly, you can simply
+pass the assembly name as a single argument to cilc and it will automatically
+generate bindings in a temporary directory, compile them using the bundle
+feature, and install the produced shared library in the lib/ subdirectory and
+the headers in include/.
+
+$ cilc Assembly.dll
+
+To tie-in with existing GOjbect hierarchies, pass pairs of pkg-config package
+and comma-separated namespaces. For example:
+
+If you want to use a Gtk# widget in a Gtk+ application:
+
+$ cilc Widget.dll gtk+-2.0 gtk
+
+To bind gtk-sharp, but tying it into the native hierarchy for gdk:
+
+$ cilc gtk-sharp.dll gtk+-2.0 gdk
+
+--
+Alp Toker <alp@atoker.com>
View
49 cilc/TODO
@@ -0,0 +1,49 @@
+TODO
+====
+
+HIGH PRIORITY
+-------------
+
+Don't generate GObjects by default, said to be too heavy. Might need to clean
+up the generator to make this easier.
+
+Consider moving the suffix underscore into NsToC (ns) to better handle namespaceless assemblies.
+
+Handle nested classes
+
+Generate structs
+
+Make parsing of existing C headers more comprehensive (support enums, structs, classes, mark as byval where necessary)
+
+Better support for return values and ref/out parameters
+
+Support more primitive types
+
+Only install relevant headers, and use the proper subdirectory path for includes
+
+Generate pkg-config files and consider the use of more than one generated assembly binding in a single unmanaged application.
+
+Test with assemblies containing multiple namespaces (eg. SWF).
+
+Make "mono-object" string a global const.
+
+Allow bundling of glib-sharp.dll if using the GObject tie-in feature.
+
+LOW PRIORITY
+------------
+
+Delegates, events etc.
+
+Complete GObject support including macros and GType, taking into account
+inheritance etc.
+
+generate autoconf/automake build files. set AC_VERSION using the assembly's
+version attribute
+
+Automatically generate inline API documentation using documentation in the
+Monodoc format. The GTK+ API documentation generator can then be used to create
+documentation familiar to GTK+ developers.
+
+Resolve GC issues using weak references or storing objects in something like a
+MonoGHashTable
+
View
105 cilc/Test.cs
@@ -0,0 +1,105 @@
+namespace Demo
+{
+ using System;
+
+ public interface INumbered
+ {
+ void Increment ();
+ }
+
+ public class Counter : INumbered
+ {
+ int counter;
+
+ public void Increment ()
+ {
+ counter++;
+ Console.WriteLine ("Instance method invoked: Value incremented, making it " + counter);
+ }
+
+ public void AddNumber (int num)
+ {
+ counter += num;
+ Console.WriteLine ("Instance method with an argument invoked: " + num + " added to value, making it " + counter);
+ }
+ }
+
+ public class Test
+ {
+ string title;
+ int counter;
+
+ public static void StaticMethod ()
+ {
+ Console.WriteLine ("Static method invoked");
+ }
+
+ public Test ()
+ {
+ title = "";
+ counter = 0;
+
+ Console.WriteLine ("Class constructor invoked: Value initialised, making it " + counter);
+ }
+
+ public void Increment ()
+ {
+ counter++;
+ Console.WriteLine ("Instance method invoked: Value incremented, making it " + counter);
+ }
+
+ public void AddNumber (int num)
+ {
+ counter += num;
+ Console.WriteLine ("Instance method with an argument invoked: " + num + " added to value, making it " + counter);
+ }
+
+ public double GetDoubleValue ()
+ {
+ return (double)counter/2;
+ }
+
+ public int GetValue ()
+ {
+ return counter;
+ }
+
+ public static Drink PickDrink ()
+ {
+ return Drink.Water;
+ }
+
+ public string Title
+ {
+ get { return title; }
+ set { title = value; }
+ }
+
+ public void Echo (string arg1string)
+ {
+ Console.WriteLine ("string: " + arg1string);
+ }
+
+ public string MakeUpper (string arg1string)
+ {
+ return arg1string.ToUpper ();
+ }
+
+ public void Method4 (string arg1string, int arg2int)
+ {
+ Console.WriteLine (arg1string + arg2int.ToString ());
+ }
+
+ public void GTypeGTypeGType ()
+ {
+ Console.WriteLine ("c# method with an unusual name invoked");
+ }
+ }
+
+ public enum Drink
+ {
+ Water,
+ Juice,
+ Cola
+ }
+}
View
1,350 cilc/cilc.cs
@@ -0,0 +1,1350 @@
+// cilc -- a CIL-to-C binding generator
+// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Alp Toker <alp@atoker.com>
+// Licensed under the terms of the MIT License
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Collections;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+
+public class cilc
+{
+ private cilc () {}
+
+ static CodeWriter C, H, Cindex, Hindex, Hdecls;
+ static string ns, dllname;
+ static string cur_type, CurType, CurTypeClass;
+ static string target_dir;
+
+ static ArrayList funcs_done = new ArrayList ();
+
+ static bool disable_glib = false;
+
+ public static int Main (string[] args)
+ {
+ if (args.Length < 1 || args.Length > 4) {
+ Console.WriteLine ("Mono CIL-to-C binding generator");
+ Console.WriteLine ("Usage: cilc assembly [target] [pkg ns[,ns...]]");
+ return 1;
+ }
+
+ ns = "Unnamed";
+
+ RegisterByVal (typeof (uint));
+ RegisterByVal (typeof (int));
+ RegisterByVal (typeof (IntPtr));
+ RegisterByVal (typeof (bool));
+ RegisterByVal (typeof (char));
+ RegisterByVal (typeof (sbyte));
+ RegisterByVal (typeof (byte));
+ RegisterByVal (typeof (double));
+
+ if (args.Length == 1) {
+ SmartBind (args[0]);
+ } else if (args.Length == 2) {
+ Generate (args[0], args[1]);
+ } else if (args.Length == 3) {
+ RegisterPkg (args[1], args[2]);
+ SmartBind (args[0]);
+ } else if (args.Length == 4) {
+ RegisterPkg (args[2], args[3]);
+ Generate (args[0], args[1]);
+ }
+
+ return 0;
+ }
+
+
+ public static void SmartBind (string aname)
+ {
+ string tmpdir = Path.GetTempPath () + Path.GetTempFileName ();
+ string cwd = Directory.GetCurrentDirectory ();
+ if (Directory.Exists (tmpdir) || File.Exists (tmpdir)) {
+ Console.WriteLine ("Error: Temporary directory " + tmpdir + " already exists.");
+ return;
+ }
+ Generate (aname, tmpdir);
+ Console.Write ("Compiling unmanaged binding");
+ RunWithReport ("make", "-C \"" + tmpdir + "\" bundle=true");
+ Console.WriteLine ();
+ Console.Write ("Installing to current directory");
+ RunWithReport ("make", "-C \"" + tmpdir + "\" install prefix=\"" + cwd + "\"");
+ Directory.Delete (tmpdir, true);
+ Console.WriteLine ();
+ }
+
+ public static string Run (string cmd, string args)
+ {
+ ProcessStartInfo psi = new ProcessStartInfo (cmd, args);
+ psi.UseShellExecute = false;
+ psi.RedirectStandardInput = true;
+ psi.RedirectStandardOutput = true;
+ psi.RedirectStandardError = true;
+
+ Process p = Process.Start (psi);
+
+ string line = p.StandardOutput.ReadLine ();
+
+ p.WaitForExit ();
+
+ return line;
+ }
+
+ public static int RunWithReport (string cmd, string args)
+ {
+ ProcessStartInfo psi = new ProcessStartInfo (cmd, args);
+ psi.UseShellExecute = false;
+ psi.RedirectStandardOutput = true;
+ psi.RedirectStandardError = true;
+
+ Process p = Process.Start (psi);
+
+ string line;
+ while ((line = p.StandardOutput.ReadLine ()) != null)
+ if (verbose)
+ Console.WriteLine (line);
+ else
+ Console.Write (".");
+
+ Console.WriteLine ();
+
+ Console.Write (p.StandardError.ReadToEnd ());
+
+ p.WaitForExit ();
+
+ return p.ExitCode;
+ }
+
+ static bool verbose = false;
+
+ static string extpkgs = String.Empty;
+ static string[] extsubpkgs = {};
+ static string[] extincludes = {};
+
+ public static void RegisterPkg (string pkg, string subpkgs)
+ {
+ extpkgs += " " + pkg;
+
+ string cflags = Run ("pkg-config", "--cflags-only-I " + pkg);
+
+ extsubpkgs = subpkgs.Trim ().Split (',');
+ extincludes = new string[extsubpkgs.Length];
+
+ for (int i = 0 ; i != extsubpkgs.Length ; i++)
+ extincludes[i] = extsubpkgs[i] + "/" + extsubpkgs[i] + ".h";
+
+ //string cmd = "gcc";
+ //string args = "-E " + cflags + " " + includedir + "/" + hname;
+
+ string cppincludes = String.Empty;
+ foreach (string include in extincludes)
+ cppincludes += " -include " + include;
+
+ string cmd = "cpp";
+ string args = cflags + cppincludes + " /dev/null";
+
+ ProcessStartInfo psi = new ProcessStartInfo (cmd, args);
+ psi.UseShellExecute = false;
+ psi.RedirectStandardOutput = true;
+ psi.RedirectStandardError = true;
+
+ Process p = Process.Start (psi);
+
+ string line;
+
+ Regex re_type = new Regex (@"typedef struct (_\w+) (\w+);");
+ Regex re_enum = new Regex (@"} (\w+);");
+
+ while ((line = p.StandardOutput.ReadLine ()) != null) {
+ line = line.Trim ();
+
+ Match m;
+
+ m = re_type.Match (line);
+ if (m.Success) {
+ string G = m.Groups[2].Value;
+
+ if (!GIsValid (G))
+ continue;
+
+ if (G.EndsWith ("Class"))
+ continue;
+
+ RegisterG (G);
+ continue;
+ }
+
+ m = re_enum.Match (line);
+ if (m.Success) {
+ string G = m.Groups[1].Value;
+
+ if (!GIsValid (G))
+ continue;
+
+ RegisterG (G);
+ RegisterByVal (G);
+ continue;
+ }
+ }
+
+ p.WaitForExit ();
+ Console.Write (p.StandardError.ReadToEnd ());
+ Console.WriteLine ();
+ }
+
+ static bool GIsValid (string G) {
+ foreach (string extsubpkg in extsubpkgs)
+ if (G.ToLower ().StartsWith (extsubpkg))
+ return true;
+
+ return false;
+ }
+
+ public static void Generate (string assembly, string target)
+ {
+ target_dir = target + Path.DirectorySeparatorChar;
+
+ if (Directory.Exists (target_dir)) {
+ Console.WriteLine ("Error: Target directory " + target_dir + " already exists.");
+ return;
+ }
+
+ Directory.CreateDirectory (target_dir);
+
+ Assembly a = Assembly.LoadFrom (assembly);
+
+ Console.WriteLine ();
+ Console.WriteLine ("References (not followed):");
+ foreach (AssemblyName reference in a.GetReferencedAssemblies ())
+ Console.WriteLine (" " + reference.Name);
+ Console.WriteLine ();
+
+ dllname = Path.GetFileName (assembly);
+ AssemblyGen (a);
+
+ //we might not want to do this in future
+ File.Copy (dllname, target_dir + dllname);
+
+ string soname = "lib" + NsToFlat (Path.GetFileNameWithoutExtension (assembly)).ToLower () + ".so";
+
+ //create the static makefile
+ StreamWriter makefile = new StreamWriter (File.Create (target_dir + "Makefile"));
+ StreamReader sr = new StreamReader (Assembly.GetAssembly (typeof(cilc)).GetManifestResourceStream ("res-Makefile"));
+
+ makefile.Write (sr.ReadToEnd ());
+ sr.Close ();
+ makefile.Close ();
+
+ //create makefile defs
+ CodeWriter makefile_defs = new CodeWriter (target_dir + "defs.mk");
+ makefile_defs.Indenter = "\t";
+ makefile_defs.WriteLine ("ASSEMBLY = " + assembly);
+ makefile_defs.WriteLine ("SONAME = " + soname);
+ makefile_defs.WriteLine (@"OBJS = $(shell ls *.c | sed -e 's/\.c/.o/')");
+
+ if (extpkgs != String.Empty) {
+ makefile_defs.WriteLine ("EXTRAINCLUDES = $(shell pkg-config --cflags" + extpkgs + ")");
+ makefile_defs.WriteLine ("EXTRALIBS = $(shell pkg-config --libs" + extpkgs + ")");
+ }
+ makefile_defs.Close ();
+
+ Console.WriteLine ();
+
+ //identify hits on types that were registered too late
+ foreach (string tn in registered_types) {
+ if (registry_hits.Contains (tn)) {
+ Console.WriteLine ("Warning: " + tn + " was incorrectly registered after it was needed instead of before. Consider re-ordering.");
+ }
+ }
+
+ MakeReport (registry_hits, "Type registry missed hits", 20);
+ Console.WriteLine ();
+ //TODO: this count is now wrong
+ Console.WriteLine (registered_types.Count + " types generated/seen in " + namespaces.Length + " namespaces; " + warnings_ignored + " types ignored");
+ Console.WriteLine ();
+ }
+
+ static void MakeReport (Hashtable ctable, string desc, int num)
+ {
+ Console.WriteLine (desc + " (top " + (registry_hits.Count > num ? num : registry_hits.Count) + " of " + registry_hits.Count + "):");
+ string[] reg_keys = (string[]) (new ArrayList (ctable.Keys)).ToArray (typeof (string));
+ int[] reg_vals = (int[]) (new ArrayList (ctable.Values)).ToArray (typeof (int));
+ Array.Sort (reg_vals, reg_keys);
+
+ Array.Reverse (reg_vals);
+ Array.Reverse (reg_keys);
+
+ for (int i = 0 ; i != reg_keys.Length && i != num ; i++) {
+ Console.WriteLine (" " + reg_keys[i] + ": " + reg_vals[i]);
+ }
+ }
+
+ static int warnings_ignored = 0;
+
+ static void AssemblyGen (Assembly a)
+ {
+ Type[] types = a.GetTypes ();
+ Hashtable ns_types = new Hashtable ();
+
+ foreach (Type t in types) {
+ if (t.IsNotPublic) {
+ //Console.WriteLine ("Ignoring non-public type: " + t.Name);
+ //warnings_ignored++;
+ continue;
+ }
+
+ if (!t.IsClass && !t.IsInterface && !t.IsEnum) {
+ //Console.WriteLine ("Ignoring unrecognised type: " + t.Name);
+ warnings_ignored++;
+ continue;
+ }
+
+ RegisterType (t);
+
+ if (t.IsEnum)
+ RegisterByVal (t);
+
+ string tns = t.Namespace == null ? String.Empty : t.Namespace;
+
+ if (!ns_types.Contains (tns))
+ ns_types[tns] = new ArrayList ();
+
+ ((ArrayList) ns_types[tns]).Add (t);
+ }
+
+ namespaces = (string[]) (new ArrayList (ns_types.Keys)).ToArray (typeof (string));
+
+ foreach (DictionaryEntry de in ns_types)
+ NamespaceGen ((string) de.Key, (Type[]) ((ArrayList) de.Value).ToArray (typeof (Type)));
+ }
+
+ static string[] namespaces;
+
+ static void NamespaceGen (string given_ns, Type[] types)
+ {
+ //ns = types[0].Namespace;
+ ns = given_ns;
+
+ Hindex = new CodeWriter (target_dir + NsToFlat (ns).ToLower () + ".h");
+ Hdecls = new CodeWriter (target_dir + NsToFlat (ns).ToLower () + "types.h");
+ Cindex = new CodeWriter (target_dir + NsToFlat (ns).ToLower () + ".c");
+
+ string Hindex_id = "__" + NsToFlat (ns).ToUpper () + "_H__";
+ Hindex.WriteLine ("#ifndef " + Hindex_id);
+ Hindex.WriteLine ("#define " + Hindex_id);
+ Hindex.WriteLine ();
+
+ string Hdecls_id = "__" + NsToFlat (ns).ToUpper () + "_DECLS_H__";
+ Hdecls.WriteLine ("#ifndef " + Hdecls_id);
+ Hdecls.WriteLine ("#define " + Hdecls_id);
+ Hdecls.WriteLine ();
+
+ Cindex.WriteLine ("#include <glib.h>");
+ Cindex.WriteLine ("#include <glib-object.h>");
+ Cindex.WriteLine ("#include <mono/jit/jit.h>");
+ Cindex.WriteLine ();
+ Cindex.WriteLine ("#include <mono/metadata/object.h>");
+ Cindex.WriteLine ("#include <mono/metadata/debug-helpers.h>");
+ Cindex.WriteLine ("#include <mono/metadata/appdomain.h>");
+ Cindex.WriteLine ();
+ Cindex.WriteLine ("#ifdef CILC_BUNDLE");
+ Cindex.WriteLine ("#include \"bundle.h\"");
+ Cindex.WriteLine ("#endif");
+ Cindex.WriteLine ();
+
+ Cindex.WriteLine ("MonoDomain *" + NsToC (ns) + "_get_mono_domain (void)");
+ Cindex.WriteLine ("{");
+ Cindex.WriteLine ("static MonoDomain *domain = NULL;");
+ Cindex.WriteLine ("if (domain != NULL) return domain;");
+ Cindex.WriteLine ("mono_config_parse (NULL);");
+ Cindex.WriteLine ("domain = mono_jit_init (\"cilc\");");
+ Cindex.WriteLine ();
+ Cindex.WriteLine ("#ifdef CILC_BUNDLE");
+ Cindex.WriteLine ("mono_register_bundled_assemblies (bundled);");
+ Cindex.WriteLine ("#endif");
+ Cindex.WriteLine ();
+
+ Cindex.WriteLine ("return domain;");
+ Cindex.WriteLine ("}");
+ Cindex.WriteLine ();
+
+ Cindex.WriteLine ("MonoAssembly *" + NsToC (ns) + "_get_mono_assembly (void)");
+ Cindex.WriteLine ("{");
+ Cindex.WriteLine ("static MonoAssembly *assembly = NULL;");
+ Cindex.WriteLine ("if (assembly != NULL) return assembly;");
+ Cindex.WriteLine ("assembly = mono_domain_assembly_open (" + NsToC (ns) + "_get_mono_domain (), \"" + dllname + "\");");
+ Cindex.WriteLine ();
+
+ Cindex.WriteLine ("return assembly;");
+ Cindex.WriteLine ("}");
+ Cindex.WriteLine ();
+
+
+ Cindex.WriteLine ("MonoObject *" + NsToC (ns) + "_cilc_glib_gobject_get_mobject (GObject *_handle)");
+ Cindex.WriteLine ("{");
+ //FIXME: instantiate monobject if it doesn't exist
+ Cindex.WriteLine ("return g_object_get_data (G_OBJECT (" + "_handle" + "), \"mono-object\");");
+ Cindex.WriteLine ("}");
+
+ Cindex.WriteLine ("gpointer " + NsToC (ns) + "_cilc_glib_mobject_get_gobject (MonoObject *_mono_object)");
+ Cindex.WriteLine ("{");
+ Cindex.WriteLine ("static MonoAssembly *_mono_assembly = NULL;");
+ Cindex.WriteLine ("static MonoMethod *_mono_method = NULL;");
+ Cindex.WriteLine ("static MonoClass *_mono_class = NULL;");
+ Cindex.WriteLine ("gpointer *retval;");
+ Cindex.WriteLine ();
+ Cindex.WriteLine ("if (_mono_assembly == NULL) {");
+ Cindex.WriteLine ("_mono_assembly = mono_domain_assembly_open (" + NsToC (ns) + "_get_mono_domain (), \"" + "glib-sharp" + "\");");
+ Cindex.WriteLine ("}");
+ Cindex.WriteLine ("if (_mono_class == NULL) {");
+ Cindex.WriteLine ("_mono_class = (MonoClass*) mono_class_from_name ((MonoImage*) mono_assembly_get_image (_mono_assembly), \"GLib\", \"Object\");");
+ Cindex.WriteLine ("}");
+ Cindex.WriteLine ("if (_mono_method == NULL) {");
+ Cindex.WriteLine ("MonoMethodDesc *_mono_method_desc = mono_method_desc_new (\":get_Handle()\", FALSE);");
+ Cindex.WriteLine ("_mono_method = mono_method_desc_search_in_class (_mono_method_desc, _mono_class);");
+ Cindex.WriteLine ("}");
+ Cindex.WriteLine ();
+ Cindex.WriteLine ("retval = (gpointer *) mono_object_unbox (mono_runtime_invoke (_mono_method, _mono_object, NULL, NULL));");
+ Cindex.WriteLine ("return (gpointer ) *retval;");
+ Cindex.WriteLine ("}");
+ Cindex.WriteLine ();
+
+
+ Console.Write ("Generating sources in " + ns);
+ foreach (Type t in types) {
+ TypeGen (t);
+ Console.Write (".");
+ }
+
+ Console.WriteLine ();
+
+ Hindex.WriteLine ();
+ Hindex.WriteLine ("#endif /* " + Hindex_id + " */");
+
+ Hdecls.WriteLine ();
+ Hdecls.WriteLine ("#endif /* " + Hdecls_id + " */");
+
+ Cindex.Close ();
+ Hindex.Close ();
+ Hdecls.Close ();
+ }
+
+ static void TypeGen (Type t)
+ {
+ //TODO: we only handle ordinary classes for now
+ /*
+ else if (t.IsSubclassOf (typeof (Delegate))) {
+ Console.WriteLine ("Ignoring delegate: " + t.Name);
+ return;
+ }
+ */
+
+ cur_type = NsToC (ns) + "_" + CamelToC (t.Name);
+ //CurType = NsToFlat (ns) + t.Name;
+ CurType = CsTypeToG (t);
+ if (t.IsInterface)
+ CurTypeClass = GToGI (CurType);
+ else
+ CurTypeClass = GToGC (CurType);
+
+ //ns = t.Namespace;
+ string fname = NsToFlat (ns).ToLower () + t.Name.ToLower ();
+ C = new CodeWriter (target_dir + fname + ".c");
+ H = new CodeWriter (target_dir + fname + ".h");
+ Hindex.WriteLine ("#include <" + fname + ".h" + ">");
+
+
+ string H_id = "__" + NsToFlat (ns).ToUpper () + "_" + t.Name.ToUpper () + "_H__";
+ H.WriteLine ("#ifndef " + H_id);
+ H.WriteLine ("#define " + H_id);
+ H.WriteLine ();
+
+ H.WriteLine ("#include <glib.h>");
+ H.WriteLine ("#include <glib-object.h>");
+
+ foreach (string include in extincludes)
+ H.WriteLine ("#include <" + include + ">");
+
+ H.WriteLine ();
+
+ if (t.BaseType != null && IsRegistered (t.BaseType) && !IsExternal (t.BaseType))
+ H.WriteLine ("#include \"" + NsToFlat (t.BaseType.Namespace).ToLower () + t.BaseType.Name.ToLower () + ".h\"");
+
+ foreach (string ext_ns in namespaces)
+ H.WriteLine ("#include \"" + NsToFlat (ext_ns).ToLower () + "types.h\"");
+
+ H.WriteLine ();
+
+ if (disable_glib) {
+ H.WriteLine ("#ifdef __cplusplus");
+ H.WriteLine ("extern \"C\" {", false);
+ H.WriteLine ("#endif /* __cplusplus */");
+ } else {
+ H.WriteLine ("G_BEGIN_DECLS");
+ }
+
+ H.WriteLine ();
+
+ C.WriteLine ("#include \"" + fname + ".h" + "\"");
+
+ Type[] ifaces;
+ ifaces = t.GetInterfaces ();
+ foreach (Type iface in ifaces) {
+ if (!IsRegistered (iface))
+ continue;
+
+ string iface_fname = NsToFlat (ns).ToLower () + iface.Name.ToLower ();
+ C.WriteLine ("#include \"" + iface_fname + ".h" + "\"");
+ }
+
+ C.WriteLine ("#include <mono/metadata/object.h>");
+ C.WriteLine ("#include <mono/metadata/debug-helpers.h>");
+ C.WriteLine ("#include <mono/metadata/appdomain.h>");
+ C.WriteLine ();
+
+ if (t.IsClass)
+ ClassGen (t);
+ else if (t.IsInterface)
+ ClassGen (t);
+ else if (t.IsEnum)
+ EnumGen (t);
+
+ H.WriteLine ();
+
+ if (disable_glib) {
+ H.WriteLine ("#ifdef __cplusplus");
+ H.WriteLine ("}", false);
+ H.WriteLine ("#endif /* __cplusplus */");
+ } else {
+ H.WriteLine ("G_END_DECLS");
+ }
+
+ H.WriteLine ();
+
+ H.WriteLine ("#endif /* " + H_id + " */");
+
+ C.Close ();
+ H.Close ();
+ }
+
+ static void EnumGen (Type t)
+ {
+ //TODO: we needn't split out each enum into its own file
+
+ string gname = CsTypeToG (t);
+
+ Hdecls.WriteLine ("typedef enum");
+ Hdecls.WriteLine ("{");
+ C.WriteLine ("GType " + cur_type + "_get_type (void)", H, ";");
+ C.WriteLine ("{");
+ C.WriteLine ("static GType etype = 0;");
+ C.WriteLine ("if (etype == 0) {");
+ C.WriteLine ("static const GEnumValue values[] = {");
+ foreach (FieldInfo fi in t.GetFields (BindingFlags.Static|BindingFlags.Public)) {
+ string finame = (cur_type + "_" + CamelToC (fi.Name)).ToUpper ();
+ Hdecls.WriteLine (finame + ",");
+ C.WriteLine ("{ " + finame + ", \"" + finame + "\", \"" + CamelToC (fi.Name).Replace ("_", "-") + "\" },");
+ }
+ Hdecls.WriteLine ("} " + gname + ";");
+ Hdecls.WriteLine ();
+ C.WriteLine ("{ 0, NULL, NULL }");
+ C.WriteLine ("};");
+ C.WriteLine ("etype = g_enum_register_static (\"" + gname + "\", values);");
+ C.WriteLine ("}");
+ C.WriteLine ("return etype;");
+ C.WriteLine ("}");
+ }
+
+ static void ClassGen (Type t)
+ {
+ //TODO: what flags do we want for GetEvents and GetConstructors?
+
+ //events as signals
+ EventInfo[] events;
+ events = t.GetEvents (BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
+
+ //events as signals
+ MethodInfo[] methods;
+ methods = t.GetMethods (BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
+
+ Type[] ifaces;
+ ifaces = t.GetInterfaces ();
+
+ {
+ string NS = NsToC (ns).ToUpper ();
+ string T = CamelToC (t.Name).ToUpper ();
+ string NST = NS + "_" + T;
+ string NSTT = NS + "_TYPE_" + T;
+
+ H.WriteLine ("#define " + NSTT + " (" + cur_type + "_get_type ())");
+ H.WriteLine ("#define " + NST + "(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), " + NSTT + ", " + CurType + "))");
+ if (!t.IsInterface)
+ H.WriteLine ("#define " + NST + "_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), " + NSTT + ", " + CurTypeClass + "))");
+ H.WriteLine ("#define " + NS + "_IS_" + T + "(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), " + NSTT + "))");
+ if (!t.IsInterface)
+ H.WriteLine ("#define " + NS + "_IS_" + T + "_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), " + NSTT + "))");
+ if (t.IsInterface)
+ H.WriteLine ("#define " + NST + "_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), " + NSTT + ", " + CurTypeClass + "))");
+ else
+ H.WriteLine ("#define " + NST + "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " + NSTT + ", " + CurTypeClass + "))");
+ }
+
+ if (!C.IsDuplicate) {
+ Hdecls.WriteLine ("typedef struct _" + CurType + " " + CurType + ";");
+ Hdecls.WriteLine ("typedef struct _" + CurTypeClass + " " + CurTypeClass + ";");
+ Hdecls.WriteLine ();
+ }
+
+ H.WriteLine ();
+
+ string ParentName;
+ string ParentNameClass;
+
+ if (t.BaseType != null) {
+ ParentName = CsTypeToG (t.BaseType);
+ ParentNameClass = GToGC (ParentName);
+ } else {
+ ParentName = "GType";
+ if (t.IsInterface)
+ ParentNameClass = ParentName + "Interface";
+ else
+ ParentNameClass = ParentName + "Class";
+ }
+
+ //H.WriteLine ("typedef struct _" + CurType + " " + CurType + ";");
+
+ //H.WriteLine ();
+ //H.WriteLine ("typedef struct _" + CurType + "Class " + CurType + "Class;");
+ if (!t.IsInterface) {
+ H.WriteLine ("typedef struct _" + CurType + "Private " + CurType + "Private;");
+ H.WriteLine ();
+ H.WriteLine ("struct _" + CurType);
+ H.WriteLine ("{");
+
+ H.WriteLine (ParentName + " parent_instance;");
+ H.WriteLine (CurType + "Private *priv;");
+ H.WriteLine ("};");
+ H.WriteLine ();
+ }
+
+ H.WriteLine ("struct _" + CurTypeClass);
+ H.WriteLine ("{");
+ //H.WriteLine (ParentNameClass + " parent_class;");
+ H.WriteLine (ParentNameClass + " parent;");
+ if (t.BaseType != null)
+ H.WriteLine ("/* inherits " + t.BaseType.Namespace + " " + t.BaseType.Name + " */");
+
+ if (events.Length != 0) {
+ H.WriteLine ();
+ H.WriteLine ("/* signals */");
+
+ //FIXME: event arguments
+ foreach (EventInfo ei in events)
+ H.WriteLine ("void (* " + CamelToC (ei.Name) + ") (" + CurType + " *thiz" + ");");
+ }
+
+ if (t.IsInterface) {
+ if (methods.Length != 0) {
+ H.WriteLine ();
+ H.WriteLine ("/* vtable */");
+
+ //FIXME: method arguments
+ //string funcname = ToValidFuncName (CamelToC (imi.Name));
+ foreach (MethodInfo mi in methods)
+ H.WriteLine ("void (* " + CamelToC (mi.Name) + ") (" + CurType + " *thiz" + ");");
+ }
+ }
+
+ H.WriteLine ("};");
+ H.WriteLine ();
+
+ //generate c file
+
+ //private struct
+ C.WriteLine ("struct _" + CurType + "Private");
+ C.WriteLine ("{");
+ C.WriteLine ("MonoObject *mono_object;");
+ C.WriteLine ("};");
+
+ C.WriteLine ();
+
+ //events
+ if (events.Length != 0) {
+ C.WriteLine ("enum {");
+
+ foreach (EventInfo ei in events)
+ C.WriteLine (CamelToC (ei.Name).ToUpper () + ",");
+
+ C.WriteLine ("LAST_SIGNAL");
+ C.WriteLine ("};");
+ C.WriteLine ();
+ }
+
+ C.WriteLine ("static gpointer parent_class;");
+
+ if (events.Length == 0)
+ C.WriteLine ("static guint signals[0];");
+ else
+ C.WriteLine ("static guint signals[LAST_SIGNAL] = { 0 };");
+ C.WriteLine ();
+
+ C.WriteLine ("static MonoClass *" + cur_type + "_get_mono_class (void)");
+ C.WriteLine ("{");
+ C.WriteLine ("MonoAssembly *assembly;");
+ C.WriteLine ("static MonoClass *class = NULL;");
+ C.WriteLine ("if (class != NULL) return class;");
+
+ C.WriteLine ("assembly = (MonoAssembly*) " + NsToC (ns) + "_get_mono_assembly ();");
+ C.WriteLine ("class = (MonoClass*) mono_class_from_name ((MonoImage*) mono_assembly_get_image (assembly)" + ", \"" + ns + "\", \"" + t.Name + "\");");
+
+ C.WriteLine ("mono_class_init (class);");
+ C.WriteLine ();
+
+ C.WriteLine ("return class;");
+ C.WriteLine ("}");
+
+ C.WriteLine ();
+
+ wrap_gobject = TypeIsGObject (t);
+
+ //TODO: generate thin wrappers for interfaces
+
+ //generate constructors
+ ConstructorInfo[] constructors;
+ constructors = t.GetConstructors ();
+ foreach (ConstructorInfo c in constructors)
+ ConstructorGen (c, t);
+
+ //generate static methods
+ //MethodInfo[] methods;
+ methods = t.GetMethods (BindingFlags.Public|BindingFlags.Static|BindingFlags.DeclaredOnly);
+ foreach (MethodInfo m in methods)
+ MethodGen (m, t);
+
+ //generate instance methods
+ methods = t.GetMethods (BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
+ foreach (MethodInfo m in methods)
+ MethodGen (m, t);
+
+ C.WriteLine ();
+
+ if (t.IsClass) {
+ //generate the GObject init function
+ C.WriteLine ("static void " + cur_type + "_init (" + CurType + " *thiz" + ")");
+ C.WriteLine ("{");
+ C.WriteLine ("thiz->priv = g_new0 (" + CurType + "Private, 1);");
+ C.WriteLine ("}");
+
+ C.WriteLine ();
+
+ //generate the GObject class init function
+ C.WriteLine ("static void " + cur_type + "_class_init (" + CurTypeClass + " *klass" + ")");
+ C.WriteLine ("{");
+
+ C.WriteLine ("GObjectClass *object_class = G_OBJECT_CLASS (klass);");
+ C.WriteLine ("parent_class = g_type_class_peek_parent (klass);");
+ //C.WriteLine ("object_class->finalize = _finalize;");
+
+ foreach (EventInfo ei in events)
+ EventGen (ei, t);
+
+ C.WriteLine ("}");
+
+ C.WriteLine ();
+ }
+
+ if (ifaces.Length != 0) {
+ foreach (Type iface in ifaces) {
+ if (!IsRegistered (iface))
+ continue;
+
+ C.WriteLine ("static void " + NsToC (iface.Namespace) + "_" + CamelToC (iface.Name) + "_interface_init (" + GToGI (CsTypeToG (iface)) + " *iface" + ")");
+ C.WriteLine ("{");
+ foreach (MethodInfo imi in iface.GetMethods (BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly)) {
+ string funcname = ToValidFuncName (CamelToC (imi.Name));
+ C.WriteLine ("iface->" + funcname + " = " + cur_type + "_" + funcname + ";");
+ }
+ //TODO: properties etc.
+ C.WriteLine ("}");
+ C.WriteLine ();
+ }
+
+ }
+
+ //generate the GObject get_type function
+ C.WriteLine ("GType " + cur_type + "_get_type (void)", H, ";");
+ C.WriteLine ("{");
+ C.WriteLine ("static GType object_type = 0;");
+ C.WriteLine ("g_type_init ();");
+ C.WriteLine ();
+ C.WriteLine ("if (object_type) return object_type;");
+ C.WriteLine ();
+ C.WriteLine ("static const GTypeInfo object_info =");
+ C.WriteLine ("{");
+ C.WriteLine ("sizeof (" + CurTypeClass + "),");
+ C.WriteLine ("(GBaseInitFunc) NULL, /* base_init */");
+ C.WriteLine ("(GBaseFinalizeFunc) NULL, /* base_finalize */");
+ if (t.IsClass)
+ C.WriteLine ("(GClassInitFunc) " + cur_type + "_class_init, /* class_init */");
+ else
+ C.WriteLine ("NULL, /* class_init */");
+ C.WriteLine ("NULL, /* class_finalize */");
+ C.WriteLine ("NULL, /* class_data */");
+ if (t.IsClass)
+ C.WriteLine ("sizeof (" + CurType + "),");
+ else
+ C.WriteLine ("0,");
+ C.WriteLine ("0, /* n_preallocs */");
+ if (t.IsClass)
+ C.WriteLine ("(GInstanceInitFunc) " + cur_type + "_init, /* instance_init */");
+ else
+ C.WriteLine ("NULL, /* instance_init */");
+ C.WriteLine ("};");
+ C.WriteLine ();
+
+ foreach (Type iface in ifaces) {
+ if (!IsRegistered (iface))
+ continue;
+
+ C.WriteLine ("static const GInterfaceInfo " + CamelToC (iface.Namespace) + "_" + CamelToC (iface.Name) + "_info" + " =");
+ C.WriteLine ("{");
+ C.WriteLine ("(GInterfaceInitFunc) " + NsToC (iface.Namespace) + "_" + CamelToC (iface.Name) + "_interface_init, /* interface_init */");
+ C.WriteLine ("(GInterfaceFinalizeFunc) NULL, /* interface_finalize */");
+ C.WriteLine ("NULL, /* interface_data */");
+ C.WriteLine ("};");
+ C.WriteLine ();
+ }
+
+ if (t.BaseType != null) {
+ string parent_type = "G_TYPE_OBJECT";
+ if (IsRegistered (t.BaseType))
+ parent_type = NsToC (t.BaseType.Namespace).ToUpper () + "_TYPE_" + CamelToC (t.BaseType.Name).ToUpper ();
+
+ C.WriteLine ("object_type = g_type_register_static (" + parent_type + ", \"" + CurType + "\", &object_info, 0);");
+ }
+
+ foreach (Type iface in ifaces) {
+ if (!IsRegistered (iface))
+ continue;
+
+ C.WriteLine ("g_type_add_interface_static (object_type, " + NsToC (iface.Namespace).ToUpper () + "_TYPE_" + CamelToC (iface.Name).ToUpper () + ", &" + NsToC (iface.Namespace) + "_" + CamelToC (iface.Name) + "_info" + ");");
+ }
+ C.WriteLine ();
+ C.WriteLine ("return object_type;");
+ C.WriteLine ("}");
+ }
+
+ static bool TypeIsGObject (Type t)
+ {
+ if (t == null)
+ return false;
+
+ if (t.FullName == "GLib.Object")
+ return true;
+
+ return TypeIsGObject (t.BaseType);
+ }
+
+
+ //FIXME: clean up this mess with hits as the type registry uses strings
+
+ static ArrayList registered_types = new ArrayList ();
+ static ArrayList byval_types = new ArrayList ();
+ static ArrayList external_types = new ArrayList ();
+ static Hashtable registry_hits = new Hashtable ();
+
+ static bool IsRegisteredByVal (Type t)
+ {
+ return byval_types.Contains (CsTypeToFlat (t));
+ }
+
+ static bool IsExternal (Type t)
+ {
+ return external_types.Contains (CsTypeToFlat (t));
+ }
+
+ static void RegisterByVal (string tn)
+ {
+ //TODO: warn on dupes
+ byval_types.Add (tn);
+ }
+
+ static void RegisterByVal (Type t)
+ {
+ RegisterByVal (CsTypeToFlat (t));
+ }
+
+ static bool IsRegistered (String tn)
+ {
+ return registered_types.Contains (tn);
+ }
+
+ static bool IsRegistered (Type t)
+ {
+ return IsRegistered (t, true);
+ }
+
+ static bool IsRegistered (Type t, bool log_hits)
+ {
+ return IsRegistered (CsTypeToFlat (t), true);
+ }
+
+ static bool IsRegistered (string tn, bool log_hits)
+ {
+ //bool isreg = registered_types.Contains (t);
+ bool isreg = registered_types.Contains (tn);
+
+ if (!isreg && log_hits) {
+ HitRegistry (tn);
+ }
+
+ return isreg;
+ }
+
+ static void HitRegistry (string tn)
+ {
+ //FIXME: ignore handled primitive types here
+
+ if (!registry_hits.Contains (tn)) {
+ int count = 0;
+ registry_hits[tn] = count;
+ }
+
+ registry_hits[tn] = (int) registry_hits[tn] + 1;
+ }
+
+ static bool RegisterG (string G)
+ {
+ if (IsRegistered (G, false)) {
+ Console.WriteLine ("Warning: unmanaged type " + G + " already registered! Can't re-register.");
+ return false;
+ }
+
+ external_types.Add (G);
+ registered_types.Add (G);
+ return true;
+ }
+
+ static string NewG (string G)
+ {
+ if (IsRegistered (G, false))
+ {
+ Console.WriteLine ("Warning: type " + G + " already registered! Appending 'Extra' and trying again");
+ Console.WriteLine ();
+ return NewG (G + "Extra"); //FIXME: handle this properly
+ }
+
+ registered_types.Add (G);
+ return (G);
+ }
+
+ static string CsTypeToFlat (Type t) //TODO: use this everywhere
+ {
+ //TODO: check registry to see if t.Name's name has been changed during NewG.
+ //if it's not in the registry, continue as usual
+
+ return NsToFlat (t.Namespace) + t.Name;
+ }
+
+ static void RegisterType (Type t)
+ {
+ NewG (CsTypeToFlat (t));
+ }
+
+ /*
+ static string NewG (Type t)
+ {
+ return NewG (CsTypeToFlat (t));
+ }
+ */
+
+ static string CsTypeToG (Type t)
+ {
+ if (IsRegistered (t))
+ return CsTypeToFlat (t);
+
+ return "GObject";
+ }
+
+ static string GToGI (string G)
+ {
+ string possGC = G + "Iface";
+ //TODO: conflict resolution
+
+ return possGC;
+ }
+
+ //static string CsTypeToGC (String tn)
+ static string GToGC (string G)
+ {
+ string possGC = G + "Class";
+
+ if (IsRegistered (possGC))
+ return GToGC (G + "Object");
+ else
+ return possGC;
+ }
+
+ static string CsTypeToC (Type t)
+ {
+ //TODO: use this method everywhere
+
+ switch (t.FullName)
+ {
+ case "System.String":
+ return "const gchar *";
+
+ case "System.Int32":
+ return "gint ";
+
+ case "System.UInt32":
+ return "guint ";
+
+ case "System.Boolean":
+ return "gboolean ";
+
+ case "System.IntPtr":
+ return "gpointer ";
+
+ case "System.Char":
+ return "guint16 ";
+
+ case "System.SByte":
+ return "gint8 ";
+
+ case "System.Byte":
+ return "guint8 ";
+
+ case "System.Double":
+ return "gdouble ";
+
+ //questionable
+ case "System.EventHandler":
+ case "System.MulticastDelegate":
+ return "GCallback ";
+ }
+
+ if (IsRegistered (t) && IsRegisteredByVal (t))
+ return CsTypeToFlat (t) + " ";
+
+ if (t == typeof (void))
+ return "void ";
+
+ return CsTypeToG (t) + " *";
+ }
+
+ static void EventGen (EventInfo ei, Type t)
+ {
+ //Console.WriteLine ("TODO: event: " + ei.Name);
+ //Console.WriteLine ("\t" + CamelToC (ei.Name));
+ string name = CamelToC (ei.Name);
+
+ C.WriteLine ();
+ C.WriteLine ("signals[" + name.ToUpper () + "] = g_signal_new (");
+ C.WriteLine ("\"" + name + "\",");
+ C.WriteLine ("G_OBJECT_CLASS_TYPE (object_class),");
+ C.WriteLine ("G_SIGNAL_RUN_LAST,");
+ C.WriteLine ("G_STRUCT_OFFSET (" + CurTypeClass + ", " + name + "),");
+ C.WriteLine ("NULL, NULL,");
+ C.WriteLine ("g_cclosure_marshal_VOID__VOID,");
+ C.WriteLine ("G_TYPE_NONE, 0");
+ C.WriteLine (");");
+ }
+
+ static void ConstructorGen (ConstructorInfo c, Type t)
+ {
+ ParameterInfo[] parameters = c.GetParameters ();
+ FunctionGen (parameters, (MethodBase) c, t, null, true);
+ }
+
+ static void MethodGen (MethodInfo m, Type t)
+ {
+ ParameterInfo[] parameters = m.GetParameters ();
+ FunctionGen (parameters, (MethodBase) m, t, m.ReturnType, false);
+ }
+
+ static readonly string[] keywords = {"auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"};
+
+ static string KeywordAvoid (string s)
+ {
+ if (Array.IndexOf (keywords, s.ToLower ()) != -1)
+ return KeywordAvoid ("_" + s);
+
+ return s;
+ }
+
+ static string ToValidFuncName (string name)
+ {
+ //avoid generated function name conflicts with internal functions
+
+ switch (name.ToLower ()) {
+ case "init":
+ return "initialize";
+ case "class_init":
+ return "class_initialize";
+ case "get_type":
+ return "retrieve_type";
+ default:
+ return name;
+ }
+ }
+
+ static bool wrap_gobject = false;
+
+ static void FunctionGen (ParameterInfo[] parameters, MethodBase m, Type t, Type ret_type, bool ctor)
+ {
+ string myargs = String.Empty;
+ bool has_return = !ctor && ret_type != null && ret_type != typeof (void);
+ bool stat = m.IsStatic;
+
+ string mytype, rettype;
+
+ mytype = CurType + " *";
+
+ if (ctor) {
+ has_return = true;
+ rettype = mytype;
+ stat = true;
+ } else
+ rettype = CsTypeToC (ret_type);
+
+ string params_arg = "NULL";
+ if (parameters.Length != 0)
+ params_arg = "_mono_params";
+
+ string instance = "thiz";
+ string mono_obj = "NULL";
+
+ if (ctor || !stat)
+ mono_obj = "_mono_object";
+
+ //if (ctor || !stat)
+ // mono_obj = instance + "->priv->mono_object";
+
+ if (!stat) {
+ myargs = mytype + instance;
+ if (parameters.Length > 0) myargs += ", ";
+ }
+
+ string myname;
+
+ myname = cur_type + "_";
+ if (ctor)
+ myname += "new";
+ else
+ myname += ToValidFuncName (CamelToC (m.Name));
+
+ //handle overloaded methods
+ //TODO: generate an alias function for the default ctor etc.
+
+ //TODO: how do we choose the default ctor/method overload? perhaps the
+ //first/shortest, but we need scope for this
+ //perhaps use DefaultMemberAttribute, Type.GetDefaultMembers
+
+ if (funcs_done.Contains (myname)) {
+ for (int i = 0 ; i < parameters.Length ; i++) {
+ ParameterInfo p = parameters[i];
+
+ if (i == 0)
+ myname += "_with_";
+ else
+ myname += "_and_";
+
+ myname += KeywordAvoid (p.Name);
+ }
+ }
+
+ if (funcs_done.Contains (myname))
+ return;
+
+ funcs_done.Add (myname);
+
+ //handle the parameters
+ string mycsargs = String.Empty;
+
+ for (int i = 0 ; i < parameters.Length ; i++) {
+ ParameterInfo p = parameters[i];
+ mycsargs += GetMonoType (Type.GetTypeCode (p.ParameterType));
+ myargs += CsTypeToC (p.ParameterType) + KeywordAvoid (p.Name);
+ if (i != parameters.Length - 1) {
+ mycsargs += ",";
+ myargs += ", ";
+ }
+ }
+
+ if (myargs == String.Empty)
+ myargs = "void";
+
+ C.WriteLine ();
+
+ C.WriteLine (rettype + myname + " (" + myargs + ")", H, ";");
+
+ C.WriteLine ("{");
+
+ C.WriteLine ("static MonoMethod *_mono_method = NULL;");
+
+ if (ctor || !stat)
+ C.WriteLine ("MonoObject *" + mono_obj + ";");
+
+ if (parameters.Length != 0) C.WriteLine ("gpointer " + params_arg + "[" + parameters.Length + "];");
+
+ if (ctor) {
+ C.WriteLine (CurType + " *" + instance + ";");
+ }
+
+ if (!ctor && !stat) {
+ C.WriteLine ();
+ C.WriteLine (mono_obj + " = g_object_get_data (G_OBJECT (" + instance + "), \"mono-object\");");
+ }
+
+ C.WriteLine ();
+
+ C.WriteLine ("if (_mono_method == NULL) {");
+
+ if (ctor)
+ C.WriteLine ("MonoMethodDesc *_mono_method_desc = mono_method_desc_new (\":.ctor(" + mycsargs + ")\", FALSE);");
+ else
+ C.WriteLine ("MonoMethodDesc *_mono_method_desc = mono_method_desc_new (\":" + m.Name + "(" + mycsargs + ")" + "\", FALSE);");
+
+
+ C.WriteLine ("_mono_method = mono_method_desc_search_in_class (_mono_method_desc, " + cur_type + "_get_mono_class ());");
+
+ C.WriteLine ("}");
+ C.WriteLine ();
+
+ //assign the parameters
+ for (int i = 0 ; i < parameters.Length ; i++) {
+ ParameterInfo p = parameters[i];
+ C.WriteLine (params_arg + "[" + i + "] = " + GetMonoVal (p.ParameterType, KeywordAvoid (p.Name)) + ";");
+ }
+
+ if (parameters.Length != 0)
+ C.WriteLine ();
+
+ if (ctor)
+ C.WriteLine (mono_obj + " = (MonoObject*) mono_object_new ((MonoDomain*) " + NsToC (ns) + "_get_mono_domain ()" + ", " + cur_type + "_get_mono_class ());");
+
+ //delegates are a special case as we want their constructor to take a function pointer
+ if (ctor && t.IsSubclassOf (typeof (MulticastDelegate))) {
+ C.WriteLine ("mono_delegate_ctor (" + mono_obj + ", object, method);");
+ } else {
+ //code to invoke the method
+
+ if (!ctor && has_return)
+ if (IsRegisteredByVal (ret_type)) {
+ C.WriteLine ("{");
+ C.WriteLine (rettype + "* retval = (" + rettype + "*) mono_object_unbox (mono_runtime_invoke (_mono_method, " + mono_obj + ", " + params_arg + ", NULL));");
+ C.WriteLine ("return (" + rettype + ") *retval;");
+ C.WriteLine ("}");
+ } else if (rettype == "const gchar *")
+ {
+ //convert the MonoString to a UTF8 before returning
+ C.WriteLine ("return (" + rettype + ") mono_string_to_utf8 ((MonoString*) mono_runtime_invoke (_mono_method, " + mono_obj + ", " + params_arg + ", NULL));");
+ } else {
+ //TODO: this isn't right
+ C.WriteLine ("return (" + rettype + ") mono_runtime_invoke (_mono_method, " + mono_obj + ", " + params_arg + ", NULL);");
+ }
+ else
+ C.WriteLine ("mono_runtime_invoke (_mono_method, " + mono_obj + ", " + params_arg + ", NULL);");
+ }
+
+ if (ctor) {
+ C.WriteLine ();
+
+ //TODO: use ->priv, not data for better performance if not wrapping a gobject
+ if (wrap_gobject)
+ C.WriteLine (instance + " = (" + CurType + " *) " + NsToC (ns) + "_cilc_glib_mobject_get_gobject (" + mono_obj + ");");
+ else
+ C.WriteLine (instance + " = (" + CurType + " *) g_object_new (" + NsToC (ns).ToUpper () + "_TYPE_" + CamelToC (t.Name).ToUpper () + ", NULL);");
+
+ C.WriteLine ("g_object_set_data (G_OBJECT (" + instance + "), \"mono-object\", " + mono_obj + ");");
+ C.WriteLine ();
+ C.WriteLine ("return " + instance + ";");
+ }
+
+ C.WriteLine ("}");
+ }
+
+ static string GetMonoType (TypeCode tc)
+ {
+ //see mcs/class/corlib/System/TypeCode.cs
+ //see mono/mono/dis/get.c
+
+ switch (tc)
+ {
+ case TypeCode.Int32:
+ return "int";
+
+ case TypeCode.String:
+ return "string";
+
+ default: //TODO: construct signature based on mono docs
+ return tc.ToString ().ToLower ();
+ }
+ }
+
+ static string GetMonoVal (Type t, string name)
+ {
+ string type = t.FullName;
+
+ if (TypeIsGObject (t))
+ return "(gpointer*) " + NsToC (ns) + "_cilc_glib_gobject_get_mobject (G_OBJECT (" + name + "))";
+
+ switch (type) {
+ case "System.String":
+ return "(gpointer*) mono_string_new ((MonoDomain*) mono_domain_get (), " + name + ")";
+
+ case "System.Int32":
+ return "&" + name;
+
+ default:
+ return "&" + name;
+ }
+ }
+
+ static string NsToC (string s)
+ {
+ if (s == null)
+ return String.Empty;
+
+ s = s.Replace ('.', '_');
+ return CamelToC (s);
+ }
+
+ static string NsToFlat (string s)
+ {
+ if (s == null)
+ return String.Empty;
+
+ s = s.Replace (".", String.Empty);
+ return s;
+ }
+
+ static string CamelToC (string s)
+ {
+ //converts camel case to c-style
+
+ string o = String.Empty;
+
+ bool prev_is_cap = true;
+
+ foreach (char c in s) {
+ char cl = c.ToString ().ToLower ()[0];
+ bool is_cap = c != cl;
+
+ if (!prev_is_cap && is_cap) {
+ o += "_";
+ }
+
+ o += cl;
+ prev_is_cap = is_cap;
+
+ if (c == '_')
+ prev_is_cap = true;
+ }
+
+ return o;
+ }
+}
View
2 cilc/cilc.exe.sources
@@ -0,0 +1,2 @@
+cilc.cs
+CodeWriter.cs
View
54 cilc/demo.c
@@ -0,0 +1,54 @@
+#include <glib.h>
+#include <glib/gprintf.h>
+#include "demo.h"
+
+int main () {
+ DemoTest *my_test;
+ const gchar *mystr;
+ int num;
+ gdouble num_dbl;
+ DemoDrink drink;
+ //GEnumClass *enum_class;
+
+ //run a static method
+ demo_test_static_method ();
+
+ //create an object instance
+ my_test = demo_test_new ();
+
+ //run an instance method
+ demo_test_increment (my_test);
+
+ //run an instance method with arguments
+ demo_test_add_number (my_test, 2);
+
+ //run an instance method with arguments
+ demo_test_echo (my_test, "hello from c");
+
+ //run an instance method with arguments and a return string
+ mystr = demo_test_make_upper (my_test, "lower to upper");
+ g_printf ("Lower to upper: %s\n", mystr);
+
+ //run a property set accessor
+ demo_test_set_title (my_test, "set property from c");
+
+ //run a property get accessor
+ mystr = demo_test_get_title (my_test);
+ g_printf ("Title property: %s\n", mystr);
+
+ num = demo_test_get_value (my_test);
+ g_printf ("The counter's value is %d\n", num);
+
+ num_dbl = demo_test_get_double_value (my_test);
+ g_printf ("The counter's double value is %.16f\n", num_dbl);
+
+ drink = demo_test_pick_drink ();
+ //enum_class = g_type_class_peek (demo_drink_get_type ());
+ //g_enum_get_value (enum_class, drink);
+ //g_printf ("%d\n", drink);
+
+ //TODO: return value
+ //g_printf ("returned string: %s\n", demo_test_get_title (my_test));
+
+ return 0;
+}
View
46 cilc/res-Makefile
@@ -0,0 +1,46 @@
+include defs.mk
+
+LIBNAME = $(shell echo $(basename $(SONAME)) | sed -e 's/^lib//')
+HTARGET = $(prefix)/include/$(LIBNAME)/
+LIBTARGET = $(prefix)/lib/
+
+CFLAGS += -static -fpic $(shell pkg-config --cflags glib-2.0 gobject-2.0 mono) $(EXTRAINCLUDES) -I.
+
+ifdef bundle
+EXTRAOBJS = bundle.o
+CFLAGS += -DCILC_BUNDLE
+EXTRATARGETS = bundle.h
+endif
+
+ifndef prefix
+prefix = $(CWD)
+endif
+
+all: $(SONAME)
+
+$(SONAME): $(EXTRAOBJS) $(OBJS)
+ gcc -Wall -fpic -shared `pkg-config --libs glib-2.0 gobject-2.0 mono` -lpthread $(EXTRAOBJS) $(OBJS) $(EXTRALIBS) -o $(SONAME)
+
+$(LIBNAME).o: $(EXTRATARGETS)
+
+bundle.o bundle.h: $(ASSEMBLY)
+ mkbundle -c -o bundle.c.tmp -oo bundle.o $(ASSEMBLY)
+ rm -f xx*
+ csplit bundle.c.tmp /mono_main/
+ mv xx00 bundle.h
+ rm -f xx*
+ rm -f bundle.c.tmp
+
+install_libs: $(SONAME)
+ mkdir -p $(LIBTARGET)
+ install -s $(SONAME) $(LIBTARGET)
+
+install_headers: *.h
+ mkdir -p $(HTARGET)
+ install *.h $(HTARGET)
+
+install: install_libs install_headers
+
+clean:
+ rm -rf core *~ *.o *.so bundle.h
+

0 comments on commit b6200d1

Please sign in to comment.