Skip to content

Commit 8166234

Browse files
committed
Allow cross-compiling outside of build.rs
Do not expect CARGO_CFG_TARGET_OS/CARGO_CFG_TARGET_ARCH to always be available, and instead try to determine this information based on the rustc target tuple.
1 parent fa8513a commit 8166234

File tree

1 file changed

+142
-60
lines changed

1 file changed

+142
-60
lines changed

src/lib.rs

Lines changed: 142 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -461,60 +461,22 @@ impl Config {
461461
if !self.defined("CMAKE_TOOLCHAIN_FILE") {
462462
if let Some(s) = self.getenv_target_os("CMAKE_TOOLCHAIN_FILE") {
463463
self.define("CMAKE_TOOLCHAIN_FILE", s);
464-
} else if target.contains("redox") {
464+
} else if target != host {
465+
self.define("CMAKE_CROSSCOMPILING", "True");
466+
467+
// Set `CMAKE_SYSTEM_NAME` and `CMAKE_SYSTEM_PROCESSOR` to
468+
// allow cross-compiling to work.
469+
//
470+
// FIXME: Also set `CMAKE_SYSTEM_VERSION` somehow?
465471
if !self.defined("CMAKE_SYSTEM_NAME") {
466-
self.define("CMAKE_SYSTEM_NAME", "Generic");
472+
let system_name = get_system_name(&target);
473+
self.define("CMAKE_SYSTEM_NAME", system_name);
474+
}
475+
476+
if !self.defined("CMAKE_SYSTEM_PROCESSOR") {
477+
let system_processor = get_system_processor(&target);
478+
self.define("CMAKE_SYSTEM_PROCESSOR", system_processor);
467479
}
468-
} else if target != host && !self.defined("CMAKE_SYSTEM_NAME") {
469-
// Set CMAKE_SYSTEM_NAME and CMAKE_SYSTEM_PROCESSOR when cross compiling
470-
let os = getenv_unwrap("CARGO_CFG_TARGET_OS");
471-
let arch = getenv_unwrap("CARGO_CFG_TARGET_ARCH");
472-
// CMAKE_SYSTEM_NAME list
473-
// https://gitlab.kitware.com/cmake/cmake/-/issues/21489#note_1077167
474-
//
475-
// CMAKE_SYSTEM_PROCESSOR
476-
// some of the values come from https://en.wikipedia.org/wiki/Uname
477-
let (system_name, system_processor) = match (os.as_str(), arch.as_str()) {
478-
("android", "arm") => ("Android", "armv7-a"),
479-
("android", "x86") => ("Android", "i686"),
480-
("android", arch) => ("Android", arch),
481-
("dragonfly", arch) => ("DragonFly", arch),
482-
("macos", "aarch64") => ("Darwin", "arm64"),
483-
("macos", arch) => ("Darwin", arch),
484-
("freebsd", "x86_64") => ("FreeBSD", "amd64"),
485-
("freebsd", arch) => ("FreeBSD", arch),
486-
("fuchsia", arch) => ("Fuchsia", arch),
487-
("haiku", arch) => ("Haiku", arch),
488-
("ios", "aarch64") => ("iOS", "arm64"),
489-
("ios", arch) => ("iOS", arch),
490-
("linux", arch) => {
491-
let name = "Linux";
492-
match arch {
493-
"powerpc" => (name, "ppc"),
494-
"powerpc64" => (name, "ppc64"),
495-
"powerpc64le" => (name, "ppc64le"),
496-
_ => (name, arch),
497-
}
498-
}
499-
("netbsd", arch) => ("NetBSD", arch),
500-
("openbsd", "x86_64") => ("OpenBSD", "amd64"),
501-
("openbsd", arch) => ("OpenBSD", arch),
502-
("solaris", arch) => ("SunOS", arch),
503-
("tvos", "aarch64") => ("tvOS", "arm64"),
504-
("tvos", arch) => ("tvOS", arch),
505-
("visionos", "aarch64") => ("visionOS", "arm64"),
506-
("visionos", arch) => ("visionOS", arch),
507-
("watchos", "aarch64") => ("watchOS", "arm64"),
508-
("watchos", arch) => ("watchOS", arch),
509-
("windows", "x86_64") => ("Windows", "AMD64"),
510-
("windows", "x86") => ("Windows", "X86"),
511-
("windows", "aarch64") => ("Windows", "ARM64"),
512-
("none", arch) => ("Generic", arch),
513-
// Others
514-
(os, arch) => (os, arch),
515-
};
516-
self.define("CMAKE_SYSTEM_NAME", system_name);
517-
self.define("CMAKE_SYSTEM_PROCESSOR", system_processor);
518480
}
519481
}
520482

@@ -681,14 +643,12 @@ impl Config {
681643
panic!("unsupported msvc target: {}", target);
682644
}
683645
}
684-
} else if target.contains("darwin") && !self.defined("CMAKE_OSX_ARCHITECTURES") {
685-
if target.contains("x86_64") {
686-
cmd.arg("-DCMAKE_OSX_ARCHITECTURES=x86_64");
687-
} else if target.contains("aarch64") {
688-
cmd.arg("-DCMAKE_OSX_ARCHITECTURES=arm64");
689-
} else {
690-
panic!("unsupported darwin target: {}", target);
691-
}
646+
}
647+
if target.contains("apple") && !self.defined("CMAKE_OSX_ARCHITECTURES") {
648+
// Make sure that CMake does not build universal binaries on macOS.
649+
// Explicitly specify the one single target architecture.
650+
let arch = get_system_processor(&target);
651+
self.define("CMAKE_OSX_ARCHITECTURES", arch);
692652
}
693653
if let Some(ref generator) = generator {
694654
cmd.arg("-G").arg(generator);
@@ -1142,6 +1102,128 @@ fn uses_named_pipe_jobserver(makeflags: &OsStr) -> bool {
11421102
.contains("--jobserver-auth=fifo:")
11431103
}
11441104

1105+
/// Find [`CMAKE_SYSTEM_NAME`] based on `$CARGO_CFG_TARGET_OS` if available,
1106+
/// otherwise try to infer it from the given target.
1107+
///
1108+
/// [`CMAKE_SYSTEM_NAME`]: https://cmake.org/cmake/help/latest/variable/CMAKE_SYSTEM_NAME.html
1109+
fn get_system_name(target: &str) -> &'static str {
1110+
let mapping = [
1111+
("aix", "AIX"),
1112+
("android", "Android"), // Matches "*-linux-android*".
1113+
("cygwin", "CYGWIN"),
1114+
("darwin", "Darwin"), // Matches target triple "*-apple-darwin".
1115+
("dragonfly", "DragonFly"),
1116+
("emscripten", "Emscripten"),
1117+
("freebsd", "FreeBSD"),
1118+
("fuchsia", "Fuchsia"),
1119+
("haiku", "Haiku"),
1120+
("illumos", "SunOS"),
1121+
("ios", "iOS"),
1122+
("linux", "Linux"), // Must be after "android".
1123+
("macos", "Darwin"), // Used when matching `CARGO_CFG_TARGET_OS`.
1124+
("netbsd", "NetBSD"),
1125+
("openbsd", "OpenBSD"),
1126+
("redox", "Generic"),
1127+
("solaris", "SunOS"),
1128+
("tvos", "tvOS"),
1129+
("visionos", "visionOS"),
1130+
("wasi", "WASI"),
1131+
("watchos", "watchOS"),
1132+
("windows", "Windows"),
1133+
("none", "Generic"), // Must be last match to handle x86_64-unknown-linux-none.
1134+
];
1135+
1136+
// `CARGO_CFG_TARGET_OS` is available when in build.rs, and is usually
1137+
// more correct than trying to extract the value from `TARGET`.
1138+
if let Some(os) = std::env::var_os("CARGO_CFG_TARGET_OS") {
1139+
let os = os.to_str().expect("CARGO_CFG_TARGET_OS must be UTF-8");
1140+
for (known_os, system_name) in mapping {
1141+
if os == known_os {
1142+
return system_name;
1143+
}
1144+
}
1145+
} else {
1146+
for (known_os, system_name) in mapping {
1147+
// Fuzzy find based on `target`.
1148+
// This is brittle, and should ideally be avoided.
1149+
if target.contains(known_os) {
1150+
return system_name;
1151+
}
1152+
}
1153+
}
1154+
1155+
warn!("unknown OS for target {target:?}, falling back to Generic");
1156+
"Generic"
1157+
}
1158+
1159+
/// Find [`CMAKE_SYSTEM_PROCESSOR`] based on the given `arch` if available,
1160+
/// otherwise try to infer it from the given target.
1161+
///
1162+
/// [`CMAKE_SYSTEM_PROCESSOR`]: https://cmake.org/cmake/help/latest/variable/CMAKE_SYSTEM_PROCESSOR.html#system-names-known-to-cmake
1163+
fn get_system_processor(target: &str) -> &str {
1164+
let (full_arch, _) = target
1165+
.split_once("-")
1166+
.expect("rustc target must have at least two components");
1167+
1168+
// `CMAKE_SYSTEM_PROCESSOR` is based on `CMAKE_HOST_SYSTEM_PROCESSOR`,
1169+
// which is set differently based on platform.
1170+
1171+
// Windows: Value of `$PROCESSOR_ARCHITECTURE` by default.
1172+
if target.contains("windows") {
1173+
return match full_arch {
1174+
"i586" | "i686" => "X86",
1175+
"x86_64" => "AMD64",
1176+
"aarch64" => "ARM64",
1177+
"arm64ec" => "AMD64", // Unsure
1178+
arch => {
1179+
warn!("unknown architecture {arch} in target {target:?}");
1180+
arch
1181+
}
1182+
};
1183+
}
1184+
1185+
// macOS/Apple: Same as the `-arch` value expected by the linker.
1186+
if target.contains("apple") {
1187+
return match full_arch {
1188+
// Renamed
1189+
"aarch64" => "arm64",
1190+
"i686" => "i386",
1191+
"powerpc" => "ppc",
1192+
"powerpc64" => "ppc64",
1193+
// Unchanged
1194+
"arm64_32" => "arm64_32",
1195+
"arm64e" => "arm64e",
1196+
"armv7" => "armv7",
1197+
"armv7k" => "armv7k",
1198+
"armv7s" => "armv7s",
1199+
"i386" => "i386",
1200+
"x86_64" => "x86_64",
1201+
"x86_64h" => "x86_64h",
1202+
arch => {
1203+
warn!("unknown architecture {arch} in target {target:?}");
1204+
arch
1205+
}
1206+
};
1207+
}
1208+
1209+
// Unix, `uname -m` on most platforms by default.
1210+
match full_arch {
1211+
"arm" if target.contains("android") => "armv6-a",
1212+
"armv7" if target.contains("android") => "armv7-a",
1213+
"i686" if target.contains("android") => "i686",
1214+
"i386" | "i486" | "i586" | "i686" | "i786" => "x86",
1215+
"powerpc" => "ppc",
1216+
"powerpc64" => "ppc64",
1217+
"powerpc64le" => "ppc64le",
1218+
"x86_64" if target.contains("openbsd") || target.contains("freebsd") => "amd64",
1219+
"x86_64" => "x86_64",
1220+
arch if arch.starts_with("arm") => "arm",
1221+
arch if arch.starts_with("thumb") => "thumb",
1222+
// TODO: Do we need to handle more here?
1223+
arch => arch,
1224+
}
1225+
}
1226+
11451227
#[cfg(test)]
11461228
mod tests {
11471229
use super::uses_named_pipe_jobserver;

0 commit comments

Comments
 (0)