How to add rules
to add rules, you need to define the nodes of your build graph.
root nodes
a root node implements the trait GRootNode
#![allow(unused)]
fn main() {
/// A root node in the build graph representing a source file.
///
/// Root nodes are inputs to the build system (e.g., source files, configuration files)
/// that do not need to be built themselves. They automatically implement [`GNode`] with
/// a no-op `build` that returns `true`.
///
/// # Examples
///
/// ## Basic GRootNode
///
/// A simple root node representing a source file:
///
/// ```
/// use std::path::PathBuf;
/// use yamake::model::GRootNode;
///
/// struct SourceFile {
/// name: String,
/// }
///
/// impl GRootNode for SourceFile {
/// fn tag(&self) -> String {
/// "SourceFile".to_string()
/// }
///
/// fn pathbuf(&self) -> PathBuf {
/// PathBuf::from(&self.name)
/// }
/// }
///
/// let source = SourceFile { name: "main.c".to_string() };
/// assert_eq!(source.tag(), "SourceFile");
/// assert_eq!(source.pathbuf(), PathBuf::from("main.c"));
/// ```
///
/// ## GRootNode with expand
///
/// A root node that generates additional nodes and edges when expanded:
///
/// ```
/// use std::path::{Path, PathBuf};
/// use yamake::model::{Edge, ExpandResult, GNode, GRootNode};
///
/// /// A generated node produced by expand.
/// struct GeneratedNode {
/// name: String,
/// }
///
/// impl GNode for GeneratedNode {
/// fn tag(&self) -> String {
/// "GeneratedNode".to_string()
/// }
/// fn pathbuf(&self) -> PathBuf {
/// PathBuf::from(&self.name)
/// }
/// fn build(&self, _sandbox: &Path, _predecessors: &[&(dyn GNode + Send + Sync)]) -> bool {
/// true
/// }
/// }
///
/// /// A root node that expands to generate additional nodes.
/// struct ConfigFile {
/// name: String,
/// }
///
/// impl GRootNode for ConfigFile {
/// fn tag(&self) -> String {
/// "ConfigFile".to_string()
/// }
///
/// fn pathbuf(&self) -> PathBuf {
/// PathBuf::from(&self.name)
/// }
///
/// fn expand(
/// &self,
/// _sandbox: &Path,
/// _predecessors: &[&(dyn GNode + Send + Sync)],
/// ) -> ExpandResult {
/// // Generate nodes based on configuration
/// let node1 = GeneratedNode { name: "generated/file1.o".to_string() };
/// let node2 = GeneratedNode { name: "generated/file2.o".to_string() };
///
/// let nodes: Vec<Box<dyn GNode + Send + Sync>> = vec![
/// Box::new(node1),
/// Box::new(node2),
/// ];
///
/// // No edges in this example
/// let edges: Vec<Edge> = vec![];
///
/// Ok((nodes, edges))
/// }
/// }
///
/// let config = ConfigFile { name: "config.yml".to_string() };
/// let sandbox = PathBuf::from("/tmp/sandbox");
/// let predecessors: Vec<&(dyn GNode + Send + Sync)> = vec![];
///
/// // Use GRootNode::expand to disambiguate from the blanket GNode impl
/// let (nodes, edges) = GRootNode::expand(&config, &sandbox, &predecessors).unwrap();
/// assert_eq!(nodes.len(), 2);
/// assert_eq!(nodes[0].pathbuf(), PathBuf::from("generated/file1.o"));
/// assert_eq!(nodes[1].pathbuf(), PathBuf::from("generated/file2.o"));
/// ```
pub trait GRootNode {
/// Expands this node to generate additional nodes and edges.
///
/// Called after the node is built to dynamically add new nodes and edges
/// to the build graph. This is useful for nodes that generate code or
/// configuration that determines additional build targets.
///
/// Returns `Ok((nodes_to_add, edges_to_add))` on success, or an `ExpandError` on failure.
fn expand(
&self,
_sandbox: &Path,
_predecessors: &[&(dyn GNode + Send + Sync)],
) -> ExpandResult {
Ok((Vec::new(), Vec::new()))
}
/// Returns a tag identifying the type of this node.
fn tag(&self) -> String;
/// Returns the path associated with this node.
fn pathbuf(&self) -> PathBuf;
}
}
built nodes
the nodes which are not root have predecessors. They must implement trait yamake::GNode
#![allow(unused)]
fn main() {
pub trait GNode: Send + Sync {
fn build(&self, _sandbox: &Path, _predecessors: &[&(dyn GNode + Send + Sync)]) -> bool {
panic!("build not implemented for {}", self.pathbuf().display())
}
fn scan(
&self,
_sandbox: &Path,
_predecessors: &[&(dyn GNode + Send + Sync)],
) -> (bool, Vec<PathBuf>) {
(true, Vec::new())
}
fn expand(
&self,
_sandbox: &Path,
_predecessors: &[&(dyn GNode + Send + Sync)],
) -> ExpandResult {
Ok((Vec::new(), Vec::new()))
}
fn tag(&self) -> String;
fn pathbuf(&self) -> PathBuf;
}
}