From e96d359c7f0e00b018459a0802fd89ae679f25d0 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 22 Jun 2023 11:43:35 -0700 Subject: [PATCH] rust: get stdlib arguments for non-rust languages when linking Otherwise we might not get things like libstdc++, which we need. --- mesonbuild/backend/ninjabackend.py | 5 ++++ mesonbuild/build.py | 31 +++++++++++++-------- test cases/rust/20 rust and cpp/lib.cpp | 18 ++++++++++++ test cases/rust/20 rust and cpp/lib.hpp | 8 ++++++ test cases/rust/20 rust and cpp/main.rs | 19 +++++++++++++ test cases/rust/20 rust and cpp/meson.build | 14 ++++++++++ 6 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 test cases/rust/20 rust and cpp/lib.cpp create mode 100644 test cases/rust/20 rust and cpp/lib.hpp create mode 100644 test cases/rust/20 rust and cpp/main.rs create mode 100644 test cases/rust/20 rust and cpp/meson.build diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index b36e12524210..21d7baf71fec 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2040,6 +2040,11 @@ def generate_rust_target(self, target: build.BuildTarget) -> None: if d == '': d = '.' args += ['-L', d] + + # Because of the way rustc links, this must come after any potential + # library need to link with their stdlibs (C++ and Fortran, for example) + args.extend(target.get_used_stdlib_args('rust')) + target_deps = target.get_dependencies() has_shared_deps = any(isinstance(dep, build.SharedLibrary) for dep in target_deps) has_rust_shared_deps = any(dep.uses_rust() diff --git a/mesonbuild/build.py b/mesonbuild/build.py index b9525987de24..1ecab0d7d210 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -698,6 +698,15 @@ class BuildTarget(Target): install_dir: T.List[T.Union[str, Literal[False]]] + # This set contains all the languages a linker can link natively + # without extra flags. For instance, nvcc (cuda) can link C++ + # without injecting -lc++/-lstdc++, see + # https://github.com/mesonbuild/meson/issues/10570 + _MASK_LANGS: T.FrozenSet[T.Tuple[str, str]] = frozenset([ + # (language, linker) + ('cpp', 'cuda'), + ]) + def __init__( self, name: str, @@ -1579,14 +1588,6 @@ def get_clink_dynamic_linker_and_stdlibs(self) -> T.Tuple['Compiler', T.List[str # Languages used by dependencies dep_langs = self.get_langs_used_by_deps() - # This set contains all the languages a linker can link natively - # without extra flags. For instance, nvcc (cuda) can link C++ - # without injecting -lc++/-lstdc++, see - # https://github.com/mesonbuild/meson/issues/10570 - MASK_LANGS = frozenset([ - # (language, linker) - ('cpp', 'cuda'), - ]) # Pick a compiler based on the language priority-order for l in clink_langs: if l in self.compilers or l in dep_langs: @@ -1597,10 +1598,7 @@ def get_clink_dynamic_linker_and_stdlibs(self) -> T.Tuple['Compiler', T.List[str f'Could not get a dynamic linker for build target {self.name!r}. ' f'Requires a linker for language "{l}", but that is not ' 'a project language.') - stdlib_args: T.List[str] = [] - for dl in itertools.chain(self.compilers, dep_langs): - if dl != linker.language and (dl, linker.language) not in MASK_LANGS: - stdlib_args += all_compilers[dl].language_stdlib_only_link_flags(self.environment) + stdlib_args: T.List[str] = self.get_used_stdlib_args(linker.language) # Type of var 'linker' is Compiler. # Pretty hard to fix because the return value is passed everywhere return linker, stdlib_args @@ -1616,6 +1614,15 @@ def get_clink_dynamic_linker_and_stdlibs(self) -> T.Tuple['Compiler', T.List[str raise AssertionError(f'Could not get a dynamic linker for build target {self.name!r}') + def get_used_stdlib_args(self, link_language: str) -> T.List[str]: + all_compilers = self.environment.coredata.compilers[self.for_machine] + all_langs = set(all_compilers).union(self.get_langs_used_by_deps()) + stdlib_args: T.List[str] = [] + for dl in all_langs: + if dl != link_language and (dl, link_language) not in self._MASK_LANGS: + stdlib_args.extend(all_compilers[dl].language_stdlib_only_link_flags(self.environment)) + return stdlib_args + def uses_rust(self) -> bool: return 'rust' in self.compilers diff --git a/test cases/rust/20 rust and cpp/lib.cpp b/test cases/rust/20 rust and cpp/lib.cpp new file mode 100644 index 000000000000..b08f870e2422 --- /dev/null +++ b/test cases/rust/20 rust and cpp/lib.cpp @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2023 Intel Corporation + +#include "lib.hpp" + +#include + +namespace { + +uint64_t priv_length(const std::string & str) { + return str.length(); +} + +} + +extern "C" uint64_t lib_length(const char * str) { + return priv_length(str); +} diff --git a/test cases/rust/20 rust and cpp/lib.hpp b/test cases/rust/20 rust and cpp/lib.hpp new file mode 100644 index 000000000000..63093c4c1179 --- /dev/null +++ b/test cases/rust/20 rust and cpp/lib.hpp @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2023 Intel Corporation + +#include +#include + +extern "C" uint64_t lib_length(const char * str); + diff --git a/test cases/rust/20 rust and cpp/main.rs b/test cases/rust/20 rust and cpp/main.rs new file mode 100644 index 000000000000..b048cac2bfb1 --- /dev/null +++ b/test cases/rust/20 rust and cpp/main.rs @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2023 Intel Corporation + +use std::ffi::CString; +use std::os::raw::c_char; + +extern "C" { + fn lib_length(s: *const c_char) -> u64; +} + +fn main() { + let len: u64; + unsafe { + let c_str = CString::new("Hello, world!").unwrap(); + len = lib_length(c_str.as_ptr()); + } + + std::process::exit(if len == 13 { 0 } else { 1 }) +} diff --git a/test cases/rust/20 rust and cpp/meson.build b/test cases/rust/20 rust and cpp/meson.build new file mode 100644 index 000000000000..c3010123a816 --- /dev/null +++ b/test cases/rust/20 rust and cpp/meson.build @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2023 Intel Corporation + +project( + 'Rust and C++', + 'rust', 'cpp', + default_options : ['cpp_std=c++14'], + meson_version : '>= 1.2.0', +) + +cpplib = static_library('cpp', 'lib.cpp') +exe = executable('main', 'main.rs', link_with : cpplib) + +test('main', exe)