Improve build.rs when configuring using the python in PATH

* First try "pythonX.Y" and
  "pythonX" before using the generic "python"
* Use LDVERSION to detect 'dmu' suffix (PEP-3149)
This commit is contained in:
Daniel Grunwald 2015-06-28 20:56:46 +02:00
parent cdca6f04e8
commit 2904330b1c
2 changed files with 50 additions and 23 deletions

View File

@ -147,8 +147,8 @@ fn cfg_line_for_var(key: &str, val: &str) -> Option<String> {
} }
/// Run a python script using the 'python' located by PATH. /// Run a python script using the 'python' located by PATH.
fn run_python_script(script: &str) -> Result<String, String> { fn run_python_script(interpreter: &str, script: &str) -> Result<String, String> {
let mut cmd = Command::new("python"); let mut cmd = Command::new(interpreter);
cmd.arg("-c").arg(script); cmd.arg("-c").arg(script);
let out = try!(cmd.output().map_err(|e| { let out = try!(cmd.output().map_err(|e| {
@ -166,6 +166,20 @@ fn run_python_script(script: &str) -> Result<String, String> {
return Ok(out); return Ok(out);
} }
fn run_python_script_try_interpreters(version: &PythonVersion, script: &str) -> Result<String, String> {
if let Some(minor) = version.minor {
let interpreter = format!("python{}.{}", version.major, minor);
if let Ok(r) = run_python_script(&interpreter, script) {
return Ok(r);
}
}
let interpreter = format!("python{}", version.major);
if let Ok(r) = run_python_script(&interpreter, script) {
return Ok(r);
}
run_python_script("python", script)
}
#[cfg(not(target_os="macos"))] #[cfg(not(target_os="macos"))]
#[cfg(not(target_os="windows"))] #[cfg(not(target_os="windows"))]
fn get_rustc_link_lib(version: &PythonVersion, enable_shared: bool) -> Result<String, String> { fn get_rustc_link_lib(version: &PythonVersion, enable_shared: bool) -> Result<String, String> {
@ -180,7 +194,7 @@ fn get_rustc_link_lib(version: &PythonVersion, enable_shared: bool) -> Result<St
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
fn get_macos_linkmodel() -> Result<String, String> { fn get_macos_linkmodel() -> Result<String, String> {
let script = "import MacOS; print MacOS.linkmodel;"; let script = "import MacOS; print MacOS.linkmodel;";
let out = run_python_script(script).unwrap(); let out = run_python_script("python", script).unwrap();
Ok(out.trim_right().to_owned()) Ok(out.trim_right().to_owned())
} }
@ -249,7 +263,7 @@ fn configure_from_path(expected_version: &PythonVersion) -> Result<String, Strin
print(sysconfig.get_config_var('LIBDIR')); \ print(sysconfig.get_config_var('LIBDIR')); \
print(sysconfig.get_config_var('Py_ENABLE_SHARED')); \ print(sysconfig.get_config_var('Py_ENABLE_SHARED')); \
print(sys.exec_prefix);"; print(sys.exec_prefix);";
let out = run_python_script(script).unwrap(); let out = run_python_script_try_interpreters(expected_version, script).unwrap();
let lines: Vec<&str> = out.split(NEWLINE_SEQUENCE).collect(); let lines: Vec<&str> = out.split(NEWLINE_SEQUENCE).collect();
let version: &str = lines[0]; let version: &str = lines[0];
let libpath: &str = lines[1]; let libpath: &str = lines[1];

View File

@ -146,9 +146,9 @@ fn cfg_line_for_var(key: &str, val: &str) -> Option<String> {
} }
} }
/// Run a python script using the 'python' located by PATH. /// Run a python script using the specified interpreter binary.
fn run_python_script(script: &str) -> Result<String, String> { fn run_python_script(interpreter: &str, script: &str) -> Result<String, String> {
let mut cmd = Command::new("python"); let mut cmd = Command::new(interpreter);
cmd.arg("-c").arg(script); cmd.arg("-c").arg(script);
let out = try!(cmd.output().map_err(|e| { let out = try!(cmd.output().map_err(|e| {
@ -166,36 +166,48 @@ fn run_python_script(script: &str) -> Result<String, String> {
return Ok(out); return Ok(out);
} }
fn run_python_script_try_interpreters(version: &PythonVersion, script: &str) -> Result<String, String> {
if let Some(minor) = version.minor {
let interpreter = format!("python{}.{}", version.major, minor);
if let Ok(r) = run_python_script(&interpreter, script) {
return Ok(r);
}
}
let interpreter = format!("python{}", version.major);
if let Ok(r) = run_python_script(&interpreter, script) {
return Ok(r);
}
run_python_script("python", script)
}
#[cfg(not(target_os="macos"))] #[cfg(not(target_os="macos"))]
#[cfg(not(target_os="windows"))] #[cfg(not(target_os="windows"))]
fn get_rustc_link_lib(version: &PythonVersion, enable_shared: bool) -> Result<String, String> { fn get_rustc_link_lib(_: &PythonVersion, ld_version: &str, enable_shared: bool) -> Result<String, String> {
let dotted_version = format!("{}.{}", version.major, version.minor.unwrap());
if enable_shared { if enable_shared {
Ok(format!("cargo:rustc-link-lib=python{}", dotted_version)) Ok(format!("cargo:rustc-link-lib=python{}", ld_version))
} else { } else {
Ok(format!("cargo:rustc-link-lib=static=python{}", dotted_version)) Ok(format!("cargo:rustc-link-lib=static=python{}", ld_version))
} }
} }
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
fn get_macos_linkmodel() -> Result<String, String> { fn get_macos_linkmodel() -> Result<String, String> {
let script = "import MacOS; print MacOS.linkmodel;"; let script = "import MacOS; print MacOS.linkmodel;";
let out = run_python_script(script).unwrap(); let out = run_python_script("python", script).unwrap();
Ok(out.trim_right().to_owned()) Ok(out.trim_right().to_owned())
} }
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
fn get_rustc_link_lib(version: &PythonVersion, _: bool) -> Result<String, String> { fn get_rustc_link_lib(_: &PythonVersion, ld_version: &str, _: bool) -> Result<String, String> {
// os x can be linked to a framework or static or dynamic, and // os x can be linked to a framework or static or dynamic, and
// Py_ENABLE_SHARED is wrong; framework means shared library // Py_ENABLE_SHARED is wrong; framework means shared library
let dotted_version = format!("{}.{}", version.major, version.minor.unwrap());
match get_macos_linkmodel().unwrap().as_ref() { match get_macos_linkmodel().unwrap().as_ref() {
"static" => Ok(format!("cargo:rustc-link-lib=static=python{}", "static" => Ok(format!("cargo:rustc-link-lib=static=python{}",
dotted_version)), ld_version)),
"dynamic" => Ok(format!("cargo:rustc-link-lib=python{}", "dynamic" => Ok(format!("cargo:rustc-link-lib=python{}",
dotted_version)), ld_version)),
"framework" => Ok(format!("cargo:rustc-link-lib=python{}", "framework" => Ok(format!("cargo:rustc-link-lib=python{}",
dotted_version)), ld_version)),
other => Err(format!("unknown linkmodel {}", other)) other => Err(format!("unknown linkmodel {}", other))
} }
} }
@ -231,7 +243,7 @@ fn get_interpreter_version(line: &str, expected_version: &PythonVersion)
} }
#[cfg(target_os="windows")] #[cfg(target_os="windows")]
fn get_rustc_link_lib(version: &PythonVersion, _: bool) -> Result<String, String> { fn get_rustc_link_lib(version: &PythonVersion, _: &str, _: bool) -> Result<String, String> {
// Py_ENABLE_SHARED doesn't seem to be present on windows. // Py_ENABLE_SHARED doesn't seem to be present on windows.
Ok(format!("cargo:rustc-link-lib=python{}{}", version.major, Ok(format!("cargo:rustc-link-lib=python{}{}", version.major,
match version.minor { match version.minor {
@ -248,19 +260,20 @@ fn configure_from_path(expected_version: &PythonVersion) -> Result<String, Strin
let script = "import sys; import sysconfig; print(sys.version_info[0:2]); \ let script = "import sys; import sysconfig; print(sys.version_info[0:2]); \
print(sysconfig.get_config_var('LIBDIR')); \ print(sysconfig.get_config_var('LIBDIR')); \
print(sysconfig.get_config_var('Py_ENABLE_SHARED')); \ print(sysconfig.get_config_var('Py_ENABLE_SHARED')); \
print(sysconfig.get_config_var('LDVERSION')); \
print(sys.exec_prefix);"; print(sys.exec_prefix);";
let out = run_python_script(script).unwrap(); let out = run_python_script_try_interpreters(expected_version, script).unwrap();
let lines: Vec<&str> = out.split(NEWLINE_SEQUENCE).collect(); let lines: Vec<&str> = out.split(NEWLINE_SEQUENCE).collect();
let version: &str = lines[0]; let version: &str = lines[0];
let libpath: &str = lines[1]; let libpath: &str = lines[1];
let enable_shared: &str = lines[2]; let enable_shared: &str = lines[2];
let exec_prefix: &str = lines[3]; let ld_version: &str = lines[3];
let exec_prefix: &str = lines[4];
let interpreter_version = try!(get_interpreter_version(version, let interpreter_version = try!(get_interpreter_version(version, expected_version));
expected_version));
println!("{}", get_rustc_link_lib(&interpreter_version, println!("{}", get_rustc_link_lib(&interpreter_version,
enable_shared == "1").unwrap()); ld_version, enable_shared == "1").unwrap());
if libpath != "None" { if libpath != "None" {
println!("cargo:rustc-link-search=native={}", libpath); println!("cargo:rustc-link-search=native={}", libpath);