cargo: Add API version into dependency name
This commit is contained in:
parent
3f73aaed2d
commit
4d3fb88753
|
@ -316,11 +316,24 @@ 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 automatically override the `<package_name>-<version>-rs` dependency
|
||||
name:
|
||||
- `package_name` is defined in `[package] name = ...` section of the `Cargo.toml`.
|
||||
- `version` is the API version deduced from `[package] version = ...` as follow:
|
||||
* `x.y.z` -> 'x'
|
||||
* `0.x.y` -> '0.x'
|
||||
* `0.0.x` -> '0'
|
||||
It allows to make different dependencies for uncompatible versions of the same
|
||||
crate.
|
||||
- `-rs` suffix is added to distinguish from regular system dependencies, for
|
||||
example `gstreamer-1.0` is a system pkg-config dependency and `gstreamer-0.22-rs`
|
||||
is a Cargo dependency.
|
||||
|
||||
That means the `.wrap` file should have `dependency_names = foo-1-rs` in their
|
||||
`[provide]` section when `Cargo.toml` has package name `foo` and version `1.2`.
|
||||
|
||||
Note that the version component was added in Meson 1.4, previous versions were
|
||||
using `<package_name>-rs` format.
|
||||
|
||||
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.
|
||||
|
@ -332,26 +345,26 @@ file like that:
|
|||
...
|
||||
method = cargo
|
||||
[provide]
|
||||
dependency_names = foo-bar-rs
|
||||
dependency_names = foo-bar-0.1-rs
|
||||
```
|
||||
|
||||
Cargo features are exposed as Meson boolean options, with the `feature-` prefix.
|
||||
For example the `default` feature is named `feature-default` and can be set from
|
||||
the command line with `-Dfoo-rs:feature-default=false`. When a cargo subproject
|
||||
the command line with `-Dfoo-1-rs:feature-default=false`. When a cargo subproject
|
||||
depends on another cargo subproject, it will automatically enable features it
|
||||
needs using the `dependency('foo-rs', default_options: ...)` mechanism. However,
|
||||
needs using the `dependency('foo-1-rs', default_options: ...)` mechanism. However,
|
||||
unlike Cargo, the set of enabled features is not managed globally. Let's assume
|
||||
the main project depends on `foo-rs` and `bar-rs`, and they both depend on
|
||||
`common-rs`. The main project will first look up `foo-rs` which itself will
|
||||
configure `common-rs` with a set of features. Later, when `bar-rs` does a lookup
|
||||
for `common-rs` it has already been configured and the set of features cannot be
|
||||
changed. If `bar-rs` wants extra features from `common-rs`, Meson will error out.
|
||||
the main project depends on `foo-1-rs` and `bar-1-rs`, and they both depend on
|
||||
`common-1-rs`. The main project will first look up `foo-1-rs` which itself will
|
||||
configure `common-rs` with a set of features. Later, when `bar-1-rs` does a lookup
|
||||
for `common-1-rs` it has already been configured and the set of features cannot be
|
||||
changed. If `bar-1-rs` wants extra features from `common-1-rs`, Meson will error out.
|
||||
It is currently the responsability of the main project to resolve those
|
||||
issues by enabling extra features on each subproject:
|
||||
```meson
|
||||
project(...,
|
||||
default_options: {
|
||||
'common-rs:feature-something': true,
|
||||
'common-1-rs:feature-something': true,
|
||||
},
|
||||
)
|
||||
```
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
## Cargo dependencies names now include the API version
|
||||
|
||||
Cargo dependencies names are now in the format `<package_name>-<version>-rs`:
|
||||
- `package_name` is defined in `[package] name = ...` section of the `Cargo.toml`.
|
||||
- `version` is the API version deduced from `[package] version = ...` as follow:
|
||||
* `x.y.z` -> 'x'
|
||||
* `0.x.y` -> '0.x'
|
||||
* `0.0.x` -> '0'
|
||||
It allows to make different dependencies for uncompatible versions of the same
|
||||
crate.
|
||||
- `-rs` suffix is added to distinguish from regular system dependencies, for
|
||||
example `gstreamer-1.0` is a system pkg-config dependency and `gstreamer-0.22-rs`
|
||||
is a Cargo dependency.
|
||||
|
||||
That means the `.wrap` file should have `dependency_names = foo-1-rs` in their
|
||||
`[provide]` section when `Cargo.toml` has package name `foo` and version `1.2`.
|
||||
|
||||
This is a breaking change (Cargo subprojects are still experimental), previous
|
||||
versions were using `<package_name>-rs` format.
|
|
@ -162,9 +162,23 @@ class Dependency:
|
|||
package: str = ''
|
||||
default_features: bool = True
|
||||
features: T.List[str] = dataclasses.field(default_factory=list)
|
||||
api: str = dataclasses.field(init=False)
|
||||
|
||||
def __post_init__(self, name: str) -> None:
|
||||
self.package = self.package or name
|
||||
# Extract wanted API version from version constraints.
|
||||
api = set()
|
||||
for v in self.version:
|
||||
if v.startswith(('>=', '==')):
|
||||
api.add(_version_to_api(v[2:].strip()))
|
||||
elif v.startswith('='):
|
||||
api.add(_version_to_api(v[1:].strip()))
|
||||
if not api:
|
||||
self.api = '0'
|
||||
elif len(api) == 1:
|
||||
self.api = api.pop()
|
||||
else:
|
||||
raise MesonException(f'Cannot determine minimum API version from {self.version}.')
|
||||
|
||||
@classmethod
|
||||
def from_raw(cls, name: str, raw: manifest.DependencyV) -> Dependency:
|
||||
|
@ -351,8 +365,21 @@ def _load_manifests(subdir: str) -> T.Dict[str, Manifest]:
|
|||
return manifests
|
||||
|
||||
|
||||
def _dependency_name(package_name: str) -> str:
|
||||
return package_name if package_name.endswith('-rs') else f'{package_name}-rs'
|
||||
def _version_to_api(version: str) -> str:
|
||||
# x.y.z -> x
|
||||
# 0.x.y -> 0.x
|
||||
# 0.0.x -> 0
|
||||
vers = version.split('.')
|
||||
if int(vers[0]) != 0:
|
||||
return vers[0]
|
||||
elif len(vers) >= 2 and int(vers[1]) != 0:
|
||||
return f'0.{vers[1]}'
|
||||
return '0'
|
||||
|
||||
|
||||
def _dependency_name(package_name: str, api: str) -> str:
|
||||
basename = package_name[:-3] if package_name.endswith('-rs') else package_name
|
||||
return f'{basename}-{api}-rs'
|
||||
|
||||
|
||||
def _dependency_varname(package_name: str) -> str:
|
||||
|
@ -517,7 +544,7 @@ def _create_dependencies(cargo: Manifest, build: builder.Builder) -> T.List[mpar
|
|||
build.assign(
|
||||
build.function(
|
||||
'dependency',
|
||||
[build.string(_dependency_name(dep.package))],
|
||||
[build.string(_dependency_name(dep.package, dep.api))],
|
||||
kw,
|
||||
),
|
||||
_dependency_varname(dep.package),
|
||||
|
@ -559,7 +586,7 @@ def _create_dependencies(cargo: Manifest, build: builder.Builder) -> T.List[mpar
|
|||
build.if_(build.not_in(build.identifier('f'), build.identifier('actual_features')), build.block([
|
||||
build.function('error', [
|
||||
build.string('Dependency'),
|
||||
build.string(_dependency_name(dep.package)),
|
||||
build.string(_dependency_name(dep.package, dep.api)),
|
||||
build.string('previously configured with features'),
|
||||
build.identifier('actual_features'),
|
||||
build.string('but need'),
|
||||
|
@ -666,7 +693,7 @@ def _create_lib(cargo: Manifest, build: builder.Builder, crate_type: manifest.CR
|
|||
'override_dependency',
|
||||
build.identifier('meson'),
|
||||
[
|
||||
build.string(_dependency_name(cargo.package.name)),
|
||||
build.string(_dependency_name(cargo.package.name, _version_to_api(cargo.package.version))),
|
||||
build.identifier('dep'),
|
||||
],
|
||||
),
|
||||
|
@ -674,7 +701,8 @@ def _create_lib(cargo: Manifest, build: builder.Builder, crate_type: manifest.CR
|
|||
|
||||
|
||||
def interpret(subp_name: str, subdir: str, env: Environment) -> T.Tuple[mparser.CodeBlockNode, KeyedOptionDictType]:
|
||||
package_name = subp_name[:-3] if subp_name.endswith('-rs') else subp_name
|
||||
# subp_name should be in the form "foo-0.1-rs"
|
||||
package_name = subp_name.rsplit('-', 2)[0]
|
||||
manifests = _load_manifests(os.path.join(env.source_dir, subdir))
|
||||
cargo = manifests.get(package_name)
|
||||
if not cargo:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
project('cargo subproject', 'c')
|
||||
|
||||
foo_dep = dependency('foo-rs')
|
||||
foo_dep = dependency('foo-0-rs')
|
||||
exe = executable('app', 'main.c',
|
||||
dependencies: foo_dep,
|
||||
)
|
||||
|
|
|
@ -7,4 +7,4 @@ d = declare_dependency(link_with: l,
|
|||
variables: {
|
||||
'features': 'default',
|
||||
})
|
||||
meson.override_dependency('extra-dep-rs', d)
|
||||
meson.override_dependency('extra-dep-1-rs', d)
|
Loading…
Reference in New Issue