Skip to content

Commit 7ae8508

Browse files
committed
Merge pull request #169 from vosen/master
Ship gdb with Visual Rust
2 parents f337f46 + 7c9719a commit 7ae8508

26 files changed

+3101
-409
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,10 @@ $RECYCLE.BIN/
153153

154154
# Mac desktop service store files
155155
.DS_Store
156+
157+
# =========================
158+
# Visual Rust specific
159+
# =========================
160+
161+
# Skip automatically downloaded files
162+
VisualRust/gdb/*/*

MIEngine

Lines changed: 139 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using System;
22
using System.Diagnostics;
3+
using System.Diagnostics.Eventing.Reader;
34
using System.IO;
5+
using System.Reflection;
46
using System.Text;
7+
using System.Text.RegularExpressions;
58
using System.Xml;
69
using Microsoft.MIDebugEngine;
710
using Microsoft.VisualStudio;
@@ -13,46 +16,53 @@ namespace VisualRust.Project
1316
{
1417
sealed class DefaultRustLauncher : IProjectLauncher
1518
{
16-
private readonly RustProjectNode _project;
17-
private RustProjectConfig _projectConfig;
18-
private readonly Configuration.Debug _debugConfig;
19+
private enum BuildArchitecture
20+
{
21+
Unknown,
22+
i686,
23+
x86_64,
24+
}
25+
26+
private readonly RustProjectNode project;
27+
private readonly Configuration.Debug debugConfig;
28+
private readonly RustProjectConfig projectConfig;
1929

2030
public DefaultRustLauncher(RustProjectNode project)
2131
{
2232
Utilities.ArgumentNotNull("project", project);
23-
_project = project;
24-
string currConfig = _project.GetProjectProperty(ProjectFileConstants.Configuration);
25-
_projectConfig = (RustProjectConfig)_project.ConfigProvider.GetProjectConfiguration(currConfig);
26-
_debugConfig = Configuration.Debug.LoadFrom(new[] { _projectConfig.UserCfg });
33+
this.project = project;
34+
string currConfig = this.project.GetProjectProperty(ProjectFileConstants.Configuration);
35+
projectConfig = (RustProjectConfig)this.project.ConfigProvider.GetProjectConfiguration(currConfig);
36+
debugConfig = Configuration.Debug.LoadFrom(new[] { projectConfig.UserCfg });
2737
}
2838

2939
public int LaunchProject(bool debug)
3040
{
31-
if (_debugConfig.StartAction == Configuration.StartAction.Project &&
32-
_project.GetProjectProperty("OutputType") != "exe")
41+
if (debugConfig.StartAction == Configuration.StartAction.Project &&
42+
project.GetProjectProperty("OutputType") != "exe")
3343
{
3444
throw new InvalidOperationException("A project with an Output Type of Library cannot be started directly.");
3545
}
3646

3747
string startupFilePath;
38-
if (_debugConfig.StartAction == Configuration.StartAction.Project)
48+
if (debugConfig.StartAction == Configuration.StartAction.Project)
3949
startupFilePath = GetProjectStartupFile();
4050
else
41-
startupFilePath = _debugConfig.ExternalProgram;
51+
startupFilePath = debugConfig.ExternalProgram;
4252

4353
return LaunchFile(startupFilePath, debug);
4454
}
4555

4656
private string GetProjectStartupFile()
4757
{
48-
var startupFilePath = Path.Combine(_project.GetProjectProperty("TargetDir"), _project.GetProjectProperty("TargetFileName"));
58+
var startupFilePath = Path.Combine(project.GetProjectProperty("TargetDir"), project.GetProjectProperty("TargetFileName"));
4959
if (string.IsNullOrEmpty(startupFilePath))
5060
{
5161
throw new ApplicationException("Visual Rust could not resolve path for your executable. Your installation of Visual Rust or .rsproj file might be corrupted.");
5262
}
5363

5464
if (!File.Exists(startupFilePath))
55-
_project.Build("Build");
65+
project.Build("Build");
5666

5767
return startupFilePath;
5868
}
@@ -65,7 +75,7 @@ public int LaunchFile(string file, bool debug)
6575
}
6676
else
6777
{
68-
var processStartInfo = CreateProcessStartInfo(file, debug);
78+
var processStartInfo = CreateProcessStartInfo(file);
6979
Process.Start(processStartInfo);
7080
}
7181

@@ -75,21 +85,29 @@ public int LaunchFile(string file, bool debug)
7585

7686
private void LaunchInGdbDebugger(string file)
7787
{
78-
VsDebugTargetInfo4[] targets = new VsDebugTargetInfo4[1];
88+
var targets = new VsDebugTargetInfo4[1];
7989
targets[0].dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess;
8090
targets[0].bstrExe = file;
8191
targets[0].guidLaunchDebugEngine = new Guid(EngineConstants.EngineId);
82-
83-
string gdbPath = GetDebuggingProperty<string>("DebuggerLocation");
84-
if (string.IsNullOrWhiteSpace(gdbPath))
92+
93+
bool useCustomPath = GetDebugProperty<bool>("UseCustomGdbPath");
94+
string gdbPath;
95+
if (useCustomPath)
8596
{
86-
gdbPath = "gdb.exe";
97+
gdbPath = GetDebugProperty<string>("DebuggerLocation");
98+
}
99+
else
100+
{
101+
gdbPath = Path.Combine(
102+
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
103+
"gdb",
104+
GuessArchitecture(),
105+
"bin\\gdb");
87106
}
88-
89107
string gdbArgs =
90108
"-q " + // quiet
91109
"-interpreter=mi " + // use machine interface
92-
GetDebuggingProperty<string>("ExtraArgs"); // add extra options from Visual Rust/Debugging options page
110+
GetDebugProperty<string>("ExtraArgs"); // add extra options from Visual Rust/Debugging options page
93111

94112
var options = new StringBuilder();
95113
using (var writer = XmlWriter.Create(options, new XmlWriterSettings { OmitXmlDeclaration = true }))
@@ -98,15 +116,15 @@ private void LaunchInGdbDebugger(string file)
98116
writer.WriteAttributeString("PipePath", gdbPath);
99117
writer.WriteAttributeString("PipeArguments", gdbArgs);
100118
writer.WriteAttributeString("ExePath", EscapePath(file));
101-
if (!string.IsNullOrEmpty(_debugConfig.CommandLineArgs))
119+
if (!string.IsNullOrEmpty(debugConfig.CommandLineArgs))
102120
{
103-
writer.WriteAttributeString("ExeArguments", _debugConfig.CommandLineArgs);
121+
writer.WriteAttributeString("ExeArguments", debugConfig.CommandLineArgs);
104122
}
105-
if (!string.IsNullOrEmpty(_debugConfig.WorkingDir))
123+
if (!string.IsNullOrEmpty(debugConfig.WorkingDir))
106124
{
107-
writer.WriteAttributeString("WorkingDirectory", EscapePath(_debugConfig.WorkingDir));
125+
writer.WriteAttributeString("WorkingDirectory", EscapePath(debugConfig.WorkingDir));
108126
// GDB won't search working directory by default, but this is expected on Windows.
109-
writer.WriteAttributeString("AdditionalSOLibSearchPath", _debugConfig.WorkingDir);
127+
writer.WriteAttributeString("AdditionalSOLibSearchPath", debugConfig.WorkingDir);
110128
}
111129
else
112130
{
@@ -122,9 +140,9 @@ private void LaunchInGdbDebugger(string file)
122140
writer.WriteElementString("Command", "alias -a gdb=echo");
123141
// launch debuggee in a new console window
124142
writer.WriteElementString("Command", "set new-console on");
125-
if (!string.IsNullOrEmpty(_debugConfig.DebuggerScript))
143+
if (!string.IsNullOrEmpty(debugConfig.DebuggerScript))
126144
{
127-
foreach (string cmd in _debugConfig.DebuggerScript.Split('\r', '\n'))
145+
foreach (string cmd in debugConfig.DebuggerScript.Split('\r', '\n'))
128146
if (!string.IsNullOrEmpty(cmd))
129147
writer.WriteElementString("Command", cmd);
130148
}
@@ -135,49 +153,109 @@ private void LaunchInGdbDebugger(string file)
135153

136154
VsDebugTargetProcessInfo[] results = new VsDebugTargetProcessInfo[targets.Length];
137155

138-
IVsDebugger4 vsDebugger = (IVsDebugger4)_project.GetService(typeof(SVsShellDebugger));
156+
IVsDebugger4 vsDebugger = (IVsDebugger4)project.GetService(typeof(SVsShellDebugger));
139157
vsDebugger.LaunchDebugTargets4((uint)targets.Length, targets, results);
140158

141159
// Type "gdb <command>" in the VS Command Window
142-
var commandWnd = (IVsCommandWindow)_project.GetService(typeof(SVsCommandWindow));
160+
var commandWnd = (IVsCommandWindow)project.GetService(typeof(SVsCommandWindow));
143161
commandWnd.ExecuteCommand("alias gdb Debug.GDBExec");
144162
}
145163

146-
private string EscapePath(string path)
164+
private string GuessArchitecture()
147165
{
148-
return String.Format("\"{0}\"", path);
166+
BuildArchitecture configArch = GetArchFromConfiguration();
167+
if (configArch != BuildArchitecture.Unknown)
168+
return ArchitectureToString(configArch);
169+
BuildArchitecture rustcArch = GetArchFromRustc();
170+
if (rustcArch != BuildArchitecture.Unknown)
171+
return ArchitectureToString(rustcArch);
172+
if (Environment.Is64BitOperatingSystem)
173+
return "x86_64";
174+
return "i686";
175+
}
176+
177+
private BuildArchitecture GetArchFromConfiguration()
178+
{
179+
string configuredTarget = Configuration.Build.LoadFrom(new ProjectConfig[] {this.projectConfig}).PlatformTarget;
180+
return ArchitectureFromTargetTriple(configuredTarget);
181+
}
182+
183+
private static BuildArchitecture ArchitectureFromTargetTriple(string configuredTarget)
184+
{
185+
int platformNameLength = configuredTarget.IndexOf('-');
186+
if (platformNameLength == -1)
187+
return BuildArchitecture.Unknown;
188+
return ParseArchitecture(configuredTarget.Substring(0, platformNameLength));
189+
}
190+
191+
private BuildArchitecture GetArchFromRustc()
192+
{
193+
string defaultInstallPath = Shared.Environment.FindInstallPath("default");
194+
if(defaultInstallPath == null)
195+
return BuildArchitecture.Unknown;
196+
string rustcPath = Path.Combine(defaultInstallPath, "rustc.exe");
197+
string rustcHost = GetRustcHost(rustcPath);
198+
return ArchitectureFromTargetTriple(rustcHost);
149199
}
150200

151-
private T GetDebuggingProperty<T>(string key)
201+
private static string ArchitectureToString(BuildArchitecture b)
152202
{
153-
var env = (EnvDTE.DTE)_project.GetService(typeof(EnvDTE.DTE));
154-
return (T)env.get_Properties("Visual Rust", "Debugging").Item(key).Value;
203+
switch (b)
204+
{
205+
case BuildArchitecture.i686:
206+
return "i686";
207+
case BuildArchitecture.x86_64:
208+
return "x86_64";
209+
default:
210+
throw new ArgumentException(null, "b");
211+
}
155212
}
156213

157-
private ProcessStartInfo CreateProcessStartInfo(string startupFile, bool debug)
214+
private static BuildArchitecture ParseArchitecture(string name)
158215
{
159-
var commandLineArgs = _debugConfig.CommandLineArgs;
160-
if(!debug)
216+
switch (name)
161217
{
162-
commandLineArgs = String.Format(@"/c """"{0}"" {1} & pause""", startupFile, commandLineArgs);
163-
startupFile = Path.Combine(System.Environment.SystemDirectory, "cmd.exe");
218+
case "i686":
219+
return BuildArchitecture.i686;
220+
case "x86_64":
221+
return BuildArchitecture.x86_64;
222+
default:
223+
return BuildArchitecture.Unknown;
164224
}
225+
}
226+
227+
private static string EscapePath(string path)
228+
{
229+
return String.Format("\"{0}\"", path);
230+
}
231+
232+
private T GetDebugProperty<T>(string key)
233+
{
234+
var env = (EnvDTE.DTE)project.GetService(typeof(EnvDTE.DTE));
235+
return (T)env.Properties["Visual Rust", "Debugging"].Item(key).Value;
236+
}
237+
238+
private ProcessStartInfo CreateProcessStartInfo(string startupFile)
239+
{
240+
var commandLineArgs = debugConfig.CommandLineArgs;
241+
commandLineArgs = String.Format(@"/c """"{0}"" {1} & pause""", startupFile, commandLineArgs);
242+
startupFile = Path.Combine(System.Environment.SystemDirectory, "cmd.exe");
165243
var startInfo = new ProcessStartInfo(startupFile, commandLineArgs);
166-
startInfo.WorkingDirectory = _debugConfig.WorkingDir;
244+
startInfo.WorkingDirectory = debugConfig.WorkingDir;
167245
startInfo.UseShellExecute = false;
168246
InjectRustBinPath(startInfo);
169247
return startInfo;
170248
}
171249

172250
private void InjectRustBinPath(ProcessStartInfo startInfo)
173251
{
174-
EnvDTE.Project proj = _project.GetAutomationObject() as EnvDTE.Project;
252+
EnvDTE.Project proj = project.GetAutomationObject() as EnvDTE.Project;
175253
if(proj == null)
176254
return;
177255
string currentConfigName = Utilities.GetActiveConfigurationName(proj);
178256
if(currentConfigName == null)
179257
return;
180-
ProjectConfig currentConfig = _project.ConfigProvider.GetProjectConfiguration(currentConfigName);
258+
ProjectConfig currentConfig = project.ConfigProvider.GetProjectConfiguration(currentConfigName);
181259
if(currentConfig == null)
182260
return;
183261
string currentTarget = currentConfig.GetConfigurationProperty("PlatformTarget", true);
@@ -190,5 +268,23 @@ private void InjectRustBinPath(ProcessStartInfo startInfo)
190268
string newEnvPath = String.Format("{0};{1}", envPath, installPath);
191269
startInfo.EnvironmentVariables["PATH"] = newEnvPath;
192270
}
271+
272+
public static string GetRustcHost(string exePath)
273+
{
274+
ProcessStartInfo psi = new ProcessStartInfo
275+
{
276+
UseShellExecute = false,
277+
CreateNoWindow = true,
278+
FileName = exePath,
279+
RedirectStandardOutput = true,
280+
Arguments = "-Vv"
281+
};
282+
Process proc = Process.Start(psi);
283+
string verboseVersion = proc.StandardOutput.ReadToEnd();
284+
Match hostMatch = Regex.Match(verboseVersion, "^host: (.+)$", RegexOptions.Multiline);
285+
if (hostMatch.Groups.Count == 1)
286+
return null;
287+
return hostMatch.Groups[1].Value;
288+
}
193289
}
194290
}

VisualRust.Project/Feature.cs

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)