-
Notifications
You must be signed in to change notification settings - Fork 0
DRAFT Feat/incremental build c objs #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0465a45
db69fb8
c4f5691
156ff2d
bde1cbc
a6bcd53
efa1d93
82be6dd
c39cb4a
386edce
84f7a80
3b7ee3d
c023451
f64d52e
66bfa06
9a310b2
1be711c
3ea8413
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,28 +1,210 @@ | ||
| // This modules handles compiling c/c++/asm/rust code | ||
| // SPDX-License-Identifier: MIT | ||
| // Copyright (c) 2025 Megaton contributors | ||
|
|
||
| use cu::Result; | ||
| use std::{ | ||
| collections::BTreeMap, | ||
| path::{Path, PathBuf}, | ||
| }; | ||
|
|
||
| use super::{Flags, Lang, RustCrate, SourceFile}; | ||
| use cu::pre::*; | ||
| use fxhash::hash; | ||
|
|
||
| // Compiles the given source file and writes it to `out` | ||
| pub fn compile(src: &SourceFile, out: &str, flags: Flags) -> Result<()> { | ||
| // TODO: Implement | ||
| use super::{Flags, RustCrate}; | ||
| use crate::{cmds::cmd_build::BuildEnvironment, env::environment}; | ||
|
|
||
| // match src.lang { | ||
| // Lang::C => todo!(), | ||
| // Lang::Cxx => todo!(), | ||
| // Lang::Asm => todo!(), | ||
| // }; | ||
| #[derive(Serialize, Deserialize)] | ||
| pub struct CompileDB { | ||
| commands: BTreeMap<String, CompileRecord>, | ||
| cc_version: String, | ||
| cxx_version: String, | ||
| } | ||
|
|
||
| Ok(todo!()) | ||
| impl CompileDB { | ||
| // Creates a new compile record and adds it to the db | ||
| fn update(&mut self, command: CompileCommand) -> cu::Result<()> { | ||
| todo!() | ||
| } | ||
| } | ||
|
|
||
| #[derive(Serialize, Deserialize)] | ||
| struct CompileRecord { | ||
| command: CompileCommand, | ||
| } | ||
|
|
||
| #[derive(Serialize, Deserialize, PartialEq, Eq)] | ||
| struct CompileCommand { | ||
| compiler: PathBuf, | ||
| source: PathBuf, | ||
| args: Vec<String>, | ||
| } | ||
|
|
||
| impl CompileCommand { | ||
| fn new( | ||
| compiler_path: &Path, | ||
| src_file: &Path, | ||
| out_file: &Path, | ||
| flags: &Vec<String>, | ||
| ) -> cu::Result<Self> { | ||
| let mut argv = flags.clone(); | ||
| argv.push( | ||
| src_file | ||
| .as_utf8() | ||
| .context("failed to parse utf-8")? | ||
| .to_string(), | ||
| ); | ||
| argv.push(String::from("-c")); | ||
| argv.push(format!( | ||
| "-o{}", | ||
| out_file.as_utf8().context("failed to parse utf-8")? | ||
| )); | ||
|
|
||
| Ok(Self { | ||
| compiler: compiler_path.to_path_buf(), | ||
| source: src_file.to_path_buf(), | ||
| args: argv, | ||
| }) | ||
| } | ||
|
|
||
| fn execute(&self) -> cu::Result<()> { | ||
| // TODO: Build and execute a cu::command | ||
| todo!() | ||
| } | ||
|
|
||
| // We need two different ways of serializing this data since it will | ||
| // need to be writen to the compiledb cache and the compile_commands.json | ||
| // and the format will be different for each | ||
| fn to_clangd_json(&self) -> String { | ||
| // TODO: Implement | ||
| todo!() | ||
| } | ||
| } | ||
|
|
||
| // A source file and its corresponding artifacts | ||
| pub struct SourceFile { | ||
| lang: Lang, | ||
| path: PathBuf, | ||
| basename: String, | ||
| hash: usize, | ||
| } | ||
|
|
||
| impl SourceFile { | ||
| pub fn new(lang: Lang, path: PathBuf) -> cu::Result<Self> { | ||
| let basename = cu::PathExtension::file_name_str(&path) | ||
| .context("path is not utf-8")? | ||
| .to_owned(); | ||
| let hash = hash(&cu::fs::read(&path).context("Failed to read source file")?); | ||
| Ok(Self { | ||
| lang, | ||
| path, | ||
| basename, | ||
| hash, | ||
| }) | ||
| } | ||
|
|
||
| pub fn compile( | ||
| &self, | ||
| flags: &Flags, | ||
| build_env: &BuildEnvironment, | ||
| compile_db: &mut CompileDB, | ||
| ) -> cu::Result<()> { | ||
| let o_path = PathBuf::from(format!( | ||
| "{}/{}/{}/o/{}-{}.o", | ||
| build_env.target, build_env.profile, build_env.module, self.basename, self.hash | ||
| )); | ||
| let d_path = PathBuf::from(format!( | ||
| "{}/{}/{}/o/{}-{}.d", | ||
| build_env.target, build_env.profile, build_env.module, self.basename, self.hash | ||
| )); | ||
|
|
||
| let (comp_path, comp_flags) = match self.lang { | ||
| Lang::C => (environment().cc_path(), &flags.cflags), | ||
| Lang::Cpp => (environment().cxx_path(), &flags.cxxflags), | ||
| Lang::S => (environment().cc_path(), &flags.sflags), | ||
| }; | ||
|
|
||
| let comp_command = CompileCommand::new(comp_path, &self.path, &o_path, &comp_flags)?; | ||
|
|
||
| if self.need_recompile(compile_db, build_env, &o_path, &d_path, &comp_command)? { | ||
| // Compile and update record | ||
| comp_command.execute()?; | ||
|
|
||
| // Ensure source and artifacts have the same timestamp | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you should read the timestamp of the source before compiling and set it on the artifacts afterwards. What if the source changes while it's being compiled? the current implementation would not recompile |
||
| let now = cu::fs::Time::now(); | ||
| cu::fs::set_mtime(o_path, now)?; | ||
| cu::fs::set_mtime(d_path, now)?; | ||
| cu::fs::set_mtime(&self.path, now)?; | ||
|
|
||
| compile_db.update(comp_command)?; | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| fn need_recompile( | ||
| &self, | ||
| compile_db: &CompileDB, | ||
| build_env: &BuildEnvironment, | ||
| o_path: &Path, | ||
| d_path: &Path, | ||
| command: &CompileCommand, | ||
| ) -> cu::Result<bool> { | ||
| // Check if record exists | ||
| let comp_record = match compile_db.commands.get(&self.basename) { | ||
| Some(record) => record, | ||
| None => return Ok(true), | ||
| }; | ||
|
|
||
| // Check if artifacts exist | ||
| if !o_path.exists() || !d_path.exists() { | ||
| return Ok(true); | ||
| } | ||
|
|
||
| // Check if artifacts are up to date | ||
| if cu::fs::get_mtime(o_path)? != cu::fs::get_mtime(&self.path)? | ||
| || cu::fs::get_mtime(d_path)? != cu::fs::get_mtime(&self.path)? | ||
| { | ||
| return Ok(true); | ||
| } | ||
|
|
||
| let d_file_contents = cu::fs::read_string(d_path)?; | ||
| let depfile = match depfile::parse(&&d_file_contents) { | ||
| Ok(depfile) => depfile, | ||
|
|
||
| // Make sure our errors are all cu compatible | ||
| Err(_) => return Err(cu::Error::msg("Failed to parse depfile")), | ||
| }; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. depfile::parse(...).context("...")?; or cu::check!(depfile::parse(...), ...format args)?; |
||
|
|
||
| for dep in depfile.recurse_deps(o_path.as_utf8()?) { | ||
| if cu::fs::get_mtime(PathBuf::from(dep))? != cu::fs::get_mtime(&self.path)? { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| return Ok(true); | ||
| } | ||
| } | ||
|
|
||
| if command != &comp_record.command { | ||
| return Ok(true); | ||
| } | ||
|
|
||
| if (self.lang == Lang::Cpp && compile_db.cxx_version != build_env.cxx_version) | ||
| || compile_db.cc_version != build_env.cc_version | ||
| { | ||
| return Ok(true); | ||
| } | ||
|
|
||
| // No need to recompile! | ||
| Ok(false) | ||
| } | ||
| } | ||
|
|
||
| // Specifies source language (rust is managed separately) | ||
| #[derive(PartialEq, Eq)] | ||
| pub enum Lang { | ||
| C, | ||
| Cpp, | ||
| S, | ||
| } | ||
|
|
||
| // Builds the give rust crate and places the binary in the target as specified in the rust manifest | ||
| pub fn compile_rust(rust_crate: RustCrate) -> Result<()> { | ||
| pub fn compile_rust(rust_crate: RustCrate) -> cu::Result<()> { | ||
| // TODO: Implement | ||
| Ok(todo!()) | ||
| } | ||
|
|
||
| fn check_needs_recompile() -> bool { | ||
| false | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,14 @@ | ||
| // This module manages linking the mod and library | ||
| // SPDX-License-Identifier: MIT | ||
| // Copyright (c) 2025 Megaton contributors | ||
|
|
||
| use cu::Result; | ||
| use cu::pre::*; | ||
|
|
||
| // Link build artifacts into a shared object elf | ||
| pub fn link() -> Result<()> { | ||
| pub fn link() -> cu::Result<()> { | ||
| Ok(todo!()) | ||
| } | ||
|
|
||
| // Convert the linked mod into an nso | ||
| pub fn make_nso() -> Result<()> { | ||
| pub fn make_nso() -> cu::Result<()> { | ||
| Ok(todo!()) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to add context here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same below