@@ -17,7 +17,7 @@
use std::fmt::Write;
-use crate::spec::{BitmapDef, EnumDef, OutFileDef, StructDef, Typ};
+use crate::spec::{BitmapDef, EnumDef, IncludeDef, OutFileDef, StructDef, Typ};
use convert_case::{Case, Casing};
use log::{debug, error, trace};
@@ -109,6 +109,39 @@ fn comment(out: &mut String, comment: &str, ind: Indentation) {
}
}
+/// Adds specified `includes`. `arch` must be treated specially in order to
+/// demultiplex the target architecture.
+///
+/// The reason for the inclusion must be printed as a comment on top of the
+/// `include` itself.
+fn includegen(out: &mut String, def: &IncludeDef) {
+ if !def.imports.is_empty() {
+ comment(
+ out,
+ &format!("for {}", def.imports.join(",\n ")),
+ Indentation(0),
+ );
+ }
+
+ if def.from == "arch" {
+ writeln!(out, "#if defined(__i386__) || defined(__x86_64__)").unwrap();
+ writeln!(out, "#include \"arch_x86.h\"").unwrap();
+ writeln!(out, "#elif defined(__arm__) || defined(__aarch64__)").unwrap();
+ writeln!(out, "#include \"arch_arm.h\"").unwrap();
+ writeln!(out, "#elif defined(__powerpc64__)").unwrap();
+ writeln!(out, "#include \"arch_ppc.h\"").unwrap();
+ writeln!(out, "#elif defined(__riscv)").unwrap();
+ writeln!(out, "#include \"arch_riscv.h\"").unwrap();
+ writeln!(out, "#else").unwrap();
+ writeln!(out, "#error \"Unsupported architecture\"").unwrap();
+ writeln!(out, "#endif").unwrap();
+ } else {
+ writeln!(out, "#include \"{}.h\"", def.from).unwrap();
+ }
+
+ writeln!(out).unwrap();
+}
+
/// Write a C-compatible struct onto `out`
fn structgen(out: &mut String, filedef: &OutFileDef, def: &StructDef) {
debug!("struct {}", def.name);
@@ -212,6 +245,10 @@ pub fn parse(filedef: &OutFileDef) -> String {
writeln!(out, "#ifndef __XEN_AUTOGEN_{name}_H").unwrap();
writeln!(out, "#define __XEN_AUTOGEN_{name}_H\n").unwrap();
+ for def in &filedef.includes {
+ includegen(&mut out, def);
+ }
+
for def in &filedef.enums {
enumgen(&mut out, def);
}
@@ -134,9 +134,24 @@ pub struct VariantDef {
pub value: u64,
}
+/// Dependency links between files.
+///
+/// Used in specifications to state a number of types (described in `imports`)
+/// is needed from another generated file (the `from` field).
+#[derive(Debug, serde::Deserialize)]
+pub struct IncludeDef {
+ /// Name of the [`InFileDef`] that contains the imported tokens of
+ /// `imports`.
+ pub from: String,
+ /// List of tokens used in this spec file that exist in `from`.
+ pub imports: Vec<String>,
+}
+
/// A language-agnostic specification.
#[derive(Debug, serde::Deserialize)]
struct InFileDef {
+ /// List of types described in other [`InFileDef`] that are required here.
+ includes: Option<Vec<IncludeDef>>,
/// List of structs described in this input specification.
structs: Option<Vec<StructDef>>,
/// List of lang-agnostic enumerated descriptions.
@@ -152,7 +167,12 @@ struct InFileDef {
pub struct OutFileDef {
/// The name of the output file, without the final extension.
pub name: String,
+ /// Represents the dependencies between various [`OutFileDef`]. A language
+ /// backend is free to ignore these if they are not required.
+ pub includes: Vec<IncludeDef>,
/// List of structs described by all input spec files merged on this file.
+ ///
+ /// Implementation is lang-specific.
pub structs: Vec<StructDef>,
/// List of enumerated descriptions.
///
@@ -176,6 +196,7 @@ impl OutFileDef {
let mut ret = Self {
name,
+ includes: Vec::new(),
structs: Vec::new(),
enums: Vec::new(),
bitmaps: Vec::new(),
@@ -195,6 +216,9 @@ impl OutFileDef {
if let Some(bitmaps) = filedef.bitmaps {
ret.bitmaps.extend(bitmaps);
}
+ if let Some(includes) = filedef.includes {
+ ret.includes.extend(includes);
+ }
}
Ok(ret)