1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
//! Codemodel cmake file API object.
//!
//! The codemodel object kind describes the build system structure as modeled by CMake.
use std::convert::TryFrom;
use std::fs;
use std::path::PathBuf;
use std::sync::Arc;
use anyhow::{anyhow, Context, Error, Result};
use serde::Deserialize;
use super::index::{self, ObjKind};
use super::Version;
/// The description of the build system structure as modeled by CMake.
#[derive(Debug, Deserialize, Clone)]
pub struct Codemodel {
#[serde(skip)]
codemodel_dir: Arc<PathBuf>,
/// The version of this object kind.
pub version: Version,
/// Some paths used by cmake.
pub paths: Paths,
/// All available build configurations.
///
/// On single-configuration generators there is one entry for the value of the
/// `CMAKE_BUILD_TYPE` variable. For multi-configuration generators there is an entry for
/// each configuration listed in the `CMAKE_CONFIGURATION_TYPES` variable.
pub configurations: Vec<Configuration>,
}
impl TryFrom<&index::Reply> for Codemodel {
type Error = Error;
fn try_from(value: &index::Reply) -> Result<Self, Self::Error> {
assert!(value.kind == ObjKind::Codemodel);
ObjKind::Codemodel
.check_version_supported(value.version.major)
.unwrap();
let mut codemodel: Codemodel = serde_json::from_reader(&fs::File::open(&value.json_file)?)
.with_context(|| {
anyhow!(
"Parsing cmake-file-api codemodel object file '{}' failed",
value.json_file.display()
)
})?;
codemodel.codemodel_dir = Arc::new(value.json_file.parent().unwrap().to_owned());
for conf in codemodel.configurations.iter_mut() {
conf.codemodel_dir = codemodel.codemodel_dir.clone();
}
Ok(codemodel)
}
}
impl Codemodel {
/// Turn this into [`configurations`](Self::configurations).
pub fn into_conf(self) -> Vec<Configuration> {
self.configurations
}
/// Turn this into [`configurations[0]`](Self::configurations).
///
/// This functions panics if there are no configurations.
pub fn into_first_conf(self) -> Configuration {
self.configurations
.into_iter()
.next()
.expect("no configurations")
}
/// The path to the directory containing the file represented by this
/// [`Codemodel`] instance.
pub fn dir_path(&self) -> &PathBuf {
&self.codemodel_dir
}
}
/// Paths used by cmake.
#[derive(Debug, Deserialize, Clone)]
pub struct Paths {
/// The absolute path to the top-level source directory.
pub source: PathBuf,
/// The absolute path to the top-level build directory.
pub build: PathBuf,
}
/// A build configuration.
#[derive(Debug, Deserialize, Clone)]
pub struct Configuration {
#[serde(skip)]
codemodel_dir: Arc<PathBuf>,
/// The name of the configuration (e.g. `Debug`)
pub name: String,
/// A build system target.
///
/// Such targets are created by calls to `add_executable()`, `add_library()`, and
/// `add_custom_target()`, excluding imported targets and interface libraries (which do
/// not generate any build rules).
#[serde(rename = "targets")]
pub target_refs: Vec<TargetRef>,
}
impl Configuration {
/// Load a codemodel target object by name.
pub fn get_target(&self, name: impl AsRef<str>) -> Option<Result<target::Target>> {
self.target_refs
.iter()
.find(|t| t.name == name.as_ref())
.map(|t| t.load(self))
}
/// Load all codemodel target objects.
pub fn targets(&self) -> impl Iterator<Item = Result<target::Target>> + '_ {
self.target_refs.iter().map(move |t| t.load(self))
}
}
/// A reference to a codemodel target object JSON file.
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct TargetRef {
/// The target name.
pub name: String,
/// An unsigned integer 0-based index into the main directories array indicating the
/// build system directory in which the target is defined.
pub directory_index: usize,
/// An unsigned integer 0-based index into the main projects array indicating the
/// build system project in which the target is defined.
pub project_index: usize,
/// A path relative to the codemodel file to another JSON file containing a
/// codemodel `target` object.
pub json_file: String,
}
impl TargetRef {
/// Load the target object from the [`json_file`](Self::json_file).
pub fn load(&self, cfg: &Configuration) -> Result<target::Target> {
target::Target::from_file(cfg.codemodel_dir.join(&self.json_file))
}
}
/// A cmake supported programming language
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
pub enum Language {
C,
#[serde(rename = "CXX")]
Cpp,
#[serde(rename = "CUDA")]
Cuda,
#[serde(rename = "OBJCXX")]
ObjectiveCpp,
#[serde(rename = "HIP")]
Hip,
#[serde(rename = "ISPC")]
Ispc,
#[serde(rename = "ASM")]
Assembly,
}
pub use target::Target;
/// Codemodel target cmake file API object.
pub mod target {
use std::path::{Path, PathBuf};
use anyhow::{anyhow, Context, Result};
use serde::Deserialize;
use super::Language;
/// A type of cmake target.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Hash)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum Type {
Executable,
StaticLibrary,
SharedLibrary,
ModuleLibrary,
ObjectLibrary,
InterfaceLibrary,
Utility,
}
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Target {
/// The logical name of the target.
pub name: String,
/// Link info of target.
pub link: Option<Link>,
/// Compile settings for source files.
#[serde(default)]
pub compile_groups: Vec<CompileGroup>,
/// The type of the target.
#[serde(rename = "type")]
pub target_type: Type,
}
impl Target {
/// Deserialize the codemodel target object JSON file from `file_path`.
pub fn from_file(file_path: impl AsRef<Path>) -> Result<Target> {
let file = std::fs::File::open(&file_path)?;
let value: Target = serde_json::from_reader(file).with_context(|| {
anyhow!(
"Failed to parse the cmake-file-api target file '{}'",
file_path.as_ref().display()
)
})?;
Ok(value)
}
}
/// Compile settings for groups of sources using the same settings.
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct CompileGroup {
/// Language of the toolchain in use to compile the source file.
pub language: Language,
/// Fragments of the compiler command line invocation if available.
#[serde(default)]
pub compile_command_fragments: Vec<Fragment>,
/// Include directories.
#[serde(default)]
pub includes: Vec<Include>,
/// Prerocessor definitions.
#[serde(default)]
pub defines: Vec<Define>,
/// Path to the sysroot.
///
/// Present when the `CMAKE_SYSROOT_COMPILE` or `CMAKE_SYSROOT` variable is defined.
pub sysroot: Option<Sysroot>,
}
/// A fragment of a compile command invocation.
#[derive(Debug, Deserialize, Clone)]
pub struct Fragment {
/// A fragment of the compile command line invocation.
///
/// The value is encoded in the build system's native shell format.
pub fragment: String,
}
/// A preprocessor definition.
#[derive(Debug, Deserialize, Clone)]
pub struct Define {
/// The preprocessor definition in the format `<name>[=<value>]`, e.g. `DEF` or `DEF=1`.
pub define: String,
}
/// A include directory.
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Include {
/// The path to the include directory, represented with forward slashes.
pub path: String,
/// Whether the include directory is marked as a system include directory.
#[serde(default)]
pub is_system: bool,
}
/// Executable or shared library link information.
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Link {
/// The language of the toolchain that is used to invoke the linker.
pub language: Language,
/// Fragments of the link command line invocation.
pub command_fragments: Vec<CommandFragment>,
/// Whether link-time optimization is enabled.
#[serde(default)]
pub lto: bool,
/// Path to the sysroot.
///
/// Present when the `CMAKE_SYSROOT_LINK` or `CMAKE_SYSROOT` variable is defined.
pub sysroot: Option<Sysroot>,
}
/// A link command linke fragment.
#[derive(Debug, Deserialize, Clone)]
pub struct CommandFragment {
/// A fragment of the link command line invocation.
///
/// The value is encoded in the build system's native shell format.
pub fragment: String,
/// The role of the fragments content.
pub role: Role,
}
#[derive(Debug, PartialEq, Eq, Deserialize, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub enum Role {
/// Link flags
Flags,
/// Link library file paths or flags
Libraries,
/// Library search path flags
LibraryPath,
/// MacOS framework search path flags
FrameworkPath,
}
/// Path to the sysroot.
#[derive(Debug, Deserialize, Clone)]
pub struct Sysroot {
/// The absolute path to the sysroot, represented with forward slashes.
pub path: PathBuf,
}
}