From 1aac6cc1ec380a14519822d1a2bdf3e5850de68b Mon Sep 17 00:00:00 2001 From: Florent Valette Date: Tue, 30 Jul 2024 11:36:50 +0200 Subject: [PATCH] compiler,rust: fix sanity check and internal deps for baremetal rust project/target Sanity check for bare metal rust wasn't working for a while and there is a pending PR (#12175). To workaround this problem, we used to let sanity check for build machine and manually defined rustc target. Commit 18f8aeda8b59a132f24fa1af800ff65cac2f61f4 breaks this workaround as, even without an exe_wrapper, native_static_libs are appends as internal deps. This behaviour makes sense for cross compiled rust in a rich environment but not any for no-std rust. As said in comments, one can't tell if the code is no-std or not because this is an annotation from sources. From our point of view, it is pretty clear that building a no-std rust target means that one has to define system='bare metal' and kernel='none' in his cross-file. According to that, sanity_check for rust compiler is modified to handle kernel == 'none' case by building a specific no-std rust snippet, with an extra args if rust_ld is ls.bfd (in order to prevent the linker to link with a potentially non existing startfile for the given target). 'native_static_libs' is also leave empty in that very case. This commit fix the spurious native static libs for no-std case and allow us to remove our dirty workaround which by-passed non working sanity check for bare metal rust. One who wants to use meson for baremetal Rust project only have to define the rust target in their cross file. e.g. rust = ['rustc', '--target', ''] --- mesonbuild/build.py | 5 +++++ mesonbuild/compilers/rust.py | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 5eff0ed80..460ed549b 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -2133,6 +2133,11 @@ class StaticLibrary(BuildTarget): if self.rust_crate_type == 'staticlib': # FIXME: In the case of no-std we should not add those libraries, # but we have no way to know currently. + + # XXX: + # In the case of no-std, we are likely in a bare metal case + # and thus, machine_info kernel should be set to 'none'. + # In that case, native_static_libs list is empty. rustc = self.compilers['rust'] d = dependencies.InternalDependency('undefined', [], [], rustc.native_static_libs, diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index d071559da..f09911db6 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -76,13 +76,33 @@ class RustCompiler(Compiler): def sanity_check(self, work_dir: str, environment: 'Environment') -> None: source_name = os.path.join(work_dir, 'sanity.rs') output_name = os.path.join(work_dir, 'rusttest') - with open(source_name, 'w', encoding='utf-8') as ofile: - ofile.write(textwrap.dedent( - '''fn main() { - } - ''')) + cmdlist = self.exelist.copy() - cmdlist = self.exelist + ['-o', output_name, source_name] + with open(source_name, 'w', encoding='utf-8') as ofile: + # If machine kernel is not `none`, try to compile a dummy program. + # If 'none', this is likely a `no-std`(i.e. bare metal) project. + if self.info.kernel != 'none': + ofile.write(textwrap.dedent( + '''fn main() { + } + ''')) + else: + # If rustc linker is gcc, add `-nostartfiles` + if 'ld.' in self.linker.id: + cmdlist.extend(['-C', 'link-arg=-nostartfiles']) + ofile.write(textwrap.dedent( + '''#![no_std] + #![no_main] + #[no_mangle] + pub fn _start() { + } + #[panic_handler] + fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} + } + ''')) + + cmdlist.extend(['-o', output_name, source_name]) pc, stdo, stde = Popen_safe_logged(cmdlist, cwd=work_dir) if pc.returncode != 0: raise EnvironmentException(f'Rust compiler {self.name_string()} cannot compile programs.') @@ -107,6 +127,10 @@ class RustCompiler(Compiler): raise EnvironmentException('Rust compiler cannot compile staticlib.') match = re.search('native-static-libs: (.*)$', stde, re.MULTILINE) if not match: + if self.info.kernel == 'none': + # no match and kernel == none (i.e. baremetal) is a valid use case. + # return and let native_static_libs list empty + return raise EnvironmentException('Failed to find native-static-libs in Rust compiler output.') # Exclude some well known libraries that we don't need because they # are always part of C/C++ linkers. Rustc probably should not print