1
//! file for represent the available configuration properties within Zork++
2
//! for setting up the target compiler
3

            
4
use serde::{Deserialize, Serialize};
5

            
6
use crate::project_model;
7

            
8
/// [`CompilerAttribute`] - Configuration properties for
9
/// targeting one of the available compilers within Zork++
10
///
11
/// * `cpp_compiler` - One of the available compilers within Zork++
12
///     They are represented by an enumerated type named [`CppCompiler`],
13
///     that holds the different options where the user can choose
14
///
15
/// * `driver_path` - The specific command line terminal identifier that will
16
///     call the compiler's binary. ie: clang++-15 will call a specific installation
17
///     of Clang in the host machine corresponding to the version 15 of the compiler.
18
///     This entry is particularly useful in Unix based OS or MinGW environments,
19
///     where multiple versions of the compiler lives at the same time, and their drivers
20
///     are identified by some sort of name like the one in the example of above
21
///
22
/// * `cpp_standard` - An string defining the version of the ISO
23
///     C++ standard that should be used on the compilation process
24
///
25
/// * `std_lib` - The concrete C++ standard library (vendor specific)
26
///     to link the built code against
27
///
28
/// * `extra_args` - A comma separated list of strings that will be passed
29
///     to the generated command lines. This ones here will be placed in every
30
///     command line generated by Zork++.
31
///     For example, if *['-O3', '-Wall']*
32
///     are included here, this will be wired in the main command line (the executable),
33
///     the ones generated for compile modules (both interfaces and implementations)
34
///     and for the command line generated for build the specified test suite and
35
///     the test executable
36
///
37
/// ### Tests
38
///
39
/// ```rust
40
/// use zork::config_file::compiler::{
41
///     CompilerAttribute, CppCompiler, LanguageLevel, StdLib
42
/// };
43
///
44
/// const CONFIG_FILE_MOCK: &str = r#"
45
///     #[compiler]
46
///     cpp_compiler = 'CLANG'
47
///     cpp_standard = '20'
48
///     driver_path = 'clang++-19'
49
///     std_lib = 'libcpp'
50
///     std_lib_installed_dir = '/usr/include/c++/v1'
51
///     extra_args = ['-O3', '-Wall']
52
///"#;
53
///
54
/// let config: CompilerAttribute = toml::from_str(CONFIG_FILE_MOCK)
55
///    .expect("A failure happened parsing the Zork toml file");
56
///
57
/// assert_eq!(config.cpp_compiler, CppCompiler::CLANG);
58
/// assert_eq!(config.cpp_standard, LanguageLevel::CPP20);
59
/// assert_eq!(config.driver_path, Some("clang++-19"));
60
/// assert_eq!(config.std_lib, Some(StdLib::LIBCPP));
61
/// assert_eq!(config.std_lib_installed_dir, Some("/usr/include/c++/v1"));
62
/// assert_eq!(config.extra_args, Some(vec!["-O3", "-Wall"]));
63
/// assert_eq!(config.system_headers_path, None);
64
/// ```
65
///
66
/// > Note: TOML table are toml commented (#) to allow us to parse
67
/// > the inner attributes as the direct type that they belongs to.
68
/// > That commented tables aren't the real TOML, they are just there
69
/// > for testing and exemplification purposes of the inner attributes
70
/// > of the configuration file.
71
///
72
/// For a test over a real example, please look at the
73
/// [`zork::config_file::ZorkConfigFile`] doc-test
74
116
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
75
#[serde(deny_unknown_fields)]
76
pub struct CompilerAttribute<'a> {
77
    pub cpp_compiler: CppCompiler,
78
    #[serde(borrow)]
79
    pub driver_path: Option<&'a str>,
80
    pub cpp_standard: LanguageLevel,
81
    pub std_lib: Option<StdLib>,
82
    #[serde(borrow)]
83
    pub std_lib_installed_dir: Option<&'a str>,
84
    #[serde(borrow)]
85
    pub extra_args: Option<Vec<&'a str>>,
86
    #[serde(borrow)]
87
    pub system_headers_path: Option<&'a str>,
88
}
89

            
90
/// The C++ compilers available within Zork++
91
40
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Default)]
92
10
pub enum CppCompiler {
93
    #[serde(alias = "CLANG", alias = "Clang", alias = "clang")]
94
    #[default]
95
    CLANG,
96
    #[serde(alias = "MSVC", alias = "Msvc", alias = "msvc")]
97
    MSVC,
98
    #[serde(alias = "GCC", alias = "Gcc", alias = "gcc")]
99
    GCC,
100
}
101

            
102
// Clippy warns to prefer implementing the From trait instead of Into.
103
// That would require that the project model know about config_file details, which is ugly.
104
#[allow(clippy::from_over_into)]
105
impl Into<project_model::compiler::CppCompiler> for CppCompiler {
106
13
    fn into(self) -> project_model::compiler::CppCompiler {
107
13
        match self {
108
10
            CppCompiler::CLANG => project_model::compiler::CppCompiler::CLANG,
109
            CppCompiler::MSVC => project_model::compiler::CppCompiler::MSVC,
110
3
            CppCompiler::GCC => project_model::compiler::CppCompiler::GCC,
111
        }
112
13
    }
113
}
114

            
115
/// The C++ ISO standard levels of the language, represented as an
116
/// enumerated type in Rust
117
///
118
/// Variants *2A* and *2B* represents Clang's way of
119
/// use the latest features available
120
///
121
/// Variant *LATEST* is the `MSVC` specific way of set the language
122
/// standard level to the latest features available in Microsoft's compiler
123
47
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
124
10
pub enum LanguageLevel {
125
    #[serde(alias = "20")]
126
    #[default]
127
    CPP20,
128
    #[serde(alias = "23")]
129
    CPP23,
130
    #[serde(alias = "2a")]
131
    CPP2A,
132
    #[serde(alias = "2b")]
133
    CPP2B,
134
    #[serde(alias = "latest")]
135
    LATEST,
136
}
137

            
138
// Clippy warns to prefer implementing the From trait instead of Into.
139
// That would require that the project model know about config_file details, which is ugly.
140
#[allow(clippy::from_over_into)]
141
impl Into<project_model::compiler::LanguageLevel> for LanguageLevel {
142
7
    fn into(self) -> project_model::compiler::LanguageLevel {
143
7
        match self {
144
            LanguageLevel::CPP20 => project_model::compiler::LanguageLevel::CPP20,
145
1
            LanguageLevel::CPP23 => project_model::compiler::LanguageLevel::CPP23,
146
            LanguageLevel::CPP2A => project_model::compiler::LanguageLevel::CPP2A,
147
6
            LanguageLevel::CPP2B => project_model::compiler::LanguageLevel::CPP2B,
148
            LanguageLevel::LATEST => project_model::compiler::LanguageLevel::LATEST,
149
        }
150
7
    }
151
}
152

            
153
/// The standard library (compiler specific) that the user
154
/// desires to link against
155
39
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
156
8
pub enum StdLib {
157
    #[serde(alias = "libstdc++", alias = "gccstdlib", alias = "libstdcpp")]
158
    STDLIBCPP,
159
    #[serde(alias = "libc++", alias = "libcpp")]
160
    LIBCPP,
161
}
162

            
163
// Clippy warns to prefer implementing the From trait instead of Into.
164
// That would require that the project model know about config_file details, which is ugly.
165
#[allow(clippy::from_over_into)]
166
impl Into<project_model::compiler::StdLib> for StdLib {
167
6
    fn into(self) -> project_model::compiler::StdLib {
168
6
        match self {
169
            StdLib::STDLIBCPP => project_model::compiler::StdLib::STDLIBCPP,
170
6
            StdLib::LIBCPP => project_model::compiler::StdLib::LIBCPP,
171
        }
172
6
    }
173
}