Skip to content

Commit

Permalink
rust: get stdlib arguments for non-rust languages when linking
Browse files Browse the repository at this point in the history
Otherwise we might not get things like libstdc++, which we need.
  • Loading branch information
dcbaker committed Jun 27, 2023
1 parent 2439803 commit e96d359
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 12 deletions.
5 changes: 5 additions & 0 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
31 changes: 19 additions & 12 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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

Expand Down
18 changes: 18 additions & 0 deletions test cases/rust/20 rust and cpp/lib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright © 2023 Intel Corporation

#include "lib.hpp"

#include <string>

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);
}
8 changes: 8 additions & 0 deletions test cases/rust/20 rust and cpp/lib.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright © 2023 Intel Corporation

#include <cstddef>
#include <cstdint>

extern "C" uint64_t lib_length(const char * str);

19 changes: 19 additions & 0 deletions test cases/rust/20 rust and cpp/main.rs
Original file line number Diff line number Diff line change
@@ -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 })
}
14 changes: 14 additions & 0 deletions test cases/rust/20 rust and cpp/meson.build
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit e96d359

Please sign in to comment.