source: trunk/tools/vslol/MenuGenerateCompilers.cs @ 2113

Last change on this file since 2113 was 2113, checked in by sam, 8 years ago

vslol: minor additional debug messages.

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