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 a special rust procedural macro crate.
"proc-macro" is new in 0.62.0. "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_extensions import Literal
from .._typing import ImmutableListProtocol from .._typing import ImmutableListProtocol
from ..build import ExtractedObjects from ..build import ExtractedObjects, LibTypes
from ..interpreter import Interpreter from ..interpreter import Interpreter
from ..linkers import DynamicLinker, StaticLinker from ..linkers import DynamicLinker, StaticLinker
from ..compilers.cs import CsCompiler from ..compilers.cs import CsCompiler
@ -1830,6 +1830,12 @@ class NinjaBackend(backends.Backend):
self.rust_crates[name] = crate 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: def generate_rust_target(self, target: build.BuildTarget) -> None:
rustc = target.compilers['rust'] rustc = target.compilers['rust']
# Rust compiler takes only the main file as input and # 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 # specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust
# dependency, so that collisions with libraries in rustc's # dependency, so that collisions with libraries in rustc's
# sysroot don't cause ambiguity # sysroot don't cause ambiguity
# d_name = self._get_rust_dependency_name(target, d)
# 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('-', '_')
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))] args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order)) project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
elif isinstance(d, build.StaticLibrary): elif isinstance(d, build.StaticLibrary):
@ -1979,11 +1981,7 @@ class NinjaBackend(backends.Backend):
# specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust # specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust
# dependency, so that collisions with libraries in rustc's # dependency, so that collisions with libraries in rustc's
# sysroot don't cause ambiguity # sysroot don't cause ambiguity
# d_name = self._get_rust_dependency_name(target, d)
# 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('-', '_')
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))] args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order)) project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
else: else:

@ -74,7 +74,7 @@ lang_arg_kwargs |= {
} }
vala_kwargs = {'vala_header', 'vala_gir', 'vala_vapi'} 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'} cs_kwargs = {'resources', 'cs_args'}
buildtarget_kwargs = { buildtarget_kwargs = {
@ -1239,6 +1239,13 @@ class BuildTarget(Target):
if self.gnu_symbol_visibility not in permitted: if self.gnu_symbol_visibility not in permitted:
raise InvalidArguments('GNU symbol visibility arg {} not one of: {}'.format(self.gnu_symbol_visibility, ', '.join(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: def validate_win_subsystem(self, value: str) -> str:
value = value.lower() 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: 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}.') raise InterpreterException(f'Unknown default_library value: {default_library}.')
def build_target(self, node: mparser.BaseNode, args, kwargs, targetclass): 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.42.0', ['rust_crate_type', 'build_rpath', 'implicit_include_directories'])
@FeatureNewKwargs('build target', '0.41.0', ['rust_args']) @FeatureNewKwargs('build target', '0.41.0', ['rust_args'])
@FeatureNewKwargs('build target', '0.38.0', ['build_by_default']) @FeatureNewKwargs('build target', '0.38.0', ['build_by_default'])

@ -1,4 +1,4 @@
#[no_mangle] #[no_mangle]
pub extern "C" fn what_have_we_here() -> i32 { 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') 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 # Even though leaf is linked using link_with, this gets implicitly promoted to link_whole because
# it is an internal Rust project. # 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) e = executable('prog', 'prog.c', link_with : branch, install : true)
test('linktest', e) test('linktest', e)

Loading…
Cancel
Save