From 3a794cd0a1a10f2b348670f50b3bf2ef3eba37f4 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 14 Mar 2024 15:11:29 -0400 Subject: [PATCH] cargo: Add support for target specific dependencies --- mesonbuild/cargo/interpreter.py | 42 ++++++++++++++----- mesonbuild/compilers/rust.py | 8 +++- .../subprojects/foo-0-rs/Cargo.toml | 3 ++ .../subprojects/foo-0-rs/lib.rs | 4 ++ .../subprojects/unixdep-0.1-rs.wrap | 2 + .../subprojects/unixdep-0.1-rs/Cargo.toml | 7 ++++ .../subprojects/unixdep-0.1-rs/lib.rs | 8 ++++ 7 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs.wrap create mode 100644 test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs/Cargo.toml create mode 100644 test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs/lib.rs diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 626eb445b227..1fa171808b1d 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -21,8 +21,7 @@ import urllib.parse import typing as T -from . import builder -from . import version +from . import builder, version, cfg from ..mesonlib import MesonException, Popen_safe, File, MachineChoice from .. import coredata, mlog from ..wrap.wrap import PackageDefinition @@ -418,10 +417,14 @@ class PackageKey: class Interpreter: def __init__(self, env: Environment) -> None: self.environment = env + self.build_rustc = T.cast('RustCompiler', self.environment.coredata.compilers[MachineChoice.BUILD]['rust']) + self.host_rustc = T.cast('RustCompiler', self.environment.coredata.compilers[MachineChoice.HOST]['rust']) # Map Cargo.toml's subdir to loaded manifest. self.manifests: T.Dict[str, Manifest] = {} # Map of cargo package (name + api) to its state self.packages: T.Dict[PackageKey, PackageState] = {} + # Rustc's config + self.cfgs = self._get_cfgs() def interpret(self, subdir: str) -> T.Tuple[mparser.CodeBlockNode, T.List[str]]: manifest = self._load_manifest(subdir) @@ -473,6 +476,10 @@ def _fetch_package(self, package_name: str, api: str) -> T.Tuple[PackageState, b manifest = self._load_manifest(subdir) pkg = PackageState(manifest) self.packages[key] = pkg + # Merge target specific dependencies that are enabled + for condition, dependencies in manifest.target.items(): + if cfg.eval_cfg(condition, self.cfgs): + manifest.dependencies.update(dependencies) # Fetch required dependencies recursively. for depname, dep in manifest.dependencies.items(): if not dep.optional: @@ -556,12 +563,9 @@ def _run_build_rs(self, pkg: PackageState, subdir: str) -> T.Tuple[T.List[str], mlog.warning('Cannot use build.rs with build-dependencies. It should be ported manually in meson/meson.build.') return [], [] - build_rustc = T.cast('RustCompiler', self.environment.coredata.compilers[MachineChoice.BUILD]['rust']) - host_rustc = T.cast('RustCompiler', self.environment.coredata.compilers[MachineChoice.HOST]['rust']) - # Prepare build.rs run environment # https://doc.rust-lang.org/cargo/reference/environment-variables.html - host_rustc_cmd = host_rustc.get_exelist(ccache=False) + host_rustc_cmd = self.host_rustc.get_exelist(ccache=False) out_dir = os.path.join(self.environment.build_dir, subdir, 'build.rs.p') version_arr = pkg.manifest.package.version.split('.') version_arr += ['' * (4 - len(version_arr))] @@ -569,7 +573,7 @@ def _run_build_rs(self, pkg: PackageState, subdir: str) -> T.Tuple[T.List[str], env.update({ 'OUT_DIR': out_dir, 'RUSTC': host_rustc_cmd[0], - 'TARGET': host_rustc.get_target_triplet(), + 'TARGET': self.host_rustc.get_target_triplet(), 'CARGO_MANIFEST_DIR': os.path.join(self.environment.source_dir, subdir), 'CARGO_PKG_VERSION': pkg.manifest.package.version, 'CARGO_PKG_VERSION_MAJOR': version_arr[0], @@ -589,16 +593,15 @@ def _run_build_rs(self, pkg: PackageState, subdir: str) -> T.Tuple[T.List[str], def conv(k: str) -> str: return k.upper().replace('-', '_') - # TODO: Add cfgs - #for k, v in self.cfgs.items(): - # env[f'CARGO_CFG_{conv(k)}'] = v + for k, v in self.cfgs.items(): + env[f'CARGO_CFG_{conv(k)}'] = v for f in pkg.features: env[f'CARGO_FEATURE_{conv(f)}'] = '' # Compile and run build.rs build_rs_file = File.from_absolute_file(build_rs) cwd = os.path.join(self.environment.source_dir, subdir) - res = build_rustc.run(build_rs_file, self.environment, run_env=env, run_cwd=cwd) + res = self.build_rustc.run(build_rs_file, self.environment, run_env=env, run_cwd=cwd) if res.returncode != 0: raise MesonException('Could not run build.rs') mlog.log('Run ', mlog.bold('build.rs'), ': ', mlog.green('YES'), sep='') @@ -617,6 +620,23 @@ def conv(k: str) -> str: return compiler_args, build_def_files + def _get_cfgs(self) -> T.Dict[str, str]: + cfgs = self.host_rustc.get_cfgs().copy() + rustflags = self.environment.coredata.get_external_args(MachineChoice.HOST, 'rust') + rustflags_i = iter(rustflags) + for i in rustflags_i: + if i == '--cfg': + cfgs.append(next(rustflags_i)) + return dict(self._split_cfg(i) for i in cfgs) + + @staticmethod + def _split_cfg(cfg: str) -> T.Tuple[str, str]: + pair = cfg.split('=', maxsplit=1) + value = pair[1] if len(pair) > 1 else '' + if value and value[0] == '"': + value = value[1:-1] + return pair[0], value + def _create_project(self, pkg: PackageState, build: builder.Builder) -> T.List[mparser.BaseNode]: """Create the project() function call diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index 9a4105b49356..0ec55b70c9ba 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -142,16 +142,20 @@ def _native_static_libs(self, work_dir: str, source_name: str) -> None: def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['--dep-info', outfile] + @functools.lru_cache(maxsize=None) def get_sysroot(self) -> str: cmd = self.get_exelist(ccache=False) + ['--print', 'sysroot'] p, stdo, stde = Popen_safe_logged(cmd) return stdo.split('\n', maxsplit=1)[0] @functools.lru_cache(maxsize=None) - def get_crt_static(self) -> bool: + def get_cfgs(self) -> T.List[str]: cmd = self.get_exelist(ccache=False) + ['--print', 'cfg'] p, stdo, stde = Popen_safe_logged(cmd) - return bool(re.search('^target_feature="crt-static"$', stdo, re.MULTILINE)) + return stdo.splitlines() + + def get_crt_static(self) -> bool: + return 'target_feature="crt-static"' in self.get_cfgs() @functools.lru_cache(maxsize=None) def get_target_triplet(self) -> str: diff --git a/test cases/rust/22 cargo subproject/subprojects/foo-0-rs/Cargo.toml b/test cases/rust/22 cargo subproject/subprojects/foo-0-rs/Cargo.toml index 8c5351a77b2e..dd8525b54682 100644 --- a/test cases/rust/22 cargo subproject/subprojects/foo-0-rs/Cargo.toml +++ b/test cases/rust/22 cargo subproject/subprojects/foo-0-rs/Cargo.toml @@ -27,6 +27,9 @@ features = ["f1"] [dependencies.libname] version = "1" +[target."cfg(unix)".dependencies.unixdep] +version = "0.1" + [features] default = ["f1"] f1 = ["f2", "f3"] diff --git a/test cases/rust/22 cargo subproject/subprojects/foo-0-rs/lib.rs b/test cases/rust/22 cargo subproject/subprojects/foo-0-rs/lib.rs index 4497dc4a4f3e..4999dc2de897 100644 --- a/test cases/rust/22 cargo subproject/subprojects/foo-0-rs/lib.rs +++ b/test cases/rust/22 cargo subproject/subprojects/foo-0-rs/lib.rs @@ -8,6 +8,10 @@ extern "C" { #[cfg(feature = "foo")] #[no_mangle] pub extern "C" fn rust_func() -> i32 { + if cfg!(unix) { + extern crate unixdep; + assert!(unixdep::only_on_unix() == 0); + } assert!(common::common_func() == 0); assert!(libothername::stuff() == 42); let v: i32; diff --git a/test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs.wrap b/test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs.wrap new file mode 100644 index 000000000000..99686e90e78e --- /dev/null +++ b/test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs.wrap @@ -0,0 +1,2 @@ +[wrap-file] +method = cargo diff --git a/test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs/Cargo.toml b/test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs/Cargo.toml new file mode 100644 index 000000000000..d72fb39be5d4 --- /dev/null +++ b/test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "unixdep" +version = "0.1" +edition = "2021" + +[lib] +path = "lib.rs" diff --git a/test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs/lib.rs b/test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs/lib.rs new file mode 100644 index 000000000000..a736e8a26451 --- /dev/null +++ b/test cases/rust/22 cargo subproject/subprojects/unixdep-0.1-rs/lib.rs @@ -0,0 +1,8 @@ +pub fn only_on_unix() -> i32 { + 0 +} + +#[cfg(not(unix))] +pub fn broken() -> i32 { + plop +}