3 // author: Dan Lewis (dihlewis@yahoo.co.uk)
8 // Tool for generating C prototypes and structures suitable for use by the runtime
9 // from a list of supplied assemblies. See ictool-config.xml for configuration details.
15 using System
.Reflection
;
16 using System
.Collections
;
19 public static void Main (string[] args
) {
20 string filename
= "ictool-config.xml";
21 if (args
.Length
== 1) {
24 else if (args
.Length
> 1) {
25 Console
.Error
.WriteLine ("Usage: ictool.exe [config.xml]");
26 Environment
.Exit (-1);
30 Stream config
= File
.OpenRead (filename
);
34 Console
.Error
.WriteLine ("Error: could not read configuration file.");
35 Console
.Error
.WriteLine (e
);
36 Environment
.Exit (-1);
45 private static void EmitPrototypes () {
46 StreamWriter methods_file
= GetOutputFile ("methods");
47 StreamWriter map_file
= GetOutputFile ("map");
51 methods_file
.WriteLine ("#include \"{0}\"\n", output_files
["types"]);
52 map_file
.WriteLine ("#include \"{0}\"\n", output_files
["methods"]);
55 "static gpointer icall_map [] = {\n\t"
58 ArrayList map_lines
= new ArrayList ();
60 BindingFlags binding
=
61 BindingFlags
.DeclaredOnly
|
62 BindingFlags
.Instance
|
65 BindingFlags
.NonPublic
;
67 foreach (Type type
in types
.Values
) {
68 bool has_icall
= false;
69 MethodInfo
[] methods
= type
.GetMethods (binding
);
71 foreach (MethodInfo method
in methods
) {
72 if (IsInternalCall (method
)) {
81 methods_file
.WriteLine ("\n/* {0} */\n", type
.FullName
);
82 //map_lines.Add (String.Format ("\n/* {0} */\n", type.FullName));
84 foreach (MethodInfo method
in methods
) {
85 if (!IsInternalCall (method
))
90 string func_name
= String
.Format ("ves_icall_{0}_{1}",
96 func_name
= func_name
.Replace ('.', '_');
100 map_lines
.Add (String
.Format (
103 type
.FullName
.Replace ('.', '_'),
110 ArrayList args
= new ArrayList ();
112 // FIXME: return types that are structs need to be inserted
113 // into the argument list as a destination pointer
115 // object/value instance pointer
117 if (IsInstanceMethod (method
)) {
118 args
.Add (String
.Format (
121 peer_map
.GetPeer (method
.DeclaringType
).GetTypedef (1),
128 foreach (ParameterInfo param
in method
.GetParameters ()) {
129 Type arg_type
= param
.ParameterType
;
132 if (arg_type
.IsByRef
) {
133 arg_type
= arg_type
.GetElementType ();
137 Peer arg_peer
= peer_map
.GetPeer (arg_type
);
138 if (!arg_peer
.IsValueType
)
141 args
.Add (String
.Format ("{0}{1}", arg_peer
.GetTypedef (refs
), param
.Name
));
144 Peer ret
= peer_map
.GetPeer (method
.ReturnType
);
145 methods_file
.WriteLine ("static {0}", ret
.GetTypedef (ret
.IsValueType
? 0 : 1));
146 methods_file
.WriteLine ("{0} ({1});",
151 methods_file
.WriteLine ();
156 methods_file
.Close ();
158 // write map file and close it
161 "{0}\n}};\n", Join (",\n\t", map_lines
)
167 private static bool IsInternalCall (MethodInfo meth
) {
168 return (meth
.GetMethodImplementationFlags () & MethodImplAttributes
.InternalCall
) != 0;
171 private static bool IsInstanceMethod (MethodInfo meth
) {
172 return (meth
.CallingConvention
& CallingConventions
.HasThis
) != 0;
175 private static void EmitStructures () {
176 StreamWriter file
= GetOutputFile ("types");
178 // build dependency graph
180 DependencyGraph dg
= new DependencyGraph ();
181 foreach (Peer peer
in peer_map
.Peers
) {
184 // peer depends on nearest base
186 if (peer
.NearestBase
!= null)
187 dg
.AddEdge (peer
.NearestBase
, peer
);
189 // peer depends on any value types used for fields
191 foreach (PeerField field
in peer
.Fields
) {
192 if (field
.Peer
.IsValueType
)
193 dg
.AddEdge (field
.Peer
, peer
);
197 // write structures in order
199 foreach (Peer peer
in dg
.TopologicalSort ()) {
204 file
.WriteLine ("typedef {0} {1};", peer
.UnderlyingPeer
.Name
, peer
.Name
);
205 file
.WriteLine ("enum _{0} {{", peer
.Name
);
207 ArrayList enum_lines
= new ArrayList ();
208 foreach (string name
in peer
.EnumConstants
.Keys
) {
209 enum_lines
.Add (String
.Format ("\t{0}_{1} = {2}",
212 peer
.EnumConstants
[name
]
216 file
.WriteLine ("{0}\n}};\n", Join (",\n", enum_lines
));
219 file
.WriteLine ("typedef struct _{0} {{", peer
.Name
);
223 if (peer
.NearestBase
!= null) {
224 file
.WriteLine ("\t{0} __base;", peer
.NearestBase
.Name
);
230 foreach (PeerField field
in peer
.Fields
) {
231 bool use_struct
= true;
232 if (field
.Peer
.IsValueType
|| field
.Peer
.IsOpaque
)
235 file
.WriteLine ("\t{0}{1}{2};",
236 use_struct
? "struct _" : "",
237 field
.Peer
.GetTypedef (field
.Peer
.IsValueType
? 0 : 1),
242 file
.WriteLine ("}} {0};\n", peer
.Name
);
247 private static void LoadAssemblies () {
248 types
= new Hashtable ();
250 foreach (string filename
in assemblies
) {
255 FileInfo info
= null;
256 foreach (string path
in assembly_paths
) {
257 info
= new FileInfo (Path
.Combine (path
, filename
));
263 Console
.Error
.WriteLine ("Error: assembly {0} not found.", filename
);
264 Environment
.Exit (-1);
269 assembly
= Assembly
.LoadFrom (info
.FullName
);
273 ArrayList loaded_types
;
276 loaded_types
= new ArrayList (assembly
.GetTypes ());
278 catch (ReflectionTypeLoadException e
) {
279 loaded_types
= new ArrayList ();
280 foreach (Type type
in e
.Types
) {
282 loaded_types
.Add (type
);
285 foreach (Exception f
in e
.LoaderExceptions
) {
286 if (f
is TypeLoadException
) {
287 Console
.Error
.WriteLine ("Warning: {0} could not be loaded from assembly {1}.",
288 ((TypeLoadException
)f
).TypeName
,
293 Console
.Error
.WriteLine (f
);
297 // add to type dictionary
299 foreach (Type type
in loaded_types
) {
300 if (!types
.Contains (type
.FullName
))
301 types
.Add (type
.FullName
, type
);
306 private static void Configure (Stream input
) {
307 XmlDocument doc
= new XmlDocument ();
312 assembly_paths
= new ArrayList ();
313 assembly_paths
.Add (".");
315 foreach (XmlNode node
in doc
.SelectNodes ("config/assemblypath")) {
316 assembly_paths
.Add (node
.Attributes
["path"].Value
);
319 assemblies
= new ArrayList ();
320 foreach (XmlNode node
in doc
.SelectNodes ("config/assembly")) {
321 assemblies
.Add (node
.Attributes
["file"].Value
);
329 XmlNode path_node
= doc
.SelectSingleNode ("config/outputpath");
330 if (path_node
!= null)
331 output_path
= path_node
.Attributes
["path"].Value
;
333 output_files
= new Hashtable ();
334 output_includes
= new Hashtable ();
335 foreach (XmlNode node
in doc
.SelectNodes ("config/outputfile")) {
336 string name
= node
.Attributes
["name"].Value
;
337 output_files
.Add (name
, node
.Attributes
["file"].Value
);
339 foreach (XmlNode child
in node
.ChildNodes
) {
340 if (child
.Name
== "include")
341 output_includes
[name
] = child
.InnerText
;
347 peer_map
= new PeerMap ();
348 foreach (XmlNode node
in doc
.SelectNodes ("config/typemap/namespace")) {
349 string ns
= node
.Attributes
["name"].Value
;
351 foreach (XmlNode child
in node
.ChildNodes
) {
352 if (child
.Name
== "type") {
353 string name
= child
.Attributes
["name"].Value
;
354 string peer_name
= child
.Attributes
["peer"].Value
;
357 if (child
.Attributes
["opaque"] != null && child
.Attributes
["opaque"].Value
== "true")
360 String fullname
= String
.Format ("{0}.{1}", ns
, name
);
363 if (child
.Attributes
["default"] != null && child
.Attributes
["default"].Value
== "true")
364 type
= Type
.GetType (fullname
);
366 type
= (Type
)types
[fullname
];
369 peer_map
.Add (new Peer (type
, peer_name
, opaque
));
374 peer_map
.ResolvePeers ();
377 private static StreamWriter
GetOutputFile (string name
) {
378 string filename
= Path
.Combine (output_path
, (string)output_files
[name
]);
379 StreamWriter file
= File
.CreateText (filename
);
380 file
.AutoFlush
= true;
389 * This file was automatically generated on {1} by ictool.exe from
390 * the following assemblies:
397 DateTime
.Now
.ToString ("d"),
398 Join (", ", assemblies
)
401 if (output_includes
.Contains (name
)) {
402 file
.WriteLine (output_includes
[name
]);
409 private static string Join (string separator
, ICollection values
) {
410 // note to microsoft: please implement this in String :)
412 string[] strs
= new string[values
.Count
];
415 foreach (object value in values
)
416 strs
[i
++] = value.ToString ();
418 return String
.Join (separator
, strs
);
421 private static ArrayList assembly_paths
;
422 private static ArrayList assemblies
;
423 private static string output_path
;
424 private static Hashtable output_files
;
425 private static Hashtable output_includes
;
426 private static PeerMap peer_map
;
427 private static Hashtable types
;