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 wraps
|
||||||
|
|
||||||
Cargo subprojects automatically override the `<package_name>-rs` dependency name.
|
Cargo subprojects automatically override the `<package_name>-<version>-rs` dependency
|
||||||
`package_name` is defined in `[package] name = ...` section of the `Cargo.toml`
|
name:
|
||||||
and `-rs` suffix is added. That means the `.wrap` file should have
|
- `package_name` is defined in `[package] name = ...` section of the `Cargo.toml`.
|
||||||
`dependency_names = foo-rs` in their `[provide]` section when `Cargo.toml` has
|
- `version` is the API version deduced from `[package] version = ...` as follow:
|
||||||
package name `foo`.
|
* `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
|
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.
|
Python versions require either the external `tomli` module or `toml2json` program.
|
||||||
|
@ -332,26 +345,26 @@ file like that:
|
||||||
...
|
...
|
||||||
method = cargo
|
method = cargo
|
||||||
[provide]
|
[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.
|
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
|
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
|
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
|
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
|
the main project depends on `foo-1-rs` and `bar-1-rs`, and they both depend on
|
||||||
`common-rs`. The main project will first look up `foo-rs` which itself will
|
`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-rs` does a lookup
|
configure `common-rs` with a set of features. Later, when `bar-1-rs` does a lookup
|
||||||
for `common-rs` it has already been configured and the set of features cannot be
|
for `common-1-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.
|
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
|
It is currently the responsability of the main project to resolve those
|
||||||
issues by enabling extra features on each subproject:
|
issues by enabling extra features on each subproject:
|
||||||
```meson
|
```meson
|
||||||
project(...,
|
project(...,
|
||||||
default_options: {
|
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 = ''
|
package: str = ''
|
||||||
default_features: bool = True
|
default_features: bool = True
|
||||||
features: T.List[str] = dataclasses.field(default_factory=list)
|
features: T.List[str] = dataclasses.field(default_factory=list)
|
||||||
|
api: str = dataclasses.field(init=False)
|
||||||
|
|
||||||
def __post_init__(self, name: str) -> None:
|
def __post_init__(self, name: str) -> None:
|
||||||
self.package = self.package or name
|
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
|
@classmethod
|
||||||
def from_raw(cls, name: str, raw: manifest.DependencyV) -> Dependency:
|
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
|
return manifests
|
||||||
|
|
||||||
|
|
||||||
def _dependency_name(package_name: str) -> str:
|
def _version_to_api(version: str) -> str:
|
||||||
return package_name if package_name.endswith('-rs') else f'{package_name}-rs'
|
# 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:
|
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.assign(
|
||||||
build.function(
|
build.function(
|
||||||
'dependency',
|
'dependency',
|
||||||
[build.string(_dependency_name(dep.package))],
|
[build.string(_dependency_name(dep.package, dep.api))],
|
||||||
kw,
|
kw,
|
||||||
),
|
),
|
||||||
_dependency_varname(dep.package),
|
_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.if_(build.not_in(build.identifier('f'), build.identifier('actual_features')), build.block([
|
||||||
build.function('error', [
|
build.function('error', [
|
||||||
build.string('Dependency'),
|
build.string('Dependency'),
|
||||||
build.string(_dependency_name(dep.package)),
|
build.string(_dependency_name(dep.package, dep.api)),
|
||||||
build.string('previously configured with features'),
|
build.string('previously configured with features'),
|
||||||
build.identifier('actual_features'),
|
build.identifier('actual_features'),
|
||||||
build.string('but need'),
|
build.string('but need'),
|
||||||
|
@ -666,7 +693,7 @@ def _create_lib(cargo: Manifest, build: builder.Builder, crate_type: manifest.CR
|
||||||
'override_dependency',
|
'override_dependency',
|
||||||
build.identifier('meson'),
|
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'),
|
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]:
|
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))
|
manifests = _load_manifests(os.path.join(env.source_dir, subdir))
|
||||||
cargo = manifests.get(package_name)
|
cargo = manifests.get(package_name)
|
||||||
if not cargo:
|
if not cargo:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
project('cargo subproject', 'c')
|
project('cargo subproject', 'c')
|
||||||
|
|
||||||
foo_dep = dependency('foo-rs')
|
foo_dep = dependency('foo-0-rs')
|
||||||
exe = executable('app', 'main.c',
|
exe = executable('app', 'main.c',
|
||||||
dependencies: foo_dep,
|
dependencies: foo_dep,
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,4 +7,4 @@ d = declare_dependency(link_with: l,
|
||||||
variables: {
|
variables: {
|
||||||
'features': 'default',
|
'features': 'default',
|
||||||
})
|
})
|
||||||
meson.override_dependency('extra-dep-rs', d)
|
meson.override_dependency('extra-dep-1-rs', d)
|
Loading…
Reference in New Issue