Skip to content

Commit 3c6e981

Browse files
committed
modules: rust: add package.executable
Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 8401afd commit 3c6e981

File tree

2 files changed

+66
-8
lines changed

2 files changed

+66
-8
lines changed

docs/markdown/Rust-module.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,7 @@ Example usage:
272272
rust = import('rust')
273273
cargo = rust.workspace()
274274
pkg = cargo.package()
275-
276-
executable('my_app', 'src/main.rs',
277-
dependencies: pkg.dependencies(),
278-
rust_args: pkg.rust_args(),
279-
rust_dependency_map: pkg.rust_dependency_map(),
280-
)
275+
pkg.executable(install: true)
281276
```
282277

283278
### workspace.subproject()
@@ -409,6 +404,26 @@ Builds a proc-macro crate for a workspace package.
409404

410405
Accepts all keyword arguments from [[shared_library]].
411406

407+
#### package.executable()
408+
409+
```meson
410+
exe = pkg.executable([target_name], [sources], ...)
411+
```
412+
413+
Builds an executable target for a workspace package. The method requires that the
414+
package has at least one `[[bin]]` section defined in its `Cargo.toml` file,
415+
or one binary discovered from the contents of the file system.
416+
417+
Positional arguments:
418+
- `target_name`: (`str`, optional) Name of the binary target to build. If the package
419+
has multiple `[[bin]]` sections in `Cargo.toml`, this argument is required and must
420+
match one of the binary names. If omitted and there's only one binary, that binary
421+
will be built automatically.
422+
- `sources`: (`StructuredSources`, optional) Source files for the executable. If omitted,
423+
uses the path specified in the corresponding `[[bin]]` section of `Cargo.toml`.
424+
425+
Accepts all keyword arguments from [[executable]].
426+
412427
### Subprojects only
413428

414429
#### subproject.dependency()

mesonbuild/modules/rust.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from ..interpreter.type_checking import (
2121
DEPENDENCIES_KW, LINK_WITH_KW, LINK_WHOLE_KW, SHARED_LIB_KWS, TEST_KWS, TEST_KWS_NO_ARGS,
2222
OUTPUT_KW, INCLUDE_DIRECTORIES, SOURCES_VARARGS, NoneType, in_set_validator,
23-
LIBRARY_KWS, _BASE_LANG_KW
23+
EXECUTABLE_KWS, LIBRARY_KWS, _BASE_LANG_KW
2424
)
2525
from ..interpreterbase import ContainerTypeInfo, InterpreterException, KwargInfo, typed_kwargs, typed_pos_args, noKwargs, noPosargs, permittedKwargs
2626
from ..interpreter.interpreterobjects import Doctest
@@ -76,6 +76,11 @@ class FuncWorkspace(TypedDict):
7676
class FuncDependency(TypedDict):
7777
rust_abi: T.Optional[RUST_ABI]
7878

79+
class RustPackageExecutable(_kwargs.Executable):
80+
dependencies: T.List[T.Union[Dependency, ExternalLibrary]]
81+
link_with: T.List[LibTypes]
82+
link_whole: T.List[LibTypes]
83+
7984
class RustPackageLibrary(_kwargs.Library):
8085
dependencies: T.List[T.Union[Dependency, ExternalLibrary]]
8186
link_with: T.List[LibTypes]
@@ -242,6 +247,7 @@ def __init__(self, rust_ws: RustWorkspace, package: cargo.PackageState) -> None:
242247
'dependencies': self.dependencies_method,
243248
'library': self.library_method,
244249
'proc_macro': self.proc_macro_method,
250+
'executable': self.executable_method,
245251
})
246252

247253
@noPosargs
@@ -289,7 +295,7 @@ def validate_pos_args(name: str, args: T.Tuple[
289295
raise MesonException(f"{name} only accepts one StructuredSources parameter")
290296
return None, args[0]
291297

292-
def merge_kw_args(self, state: ModuleState, kwargs: RustPackageLibrary) -> None:
298+
def merge_kw_args(self, state: ModuleState, kwargs: T.Union[RustPackageExecutable, RustPackageLibrary]) -> None:
293299
deps = kwargs['dependencies']
294300
kwargs['dependencies'] = self.dependencies_method(state, [], {})
295301
kwargs['dependencies'].extend(deps)
@@ -394,6 +400,43 @@ def proc_macro_method(self, state: 'ModuleState', args: T.Tuple[
394400
raise MesonException("not a procedural macro crate")
395401
return self._proc_macro_method(state, args, kwargs)
396402

403+
@typed_pos_args('package.executable', optargs=[(str, StructuredSources), StructuredSources])
404+
@typed_kwargs(
405+
'package.executable',
406+
*EXECUTABLE_KWS,
407+
DEPENDENCIES_KW,
408+
LINK_WITH_KW,
409+
LINK_WHOLE_KW,
410+
_BASE_LANG_KW.evolve(name='rust_args'),
411+
)
412+
def executable_method(self, state: 'ModuleState', args: T.Tuple[
413+
T.Optional[T.Union[str, StructuredSources]],
414+
T.Optional[StructuredSources]], kwargs: RustPackageExecutable) -> Executable:
415+
"""Builds executable targets from workspace bins."""
416+
tgt_args = self.validate_pos_args('package.executable', args)
417+
if not self.package.manifest.bin:
418+
raise MesonException("no [[bin]] section in Cargo package")
419+
420+
sources: T.Union[StructuredSources, str]
421+
tgt_name, sources = tgt_args
422+
# If there's more than one binary, the first argument must be specified
423+
# and must be one of the keys in pkg.bin
424+
if not tgt_name:
425+
if len(self.package.manifest.bin) > 1:
426+
raise MesonException("Package has multiple binaries, you must specify which one to build as the first argument")
427+
# Single binary, use it
428+
tgt_name = next(iter(self.package.manifest.bin.keys()))
429+
else:
430+
if tgt_name not in self.package.manifest.bin:
431+
raise MesonException(f"Binary '{tgt_name}' not found.")
432+
433+
if not sources:
434+
sources = self.package.manifest.bin[tgt_name].path
435+
436+
exe_args: T.Tuple[str, SourcesVarargsType] = (tgt_name, [sources])
437+
self.merge_kw_args(state, kwargs)
438+
return state._interpreter.build_target(state.current_node, exe_args, kwargs, Executable)
439+
397440

398441
class RustSubproject(RustCrate):
399442
"""Represents a Cargo subproject."""

0 commit comments

Comments
 (0)