MonoChecker.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text.RegularExpressions;
  6. using CppSharp.AST;
  7. using CppSharp.AST.Extensions;
  8. using CppSharp.Parser;
  9. using Newtonsoft.Json;
  10. namespace CppSharp
  11. {
  12. /**
  13. * This tool reads the AST of a Mono source checkout.
  14. */
  15. static class MonoChecker
  16. {
  17. static string CompilationDatabasePath = @"";
  18. public static void Main(string[] args)
  19. {
  20. ParseCommandLineArgs(args);
  21. Console.WriteLine();
  22. Console.WriteLine("Parsing Mono's source code...");
  23. var options = new DriverOptions();
  24. var log = new TextDiagnosticPrinter();
  25. var driver = new Driver(options, log);
  26. Setup(driver);
  27. driver.Setup();
  28. BuildParseOptions(driver);
  29. if (!driver.ParseCode())
  30. return;
  31. Check(driver.ASTContext);
  32. }
  33. static void ParseCommandLineArgs(string[] args)
  34. {
  35. var needsArgs = string.IsNullOrWhiteSpace(CompilationDatabasePath);
  36. if (!needsArgs)
  37. return;
  38. if (args.Length >= 1)
  39. CompilationDatabasePath = Path.GetFullPath(args[0]);
  40. else
  41. CompilationDatabasePath = "compile_commands.json";
  42. if (!File.Exists(CompilationDatabasePath)) {
  43. Console.WriteLine("Could not find JSON compilation database '{0}'",
  44. CompilationDatabasePath);
  45. Environment.Exit(0);
  46. }
  47. }
  48. static string GetXcodeToolchainPath()
  49. {
  50. var toolchains = Directory.EnumerateDirectories("/Applications", "Xcode*")
  51. .ToList();
  52. toolchains.Sort();
  53. var toolchainPath = toolchains.LastOrDefault();
  54. if (toolchainPath == null)
  55. throw new Exception("Could not find a valid Xcode SDK");
  56. return toolchainPath;
  57. }
  58. static string GetXcodeBuiltinIncludesFolder()
  59. {
  60. var toolchainPath = GetXcodeToolchainPath();
  61. var toolchains = Directory.EnumerateDirectories(Path.Combine(toolchainPath,
  62. "Contents/Developer/Toolchains")).ToList();
  63. toolchains.Sort();
  64. toolchainPath = toolchains.LastOrDefault();
  65. if (toolchainPath == null)
  66. throw new Exception("Could not find a valid Xcode toolchain");
  67. var includePaths = Directory.EnumerateDirectories(Path.Combine(toolchainPath,
  68. "usr/lib/clang")).ToList();
  69. var includePath = includePaths.LastOrDefault();
  70. if (includePath == null)
  71. throw new Exception("Could not find a valid Clang include folder");
  72. return Path.Combine(includePath, "include");
  73. }
  74. static void SetupXcode(Driver driver)
  75. {
  76. var options = driver.Options;
  77. var builtinsPath = GetXcodeBuiltinIncludesFolder();
  78. options.addSystemIncludeDirs(builtinsPath);
  79. var includePath = "/usr/include";
  80. options.addSystemIncludeDirs(includePath);
  81. options.NoBuiltinIncludes = true;
  82. options.NoStandardIncludes = true;
  83. }
  84. static void Setup(Driver driver)
  85. {
  86. var options = driver.Options;
  87. options.DryRun = true;
  88. options.Verbose = false;
  89. options.LibraryName = "Mono";
  90. options.MicrosoftMode = false;
  91. options.addArguments("-xc");
  92. options.addArguments("-std=gnu99");
  93. SetupXcode(driver);
  94. }
  95. struct CompileUnit
  96. {
  97. public string directory;
  98. public string command;
  99. public string file;
  100. }
  101. static List<CompileUnit> CleanCompileUnits(List<CompileUnit> database)
  102. {
  103. // The compilation database we get from Bear has duplicated entries
  104. // for the same files, so clean it up before passing it down to
  105. // further processing.
  106. var units = new List<CompileUnit>();
  107. foreach (var unit in database) {
  108. // Ignore compile units compiled with PIC (Position-independent code)
  109. if (unit.command.EndsWith("-fPIC -DPIC"))
  110. continue;
  111. // Ignore compile units that are compiled with gcc since in OSX
  112. // it's a wrapper for the real compiler (clang) for which there'll
  113. // be another entry.
  114. if (unit.command.Contains("gcc"))
  115. continue;
  116. // Ignore the static runtime build.
  117. if (unit.command.Contains("_static_la"))
  118. continue;
  119. // Ignore the Boehm runtime build.
  120. if (unit.command.Contains("libmonoruntime_la"))
  121. continue;
  122. units.Add(unit);
  123. }
  124. return units;
  125. }
  126. static void BuildParseOptions(Driver driver)
  127. {
  128. var json = File.ReadAllText(CompilationDatabasePath);
  129. var compileUnits = JsonConvert.DeserializeObject<List<CompileUnit>>(json);
  130. compileUnits = CleanCompileUnits(compileUnits);
  131. compileUnits = compileUnits.OrderBy(unit => unit.file).ToList();
  132. foreach (var unit in compileUnits) {
  133. var source = driver.Project.AddFile(unit.file);
  134. source.Options = driver.BuildParseOptions(source);
  135. var args = unit.command.Split(new char[] {' '}).Skip(1);
  136. foreach (var arg in args) {
  137. // Skip some arguments that Clang complains about...
  138. var arguments = new List<string> {
  139. "-no-cpp-precomp",
  140. "-Qunused-arguments",
  141. "-fno-strict-aliasing",
  142. "-Qunused-arguments",
  143. "-MD",
  144. "-MF",
  145. "-c"
  146. };
  147. if (arguments.Contains(arg))
  148. continue;
  149. source.Options.addArguments(arg);
  150. }
  151. }
  152. }
  153. static void Check(ASTContext context)
  154. {
  155. // TODO: Implement checking here
  156. }
  157. }
  158. }