Skip to content

Commit

Permalink
refactor code ande remove the check of fortran
Browse files Browse the repository at this point in the history
  • Loading branch information
Dirreke committed Nov 29, 2024
1 parent c79abe9 commit 5956252
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 138 deletions.
139 changes: 83 additions & 56 deletions openblas-build/src/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Execute make of OpenBLAS, and its options
use crate::{check::*, error::*};
use std::{fs, path::*, process::Command, str::FromStr};
use std::{env, fs, path::*, process::Command, str::FromStr};
use walkdir::WalkDir;

/// Interface for 32-bit interger (LP64) and 64-bit integer (ILP64)
Expand Down Expand Up @@ -303,6 +303,14 @@ impl FromStr for Target {
}
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
pub struct Compilers {
pub cc: Option<String>,
pub fc: Option<String>,
pub hostcc: Option<String>,
pub ranlib: Option<String>,
}

/// make option generator
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Configure {
Expand All @@ -316,6 +324,7 @@ pub struct Configure {
pub dynamic_arch: bool,
pub interface: Interface,
pub target: Option<Target>,
pub compilers: Compilers,
}

impl Default for Configure {
Expand All @@ -331,45 +340,18 @@ impl Default for Configure {
dynamic_arch: false,
interface: Interface::LP64,
target: None,
compilers: Compilers::default(),
}
}
}

/// Deliverables of `make` command
pub struct Deliverables {
/// None if `no_static`
pub static_lib: Option<LibInspect>,
/// None if `no_shared`
pub shared_lib: Option<LibInspect>,
/// Inspection what `make` command really show.
pub make_conf: MakeConf,
}

impl Configure {
fn cross_compile_args(&self) -> Result<Vec<String>, Error> {
let mut args = Vec::new();
for name in ["CC", "FC", "HOSTCC"] {
if let Ok(value) = std::env::var(format!("OPENBLAS_{}", name)) {
args.push(format!("{}={}", name, value));
eprintln!("{}={}", name, value);
} else {
eprintln!("not found {}", name);
}
}
// for successful compile all 3 env-vars must be set
if !args.is_empty() && args.len() != 3 {
return Err(Error::MissingCrossCompileInfo);
}
// optional flags
for name in ["RANLIB"] {
if let Ok(value) = std::env::var(format!("OPENBLAS_{}", name)) {
args.push(format!("{}={}", name, value));
eprintln!("{}={}", name, value);
}
}
Ok(args)
}

fn make_args(&self) -> Vec<String> {
let mut args = Vec::new();
if self.no_static {
Expand Down Expand Up @@ -399,13 +381,18 @@ impl Configure {
if let Some(target) = self.target.as_ref() {
args.push(format!("TARGET={:?}", target))
}

for name in ["CC", "FC", "HOSTCC"] {
if let Ok(value) = std::env::var(format!("OPENBLAS_{}", name)) {
args.push(format!("{}={}", name, value));
}
if let Some(compiler_cc) = self.compilers.cc.as_ref() {
args.push(format!("CC={}", compiler_cc))
}
if let Some(compiler_fc) = self.compilers.fc.as_ref() {
args.push(format!("FC={}", compiler_fc))
}
if let Some(compiler_hostcc) = self.compilers.hostcc.as_ref() {
args.push(format!("HOSTCC={}", compiler_hostcc))
}
if let Some(compiler_ranlib) = self.compilers.ranlib.as_ref() {
args.push(format!("RANLIB={}", compiler_ranlib))
}

args
}

Expand All @@ -420,28 +407,24 @@ impl Configure {
pub fn inspect(&self, out_dir: impl AsRef<Path>) -> Result<Deliverables, Error> {
let out_dir = out_dir.as_ref();
let make_conf = MakeConf::new(out_dir.join("Makefile.conf"))?;

if !self.no_lapack && make_conf.no_fortran {
return Err(Error::FortranCompilerNotFound);
if !self.no_static {
let lib_path = out_dir.join("libopenblas.a");
if !lib_path.exists() {
return Err(Error::LibraryNotExist { path: lib_path });
}
}

Ok(Deliverables {
static_lib: if !self.no_static {
Some(LibInspect::new(out_dir.join("libopenblas.a"))?)
if !self.no_shared {
let lib_path = if cfg!(target_os = "macos") {
out_dir.join("libopenblas.dylib")
} else {
None
},
shared_lib: if !self.no_shared {
Some(LibInspect::new(if cfg!(target_os = "macos") {
out_dir.join("libopenblas.dylib")
} else {
out_dir.join("libopenblas.so")
})?)
} else {
None
},
make_conf,
})
out_dir.join("libopenblas.so")
};
if !lib_path.exists() {
return Err(Error::LibraryNotExist { path: lib_path });
}
}

Ok(Deliverables { make_conf })
}

/// Build OpenBLAS
Expand Down Expand Up @@ -492,6 +475,14 @@ impl Configure {
}
}

// check if cross compile is needed
let build_target = env::var("TARGET").unwrap_or_default();
let build_host = env::var("HOST").unwrap_or_default();
let is_cross_compile = build_target != build_host;
if is_cross_compile && (self.compilers.cc.is_none() || self.compilers.hostcc.is_none()) {
return Err(Error::MissingCrossCompileInfo);
}

// Run `make` as an subprocess
//
// - This will automatically run in parallel without `-j` flag
Expand All @@ -507,7 +498,6 @@ impl Configure {
.stdout(out)
.stderr(err)
.args(self.make_args())
.args(self.cross_compile_args()?)
.args(["all"])
.env_remove("TARGET")
.check_call()
Expand All @@ -524,6 +514,43 @@ impl Configure {
return Err(e);
}
}
#[cfg(target_os = "macos")]
if !self.no_shared {
let out =
fs::File::create(out_dir.join("out_install.log")).expect("Cannot create log file");
let err =
fs::File::create(out_dir.join("err_install.log")).expect("Cannot create log file");
match Command::new("make")
.arg("install")
.arg(format!("PREFIX={}", out_dir.display()))
.current_dir(out_dir)
.stdout(out)
.stderr(err)
.env_remove("TARGET")
.check_call()
{
Ok(_) => {}
Err(err @ Error::NonZeroExitStatus { .. }) => {
eprintln!(
"{}",
fs::read_to_string(out_dir.join("err_install.log"))
.expect("Cannot read log file")
);
return Err(err);
}
Err(e) => {
return Err(e);
}
}
println!("cargo:rustc-link-search={}", out_dir.join("lib").display(),);
}
let a = Command::new("ls")
.current_dir(out_dir.join("lib/"))
.output()
.unwrap()
.stdout;
let a = String::from_utf8(a).unwrap();
eprintln!("{}", a);

self.inspect(out_dir)
}
Expand Down
4 changes: 4 additions & 0 deletions openblas-build/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ impl MakeConf {
"FEXTRALIB" => detail.f_extra_libs = LinkFlags::parse(entry[1])?,
_ => continue,
}
#[cfg(target_os = "macos")]
detail.c_extra_libs.libs.retain(|lib| lib != "to_library");
}
Ok(detail)
}
Expand All @@ -103,11 +105,13 @@ impl MakeConf {
/// - Linked shared libraries using `objdump -p` external command.
/// - Global "T" symbols in the text (code) section of library using `nm -g` external command.
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct LibInspect {
pub libs: Vec<String>,
pub symbols: Vec<String>,
}

#[allow(dead_code)]
impl LibInspect {
/// Inspect library file
///
Expand Down
87 changes: 5 additions & 82 deletions openblas-src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ fn main() {
}

/// Build OpenBLAS using openblas-build crate
#[cfg(target_os = "linux")]
fn build() {
println!("cargo:rerun-if-env-changed=OPENBLAS_TARGET");
println!("cargo:rerun-if-env-changed=OPENBLAS_CC");
Expand Down Expand Up @@ -150,6 +149,10 @@ fn build() {
// Do not default to the native target (represented by `cfg.target == None`)
// because most user set `$OPENBLAS_TARGET` explicitly will hope not to use the native target.
}
cfg.compilers.cc = env::var("OPENBLAS_CC").ok();
cfg.compilers.hostcc = env::var("OPENBLAS_HOSTCC").ok();
cfg.compilers.fc = env::var("OPENBLAS_FC").ok();
cfg.compilers.ranlib = env::var("OPENBLAS_RANLIB").ok();

let output = if feature_enabled("cache") {
use std::hash::*;
Expand Down Expand Up @@ -183,7 +186,7 @@ fn build() {
//
// Be sure that `cargo:warning` is shown only when openblas-src is build as path dependency...
// https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargowarningmessage
if !feature_enabled("static") {
if !feature_enabled("static") && cfg!(not(target_os = "macos")) {
println!(
"cargo:warning=OpenBLAS is built as a shared library. You need to set LD_LIBRARY_PATH={}",
output.display()
Expand All @@ -207,83 +210,3 @@ fn build() {
println!("cargo:rustc-link-lib={}", lib);
}
}

/// openblas-src 0.9.0 compatible `make` runner
///
/// This cannot detect that OpenBLAS skips LAPACK build due to the absense of Fortran compiler.
/// openblas-build crate can detect it by sneaking OpenBLAS build system, but only works on Linux.
///
#[cfg(not(target_os = "linux"))]
fn build() {
use std::fs;

let output = PathBuf::from(env::var("OUT_DIR").unwrap().replace(r"\", "/"));
let mut make = Command::new("make");
make.args(&["all"])
.arg(format!("BINARY={}", binary()))
.arg(format!(
"{}_CBLAS=1",
if feature_enabled("cblas") {
"YES"
} else {
"NO"
}
))
.arg(format!(
"{}_LAPACKE=1",
if feature_enabled("lapacke") {
"YES"
} else {
"NO"
}
));
match env::var("OPENBLAS_ARGS") {
Ok(args) => {
make.args(args.split_whitespace());
}
_ => (),
};
if let Ok(num_jobs) = env::var("NUM_JOBS") {
make.arg(format!("-j{}", num_jobs));
}
let target = match env::var("OPENBLAS_TARGET") {
Ok(target) => {
make.arg(format!("TARGET={}", target));
target
}
_ => env::var("TARGET").unwrap(),
};
env::remove_var("TARGET");
let source = if feature_enabled("cache") {
PathBuf::from(format!("source_{}", target.to_lowercase()))
} else {
output.join(format!("source_{}", target.to_lowercase()))
};

if !source.exists() {
let source_tmp = openblas_build::download(&output).unwrap();
fs::rename(&source_tmp, &source).unwrap();
}
for name in &vec!["CC", "FC", "HOSTCC"] {
if let Ok(value) = env::var(format!("OPENBLAS_{}", name)) {
make.arg(format!("{}={}", name, value));
}
}
run(&mut make.current_dir(&source));
run(Command::new("make")
.arg("install")
.arg(format!("DESTDIR={}", output.display()))
.current_dir(&source));
println!(
"cargo:rustc-link-search={}",
output.join("opt/OpenBLAS/lib").display(),
);

fn binary() -> &'static str {
if cfg!(target_pointer_width = "32") {
"32"
} else {
"64"
}
}
}

0 comments on commit 5956252

Please sign in to comment.