From 295a61ddfd1818f3102122ca7ba3f295584ab7fc Mon Sep 17 00:00:00 2001 From: Sebastian Goll <1277035+sgoll@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:38:48 +0100 Subject: [PATCH] Add unsafe to extern blocks for Rust 2024 (#36) ## Description This replaces the declaration of `extern "C"` blocks with `unsafe extern "C"` as will be required by Rust 2024. Remove this when https://github.com/rust-lang/rust-bindgen/issues/2901 is merged and [bindgen](https://crates.io/crates/bindgen) can generate these blocks automatically as required. --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + build.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 246cfab..6a50e5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -210,6 +210,7 @@ dependencies = [ "bindgen", "cc", "cmake", + "version_check", ] [[package]] @@ -317,6 +318,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "which" version = "4.4.2" diff --git a/Cargo.toml b/Cargo.toml index c0405a6..520b2f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 } diff --git a/build.rs b/build.rs index 89a12b4..1721a37 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,7 @@ use std::{ env, + fs::File, + io::{self, Write as _}, path::{Path, PathBuf}, }; @@ -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"); @@ -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 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 + // . + 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() @@ -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(()) +}