From b4ebed84a2540bb2fa29f22be3765d23423b8b04 Mon Sep 17 00:00:00 2001 From: chrysn Date: Thu, 17 Oct 2024 10:33:31 +0200 Subject: [PATCH] gcoap: adapt to API change in [PR20900] While [PR20900] provides a compatibility .hdr accessor through a union, that trick is not available through bindgen or c2rust, which all introduce a dummy-named field for the anonymous union. Instead, we follow the path set out by [PR79] and introspect the source file. [PR20900]: https://github.com/RIOT-OS/RIOT/pull/20900 [PR79]: https://github.com/RIOT-OS/rust-riot-wrappers/pull/79 Co-Authored-By: Marian Buschsieweke --- build.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gcoap.rs | 11 ++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 52b4fde..ac5ffc3 100644 --- a/build.rs +++ b/build.rs @@ -117,4 +117,53 @@ fn main() { for module in known_modules { println!("cargo::rustc-check-cfg=cfg(riot_module_{})", module); } + + // As a means of last resort, we emulate cfg(accessible(::path::to::thing)), as a + // workaround for https://github.com/rust-lang/rust/issues/64797 + // + // This is sometimes necessary when some C API compatible change (eg. renaming a field with a + // deprecated union while introducing a proper accessor, as done in + // https://github.com/RIOT-OS/RIOT/pull/20900) leads to changes in bindgen and c2rust outputs. + // + // This is similar to the markers that were previously used in riot-sys. We access files + // directly to avoid going through `links=` (see also + // ). This + // + // * limits the impact of source changes (this way, only changs to relevant headerst trigger + // a rebuild of riot-wrappers), and + // * removes the need for lock-stepping riot-sys and riot-wrappers. + // + // The downside of the tighter coupling with the paths in RIOT is reduced by keeping things + // local and the stabiity structure: All these access checks can be removed once riot-wrappers + // stops supporting a RIOT version that has the symbol unconditionally, without any concern for + // compatibility between crates (as the cfgs are just internal). + + let riotbase: std::path::PathBuf = env::var("RIOTBASE") + .expect("No RIOTBASE set, can not inspect source files for symbol presence.") + .into(); + println!("cargo:rerun-if-env-changed=RIOTBASE"); + + let emulate_accessible = [ + // It's a static inline function and riot-sys currently only gives the file for the bindgen + // output, not the c2rust output. Using coap_build_udp_hdr presence as a stand-in. + // + // Remove this after a release including coap_pkt_set_code + // has been published. + ( + &"inline_coap_pkt_set_code", + &"sys/include/net/nanocoap.h", + &"coap_pkt_set_code", + ), + ]; + + for (rust_name, header_file, header_search_string) in emulate_accessible { + let header_file = riotbase.join(header_file); + println!("cargo:rerun-if-changed={}", header_file.display()); + let header_code = + std::fs::read_to_string(&header_file).expect("Failed to read header file"); + println!("cargo:rustc-check-cfg=cfg(accessible_riot_sys_{rust_name})"); + if header_code.contains(header_search_string) { + println!("cargo:rustc-cfg=accessible_riot_sys_{rust_name}"); + } + } } diff --git a/src/gcoap.rs b/src/gcoap.rs index d7dddf5..fc1267e 100644 --- a/src/gcoap.rs +++ b/src/gcoap.rs @@ -380,7 +380,16 @@ impl<'b> PacketBuffer<'b> { } pub fn set_code_raw(&mut self, code: u8) { - unsafe { (*(*self.pkt).hdr).code = code }; + #[cfg(accessible_riot_sys_inline_coap_pkt_set_code)] + { + unsafe { + riot_sys::inline::coap_pkt_set_code(crate::inline_cast_ref_mut(self.pkt), code) + }; + } + #[cfg(not(accessible_riot_sys_inline_coap_pkt_set_code))] + { + unsafe { (*(*self.pkt).hdr).code = code }; + } } /// Return the total number of bytes in the message, given that `payload_used` bytes were