diff options
Diffstat (limited to 'mingling_pathf/src')
| -rw-r--r-- | mingling_pathf/src/error.rs | 6 | ||||
| -rw-r--r-- | mingling_pathf/src/lib.rs | 2 | ||||
| -rw-r--r-- | mingling_pathf/src/type_mapping_builder.rs | 76 |
3 files changed, 64 insertions, 20 deletions
diff --git a/mingling_pathf/src/error.rs b/mingling_pathf/src/error.rs index 5a748c4..bd850a8 100644 --- a/mingling_pathf/src/error.rs +++ b/mingling_pathf/src/error.rs @@ -53,6 +53,11 @@ pub enum MinglingPathfinderError { /// Details from the parser about the parse failure. message: String, }, + + /// `cargo metadata` could not be executed or parsed. + /// + /// `message` contains the underlying error from the cargo invocation. + CargoMetadata(String), } impl fmt::Display for MinglingPathfinderError { @@ -82,6 +87,7 @@ impl fmt::Display for MinglingPathfinderError { Self::SynError { path, message } => { write!(f, "Failed to parse {}: {message}", path.display()) } + Self::CargoMetadata(message) => write!(f, "cargo metadata failed: {message}"), } } } diff --git a/mingling_pathf/src/lib.rs b/mingling_pathf/src/lib.rs index 492bfc7..f0637e8 100644 --- a/mingling_pathf/src/lib.rs +++ b/mingling_pathf/src/lib.rs @@ -13,3 +13,5 @@ pub mod patterns; mod type_mapping_builder; pub use type_mapping_builder::analyze_and_build_type_mapping; pub use type_mapping_builder::analyze_and_build_type_mapping_for; +pub use type_mapping_builder::build_output_dir; +pub use type_mapping_builder::target_directory; diff --git a/mingling_pathf/src/type_mapping_builder.rs b/mingling_pathf/src/type_mapping_builder.rs index 1ccd267..4d0799f 100644 --- a/mingling_pathf/src/type_mapping_builder.rs +++ b/mingling_pathf/src/type_mapping_builder.rs @@ -5,7 +5,9 @@ use std::collections::HashSet; use std::fmt::Write as FmtWrite; -use std::path::Path; +use std::path::{Path, PathBuf}; + +use cargo_metadata::MetadataCommand; use crate::error::MinglingPathfinderError; use crate::module_pathf; @@ -87,40 +89,74 @@ pub fn analyze_and_build_type_mapping_for( Ok(()) } -/// Convenience version to be called from `build.rs`, automatically reading configuration -/// from environment variables. +/// Runs `cargo metadata` from the given crate directory and returns the +/// workspace's target directory. +/// +/// The subprocess resolves the target directory exactly as Cargo does, +/// honoring `.cargo/config.toml`, `CARGO_TARGET_DIR`, and `--target-dir`. +/// +/// `crate_dir` — crate root directory (i.e., the directory containing Cargo.toml). +/// +/// # Errors +/// +/// Returns a [`MinglingPathfinderError::CargoMetadata`] if `cargo metadata` +/// cannot be executed or its output cannot be parsed. +pub fn target_directory(crate_dir: &Path) -> Result<PathBuf, MinglingPathfinderError> { + let metadata = MetadataCommand::new() + .current_dir(crate_dir) + .no_deps() + .exec() + .map_err(|e| MinglingPathfinderError::CargoMetadata(e.to_string()))?; + Ok(metadata.target_directory.into_std_path_buf()) +} + +/// The directory where all of Mingling's compile-time build artifacts are +/// written for the current crate: `{target_directory}/mingling/`. +/// +/// Reads `CARGO_MANIFEST_DIR` from the environment to locate the crate, then +/// resolves the target directory via [`target_directory`]. Works both from a +/// `build.rs` and from proc-macro expansion (no `OUT_DIR` required). +/// +/// # Errors +/// +/// Returns a [`MinglingPathfinderError`] if the environment variables are +/// missing or the target directory cannot be resolved. +pub fn build_output_dir() -> Result<PathBuf, MinglingPathfinderError> { + let crate_dir = std::env::var("CARGO_MANIFEST_DIR").map_err(|_| { + MinglingPathfinderError::IoError(std::io::Error::new( + std::io::ErrorKind::NotFound, + "CARGO_MANIFEST_DIR not set", + )) + })?; + Ok(target_directory(Path::new(&crate_dir))?.join("mingling")) +} + +/// Convenience version to be called from `build.rs` or macro expansion, +/// automatically reading configuration from environment variables. /// -/// Reads `CARGO_PKG_NAME` and `OUT_DIR`, and outputs to `{OUT_DIR}/{CARGO_PKG_NAME}/`. +/// Reads `CARGO_PKG_NAME` and `CARGO_MANIFEST_DIR`, and outputs to +/// `{target_directory}/mingling/{CARGO_PKG_NAME}/` (see [`build_output_dir`]). /// /// # Errors /// /// Returns a [`MinglingPathfinderError`] if the required environment variables -/// (`CARGO_PKG_NAME`, `OUT_DIR`) are not set, the current directory cannot be -/// determined, or the type mapping generation fails. +/// (`CARGO_PKG_NAME`, `CARGO_MANIFEST_DIR`) are not set or the type mapping +/// generation fails. pub fn analyze_and_build_type_mapping() -> Result<(), MinglingPathfinderError> { let crate_name = std::env::var("CARGO_PKG_NAME").map_err(|_| { MinglingPathfinderError::IoError(std::io::Error::new( std::io::ErrorKind::NotFound, - "CARGO_PKG_NAME not set (not running in build.rs?)", + "CARGO_PKG_NAME not set", )) })?; - - let out_dir = std::env::var("OUT_DIR").map_err(|_| { + let crate_dir = std::env::var("CARGO_MANIFEST_DIR").map_err(|_| { MinglingPathfinderError::IoError(std::io::Error::new( std::io::ErrorKind::NotFound, - "OUT_DIR not set (not running in build.rs?)", + "CARGO_MANIFEST_DIR not set", )) })?; - let crate_dir = std::env::current_dir()?; - let output_dir = Path::new(&out_dir).join(&crate_name); - - analyze_and_build_type_mapping_for(&crate_dir, &output_dir)?; + let output_dir = build_output_dir()?.join(&crate_name); - // Notify Cargo to re-run build.rs when source files change - println!("cargo:rerun-if-changed=src/"); - println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_OS"); - println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_ARCH"); - - Ok(()) + analyze_and_build_type_mapping_for(Path::new(&crate_dir), &output_dir) } |
