mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-07 05:15:02 +00:00
Use trimmed down deserialization impl for config
This reduces binary size from 10.1MiB (6.2MiB for just rustbuild code) to 9.7MiB (5.8MiB for just rustbuild code). This also reduces compile time from ~6.1s for incr recompilation to ~5.6s. There is still a lot of unnecessary code due to the toml crate monomorphizing every deserialization impl 5 times.
This commit is contained in:
parent
88609e5126
commit
a0b4d2136d
@ -17,7 +17,7 @@ use crate::channel::GitInfo;
|
|||||||
pub use crate::flags::Subcommand;
|
pub use crate::flags::Subcommand;
|
||||||
use crate::flags::{Color, Flags};
|
use crate::flags::{Color, Flags};
|
||||||
use crate::util::{exe, t};
|
use crate::util::{exe, t};
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
macro_rules! check_ci_llvm {
|
macro_rules! check_ci_llvm {
|
||||||
($name:expr) => {
|
($name:expr) => {
|
||||||
@ -364,13 +364,11 @@ impl Merge for TomlConfig {
|
|||||||
// rustbuild.
|
// rustbuild.
|
||||||
macro_rules! define_config {
|
macro_rules! define_config {
|
||||||
($(#[$attr:meta])* struct $name:ident {
|
($(#[$attr:meta])* struct $name:ident {
|
||||||
$($field:ident: $field_ty:ty,)*
|
$($field:ident: Option<$field_ty:ty> = $field_key:literal,)*
|
||||||
}) => {
|
}) => {
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
|
||||||
struct $name {
|
struct $name {
|
||||||
$($field: $field_ty,)*
|
$($field: Option<$field_ty>,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Merge for $name {
|
impl Merge for $name {
|
||||||
@ -382,6 +380,99 @@ macro_rules! define_config {
|
|||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The following is a trimmed version of what serde_derive generates. All parts not relevant
|
||||||
|
// for toml deserialization have been removed. This reduces the binary size and improves
|
||||||
|
// compile time of rustbuild.
|
||||||
|
impl<'de> Deserialize<'de> for $name {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
enum FieldName {
|
||||||
|
$($field,)*
|
||||||
|
}
|
||||||
|
struct FieldNameVisitor;
|
||||||
|
impl<'de> serde::de::Visitor<'de> for FieldNameVisitor {
|
||||||
|
type Value = FieldName;
|
||||||
|
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("field identifier")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
$($field_key => Ok(FieldName::$field),)*
|
||||||
|
_ => Err(serde::de::Error::unknown_field(value, FIELDS)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'de> Deserialize<'de> for FieldName {
|
||||||
|
#[inline]
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Deserializer::deserialize_identifier(deserializer, FieldNameVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct Field;
|
||||||
|
impl<'de> serde::de::Visitor<'de> for Field {
|
||||||
|
type Value = $name;
|
||||||
|
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(concat!("struct ", stringify!($name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
$(let mut $field: Option<$field_ty> = None;)*
|
||||||
|
while let Some(key) =
|
||||||
|
match serde::de::MapAccess::next_key::<FieldName>(&mut map) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(err) => {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
match key {
|
||||||
|
$(FieldName::$field => {
|
||||||
|
if $field.is_some() {
|
||||||
|
return Err(<A::Error as serde::de::Error>::duplicate_field(
|
||||||
|
$field_key,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
$field = match serde::de::MapAccess::next_value::<$field_ty>(
|
||||||
|
&mut map,
|
||||||
|
) {
|
||||||
|
Ok(val) => Some(val),
|
||||||
|
Err(err) => {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok($name { $($field),* })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const FIELDS: &'static [&'static str] = &[
|
||||||
|
$($field_key,)*
|
||||||
|
];
|
||||||
|
Deserializer::deserialize_struct(
|
||||||
|
deserializer,
|
||||||
|
stringify!($name),
|
||||||
|
FIELDS,
|
||||||
|
Field,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,101 +480,101 @@ define_config! {
|
|||||||
/// TOML representation of various global build decisions.
|
/// TOML representation of various global build decisions.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Build {
|
struct Build {
|
||||||
build: Option<String>,
|
build: Option<String> = "build",
|
||||||
host: Option<Vec<String>>,
|
host: Option<Vec<String>> = "host",
|
||||||
target: Option<Vec<String>>,
|
target: Option<Vec<String>> = "target",
|
||||||
build_dir: Option<String>,
|
build_dir: Option<String> = "build-dir",
|
||||||
cargo: Option<String>,
|
cargo: Option<String> = "cargo",
|
||||||
rustc: Option<String>,
|
rustc: Option<String> = "rustc",
|
||||||
rustfmt: Option<PathBuf>,
|
rustfmt: Option<PathBuf> = "rustfmt",
|
||||||
docs: Option<bool>,
|
docs: Option<bool> = "docs",
|
||||||
compiler_docs: Option<bool>,
|
compiler_docs: Option<bool> = "compiler-docs",
|
||||||
docs_minification: Option<bool>,
|
docs_minification: Option<bool> = "docs-minification",
|
||||||
submodules: Option<bool>,
|
submodules: Option<bool> = "submodules",
|
||||||
fast_submodules: Option<bool>,
|
fast_submodules: Option<bool> = "fast-submodules",
|
||||||
gdb: Option<String>,
|
gdb: Option<String> = "gdb",
|
||||||
nodejs: Option<String>,
|
nodejs: Option<String> = "nodejs",
|
||||||
npm: Option<String>,
|
npm: Option<String> = "npm",
|
||||||
python: Option<String>,
|
python: Option<String> = "python",
|
||||||
locked_deps: Option<bool>,
|
locked_deps: Option<bool> = "locked-deps",
|
||||||
vendor: Option<bool>,
|
vendor: Option<bool> = "vendor",
|
||||||
full_bootstrap: Option<bool>,
|
full_bootstrap: Option<bool> = "full-bootstrap",
|
||||||
extended: Option<bool>,
|
extended: Option<bool> = "extended",
|
||||||
tools: Option<HashSet<String>>,
|
tools: Option<HashSet<String>> = "tools",
|
||||||
verbose: Option<usize>,
|
verbose: Option<usize> = "verbose",
|
||||||
sanitizers: Option<bool>,
|
sanitizers: Option<bool> = "sanitizers",
|
||||||
profiler: Option<bool>,
|
profiler: Option<bool> = "profiler",
|
||||||
cargo_native_static: Option<bool>,
|
cargo_native_static: Option<bool> = "cargo-native-static",
|
||||||
low_priority: Option<bool>,
|
low_priority: Option<bool> = "low-priority",
|
||||||
configure_args: Option<Vec<String>>,
|
configure_args: Option<Vec<String>> = "configure-args",
|
||||||
local_rebuild: Option<bool>,
|
local_rebuild: Option<bool> = "local-rebuild",
|
||||||
print_step_timings: Option<bool>,
|
print_step_timings: Option<bool> = "print-step-timings",
|
||||||
print_step_rusage: Option<bool>,
|
print_step_rusage: Option<bool> = "print-step-rusage",
|
||||||
check_stage: Option<u32>,
|
check_stage: Option<u32> = "check-stage",
|
||||||
doc_stage: Option<u32>,
|
doc_stage: Option<u32> = "doc-stage",
|
||||||
build_stage: Option<u32>,
|
build_stage: Option<u32> = "build-stage",
|
||||||
test_stage: Option<u32>,
|
test_stage: Option<u32> = "test-stage",
|
||||||
install_stage: Option<u32>,
|
install_stage: Option<u32> = "install-stage",
|
||||||
dist_stage: Option<u32>,
|
dist_stage: Option<u32> = "dist-stage",
|
||||||
bench_stage: Option<u32>,
|
bench_stage: Option<u32> = "bench-stage",
|
||||||
patch_binaries_for_nix: Option<bool>,
|
patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
define_config! {
|
define_config! {
|
||||||
/// TOML representation of various global install decisions.
|
/// TOML representation of various global install decisions.
|
||||||
struct Install {
|
struct Install {
|
||||||
prefix: Option<String>,
|
prefix: Option<String> = "prefix",
|
||||||
sysconfdir: Option<String>,
|
sysconfdir: Option<String> = "sysconfdir",
|
||||||
docdir: Option<String>,
|
docdir: Option<String> = "docdir",
|
||||||
bindir: Option<String>,
|
bindir: Option<String> = "bindir",
|
||||||
libdir: Option<String>,
|
libdir: Option<String> = "libdir",
|
||||||
mandir: Option<String>,
|
mandir: Option<String> = "mandir",
|
||||||
datadir: Option<String>,
|
datadir: Option<String> = "datadir",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
define_config! {
|
define_config! {
|
||||||
/// TOML representation of how the LLVM build is configured.
|
/// TOML representation of how the LLVM build is configured.
|
||||||
struct Llvm {
|
struct Llvm {
|
||||||
skip_rebuild: Option<bool>,
|
skip_rebuild: Option<bool> = "skip-rebuild",
|
||||||
optimize: Option<bool>,
|
optimize: Option<bool> = "optimize",
|
||||||
thin_lto: Option<bool>,
|
thin_lto: Option<bool> = "thin-lto",
|
||||||
release_debuginfo: Option<bool>,
|
release_debuginfo: Option<bool> = "release-debuginfo",
|
||||||
assertions: Option<bool>,
|
assertions: Option<bool> = "assertions",
|
||||||
tests: Option<bool>,
|
tests: Option<bool> = "tests",
|
||||||
plugins: Option<bool>,
|
plugins: Option<bool> = "plugins",
|
||||||
ccache: Option<StringOrBool>,
|
ccache: Option<StringOrBool> = "ccache",
|
||||||
version_check: Option<bool>,
|
version_check: Option<bool> = "version-check",
|
||||||
static_libstdcpp: Option<bool>,
|
static_libstdcpp: Option<bool> = "static-libstdcpp",
|
||||||
ninja: Option<bool>,
|
ninja: Option<bool> = "ninja",
|
||||||
targets: Option<String>,
|
targets: Option<String> = "targets",
|
||||||
experimental_targets: Option<String>,
|
experimental_targets: Option<String> = "experimental-targets",
|
||||||
link_jobs: Option<u32>,
|
link_jobs: Option<u32> = "link-jobs",
|
||||||
link_shared: Option<bool>,
|
link_shared: Option<bool> = "link-shared",
|
||||||
version_suffix: Option<String>,
|
version_suffix: Option<String> = "version-suffix",
|
||||||
clang_cl: Option<String>,
|
clang_cl: Option<String> = "clang-cl",
|
||||||
cflags: Option<String>,
|
cflags: Option<String> = "cflags",
|
||||||
cxxflags: Option<String>,
|
cxxflags: Option<String> = "cxxflags",
|
||||||
ldflags: Option<String>,
|
ldflags: Option<String> = "ldflags",
|
||||||
use_libcxx: Option<bool>,
|
use_libcxx: Option<bool> = "use-libcxx",
|
||||||
use_linker: Option<String>,
|
use_linker: Option<String> = "use-linker",
|
||||||
allow_old_toolchain: Option<bool>,
|
allow_old_toolchain: Option<bool> = "allow-old-toolchain",
|
||||||
polly: Option<bool>,
|
polly: Option<bool> = "polly",
|
||||||
clang: Option<bool>,
|
clang: Option<bool> = "clang",
|
||||||
download_ci_llvm: Option<StringOrBool>,
|
download_ci_llvm: Option<StringOrBool> = "download-ci-llvm",
|
||||||
build_config: Option<HashMap<String, String>>,
|
build_config: Option<HashMap<String, String>> = "build-config",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
define_config! {
|
define_config! {
|
||||||
struct Dist {
|
struct Dist {
|
||||||
sign_folder: Option<String>,
|
sign_folder: Option<String> = "sign-folder",
|
||||||
gpg_password_file: Option<String>,
|
gpg_password_file: Option<String> = "gpg-password-file",
|
||||||
upload_addr: Option<String>,
|
upload_addr: Option<String> = "upload-addr",
|
||||||
src_tarball: Option<bool>,
|
src_tarball: Option<bool> = "src-tarball",
|
||||||
missing_tools: Option<bool>,
|
missing_tools: Option<bool> = "missing-tools",
|
||||||
compression_formats: Option<Vec<String>>,
|
compression_formats: Option<Vec<String>> = "compression-formats",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,76 +594,76 @@ impl Default for StringOrBool {
|
|||||||
define_config! {
|
define_config! {
|
||||||
/// TOML representation of how the Rust build is configured.
|
/// TOML representation of how the Rust build is configured.
|
||||||
struct Rust {
|
struct Rust {
|
||||||
optimize: Option<bool>,
|
optimize: Option<bool> = "optimize",
|
||||||
debug: Option<bool>,
|
debug: Option<bool> = "debug",
|
||||||
codegen_units: Option<u32>,
|
codegen_units: Option<u32> = "codegen-units",
|
||||||
codegen_units_std: Option<u32>,
|
codegen_units_std: Option<u32> = "codegen-units-std",
|
||||||
debug_assertions: Option<bool>,
|
debug_assertions: Option<bool> = "debug-assertions",
|
||||||
debug_assertions_std: Option<bool>,
|
debug_assertions_std: Option<bool> = "debug-assertions-std",
|
||||||
overflow_checks: Option<bool>,
|
overflow_checks: Option<bool> = "overflow-checks",
|
||||||
overflow_checks_std: Option<bool>,
|
overflow_checks_std: Option<bool> = "overflow-checks-std",
|
||||||
debug_logging: Option<bool>,
|
debug_logging: Option<bool> = "debug-logging",
|
||||||
debuginfo_level: Option<u32>,
|
debuginfo_level: Option<u32> = "debuginfo-level",
|
||||||
debuginfo_level_rustc: Option<u32>,
|
debuginfo_level_rustc: Option<u32> = "debuginfo-level-rustc",
|
||||||
debuginfo_level_std: Option<u32>,
|
debuginfo_level_std: Option<u32> = "debuginfo-level-std",
|
||||||
debuginfo_level_tools: Option<u32>,
|
debuginfo_level_tools: Option<u32> = "debuginfo-level-tools",
|
||||||
debuginfo_level_tests: Option<u32>,
|
debuginfo_level_tests: Option<u32> = "debuginfo-level-tests",
|
||||||
run_dsymutil: Option<bool>,
|
run_dsymutil: Option<bool> = "run-dsymutil",
|
||||||
backtrace: Option<bool>,
|
backtrace: Option<bool> = "backtrace",
|
||||||
incremental: Option<bool>,
|
incremental: Option<bool> = "incremental",
|
||||||
parallel_compiler: Option<bool>,
|
parallel_compiler: Option<bool> = "parallel-compiler",
|
||||||
default_linker: Option<String>,
|
default_linker: Option<String> = "default-linker",
|
||||||
channel: Option<String>,
|
channel: Option<String> = "channel",
|
||||||
description: Option<String>,
|
description: Option<String> = "description",
|
||||||
musl_root: Option<String>,
|
musl_root: Option<String> = "musl-root",
|
||||||
rpath: Option<bool>,
|
rpath: Option<bool> = "rpath",
|
||||||
verbose_tests: Option<bool>,
|
verbose_tests: Option<bool> = "verbose-tests",
|
||||||
optimize_tests: Option<bool>,
|
optimize_tests: Option<bool> = "optimize-tests",
|
||||||
codegen_tests: Option<bool>,
|
codegen_tests: Option<bool> = "codegen-tests",
|
||||||
ignore_git: Option<bool>,
|
ignore_git: Option<bool> = "ignore-git",
|
||||||
dist_src: Option<bool>,
|
dist_src: Option<bool> = "dist-src",
|
||||||
save_toolstates: Option<String>,
|
save_toolstates: Option<String> = "save-toolstates",
|
||||||
codegen_backends: Option<Vec<String>>,
|
codegen_backends: Option<Vec<String>> = "codegen-backends",
|
||||||
lld: Option<bool>,
|
lld: Option<bool> = "lld",
|
||||||
use_lld: Option<bool>,
|
use_lld: Option<bool> = "use-lld",
|
||||||
llvm_tools: Option<bool>,
|
llvm_tools: Option<bool> = "llvm-tools",
|
||||||
deny_warnings: Option<bool>,
|
deny_warnings: Option<bool> = "deny-warnings",
|
||||||
backtrace_on_ice: Option<bool>,
|
backtrace_on_ice: Option<bool> = "backtrace-on-ice",
|
||||||
verify_llvm_ir: Option<bool>,
|
verify_llvm_ir: Option<bool> = "verify-llvm-ir",
|
||||||
thin_lto_import_instr_limit: Option<u32>,
|
thin_lto_import_instr_limit: Option<u32> = "thin-lto-import-instr-limit",
|
||||||
remap_debuginfo: Option<bool>,
|
remap_debuginfo: Option<bool> = "remap-debuginfo",
|
||||||
jemalloc: Option<bool>,
|
jemalloc: Option<bool> = "jemalloc",
|
||||||
test_compare_mode: Option<bool>,
|
test_compare_mode: Option<bool> = "test-compare-mode",
|
||||||
llvm_libunwind: Option<String>,
|
llvm_libunwind: Option<String> = "llvm-libunwind",
|
||||||
control_flow_guard: Option<bool>,
|
control_flow_guard: Option<bool> = "control-flow-guard",
|
||||||
new_symbol_mangling: Option<bool>,
|
new_symbol_mangling: Option<bool> = "new-symbol-mangling",
|
||||||
profile_generate: Option<String>,
|
profile_generate: Option<String> = "profile-generate",
|
||||||
profile_use: Option<String>,
|
profile_use: Option<String> = "profile-use",
|
||||||
// ignored; this is set from an env var set by bootstrap.py
|
// ignored; this is set from an env var set by bootstrap.py
|
||||||
download_rustc: Option<StringOrBool>,
|
download_rustc: Option<StringOrBool> = "download-rustc",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
define_config! {
|
define_config! {
|
||||||
/// TOML representation of how each build target is configured.
|
/// TOML representation of how each build target is configured.
|
||||||
struct TomlTarget {
|
struct TomlTarget {
|
||||||
cc: Option<String>,
|
cc: Option<String> = "cc",
|
||||||
cxx: Option<String>,
|
cxx: Option<String> = "cxx",
|
||||||
ar: Option<String>,
|
ar: Option<String> = "ar",
|
||||||
ranlib: Option<String>,
|
ranlib: Option<String> = "ranlib",
|
||||||
default_linker: Option<PathBuf>,
|
default_linker: Option<PathBuf> = "default-linker",
|
||||||
linker: Option<String>,
|
linker: Option<String> = "linker",
|
||||||
llvm_config: Option<String>,
|
llvm_config: Option<String> = "llvm-config",
|
||||||
llvm_filecheck: Option<String>,
|
llvm_filecheck: Option<String> = "llvm-filecheck",
|
||||||
android_ndk: Option<String>,
|
android_ndk: Option<String> = "android-ndk",
|
||||||
sanitizers: Option<bool>,
|
sanitizers: Option<bool> = "sanitizers",
|
||||||
profiler: Option<bool>,
|
profiler: Option<bool> = "profiler",
|
||||||
crt_static: Option<bool>,
|
crt_static: Option<bool> = "crt-static",
|
||||||
musl_root: Option<String>,
|
musl_root: Option<String> = "musl-root",
|
||||||
musl_libdir: Option<String>,
|
musl_libdir: Option<String> = "musl-libdir",
|
||||||
wasi_root: Option<String>,
|
wasi_root: Option<String> = "wasi-root",
|
||||||
qemu_rootfs: Option<String>,
|
qemu_rootfs: Option<String> = "qemu-rootfs",
|
||||||
no_std: Option<bool>,
|
no_std: Option<bool> = "no-std",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user