Skip to content

Commit dbf4edb

Browse files
committed
Detect TARGET, CC, HOSTCC, FC automically
1 parent 5b7c298 commit dbf4edb

File tree

5 files changed

+135
-48
lines changed

5 files changed

+135
-48
lines changed

Cross.toml

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,11 @@ pre-build = [
44
"dpkg --add-architecture $CROSS_DEB_ARCH",
55
"apt-get update && apt-get --assume-yes install libopenblas-dev:$CROSS_DEB_ARCH libssl-dev"
66
]
7-
[target.aarch64-unknown-linux-gnu.env]
8-
passthrough = [
9-
"OPENBLAS_CC=aarch64-linux-gnu-gcc",
10-
"OPENBLAS_HOSTCC=gcc",
11-
"OPENBLAS_FC=aarch64-linux-gnu-gfortran",
12-
"OPENBLAS_TARGET=ARMV8"
13-
]
147

158
[target.armv7-unknown-linux-gnueabihf]
169
image = "ghcr.io/cross-rs/armv7-unknown-linux-gnueabihf:main"
1710
pre-build = [
1811
"dpkg --add-architecture $CROSS_DEB_ARCH",
1912
"apt-get update && apt-get --assume-yes install libopenblas-dev:$CROSS_DEB_ARCH libssl-dev"
2013
]
21-
[target.armv7-unknown-linux-gnueabihf.env]
22-
passthrough = [
23-
"OPENBLAS_CC=arm-linux-gnueabihf-gcc",
24-
"OPENBLAS_HOSTCC=gcc",
25-
"OPENBLAS_FC=arm-linux-gnueabihf-gfortran",
26-
"OPENBLAS_TARGET=ARMV7"
27-
]
2814

openblas-build/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ exclude = ["test_build/"]
1313

1414
[dependencies]
1515
anyhow = "1.0.68"
16+
cc = "1.0"
1617
flate2 = "1.0.25"
1718
tar = "0.4.38"
1819
thiserror = "2.0"

openblas-build/src/build.rs

Lines changed: 109 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pub enum Interface {
1414
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1515
#[allow(non_camel_case_types)] // to use original identifiers
1616
pub enum Target {
17+
// for DYNNAMIC_ARCH=1
18+
GENERIC,
1719
// X86/X86_64 Intel
1820
P2,
1921
KATMAI,
@@ -156,6 +158,7 @@ impl FromStr for Target {
156158

157159
fn from_str(s: &str) -> Result<Self, Self::Err> {
158160
let target = match s.to_ascii_lowercase().as_str() {
161+
"generic" => Self::GENERIC,
159162
// X86/X86_64 Intel
160163
"p2" => Self::P2,
161164
"katamai" => Self::KATMAI,
@@ -302,6 +305,28 @@ impl FromStr for Target {
302305
}
303306
}
304307

308+
impl Target {
309+
fn get_generic_target() -> Option<Self> {
310+
let target = env::var("TARGET").unwrap();
311+
let target_arch = target.split('-').nth(0).unwrap();
312+
match target_arch {
313+
"aarch64" => Some(Target::ARMV8),
314+
"arm" => Some(Target::ARMV6),
315+
"armv5te" => Some(Target::ARMV5),
316+
"armv6" => Some(Target::ARMV6),
317+
"armv7" => Some(Target::ARMV7),
318+
"loongarch64" => Some(Target::LOONGSONGENERIC),
319+
"mips64" => Some(Target::MIPS64_GENERIC),
320+
"mips64el" => Some(Target::MIPS64_GENERIC),
321+
"riscv64" => Some(Target::RISCV64_GENERIC),
322+
"csky" => Some(Target::CK860FV),
323+
"sparc" => Some(Target::SPARCV7),
324+
//TODO: add more generic targets
325+
_ => None,
326+
}
327+
}
328+
}
329+
305330
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
306331
pub struct Compilers {
307332
pub cc: Option<String>,
@@ -345,48 +370,101 @@ impl Default for Configure {
345370
}
346371

347372
impl Configure {
348-
fn make_args(&self) -> Vec<String> {
373+
fn make_args(&self) -> Result<Vec<String>, Error> {
374+
// check if it is cross-compilation
375+
let build_target = env::var("TARGET").unwrap_or_default();
376+
let build_host = env::var("HOST").unwrap_or_default();
377+
let is_cross_compile = build_target != build_host;
378+
349379
let mut args = Vec::new();
350380
if self.no_static {
351-
args.push("NO_STATIC=1".into())
381+
args.push("NO_STATIC=1".into());
352382
}
353383
if self.no_shared {
354-
args.push("NO_SHARED=1".into())
384+
args.push("NO_SHARED=1".into());
355385
}
356386
if self.no_cblas {
357-
args.push("NO_CBLAS=1".into())
387+
args.push("NO_CBLAS=1".into());
358388
}
359389
if self.no_lapack {
360-
args.push("NO_LAPACK=1".into())
390+
args.push("NO_LAPACK=1".into());
361391
}
362392
if self.no_lapacke {
363-
args.push("NO_LAPACKE=1".into())
393+
args.push("NO_LAPACKE=1".into());
364394
}
365395
if self.use_thread {
366-
args.push("USE_THREAD=1".into())
396+
args.push("USE_THREAD=1".into());
367397
}
368398
if self.use_openmp {
369-
args.push("USE_OPENMP=1".into())
399+
args.push("USE_OPENMP=1".into());
370400
}
371401
if matches!(self.interface, Interface::ILP64) {
372-
args.push("INTERFACE64=1".into())
402+
args.push("INTERFACE64=1".into());
373403
}
374404
if let Some(target) = self.target.as_ref() {
375-
args.push(format!("TARGET={:?}", target))
405+
args.push(format!("TARGET={:?}", target));
406+
} else if is_cross_compile {
407+
if let Some(target) = Target::get_generic_target() {
408+
args.push(format!("TARGET={:?}", target));
409+
} else {
410+
return Err(Error::MissingCrossCompileInfo {
411+
info: "TARGET".to_string(),
412+
});
413+
}
376414
}
377-
if let Some(compiler_cc) = self.compilers.cc.as_ref() {
378-
args.push(format!("CC={}", compiler_cc))
415+
416+
let mut cc_compiler = self.compilers.cc.clone();
417+
if let Some(cc) = self.compilers.cc.as_ref() {
418+
args.push(format!("CC={}", cc));
419+
} else if is_cross_compile {
420+
let compiler = cc::Build::new().get_compiler();
421+
let compiler_path = compiler.path().to_str();
422+
if let Some(cc) = compiler_path {
423+
args.push(format!("CC={}", cc));
424+
cc_compiler = Some(cc.to_string());
425+
} else {
426+
return Err(Error::MissingCrossCompileInfo {
427+
info: "CC".to_string(),
428+
});
429+
}
379430
}
380-
if let Some(compiler_fc) = self.compilers.fc.as_ref() {
381-
args.push(format!("FC={}", compiler_fc))
431+
if let Some(fc) = self.compilers.fc.as_ref() {
432+
args.push(format!("FC={}", fc))
433+
} else if is_cross_compile {
434+
let mut fortran = false;
435+
if let Some(cc) = cc_compiler {
436+
let fc = cc
437+
.replace("gcc", "gfortran")
438+
.replace("clang", "flang")
439+
.replace("icc", "ifort");
440+
441+
if Command::new(&fc).arg("--version").check_call().is_ok() {
442+
args.push(format!("FC={}", fc));
443+
fortran = true;
444+
}
445+
}
446+
if !fortran {
447+
println!("cargo:warning=OpenBLAS: Detecting fortran compiler failed. Can only compile BLAS and f2c-converted LAPACK.");
448+
args.push("NOFORTRAN=1".into());
449+
}
382450
}
383-
if let Some(compiler_hostcc) = self.compilers.hostcc.as_ref() {
384-
args.push(format!("HOSTCC={}", compiler_hostcc))
451+
if let Some(hostcc) = self.compilers.hostcc.as_ref() {
452+
args.push(format!("HOSTCC={}", hostcc))
453+
} else if is_cross_compile {
454+
let compiler = cc::Build::new().target(build_host.as_str()).get_compiler();
455+
let compiler_path = compiler.path().to_str();
456+
if let Some(hostcc) = compiler_path {
457+
args.push(format!("HOSTCC={}", hostcc));
458+
} else {
459+
return Err(Error::MissingCrossCompileInfo {
460+
info: "HOSTCC".to_string(),
461+
});
462+
}
385463
}
386-
if let Some(compiler_ranlib) = self.compilers.ranlib.as_ref() {
387-
args.push(format!("RANLIB={}", compiler_ranlib))
464+
if let Some(ranlib) = self.compilers.ranlib.as_ref() {
465+
args.push(format!("RANLIB={}", ranlib))
388466
}
389-
args
467+
Ok(args)
390468
}
391469

392470
/// Build OpenBLAS
@@ -407,12 +485,12 @@ impl Configure {
407485
}
408486

409487
// check if cross compile is needed
410-
let build_target = env::var("TARGET").unwrap_or_default();
411-
let build_host = env::var("HOST").unwrap_or_default();
412-
let is_cross_compile = build_target != build_host;
413-
if is_cross_compile && (self.compilers.cc.is_none() || self.compilers.hostcc.is_none()) {
414-
return Err(Error::MissingCrossCompileInfo);
415-
}
488+
// let build_target = env::var("TARGET").unwrap_or_default();
489+
// let build_host = env::var("HOST").unwrap_or_default();
490+
// let is_cross_compile = build_target != build_host;
491+
// if is_cross_compile && (self.compilers.cc.is_none() || self.compilers.hostcc.is_none()) {
492+
// return Err(Error::MissingCrossCompileInfo);
493+
// }
416494

417495
// Run `make` as an subprocess
418496
//
@@ -428,7 +506,7 @@ impl Configure {
428506
.current_dir(root)
429507
.stdout(out)
430508
.stderr(err)
431-
.args(self.make_args())
509+
.args(self.make_args()?)
432510
.args(["all"])
433511
.env_remove("TARGET")
434512
.check_call()
@@ -446,7 +524,11 @@ impl Configure {
446524
}
447525
}
448526

449-
MakeConf::new(root.join("Makefile.conf"))
527+
let make_conf = MakeConf::new(root.join("Makefile.conf"))?;
528+
if make_conf.no_fortran {
529+
println!("cargo:warning=OpenBLAS: Detecting fortran compiler failed. Only BLAS and f2c-converted LAPACK are compiled.");
530+
}
531+
Ok(make_conf)
450532
}
451533
}
452534

openblas-build/src/error.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ pub enum Error {
2424
#[error("Target {} is unsupported", target)]
2525
UnsupportedTarget { target: String },
2626

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

3033
#[error("Other IO errors: {0:?}")]
3134
IOError(#[from] io::Error),

openblas-src/build.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ fn build() {
177177
} else {
178178
PathBuf::from(env::var("OUT_DIR").unwrap())
179179
};
180+
let source = openblas_build::download(&output).unwrap();
180181

181182
// If OpenBLAS is build as shared, user of openblas-src will have to find `libopenblas.so` at runtime.
182183
//
@@ -188,15 +189,29 @@ fn build() {
188189
//
189190
// Be sure that `cargo:warning` is shown only when openblas-src is build as path dependency...
190191
// https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargowarningmessage
191-
if !feature_enabled("static") && cfg!(not(target_os = "macos")) {
192+
if !feature_enabled("static") {
193+
let ld_name = if cfg!(target_os = "macos") {
194+
"DYLD_LIBRARY_PATH"
195+
} else {
196+
"LD_LIBRARY_PATH"
197+
};
192198
println!(
193-
"cargo:warning=OpenBLAS is built as a shared library. You need to set LD_LIBRARY_PATH={}",
194-
output.display()
199+
"cargo:warning=OpenBLAS is built as a shared library. You need to set {}={}",
200+
ld_name,
201+
source.display()
195202
);
196203
}
197204

198-
let source = openblas_build::download(&output).unwrap();
199-
let make_conf = cfg.build(&source).unwrap();
205+
let build_result = cfg.build(&source);
206+
let make_conf = match build_result {
207+
Ok(c) => c,
208+
Err(openblas_build::error::Error::MissingCrossCompileInfo { info }) => {
209+
panic!("Cross compile information is missing and cannot be inferred: OPENBLAS_{}", info);
210+
}
211+
Err(e) => {
212+
panic!("OpenBLAS build failed: {}", e);
213+
}
214+
};
200215

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

0 commit comments

Comments
 (0)