Skip to content

Commit

Permalink
Set +whole-archive on C/C++ libraries
Browse files Browse the repository at this point in the history
This fixes the build for Rust 1.61+ on some machines. I can reliably
reproduce this locally, but CI does not exhibit this issue (I'm not
sure why).

The Rust compatibility notes document this change:
https://github.com/rust-lang/rust/blob/1.61.0/RELEASES.md#compatibility-notes

and eventually this will be supported by cc:
rust-lang/cc-rs#671

Fixes #339
  • Loading branch information
Wilfred committed Aug 28, 2022
1 parent d3963ca commit a247218
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,9 @@
## 0.34 (unreleased)

### Build

Fixed build on Rust 1.61+.

### Display

Fixed an issue where side-by-side display would sometimes print the
Expand Down
51 changes: 51 additions & 0 deletions build.rs
Expand Up @@ -7,6 +7,49 @@ struct TreeSitterParser {
extra_files: Vec<&'static str>,
}

/// Emit linking flags for this library, but specifcy `+whole-archive`.
///
/// This should be possible in the cc crate directly after
/// https://github.com/rust-lang/cc-rs/pull/671
fn emit_whole_archive_link_flags(lib_name: &str, is_cpp: bool) {
println!("cargo:rustc-link-lib=static:+whole-archive={}", lib_name);
println!(
"cargo:rustc-link-search=native={}",
std::env::var("OUT_DIR").expect("did not set OUT_DIR")
);

if is_cpp {
let cpp_stdlib = if let Ok(stdlib) = std::env::var("CXXSTDLIB") {
if stdlib.is_empty() {
None
} else {
Some(stdlib)
}
} else {
let target = std::env::var("TARGET").expect("TARGET environment should be set");

// Equivalent to https://github.com/rust-lang/cc-rs/blob/53fb72c87e5769a299f1886ead831901b9c775d6/src/lib.rs#L2528
if target.contains("msvc") {
None
} else if target.contains("apple") {
Some("c++".to_string())
} else if target.contains("freebsd") {
Some("c++".to_string())
} else if target.contains("openbsd") {
Some("c++".to_string())
} else if target.contains("android") {
Some("c++_shared".to_string())
} else {
Some("stdc++".to_string())
}
};

if let Some(cpp_stdlib) = cpp_stdlib {
println!("cargo:rustc-link-lib={}", cpp_stdlib);
}
}
}

impl TreeSitterParser {
fn build(&self) {
let dir = PathBuf::from(&self.src_dir);
Expand Down Expand Up @@ -49,6 +92,10 @@ impl TreeSitterParser {
for file in cpp_files {
cpp_build.file(dir.join(file));
}

cpp_build.cargo_metadata(false);
emit_whole_archive_link_flags(&format!("{}-cpp", self.name), true);

cpp_build.compile(&format!("{}-cpp", self.name));
}

Expand All @@ -60,6 +107,10 @@ impl TreeSitterParser {
for file in c_files {
build.file(dir.join(file));
}

build.cargo_metadata(false);
emit_whole_archive_link_flags(self.name, false);

build.compile(self.name);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/main.rs
Expand Up @@ -12,6 +12,9 @@
// It's common to have pairs foo_lhs and foo_rhs, leading to double
// the number of arguments and triggering this lint.
#![allow(clippy::too_many_arguments)]
// Has false positives on else if chains that sometimes have the same
// body for readability.
#![allow(clippy::clippy::if_same_then_else)]

mod constants;
mod diff;
Expand Down

0 comments on commit a247218

Please sign in to comment.