Skip to content
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
7 changes: 7 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4163,6 +4163,7 @@ version = "0.0.0"
dependencies = [
"cc",
"libc",
"shell-words",
]

[[package]]
Expand Down Expand Up @@ -5174,6 +5175,12 @@ dependencies = [
"lazy_static",
]

[[package]]
name = "shell-words"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77"

[[package]]
name = "shlex"
version = "1.3.0"
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_llvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ libc = "0.2.73"
# tidy-alphabetical-start
# `cc` updates often break things, so we pin it here.
cc = "=1.2.16"
shell-words = "1.1.1"
# tidy-alphabetical-end

[features]
Expand Down
90 changes: 76 additions & 14 deletions compiler/rustc_llvm/build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::borrow::Cow;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fmt::Display;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::process::{Command, Output, Stdio};
use std::str::SplitWhitespace;
use std::vec::IntoIter;

const OPTIONAL_COMPONENTS: &[&str] = &[
"x86",
Expand Down Expand Up @@ -86,8 +89,8 @@ fn rerun_if_changed_anything_in_dir(dir: &Path) {
}

#[track_caller]
fn output(cmd: &mut Command) -> String {
let output = match cmd.stderr(Stdio::inherit()).output() {
fn execute(cmd: &mut Command) -> Output {
let output = match cmd.output() {
Ok(status) => status,
Err(e) => {
println!("\n\nfailed to execute command: {cmd:?}\nerror: {e}\n\n");
Expand All @@ -101,7 +104,52 @@ fn output(cmd: &mut Command) -> String {
cmd, output.status
);
}
String::from_utf8(output.stdout).unwrap()
output
}

#[track_caller]
fn output(cmd: &mut Command) -> String {
String::from_utf8(execute(cmd.stderr(Stdio::inherit())).stdout).unwrap()
}
#[track_caller]
fn stderr(cmd: &mut Command) -> String {
String::from_utf8(execute(cmd).stderr).unwrap()
}

enum LlvmConfigOutput {
QuotedPaths(String),
UnquotedPaths(String),
}

#[derive(Clone)]
enum SplitLlvmConfigOutput<'a> {
QuotedPaths(IntoIter<String>),
UnquotedPaths(SplitWhitespace<'a>),
}

impl<'a> Iterator for SplitLlvmConfigOutput<'a> {
type Item = Cow<'a, str>;
fn next(&mut self) -> Option<Cow<'a, str>> {
match self {
Self::QuotedPaths(iter) => iter.next().map(Cow::Owned),
Self::UnquotedPaths(iter) => iter.next().map(Cow::Borrowed),
}
}
}

impl<'a> IntoIterator for &'a LlvmConfigOutput {
type Item = Cow<'a, str>;
type IntoIter = SplitLlvmConfigOutput<'a>;
fn into_iter(self) -> Self::IntoIter {
match self {
LlvmConfigOutput::QuotedPaths(output) => SplitLlvmConfigOutput::QuotedPaths(
shell_words::split(&output).expect("matched quotes").into_iter(),
),
LlvmConfigOutput::UnquotedPaths(output) => {
SplitLlvmConfigOutput::UnquotedPaths(output.split_whitespace())
}
}
}
}

fn main() {
Expand All @@ -125,6 +173,19 @@ fn main() {

println!("cargo:rerun-if-changed={}", llvm_config.display());

// FIXME: `--quote-paths` was added to llvm-config in LLVM 22, so this test (and all its ensuing
// fallback paths) can be removed once we bump the minimum llvm_version >= (22, 0, 0).
let llvm_config_supports_quote_paths =
stderr(Command::new(&llvm_config).arg("--help")).contains("quote-paths");
Comment thread
eggyal marked this conversation as resolved.

let quoted_split = |mut cmd: Command| {
if llvm_config_supports_quote_paths {
LlvmConfigOutput::QuotedPaths(output(cmd.arg("--quote-paths")))
} else {
LlvmConfigOutput::UnquotedPaths(output(&mut cmd))
}
};

// Test whether we're cross-compiling LLVM. This is a pretty rare case
// currently where we're producing an LLVM for a different platform than
// what this build script is currently running on.
Expand Down Expand Up @@ -167,7 +228,8 @@ fn main() {
// Link in our own LLVM shims, compiled with the same flags as LLVM
let mut cmd = Command::new(&llvm_config);
cmd.arg("--cxxflags");
let cxxflags = output(&mut cmd);
let cxxflags = quoted_split(cmd);
let mut cxxflags_iter = cxxflags.into_iter();
let mut cfg = cc::Build::new();
cfg.warnings(false);

Expand All @@ -180,7 +242,7 @@ fn main() {
if std::env::var_os("CI").is_some() && !target.contains("msvc") {
cfg.warnings_into_errors(true);
}
for flag in cxxflags.split_whitespace() {
for flag in cxxflags_iter.clone() {
// Ignore flags like `-m64` when we're doing a cross build
if is_crossed && flag.starts_with("-m") {
continue;
Expand All @@ -201,7 +263,7 @@ fn main() {
continue;
}

cfg.flag(flag);
cfg.flag(&*flag);
}

for component in &components {
Expand Down Expand Up @@ -289,13 +351,13 @@ fn main() {
}
cmd.args(&components);

for lib in output(&mut cmd).split_whitespace() {
for lib in &quoted_split(cmd) {
let mut is_static = false;
let name = if let Some(stripped) = lib.strip_prefix("-l") {
stripped
} else if let Some(stripped) = lib.strip_prefix('-') {
stripped
} else if Path::new(lib).exists() {
} else if Path::new(&*lib).exists() {
// On MSVC llvm-config will print the full name to libraries, but
// we're only interested in the name part
// On Unix when we get a static library llvm-config will print the
Expand All @@ -306,7 +368,7 @@ fn main() {
// and we transform the zstd part into
// cargo:rustc-link-search-native=/usr/local/lib
// cargo:rustc-link-lib=static=zstd
let path = Path::new(lib);
let path = Path::new(&*lib);
if lib.ends_with(".a") {
is_static = true;
println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
Expand Down Expand Up @@ -351,7 +413,7 @@ fn main() {
// that those -L directories are the same!
let mut cmd = Command::new(&llvm_config);
cmd.arg(llvm_link_arg).arg("--ldflags");
for lib in output(&mut cmd).split_whitespace() {
for lib in &quoted_split(cmd) {
if is_crossed {
if let Some(stripped) = lib.strip_prefix("-LIBPATH:") {
println!("cargo:rustc-link-search=native={}", stripped.replace(&host, &target));
Expand All @@ -373,7 +435,7 @@ fn main() {
// dependencies.
let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS");
if let Some(s) = llvm_linker_flags {
for lib in s.into_string().unwrap().split_whitespace() {
for lib in shell_words::split(&s.into_string().unwrap()).expect("matched quotes") {
if let Some(stripped) = lib.strip_prefix("-l") {
println!("cargo:rustc-link-lib={stripped}");
} else if let Some(stripped) = lib.strip_prefix("-L") {
Expand Down Expand Up @@ -414,15 +476,15 @@ fn main() {
// C++ runtime library
if !target.contains("msvc") {
if let Some(s) = llvm_static_stdcpp {
assert!(!cxxflags.contains("stdlib=libc++"));
assert!(cxxflags_iter.all(|flag| flag != "stdlib=libc++"));
let path = PathBuf::from(s);
println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
if target.contains("windows") {
println!("cargo:rustc-link-lib=static:-bundle={stdcppname}");
} else {
println!("cargo:rustc-link-lib=static={stdcppname}");
}
} else if cxxflags.contains("stdlib=libc++") {
} else if cxxflags_iter.any(|flag| flag == "stdlib=libc++") {
println!("cargo:rustc-link-lib=c++");
} else {
println!("cargo:rustc-link-lib={stdcppname}");
Expand Down
1 change: 1 addition & 0 deletions src/tools/tidy/src/deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"sha1",
"sha2",
"sharded-slab",
"shell-words",
"shlex",
"simd-adler32",
"smallvec",
Expand Down
Loading