Skip to content

Add unsafe to extern blocks for Rust 2024 #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 15, 2024
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ include = [
bindgen = { version = "0.69.4", features = ["experimental"] }
cc = "1.0.83"
cmake = "0.1.50"
version_check = "0.9.5"

[lints.rust]
future_incompatible = { level = "warn", priority = -1 }
Expand Down
41 changes: 40 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::{
env,
fs::File,
io::{self, Write as _},
path::{Path, PathBuf},
};

Expand All @@ -16,6 +18,16 @@ const LIB_BASE: &str = "open62541";
/// the `cc` build adds it as `rustc-link-lib` automatically.
const LIB_EXT: &str = "open62541-ext";

/// Pattern to search for compatibility with Edition 2024.
///
/// See also [`LEGACY_EXTERN_REPLACEMENT`].
const LEGACY_EXTERN_PATTERN: &str = r#"extern "C" {"#;

/// Replacement to use for compatibility with Edition 2024.
///
/// See also [`LEGACY_EXTERN_PATTERN`].
const LEGACY_EXTERN_REPLACEMENT: &str = r#"unsafe extern "C" {"#;

fn main() {
let src = env::current_dir().expect("should get current directory");

Expand Down Expand Up @@ -122,9 +134,22 @@ fn main() {
.expect("should generate `Bindings` instance");

bindings
.write_to_file(out_bindings_rs)
.write_to_file(out_bindings_rs.clone())
.expect("should write `bindings.rs`");

// Until <https://github.com/rust-lang/rust-bindgen/issues/2901> is resolved, we replace `extern
// "C"` with `unsafe extern "C"` manually here. Remove this when `bindgen` is able to do it.
if version_check::is_min_version("1.82.0") == Some(true) {
// We can only use `unsafe extern` starting with Rust 1.82.0. See
// <https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html#safe-items-with-unsafe-extern>.
replace_in_file(
&out_bindings_rs,
LEGACY_EXTERN_PATTERN,
LEGACY_EXTERN_REPLACEMENT,
)
.expect("should add unsafe to extern statements");
}

// Build `extern.c` and our custom `wrapper.c` that both hold additional helpers that we want to
// link in addition to the base `open62541` library.
cc::Build::new()
Expand Down Expand Up @@ -184,3 +209,17 @@ impl bindgen::callbacks::ParseCallbacks for CustomCallbacks {
original_item_name.strip_prefix("RS_").map(str::to_owned)
}
}

/// Replaces all occurrences of pattern in file.
///
/// Note that this is not particularly efficient because it reads the entire file into memory before
/// writing it back. Care should be taken when operating on large files.
fn replace_in_file(path: &Path, pattern: &str, replacement: &str) -> io::Result<()> {
let buf = io::read_to_string(File::open(path)?)?;

let buf = buf.replace(pattern, replacement);

File::create(path)?.write_all(buf.as_bytes())?;

Ok(())
}