fel4_config/
cmake_integration.rs

1use cmake::Config as CmakeConfig;
2use std::collections::HashMap;
3/// Utilities for configuring the sel4_kernel CMake build based
4/// on fel4 configuration data
5///
6use std::env;
7use std::path::Path;
8use types::*;
9#[derive(Clone, Debug, Fail, PartialEq)]
10pub enum CmakeConfigurationError {
11    #[fail(display = "Missing the required {} environment variable", _0)]
12    MissingRequiredEnvVar(String),
13    #[fail(
14        display = "Cargo is attempting to build for the {} target, however fel4.toml has declared the target to be {}",
15        _0,
16        _1
17    )]
18    CargoTargetToFel4TargetMismatch(String, String),
19}
20/// Configure a seL4_kernel CMake build configuration with data derived from
21/// the fel4.toml manifest
22///
23/// Assumes `cargo_target` is a rust build target option
24/// Assumes the seL4_kernel is at `${cargo_manifest_dir}/deps/seL4_kernel`
25pub fn configure_cmake_build<P: AsRef<Path>>(
26    cmake_config: &mut CmakeConfig,
27    fel4_config: &Fel4Config,
28    cargo_manifest_dir: P,
29    cargo_target: &str,
30) -> Result<(), CmakeConfigurationError> {
31    let kernel_path = cargo_manifest_dir.as_ref().join("deps").join("seL4_kernel");
32
33    if cargo_target != fel4_config.target.full_name() {
34        return Err(CmakeConfigurationError::CargoTargetToFel4TargetMismatch(
35            cargo_target.to_string(),
36            fel4_config.target.full_name().to_string(),
37        ));
38    }
39
40    // CMAKE_TOOLCHAIN_FILE is resolved immediately by CMake
41    cmake_config.define("CMAKE_TOOLCHAIN_FILE", kernel_path.join("gcc.cmake"));
42    cmake_config.define("KERNEL_PATH", kernel_path);
43
44    add_cmake_definitions(cmake_config, &fel4_config.properties);
45
46    // Supply additional cross compilation toolchain guidance for arm,
47    // since the seL4-CMake inferred option doesn't support hardware floating point
48    if fel4_config.target == SupportedTarget::Armv7Sel4Fel4 {
49        cmake_config.define("CROSS_COMPILER_PREFIX", "arm-linux-gnueabihf-");
50    } else if fel4_config.target == SupportedTarget::Aarch64Sel4Fel4 {
51        cmake_config.define("CROSS_COMPILER_PREFIX", "aarch64-linux-gnu-");
52    }
53
54    // seL4 handles these so we clear them to prevent cmake-rs from
55    // auto-populating
56    cmake_config.define("CMAKE_C_FLAGS", "");
57    cmake_config.define("CMAKE_CXX_FLAGS", "");
58
59    // Ninja generator
60    cmake_config.generator("Ninja");
61    Ok(())
62}
63
64/// Configure a seL4_kernel CMake build configuration with data derived from
65/// the fel4.toml manifest and choice environment variables.
66///
67/// Assumes the presence of the CARGO_MANIFEST_DIR and TARGET environment
68/// variables from cargo Assumes the seL4_kernel is at
69/// `${CARGO_MANIFEST_DIR}/deps/seL4_kernel`
70pub fn configure_cmake_build_from_env(
71    cmake_config: &mut CmakeConfig,
72    fel4_config: &Fel4Config,
73) -> Result<(), CmakeConfigurationError> {
74    let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR").map_err(|_| {
75        CmakeConfigurationError::MissingRequiredEnvVar("CARGO_MANIFEST_DIR".to_string())
76    })?;
77    let cargo_target = env::var("TARGET")
78        .map_err(|_| CmakeConfigurationError::MissingRequiredEnvVar("TARGET".to_string()))?;
79    configure_cmake_build(cmake_config, fel4_config, cargo_manifest_dir, &cargo_target)
80}
81
82fn add_cmake_definitions(
83    cmake_config: &mut CmakeConfig,
84    properties: &HashMap<String, FlatTomlValue>,
85) {
86    for (name, value) in properties {
87        add_cmake_definition(cmake_config, name, value);
88    }
89}
90
91fn add_cmake_definition(config: &mut CmakeConfig, name: &str, value: &FlatTomlValue) {
92    match *value {
93        FlatTomlValue::Boolean(b) => {
94            config.define(format!("{}:BOOL", name), if b { "ON" } else { "OFF" })
95        }
96        FlatTomlValue::Integer(i) => config.define(name, i.to_string()),
97        FlatTomlValue::String(ref s) => config.define(name, s),
98        FlatTomlValue::Float(f) => config.define(name, f.to_string()),
99        FlatTomlValue::Datetime(ref d) => config.define(name, format!("{}", d)),
100    };
101}
102#[cfg(test)]
103mod tests {
104    use super::super::*;
105    use super::*;
106    use std::path::PathBuf;
107
108    #[test]
109    fn sanity_check_exemplar_cmake_configuration() {
110        let mut c = CmakeConfig::new(PathBuf::from("./somewhere/bogus"));
111        let full = parse_full_manifest(get_exemplar_default_toml())
112            .expect("Should be able to get the default fel4.toml");
113        let fel4_config =
114            resolve_fel4_config(full, &BuildProfile::Debug).expect("Trouble in config resolution");
115        let r = configure_cmake_build(
116            &mut c,
117            &fel4_config,
118            Path::new("./some/repo"),
119            "x86_64-sel4-fel4",
120        );
121        assert_eq!(Ok(()), r);
122    }
123
124    #[test]
125    fn sanity_check_exemplar_cmake_configuration_target_mismatch() {
126        let mut c = CmakeConfig::new(PathBuf::from("./somewhere/bogus"));
127        let full = parse_full_manifest(get_exemplar_default_toml())
128            .expect("Should be able to get the default fel4.toml");
129        let fel4_config =
130            resolve_fel4_config(full, &BuildProfile::Debug).expect("Trouble in config resolution");
131        let r = configure_cmake_build(
132            &mut c,
133            &fel4_config,
134            Path::new("./some/repo"),
135            "armv7-sel4-fel4",
136        );
137        assert_eq!(
138            Err(CmakeConfigurationError::CargoTargetToFel4TargetMismatch(
139                "armv7-sel4-fel4".to_string(),
140                "x86_64-sel4-fel4".to_string()
141            )),
142            r
143        );
144    }
145
146    // TODO - better testing after environment variable usage is factored out of
147    // configure_cmake_build
148}