Skip to content

Commit 5a4897d

Browse files
committed
modules: rust: add package.executable
Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 000275e commit 5a4897d

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

docs/markdown/Rust-module.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,7 @@ Example usage:
242242
rust = import('rust')
243243
cargo = rust.workspace()
244244
pkg = cargo.package()
245-
246-
executable('my_app', 'src/main.rs',
247-
dependencies: pkg.dependencies(),
248-
rust_args: pkg.rust_args(),
249-
rust_dependency_map: pkg.rust_dependency_map(),
250-
)
245+
pkg.executable(install: true)
251246
```
252247

253248
### workspace.subproject()
@@ -379,6 +374,26 @@ Builds a proc-macro crate for a workspace package.
379374

380375
Accepts all keyword arguments from [[shared_library]].
381376

377+
#### package.executable()
378+
379+
```meson
380+
exe = pkg.executable([target_name], [sources], ...)
381+
```
382+
383+
Builds an executable target for a workspace package. The method requires that the
384+
package has at least one `[[bin]]` section defined in its `Cargo.toml` file,
385+
or one binary discovered from the contents of the file system.
386+
387+
Positional arguments:
388+
- `target_name`: (`str`, optional) Name of the binary target to build. If the package
389+
has multiple `[[bin]]` sections in `Cargo.toml`, this argument is required and must
390+
match one of the binary names. If omitted and there's only one binary, that binary
391+
will be built automatically.
392+
- `sources`: (`StructuredSources`, optional) Source files for the executable. If omitted,
393+
uses the path specified in the corresponding `[[bin]]` section of `Cargo.toml`.
394+
395+
Accepts all keyword arguments from [[executable]].
396+
382397
### Subprojects only
383398

384399
#### subproject.dependency()

mesonbuild/modules/rust.py

Lines changed: 44 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
@@ -77,6 +77,11 @@ class FuncWorkspace(TypedDict):
7777
class FuncDependency(TypedDict):
7878
rust_abi: T.Optional[RUST_ABI]
7979

80+
class RustPackageExecutable(_kwargs.Executable):
81+
dependencies: T.List[T.Union[Dependency, ExternalLibrary]]
82+
link_with: T.List[LibTypes]
83+
link_whole: T.List[LibTypes]
84+
8085
class RustPackageLibrary(_kwargs.Library):
8186
dependencies: T.List[T.Union[Dependency, ExternalLibrary]]
8287
link_with: T.List[LibTypes]
@@ -243,6 +248,7 @@ def __init__(self, rust_ws: RustWorkspace, package: cargo.PackageState) -> None:
243248
'dependencies': self.dependencies_method,
244249
'library': self.library_method,
245250
'proc_macro': self.proc_macro_method,
251+
'executable': self.executable_method,
246252
})
247253

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

293-
def merge_kw_args(self, state: ModuleState, kwargs: RustPackageLibrary) -> None:
299+
def merge_kw_args(self, state: ModuleState, kwargs: T.Union[RustPackageExecutable, RustPackageLibrary]) -> None:
294300
deps = kwargs['dependencies']
295301
kwargs['dependencies'] = self.dependencies_method(state, [], {})
296302
kwargs['dependencies'].extend(deps)
@@ -382,6 +388,42 @@ def proc_macro_method(self, state: 'ModuleState', args: T.Tuple[
382388
result = self._library_method(state, args, kwargs)
383389
return T.cast('SharedLibrary', result)
384390

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

386428
class RustSubproject(RustCrate):
387429
"""Represents a Cargo subproject."""

0 commit comments

Comments
 (0)