From 4a2e9595358d5cfca0311bdc5fe45e1f7a66a0f2 Mon Sep 17 00:00:00 2001 From: godsfryingpan Date: Mon, 23 Mar 2026 11:17:42 -0600 Subject: [PATCH] Add ability to make compile_commands.json (#13) issue: #8 Reviewed-on: http://192.168.1.227:3000/sfrembling/pallet/pulls/13 Co-authored-by: godsfryingpan Co-committed-by: godsfryingpan --- Cargo.lock | 32 +++++++++++++++++++++++++++ Cargo.toml | 1 + src/app.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 22efbb4..866368d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,12 +233,24 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "libc" version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + [[package]] name = "once_cell_polyfill" version = "1.70.2" @@ -254,6 +266,7 @@ dependencies = [ "colored", "glob", "serde", + "serde_json", "sha256", "toml", ] @@ -312,6 +325,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "serde_spanned" version = "1.0.4" @@ -455,3 +481,9 @@ name = "winnow" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 90ab629..bb865a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,6 @@ clap_complete = "4.6.0" colored = "3.1.1" glob = "0.3.3" serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.149" sha256 = "1.6.0" toml = "1.0.7" diff --git a/src/app.rs b/src/app.rs index ebb4612..0c71158 100644 --- a/src/app.rs +++ b/src/app.rs @@ -9,7 +9,7 @@ use colored::Colorize; use glob::glob; const MAIN_C: &str = include_str!("templates/main.c"); -const GITIGNORE: &str = "target/"; +const GITIGNORE: &str = "target/\ncompile_commands.json\n"; #[derive(clap::Parser)] #[clap(version, about)] @@ -65,6 +65,11 @@ enum UtilSubcommand { #[arg(value_enum, long, short)] shell: ShellCompletions, }, + /// Generate compile_commands.json for IDE support + GenCompileCommands { + /// The build mode to generate for + mode: Option, + }, } #[derive(Clone, clap::ValueEnum)] @@ -150,6 +155,12 @@ impl App { ), } } + UtilSubcommand::GenCompileCommands { mode } => { + if let Err(e) = gen_compile_commands(&mode) { + eprintln!("Error generating compile commands: {e}"); + std::process::exit(1); + } + } }, Subcommand::List => { if let Err(e) = list() { @@ -161,6 +172,55 @@ impl App { } } +fn gen_compile_commands(mode: &Option) -> std::io::Result<()> { + let conf = get_config().ok_or(std::io::Error::new( + std::io::ErrorKind::NotFound, + "no Pallet.toml found in current directory", + ))?; + + let build_config = conf.get_or_default(mode).ok_or(std::io::Error::new( + std::io::ErrorKind::NotFound, + "build layout not found", + ))?; + + let compiler = conf.compiler.as_deref().unwrap_or("gcc"); + let cwd = std::env::current_dir()?; + let obj_dir = format!("target/{}/obj", build_config.name); + + let source_files: Vec = glob("src/*.c") + .map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, format!("{e}")))? + .filter_map(|e| e.ok()) + .collect(); + + let entries: Vec = source_files + .iter() + .map(|src| { + let stem = src.file_stem().unwrap().to_string_lossy(); + let obj = format!("{}/{}.o", obj_dir, stem); + let command = std::iter::once(compiler.to_string()) + .chain(build_config.args.iter().cloned()) + .chain(["-c".to_string(), src.to_string_lossy().to_string()]) + .chain(["-o".to_string(), obj]) + .collect::>() + .join(" "); + serde_json::json!({ + "directory": cwd.to_string_lossy(), + "file": cwd.join(src).to_string_lossy(), + "command": command + }) + }) + .collect(); + + let json = serde_json::to_string_pretty(&entries) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{e}")))?; + + std::fs::write("compile_commands.json", json)?; + + println!(" {} compile_commands.json", "Generated".green().bold()); + + Ok(()) +} + fn list() -> std::io::Result<()> { let conf = get_config().ok_or(std::io::Error::new( std::io::ErrorKind::NotFound, @@ -331,6 +391,8 @@ fn build(mode: &Option, force_recompile: bool) -> std::io::Result<()> { let stop = start.elapsed(); + gen_compile_commands(&mode)?; + println!( " {} '{}' profile for project '{}' in {:.2}s", "Finished".green().bold(),