bricks/build/
mod.rs

1pub mod compile;
2pub mod compile_commands;
3pub mod include;
4pub mod link;
5pub mod tools;
6
7use std::{
8    fs::{self},
9    path::{Path, PathBuf},
10    process::Command,
11};
12
13use anyhow::Result;
14use compile_commands::CompileDatabase;
15
16use crate::{
17    cli::{args::BuildCommand, pretty},
18    config::{brick::BrickKind, overrides::OverrideDatabase, Config},
19};
20
21pub fn build(
22    config: &Config,
23    build_command: BuildCommand,
24    override_cmd: Option<String>,
25) -> Result<Option<PathBuf>> {
26    if let Some(override_cmd) = override_cmd {
27        pretty::msg("build", &override_cmd);
28
29        let mut cmd = match std::env::consts::OS {
30            "windows" => {
31                let mut cmd = Command::new("powershell.exe");
32                cmd.args(["-NoLogo", "-NonInteractive", "-NoProfile"]);
33                cmd.arg("/C");
34                cmd
35            }
36            _ => {
37                let mut cmd = Command::new("sh");
38                cmd.arg("-c");
39                cmd
40            }
41        };
42        cmd.current_dir(build_command.path);
43        cmd.arg(override_cmd);
44        cmd.status()?;
45
46        return Ok(None);
47    }
48
49    let mut compile_paths = vec![];
50
51    let src_path = Path::new(&build_command.path).join("src");
52
53    let override_path = Path::new(&build_command.path)
54        .join("build")
55        .join("overrides.json");
56    let override_file = match fs::read_to_string(override_path) {
57        Ok(v) => v,
58        Err(_) => {
59            pretty::warning(format!(
60                "no `build/overrides.json` found in {}. defaulting to no overrides.",
61                &build_command.path
62            ));
63            "{}".to_string()
64        }
65    };
66    let override_db: OverrideDatabase = serde_json::from_str(&override_file)?;
67
68    let mut compile_db = CompileDatabase::new();
69
70    for entry in walkdir::WalkDir::new(&src_path).follow_links(true) {
71        let Some((path, compile_cmd)) = compile::compile(
72            config,
73            entry,
74            &override_db,
75            build_command.force,
76            build_command.silent,
77        )?
78        else {
79            continue;
80        };
81        compile_paths.push(path);
82        compile_db.push(compile_cmd);
83    }
84
85    let mut ldflags = config.brick.ldflags.to_string();
86    ldflags += &match config.brick.platform() {
87        Some(platform) => match &platform.ldflags {
88            Some(v) => format!(" {}", v),
89            None => "".to_string(),
90        },
91        None => "".to_string(),
92    };
93
94    let build_result = match config.brick.kind {
95        BrickKind::Binary => link::binary(
96            &config.libs,
97            &compile_paths,
98            &Path::new(&build_command.path)
99                .join("build")
100                .join(&config.brick.name),
101            &override_db,
102            &ldflags,
103            config.brick.lang,
104            build_command.silent,
105        ),
106        BrickKind::Library => link::library(
107            &config.libs,
108            &compile_paths,
109            &Path::new(&build_command.path)
110                .join("build")
111                .join("lib")
112                .join(String::from("lib") + &config.brick.name + ".a"),
113            &override_db,
114            &ldflags,
115            config.brick.lang,
116            build_command.silent,
117        ),
118    };
119
120    if build_command.emit_compile_commands {
121        if !build_command.silent {
122            pretty::msg("emit", "build/compile_commands.json");
123        }
124        let comp_path = Path::new(&build_command.path)
125            .join("build")
126            .join("compile_commands.json");
127        let comp_file = fs::File::create(comp_path)?;
128        serde_json::to_writer(comp_file, &compile_db)?;
129    };
130
131    include::copy_headers(&src_path, &config.brick.name)?;
132
133    build_result
134}
135
136#[cfg(test)]
137mod tests {
138    use crate::build::compile::src_to_build_path;
139    use std::path::Path;
140
141    #[test]
142    fn check_src_to_build_path() {
143        assert_eq!(
144            src_to_build_path(Path::new("./src/main.c")),
145            Path::new("./build/main.o")
146        );
147        assert_eq!(
148            src_to_build_path(Path::new("./src/utils/crazy/main.c")),
149            Path::new("./build/utils/crazy/main.o")
150        );
151        assert_eq!(
152            src_to_build_path(Path::new("./main.c")),
153            Path::new("./main.o")
154        );
155    }
156}