Skip to main content

cargo_xwin/
options.rs

1use std::path::{Path, PathBuf};
2use std::process::Command;
3
4use anyhow::Result;
5use clap::{
6    Parser, ValueEnum,
7    builder::{PossibleValuesParser, TypedValueParser as _},
8};
9use fs_err as fs;
10
11/// MSVC cross compiler
12#[derive(Clone, Debug, Default, ValueEnum)]
13pub enum CrossCompiler {
14    /// clang-cl backend
15    #[default]
16    ClangCl,
17    /// clang backend
18    Clang,
19}
20
21/// common xwin options
22#[derive(Clone, Debug, Parser)]
23pub struct XWinOptions {
24    /// The cross compiler to use
25    #[arg(long, env = "XWIN_CROSS_COMPILER", default_value = "clang-cl")]
26    pub cross_compiler: CrossCompiler,
27
28    /// xwin cache directory
29    #[arg(long, env = "XWIN_CACHE_DIR", hide = true)]
30    pub xwin_cache_dir: Option<PathBuf>,
31
32    /// The architectures to include in CRT/SDK
33    #[arg(
34        long,
35        env = "XWIN_ARCH",
36        value_parser = PossibleValuesParser::new(["x86", "x86_64", "aarch", "aarch64"])
37            .map(|s| s.parse::<xwin::Arch>().unwrap()),
38        value_delimiter = ',',
39        default_values_t = vec![xwin::Arch::X86_64, xwin::Arch::Aarch64],
40        hide = true,
41    )]
42    pub xwin_arch: Vec<xwin::Arch>,
43
44    /// The variants to include
45    #[arg(
46        long,
47        env = "XWIN_VARIANT",
48        value_parser = PossibleValuesParser::new(["desktop", "onecore", /*"store",*/ "spectre"])
49            .map(|s| s.parse::<xwin::Variant>().unwrap()),
50        value_delimiter = ',',
51        default_values_t = vec![xwin::Variant::Desktop],
52        hide = true,
53    )]
54    pub xwin_variant: Vec<xwin::Variant>,
55
56    /// The version to retrieve, can either be a major version of 15, 16, 17 or 18, or
57    /// a "<major>.<minor>" version.
58    #[arg(long, env = "XWIN_VERSION", default_value = "17")]
59    pub xwin_version: u8,
60
61    /// If specified, this is the version of the SDK that the user wishes to use
62    /// instead of defaulting to the latest SDK available in the the manifest
63    #[arg(long, env = "XWIN_SDK_VERSION")]
64    pub xwin_sdk_version: Option<String>,
65    /// If specified, this is the version of the MSVCRT that the user wishes to use
66    /// instead of defaulting to the latest MSVCRT available in the the manifest
67    #[arg(long, env = "XWIN_CRT_VERSION")]
68    pub xwin_crt_version: Option<String>,
69
70    /// Whether to include the Active Template Library (ATL) in the installation
71    #[arg(long, env = "XWIN_INCLUDE_ATL")]
72    pub xwin_include_atl: bool,
73
74    /// Whether or not to include debug libs
75    #[arg(long, env = "XWIN_INCLUDE_DEBUG_LIBS", hide = true)]
76    pub xwin_include_debug_libs: bool,
77
78    /// Whether or not to include debug symbols (PDBs)
79    #[arg(long, env = "XWIN_INCLUDE_DEBUG_SYMBOLS", hide = true)]
80    pub xwin_include_debug_symbols: bool,
81
82    /// Number of times to retry HTTP requests when downloading
83    #[arg(long, env = "XWIN_HTTP_RETRIES", default_value = "3")]
84    pub xwin_http_retries: u32,
85}
86
87impl Default for XWinOptions {
88    fn default() -> Self {
89        Self {
90            xwin_cache_dir: None,
91            xwin_arch: vec![xwin::Arch::X86_64, xwin::Arch::Aarch64],
92            xwin_variant: vec![xwin::Variant::Desktop],
93            xwin_version: 17,
94            xwin_sdk_version: None,
95            xwin_crt_version: None,
96            xwin_include_atl: false,
97            xwin_include_debug_libs: false,
98            xwin_include_debug_symbols: false,
99            cross_compiler: CrossCompiler::ClangCl,
100            xwin_http_retries: 3,
101        }
102    }
103}
104
105impl XWinOptions {
106    pub fn apply_command_env(
107        &self,
108        manifest_path: Option<&Path>,
109        cargo: &cargo_options::CommonOptions,
110        cmd: &mut Command,
111    ) -> Result<()> {
112        let cache_dir = {
113            let cache_dir = self.xwin_cache_dir.clone().unwrap_or_else(|| {
114                dirs::cache_dir()
115                    .unwrap_or_else(|| std::env::current_dir().expect("Failed to get current dir"))
116                    .join(env!("CARGO_PKG_NAME"))
117            });
118            fs::create_dir_all(&cache_dir)?;
119            cache_dir.canonicalize()?
120        };
121        match self.cross_compiler {
122            CrossCompiler::ClangCl => {
123                let clang_cl = crate::compiler::clang_cl::ClangCl::new(self);
124                clang_cl.apply_command_env(manifest_path, cargo, cache_dir, cmd)?;
125            }
126            CrossCompiler::Clang => {
127                let clang = crate::compiler::clang::Clang::new();
128                clang.apply_command_env(manifest_path, cargo, cache_dir, cmd)?;
129            }
130        }
131        Ok(())
132    }
133}