Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add if-identical mode for download-ci-llvm #113761

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,7 @@ impl<'a> Builder<'a> {
dist::Miri,
dist::LlvmTools,
dist::RustDev,
dist::RustDevConfig,
dist::Bootstrap,
dist::Extended,
// It seems that PlainSourceTarball somehow changes how some of the tools
Expand Down Expand Up @@ -1872,7 +1873,7 @@ impl<'a> Builder<'a> {
//
// FIXME: the guard against msvc shouldn't need to be here
if target.contains("msvc") {
if let Some(ref cl) = self.config.llvm_clang_cl {
if let Some(ref cl) = self.config.llvm.clang_cl {
cargo.env("CC", cl).env("CXX", cl);
}
} else {
Expand Down
14 changes: 7 additions & 7 deletions src/bootstrap/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ impl Step for Rustc {
// is already on by default in MSVC optimized builds, which is interpreted as --icf=all:
// https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746
// https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827
if builder.config.use_lld && !compiler.host.contains("msvc") {
if builder.config.llvm.use_lld && !compiler.host.contains("msvc") {
cargo.rustflag("-Clink-args=-Wl,--icf=all");
}

Expand Down Expand Up @@ -1002,15 +1002,15 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
// `__llvm_profile_instrument_memop` when linking `rustc_driver`.
let mut llvm_linker_flags = String::new();
if builder.config.llvm_profile_generate && target.contains("msvc") {
if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl {
if let Some(ref clang_cl_path) = builder.config.llvm.clang_cl {
// Add clang's runtime library directory to the search path
let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
}
}

// The config can also specify its own llvm linker flags.
if let Some(ref s) = builder.config.llvm_ldflags {
if let Some(ref s) = builder.config.llvm.ldflags {
if !llvm_linker_flags.is_empty() {
llvm_linker_flags.push_str(" ");
}
Expand All @@ -1024,7 +1024,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect

// Building with a static libstdc++ is only supported on linux right now,
// not for MSVC or macOS
if builder.config.llvm_static_stdcpp
if builder.config.llvm.static_stdcpp
&& !target.contains("freebsd")
&& !target.contains("msvc")
&& !target.contains("apple")
Expand All @@ -1042,10 +1042,10 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
if builder.llvm_link_shared() {
cargo.env("LLVM_LINK_SHARED", "1");
}
if builder.config.llvm_use_libcxx {
if builder.config.llvm.use_libcxx {
cargo.env("LLVM_USE_LIBCXX", "1");
}
if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo {
if builder.config.llvm.optimize && !builder.config.llvm.release_debuginfo {
cargo.env("LLVM_NDEBUG", "1");
}
}
Expand Down Expand Up @@ -1564,7 +1564,7 @@ impl Step for Assemble {
});
}

let lld_install = if builder.config.lld_enabled {
let lld_install = if builder.config.llvm.lld_enabled {
Some(builder.ensure(llvm::Lld { target: target_compiler.host }))
} else {
None
Expand Down
158 changes: 88 additions & 70 deletions src/bootstrap/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,39 @@ impl Display for DebuginfoLevel {
}
}

#[derive(Default, Clone, PartialEq, serde_derive::Serialize, serde_derive::Deserialize)]
pub struct LLVMConfig {
pub assertions: bool,
pub tests: bool,
pub plugins: bool,
pub optimize: bool,
pub thin_lto: bool,
pub release_debuginfo: bool,
pub static_stdcpp: bool,
/// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
pub link_shared: Cell<Option<bool>>,
pub clang_cl: Option<String>,
pub targets: Option<String>,
pub experimental_targets: Option<String>,
pub link_jobs: Option<u32>,
pub version_suffix: Option<String>,
pub use_linker: Option<String>,
pub allow_old_toolchain: bool,
pub polly: bool,
pub clang: bool,
pub enable_warnings: bool,
pub build_config: HashMap<String, String>,

pub use_lld: bool,
pub lld_enabled: bool,
pub tools_enabled: bool,

pub cflags: Option<String>,
pub cxxflags: Option<String>,
pub ldflags: Option<String>,
pub use_libcxx: bool,
}

/// Global configuration for the entire build and/or bootstrap.
///
/// This structure is parsed from `config.toml`, and some of the fields are inferred from `git` or build-time parameters.
Expand Down Expand Up @@ -167,39 +200,8 @@ pub struct Config {
pub backtrace_on_ice: bool,

// llvm codegen options
pub llvm_assertions: bool,
pub llvm_tests: bool,
pub llvm_plugins: bool,
pub llvm_optimize: bool,
pub llvm_thin_lto: bool,
pub llvm_release_debuginfo: bool,
pub llvm_static_stdcpp: bool,
/// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
#[cfg(not(test))]
llvm_link_shared: Cell<Option<bool>>,
#[cfg(test)]
pub llvm_link_shared: Cell<Option<bool>>,
pub llvm_clang_cl: Option<String>,
pub llvm_targets: Option<String>,
pub llvm_experimental_targets: Option<String>,
pub llvm_link_jobs: Option<u32>,
pub llvm_version_suffix: Option<String>,
pub llvm_use_linker: Option<String>,
pub llvm_allow_old_toolchain: bool,
pub llvm_polly: bool,
pub llvm_clang: bool,
pub llvm_enable_warnings: bool,
pub llvm_from_ci: bool,
Kobzol marked this conversation as resolved.
Show resolved Hide resolved
pub llvm_build_config: HashMap<String, String>,

pub use_lld: bool,
pub lld_enabled: bool,
pub llvm_tools_enabled: bool,

pub llvm_cflags: Option<String>,
pub llvm_cxxflags: Option<String>,
pub llvm_ldflags: Option<String>,
pub llvm_use_libcxx: bool,
pub llvm: LLVMConfig,

// rust codegen options
pub rust_optimize: RustOptimize,
Expand Down Expand Up @@ -1052,9 +1054,9 @@ define_config! {
impl Config {
pub fn default_opts() -> Config {
let mut config = Config::default();
config.llvm_optimize = true;
config.llvm.optimize = true;
config.ninja_in_file = true;
config.llvm_static_stdcpp = false;
config.llvm.static_stdcpp = false;
config.backtrace = true;
config.rust_optimize = RustOptimize::Bool(true);
config.rust_optimize_tests = true;
Expand Down Expand Up @@ -1428,9 +1430,9 @@ impl Config {
if let Some(true) = rust.incremental {
config.incremental = true;
}
set(&mut config.use_lld, rust.use_lld);
set(&mut config.lld_enabled, rust.lld);
set(&mut config.llvm_tools_enabled, rust.llvm_tools);
set(&mut config.llvm.use_lld, rust.use_lld);
set(&mut config.llvm.lld_enabled, rust.lld);
set(&mut config.llvm.tools_enabled, rust.llvm_tools);
config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
config.rustc_default_linker = rust.default_linker;
config.musl_root = rust.musl_root.map(PathBuf::from);
Expand Down Expand Up @@ -1489,43 +1491,51 @@ impl Config {
llvm_assertions = llvm.assertions;
llvm_tests = llvm.tests;
llvm_plugins = llvm.plugins;
set(&mut config.llvm_optimize, llvm.optimize);
set(&mut config.llvm_thin_lto, llvm.thin_lto);
set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
set(&mut config.llvm.optimize, llvm.optimize);
set(&mut config.llvm.thin_lto, llvm.thin_lto);
set(&mut config.llvm.release_debuginfo, llvm.release_debuginfo);
set(&mut config.llvm.static_stdcpp, llvm.static_libstdcpp);
if let Some(v) = llvm.link_shared {
config.llvm_link_shared.set(Some(v));
config.llvm.link_shared.set(Some(v));
}
config.llvm_targets = llvm.targets.clone();
config.llvm_experimental_targets = llvm.experimental_targets.clone();
config.llvm_link_jobs = llvm.link_jobs;
config.llvm_version_suffix = llvm.version_suffix.clone();
config.llvm_clang_cl = llvm.clang_cl.clone();

config.llvm_cflags = llvm.cflags.clone();
config.llvm_cxxflags = llvm.cxxflags.clone();
config.llvm_ldflags = llvm.ldflags.clone();
set(&mut config.llvm_use_libcxx, llvm.use_libcxx);
config.llvm_use_linker = llvm.use_linker.clone();
config.llvm_allow_old_toolchain = llvm.allow_old_toolchain.unwrap_or(false);
config.llvm_polly = llvm.polly.unwrap_or(false);
config.llvm_clang = llvm.clang.unwrap_or(false);
config.llvm_enable_warnings = llvm.enable_warnings.unwrap_or(false);
config.llvm_build_config = llvm.build_config.clone().unwrap_or(Default::default());
config.llvm.targets = llvm.targets.clone();
config.llvm.experimental_targets = llvm.experimental_targets.clone();
config.llvm.link_jobs = llvm.link_jobs;
config.llvm.version_suffix = llvm.version_suffix.clone();
config.llvm.clang_cl = llvm.clang_cl.clone();

config.llvm.cflags = llvm.cflags.clone();
config.llvm.cxxflags = llvm.cxxflags.clone();
config.llvm.ldflags = llvm.ldflags.clone();
set(&mut config.llvm.use_libcxx, llvm.use_libcxx);
config.llvm.use_linker = llvm.use_linker.clone();
config.llvm.allow_old_toolchain = llvm.allow_old_toolchain.unwrap_or(false);
config.llvm.polly = llvm.polly.unwrap_or(false);
config.llvm.clang = llvm.clang.unwrap_or(false);
config.llvm.enable_warnings = llvm.enable_warnings.unwrap_or(false);
config.llvm.build_config = llvm.build_config.clone().unwrap_or(Default::default());

let asserts = llvm_assertions.unwrap_or(false);
let mut downloaded_config = false;
config.llvm_from_ci = match llvm.download_ci_llvm {
Some(StringOrBool::String(s)) => {
assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
crate::llvm::is_ci_llvm_available(&config, asserts)
}
Some(StringOrBool::String(s)) => match s.as_str() {
"if-available" => crate::llvm::is_ci_llvm_available(&config, asserts),
"if-identical" => match crate::llvm::get_llvm_opts_from_ci(&config) {
Kobzol marked this conversation as resolved.
Show resolved Hide resolved
Some(config_ci) => {
downloaded_config = true;
is_llvm_config_identical(&config_ci, &config.llvm)
}
None => false,
},
_ => panic!("unknown option `{s}` for download-ci-llvm"),
},
Some(StringOrBool::Bool(b)) => b,
None => {
config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, asserts)
}
};

if config.llvm_from_ci {
if config.llvm_from_ci && !downloaded_config {
// None of the LLVM options, except assertions, are supported
// when using downloaded LLVM. We could just ignore these but
// that's potentially confusing, so force them to not be
Expand Down Expand Up @@ -1556,11 +1566,11 @@ impl Config {
}

// NOTE: can never be hit when downloading from CI, since we call `check_ci_llvm!(thin_lto)` above.
if config.llvm_thin_lto && llvm.link_shared.is_none() {
if !downloaded_config && config.llvm.thin_lto && llvm.link_shared.is_none() {
// If we're building with ThinLTO on, by default we want to link
// to LLVM shared, to avoid re-doing ThinLTO (which happens in
// the link step) with each stage.
config.llvm_link_shared.set(Some(true));
config.llvm.link_shared.set(Some(true));
}
} else {
config.llvm_from_ci =
Expand Down Expand Up @@ -1650,9 +1660,9 @@ impl Config {
// Now that we've reached the end of our configuration, infer the
// default values for all options that we haven't otherwise stored yet.

config.llvm_assertions = llvm_assertions.unwrap_or(false);
config.llvm_tests = llvm_tests.unwrap_or(false);
config.llvm_plugins = llvm_plugins.unwrap_or(false);
config.llvm.assertions = llvm_assertions.unwrap_or(false);
config.llvm.tests = llvm_tests.unwrap_or(false);
config.llvm.plugins = llvm_plugins.unwrap_or(false);
config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));

let default = debug == Some(true);
Expand Down Expand Up @@ -1859,6 +1869,10 @@ impl Config {
self.out.join(&*self.build.triple).join("ci-llvm")
}

pub(crate) fn ci_llvm_root_opts(&self) -> PathBuf {
self.out.join(&*self.build.triple).join("ci-llvm-opts")
}

/// Directory where the extracted `rustc-dev` component is stored.
pub(crate) fn ci_rustc_dir(&self) -> PathBuf {
assert!(self.download_rustc());
Expand All @@ -1870,7 +1884,7 @@ impl Config {
/// If `false`, llvm should be linked statically.
/// This is computed on demand since LLVM might have to first be downloaded from CI.
pub(crate) fn llvm_link_shared(&self) -> bool {
let mut opt = self.llvm_link_shared.get();
let mut opt = self.llvm.link_shared.get();
if opt.is_none() && self.dry_run() {
// just assume static for now - dynamic linking isn't supported on all platforms
return false;
Expand All @@ -1891,7 +1905,7 @@ impl Config {
false
}
});
self.llvm_link_shared.set(opt);
self.llvm.link_shared.set(opt);
llvm_link_shared
}

Expand Down Expand Up @@ -2084,6 +2098,10 @@ impl Config {
}
}

fn is_llvm_config_identical(from_ci: &LLVMConfig, current: &LLVMConfig) -> bool {
from_ci == current
}
Kobzol marked this conversation as resolved.
Show resolved Hide resolved

fn set<T>(field: &mut T, val: Option<T>) {
if let Some(v) = val {
*field = v;
Expand Down
44 changes: 43 additions & 1 deletion src/bootstrap/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ impl Step for Rustc {
t!(fs::create_dir_all(&dst_dir));

// Copy over lld if it's there
if builder.config.lld_enabled {
if builder.config.llvm.lld_enabled {
let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
let rust_lld = exe("rust-lld", compiler.host);
builder.copy(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld));
Expand Down Expand Up @@ -2297,6 +2297,48 @@ impl Step for RustDev {
}
}

// Tarball intended for internal consumption to ease rustc/std development.
//
// Should not be considered stable by end users.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct RustDevConfig {
pub target: TargetSelection,
}

impl Step for RustDevConfig {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;

fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("rust-dev-config")
}

fn make_run(run: RunConfig<'_>) {
run.builder.ensure(RustDevConfig { target: run.target });
}

fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
let target = self.target;

/* run only if llvm-config isn't used */
if let Some(config) = builder.config.target_config.get(&target) {
if let Some(ref _s) = config.llvm_config {
builder.info(&format!("Skipping RustDevConfig ({}): external LLVM", target));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is true but confusing when llvm_from_ci is set. maybe we can improve it a bit?

Suggested change
builder.info(&format!("Skipping RustDevConfig ({}): external LLVM", target));
let reason = if builder.config.llvm_from_ci { "downloaded LLVM from CI instead of building it" } else { "external llvm" };
builder.info(&format!("Skipping RustDevConfig ({target}): {reason}");

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. However, I realized that this shouldn't fail when llvm_from_ci is true? Because this has to succeed when download-ci-llvm is if-identical. We should probably make llvm_from_ci an enum to distinguish these situations?

return None;
}
}
Comment on lines +2324 to +2330
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make this a default instead of a skip, so that we can give a hard error if someone runs x dist rust-dev-config when external llvm is set? see #113640 for an example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this?

fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let config = run.builder.config.target_config.get(&<how to get target?>).map(|c| c.llvm_config);
        run.alias("rust-dev-config").default_condition(config.is_none())
    }

I'm not sure how to get the target, because run.builder contains a list of targets.


let mut tarball = Tarball::new(builder, "rust-dev-config", &target.triple);
tarball.set_overlay(OverlayKind::LLVM);

let config = t!(serde_json::to_string_pretty(&builder.build.config.llvm));
t!(std::fs::write(tarball.image_dir().join("llvm-opts.json"), config));
jyn514 marked this conversation as resolved.
Show resolved Hide resolved

Some(tarball.generate())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this panics when running x dist rust-dev-config before the llvm submodule is checked out. could you add builder.update_submodule somewhere around

for file in self.overlay.legal_and_readme() {
self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644);
}
please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I really update LLVM submodule in a function that creates a tarball? Shouldn't this be in RustDevConfig? It sounds quite LLVM specific to do this in the Tarball struct.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, i suppose doing it in this Step is fine. i was imaging you'd check overlay_kind in Tarball so each calling Step doesn't have to worry about it but in practice they're probably all doing the right thing.

}
}

// Tarball intended for internal consumption to ease rustc/std development.
//
// Should not be considered stable by end users.
Expand Down
Loading