diff --git a/CHANGELOG.md b/CHANGELOG.md index a946aa9..156ae13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - ReleaseDate +### Added +- [PR#101](https://github.com/Jake-Shadle/xwin/pull/101) resolved [#28](https://github.com/Jake-Shadle/xwin/issues/28), [#84](https://github.com/Jake-Shadle/xwin/issues/84), and [#85](https://github.com/Jake-Shadle/xwin/issues/85) by adding a `minimize` command that straces a cargo build to write a `map` file that can be used by a `splat` command to only splat the headers and libraries actually needed to build, drastically reducing the splat output (eg. 1.3GiB -> 101MiB). This `map` file also allows the creation of symlinks on a per-file basis, allowing users to create their own symlinks if needed. +- [PR#104](https://github.com/Jake-Shadle/xwin/pull/104) resolved [#103](https://github.com/Jake-Shadle/xwin/issues/103) by allowing custom certificates to be specified via the `SSL_CERT_FILE`, `CURL_CA_BUNDLE`, or `REQUESTS_CA_BUNDLE` environment variables. `xwin` must be compiled with the `native-tls` feature for this to function. Thanks [@Owen-CH-Leung](https://github.com/Owen-CH-Leung)! +- [PR#105](https://github.com/Jake-Shadle/xwin/pull/105) supplanted [#100](https://github.com/Jake-Shadle/xwin/pull/100), allowing creation of symlinks on a Windows host. Thanks [@sykhro](https://github.com/sykhro)! + ## [0.3.1] - 2023-09-12 ### Changed - [PR#99](https://github.com/Jake-Shadle/xwin/pull/99) changed the default VS manifest version from 16 -> 17. You can preserve the old behavior by passing `--manifest-version 16` on the cmd line. diff --git a/Cargo.lock b/Cargo.lock index 19bbbea..3d94104 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,9 +145,9 @@ dependencies = [ [[package]] name = "cfb" -version = "0.7.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +checksum = "b390793e912300f1aa713429f7fd0c391024e6c18b988962558bc4f96a349b1f" dependencies = [ "byteorder", "fnv", @@ -640,9 +640,9 @@ dependencies = [ [[package]] name = "msi" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7124fc3188eff23916d20d82bcbbb993914b22fba5603f9e7745e347a86cf67" +checksum = "226b2404f03d2cf47375b9715c8adfae4e388bb2377cff908e8a40f31e421514" dependencies = [ "byteorder", "cfb", diff --git a/Cargo.toml b/Cargo.toml index 86ba095..ee8ceec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,15 @@ repository = "https://github.com/Jake-Shadle/xwin" homepage = "https://github.com/Jake-Shadle/xwin" categories = ["development-tools", "command-line-utilities"] keywords = ["windows", "cross-compilation"] +exclude = [ + ".cargo", + ".github", + "docs", + "tests/**", + "deny.toml", + "release.toml", + "xwin.dockerfile", +] [features] # By default we use rustls for TLS @@ -16,7 +25,12 @@ default = ["rustls-tls"] rustls-tls = ["ureq/tls"] # If this feature is enabled we instead use the native TLS implementation for the # target platform -native-tls = ["ureq/native-tls", "native-tls-crate/vendored", "rustls-pemfile", "rustls"] +native-tls = [ + "ureq/native-tls", + "native-tls-crate/vendored", + "rustls-pemfile", + "rustls", +] [dependencies] # Easy errors @@ -37,7 +51,7 @@ flate2 = { version = "1.0", default-features = false, features = [ # Pretty progress bars indicatif = "0.17" # Decoding of MSI installer packages -msi = "0.6" +msi = "0.7" parking_lot = "0.12" # brrr rayon = "1.5" diff --git a/README.md b/README.md index 03972ca..92e7413 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ You can download a prebuilt binary from the [Releases](https://github.com/Jake-S ## Usage +### Common + * `--accept-license` - Doesn't display the prompt to accept the license. You can also set the `XWIN_ACCEPT_LICENSE=1` environment variable * `--arch ` - The architectures to include [default: x86_64] [possible values: x86, x86_64, aarch, aarch64]. Note that I haven't fully tested aarch/64 nor x86 so there _might_ be issues with them, please file an issue if you encounter problems with them. * `--cache-dir ` - Specifies the cache directory used to persist downloaded items to disk. Defaults to `./.xwin-cache` if not specified. @@ -48,6 +50,12 @@ You can download a prebuilt binary from the [Releases](https://github.com/Jake-S * `--channel ` - The product channel to use [default: release] * `--manifest-version ` - The manifest version to retrieve [default: 16]. * `--manifest` - Specifies a top level manifest to use, rather than downloading it from Microsoft. This can be used to ensure the output is reproducible. +* `--sdk-version` - The specific SDK version to use. If not specified the latest SDK version in the manifest is used. +* `--crt-version` - The specific CRT version to use. If not specified the latest CRT version in the manifest is used. +* `--timeout` - Specifies a timeout for long a single HTTP get request is allowed to take. The default is 60s. + +### Env vars + * `https_proxy` - Environment variable that specifies the HTTPS proxy to use. ### `xwin download` @@ -62,12 +70,15 @@ Decompresses all of the downloaded package contents to disk. `download` is run a Fixes the packages to prune unneeded files and adds symlinks to address file casing issues and then spalts the final artifacts into directories. This is the main command you will want to run as it also `download`s and `unpack`s automatically, providing the desired headers at the path specified to `--output` (`./.xwin-cache/splat`). +#### Splat options + * `--copy` - Copies files from the unpack directory to the splat directory instead of moving them, which preserves the original unpack directories but increases overall execution time and disk usage. * `--disable-symlinks` - By default, symlinks are added to both the CRT and WindowsSDK to address casing issues in general usage. For example, if you are compiling C/C++ code that does `#include `, it will break on a case-sensitive file system, as the actual path in the WindowsSDK is `Windows.h`. This also applies even if the C/C++ you are compiling uses correct casing for all CRT/SDK includes, as the internal headers also use incorrect casing in most cases * `--include-debug-libs` - The MSVCRT includes (non-redistributable) debug versions of the various libs that are generally uninteresting to keep for most usage * `--include-debug-symbols` - The MSVCRT includes PDB (debug symbols) files for several of the libraries that are generally uninteresting to keep for most usage * `--preserve-ms-arch-notation` - By default, we convert the MS specific `x64`, `arm`, and `arm64` target architectures to the more canonical `x86_64`, `aarch`, and `aarch64` of LLVM etc when creating directories/names. Passing this flag will preserve the MS names for those targets * `--output` - The root output directory. Defaults to `./.xwin-cache/splat` if not specified +* `--map` - An optional [map](#map-file) file used to configure what files are splatted, and any additional symlinks to create. This moves all of the unpacked files which aren't pruned to their canonical locations under a root directory, for example here is what an `x86_64` `Desktop` splat looks like. `unpack` is run automatically as needed. @@ -113,10 +124,59 @@ This moves all of the unpacked files which aren't pruned to their canonical loca └── x86_64 ``` +### `xwin minimize` + +This is an advanced command that performs a `splat` before performing a build on a cargo manifest using strace to capture all of the headers and libraries that are used throughout the build and dumping them to a [map](#map-file). This command can also output the final splat to disk, or the map file can be used with `splat` to only splat the files and symlinks described in it. + +Note that currently the build is always done with the `/vctoolsdir` and `/winsdkdir` options, so it is expected these are the same options used when compiling C/C++ code in your normal environment. If that is not the case please open an issue. + +#### Requirements + +* Linux host - This _might_ work on other platforms, but it's not guaranteed, nor tested +* `cargo` - This is the singular supported build tool. +* `-pc-windows-msvc` - The target you are building for needs to be installed (eg. via `rustup target add`) +* `clang-cl` - This is used as the C/C++ compiler +* `llvm-lib` - This is used as the archiver +* `lld-link` - This is used as the linker +* `strace` - This is used to capture the syscalls made by the lld and clang compiler + +#### Minimize options + +Note all of the [splat options](#splat-options) also apply to minimize. + +* `--map` - The path to the [map](#map-file) to output the minimized results to. Default to `./.xwin-cache/xwin-map.toml` if not specified. +* `--minimize-output` - The root directory where only the minimized files are splatted to. If not specified only the `--map` file is written in addition to the normal splat +* `--preserve-strace` - By default the `strace` output is written to disk in a temporary location that is deleted once the build is finished, passing this option allows it to be persisted. The path is written out before the build starts. + +## Map file + +As noted in [minimize](#xwin-minimize), there are many restrictions on it to make my life easier, but that make it unsuitable for those who don't use cargo/rust. It's possible for others to come up with their own versions of minimize that can output the same format that `splat` understands to still get the benefits of `xwin` without cargo/rust. + +The format is extremely simple + +```txt +├── crt +│ ├── headers +│ │ ├── filter - Array of relative paths to keep +│ │ └── symlinks +│ │ └── - The same path as one of the filters +│ │ └── - Array of symlinks to create in the same directory as the parent path +│ ├── libs * +└── sdk * +``` + +### Example + +See [docs/example-map.toml](docs/example-map.toml) for a real world example. + ## Container [xwin.dockerfile](xwin.dockerfile) is an example Dockerfile that can be used a container image capable of building and testing Rust crates targeting `x86_64-pc-windows-msvc`. +## Custom certificates + +If you require custom certificates you can specify the path via the `SSL_CERT_FILE`, `CURL_CA_BUNDLE`, or `REQUESTS_CA_BUNDLE` environment variables. This requires being compiled with the `native-tls` feature. + ### Thanks Special thanks to for the inspiration and [@mdsteele](https://github.com/mdsteele) for publishing several Rust crates around msi/cab files that were needed in this project diff --git a/docs/example-map.toml b/docs/example-map.toml new file mode 100644 index 0000000..05c6b41 --- /dev/null +++ b/docs/example-map.toml @@ -0,0 +1,264 @@ +[crt.headers] +filter = [ + "__msvc_iter_core.hpp", + "__msvc_sanitizer_annotate_container.hpp", + "algorithm", + "cassert", + "cctype", + "cfloat", + "climits", + "concurrencysal.h", + "crtdefs.h", + "cstddef", + "cstdint", + "cstdio", + "cstdlib", + "cstring", + "cwchar", + "eh.h", + "exception", + "excpt.h", + "initializer_list", + "iosfwd", + "isa_availability.h", + "limits", + "limits.h", + "list", + "new", + "sal.h", + "setjmp.h", + "stdint.h", + "string", + "type_traits", + "use_ansi.h", + "utility", + "vadefs.h", + "vcruntime.h", + "vcruntime_exception.h", + "vcruntime_new.h", + "vcruntime_new_debug.h", + "vcruntime_string.h", + "vector", + "xatomic.h", + "xkeycheck.h", + "xmemory", + "xstring", + "xtr1common", + "xutility", + "yvals.h", + "yvals_core.h", +] + +[crt.libs] +filter = ["x86_64/msvcrt.lib", "x86_64/vcruntime.lib"] + +[crt.libs.symlinks] +"x86_64/msvcrt.lib" = ["MSVCRT.lib"] + +[sdk.headers] +filter = [ + "shared/WTypesbase.h", + "shared/apiset.h", + "shared/apisetcconv.h", + "shared/basetsd.h", + "shared/bcrypt.h", + "shared/cderr.h", + "shared/driverspecs.h", + "shared/guiddef.h", + "shared/inaddr.h", + "shared/kernelspecs.h", + "shared/ktmtypes.h", + "shared/minwindef.h", + "shared/poppack.h", + "shared/pshpack1.h", + "shared/pshpack2.h", + "shared/pshpack4.h", + "shared/pshpack8.h", + "shared/rpc.h", + "shared/rpcasync.h", + "shared/rpcdce.h", + "shared/rpcdcep.h", + "shared/rpcndr.h", + "shared/rpcnterr.h", + "shared/rpcsal.h", + "shared/sdkddkver.h", + "shared/sdv_driverspecs.h", + "shared/specstrings.h", + "shared/specstrings_strict.h", + "shared/specstrings_undef.h", + "shared/stralign.h", + "shared/tvout.h", + "shared/winapifamily.h", + "shared/windef.h", + "shared/winerror.h", + "shared/winpackagefamily.h", + "shared/winsmcrd.h", + "shared/wnnc.h", + "shared/wtypes.h", + "ucrt/assert.h", + "ucrt/corecrt.h", + "ucrt/corecrt_malloc.h", + "ucrt/corecrt_memcpy_s.h", + "ucrt/corecrt_memory.h", + "ucrt/corecrt_search.h", + "ucrt/corecrt_share.h", + "ucrt/corecrt_stdio_config.h", + "ucrt/corecrt_terminate.h", + "ucrt/corecrt_wconio.h", + "ucrt/corecrt_wctype.h", + "ucrt/corecrt_wdirect.h", + "ucrt/corecrt_wio.h", + "ucrt/corecrt_wprocess.h", + "ucrt/corecrt_wstdio.h", + "ucrt/corecrt_wstdlib.h", + "ucrt/corecrt_wstring.h", + "ucrt/corecrt_wtime.h", + "ucrt/crtdbg.h", + "ucrt/ctype.h", + "ucrt/errno.h", + "ucrt/float.h", + "ucrt/inttypes.h", + "ucrt/malloc.h", + "ucrt/math.h", + "ucrt/stdio.h", + "ucrt/stdlib.h", + "ucrt/string.h", + "ucrt/sys/stat.h", + "ucrt/sys/types.h", + "ucrt/wchar.h", + "um/DbgHelp.h", + "um/PropIdl.h", + "um/PropIdlBase.h", + "um/Unknwn.h", + "um/Unknwnbase.h", + "um/WinBase.h", + "um/WinNls.h", + "um/WinUser.h", + "um/Windows.h", + "um/apiquery2.h", + "um/cguid.h", + "um/combaseapi.h", + "um/coml2api.h", + "um/commdlg.h", + "um/consoleapi.h", + "um/consoleapi2.h", + "um/consoleapi3.h", + "um/datetimeapi.h", + "um/dde.h", + "um/ddeml.h", + "um/debugapi.h", + "um/dlgs.h", + "um/dpapi.h", + "um/enclaveapi.h", + "um/errhandlingapi.h", + "um/fibersapi.h", + "um/fileapi.h", + "um/fileapifromapp.h", + "um/handleapi.h", + "um/heapapi.h", + "um/ime_cmodes.h", + "um/imm.h", + "um/interlockedapi.h", + "um/ioapiset.h", + "um/jobapi.h", + "um/jobapi2.h", + "um/joystickapi.h", + "um/libloaderapi.h", + "um/lzexpand.h", + "um/mciapi.h", + "um/mcx.h", + "um/memoryapi.h", + "um/minidumpapiset.h", + "um/minwinbase.h", + "um/mmeapi.h", + "um/mmiscapi.h", + "um/mmiscapi2.h", + "um/mmsyscom.h", + "um/mmsystem.h", + "um/msxml.h", + "um/namedpipeapi.h", + "um/namespaceapi.h", + "um/nb30.h", + "um/ncrypt.h", + "um/oaidl.h", + "um/objbase.h", + "um/objidl.h", + "um/objidlbase.h", + "um/ole2.h", + "um/oleauto.h", + "um/oleidl.h", + "um/playsoundapi.h", + "um/processenv.h", + "um/processthreadsapi.h", + "um/processtopologyapi.h", + "um/profileapi.h", + "um/prsht.h", + "um/realtimeapiset.h", + "um/reason.h", + "um/rpcnsi.h", + "um/rpcnsip.h", + "um/securityappcontainer.h", + "um/securitybaseapi.h", + "um/servprov.h", + "um/shellapi.h", + "um/stringapiset.h", + "um/synchapi.h", + "um/sysinfoapi.h", + "um/systemtopologyapi.h", + "um/threadpoolapiset.h", + "um/threadpoollegacyapiset.h", + "um/timeapi.h", + "um/timezoneapi.h", + "um/urlmon.h", + "um/utilapiset.h", + "um/verrsrc.h", + "um/wincon.h", + "um/wincontypes.h", + "um/wincrypt.h", + "um/winefs.h", + "um/wingdi.h", + "um/winioctl.h", + "um/winnetwk.h", + "um/winnt.h", + "um/winperf.h", + "um/winreg.h", + "um/winscard.h", + "um/winsock.h", + "um/winspool.h", + "um/winsvc.h", + "um/winver.h", + "um/wow64apiset.h", +] + +[sdk.headers.symlinks] +"shared/WTypesbase.h" = ["wtypesbase.h"] +"shared/driverspecs.h" = ["DriverSpecs.h"] +"shared/specstrings.h" = ["SpecStrings.h"] +"um/DbgHelp.h" = ["dbghelp.h"] +"um/PropIdl.h" = ["propidl.h"] +"um/PropIdlBase.h" = ["propidlbase.h"] +"um/Unknwn.h" = ["unknwn.h"] +"um/Unknwnbase.h" = ["unknwnbase.h"] +"um/WinBase.h" = ["winbase.h"] +"um/WinNls.h" = ["winnls.h"] +"um/WinUser.h" = ["winuser.h"] +"um/Windows.h" = ["windows.h"] + +[sdk.libs] +filter = [ + "ucrt/x86_64/ucrt.lib", + "um/x86_64/AdvAPI32.Lib", + "um/x86_64/UserEnv.Lib", + "um/x86_64/WS2_32.Lib", + "um/x86_64/bcrypt.lib", + "um/x86_64/kernel32.Lib", + "um/x86_64/ntdll.lib", +] + +[sdk.libs.symlinks] +"um/x86_64/AdvAPI32.Lib" = ["ADVAPI32.lib", "advapi32.lib"] +"um/x86_64/UserEnv.Lib" = ["USERENV.lib", "userenv.lib"] +"um/x86_64/WS2_32.Lib" = ["WS2_32.lib", "ws2_32.lib"] +"um/x86_64/bcrypt.lib" = ["BCRYPT.lib"] +"um/x86_64/kernel32.Lib" = ["KERNEL32.lib", "Kernel32.lib", "kernel32.lib"] +"um/x86_64/ntdll.lib" = ["NTDLL.lib"] diff --git a/src/ctx.rs b/src/ctx.rs index cfd62ad..edb2185 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -27,24 +27,39 @@ pub struct Ctx { impl Ctx { fn http_client(read_timeout: Option) -> Result { let mut builder = ureq::builder(); + #[cfg(feature = "native-tls")] - { - use std::env; - use std::fs::File; - use std::io::BufReader; - use std::sync::Arc; - - let mut tls_builder = native_tls_crate::TlsConnector::builder(); - if let Some(custom_ca) = - env::var_os("REQUESTS_CA_BUNDLE").or_else(|| env::var_os("CURL_CA_BUNDLE")) - { - let mut reader = BufReader::new(File::open(custom_ca)?); + 'custom: { + // "common"? env vars that people who use custom certs use? I guess + // this is easy to expand if it's not the case. /shrug + const CERT_ENVS: &[&str] = &["REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE", "SSL_CERT_FILE"]; + + let Some((env, cert_path)) = CERT_ENVS.iter().find_map(|env| { + std::env::var_os(env).map(|var| (env, std::path::PathBuf::from(var))) + }) else { + break 'custom; + }; + + fn build( + cert_path: &std::path::Path, + ) -> anyhow::Result { + let mut tls_builder = native_tls_crate::TlsConnector::builder(); + let mut reader = std::io::BufReader::new(std::fs::File::open(cert_path)?); for cert in rustls_pemfile::certs(&mut reader)? { tls_builder .add_root_certificate(native_tls_crate::Certificate::from_pem(&cert)?); } + Ok(tls_builder.build()?) } - builder = builder.tls_connector(Arc::new(tls_builder.build()?)); + + let tls_connector = build(&cert_path).with_context(|| { + format!( + "failed to add custom cert from path '{}' configured by env var '{env}'", + cert_path.display() + ) + })?; + + builder = builder.tls_connector(std::sync::Arc::new(tls_connector)); } // Allow user to specify timeout values in the case of bad/slow proxies @@ -213,43 +228,46 @@ impl Ctx { let packages = std::sync::Arc::new(packages); - let splat_roots = match &ops { - crate::Ops::Splat(config) => { - Some(crate::splat::prep_splat(self.clone(), &config.output)?) - } - crate::Ops::Minimize(config) => Some(crate::splat::prep_splat( - self.clone(), - &config.splat_output, - )?), - _ => None, - }; - let mut results = Vec::new(); let crt_ft = parking_lot::Mutex::new(None); let atl_ft = parking_lot::Mutex::new(None); let splat_config = match &ops { - crate::Ops::Splat(config) => Some(config.clone()), - crate::Ops::Minimize(config) => Some(crate::SplatConfig { - preserve_ms_arch_notation: config.preserve_ms_arch_notation, - include_debug_libs: config.include_debug_libs, - include_debug_symbols: config.include_debug_symbols, - enable_symlinks: config.enable_symlinks, - output: config.splat_output.clone(), - map: Some(config.map.clone()), - copy: config.copy, - }), + crate::Ops::Splat(config) => { + let splat_roots = crate::splat::prep_splat(self.clone(), &config.output)?; + let mut config = config.clone(); + config.output = splat_roots.root.clone(); + + Some((splat_roots, config)) + } + crate::Ops::Minimize(config) => { + let splat_roots = crate::splat::prep_splat(self.clone(), &config.splat_output)?; + + let config = crate::SplatConfig { + preserve_ms_arch_notation: config.preserve_ms_arch_notation, + include_debug_libs: config.include_debug_libs, + include_debug_symbols: config.include_debug_symbols, + enable_symlinks: config.enable_symlinks, + output: splat_roots.root.clone(), + map: Some(config.map.clone()), + copy: config.copy, + }; + + Some((splat_roots, config)) + } _ => None, }; - let map = if let Some(map) = splat_config.as_ref().and_then(|sp| sp.map.as_ref()) { + let map = if let Some(map) = splat_config.as_ref().and_then(|(_, sp)| sp.map.as_ref()) { match std::fs::read_to_string(map) { Ok(m) => Some( toml::from_str::(&m) .with_context(|| format!("failed to deserialize '{map}'"))?, ), Err(err) => { - tracing::error!("unable to read mapping from '{map}': {err}"); + if !matches!(err.kind(), std::io::ErrorKind::NotFound) { + tracing::error!("unable to read mapping from '{map}': {err}"); + } None } } @@ -273,10 +291,10 @@ impl Ctx { return Ok(None); } - let sdk_headers = if let Some(config) = &splat_config { + let sdk_headers = if let Some((splat_roots, config)) = &splat_config { crate::splat::splat( config, - splat_roots.as_ref().unwrap(), + splat_roots, &wi, &ft, map.as_ref() @@ -303,61 +321,63 @@ impl Ctx { let sdk_headers = results.into_iter().collect::, _>>()?; let sdk_headers = sdk_headers.into_iter().flatten().collect(); - if let Some(roots) = splat_roots { - let splat_links = |enable_symlinks: bool| -> anyhow::Result<()> { - if enable_symlinks { - let crt_ft = crt_ft.lock().take(); - let atl_ft = atl_ft.lock().take(); + let Some(roots) = splat_config.map(|(sr, _)| sr) else { + return Ok(()); + }; - crate::splat::finalize_splat(&self, &roots, sdk_headers, crt_ft, atl_ft)?; - } + let splat_links = |enable_symlinks: bool| -> anyhow::Result<()> { + if enable_symlinks { + let crt_ft = crt_ft.lock().take(); + let atl_ft = atl_ft.lock().take(); - Ok(()) - }; + crate::splat::finalize_splat(&self, &roots, sdk_headers, crt_ft, atl_ft)?; + } - match ops { - crate::Ops::Minimize(config) => { - splat_links(config.enable_symlinks)?; - let results = crate::minimize::minimize(self, config, roots)?; - - fn emit(name: &str, num: crate::minimize::FileNumbers) { - fn hb(bytes: u64) -> String { - let mut bytes = bytes as f64; - - for unit in ["B", "KiB", "MiB", "GiB"] { - if bytes > 1024.0 { - bytes /= 1024.0; - } else { - return format!("{bytes:.1}{unit}"); - } - } + Ok(()) + }; - "this seems bad".to_owned() - } + match ops { + crate::Ops::Minimize(config) => { + splat_links(config.enable_symlinks)?; + let results = crate::minimize::minimize(self, config, roots, &sdk_version)?; - let ratio = (num.used.bytes as f64 / num.total.bytes as f64) * 100.0; + fn emit(name: &str, num: crate::minimize::FileNumbers) { + fn hb(bytes: u64) -> String { + let mut bytes = bytes as f64; - println!( - " {name}: {}({}) / {}({}) => {ratio:.02}%", - num.used.count, - hb(num.used.bytes), - num.total.count, - hb(num.total.bytes), - ); + for unit in ["B", "KiB", "MiB", "GiB"] { + if bytes > 1024.0 { + bytes /= 1024.0; + } else { + return format!("{bytes:.1}{unit}"); + } + } + + "this seems bad".to_owned() } - emit("crt headers", results.crt_headers); - emit("crt libs", results.crt_libs); - emit("sdk headers", results.sdk_headers); - emit("sdk libs", results.sdk_libs); + let ratio = (num.used.bytes as f64 / num.total.bytes as f64) * 100.0; + + println!( + " {name}: {}({}) / {}({}) => {ratio:.02}%", + num.used.count, + hb(num.used.bytes), + num.total.count, + hb(num.total.bytes), + ); } - crate::Ops::Splat(config) => { - if map.is_none() { - splat_links(config.enable_symlinks)?; - } + + emit("crt headers", results.crt_headers); + emit("crt libs", results.crt_libs); + emit("sdk headers", results.sdk_headers); + emit("sdk libs", results.sdk_libs); + } + crate::Ops::Splat(config) => { + if map.is_none() { + splat_links(config.enable_symlinks)?; } - _ => {} } + _ => {} } Ok(()) diff --git a/src/lib.rs b/src/lib.rs index e371654..7647acb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,10 @@ use anyhow::{Context as _, Error}; pub use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf}; -use std::{collections::BTreeMap, fmt}; +use std::{ + collections::{BTreeMap, BTreeSet}, + fmt, +}; mod ctx; mod download; @@ -688,10 +691,51 @@ fn get_sdk( #[derive(serde::Serialize, serde::Deserialize, Default)] pub struct Map { - #[serde(default)] - pub filter: std::collections::BTreeSet, - #[serde(default)] - pub symlinks: std::collections::BTreeMap>, + pub crt: Block, + pub sdk: Block, +} + +impl Map { + fn clear(&mut self) { + self.crt.clear(); + self.sdk.clear(); + } +} + +#[derive(serde::Serialize, serde::Deserialize, Default)] +pub struct Block { + pub headers: Section, + pub libs: Section, +} + +impl Block { + fn clear(&mut self) { + self.headers.clear(); + self.libs.clear(); + } +} + +#[derive(Copy, Clone)] +pub enum SectionKind { + CrtHeader, + CrtLib, + SdkHeader, + SdkLib, +} + +#[derive(serde::Serialize, serde::Deserialize, Default)] +pub struct Section { + #[serde(default, skip_serializing_if = "BTreeSet::is_empty")] + pub filter: BTreeSet, + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub symlinks: BTreeMap>, +} + +impl Section { + fn clear(&mut self) { + self.filter.clear(); + self.symlinks.clear(); + } } #[cfg(unix)] diff --git a/src/main.rs b/src/main.rs index f6043c7..c3c3357 100644 --- a/src/main.rs +++ b/src/main.rs @@ -106,13 +106,15 @@ pub enum Command { /// The path of the filter file that is generated. Defaults to ./.xwin-cache/xwin-map.toml #[arg(long)] map: Option, - /// The root output directory. Defaults to `./.xwin-cache/splat` if not + /// The root splat output directory. Defaults to `./.xwin-cache/splat` if not /// specified. #[arg(long)] - splat_output: Option, - /// The root output directory. - #[arg(long)] output: Option, + /// The root output directory for the minimized set of files discovered during + /// the build. If not specified only the map file is written in addition + /// to the splat. + #[arg(long)] + minimize_output: Option, /// Copies files from the splat directory rather than moving them. Only /// used if --output is specified. #[arg(long)] @@ -311,7 +313,7 @@ fn main() -> Result<(), Error> { map, output, copy, - splat_output, + minimize_output, options, target, manifest_path, @@ -321,9 +323,9 @@ fn main() -> Result<(), Error> { include_debug_symbols: options.include_debug_symbols, enable_symlinks: !options.disable_symlinks, preserve_ms_arch_notation: options.preserve_ms_arch_notation, - splat_output: splat_output.unwrap_or_else(|| ctx.work_dir.join("splat")), + splat_output: output.unwrap_or_else(|| ctx.work_dir.join("splat")), copy, - output, + minimize_output, map: map.unwrap_or_else(|| ctx.work_dir.join("xwin-map.toml")), target: target.unwrap_or("x86_64-pc-windows-msvc".to_owned()), manifest_path: manifest_path.unwrap_or("Cargo.toml".into()), diff --git a/src/minimize.rs b/src/minimize.rs index c329e4b..f42d7ad 100644 --- a/src/minimize.rs +++ b/src/minimize.rs @@ -1,4 +1,4 @@ -use crate::{Ctx, Path, PathBuf}; +use crate::{util::canonicalize, Ctx, Path, PathBuf, SectionKind}; use anyhow::Context as _; pub struct MinimizeConfig { @@ -8,7 +8,7 @@ pub struct MinimizeConfig { pub preserve_ms_arch_notation: bool, pub splat_output: PathBuf, pub copy: bool, - pub output: Option, + pub minimize_output: Option, pub map: PathBuf, pub target: String, pub manifest_path: PathBuf, @@ -39,15 +39,12 @@ pub(crate) fn minimize( _ctx: std::sync::Arc, config: MinimizeConfig, roots: crate::splat::SplatRoots, + sdk_version: &str, ) -> anyhow::Result { - let mut used_paths: std::collections::BTreeMap> = - std::collections::BTreeMap::new(); - - #[inline] - fn canonicalize(path: &Path) -> anyhow::Result { - PathBuf::from_path_buf(path.canonicalize().context("unable to canonicalize path")?) - .map_err(|pb| anyhow::anyhow!("canonicalized path {} is not utf-8", pb.display())) - } + let mut used_paths: std::collections::BTreeMap< + PathBuf, + (SectionKind, std::collections::BTreeSet), + > = std::collections::BTreeMap::new(); let (used, total) = rayon::join( || -> anyhow::Result<_> { @@ -104,11 +101,13 @@ pub(crate) fn minimize( let mut libs = format!("-C linker=lld-link -Lnative={splat_root}/crt/lib/x86_64 -Lnative={splat_root}/sdk/lib/um/x86_64 -Lnative={splat_root}/sdk/lib/ucrt/x86_64"); - // Sigh, some people use RUSTFLAGS to enable hidden library features, incredibly annoying - if let Ok(rf) = std::env::var(format!( + let rust_flags_env = format!( "CARGO_TARGET_{}_RUSTFLAGS", config.target.replace('-', "_").to_uppercase() - )) { + ); + + // Sigh, some people use RUSTFLAGS to enable hidden library features, incredibly annoying + if let Ok(rf) = std::env::var(&rust_flags_env) { libs.push(' '); libs.push_str(&rf); } else if let Ok(rf) = std::env::var("RUSTFLAGS") { @@ -124,7 +123,7 @@ pub(crate) fn minimize( (format!("AR_{triple}"), "llvm-lib"), (format!("CFLAGS_{triple}"), &includes), (format!("CXXFLAGS_{triple}"), &includes), - ("RUSTFLAGS".to_owned(), &libs), + (rust_flags_env, &libs), ]; strace.envs(cc_env); @@ -237,23 +236,37 @@ pub(crate) fn minimize( while let Ok(path) = rx.recv() { let path = PathBuf::from(path); - let (hdrs, libs) = if path.starts_with(&sdk_root) { - (&mut sdk_headers, &mut sdk_libs) + let (hdrs, libs, is_sdk) = if path.starts_with(&sdk_root) { + (&mut sdk_headers, &mut sdk_libs, true) } else if path.starts_with(&crt_root) { - (&mut crt_headers, &mut crt_libs) + (&mut crt_headers, &mut crt_libs, false) } else { continue; }; - let counts = match path.extension() { + let (counts, which) = match path.extension() { // Some headers don't have extensions, eg ciso646 - Some("h" | "hpp") | None => hdrs, - Some("lib" | "Lib") => libs, + Some("h" | "hpp") | None => ( + hdrs, + if is_sdk { + SectionKind::SdkHeader + } else { + SectionKind::CrtHeader + }, + ), + Some("lib" | "Lib") => ( + libs, + if is_sdk { + SectionKind::SdkLib + } else { + SectionKind::CrtLib + }, + ), _ => continue, }; let mut insert = |path: PathBuf, symlink: Option| { - if let Some(sls) = used_paths.get_mut(&path) { + if let Some((_, sls)) = used_paths.get_mut(&path) { sls.extend(symlink); return; } @@ -275,7 +288,11 @@ pub(crate) fn minimize( counts.bytes += md.len(); counts.count += 1; - used_paths.entry(path).or_default().extend(symlink); + used_paths + .entry(path) + .or_insert_with(|| (which, Default::default())) + .1 + .extend(symlink); }; if path.is_symlink() { @@ -374,7 +391,7 @@ pub(crate) fn minimize( // all the symlinks from which they are rereferenced, so just be conservative // and add all of them for (p, sls) in symlinks { - if let Some(symlinks) = used_paths.get_mut(&p) { + if let Some((_, symlinks)) = used_paths.get_mut(&p) { let before = symlinks.len(); symlinks.extend(sls); additional_symlinks += symlinks.len() - before; @@ -383,8 +400,8 @@ pub(crate) fn minimize( tracing::info!("added {additional_symlinks} additional symlinks"); - let (_, mv) = rayon::join( - || { + let (serialize, mv) = rayon::join( + || -> anyhow::Result<()> { let cur_map = if config.map.exists() { match std::fs::read_to_string(&config.map) { Ok(contents) => match toml::from_str::(&contents) { @@ -418,22 +435,43 @@ pub(crate) fn minimize( // actually using any longer, if this file is in source control then // they can just revert the changes if a file that was previously in // the list was removed - map.filter.clear(); - map.symlinks.clear(); - - map.filter.extend(used_paths.keys().map(|p| { - let path = p.strip_prefix(&root).unwrap().as_str().to_owned(); - path - })); - map.symlinks - .extend(used_paths.iter().filter_map(|(p, sls)| { - if sls.is_empty() { - return None; - } + map.clear(); + + let crt_hdr_prefix = roots.crt.join("include"); + let crt_lib_prefix = roots.crt.join("lib"); + let sdk_hdr_prefix = { + let mut sp = roots.sdk.clone(); + sp.push("Include"); + sp.push(sdk_version); + sp + }; + let sdk_lib_prefix = roots.sdk.join("lib"); + + for (p, (which, sls)) in &used_paths { + let (prefix, section) = match which { + SectionKind::SdkHeader => (&sdk_hdr_prefix, &mut map.sdk.headers), + SectionKind::SdkLib => (&sdk_lib_prefix, &mut map.sdk.libs), + SectionKind::CrtHeader => (&crt_hdr_prefix, &mut map.crt.headers), + SectionKind::CrtLib => (&crt_lib_prefix, &mut map.crt.libs), + }; + + let path = p + .strip_prefix(prefix) + .with_context(|| { + format!("path {p} did not begin with expected prefix {prefix}") + }) + .unwrap() + .as_str() + .to_owned(); + + if sls.is_empty() { + section.filter.insert(path); + continue; + } - let path = p.strip_prefix(&root).unwrap().as_str().to_owned(); - Some((path, sls.iter().cloned().collect())) - })); + section.filter.insert(path.clone()); + section.symlinks.insert(path, sls.iter().cloned().collect()); + } let serialized = toml::to_string_pretty(&map).unwrap(); @@ -444,9 +482,11 @@ pub(crate) fn minimize( "failed to write map file" ); } + + Ok(()) }, || -> anyhow::Result<()> { - let Some(od) = config.output else { + let Some(od) = config.minimize_output else { return Ok(()); }; @@ -471,7 +511,7 @@ pub(crate) fn minimize( Ok(np) }; - for (up, sls) in &used_paths { + for (up, (_, sls)) in &used_paths { let np = mv(up)?; for sl in sls { @@ -485,6 +525,7 @@ pub(crate) fn minimize( }, ); + serialize?; mv?; Ok(MinimizeResults { diff --git a/src/splat.rs b/src/splat.rs index 935f25e..7ad3f7d 100644 --- a/src/splat.rs +++ b/src/splat.rs @@ -1,4 +1,4 @@ -use crate::{symlink, Arch, Ctx, Error, Path, PathBuf, PayloadKind, Variant}; +use crate::{symlink, Arch, Ctx, Error, Path, PathBuf, PayloadKind, SectionKind, Variant}; use anyhow::Context as _; use rayon::prelude::*; use std::collections::BTreeMap; @@ -52,6 +52,13 @@ pub(crate) struct SplatRoots { } pub(crate) fn prep_splat(ctx: std::sync::Arc, root: &Path) -> Result { + // Ensure we create the path first, you can't canonicalize a non-existant path + if !root.exists() { + std::fs::create_dir_all(root) + .with_context(|| format!("unable to create splat directory {root}"))?; + } + + let root = crate::util::canonicalize(root)?; let crt_root = root.join("crt"); let sdk_root = root.join("sdk"); @@ -73,7 +80,7 @@ pub(crate) fn prep_splat(ctx: std::sync::Arc, root: &Path) -> Result, + section: SectionKind, } let mut src = roots.src.join(&item.payload.filename); @@ -146,6 +154,7 @@ pub(crate) fn splat( tree, kind, variant, + section: SectionKind::CrtHeader, }] } PayloadKind::AtlLibs => { @@ -174,6 +183,7 @@ pub(crate) fn splat( tree, kind, variant, + section: SectionKind::CrtLib, }] } @@ -223,6 +233,7 @@ pub(crate) fn splat( tree, kind, variant, + section: SectionKind::CrtLib, }] } PayloadKind::SdkHeaders => { @@ -244,6 +255,7 @@ pub(crate) fn splat( tree, kind, variant, + section: SectionKind::SdkHeader, }] } PayloadKind::SdkLibs => { @@ -266,6 +278,7 @@ pub(crate) fn splat( tree, kind, variant, + section: SectionKind::SdkLib, }] } PayloadKind::SdkStoreLibs => { @@ -287,6 +300,7 @@ pub(crate) fn splat( tree, kind, variant, + section: SectionKind::SdkLib, }) }) .collect::, _>>()? @@ -311,6 +325,7 @@ pub(crate) fn splat( tree, kind, variant, + section: SectionKind::SdkHeader, }]; src.push("lib/ucrt"); @@ -329,6 +344,7 @@ pub(crate) fn splat( tree, kind, variant, + section: SectionKind::SdkLib, }); } @@ -353,7 +369,32 @@ pub(crate) fn splat( mappings .into_par_iter() .map(|mapping| -> Result, Error> { - //let rel_root = mapping.target.strip_prefix(&roots.root).unwrap(); + let (prefix, section) = match mapping.section { + SectionKind::SdkHeader => { + // All ucrt headers are in the ucrt subdir, but we have a flat + // list in the mapping file, so we need to drop that from the prefix + // so they match like all the other paths + + ( + if matches!(mapping.kind, PayloadKind::Ucrt) { + mapping.target.parent().unwrap().to_owned() + } else { + mapping.target.clone() + }, + &map.sdk.headers, + ) + } + SectionKind::SdkLib => (roots.sdk.join("lib"), &map.sdk.libs), + SectionKind::CrtHeader => (mapping.target.clone(), &map.crt.headers), + SectionKind::CrtLib => { + ( + // Pop the arch directory, it's part of the prefix in + // the filter + mapping.target.parent().unwrap().to_owned(), + &map.crt.libs, + ) + } + }; let mut dir_stack = vec![Dir { src: mapping.src, @@ -371,41 +412,38 @@ pub(crate) fn splat( tar.push(fname); - let unprefixed = tar - .strip_prefix(&roots.root) - .with_context(|| format!("invalid path {tar}"))?; + let unprefixed = tar.strip_prefix(&prefix).with_context(|| { + format!("invalid path {tar}: doesn't begin with prefix {prefix}") + })?; - // if kind == PayloadKind::Ucrt { - // dbg!(&roots.root, &tar, unprefixed); - // } + if !section.filter.contains(unprefixed.as_str()) { + tar.pop(); + continue; + } - if map.filter.contains(unprefixed.as_str()) { - let src_path = src.join(fname); + let src_path = src.join(fname); - if !created_dir { - std::fs::create_dir_all(tar.parent().unwrap()) - .with_context(|| format!("unable to create {tar}"))?; - created_dir = true; - } + if !created_dir { + std::fs::create_dir_all(tar.parent().unwrap()) + .with_context(|| format!("unable to create {tar}"))?; + created_dir = true; + } - if config.copy { - std::fs::copy(&src_path, &tar).with_context(|| { - format!("failed to copy {src_path} to {tar}") - })?; - } else { - std::fs::rename(&src_path, &tar).with_context(|| { - format!("failed to move {src_path} to {tar}") - })?; - } + if config.copy { + std::fs::copy(&src_path, &tar) + .with_context(|| format!("failed to copy {src_path} to {tar}"))?; + } else { + std::fs::rename(&src_path, &tar) + .with_context(|| format!("failed to move {src_path} to {tar}"))?; + } - // Create any associated symlinks, these are always going to be symlinks - // in the same target directory - if let Some(symlinks) = map.symlinks.get(unprefixed.as_str()) { - for sl in symlinks { - tar.pop(); - tar.push(sl); - symlink(fname.as_str(), &tar)?; - } + // Create any associated symlinks, these are always going to be symlinks + // in the same target directory + if let Some(symlinks) = section.symlinks.get(unprefixed.as_str()) { + for sl in symlinks { + tar.pop(); + tar.push(sl); + symlink(fname.as_str(), &tar)?; } } diff --git a/src/util.rs b/src/util.rs index 04f636a..be46443 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,16 @@ -use anyhow::Error; +use crate::{Path, PathBuf}; +use anyhow::{Context as _, Error}; use std::fmt; +#[inline] +pub fn canonicalize(path: &Path) -> anyhow::Result { + PathBuf::from_path_buf( + path.canonicalize() + .with_context(|| format!("unable to canonicalize path '{path}'"))?, + ) + .map_err(|pb| anyhow::anyhow!("canonicalized path {} is not utf-8", pb.display())) +} + #[derive(Copy, Clone)] pub enum ProgressTarget { Stdout, diff --git a/tests/compiles.rs b/tests/compiles.rs index 4638c89..8e79277 100644 --- a/tests/compiles.rs +++ b/tests/compiles.rs @@ -50,8 +50,6 @@ fn verify_compiles() { output: output_dir.clone(), }); - let output_dir = xwin::PathBuf::from_path_buf(output_dir.canonicalize().unwrap()).unwrap(); - ctx.execute( pkg_manifest.packages, pruned @@ -82,8 +80,10 @@ fn verify_compiles() { "tests/xwin-test/Cargo.toml", ]); - let includes = format!("-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc{0}/crt/include /imsvc{0}/sdk/include/ucrt /imsvc{0}/sdk/include/um /imsvc{0}/sdk/include/shared", output_dir); - let libs = format!("-C linker=lld-link -Lnative={0}/crt/lib/x86_64 -Lnative={0}/sdk/lib/um/x86_64 -Lnative={0}/sdk/lib/ucrt/x86_64", output_dir); + let od = xwin::util::canonicalize(&output_dir).unwrap(); + + let includes = format!("-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc{od}/crt/include /imsvc{od}/sdk/include/ucrt /imsvc{od}/sdk/include/um /imsvc{od}/sdk/include/shared"); + let libs = format!("-C linker=lld-link -Lnative={od}/crt/lib/x86_64 -Lnative={od}/sdk/lib/um/x86_64 -Lnative={od}/sdk/lib/ucrt/x86_64"); let cc_env = [ ("CC_x86_64_pc_windows_msvc", "clang-cl"), @@ -117,10 +117,9 @@ fn verify_compiles() { ]); let includes = format!( - "-Wno-unused-command-line-argument -fuse-ld=lld-link /vctoolsdir {0}/crt /winsdkdir {0}/sdk", - output_dir + "-Wno-unused-command-line-argument -fuse-ld=lld-link /vctoolsdir {od}/crt /winsdkdir {od}/sdk" ); - let libs = format!("-C linker=lld-link -Lnative={0}/crt/lib/x86_64 -Lnative={0}/sdk/lib/um/x86_64 -Lnative={0}/sdk/lib/ucrt/x86_64", output_dir); + let libs = format!("-C linker=lld-link -Lnative={od}/crt/lib/x86_64 -Lnative={od}/sdk/lib/um/x86_64 -Lnative={od}/sdk/lib/ucrt/x86_64"); let cc_env = [ ("CC_x86_64_pc_windows_msvc", "clang-cl"), @@ -196,12 +195,10 @@ fn verify_compiles_minimized() { splat_output: output_dir.clone(), manifest_path: "tests/xwin-test/Cargo.toml".into(), target: "x86_64-pc-windows-msvc".into(), - output: Some(filtered.clone()), + minimize_output: Some(filtered.clone()), preserve_strace: false, }); - let output_dir = xwin::PathBuf::from_path_buf(filtered.canonicalize().unwrap()).unwrap(); - ctx.execute( pkg_manifest.packages, pruned @@ -234,11 +231,12 @@ fn verify_compiles_minimized() { "tests/xwin-test/Cargo.toml", ]); + let od = xwin::util::canonicalize(&filtered).unwrap(); + let includes = format!( - "-Wno-unused-command-line-argument -fuse-ld=lld-link /vctoolsdir {0}/crt /winsdkdir {0}/sdk", - output_dir + "-Wno-unused-command-line-argument -fuse-ld=lld-link /vctoolsdir {od}/crt /winsdkdir {od}/sdk" ); - let libs = format!("-C linker=lld-link -Lnative={0}/crt/lib/x86_64 -Lnative={0}/sdk/lib/um/x86_64 -Lnative={0}/sdk/lib/ucrt/x86_64", output_dir); + let libs = format!("-C linker=lld-link -Lnative={od}/crt/lib/x86_64 -Lnative={od}/sdk/lib/um/x86_64 -Lnative={od}/sdk/lib/ucrt/x86_64"); let cc_env = [ ("CC_x86_64_pc_windows_msvc", "clang-cl"), diff --git a/tests/deterministic.rs b/tests/deterministic.rs index afb82ec..8d926bf 100644 --- a/tests/deterministic.rs +++ b/tests/deterministic.rs @@ -44,8 +44,6 @@ fn verify_deterministic() { output: output_dir.clone(), }); - let output_dir = PathBuf::from_path_buf(output_dir.canonicalize().unwrap()).unwrap(); - ctx.execute( pkg_manifest.packages, pruned @@ -92,6 +90,7 @@ fn verify_deterministic() { hash: u64, } + let output_dir = xwin::util::canonicalize(&output_dir).unwrap(); let mut files: Vec<_> = walkdir::WalkDir::new(&output_dir) .sort_by_file_name() .into_iter() diff --git a/tests/snapshots/compiles__verify_compiles_minimized.snap b/tests/snapshots/compiles__verify_compiles_minimized.snap index 869270c..9f298f1 100644 --- a/tests/snapshots/compiles__verify_compiles_minimized.snap +++ b/tests/snapshots/compiles__verify_compiles_minimized.snap @@ -2,267 +2,284 @@ source: tests/compiles.rs expression: "std::fs::read_to_string(map_path).unwrap()" --- +[crt.headers] filter = [ - "crt/include/__msvc_iter_core.hpp", - "crt/include/__msvc_sanitizer_annotate_container.hpp", - "crt/include/algorithm", - "crt/include/cassert", - "crt/include/cctype", - "crt/include/cfloat", - "crt/include/climits", - "crt/include/concurrencysal.h", - "crt/include/crtdefs.h", - "crt/include/cstddef", - "crt/include/cstdint", - "crt/include/cstdio", - "crt/include/cstdlib", - "crt/include/cstring", - "crt/include/cwchar", - "crt/include/eh.h", - "crt/include/exception", - "crt/include/excpt.h", - "crt/include/initializer_list", - "crt/include/iosfwd", - "crt/include/isa_availability.h", - "crt/include/limits", - "crt/include/limits.h", - "crt/include/list", - "crt/include/new", - "crt/include/sal.h", - "crt/include/setjmp.h", - "crt/include/stdint.h", - "crt/include/string", - "crt/include/type_traits", - "crt/include/use_ansi.h", - "crt/include/utility", - "crt/include/vadefs.h", - "crt/include/vcruntime.h", - "crt/include/vcruntime_exception.h", - "crt/include/vcruntime_new.h", - "crt/include/vcruntime_new_debug.h", - "crt/include/vcruntime_string.h", - "crt/include/vector", - "crt/include/xatomic.h", - "crt/include/xkeycheck.h", - "crt/include/xmemory", - "crt/include/xstring", - "crt/include/xtr1common", - "crt/include/xutility", - "crt/include/yvals.h", - "crt/include/yvals_core.h", - "crt/lib/x86_64/msvcrt.lib", - "crt/lib/x86_64/vcruntime.lib", - "sdk/Include/10.0.22621/shared/WTypesbase.h", - "sdk/Include/10.0.22621/shared/apiset.h", - "sdk/Include/10.0.22621/shared/apisetcconv.h", - "sdk/Include/10.0.22621/shared/basetsd.h", - "sdk/Include/10.0.22621/shared/bcrypt.h", - "sdk/Include/10.0.22621/shared/cderr.h", - "sdk/Include/10.0.22621/shared/driverspecs.h", - "sdk/Include/10.0.22621/shared/guiddef.h", - "sdk/Include/10.0.22621/shared/inaddr.h", - "sdk/Include/10.0.22621/shared/kernelspecs.h", - "sdk/Include/10.0.22621/shared/ktmtypes.h", - "sdk/Include/10.0.22621/shared/minwindef.h", - "sdk/Include/10.0.22621/shared/poppack.h", - "sdk/Include/10.0.22621/shared/pshpack1.h", - "sdk/Include/10.0.22621/shared/pshpack2.h", - "sdk/Include/10.0.22621/shared/pshpack4.h", - "sdk/Include/10.0.22621/shared/pshpack8.h", - "sdk/Include/10.0.22621/shared/rpc.h", - "sdk/Include/10.0.22621/shared/rpcasync.h", - "sdk/Include/10.0.22621/shared/rpcdce.h", - "sdk/Include/10.0.22621/shared/rpcdcep.h", - "sdk/Include/10.0.22621/shared/rpcndr.h", - "sdk/Include/10.0.22621/shared/rpcnterr.h", - "sdk/Include/10.0.22621/shared/rpcsal.h", - "sdk/Include/10.0.22621/shared/sdkddkver.h", - "sdk/Include/10.0.22621/shared/sdv_driverspecs.h", - "sdk/Include/10.0.22621/shared/specstrings.h", - "sdk/Include/10.0.22621/shared/specstrings_strict.h", - "sdk/Include/10.0.22621/shared/specstrings_undef.h", - "sdk/Include/10.0.22621/shared/stralign.h", - "sdk/Include/10.0.22621/shared/tvout.h", - "sdk/Include/10.0.22621/shared/winapifamily.h", - "sdk/Include/10.0.22621/shared/windef.h", - "sdk/Include/10.0.22621/shared/winerror.h", - "sdk/Include/10.0.22621/shared/winpackagefamily.h", - "sdk/Include/10.0.22621/shared/winsmcrd.h", - "sdk/Include/10.0.22621/shared/wnnc.h", - "sdk/Include/10.0.22621/shared/wtypes.h", - "sdk/Include/10.0.22621/ucrt/assert.h", - "sdk/Include/10.0.22621/ucrt/corecrt.h", - "sdk/Include/10.0.22621/ucrt/corecrt_malloc.h", - "sdk/Include/10.0.22621/ucrt/corecrt_memcpy_s.h", - "sdk/Include/10.0.22621/ucrt/corecrt_memory.h", - "sdk/Include/10.0.22621/ucrt/corecrt_search.h", - "sdk/Include/10.0.22621/ucrt/corecrt_share.h", - "sdk/Include/10.0.22621/ucrt/corecrt_stdio_config.h", - "sdk/Include/10.0.22621/ucrt/corecrt_terminate.h", - "sdk/Include/10.0.22621/ucrt/corecrt_wconio.h", - "sdk/Include/10.0.22621/ucrt/corecrt_wctype.h", - "sdk/Include/10.0.22621/ucrt/corecrt_wdirect.h", - "sdk/Include/10.0.22621/ucrt/corecrt_wio.h", - "sdk/Include/10.0.22621/ucrt/corecrt_wprocess.h", - "sdk/Include/10.0.22621/ucrt/corecrt_wstdio.h", - "sdk/Include/10.0.22621/ucrt/corecrt_wstdlib.h", - "sdk/Include/10.0.22621/ucrt/corecrt_wstring.h", - "sdk/Include/10.0.22621/ucrt/corecrt_wtime.h", - "sdk/Include/10.0.22621/ucrt/crtdbg.h", - "sdk/Include/10.0.22621/ucrt/ctype.h", - "sdk/Include/10.0.22621/ucrt/errno.h", - "sdk/Include/10.0.22621/ucrt/float.h", - "sdk/Include/10.0.22621/ucrt/inttypes.h", - "sdk/Include/10.0.22621/ucrt/malloc.h", - "sdk/Include/10.0.22621/ucrt/math.h", - "sdk/Include/10.0.22621/ucrt/stdio.h", - "sdk/Include/10.0.22621/ucrt/stdlib.h", - "sdk/Include/10.0.22621/ucrt/string.h", - "sdk/Include/10.0.22621/ucrt/sys/stat.h", - "sdk/Include/10.0.22621/ucrt/sys/types.h", - "sdk/Include/10.0.22621/ucrt/wchar.h", - "sdk/Include/10.0.22621/um/DbgHelp.h", - "sdk/Include/10.0.22621/um/PropIdl.h", - "sdk/Include/10.0.22621/um/PropIdlBase.h", - "sdk/Include/10.0.22621/um/Unknwn.h", - "sdk/Include/10.0.22621/um/Unknwnbase.h", - "sdk/Include/10.0.22621/um/WinBase.h", - "sdk/Include/10.0.22621/um/WinNls.h", - "sdk/Include/10.0.22621/um/WinUser.h", - "sdk/Include/10.0.22621/um/Windows.h", - "sdk/Include/10.0.22621/um/apiquery2.h", - "sdk/Include/10.0.22621/um/cguid.h", - "sdk/Include/10.0.22621/um/combaseapi.h", - "sdk/Include/10.0.22621/um/coml2api.h", - "sdk/Include/10.0.22621/um/commdlg.h", - "sdk/Include/10.0.22621/um/consoleapi.h", - "sdk/Include/10.0.22621/um/consoleapi2.h", - "sdk/Include/10.0.22621/um/consoleapi3.h", - "sdk/Include/10.0.22621/um/datetimeapi.h", - "sdk/Include/10.0.22621/um/dde.h", - "sdk/Include/10.0.22621/um/ddeml.h", - "sdk/Include/10.0.22621/um/debugapi.h", - "sdk/Include/10.0.22621/um/dlgs.h", - "sdk/Include/10.0.22621/um/dpapi.h", - "sdk/Include/10.0.22621/um/enclaveapi.h", - "sdk/Include/10.0.22621/um/errhandlingapi.h", - "sdk/Include/10.0.22621/um/fibersapi.h", - "sdk/Include/10.0.22621/um/fileapi.h", - "sdk/Include/10.0.22621/um/fileapifromapp.h", - "sdk/Include/10.0.22621/um/handleapi.h", - "sdk/Include/10.0.22621/um/heapapi.h", - "sdk/Include/10.0.22621/um/ime_cmodes.h", - "sdk/Include/10.0.22621/um/imm.h", - "sdk/Include/10.0.22621/um/interlockedapi.h", - "sdk/Include/10.0.22621/um/ioapiset.h", - "sdk/Include/10.0.22621/um/jobapi.h", - "sdk/Include/10.0.22621/um/jobapi2.h", - "sdk/Include/10.0.22621/um/joystickapi.h", - "sdk/Include/10.0.22621/um/libloaderapi.h", - "sdk/Include/10.0.22621/um/lzexpand.h", - "sdk/Include/10.0.22621/um/mciapi.h", - "sdk/Include/10.0.22621/um/mcx.h", - "sdk/Include/10.0.22621/um/memoryapi.h", - "sdk/Include/10.0.22621/um/minidumpapiset.h", - "sdk/Include/10.0.22621/um/minwinbase.h", - "sdk/Include/10.0.22621/um/mmeapi.h", - "sdk/Include/10.0.22621/um/mmiscapi.h", - "sdk/Include/10.0.22621/um/mmiscapi2.h", - "sdk/Include/10.0.22621/um/mmsyscom.h", - "sdk/Include/10.0.22621/um/mmsystem.h", - "sdk/Include/10.0.22621/um/msxml.h", - "sdk/Include/10.0.22621/um/namedpipeapi.h", - "sdk/Include/10.0.22621/um/namespaceapi.h", - "sdk/Include/10.0.22621/um/nb30.h", - "sdk/Include/10.0.22621/um/ncrypt.h", - "sdk/Include/10.0.22621/um/oaidl.h", - "sdk/Include/10.0.22621/um/objbase.h", - "sdk/Include/10.0.22621/um/objidl.h", - "sdk/Include/10.0.22621/um/objidlbase.h", - "sdk/Include/10.0.22621/um/ole2.h", - "sdk/Include/10.0.22621/um/oleauto.h", - "sdk/Include/10.0.22621/um/oleidl.h", - "sdk/Include/10.0.22621/um/playsoundapi.h", - "sdk/Include/10.0.22621/um/processenv.h", - "sdk/Include/10.0.22621/um/processthreadsapi.h", - "sdk/Include/10.0.22621/um/processtopologyapi.h", - "sdk/Include/10.0.22621/um/profileapi.h", - "sdk/Include/10.0.22621/um/prsht.h", - "sdk/Include/10.0.22621/um/realtimeapiset.h", - "sdk/Include/10.0.22621/um/reason.h", - "sdk/Include/10.0.22621/um/rpcnsi.h", - "sdk/Include/10.0.22621/um/rpcnsip.h", - "sdk/Include/10.0.22621/um/securityappcontainer.h", - "sdk/Include/10.0.22621/um/securitybaseapi.h", - "sdk/Include/10.0.22621/um/servprov.h", - "sdk/Include/10.0.22621/um/shellapi.h", - "sdk/Include/10.0.22621/um/stringapiset.h", - "sdk/Include/10.0.22621/um/synchapi.h", - "sdk/Include/10.0.22621/um/sysinfoapi.h", - "sdk/Include/10.0.22621/um/systemtopologyapi.h", - "sdk/Include/10.0.22621/um/threadpoolapiset.h", - "sdk/Include/10.0.22621/um/threadpoollegacyapiset.h", - "sdk/Include/10.0.22621/um/timeapi.h", - "sdk/Include/10.0.22621/um/timezoneapi.h", - "sdk/Include/10.0.22621/um/urlmon.h", - "sdk/Include/10.0.22621/um/utilapiset.h", - "sdk/Include/10.0.22621/um/verrsrc.h", - "sdk/Include/10.0.22621/um/wincon.h", - "sdk/Include/10.0.22621/um/wincontypes.h", - "sdk/Include/10.0.22621/um/wincrypt.h", - "sdk/Include/10.0.22621/um/winefs.h", - "sdk/Include/10.0.22621/um/wingdi.h", - "sdk/Include/10.0.22621/um/winioctl.h", - "sdk/Include/10.0.22621/um/winnetwk.h", - "sdk/Include/10.0.22621/um/winnt.h", - "sdk/Include/10.0.22621/um/winperf.h", - "sdk/Include/10.0.22621/um/winreg.h", - "sdk/Include/10.0.22621/um/winscard.h", - "sdk/Include/10.0.22621/um/winsock.h", - "sdk/Include/10.0.22621/um/winspool.h", - "sdk/Include/10.0.22621/um/winsvc.h", - "sdk/Include/10.0.22621/um/winver.h", - "sdk/Include/10.0.22621/um/wow64apiset.h", - "sdk/lib/ucrt/x86_64/ucrt.lib", - "sdk/lib/um/x86_64/AdvAPI32.Lib", - "sdk/lib/um/x86_64/UserEnv.Lib", - "sdk/lib/um/x86_64/WS2_32.Lib", - "sdk/lib/um/x86_64/bcrypt.lib", - "sdk/lib/um/x86_64/kernel32.Lib", - "sdk/lib/um/x86_64/ntdll.lib", + "__msvc_iter_core.hpp", + "__msvc_sanitizer_annotate_container.hpp", + "algorithm", + "cassert", + "cctype", + "cfloat", + "climits", + "concurrencysal.h", + "crtdefs.h", + "cstddef", + "cstdint", + "cstdio", + "cstdlib", + "cstring", + "cwchar", + "eh.h", + "exception", + "excpt.h", + "initializer_list", + "iosfwd", + "isa_availability.h", + "limits", + "limits.h", + "list", + "new", + "sal.h", + "setjmp.h", + "stdint.h", + "string", + "type_traits", + "use_ansi.h", + "utility", + "vadefs.h", + "vcruntime.h", + "vcruntime_exception.h", + "vcruntime_new.h", + "vcruntime_new_debug.h", + "vcruntime_string.h", + "vector", + "xatomic.h", + "xkeycheck.h", + "xmemory", + "xstring", + "xtr1common", + "xutility", + "yvals.h", + "yvals_core.h", ] -[symlinks] -"crt/lib/x86_64/msvcrt.lib" = ["MSVCRT.lib"] -"sdk/Include/10.0.22621/shared/WTypesbase.h" = ["wtypesbase.h"] -"sdk/Include/10.0.22621/shared/driverspecs.h" = ["DriverSpecs.h"] -"sdk/Include/10.0.22621/shared/specstrings.h" = ["SpecStrings.h"] -"sdk/Include/10.0.22621/um/DbgHelp.h" = ["dbghelp.h"] -"sdk/Include/10.0.22621/um/PropIdl.h" = ["propidl.h"] -"sdk/Include/10.0.22621/um/PropIdlBase.h" = ["propidlbase.h"] -"sdk/Include/10.0.22621/um/Unknwn.h" = ["unknwn.h"] -"sdk/Include/10.0.22621/um/Unknwnbase.h" = ["unknwnbase.h"] -"sdk/Include/10.0.22621/um/WinBase.h" = ["winbase.h"] -"sdk/Include/10.0.22621/um/WinNls.h" = ["winnls.h"] -"sdk/Include/10.0.22621/um/WinUser.h" = ["winuser.h"] -"sdk/Include/10.0.22621/um/Windows.h" = ["windows.h"] -"sdk/lib/um/x86_64/AdvAPI32.Lib" = [ +[crt.libs] +filter = [ + "x86_64/msvcrt.lib", + "x86_64/vcruntime.lib", +] + +[crt.libs.symlinks] +"x86_64/msvcrt.lib" = ["MSVCRT.lib"] + +[sdk.headers] +filter = [ + "shared/WTypesbase.h", + "shared/apiset.h", + "shared/apisetcconv.h", + "shared/basetsd.h", + "shared/bcrypt.h", + "shared/cderr.h", + "shared/driverspecs.h", + "shared/guiddef.h", + "shared/inaddr.h", + "shared/kernelspecs.h", + "shared/ktmtypes.h", + "shared/minwindef.h", + "shared/poppack.h", + "shared/pshpack1.h", + "shared/pshpack2.h", + "shared/pshpack4.h", + "shared/pshpack8.h", + "shared/rpc.h", + "shared/rpcasync.h", + "shared/rpcdce.h", + "shared/rpcdcep.h", + "shared/rpcndr.h", + "shared/rpcnterr.h", + "shared/rpcsal.h", + "shared/sdkddkver.h", + "shared/sdv_driverspecs.h", + "shared/specstrings.h", + "shared/specstrings_strict.h", + "shared/specstrings_undef.h", + "shared/stralign.h", + "shared/tvout.h", + "shared/winapifamily.h", + "shared/windef.h", + "shared/winerror.h", + "shared/winpackagefamily.h", + "shared/winsmcrd.h", + "shared/wnnc.h", + "shared/wtypes.h", + "ucrt/assert.h", + "ucrt/corecrt.h", + "ucrt/corecrt_malloc.h", + "ucrt/corecrt_memcpy_s.h", + "ucrt/corecrt_memory.h", + "ucrt/corecrt_search.h", + "ucrt/corecrt_share.h", + "ucrt/corecrt_stdio_config.h", + "ucrt/corecrt_terminate.h", + "ucrt/corecrt_wconio.h", + "ucrt/corecrt_wctype.h", + "ucrt/corecrt_wdirect.h", + "ucrt/corecrt_wio.h", + "ucrt/corecrt_wprocess.h", + "ucrt/corecrt_wstdio.h", + "ucrt/corecrt_wstdlib.h", + "ucrt/corecrt_wstring.h", + "ucrt/corecrt_wtime.h", + "ucrt/crtdbg.h", + "ucrt/ctype.h", + "ucrt/errno.h", + "ucrt/float.h", + "ucrt/inttypes.h", + "ucrt/malloc.h", + "ucrt/math.h", + "ucrt/stdio.h", + "ucrt/stdlib.h", + "ucrt/string.h", + "ucrt/sys/stat.h", + "ucrt/sys/types.h", + "ucrt/wchar.h", + "um/DbgHelp.h", + "um/PropIdl.h", + "um/PropIdlBase.h", + "um/Unknwn.h", + "um/Unknwnbase.h", + "um/WinBase.h", + "um/WinNls.h", + "um/WinUser.h", + "um/Windows.h", + "um/apiquery2.h", + "um/cguid.h", + "um/combaseapi.h", + "um/coml2api.h", + "um/commdlg.h", + "um/consoleapi.h", + "um/consoleapi2.h", + "um/consoleapi3.h", + "um/datetimeapi.h", + "um/dde.h", + "um/ddeml.h", + "um/debugapi.h", + "um/dlgs.h", + "um/dpapi.h", + "um/enclaveapi.h", + "um/errhandlingapi.h", + "um/fibersapi.h", + "um/fileapi.h", + "um/fileapifromapp.h", + "um/handleapi.h", + "um/heapapi.h", + "um/ime_cmodes.h", + "um/imm.h", + "um/interlockedapi.h", + "um/ioapiset.h", + "um/jobapi.h", + "um/jobapi2.h", + "um/joystickapi.h", + "um/libloaderapi.h", + "um/lzexpand.h", + "um/mciapi.h", + "um/mcx.h", + "um/memoryapi.h", + "um/minidumpapiset.h", + "um/minwinbase.h", + "um/mmeapi.h", + "um/mmiscapi.h", + "um/mmiscapi2.h", + "um/mmsyscom.h", + "um/mmsystem.h", + "um/msxml.h", + "um/namedpipeapi.h", + "um/namespaceapi.h", + "um/nb30.h", + "um/ncrypt.h", + "um/oaidl.h", + "um/objbase.h", + "um/objidl.h", + "um/objidlbase.h", + "um/ole2.h", + "um/oleauto.h", + "um/oleidl.h", + "um/playsoundapi.h", + "um/processenv.h", + "um/processthreadsapi.h", + "um/processtopologyapi.h", + "um/profileapi.h", + "um/prsht.h", + "um/realtimeapiset.h", + "um/reason.h", + "um/rpcnsi.h", + "um/rpcnsip.h", + "um/securityappcontainer.h", + "um/securitybaseapi.h", + "um/servprov.h", + "um/shellapi.h", + "um/stringapiset.h", + "um/synchapi.h", + "um/sysinfoapi.h", + "um/systemtopologyapi.h", + "um/threadpoolapiset.h", + "um/threadpoollegacyapiset.h", + "um/timeapi.h", + "um/timezoneapi.h", + "um/urlmon.h", + "um/utilapiset.h", + "um/verrsrc.h", + "um/wincon.h", + "um/wincontypes.h", + "um/wincrypt.h", + "um/winefs.h", + "um/wingdi.h", + "um/winioctl.h", + "um/winnetwk.h", + "um/winnt.h", + "um/winperf.h", + "um/winreg.h", + "um/winscard.h", + "um/winsock.h", + "um/winspool.h", + "um/winsvc.h", + "um/winver.h", + "um/wow64apiset.h", +] + +[sdk.headers.symlinks] +"shared/WTypesbase.h" = ["wtypesbase.h"] +"shared/driverspecs.h" = ["DriverSpecs.h"] +"shared/specstrings.h" = ["SpecStrings.h"] +"um/DbgHelp.h" = ["dbghelp.h"] +"um/PropIdl.h" = ["propidl.h"] +"um/PropIdlBase.h" = ["propidlbase.h"] +"um/Unknwn.h" = ["unknwn.h"] +"um/Unknwnbase.h" = ["unknwnbase.h"] +"um/WinBase.h" = ["winbase.h"] +"um/WinNls.h" = ["winnls.h"] +"um/WinUser.h" = ["winuser.h"] +"um/Windows.h" = ["windows.h"] + +[sdk.libs] +filter = [ + "ucrt/x86_64/ucrt.lib", + "um/x86_64/AdvAPI32.Lib", + "um/x86_64/UserEnv.Lib", + "um/x86_64/WS2_32.Lib", + "um/x86_64/bcrypt.lib", + "um/x86_64/kernel32.Lib", + "um/x86_64/ntdll.lib", +] + +[sdk.libs.symlinks] +"um/x86_64/AdvAPI32.Lib" = [ "ADVAPI32.lib", "advapi32.lib", ] -"sdk/lib/um/x86_64/UserEnv.Lib" = [ +"um/x86_64/UserEnv.Lib" = [ "USERENV.lib", "userenv.lib", ] -"sdk/lib/um/x86_64/WS2_32.Lib" = [ +"um/x86_64/WS2_32.Lib" = [ "WS2_32.lib", "ws2_32.lib", ] -"sdk/lib/um/x86_64/bcrypt.lib" = ["BCRYPT.lib"] -"sdk/lib/um/x86_64/kernel32.Lib" = [ +"um/x86_64/bcrypt.lib" = ["BCRYPT.lib"] +"um/x86_64/kernel32.Lib" = [ "KERNEL32.lib", "Kernel32.lib", "kernel32.lib", ] -"sdk/lib/um/x86_64/ntdll.lib" = ["NTDLL.lib"] +"um/x86_64/ntdll.lib" = ["NTDLL.lib"] diff --git a/tests/snapshots/xwin-minimize.snap b/tests/snapshots/xwin-minimize.snap index d63645a..3945321 100644 --- a/tests/snapshots/xwin-minimize.snap +++ b/tests/snapshots/xwin-minimize.snap @@ -41,12 +41,14 @@ Options: The path of the filter file that is generated. Defaults to ./.xwin-cache/xwin-map.toml - --splat-output - The root output directory. Defaults to `./.xwin-cache/splat` if not - specified - --output - The root output directory + The root splat output directory. Defaults to `./.xwin-cache/splat` if + not specified + + --minimize-output + The root output directory for the minimized set of files discovered + during the build. If not specified only the map file is written in + addition to the splat --copy Copies files from the splat directory rather than moving them. Only