Skip to content

Commit

Permalink
cargo: Add support for system-deps dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
thiblahute authored and xclaesse committed Oct 24, 2024
1 parent 4cf9940 commit 962eec5
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 1 deletion.
71 changes: 70 additions & 1 deletion mesonbuild/cargo/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,39 @@ class Package:
def __post_init__(self) -> None:
self.api = _version_to_api(self.version)

@dataclasses.dataclass
class SystemDependency:

""" Representation of a Cargo system-deps entry
https://docs.rs/system-deps/latest/system_deps
"""

name: str
version: T.List[str]
optional: bool
feature: T.Optional[str]
feature_overrides: T.Dict[str, T.Dict[str, str]]

@classmethod
def from_raw(cls, name: str, raw: T.Dict[str, T.Any]) -> SystemDependency:
name = raw.get('name', name)
version = raw.get('version')
version = version.split(',') if version is not None else []
vers: T.List[str] = []
for v in version:
v = v.strip()
if v[0] not in '><=':
v = f'>={v}'
vers.append(v)
optional = raw.get('optional', False)
feature = raw.get('feature')
# Everything else are overrides when certain features are enabled.
feature_overrides = {k: v for k, v in raw.items() if k not in {'name', 'version', 'optional', 'feature'}}
return cls(name, vers, optional, feature, feature_overrides)

def enabled(self, features: T.Set[str]) -> bool:
return self.feature is None or self.feature in features

@dataclasses.dataclass
class Dependency:

Expand Down Expand Up @@ -289,6 +322,7 @@ class Manifest:
dependencies: T.Dict[str, Dependency]
dev_dependencies: T.Dict[str, Dependency]
build_dependencies: T.Dict[str, Dependency]
system_dependencies: T.Dict[str, SystemDependency] = dataclasses.field(init=False)
lib: Library
bin: T.List[Binary]
test: T.List[Test]
Expand All @@ -300,6 +334,7 @@ class Manifest:

def __post_init__(self) -> None:
self.features.setdefault('default', [])
self.system_dependencies = {k: SystemDependency.from_raw(k, v) for k, v in self.package.metadata.get('system-deps', {}).items()}


def _convert_manifest(raw_manifest: manifest.Manifest, subdir: str, path: str = '') -> Manifest:
Expand Down Expand Up @@ -563,8 +598,38 @@ def _create_dependencies(self, pkg: PackageState, build: builder.Builder) -> T.L
for depname in pkg.required_deps:
dep = pkg.manifest.dependencies[depname]
ast += self._create_dependency(dep, build)
ast.append(build.assign(build.array([]), 'system_deps_args'))
for name, sys_dep in pkg.manifest.system_dependencies.items():
if sys_dep.enabled(pkg.features):
ast += self._create_system_dependency(name, sys_dep, build)
return ast

def _create_system_dependency(self, name: str, dep: SystemDependency, build: builder.Builder) -> T.List[mparser.BaseNode]:
kw = {
'version': build.array([build.string(s) for s in dep.version]),
'required': build.bool(not dep.optional),
}
varname = f'{fixup_meson_varname(name)}_system_dep'
cfg = f'system_deps_have_{fixup_meson_varname(name)}'
return [
build.assign(
build.function(
'dependency',
[build.string(dep.name)],
kw,
),
varname,
),
build.if_(
build.method('found', build.identifier(varname)), build.block([
build.plusassign(
build.array([build.string('--cfg'), build.string(cfg)]),
'system_deps_args'
),
])
),
]

def _create_dependency(self, dep: Dependency, build: builder.Builder) -> T.List[mparser.BaseNode]:
pkg = self._dep_package(dep)
kw = {
Expand Down Expand Up @@ -654,10 +719,14 @@ def _create_lib(self, pkg: PackageState, build: builder.Builder, crate_type: man
dep_pkg = self._dep_package(dep)
dep_lib_name = dep_pkg.manifest.lib.name
dependency_map[build.string(fixup_meson_varname(dep_lib_name))] = build.string(name)
for name, sys_dep in pkg.manifest.system_dependencies.items():
if sys_dep.enabled(pkg.features):
dependencies.append(build.identifier(f'{fixup_meson_varname(name)}_system_dep'))

rust_args: T.List[mparser.BaseNode] = [
build.identifier('features_args'),
build.identifier(_extra_args_varname())
build.identifier(_extra_args_varname()),
build.identifier('system_deps_args'),
]

dependencies.append(build.identifier(_extra_deps_varname()))
Expand Down
5 changes: 5 additions & 0 deletions test cases/rust/26 cargo system deps/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extern crate sub;

pub fn main() {
sub::func();
}
11 changes: 11 additions & 0 deletions test cases/rust/26 cargo system deps/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
project('cargo system-deps', 'rust')

glib = dependency('glib-2.0', required: false)
if not glib.found()
error('MESON_SKIP_TEST: Need glib system dependency')
endif

sub_dep = dependency('sub-1-rs')
exe = executable('main', 'main.rs', dependencies : sub_dep)
test('main', exe)

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,15 @@
[package]
name = 'sub'
version = '1'

[build-dependencies]
system-deps = "6"

[lib]
name = "sub"
path = "lib.rs"

[package.metadata.system-deps]
glib = { name = "glib-2.0", version=" 2.0 , 2.1 , <3 ", feature="default" }
gobject = { name = "gobject-2.0", version=">=99", optional=true }
notfound = { feature="notfound" }
15 changes: 15 additions & 0 deletions test cases/rust/26 cargo system deps/subprojects/sub-1-rs/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
extern "C" {
fn g_get_tmp_dir() -> *mut std::ffi::c_void;
}

#[cfg(system_deps_have_glib)]
#[cfg(not(system_deps_have_gobject))]
pub fn func() {
unsafe {
g_get_tmp_dir();
}
}

pub fn func1() {
func()
}

0 comments on commit 962eec5

Please sign in to comment.