detect gdb version & rust support in compiletest

This commit is contained in:
Tim Neumann 2016-10-29 20:11:53 +02:00
parent 6554fb0d8d
commit dce460028e
11 changed files with 180 additions and 89 deletions

7
configure vendored
View file

@ -862,13 +862,6 @@ then
fi fi
fi fi
if [ -n "$CFG_GDB" ]
then
# Store GDB's version
CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1)
putvar CFG_GDB_VERSION
fi
if [ -n "$CFG_LLDB" ] if [ -n "$CFG_LLDB" ]
then then
# Store LLDB's version # Store LLDB's version

View file

@ -648,7 +648,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \
--host $(3) \ --host $(3) \
--docck-python $$(CFG_PYTHON) \ --docck-python $$(CFG_PYTHON) \
--lldb-python $$(CFG_LLDB_PYTHON) \ --lldb-python $$(CFG_LLDB_PYTHON) \
--gdb-version="$(CFG_GDB_VERSION)" \ --gdb="$(CFG_GDB)" \
--lldb-version="$(CFG_LLDB_VERSION)" \ --lldb-version="$(CFG_LLDB_VERSION)" \
--llvm-version="$$(LLVM_VERSION_$(3))" \ --llvm-version="$$(LLVM_VERSION_$(3))" \
--android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \ --android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \

View file

@ -168,8 +168,8 @@ pub fn compiletest(build: &Build,
cmd.arg("--lldb-python").arg(python_default); cmd.arg("--lldb-python").arg(python_default);
} }
if let Some(ref vers) = build.gdb_version { if let Some(ref gdb) = build.config.gdb {
cmd.arg("--gdb-version").arg(vers); cmd.arg("--gdb").arg(gdb);
} }
if let Some(ref vers) = build.lldb_version { if let Some(ref vers) = build.lldb_version {
cmd.arg("--lldb-version").arg(vers); cmd.arg("--lldb-version").arg(vers);

View file

@ -85,6 +85,7 @@ pub struct Config {
pub mandir: Option<String>, pub mandir: Option<String>,
pub codegen_tests: bool, pub codegen_tests: bool,
pub nodejs: Option<PathBuf>, pub nodejs: Option<PathBuf>,
pub gdb: Option<PathBuf>,
} }
/// Per-target configuration stored in the global configuration structure. /// Per-target configuration stored in the global configuration structure.
@ -122,6 +123,7 @@ struct Build {
compiler_docs: Option<bool>, compiler_docs: Option<bool>,
docs: Option<bool>, docs: Option<bool>,
submodules: Option<bool>, submodules: Option<bool>,
gdb: Option<String>,
} }
/// TOML representation of how the LLVM build is configured. /// TOML representation of how the LLVM build is configured.
@ -226,6 +228,7 @@ impl Config {
} }
config.rustc = build.rustc.map(PathBuf::from); config.rustc = build.rustc.map(PathBuf::from);
config.cargo = build.cargo.map(PathBuf::from); config.cargo = build.cargo.map(PathBuf::from);
config.gdb = build.gdb.map(PathBuf::from);
set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.compiler_docs, build.compiler_docs);
set(&mut config.docs, build.docs); set(&mut config.docs, build.docs);
set(&mut config.submodules, build.submodules); set(&mut config.submodules, build.submodules);
@ -392,6 +395,9 @@ impl Config {
"CFG_DEFAULT_LINKER" if value.len() > 0 => { "CFG_DEFAULT_LINKER" if value.len() > 0 => {
self.rustc_default_linker = Some(value.to_string()); self.rustc_default_linker = Some(value.to_string());
} }
"CFG_GDB" if value.len() > 0 => {
self.gdb = Some(PathBuf::from(value));
}
"CFG_RELEASE_CHANNEL" => { "CFG_RELEASE_CHANNEL" => {
self.channel = value.to_string(); self.channel = value.to_string();
} }

View file

@ -79,6 +79,9 @@
# Indicate whether submodules are managed and updated automatically. # Indicate whether submodules are managed and updated automatically.
#submodules = true #submodules = true
# The path to (or name of) the GDB executable to use
#gdb = "gdb"
# ============================================================================= # =============================================================================
# Options for compiling Rust code itself # Options for compiling Rust code itself
# ============================================================================= # =============================================================================

View file

@ -123,7 +123,6 @@ pub struct Build {
bootstrap_key_stage0: String, bootstrap_key_stage0: String,
// Probed tools at runtime // Probed tools at runtime
gdb_version: Option<String>,
lldb_version: Option<String>, lldb_version: Option<String>,
lldb_python_dir: Option<String>, lldb_python_dir: Option<String>,
@ -196,7 +195,6 @@ impl Build {
package_vers: String::new(), package_vers: String::new(),
cc: HashMap::new(), cc: HashMap::new(),
cxx: HashMap::new(), cxx: HashMap::new(),
gdb_version: None,
lldb_version: None, lldb_version: None,
lldb_python_dir: None, lldb_python_dir: None,
} }

View file

@ -92,6 +92,12 @@ pub fn check(build: &mut Build) {
need_cmd(s.as_ref()); need_cmd(s.as_ref());
} }
if let Some(ref gdb) = build.config.gdb {
need_cmd(gdb.as_ref());
} else {
build.config.gdb = have_cmd("gdb".as_ref());
}
// We're gonna build some custom C code here and there, host triples // We're gonna build some custom C code here and there, host triples
// also build some C++ shims for LLVM so we need a C++ compiler. // also build some C++ shims for LLVM so we need a C++ compiler.
for target in build.config.target.iter() { for target in build.config.target.iter() {
@ -198,7 +204,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
.to_string() .to_string()
}) })
}; };
build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
build.lldb_version = run(Command::new("lldb").arg("--version")).ok(); build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
if build.lldb_version.is_some() { if build.lldb_version.is_some() {
build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok(); build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();

View file

@ -146,8 +146,11 @@ pub struct Config {
// Host triple for the compiler being invoked // Host triple for the compiler being invoked
pub host: String, pub host: String,
// Version of GDB // Path to / name of the GDB executable
pub gdb_version: Option<String>, pub gdb: Option<String>,
// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch
pub gdb_version: Option<u32>,
// Whether GDB has native rust support // Whether GDB has native rust support
pub gdb_native_rust: bool, pub gdb_native_rust: bool,

View file

@ -18,6 +18,8 @@ use common::Config;
use common; use common;
use util; use util;
use extract_gdb_version;
/// Properties which must be known very early, before actually running /// Properties which must be known very early, before actually running
/// the test. /// the test.
pub struct EarlyProps { pub struct EarlyProps {
@ -75,7 +77,7 @@ impl EarlyProps {
return true; return true;
} }
if let Some(ref actual_version) = config.gdb_version { if let Some(actual_version) = config.gdb_version {
if line.contains("min-gdb-version") { if line.contains("min-gdb-version") {
let min_version = line.trim() let min_version = line.trim()
.split(' ') .split(' ')
@ -83,7 +85,7 @@ impl EarlyProps {
.expect("Malformed GDB version directive"); .expect("Malformed GDB version directive");
// Ignore if actual version is smaller the minimum required // Ignore if actual version is smaller the minimum required
// version // version
gdb_version_to_int(actual_version) < gdb_version_to_int(min_version) actual_version < extract_gdb_version(min_version).unwrap()
} else { } else {
false false
} }
@ -464,23 +466,6 @@ pub fn parse_name_value_directive(line: &str, directive: &str) -> Option<String>
} }
} }
pub fn gdb_version_to_int(version_string: &str) -> isize {
let error_string = format!("Encountered GDB version string with unexpected format: {}",
version_string);
let error_string = error_string;
let components: Vec<&str> = version_string.trim().split('.').collect();
if components.len() != 2 {
panic!("{}", error_string);
}
let major: isize = components[0].parse().ok().expect(&error_string);
let minor: isize = components[1].parse().ok().expect(&error_string);
return major * 1000 + minor;
}
pub fn lldb_version_to_int(version_string: &str) -> isize { pub fn lldb_version_to_int(version_string: &str) -> isize {
let error_string = format!("Encountered LLDB version string with unexpected format: {}", let error_string = format!("Encountered LLDB version string with unexpected format: {}",
version_string); version_string);

View file

@ -12,6 +12,7 @@
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(static_in_const)]
#![feature(test)] #![feature(test)]
#![feature(libc)] #![feature(libc)]
@ -35,6 +36,7 @@ use std::ffi::OsString;
use std::fs; use std::fs;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command;
use getopts::{optopt, optflag, reqopt}; use getopts::{optopt, optflag, reqopt};
use common::Config; use common::Config;
use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Mode}; use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Mode};
@ -98,7 +100,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
optopt("", "logfile", "file to log test execution to", "FILE"), optopt("", "logfile", "file to log test execution to", "FILE"),
optopt("", "target", "the target to build for", "TARGET"), optopt("", "target", "the target to build for", "TARGET"),
optopt("", "host", "the host to build for", "HOST"), optopt("", "host", "the host to build for", "HOST"),
optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"), optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH"),
optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"), optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"),
optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING"), optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING"),
optopt("", "android-cross-path", "Android NDK standalone path", "PATH"), optopt("", "android-cross-path", "Android NDK standalone path", "PATH"),
@ -149,6 +151,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
} }
} }
let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"));
Config { Config {
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
@ -171,8 +175,9 @@ pub fn parse_config(args: Vec<String> ) -> Config {
target_rustcflags: matches.opt_str("target-rustcflags"), target_rustcflags: matches.opt_str("target-rustcflags"),
target: opt_str2(matches.opt_str("target")), target: opt_str2(matches.opt_str("target")),
host: opt_str2(matches.opt_str("host")), host: opt_str2(matches.opt_str("host")),
gdb_version: extract_gdb_version(matches.opt_str("gdb-version")), gdb: gdb,
gdb_native_rust: false, gdb_version: gdb_version,
gdb_native_rust: gdb_native_rust,
lldb_version: extract_lldb_version(matches.opt_str("lldb-version")), lldb_version: extract_lldb_version(matches.opt_str("lldb-version")),
llvm_version: matches.opt_str("llvm-version"), llvm_version: matches.opt_str("llvm-version"),
android_cross_path: opt_path(matches, "android-cross-path"), android_cross_path: opt_path(matches, "android-cross-path"),
@ -471,44 +476,96 @@ pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn
})) }))
} }
fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> { /// Returns (Path to GDB, GDB Version, GDB has Rust Support)
match full_version_line { fn analyze_gdb(gdb: Option<String>) -> (Option<String>, Option<u32>, bool) {
Some(ref full_version_line) #[cfg(not(windows))]
if !full_version_line.trim().is_empty() => { const GDB_FALLBACK: &str = "gdb";
#[cfg(windows)]
const GDB_FALLBACK: &str = "gdb.exe";
const MIN_GDB_WITH_RUST: u32 = 7011010;
let gdb = match gdb {
None => GDB_FALLBACK,
Some(ref s) if s.is_empty() => GDB_FALLBACK, // may be empty if configure found no gdb
Some(ref s) => s,
};
let version_line = Command::new(gdb).arg("--version").output().map(|output| {
String::from_utf8_lossy(&output.stdout).lines().next().unwrap().to_string()
}).ok();
let version = match version_line {
Some(line) => extract_gdb_version(&line),
None => return (None, None, false),
};
let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST);
return (Some(gdb.to_owned()), version, gdb_native_rust);
}
fn extract_gdb_version(full_version_line: &str) -> Option<u32> {
let full_version_line = full_version_line.trim(); let full_version_line = full_version_line.trim();
// used to be a regex "(^|[^0-9])([0-9]\.[0-9]+)" // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both
// of the ? sections being optional
// We will parse up to 3 digits for minor and patch, ignoring the date
// We limit major to 1 digit, otherwise, on openSUSE, we parse the openSUSE version
// don't start parsing in the middle of a number
let mut prev_was_digit = false;
for (pos, c) in full_version_line.char_indices() { for (pos, c) in full_version_line.char_indices() {
if !c.is_digit(10) { if prev_was_digit || !c.is_digit(10) {
prev_was_digit = c.is_digit(10);
continue continue
} }
if pos + 2 >= full_version_line.len() {
continue prev_was_digit = true;
let line = &full_version_line[pos..];
let next_split = match line.find(|c: char| !c.is_digit(10)) {
Some(idx) => idx,
None => continue, // no minor version
};
if line.as_bytes()[next_split] != b'.' {
continue; // no minor version
} }
if full_version_line[pos + 1..].chars().next().unwrap() != '.' {
continue let major = &line[..next_split];
} let line = &line[next_split + 1..];
if !full_version_line[pos + 2..].chars().next().unwrap().is_digit(10) {
continue let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) {
} Some(idx) => if line.as_bytes()[idx] == b'.' {
if pos > 0 && full_version_line[..pos].chars().next_back() let patch = &line[idx + 1..];
.unwrap().is_digit(10) {
continue let patch_len = patch.find(|c: char| !c.is_digit(10)).unwrap_or(patch.len());
} let patch = &patch[..patch_len];
let mut end = pos + 3; let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) };
while end < full_version_line.len() &&
full_version_line[end..].chars().next() (&line[..idx], patch)
.unwrap().is_digit(10) { } else {
end += 1; (&line[..idx], None)
}
return Some(full_version_line[pos..end].to_owned());
}
println!("Could not extract GDB version from line '{}'",
full_version_line);
None
}, },
_ => None None => (line, None),
};
if major.len() != 1 || minor.is_empty() {
continue;
} }
let major: u32 = major.parse().unwrap();
let minor: u32 = minor.parse().unwrap();
let patch: u32 = patch.unwrap_or("0").parse().unwrap();
return Some(((major * 1000) + minor) * 1000 + patch);
}
println!("Could not extract GDB version from line '{}'", full_version_line);
None
} }
fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> { fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
@ -554,3 +611,44 @@ fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
fn is_blacklisted_lldb_version(version: &str) -> bool { fn is_blacklisted_lldb_version(version: &str) -> bool {
version == "350" version == "350"
} }
#[test]
fn test_extract_gdb_version() {
macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$(
assert_eq!(extract_gdb_version($input), Some($expectation));
)*}}}
test! {
7000001: "GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)",
7002000: "GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)",
7004000: "GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04",
7004001: "GNU gdb (GDB) 7.4.1-debian",
7006001: "GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7",
7007001: "GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1",
7007001: "GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1",
7007001: "GNU gdb (GDB) Fedora 7.7.1-21.fc20",
7008000: "GNU gdb (GDB; openSUSE 13.2) 7.8",
7009001: "GNU gdb (GDB) Fedora 7.9.1-20.fc22",
7010001: "GNU gdb (GDB) Fedora 7.10.1-31.fc23",
7011000: "GNU gdb (Ubuntu 7.11-0ubuntu1) 7.11",
7011001: "GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1",
7011001: "GNU gdb (Debian 7.11.1-2) 7.11.1",
7011001: "GNU gdb (GDB) Fedora 7.11.1-86.fc24",
7011001: "GNU gdb (GDB; openSUSE Leap 42.1) 7.11.1",
7011001: "GNU gdb (GDB; openSUSE Tumbleweed) 7.11.1",
7011090: "7.11.90",
7011090: "GNU gdb (Ubuntu 7.11.90.20161005-0ubuntu1) 7.11.90.20161005-git",
7012000: "7.12",
7012000: "GNU gdb (GDB) 7.12",
7012000: "GNU gdb (GDB) 7.12.20161027-git",
7012050: "GNU gdb (GDB) 7.12.50.20161027-git",
}
}

View file

@ -32,6 +32,8 @@ use std::path::{Path, PathBuf};
use std::process::{Command, Output, ExitStatus}; use std::process::{Command, Output, ExitStatus};
use std::str; use std::str;
use extract_gdb_version;
pub fn run(config: Config, testpaths: &TestPaths) { pub fn run(config: Config, testpaths: &TestPaths) {
match &*config.target { match &*config.target {
@ -44,6 +46,10 @@ pub fn run(config: Config, testpaths: &TestPaths) {
_=> { } _=> { }
} }
if config.mode == DebugInfoGdb && config.gdb.is_none() {
panic!("gdb not available but debuginfo gdb debuginfo test requested");
}
if config.verbose { if config.verbose {
// We're going to be dumping a lot of info. Start on a new line. // We're going to be dumping a lot of info. Start on a new line.
print!("\n\n"); print!("\n\n");
@ -598,12 +604,11 @@ actual:\n\
script_str.push_str("show version\n"); script_str.push_str("show version\n");
match self.config.gdb_version { match self.config.gdb_version {
Some(ref version) => { Some(version) => {
println!("NOTE: compiletest thinks it is using GDB version {}", println!("NOTE: compiletest thinks it is using GDB version {}",
version); version);
if header::gdb_version_to_int(version) > if version > extract_gdb_version("7.4").unwrap() {
header::gdb_version_to_int("7.4") {
// Add the directory containing the pretty printers to // Add the directory containing the pretty printers to
// GDB's script auto loading safe path // GDB's script auto loading safe path
script_str.push_str( script_str.push_str(
@ -645,11 +650,6 @@ actual:\n\
debug!("script_str = {}", script_str); debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script"); self.dump_output_file(&script_str, "debugger.script");
// run debugger script with gdb
fn debugger() -> &'static str {
if cfg!(windows) {"gdb.exe"} else {"gdb"}
}
let debugger_script = self.make_out_name("debugger.script"); let debugger_script = self.make_out_name("debugger.script");
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
@ -660,7 +660,7 @@ actual:\n\
format!("-command={}", debugger_script.to_str().unwrap())); format!("-command={}", debugger_script.to_str().unwrap()));
let proc_args = ProcArgs { let proc_args = ProcArgs {
prog: debugger().to_owned(), prog: self.config.gdb.as_ref().unwrap().to_owned(),
args: debugger_opts, args: debugger_opts,
}; };