1pub mod target_path;
2pub mod dependency_path;
3
4use crate::cli::{BuildArgs, BuildModeCli};
5use crate::command::build::dependency_path::DependencyPath;
6use crate::command::build::target_path::TargetPath;
7use crate::config::{Config, LinkStrategy, OptimizationLevel, Profile};
8use crate::tool::compiler::Compiler;
9use crate::tool::configuration_parser::ConfigurationParser;
10use crate::tool::dependency_include_fetcher::DependencyIncludeFetcher;
11use crate::tool::dependency_source_fetcher::DependencySourceFetcher;
12use crate::tool::files_fetcher::fetch_files;
13use crate::tool::linker::Linker;
14use anyhow::{Context, Result};
15use std::fs;
16use std::path::PathBuf;
17
18pub fn build(build_args: BuildArgs) -> Result<PathBuf> {
19 let project_path = build_args.path.clone();
20
21 log::info!("Building project in directory {:?}", &project_path);
22
23 log::info!("Parsing build.yaml file");
25 let config = ConfigurationParser::new(project_path.clone())
26 .parse()
27 .context("Corge project is not detected")?;
28
29 let build_mode = build_args.build_mode();
30 let profile = fetch_profile(&config, &build_mode);
31 let (toolchain_name, toolchain) = config.toolchain(build_args.toolchain)
32 .context("Failed to find toolchain in build.yaml file")?;
33
34 let dependency_path = DependencyPath::create(&project_path)?;
36 let target_path = TargetPath::create(&project_path, &build_mode.to_string(), &toolchain_name)?;
37
38 log::info!("Fetching dependencies");
40 let artifacts = DependencySourceFetcher::new(config.registries, config.dependencies, )
41 .fetch(&dependency_path.source)
42 .context("Failed to fetch dependency sources")?;
43
44 DependencyIncludeFetcher::new(&artifacts)
45 .fetch(&dependency_path.include)
46 .context("Failed to fetch dependency headers")?;
47
48 log::info!("Compiling project");
50 let compiler = Compiler::new(profile, toolchain.clone(), dependency_path.include.clone());
51
52 let pic = matches!(build_args.link, LinkStrategy::DynamicLibrary);
54
55 let mut object_files = vec![];
56
57 for artifact in &artifacts {
59 let target_path = target_path.build_mode.toolchain.cache.dependency.join(&artifact.dependency.name);
60 fs::create_dir_all(&target_path)
61 .with_context(|| format!("Failed to create directory {:?}", &target_path))?;
62
63 let source_files = fetch_files(&artifact.path.join("src"), "c")
64 .with_context(|| format!("Failed to fetch source files for dependency {}", &artifact.dependency.name))?;
65
66 let artifact_object_files = compiler
67 .compile(&source_files, &target_path, pic)
68 .with_context(|| format!("Failed to compile dependency '{}' artifact", &artifact.dependency.name))?;
69
70 object_files.extend(artifact_object_files);
71 }
72
73 let source_files = fetch_files(&project_path.join("src"), "c")
75 .context("Failed to fetch source files for project")?;
76
77 let project_object_files = compiler
78 .compile(&source_files, &target_path.build_mode.toolchain.cache.project, pic)
79 .context("Failed to compile project files")?;
80 object_files.extend(project_object_files);
81
82 log::info!("Linking project");
84 let linker = Linker::new(toolchain);
85 let output_file_path = linker.link(&build_args.link, &object_files, &target_path.build_mode.toolchain.output, &config.project.name)
86 .context("Failed to link project")?;
87
88 log::info!("BUILD SUCCESSFUL");
89 Ok(output_file_path)
90}
91
92fn fetch_profile(config: &Config, build_mode: &BuildModeCli,) -> Profile {
93 match build_mode {
94 BuildModeCli::Development => {
95 config.profiles.development.clone().unwrap_or_else(|| Profile {
96 optimization_level: OptimizationLevel::O
97 })
98 }
99 BuildModeCli::Release => {
100 config.profiles.release.clone().unwrap_or_else(|| Profile {
101 optimization_level: OptimizationLevel::Ofast
102 })
103 }
104 }
105}