From fe42c5eaa40f43930bfb96e0e6bd19dc270667ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 1 Oct 2025 14:54:21 +0200 Subject: [PATCH 1/5] wip gnullvm self-contained --- .../src/spec/base/windows_gnullvm.rs | 15 ++++-- .../spec/targets/x86_64_pc_windows_gnullvm.rs | 1 + src/bootstrap/src/core/build_steps/compile.rs | 2 +- src/bootstrap/src/core/build_steps/dist.rs | 48 ++++++++++++++++++- src/bootstrap/src/core/builder/cargo.rs | 2 + .../src/core/config/target_selection.rs | 4 ++ 6 files changed, 64 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index f24ad781e2b81..5ed4c70d77bf5 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -1,7 +1,9 @@ use std::borrow::Cow; +use crate::spec::crt_objects::pre_mingw_self_contained; use crate::spec::{ - BinaryFormat, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs, + BinaryFormat, Cc, DebuginfoKind, LinkSelfContainedDefault, LinkerFlavor, Lld, SplitDebuginfo, + TargetOptions, add_link_args, cvs, }; pub(crate) fn opts() -> TargetOptions { @@ -14,10 +16,11 @@ pub(crate) fn opts() -> TargetOptions { &["-nolibc", "--unwindlib=none"], ); // Order of `late_link_args*` does not matter with LLD. - let late_link_args = TargetOptions::link_args( - LinkerFlavor::Gnu(Cc::Yes, Lld::No), - &["-lmingw32", "-lmingwex", "-lmsvcrt", "-lkernel32", "-luser32"], - ); + let mingw_libs = &["-lmingw32", "-lmingwex", "-lmsvcrt", "-lkernel32", "-luser32"]; + + let mut late_link_args = + TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), mingw_libs); + add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), mingw_libs); TargetOptions { os: "windows".into(), @@ -35,6 +38,8 @@ pub(crate) fn opts() -> TargetOptions { binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, + pre_link_objects_self_contained: pre_mingw_self_contained(), + link_self_contained: LinkSelfContainedDefault::InferredForMingw, late_link_args, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs index 1a03390c2b89a..3b61a389f3452 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs @@ -6,6 +6,7 @@ pub(crate) fn target() -> Target { base.features = "+cx16,+sse3,+sahf".into(); base.plt_by_default = false; base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &["-m", "i386pep"]); base.max_atomic_width = Some(128); base.linker = Some("x86_64-w64-mingw32-clang".into()); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 87d54c2b5ad30..72756921bcd55 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -450,7 +450,7 @@ fn copy_self_contained_objects( DependencyType::TargetSelfContained, ); } - } else if target.is_windows_gnu() { + } else if target.is_windows_gnu() || target.is_windows_gnullvm() { for obj in ["crt2.o", "dllcrt2.o"].iter() { let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj); let dst = libdir_self_contained.join(obj); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 411d42962644d..b86e1e3c37b4b 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -344,6 +344,44 @@ fn runtime_dll_dist(rust_root: &Path, target: TargetSelection, builder: &Builder } } +fn make_win_llvm_dist(plat_root: &Path, target: TargetSelection, builder: &Builder<'_>) { + if builder.config.dry_run() { + return; + } + + let (_, lib_path) = get_cc_search_dirs(target, builder); + + // Libraries necessary to link the windows-gnu toolchains. + // System libraries will be preferred if they are available (see #67429). + let target_libs = [ + // MinGW libs + "libunwind.a", + "libunwind.dll.a", + "libmingw32.a", + "libmingwex.a", + "libmsvcrt.a", + // Windows import libs, remove them once std transitions to raw-dylib + "libkernel32.a", + "libuser32.a", + "libntdll.a", + "libuserenv.a", + "libws2_32.a", + "libdbghelp.a", + ]; + + //Find mingw artifacts we want to bundle + let target_libs = find_files(&target_libs, &lib_path); + + //Copy platform libs to platform-specific lib directory + let plat_target_lib_self_contained_dir = + plat_root.join("lib/rustlib").join(target).join("lib/self-contained"); + fs::create_dir_all(&plat_target_lib_self_contained_dir) + .expect("creating plat_target_lib_self_contained_dir failed"); + for src in target_libs { + builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir); + } +} + fn get_cc_search_dirs( target: TargetSelection, builder: &Builder<'_>, @@ -394,14 +432,20 @@ impl Step for Mingw { fn run(self, builder: &Builder<'_>) -> Option { let target = self.target; - if !target.ends_with("pc-windows-gnu") || !builder.config.dist_include_mingw_linker { + if !target.contains("pc-windows-gnu") || !builder.config.dist_include_mingw_linker { return None; } let mut tarball = Tarball::new(builder, "rust-mingw", &target.triple); tarball.set_product_name("Rust MinGW"); - make_win_dist(tarball.image_dir(), target, builder); + if target.ends_with("pc-windows-gnu") { + make_win_dist(tarball.image_dir(), target, builder); + } else if target.ends_with("pc-windows-gnullvm") { + make_win_llvm_dist(tarball.image_dir(), target, builder); + } else { + unreachable!(); + } Some(tarball.generate()) } diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index c2029f97391d4..c8cb2a2f2ac26 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -646,6 +646,8 @@ impl Builder<'_> { if let Mode::Rustc | Mode::ToolRustcPrivate | Mode::ToolBootstrap | Mode::ToolTarget = mode { rustflags.arg("--cfg=windows_raw_dylib"); + } else if mode == Mode::Std && target.ends_with("gnullvm") { + rustflags.arg("--cfg=windows_raw_dylib"); } if use_new_symbol_mangling { diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs index 40b63a7f9c752..47f6d6f386dfb 100644 --- a/src/bootstrap/src/core/config/target_selection.rs +++ b/src/bootstrap/src/core/config/target_selection.rs @@ -86,6 +86,10 @@ impl TargetSelection { self.ends_with("windows-gnu") } + pub fn is_windows_gnullvm(&self) -> bool { + self.ends_with("windows-gnullvm") + } + pub fn is_cygwin(&self) -> bool { self.is_windows() && // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html From 908e7204c27acfc1227e0b458985171bbd989c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Fri, 3 Oct 2025 23:11:58 +0200 Subject: [PATCH 2/5] Slightly refactor mingw detection --- compiler/rustc_codegen_ssa/src/back/link.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ea538d3d46981..9c56ba229baac 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -685,8 +685,8 @@ fn link_natively( codegen_backend: &'static str, ) { info!("preparing {:?} to {:?}", crate_type, out_filename); + let self_contained_components = self_contained_components(sess, crate_type); let (linker_path, flavor) = linker_and_flavor(sess); - let self_contained_components = self_contained_components(sess, crate_type, &linker_path); // On AIX, we ship all libraries as .a big_af archive // the expected format is lib.a(libname.so) for the actual @@ -1760,7 +1760,13 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { } // Returns true if linker is located within sysroot -fn detect_self_contained_mingw(sess: &Session, linker: &Path) -> bool { +fn detect_self_contained_mingw(sess: &Session) -> bool { + let linker = if let Some(linker) = &sess.target.linker { + Path::new(linker.as_ref()) + } else { + return false; + }; + // Assume `-C linker=rust-lld` as self-contained mode if linker == Path::new("rust-lld") { return true; @@ -1772,7 +1778,7 @@ fn detect_self_contained_mingw(sess: &Session, linker: &Path) -> bool { }; for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { let full_path = dir.join(&linker_with_extension); - // If linker comes from sysroot assume self-contained mode + // If linker doesn't come from sysroot assume non-self-contained mode if full_path.is_file() && !full_path.starts_with(sess.opts.sysroot.path()) { return false; } @@ -1783,11 +1789,7 @@ fn detect_self_contained_mingw(sess: &Session, linker: &Path) -> bool { /// Various toolchain components used during linking are used from rustc distribution /// instead of being found somewhere on the host system. /// We only provide such support for a very limited number of targets. -fn self_contained_components( - sess: &Session, - crate_type: CrateType, - linker: &Path, -) -> LinkSelfContainedComponents { +fn self_contained_components(sess: &Session, crate_type: CrateType) -> LinkSelfContainedComponents { // Turn the backwards compatible bool values for `self_contained` into fully inferred // `LinkSelfContainedComponents`. let self_contained = @@ -1816,7 +1818,7 @@ fn self_contained_components( LinkSelfContainedDefault::InferredForMingw => { sess.host == sess.target && sess.target.vendor != "uwp" - && detect_self_contained_mingw(sess, linker) + && detect_self_contained_mingw(sess) } } }; From dd203d6d7a1075719b0169422028a04da5e1acb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Thu, 9 Oct 2025 18:23:23 +0200 Subject: [PATCH 3/5] Use self-contained with windows-gnullvm --- compiler/rustc_codegen_ssa/src/back/link.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 9c56ba229baac..bdf822dfcd797 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -686,7 +686,8 @@ fn link_natively( ) { info!("preparing {:?} to {:?}", crate_type, out_filename); let self_contained_components = self_contained_components(sess, crate_type); - let (linker_path, flavor) = linker_and_flavor(sess); + let (linker_path, flavor) = + linker_and_flavor(sess, self_contained_components.is_linker_enabled()); // On AIX, we ship all libraries as .a big_af archive // the expected format is lib.a(libname.so) for the actual @@ -1314,7 +1315,7 @@ pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool } /// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use -pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { +pub fn linker_and_flavor(sess: &Session, self_contained: bool) -> (PathBuf, LinkerFlavor) { fn infer_from( sess: &Session, linker: Option, @@ -1413,6 +1414,15 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { return ret; } + // FIXME: do it better + if sess.target.os == "windows" + && sess.target.env == "gnu" + && sess.target.abi == "llvm" + && self_contained + { + return (PathBuf::from("rust-lld.exe"), LinkerFlavor::Gnu(Cc::No, Lld::Yes)); + } + if let Some(ret) = infer_from( sess, sess.target.linker.as_deref().map(PathBuf::from), From 66b6bc0710eca5109ede7796d284ca0699d2f1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Thu, 9 Oct 2025 19:39:18 +0200 Subject: [PATCH 4/5] Fix -C linker=rust-lld --- compiler/rustc_codegen_ssa/src/back/link.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index bdf822dfcd797..488b517e0f87c 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1771,8 +1771,16 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { // Returns true if linker is located within sysroot fn detect_self_contained_mingw(sess: &Session) -> bool { - let linker = if let Some(linker) = &sess.target.linker { - Path::new(linker.as_ref()) + // FIXME: this sort of duplicates `infer_from()` inside `linker_and_flavor()` + let path_buf = sess + .opts + .cg + .linker + .as_ref() + .map(|l| l.as_path()) + .or_else(|| sess.target.linker.as_ref().map(|linker| Path::new(linker.as_ref()))); + let linker = if let Some(linker) = path_buf { + linker } else { return false; }; From bc08890438b1d1c5627a29c6c9db2d30f45feb31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Thu, 9 Oct 2025 20:55:58 +0200 Subject: [PATCH 5/5] workaround for cranelift --- compiler/rustc_codegen_cranelift/src/toolchain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_cranelift/src/toolchain.rs b/compiler/rustc_codegen_cranelift/src/toolchain.rs index b6b465e1f4e0a..ecaf82ca16259 100644 --- a/compiler/rustc_codegen_cranelift/src/toolchain.rs +++ b/compiler/rustc_codegen_cranelift/src/toolchain.rs @@ -7,7 +7,7 @@ use rustc_session::Session; /// Tries to infer the path of a binary for the target toolchain from the linker name. pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf { - let (mut linker, _linker_flavor) = linker_and_flavor(sess); + let (mut linker, _linker_flavor) = linker_and_flavor(sess, false); let linker_file_name = linker.file_name().unwrap().to_str().expect("linker filename should be valid UTF-8");