diff --git a/crates/bhyve-api/header-check/build.rs b/crates/bhyve-api/header-check/build.rs index 5601b80a7..0625bb04c 100644 --- a/crates/bhyve-api/header-check/build.rs +++ b/crates/bhyve-api/header-check/build.rs @@ -24,6 +24,7 @@ fn ver_lt(ver: u32) -> bool { CHECK_VERSION.load(Ordering::Relaxed) < ver } /// Source checked against has API version equal to `ver` argument +#[allow(dead_code)] fn ver_eq(ver: u32) -> bool { CHECK_VERSION.load(Ordering::Relaxed) == ver } @@ -91,13 +92,15 @@ fn main() { // We expose our own copy for now for us as a constraint. "VM_MAXCPU" => true, - // Do not bother checking the version definition define if we are - // assuming the source is from a different version. - "VMM_CURRENT_INTERFACE_VERSION" - if !ver_eq(VMM_CURRENT_INTERFACE_VERSION) => - { - true - } + // The bhyve interface is generally backwards-compatible; headers may be newer + // than Propolis knows about. In service of additive changes, ignore the + // interface version from headers. + // + // If items (structs, ioctl numbers) we know about changed, header-check + // will find and report those specifically. If items were removed, we + // may need to conditionally `skip_const` or `skip_field` based on the + // version Propolis knows about. + "VMM_CURRENT_INTERFACE_VERSION" => true, // API V11 saw the removal of several time-realted VMM_ARCH defines "VAI_TSC_BOOT_OFFSET" | "VAI_BOOT_HRTIME" | "VAI_TSC_FREQ" diff --git a/crates/viona-api/header-check/Cargo.toml b/crates/viona-api/header-check/Cargo.toml index f26d8d8b8..1b5057ccc 100644 --- a/crates/viona-api/header-check/Cargo.toml +++ b/crates/viona-api/header-check/Cargo.toml @@ -13,6 +13,8 @@ libc = "0.2" [build-dependencies] cc = "1" ctest2 = "0.4.7" +# Build-time conditions depend on the max API version defined in the crate +viona_api = { path = ".." } [[test]] name = "main" diff --git a/crates/viona-api/header-check/build.rs b/crates/viona-api/header-check/build.rs index b2a7b374c..c8c0bab5c 100644 --- a/crates/viona-api/header-check/build.rs +++ b/crates/viona-api/header-check/build.rs @@ -7,6 +7,34 @@ use std::convert::TryFrom; use std::env; use std::path::PathBuf; +use std::str::FromStr; +use std::sync::atomic::{AtomicU32, Ordering}; + +use viona_api::VIONA_CURRENT_INTERFACE_VERSION; + +static CHECK_VERSION: AtomicU32 = + AtomicU32::new(VIONA_CURRENT_INTERFACE_VERSION); + +// A selection of helpers to concisely manage header-check rules, below. +// +// These are added in expectation of future use, hence `allow(dead_code)`. +// Remove the attributes as they become used, please. + +/// Source checked against has API version greater than `ver` argument +#[allow(dead_code)] +fn ver_gt(ver: u32) -> bool { + CHECK_VERSION.load(Ordering::Relaxed) > ver +} +/// Source checked against has API version less than `ver` argument +#[allow(dead_code)] +fn ver_lt(ver: u32) -> bool { + CHECK_VERSION.load(Ordering::Relaxed) < ver +} +/// Source checked against has API version equal to `ver` argument +#[allow(dead_code)] +fn ver_eq(ver: u32) -> bool { + CHECK_VERSION.load(Ordering::Relaxed) == ver +} fn main() { let mut cfg = ctest2::TestGenerator::new(); @@ -19,6 +47,27 @@ fn main() { } }; + // Like with byhve: allow the user to specify a target interface version to + // check against. + match env::var("API_VERSION").ok().map(|v| u32::from_str(&v)) { + Some(Ok(ver)) => { + if ver > VIONA_CURRENT_INTERFACE_VERSION { + eprintln!( + "API_VERSION {} cannot be > \ + VIONA_CURRENT_INTERFACE_VERSION ({})", + ver, VIONA_CURRENT_INTERFACE_VERSION + ); + std::process::exit(1); + } + CHECK_VERSION.store(ver, Ordering::Relaxed); + } + Some(Err(e)) => { + eprintln!("Invalid API_VERSION {:?}", e); + std::process::exit(1); + } + _ => {} + } + let include_paths = ["usr/src/uts/intel", "usr/src/uts/common"]; cfg.include("/usr/include"); for p in include_paths { @@ -31,6 +80,16 @@ fn main() { cfg.skip_const(move |name| match name { "VIONA_DEV_PATH" => true, + // Like bhyve, the viona interface is generally backwards-compatible. + // Headers may be newer than Propolis knows about. In service of + // additive changes, ignore the interface version from headers. + // + // If items (structs, ioctl numbers) we know about changed, header-check + // will find and report those specifically. If items were removed, we + // may need to conditionally `skip_const` or `skip_field` based on the + // version Propolis knows about. + "VIONA_CURRENT_INTERFACE_VERSION" => true, + _ => false, });