Skip to content
Merged
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
45 changes: 25 additions & 20 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from .. import mlog
from .. import compilers
from ..arglist import CompilerArgs
from ..compilers import Compiler
from ..compilers import Compiler, is_library
from ..linkers import ArLikeLinker, RSPFileSyntax
from ..mesonlib import (
File, LibType, MachineChoice, MesonBugException, MesonException, OrderedSet, PerMachine,
Expand Down Expand Up @@ -2038,18 +2038,28 @@ def get_rust_compiler_deps_and_args(self, target: build.BuildTarget, rustc: Comp
except (KeyError, AttributeError):
pass

if mesonlib.version_compare(rustc.version, '>= 1.67.0'):
verbatim = '+verbatim'
else:
verbatim = ''

def _link_library(libname: str, static: bool, bundle: bool = False) -> None:
orig_libname = libname
type_ = 'static' if static else 'dylib'
modifiers = []
# Except with -Clink-arg, search is limited to the -L search paths
dir_, libname = os.path.split(libname)
linkdirs.add(dir_)
if not bundle and static:
modifiers.append('-bundle')
if verbatim:
modifiers.append(verbatim)
if rustc.has_verbatim():
modifiers.append('+verbatim')
else:
# undo the effects of -l without verbatim
badname = not is_library(libname)
libname, ext = os.path.splitext(libname)
if libname.startswith('lib'):
libname = libname[3:]
else:
badname = True
if badname:
raise MesonException(f"rustc does not implement '-l{type_}:+verbatim'; cannot link to '{orig_libname}' due to nonstandard name")

if modifiers:
type_ += ':' + ','.join(modifiers)
args.append(f'-l{type_}={libname}')
Expand All @@ -2062,11 +2072,11 @@ def _link_library(libname: str, static: bool, bundle: bool = False) -> None:
external_deps = target.external_deps.copy()
target_deps = target.get_dependencies()
for d in target_deps:
linkdirs.add(d.subdir)
deps.append(self.get_dependency_filename(d))
if isinstance(d, build.StaticLibrary):
external_deps.extend(d.external_deps)
if d.uses_rust_abi():
linkdirs.add(d.subdir)
if d not in itertools.chain(target.link_targets, target.link_whole_targets):
# Indirect Rust ABI dependency, we only need its path in linkdirs.
continue
Expand Down Expand Up @@ -2094,8 +2104,7 @@ def _link_library(libname: str, static: bool, bundle: bool = False) -> None:
link_whole = d in target.link_whole_targets
if isinstance(target, build.StaticLibrary) or (isinstance(target, build.Executable) and rustc.get_crt_static()):
static = isinstance(d, build.StaticLibrary)
libname = os.path.basename(lib) if verbatim else d.name
_link_library(libname, static, bundle=link_whole)
_link_library(lib, static, bundle=link_whole)
elif link_whole:
link_whole_args = rustc.linker.get_link_whole_for([lib])
args += [f'-Clink-arg={a}' for a in link_whole_args]
Expand All @@ -2110,19 +2119,15 @@ def _link_library(libname: str, static: bool, bundle: bool = False) -> None:
elif a.startswith('-L'):
args.append(a)
continue
elif a.endswith(('.dll', '.so', '.dylib', '.a', '.lib')):
dir_, lib = os.path.split(a)
linkdirs.add(dir_)

elif is_library(a):
if isinstance(target, build.StaticLibrary):
if not verbatim:
lib, ext = os.path.splitext(lib)
if lib.startswith('lib'):
lib = lib[3:]
static = a.endswith(('.a', '.lib'))
_link_library(lib, static)
_link_library(a, static)
continue

dir_, _ = os.path.split(lib)
linkdirs.add(dir_)

args.append(f'-Clink-arg={a}')

for d in linkdirs:
Expand Down
16 changes: 15 additions & 1 deletion mesonbuild/compilers/rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import typing as T

from .. import options
from ..mesonlib import EnvironmentException, MesonException, Popen_safe_logged
from ..mesonlib import EnvironmentException, MesonException, Popen_safe_logged, version_compare
from ..options import OptionKey
from .compilers import Compiler, CompileCheckMode, clike_debug_args

Expand Down Expand Up @@ -194,6 +194,20 @@ def get_cfgs(self) -> T.List[str]:
def get_crt_static(self) -> bool:
return 'target_feature="crt-static"' in self.get_cfgs()

@functools.lru_cache(maxsize=None)
def has_verbatim(self) -> bool:
if version_compare(self.version, '< 1.67.0'):
return False
# GNU ld support '-l:PATH'
if 'ld.' in self.linker.id:
return True
# -l:+verbatim does not work (yet?) with MSVC link or Apple ld64
# (https://github.com/rust-lang/rust/pull/138753). For ld64, it
# works together with -l:+whole_archive because -force_load (the macOS
# equivalent of --whole-archive), receives the full path to the library
# being linked. However, Meson uses "bundle", not "whole_archive".
return False

def get_debug_args(self, is_debug: bool) -> T.List[str]:
return clike_debug_args[is_debug]

Expand Down
3 changes: 3 additions & 0 deletions test cases/rust/3 staticlib/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ v = static_library('value', 'value.c')
l = static_library('stuff', 'stuff.rs', link_whole : [o, v], install : true)
e = executable('prog', 'prog.rs', link_with : l, install : true)
test('linktest', e)

l = static_library('stuff2', 'stuff2.rs', link_with : [o, v])
e = executable('prog2', 'prog2.rs', link_with : l)
5 changes: 5 additions & 0 deletions test cases/rust/3 staticlib/prog2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extern crate stuff2;

fn main() {
println!("printing: {}", stuff2::explore());
}
14 changes: 14 additions & 0 deletions test cases/rust/3 staticlib/stuff2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![crate_name = "stuff2"]

extern crate other;

extern "C" {
fn c_explore_value() -> i32;
}

pub fn explore(
) -> String {
unsafe {
other::explore(c_explore_value())
}
}
Loading