rust: Add new `rust_dependency_map` target configuration

This allows changing the crate name with which a library ends up being
available inside the Rust code, similar to cargo's dependency renaming
feature or `extern crate foo as bar` inside Rust code.
pull/11716/head
Sebastian Dröge 2 years ago committed by Xavier Claessens
parent 474e3ea8af
commit 01420bf8fc
  1. 18
      docs/markdown/snippets/rust_dependency_map.md
  2. 10
      docs/yaml/functions/_build_target_base.yaml
  3. 20
      mesonbuild/backend/ninjabackend.py
  4. 9
      mesonbuild/build.py
  5. 1
      mesonbuild/interpreter/interpreter.py
  6. 2
      test cases/rust/17 staticlib link staticlib/branch.rs
  7. 2
      test cases/rust/17 staticlib link staticlib/meson.build

@ -0,0 +1,18 @@
## Support for defining crate names of Rust dependencies in Rust targets
Rust supports defining a different crate name for a dependency than what the
actual crate name during compilation of that dependency was.
This allows using multiple versions of the same crate at once, or simply using
a shorter name of the crate for convenience.
```meson
a_dep = dependency('some-very-long-name')
my_executable = executable('my-executable', 'src/main.rs',
rust_dependency_map : {
'some_very_long_name' : 'a',
},
dependencies : [a_dep],
)
```

@ -302,3 +302,13 @@ kwargs:
"proc-macro" is a special rust procedural macro crate.
"proc-macro" is new in 0.62.0.
rust_dependency_map:
type: dict[str]
since: 1.2.0
description: |
On rust targets this provides a map of library names to the crate name
with which it would be available inside the rust code.
This allows renaming similar to the dependency renaming feature of cargo
or `extern crate foo as bar` inside rust code.

@ -50,7 +50,7 @@ if T.TYPE_CHECKING:
from typing_extensions import Literal
from .._typing import ImmutableListProtocol
from ..build import ExtractedObjects
from ..build import ExtractedObjects, LibTypes
from ..interpreter import Interpreter
from ..linkers import DynamicLinker, StaticLinker
from ..compilers.cs import CsCompiler
@ -1830,6 +1830,12 @@ class NinjaBackend(backends.Backend):
self.rust_crates[name] = crate
def _get_rust_dependency_name(self, target: build.BuildTarget, dependency: LibTypes) -> str:
# Convert crate names with dashes to underscores by default like
# cargo does as dashes can't be used as parts of identifiers
# in Rust
return target.rust_dependency_map.get(dependency.name, dependency.name).replace('-', '_')
def generate_rust_target(self, target: build.BuildTarget) -> None:
rustc = target.compilers['rust']
# Rust compiler takes only the main file as input and
@ -1936,11 +1942,7 @@ class NinjaBackend(backends.Backend):
# specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust
# dependency, so that collisions with libraries in rustc's
# sysroot don't cause ambiguity
#
# Also convert crate names with dashes to underscores like
# cargo does as dashes can't be used as parts of identifiers
# in Rust
d_name = d.name.replace('-', '_')
d_name = self._get_rust_dependency_name(target, d)
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
elif isinstance(d, build.StaticLibrary):
@ -1979,11 +1981,7 @@ class NinjaBackend(backends.Backend):
# specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust
# dependency, so that collisions with libraries in rustc's
# sysroot don't cause ambiguity
#
# Also convert crate names with dashes to underscores like
# cargo does as dashes can't be used as parts of identifiers
# in Rust
d_name = d.name.replace('-', '_')
d_name = self._get_rust_dependency_name(target, d)
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
else:

@ -74,7 +74,7 @@ lang_arg_kwargs |= {
}
vala_kwargs = {'vala_header', 'vala_gir', 'vala_vapi'}
rust_kwargs = {'rust_crate_type'}
rust_kwargs = {'rust_crate_type', 'rust_dependency_map'}
cs_kwargs = {'resources', 'cs_args'}
buildtarget_kwargs = {
@ -1239,6 +1239,13 @@ class BuildTarget(Target):
if self.gnu_symbol_visibility not in permitted:
raise InvalidArguments('GNU symbol visibility arg {} not one of: {}'.format(self.gnu_symbol_visibility, ', '.join(permitted)))
rust_dependency_map = kwargs.get('rust_dependency_map', {})
if not isinstance(rust_dependency_map, dict):
raise InvalidArguments(f'Invalid rust_dependency_map "{rust_dependency_map}": must be a dictionary.')
if any(not isinstance(v, str) for v in rust_dependency_map.values()):
raise InvalidArguments(f'Invalid rust_dependency_map "{rust_dependency_map}": must be a dictionary with string values.')
self.rust_dependency_map = rust_dependency_map
def validate_win_subsystem(self, value: str) -> str:
value = value.lower()
if re.fullmatch(r'(boot_application|console|efi_application|efi_boot_service_driver|efi_rom|efi_runtime_driver|native|posix|windows)(,\d+(\.\d+)?)?', value) is None:

@ -3183,6 +3183,7 @@ class Interpreter(InterpreterBase, HoldableObject):
raise InterpreterException(f'Unknown default_library value: {default_library}.')
def build_target(self, node: mparser.BaseNode, args, kwargs, targetclass):
@FeatureNewKwargs('build target', '1.2.0', ['rust_dependency_map'])
@FeatureNewKwargs('build target', '0.42.0', ['rust_crate_type', 'build_rpath', 'implicit_include_directories'])
@FeatureNewKwargs('build target', '0.41.0', ['rust_args'])
@FeatureNewKwargs('build target', '0.38.0', ['build_by_default'])

@ -1,4 +1,4 @@
#[no_mangle]
pub extern "C" fn what_have_we_here() -> i32 {
leaf::HOW_MANY * leaf::HOW_MANY
myleaf::HOW_MANY * myleaf::HOW_MANY
}

@ -3,6 +3,6 @@ project('staticlib link staticlib', 'c', 'rust')
leaf = static_library('leaf', 'leaf.rs', rust_crate_type : 'rlib')
# Even though leaf is linked using link_with, this gets implicitly promoted to link_whole because
# it is an internal Rust project.
branch = static_library('branch', 'branch.rs', link_with: leaf, rust_crate_type : 'staticlib', install : true)
branch = static_library('branch', 'branch.rs', link_with: leaf, rust_crate_type : 'staticlib', rust_dependency_map : { 'leaf' : 'myleaf' }, install : true)
e = executable('prog', 'prog.c', link_with : branch, install : true)
test('linktest', e)

Loading…
Cancel
Save