You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MenuGenerateCompilers.cs 9.6 KiB

преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.ComponentModel.Design;
  5. using System.Diagnostics;
  6. using System.Globalization;
  7. using System.IO;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using EnvDTE;
  11. using Microsoft.VisualStudio.Shell;
  12. using Microsoft.VisualStudio.Shell.Interop;
  13. using VSConstants = Microsoft.VisualStudio.VSConstants;
  14. namespace Lol.VisualStudio.Plugin
  15. {
  16. internal class MenuGenerateCompilers : OleMenuCommand
  17. {
  18. public MenuGenerateCompilers(ServiceProvider sp, CommandID id) :
  19. base(new EventHandler(ClickCallback), id, VsLol.ResourceManager.GetString("GenerateCompilersText"))
  20. {
  21. this.sp = sp;
  22. this.projects = new List<Project>();
  23. this.BeforeQueryStatus += new EventHandler(OnBeforeQueryStatus);
  24. }
  25. private void OnBeforeQueryStatus(object sender, EventArgs e)
  26. {
  27. projects.Clear();
  28. var cmd = sender as OleMenuCommand;
  29. if (cmd == null)
  30. return;
  31. IVsMonitorSelection monitorSelection = sp.GetService(typeof(IVsMonitorSelection)) as IVsMonitorSelection;
  32. if (monitorSelection == null)
  33. return;
  34. IntPtr hier = IntPtr.Zero;
  35. UInt32 itemid;
  36. IVsMultiItemSelect multiitem = null;
  37. IntPtr container = IntPtr.Zero;
  38. try
  39. {
  40. monitorSelection.GetCurrentSelection(out hier, out itemid, out multiitem, out container);
  41. /* Bail out if nothing is selected */
  42. if (itemid != VSConstants.VSITEMID_SELECTION && itemid != VSConstants.VSITEMID_NIL)
  43. {
  44. if (hier == IntPtr.Zero)
  45. {
  46. /* FIXME: parse the whole solution */
  47. }
  48. else
  49. {
  50. object project = null;
  51. IVsHierarchy hierarchy = (IVsHierarchy)Marshal.GetObjectForIUnknown(hier);
  52. hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out project);
  53. projects.Add(project as Project);
  54. }
  55. }
  56. }
  57. finally
  58. {
  59. if (hier != IntPtr.Zero)
  60. Marshal.Release(hier);
  61. if (container != IntPtr.Zero)
  62. Marshal.Release(container);
  63. }
  64. // If there are .l or .y files in this project, display the context menu
  65. Visible = false;
  66. foreach (Project project in projects)
  67. foreach (ProjectItem item in ParseProjectItems(project))
  68. {
  69. if (item.Name.EndsWith("-scanner.l")
  70. || item.Name.EndsWith("-parser.y"))
  71. Visible = true;
  72. }
  73. }
  74. private static void ClickCallback(object sender, EventArgs args)
  75. {
  76. MenuGenerateCompilers cmd = sender as MenuGenerateCompilers;
  77. if (cmd == null)
  78. return;
  79. cmd.ClearOutputPane();
  80. cmd.WriteToOutputPane("------ Build started: Generating Compilers ------\n");
  81. int scanner_count = 0, parser_count = 0, error_count = 0;
  82. foreach (Project project in cmd.projects)
  83. {
  84. cmd.WriteToOutputPane("Project " + project.Name + "\n");
  85. string project_path = Path.GetDirectoryName(project.FullName);
  86. /* FIXME: find this using the solution globals! */
  87. string contrib_path = project_path;
  88. for (int i = 0; i < 10; ++i)
  89. {
  90. contrib_path += "\\..";
  91. if (Directory.Exists(contrib_path + "\\contrib"))
  92. break;
  93. }
  94. /* FIXME: do not hardcode shit! */
  95. string flex_path = contrib_path + "\\contrib\\flex-2.5.35";
  96. string bison_path = contrib_path + "\\contrib\\bison-2.4.2";
  97. // Run flex on all the .l files
  98. foreach (ProjectItem item in ParseProjectItems(project))
  99. {
  100. string filename = item.get_FileNames(0);
  101. if (filename.StartsWith(project_path + "\\"))
  102. {
  103. filename = filename.Substring(project_path.Length + 1);
  104. filename = filename.Replace("\\", "/");
  105. }
  106. if (item.Name.EndsWith("-scanner.l"))
  107. {
  108. cmd.WriteToOutputPane("flex.exe " + filename + "\n");
  109. string basename = Path.GetFileName(filename.Substring(0, filename.LastIndexOf("-scanner.l")));
  110. if (!cmd.Run(project_path,
  111. flex_path + "\\bin\\flex.exe",
  112. "-v -o "
  113. + "generated/" + basename + "-scanner.cpp "
  114. + filename,
  115. ""))
  116. ++error_count;
  117. ++scanner_count;
  118. }
  119. if (item.Name.EndsWith("-parser.y"))
  120. {
  121. cmd.WriteToOutputPane("bison.exe " + filename + "\n");
  122. string basename = Path.GetFileName(filename.Substring(0, filename.LastIndexOf("-parser.y")));
  123. if (!cmd.Run(project_path,
  124. bison_path + "\\bin\\bison.exe",
  125. "-v -o "
  126. + "generated/" + basename + "-parser.cpp "
  127. + "--defines=generated/" + basename + "-parser.h "
  128. + "-d "
  129. + "-b "
  130. + "generated/" + basename + " "
  131. + filename,
  132. "BISON_PKGDATADIR=" + bison_path + "\\share\\bison"))
  133. ++error_count;
  134. ++parser_count;
  135. }
  136. }
  137. }
  138. cmd.WriteToOutputPane(string.Format("========== Done: {0} scanner(s), {1} parser(s), {2} error(s) ==========\n",
  139. scanner_count, parser_count, error_count));
  140. }
  141. bool Run(string directory, string executable, string arguments, string env)
  142. {
  143. System.Diagnostics.Process p = new System.Diagnostics.Process();
  144. p.StartInfo.FileName = executable;
  145. p.StartInfo.Arguments = arguments;
  146. foreach (string s in env.Split(new char[]{'\n'}, StringSplitOptions.RemoveEmptyEntries))
  147. {
  148. int i = s.IndexOf("=");
  149. if (i > 0 && i < s.Length - 1)
  150. p.StartInfo.EnvironmentVariables[s.Substring(0, i - 1)] = s.Substring(i + 1);
  151. }
  152. p.StartInfo.WorkingDirectory = directory;
  153. p.StartInfo.CreateNoWindow = true;
  154. p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  155. p.StartInfo.RedirectStandardError = true;
  156. p.StartInfo.RedirectStandardOutput = true;
  157. p.StartInfo.RedirectStandardInput = true;
  158. p.StartInfo.UseShellExecute = false;
  159. try
  160. {
  161. p.Start();
  162. string output = p.StandardError.ReadToEnd()
  163. + p.StandardOutput.ReadToEnd();
  164. p.WaitForExit();
  165. WriteToOutputPane(output);
  166. if (p.ExitCode != 0)
  167. {
  168. WriteToOutputPane("Error: " + executable + " exited with code " + p.ExitCode + "\n");
  169. return false;
  170. }
  171. }
  172. catch (Exception e)
  173. {
  174. WriteToOutputPane("Error: failed to launch " + executable + "\n");
  175. return false;
  176. }
  177. return true;
  178. }
  179. private void ClearOutputPane()
  180. {
  181. IVsOutputWindow win = sp.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow;
  182. if (null == win)
  183. {
  184. Trace.WriteLine("Failed to get a reference to IVsOutputWindow");
  185. pane = null;
  186. }
  187. Guid guid = Microsoft.VisualStudio.VSConstants.OutputWindowPaneGuid.BuildOutputPane_guid;
  188. if (Microsoft.VisualStudio.ErrorHandler.Failed(win.GetPane(ref guid, out pane)))
  189. {
  190. Trace.WriteLine("Failed to get a reference to the Output window Build pane");
  191. pane = null;
  192. }
  193. pane.Activate();
  194. pane.Clear();
  195. }
  196. private void WriteToOutputPane(string s)
  197. {
  198. if (pane != null)
  199. pane.OutputString(s);
  200. }
  201. private static IEnumerable<ProjectItem> ParseProjectItems(object o)
  202. {
  203. ProjectItems subitems;
  204. if (o is Project)
  205. {
  206. subitems = (o as Project).ProjectItems;
  207. }
  208. else
  209. {
  210. yield return (o as ProjectItem);
  211. subitems = (o as ProjectItem).ProjectItems;
  212. }
  213. foreach (ProjectItem item in subitems)
  214. foreach (ProjectItem i in ParseProjectItems(item))
  215. yield return i;
  216. }
  217. private ServiceProvider sp;
  218. private IVsOutputWindowPane pane;
  219. private List<Project> projects;
  220. }
  221. }