Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect TARGET, CC, HOSTCC, FC automically when cross-compiling #129

Merged
merged 1 commit into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions Cross.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,11 @@ pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update && apt-get --assume-yes install libopenblas-dev:$CROSS_DEB_ARCH libssl-dev"
]
[target.aarch64-unknown-linux-gnu.env]
passthrough = [
"OPENBLAS_CC=aarch64-linux-gnu-gcc",
"OPENBLAS_HOSTCC=gcc",
"OPENBLAS_FC=aarch64-linux-gnu-gfortran",
"OPENBLAS_TARGET=ARMV8"
]

[target.armv7-unknown-linux-gnueabihf]
image = "ghcr.io/cross-rs/armv7-unknown-linux-gnueabihf:main"
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update && apt-get --assume-yes install libopenblas-dev:$CROSS_DEB_ARCH libssl-dev"
]
[target.armv7-unknown-linux-gnueabihf.env]
passthrough = [
"OPENBLAS_CC=arm-linux-gnueabihf-gcc",
"OPENBLAS_HOSTCC=gcc",
"OPENBLAS_FC=arm-linux-gnueabihf-gfortran",
"OPENBLAS_TARGET=ARMV7"
]

1 change: 1 addition & 0 deletions openblas-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ exclude = ["test_build/"]

[dependencies]
anyhow = "1.0.68"
cc = "1.0"
flate2 = "1.0.25"
tar = "0.4.38"
thiserror = "2.0"
Expand Down
136 changes: 109 additions & 27 deletions openblas-build/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub enum Interface {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types)] // to use original identifiers
pub enum Target {
// for DYNNAMIC_ARCH=1
GENERIC,
// X86/X86_64 Intel
P2,
KATMAI,
Expand Down Expand Up @@ -156,6 +158,7 @@ impl FromStr for Target {

fn from_str(s: &str) -> Result<Self, Self::Err> {
let target = match s.to_ascii_lowercase().as_str() {
"generic" => Self::GENERIC,
// X86/X86_64 Intel
"p2" => Self::P2,
"katamai" => Self::KATMAI,
Expand Down Expand Up @@ -302,6 +305,28 @@ impl FromStr for Target {
}
}

impl Target {
fn get_generic_target() -> Option<Self> {
let target = env::var("TARGET").unwrap();
let target_arch = target.split('-').nth(0).unwrap();
match target_arch {
"aarch64" => Some(Target::ARMV8),
"arm" => Some(Target::ARMV6),
"armv5te" => Some(Target::ARMV5),
"armv6" => Some(Target::ARMV6),
"armv7" => Some(Target::ARMV7),
"loongarch64" => Some(Target::LOONGSONGENERIC),
"mips64" => Some(Target::MIPS64_GENERIC),
"mips64el" => Some(Target::MIPS64_GENERIC),
"riscv64" => Some(Target::RISCV64_GENERIC),
"csky" => Some(Target::CK860FV),
"sparc" => Some(Target::SPARCV7),
//TODO: add more generic targets
_ => None,
}
}
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
pub struct Compilers {
pub cc: Option<String>,
Expand Down Expand Up @@ -345,48 +370,101 @@ impl Default for Configure {
}

impl Configure {
fn make_args(&self) -> Vec<String> {
fn make_args(&self) -> Result<Vec<String>, Error> {
// check if it is cross-compilation
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;

let mut args = Vec::new();
if self.no_static {
args.push("NO_STATIC=1".into())
args.push("NO_STATIC=1".into());
}
if self.no_shared {
args.push("NO_SHARED=1".into())
args.push("NO_SHARED=1".into());
}
if self.no_cblas {
args.push("NO_CBLAS=1".into())
args.push("NO_CBLAS=1".into());
}
if self.no_lapack {
args.push("NO_LAPACK=1".into())
args.push("NO_LAPACK=1".into());
}
if self.no_lapacke {
args.push("NO_LAPACKE=1".into())
args.push("NO_LAPACKE=1".into());
}
if self.use_thread {
args.push("USE_THREAD=1".into())
args.push("USE_THREAD=1".into());
}
if self.use_openmp {
args.push("USE_OPENMP=1".into())
args.push("USE_OPENMP=1".into());
}
if matches!(self.interface, Interface::ILP64) {
args.push("INTERFACE64=1".into())
args.push("INTERFACE64=1".into());
}
if let Some(target) = self.target.as_ref() {
args.push(format!("TARGET={:?}", target))
args.push(format!("TARGET={:?}", target));
} else if is_cross_compile {
if let Some(target) = Target::get_generic_target() {
args.push(format!("TARGET={:?}", target));
} else {
return Err(Error::MissingCrossCompileInfo {
info: "TARGET".to_string(),
});
}
}
if let Some(compiler_cc) = self.compilers.cc.as_ref() {
args.push(format!("CC={}", compiler_cc))

let mut cc_compiler = self.compilers.cc.clone();
if let Some(cc) = self.compilers.cc.as_ref() {
args.push(format!("CC={}", cc));
} else if is_cross_compile {
let compiler = cc::Build::new().get_compiler();
let compiler_path = compiler.path().to_str();
if let Some(cc) = compiler_path {
args.push(format!("CC={}", cc));
cc_compiler = Some(cc.to_string());
} else {
return Err(Error::MissingCrossCompileInfo {
info: "CC".to_string(),
});
}
}
if let Some(compiler_fc) = self.compilers.fc.as_ref() {
args.push(format!("FC={}", compiler_fc))
if let Some(fc) = self.compilers.fc.as_ref() {
args.push(format!("FC={}", fc))
} else if is_cross_compile {
let mut fortran = false;
if let Some(cc) = cc_compiler {
let fc = cc
.replace("gcc", "gfortran")
.replace("clang", "flang")
.replace("icc", "ifort");

if Command::new(&fc).arg("--version").check_call().is_ok() {
args.push(format!("FC={}", fc));
fortran = true;
}
}
if !fortran {
println!("cargo:warning=OpenBLAS: Detecting fortran compiler failed. Can only compile BLAS and f2c-converted LAPACK.");
args.push("NOFORTRAN=1".into());
}
}
if let Some(compiler_hostcc) = self.compilers.hostcc.as_ref() {
args.push(format!("HOSTCC={}", compiler_hostcc))
if let Some(hostcc) = self.compilers.hostcc.as_ref() {
args.push(format!("HOSTCC={}", hostcc))
} else if is_cross_compile {
let compiler = cc::Build::new().target(build_host.as_str()).get_compiler();
let compiler_path = compiler.path().to_str();
if let Some(hostcc) = compiler_path {
args.push(format!("HOSTCC={}", hostcc));
} else {
return Err(Error::MissingCrossCompileInfo {
info: "HOSTCC".to_string(),
});
}
}
if let Some(compiler_ranlib) = self.compilers.ranlib.as_ref() {
args.push(format!("RANLIB={}", compiler_ranlib))
if let Some(ranlib) = self.compilers.ranlib.as_ref() {
args.push(format!("RANLIB={}", ranlib))
}
args
Ok(args)
}

/// Build OpenBLAS
Expand All @@ -407,12 +485,12 @@ 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);
}
// 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
//
Expand All @@ -428,7 +506,7 @@ impl Configure {
.current_dir(root)
.stdout(out)
.stderr(err)
.args(self.make_args())
.args(self.make_args()?)
.args(["all"])
.env_remove("TARGET")
.check_call()
Expand All @@ -446,7 +524,11 @@ impl Configure {
}
}

MakeConf::new(root.join("Makefile.conf"))
let make_conf = MakeConf::new(root.join("Makefile.conf"))?;
if make_conf.no_fortran {
println!("cargo:warning=OpenBLAS: Detecting fortran compiler failed. Only BLAS and f2c-converted LAPACK are compiled.");
}
Ok(make_conf)
}
}

Expand Down
7 changes: 5 additions & 2 deletions openblas-build/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ pub enum Error {
#[error("Target {} is unsupported", target)]
UnsupportedTarget { target: String },

#[error("Insufficient cross compile information, need all of OPENBLAS_{{CC, FC, HOSTCC}}")]
MissingCrossCompileInfo,
#[error(
"Cross compile information is missing and cannot be inferred, {}",
info
)]
MissingCrossCompileInfo { info: String },

#[error("Other IO errors: {0:?}")]
IOError(#[from] io::Error),
Expand Down
28 changes: 23 additions & 5 deletions openblas-src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ fn build() {
} else {
PathBuf::from(env::var("OUT_DIR").unwrap())
};
let source = openblas_build::download(&output).unwrap();

// If OpenBLAS is build as shared, user of openblas-src will have to find `libopenblas.so` at runtime.
//
Expand All @@ -188,15 +189,32 @@ 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") && cfg!(not(target_os = "macos")) {
if !feature_enabled("static") {
let ld_name = if cfg!(target_os = "macos") {
"DYLD_LIBRARY_PATH"
} else {
"LD_LIBRARY_PATH"
};
println!(
"cargo:warning=OpenBLAS is built as a shared library. You need to set LD_LIBRARY_PATH={}",
output.display()
"cargo:warning=OpenBLAS is built as a shared library. You need to set {}={}",
ld_name,
source.display()
);
}

let source = openblas_build::download(&output).unwrap();
let make_conf = cfg.build(&source).unwrap();
let build_result = cfg.build(&source);
let make_conf = match build_result {
Ok(c) => c,
Err(openblas_build::error::Error::MissingCrossCompileInfo { info }) => {
panic!(
"Cross compile information is missing and cannot be inferred: OPENBLAS_{}",
info
);
}
Err(e) => {
panic!("OpenBLAS build failed: {}", e);
}
};

println!("cargo:rustc-link-search={}", source.display());
for search_path in &make_conf.c_extra_libs.search_paths {
Expand Down