|
| 1 | +use std::borrow::Cow; |
1 | 2 | use std::path::Path; |
2 | 3 |
|
| 4 | +use crate::core::android; |
3 | 5 | use crate::core::builder::Builder; |
| 6 | +use crate::utils::exec::BootstrapCommand; |
4 | 7 |
|
5 | 8 | pub(crate) struct Gdb<'a> { |
6 | | - pub(crate) gdb: &'a Path, |
| 9 | + pub(crate) gdb: Cow<'a, Path>, |
7 | 10 | } |
8 | 11 |
|
9 | | -pub(crate) fn discover_gdb<'a>(builder: &'a Builder<'_>) -> Option<Gdb<'a>> { |
10 | | - let gdb = builder.config.gdb.as_deref()?; |
| 12 | +pub(crate) fn discover_gdb<'a>( |
| 13 | + builder: &'a Builder<'_>, |
| 14 | + android: Option<&android::Android>, |
| 15 | +) -> Option<Gdb<'a>> { |
| 16 | + // If there's an explicitly-configured gdb, use that. |
| 17 | + if let Some(gdb) = builder.config.gdb.as_deref() { |
| 18 | + // FIXME(Zalathar): Consider returning None if gdb is an empty string, |
| 19 | + // as a way to explicitly disable ambient gdb discovery. |
| 20 | + let gdb = Cow::Borrowed(gdb); |
| 21 | + return Some(Gdb { gdb }); |
| 22 | + } |
11 | 23 |
|
12 | | - Some(Gdb { gdb }) |
| 24 | + // Otherwise, fall back to whatever gdb is sitting around in PATH. |
| 25 | + // (That's the historical behavior, but maybe we should require opt-in?) |
| 26 | + |
| 27 | + let gdb: Cow<'_, Path> = match android { |
| 28 | + Some(android::Android { android_cross_path, .. }) => { |
| 29 | + android_cross_path.join("bin/gdb").into() |
| 30 | + } |
| 31 | + None => Path::new("gdb").into(), |
| 32 | + }; |
| 33 | + |
| 34 | + // Check whether an ambient gdb exists, by running `gdb --version`. |
| 35 | + let output = { |
| 36 | + let mut gdb_command = BootstrapCommand::new(gdb.as_ref()).allow_failure(); |
| 37 | + gdb_command.arg("--version"); |
| 38 | + gdb_command.run_capture(builder) |
| 39 | + }; |
| 40 | + |
| 41 | + if output.is_success() { Some(Gdb { gdb }) } else { None } |
13 | 42 | } |
0 commit comments