Skip to content

Commit

Permalink
Allowing '--extern' usage in build scripts and in config files
Browse files Browse the repository at this point in the history
  • Loading branch information
notdanilo committed Jun 18, 2024
1 parent 05e61b2 commit f0d365e
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 11 deletions.
23 changes: 16 additions & 7 deletions src/cargo/core/compiler/custom_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ pub struct BuildOutput {
pub library_paths: Vec<PathBuf>,
/// Names and link kinds of libraries, suitable for the `-l` flag.
pub library_links: Vec<String>,
/// External direct library dependencies passed to rustc with the `--extern` flag.
pub library_externs: Vec<String>,
/// Linker arguments suitable to be passed to `-C link-arg=<args>`
pub linker_args: Vec<(LinkArgTarget, String)>,
/// Various `--cfg` flags to pass to the compiler.
Expand Down Expand Up @@ -684,6 +686,7 @@ impl BuildOutput {
) -> CargoResult<BuildOutput> {
let mut library_paths = Vec::new();
let mut library_links = Vec::new();
let mut library_externs = Vec::new();
let mut linker_args = Vec::new();
let mut cfgs = Vec::new();
let mut check_cfgs = Vec::new();
Expand Down Expand Up @@ -855,9 +858,10 @@ impl BuildOutput {
// Keep in sync with TargetConfig::parse_links_overrides.
match key {
"rustc-flags" => {
let (paths, links) = BuildOutput::parse_rustc_flags(&value, &whence)?;
let (paths, links, externs) = BuildOutput::parse_rustc_flags(&value, &whence)?;
library_links.extend(links.into_iter());
library_paths.extend(paths.into_iter());
library_externs.extend(externs.into_iter());
}
"rustc-link-lib" => library_links.push(value.to_string()),
"rustc-link-search" => library_paths.push(PathBuf::from(value)),
Expand Down Expand Up @@ -1001,6 +1005,7 @@ impl BuildOutput {
Ok(BuildOutput {
library_paths,
library_links,
library_externs,
linker_args,
cfgs,
check_cfgs,
Expand All @@ -1018,19 +1023,22 @@ impl BuildOutput {
pub fn parse_rustc_flags(
value: &str,
whence: &str,
) -> CargoResult<(Vec<PathBuf>, Vec<String>)> {
) -> CargoResult<(Vec<PathBuf>, Vec<String>, Vec<String>)> {
let value = value.trim();
let mut flags_iter = value
.split(|c: char| c.is_whitespace())
.filter(|w| w.chars().any(|c| !c.is_whitespace()));
let (mut library_paths, mut library_links) = (Vec::new(), Vec::new());
let (mut library_paths, mut library_links, mut externs) =
(Vec::new(), Vec::new(), Vec::new());

while let Some(flag) = flags_iter.next() {
if flag.starts_with("-l") || flag.starts_with("-L") {
let is_extern = flag.starts_with("--extern");
if flag.starts_with("-l") || flag.starts_with("-L") || is_extern {
// Check if this flag has no space before the value as is
// common with tools like pkg-config
// e.g. -L/some/dir/local/lib or -licui18n
let (flag, mut value) = flag.split_at(2);
let split_location = if is_extern { 8 } else { 2 };
let (flag, mut value) = flag.split_at(split_location);
if value.is_empty() {
value = match flags_iter.next() {
Some(v) => v,
Expand All @@ -1045,19 +1053,20 @@ impl BuildOutput {
match flag {
"-l" => library_links.push(value.to_string()),
"-L" => library_paths.push(PathBuf::from(value)),
"--extern" => externs.push(value.to_string()),

// This was already checked above
_ => unreachable!(),
};
} else {
bail!(
"Only `-l` and `-L` flags are allowed in {}: `{}`",
"Only `-l`, `-L` and `--extern` flags are allowed in {}: `{}`",
whence,
value
)
}
}
Ok((library_paths, library_links))
Ok((library_paths, library_links, externs))
}

/// Parses [`cargo::rustc-env`] instruction.
Expand Down
7 changes: 6 additions & 1 deletion src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ fn rustc(
Ok(())
}));

// Add all relevant `-L` and `-l` flags from dependencies (now calculated and
// Add all relevant `-L`, `-l` and `--extern` flags from dependencies (now calculated and
// present in `state`) to the command provided.
fn add_native_deps(
rustc: &mut ProcessBuilder,
Expand All @@ -484,6 +484,11 @@ fn rustc(
}

if key.0 == current_id {
for extern_ in output.library_externs.iter() {
println!("Adding extern {}", extern_);
rustc.arg("--extern").arg(extern_);
}

if pass_l_flag {
for name in output.library_links.iter() {
rustc.arg("-l").arg(name);
Expand Down
3 changes: 2 additions & 1 deletion src/cargo/util/context/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,10 @@ fn parse_links_overrides(
"rustc-flags" => {
let flags = value.string(key)?;
let whence = format!("target config `{}.{}` (in {})", target_key, key, flags.1);
let (paths, links) = BuildOutput::parse_rustc_flags(flags.0, &whence)?;
let (paths, links, externs) = BuildOutput::parse_rustc_flags(flags.0, &whence)?;
output.library_paths.extend(paths);
output.library_links.extend(links);
output.library_externs.extend(externs);
}
"rustc-link-lib" => {
let list = value.list(key)?;
Expand Down
2 changes: 1 addition & 1 deletion tests/testsuite/bad_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2960,7 +2960,7 @@ fn bad_target_links_overrides() {
p.cargo("check")
.with_status(101)
.with_stderr_data(str![[r"
[ERROR] Only `-l` and `-L` flags are allowed in target config `target.[..].rustc-flags` (in [..]foo/.cargo/config.toml): `foo`
[ERROR] Only `-l`, `-L` and `--extern` flags are allowed in target config `target.[..].rustc-flags` (in [..]foo/.cargo/config.toml): `foo`
"]])
.run();
Expand Down
2 changes: 1 addition & 1 deletion tests/testsuite/build_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ fn custom_build_script_wrong_rustc_flags() {
p.cargo("build")
.with_status(101)
.with_stderr_contains(
"[ERROR] Only `-l` and `-L` flags are allowed in build script of `foo v0.5.0 ([CWD])`: \
"[ERROR] Only `-l`, `-L` and `--extern` flags are allowed in build script of `foo v0.5.0 ([CWD])`: \
`-aaa -bbb`",
)
.run();
Expand Down

0 comments on commit f0d365e

Please sign in to comment.