Skip to content

Commit

Permalink
interpreter: Add support for cargo subproject
Browse files Browse the repository at this point in the history
  • Loading branch information
xclaesse committed Jun 10, 2023
1 parent a2181bb commit be44e8c
Show file tree
Hide file tree
Showing 15 changed files with 90 additions and 10 deletions.
21 changes: 21 additions & 0 deletions docs/markdown/Wrap-dependency-system-manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ previously reserved to `wrap-file`:
Supported methods:
- `meson` requires `meson.build` file.
- `cmake` requires `CMakeLists.txt` file. [See details](#cmake-wraps).
- `cargo` requires `Cargo.toml` file. [See details](#cargo-wraps).

### Specific to wrap-file
- `source_url` - download url to retrieve the wrap-file source archive
Expand Down Expand Up @@ -307,6 +308,26 @@ method = cmake
[provide]
foo-bar-1.0 = foo_bar_dep
```
### Cargo wraps

Cargo subprojects automatically override the `<package_name>-rs` dependency name.
`package_name` is defined in `[package] name = ...` section of the `Cargo.toml`
and `-rs` suffix is added. That means the `.wrap` file should have
`dependency_names = foo-rs` in their `[provide]` section when `Cargo.toml` has
package name `foo`.

Cargo subprojects require a toml parser. Python >= 3.11 have one built-in, older
Python versions require either the external `tomli` module or `toml2json` program.

For example, a Cargo project with the package name `foo-bar` would have a wrap
file like that:
```ini
[wrap-file]
...
method = cargo
[provide]
dependency_names = foo-bar-rs
```

## Using wrapped projects

Expand Down
3 changes: 2 additions & 1 deletion docs/markdown/snippets/wrap.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Automatic fallback to `cmake` subproject
## Automatic fallback to `cmake` and `cargo` subproject

CMake subprojects have been supported for a while using the `cmake.subproject()`
module method. However until now it was not possible to use a CMake subproject
Expand All @@ -10,3 +10,4 @@ key in the wrap file's first section. The method defaults to `meson`.
Supported methods:
- `meson` requires `meson.build` file.
- `cmake` requires `CMakeLists.txt` file. [See details](Wrap-dependency-system-manual.md#cmake-wraps).
- `cargo` requires `Cargo.toml` file. [See details](Wrap-dependency-system-manual.md#cargo-wraps).
5 changes: 5 additions & 0 deletions mesonbuild/cargo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
__all__ = [
'interpret'
]

from .interpreter import interpret
8 changes: 7 additions & 1 deletion mesonbuild/cargo/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,13 @@ def _create_lib(cargo: Manifest, build: builder.Builder, crate_type: manifest.CR
]


def interpret(cargo: Manifest, env: Environment) -> mparser.CodeBlockNode:
def interpret(subp_name: str, subdir: str, env: Environment) -> mparser.CodeBlockNode:
package_name = subp_name[:-3] if subp_name.endswith('-rs') else subp_name
manifests = _load_manifests(os.path.join(env.source_dir, subdir))
cargo = manifests.get(package_name)
if not cargo:
raise MesonException(f'Cargo package {package_name!r} not found in {subdir}')

filename = os.path.join(cargo.subdir, cargo.path, 'Cargo.toml')
build = builder.Builder(filename)

Expand Down
24 changes: 18 additions & 6 deletions mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from ..modules import ExtensionModule, ModuleObject, MutableModuleObject, NewExtensionModule, NotFoundExtensionModule
from ..cmake import CMakeInterpreter
from ..backend.backends import ExecutableSerialisation
from .. import cargo

from . import interpreterobjects as OBJ
from . import compiler as compilerOBJ
Expand Down Expand Up @@ -935,13 +936,14 @@ def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_meth
m += ['method', mlog.bold(method)]
mlog.log(*m, '\n', nested=False)

methods_map: T.Dict[wrap.Method, T.Callable[[str, str, T.Dict[OptionKey, str, kwtypes.DoSubproject]], SubprojectHolder]] = {
'meson': self._do_subproject_meson,
'cmake': self._do_subproject_cmake,
'cargo': self._do_subproject_cargo,
}

try:
if method == 'meson':
return self._do_subproject_meson(subp_name, subdir, default_options, kwargs)
elif method == 'cmake':
return self._do_subproject_cmake(subp_name, subdir, default_options, kwargs)
else:
raise mesonlib.MesonBugException(f'The method {method} is invalid for the subproject {subp_name}')
return methods_map[method](subp_name, subdir, default_options, kwargs)
# Invalid code is always an error
except InvalidCode:
raise
Expand Down Expand Up @@ -1042,6 +1044,16 @@ def _do_subproject_cmake(self, subp_name: str, subdir: str,
result.cm_interpreter = cm_int
return result

def _do_subproject_cargo(self, subp_name: str, subdir: str,
default_options: T.Dict[OptionKey, str],
kwargs: kwtypes.DoSubproject) -> SubprojectHolder:
with mlog.nested(subp_name):
ast = cargo.interpret(subp_name, subdir, self.environment)
return self._do_subproject_meson(
subp_name, subdir, default_options, kwargs, ast,
# FIXME: Are there other files used by cargo interpreter?
[os.path.join(subdir, 'Cargo.toml')])

def get_option_internal(self, optname: str) -> coredata.UserOption:
key = OptionKey.from_string(optname).evolve(subproject=self.subproject)

Expand Down
3 changes: 2 additions & 1 deletion mesonbuild/wrap/wrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

if T.TYPE_CHECKING:
import http.client
Method = T.Literal['meson', 'cmake']
Method = T.Literal['meson', 'cmake', 'cargo']

try:
# Importing is just done to check if SSL exists, so all warnings
Expand Down Expand Up @@ -448,6 +448,7 @@ def resolve(self, packagename: str, force_method: T.Optional[Method] = None) ->
methods_map: T.Dict[Method, str] = {
'meson': 'meson.build',
'cmake': 'CMakeLists.txt',
'cargo': 'Cargo.toml',
}

# Check if this wrap forces a specific method, use meson otherwise.
Expand Down
2 changes: 1 addition & 1 deletion test cases/cmake/26 dependency fallback/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ test('test1', exe1)
# to meson but wrap force cmake.
subproject('force_cmake')

testcase expect_error('Wrap method \'notfound\' is not supported, must be one of: meson, cmake')
testcase expect_error('Wrap method \'notfound\' is not supported, must be one of: meson, cmake, cargo')
subproject('broken_method')
endtestcase

Expand Down
5 changes: 5 additions & 0 deletions test cases/rust/21 cargo subproject/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
int rust_func(void);

int main(int argc, char *argv[]) {
return rust_func();
}
7 changes: 7 additions & 0 deletions test cases/rust/21 cargo subproject/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project('cargo subproject', 'c')

foo_dep = dependency('foo-rs')
exe = executable('foo', 'main.c',
dependencies: foo_dep,
)
test('cargo-test', exe)
2 changes: 2 additions & 0 deletions test cases/rust/21 cargo subproject/subprojects/bar-rs.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[wrap-file]
method = cargo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[package]
name = "bar"
version = "0.1"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub const VALUE: i32 = 0;
2 changes: 2 additions & 0 deletions test cases/rust/21 cargo subproject/subprojects/foo-rs.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[wrap-file]
method = cargo
10 changes: 10 additions & 0 deletions test cases/rust/21 cargo subproject/subprojects/foo-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "foo"
version = "0.0.1"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
mybar = { version = "0.1", package = "bar" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[no_mangle]
pub extern "C" fn rust_func() -> i32 {
mybar::VALUE
}

0 comments on commit be44e8c

Please sign in to comment.