corge/command/
build.rs

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    /** Configuration parsing */
24    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    /* Path definition */
35    let dependency_path = DependencyPath::create(&project_path)?;
36    let target_path = TargetPath::create(&project_path, &build_mode.to_string(), &toolchain_name)?;
37
38    /** Dependency fetching */
39    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    /** Compilation */
49    log::info!("Compiling project");
50    let compiler = Compiler::new(profile, toolchain.clone(), dependency_path.include.clone());
51
52    /* generate position-independent code if the project is a dynamic library */
53    let pic = matches!(build_args.link, LinkStrategy::DynamicLibrary);
54
55    let mut object_files = vec![];
56
57    /* compile dependencies artifacts */
58    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    /* compile project sources */
74    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    /** Linking */
83    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}