project_C/main.rs
1//! Example: Building a C project with yamake.
2//!
3//! This example demonstrates how to use yamake to build a simple C project
4//! consisting of multiple source files, a static library, and an executable.
5//!
6//! # Project Structure
7//!
8//! ```text
9//! project_C/
10//! ├── main.c # Main source file
11//! ├── add.c # Library source file
12//! ├── add.h # Library header
13//! └── wrapper.h # Wrapper header (includes add.h)
14//! ```
15//!
16//! # Build Graph
17//!
18//! The build creates the following dependency graph:
19//!
20//! ```text
21//! main.c ──► main.o ──────────────────────► app
22//! ▲
23//! add.c ───► add.o ───► libproject.a ────────┘
24//! ```
25//!
26//! # Usage
27//!
28//! ```bash
29//! cargo run --example project_C -- -s demo_projects -b /tmp/sandbox
30//! ```
31//!
32//! # Key Concepts
33//!
34//! - **Root nodes**: Source files (`CFile`, `HFile`) that don't need building
35//! - **Build nodes**: Output files (`OFile`, `AFile`, `XFile`) that are built
36//! - **Edges**: Dependencies between nodes (source → object → executable)
37//! - **Automatic scanning**: Header dependencies are discovered automatically
38
39// ANCHOR: use
40use argh::FromArgs;
41use log::info;
42use std::path::PathBuf;
43use yamake::c_nodes::{AFile, CFile, HFile, OFile, XFile};
44use yamake::model::G;
45// ANCHOR_END: use
46
47// ANCHOR: use_existing_rules
48// Using existing C build rules from yamake::c_nodes:
49// - CFile: C source files (.c)
50// - HFile: Header files (.h)
51// - OFile: Object files (.o)
52// - AFile: Static library files (.a)
53// - XFile: Executable files
54// ANCHOR_END: use_existing_rules
55
56/// Command-line arguments for the project_C example.
57#[derive(FromArgs)]
58/// A C project build example
59struct Args {
60 /// source directory
61 #[argh(option, short = 's')]
62 src: PathBuf,
63
64 /// sandbox directory
65 #[argh(option, short = 'b')]
66 sandbox: PathBuf,
67}
68
69fn main() {
70 env_logger::init();
71
72 let args: Args = argh::from_env();
73
74 let srcdir = args.src;
75 let sandbox = args.sandbox;
76
77 // ANCHOR: instanciate
78 let mut g = G::new(srcdir, sandbox);
79 // ANCHOR_END: instanciate
80
81 // ANCHOR: add_nodes
82 let main_c = g.add_root_node(CFile::new("project_C/main.c")).unwrap();
83 let main_o = g
84 .add_node(OFile::new("project_C/main.o", vec![], vec![]))
85 .unwrap();
86 let add_c = g.add_root_node(CFile::new("project_C/add.c")).unwrap();
87 let add_o = g
88 .add_node(OFile::new(
89 "project_C/add.o",
90 vec![],
91 vec!["-DYYY_defined".to_string()],
92 ))
93 .unwrap();
94 let _add_h = g.add_root_node(HFile::new("project_C/add.h")).unwrap();
95 let _wrapper_h = g.add_root_node(HFile::new("project_C/wrapper.h")).unwrap();
96 let project_a = g.add_node(AFile::new("project_C/libproject.a")).unwrap();
97 let app = g.add_node(XFile::new("project_C/app")).unwrap();
98 // ANCHOR_END: add_nodes
99
100 // ANCHOR: add_edges
101 g.add_edge(main_c, main_o);
102 g.add_edge(main_o, app);
103 g.add_edge(add_c, add_o);
104 g.add_edge(add_o, project_a);
105 g.add_edge(project_a, app);
106 // ANCHOR_END: add_edges
107
108 info!(
109 "Created graph with {} nodes and {} edges",
110 g.g.node_count(),
111 g.g.edge_count()
112 );
113
114 // ANCHOR: make
115 // make() will:
116 // 1. Mount root nodes (copy source files to sandbox)
117 // 2. Scan for dependencies (adds edges for #include directives)
118 // 3. Build all nodes in dependency order (parallel where possible)
119 let success = g.make();
120 info!("Build {}", if success { "succeeded" } else { "failed" });
121 // ANCHOR_END: make
122}