public Preprocessor(Configuration options) { // primary source file is the one that wave is run against // to produce a single preprocessed monolithic header primarySource = Environment.ExpandEnvironmentVariables(options.PrimaryHeader); wavePath = "wave.exe"; // -E indicates default naming scheme for output file (e.g. input.i) // -m macros.txt creates a separate file containing a list of all found macros // --variadics enables macros with empty argument lists (necessary for some win32 header) // -S adds an include path (specified in our config file) // -D adds a predefined macro (several are necessary to compile the win32 headers) // -r forcibly ignores a given definition // final argument is the primary header file to run against var builder = new StringBuilder("-E -m macros.txt --variadics "); foreach (var path in options.IncludePaths) builder.Append("-S \"").Append(Environment.ExpandEnvironmentVariables(path)).Append("\" "); foreach (var symbol in options.DefineSymbols) builder.Append("-D ").Append(symbol).Append(" "); foreach (var symbol in options.IgnoreSymbols) builder.Append("-r ").Append(symbol).Append(" "); Source = Path.GetFileName(primarySource); builder.AppendFormat("\"{0}\"", Source); arguments = builder.ToString(); }
static void RunGenerator(ApiModel api, Configuration configuration) { var templateDirectory = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Templates"); var templateEngine = new TemplateEngine(new[] { templateDirectory }); templateEngine.RegisterCallback("ApiNamespace", (e, s) => api.Name); templateEngine.RegisterCallback("ApiName", (e, s) => TemplateCallbacks.GetApiClassName(api)); templateEngine.RegisterCallback("ApiDll", (e, s) => TemplateCallbacks.GetApiDllName(api)); templateEngine.RegisterCallbacks(typeof(TemplateCallbacks)); var outputDirectory = configuration.GeneratorOutputPath; if (!Directory.Exists(outputDirectory)) Directory.CreateDirectory(outputDirectory); ApplyTemplate(api, outputDirectory, templateEngine, "Api"); ApplyTemplate(api.Enumerations, outputDirectory, templateEngine, "Enumeration"); ApplyTemplate(api.Structures, outputDirectory, templateEngine, "Structure"); ApplyTemplate(api.Interfaces, outputDirectory, templateEngine, "Interface"); BuildTrampolineAssembly(api, outputDirectory, string.Format("{0}.Trampoline", api.Name)); }
static JObject RunParser(Configuration configuration) { // run boost::wave on the primary source file to get a preprocessed file and a list of macros var preprocessor = new Preprocessor(configuration); Console.WriteLine(preprocessor.Run()); // before parsing, run some transformations on the preprocessed file to cut down on the size needed to be examined // this includes dropping any source that is not from the given primary or ancillary // sources, which is indicated in the preprocessed file by #line directives var source = preprocessor.Source; var rawSources = configuration.AdditionalHeaders.Concat(new[] { Path.Combine(Directory.GetCurrentDirectory(), source) }); var relevantSources = new List<string>(); foreach (string s in rawSources) relevantSources.Add(Environment.ExpandEnvironmentVariables(s)); source = Path.ChangeExtension(source, ".i"); Preprocessor.PostTransform(source, new HashSet<string>(relevantSources)); // run the parser on the preprocessed file to generate a model of the file in memory var grammarFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "header_grammar.cgt"); var parser = new HeaderParser(grammarFile); var root = parser.Parse(source).ToXml(); var json = ModelXml.Transform(root); // add a dependency to the base SlimDX.json file json.Add(new JProperty("dependencies", new JArray(new JValue("../SlimDX/SlimDX.json")))); return json; }
/// <summary> /// The application's entry point. /// </summary> /// <param name="arguments">The command line arguments.</param> static void Main(string[] arguments) { if (arguments.Length == 0) throw new InvalidOperationException("Missing configuration file path."); var configuration = new Configuration(arguments[0]); var searchPaths = new HashSet<string>(); var json = RunParser(configuration); foreach (var layer in configuration.Layers) { JObject current = null; current = JObject.Parse(File.ReadAllText(layer)); searchPaths.Add(Path.GetDirectoryName(Path.GetFullPath(layer))); // combine the current layer with the base if (json == null) json = current; else CompositingEngine.Compose(json, current); } var generatedModelFile = Path.Combine(configuration.GeneratorOutputPath, configuration.ApiName + ".json"); File.WriteAllText(generatedModelFile, json.ToString()); // run the generator on the composed Json model var api = ModelJson.Parse(json, searchPaths); RunGenerator(api, configuration); }