Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ opener.workspace = true
os_info.workspace = true
pasetors.workspace = true
pathdiff.workspace = true
pkg-config.workspace = true
rand.workspace = true
regex.workspace = true
rusqlite.workspace = true
Expand Down
115 changes: 115 additions & 0 deletions crates/cargo-util-schemas/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@
"$ref": "#/$defs/InheritableDependency"
}
},
"pkgconfig-dependencies": {
"type": [
"object",
"null"
],
"additionalProperties": {
"$ref": "#/$defs/TomlPkgConfigDependency"
}
},
"target": {
"type": [
"object",
Expand Down Expand Up @@ -922,6 +931,103 @@
"workspace"
]
},
"TomlPkgConfigDependency": {
"description": "A pkg-config dependency specification",
"anyOf": [
{
"description": "In the simple format, only a version is specified, eg.\n`libfoo = \"1.2\"`",
"type": "string"
},
{
"description": "The simple format is equivalent to a detailed dependency\nspecifying only a version, eg.\n`libfoo = { version = \"1.2\" }`",
"$ref": "#/$defs/TomlPkgConfigDetailedDependency"
}
]
},
"TomlPkgConfigDetailedDependency": {
"type": "object",
"properties": {
"version": {
"type": [
"string",
"null"
]
},
"names": {
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"optional": {
"type": [
"boolean",
"null"
]
},
"feature": {
"type": [
"string",
"null"
]
},
"link": {
"type": [
"string",
"null"
]
},
"fallback": {
"anyOf": [
{
"$ref": "#/$defs/TomlPkgConfigFallback"
},
{
"type": "null"
}
]
}
}
},
"TomlPkgConfigFallback": {
"description": "Fallback specification for pkg-config dependencies\nUsed when pkg-config query fails",
"type": "object",
"properties": {
"libs": {
"description": "Library names to link (-l flags)",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"lib-paths": {
"description": "Library search paths (-L flags)",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"include-paths": {
"description": "Include search paths (-I flags)",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
}
},
"TomlPlatform": {
"description": "Corresponds to a `target` entry, but `TomlTarget` is already used.",
"type": "object",
Expand Down Expand Up @@ -970,6 +1076,15 @@
"additionalProperties": {
"$ref": "#/$defs/InheritableDependency"
}
},
"pkgconfig-dependencies": {
"type": [
"object",
"null"
],
"additionalProperties": {
"$ref": "#/$defs/TomlPkgConfigDependency"
}
}
}
},
Expand Down
134 changes: 134 additions & 0 deletions crates/cargo-util-schemas/src/manifest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub struct TomlManifest {
pub build_dependencies: Option<BTreeMap<PackageName, InheritableDependency>>,
#[serde(rename = "build_dependencies")]
pub build_dependencies2: Option<BTreeMap<PackageName, InheritableDependency>>,
pub pkgconfig_dependencies: Option<BTreeMap<String, TomlPkgConfigDependency>>,
pub target: Option<BTreeMap<String, TomlPlatform>>,
pub lints: Option<InheritableLints>,
pub hints: Option<Hints>,
Expand Down Expand Up @@ -84,6 +85,9 @@ impl TomlManifest {
self.build_dependencies()
.as_ref()
.map(|_| "build-dependencies"),
self.pkgconfig_dependencies
.as_ref()
.map(|_| "pkgconfig-dependencies"),
self.target.as_ref().map(|_| "target"),
self.lints.as_ref().map(|_| "lints"),
self.hints.as_ref().map(|_| "hints"),
Expand Down Expand Up @@ -899,6 +903,135 @@ impl<P: Clone> Default for TomlDetailedDependency<P> {
}
}

/// A pkg-config dependency specification
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
pub enum TomlPkgConfigDependency {
/// In the simple format, only a version is specified, eg.
/// `libfoo = "1.2"`
Simple(String),
/// The simple format is equivalent to a detailed dependency
/// specifying only a version, eg.
/// `libfoo = { version = "1.2" }`
Detailed(TomlPkgConfigDetailedDependency),
}

impl TomlPkgConfigDependency {
pub fn version_constraint(&self) -> Option<&str> {
match self {
TomlPkgConfigDependency::Simple(v) => Some(v),
TomlPkgConfigDependency::Detailed(d) => d.version.as_deref(),
}
}

pub fn names(&self) -> Option<&[String]> {
match self {
TomlPkgConfigDependency::Simple(_) => None,
TomlPkgConfigDependency::Detailed(d) => d.names.as_deref(),
}
}

pub fn is_optional(&self) -> bool {
match self {
TomlPkgConfigDependency::Simple(_) => false,
TomlPkgConfigDependency::Detailed(d) => d.optional.unwrap_or(false),
}
}

pub fn feature(&self) -> Option<&str> {
match self {
TomlPkgConfigDependency::Simple(_) => None,
TomlPkgConfigDependency::Detailed(d) => d.feature.as_deref(),
}
}

pub fn link(&self) -> Option<&str> {
match self {
TomlPkgConfigDependency::Simple(_) => None,
TomlPkgConfigDependency::Detailed(d) => d.link.as_deref(),
}
}

pub fn fallback(&self) -> Option<&TomlPkgConfigFallback> {
match self {
TomlPkgConfigDependency::Simple(_) => None,
TomlPkgConfigDependency::Detailed(d) => d.fallback.as_ref(),
}
}

pub fn unused_keys(&self) -> Vec<String> {
match self {
TomlPkgConfigDependency::Simple(_) => vec![],
TomlPkgConfigDependency::Detailed(detailed) => {
detailed._unused_keys.keys().cloned().collect()
}
}
}
}

impl<'de> de::Deserialize<'de> for TomlPkgConfigDependency {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
let expected = "a version string like \"1.2\" or a \
detailed dependency like { version = \"1.2\" }";
UntaggedEnumVisitor::new()
.expecting(expected)
.string(|value| Ok(TomlPkgConfigDependency::Simple(value.to_owned())))
.map(|value| value.deserialize().map(TomlPkgConfigDependency::Detailed))
.deserialize(deserializer)
}
}

#[derive(Deserialize, Serialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
pub struct TomlPkgConfigDetailedDependency {
pub version: Option<String>,
pub names: Option<Vec<String>>,
pub optional: Option<bool>,
pub feature: Option<String>,
pub link: Option<String>,
pub fallback: Option<TomlPkgConfigFallback>,

/// This is here to provide a way to see the "unused manifest keys" when deserializing
#[serde(skip_serializing)]
#[serde(flatten)]
#[cfg_attr(feature = "unstable-schema", schemars(skip))]
pub _unused_keys: BTreeMap<String, toml::Value>,
}

// Explicit implementation so we avoid pulling in default from flatten
impl Default for TomlPkgConfigDetailedDependency {
fn default() -> Self {
Self {
version: Default::default(),
names: Default::default(),
optional: Default::default(),
feature: Default::default(),
link: Default::default(),
fallback: Default::default(),
_unused_keys: Default::default(),
}
}
}

/// Fallback specification for pkg-config dependencies
/// Used when pkg-config query fails
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
pub struct TomlPkgConfigFallback {
/// Library names to link (-l flags)
pub libs: Option<Vec<String>>,
/// Library search paths (-L flags)
pub lib_paths: Option<Vec<String>>,
/// Include search paths (-I flags)
pub include_paths: Option<Vec<String>>,
}

#[derive(Deserialize, Serialize, Clone, Debug, Default)]
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
pub struct TomlProfiles(pub BTreeMap<ProfileName, TomlProfile>);
Expand Down Expand Up @@ -1517,6 +1650,7 @@ pub struct TomlPlatform {
pub dev_dependencies: Option<BTreeMap<PackageName, InheritableDependency>>,
#[serde(rename = "dev_dependencies")]
pub dev_dependencies2: Option<BTreeMap<PackageName, InheritableDependency>>,
pub pkgconfig_dependencies: Option<BTreeMap<String, TomlPkgConfigDependency>>,
}

impl TomlPlatform {
Expand Down
1 change: 1 addition & 0 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ mod links;
mod lto;
mod output_depinfo;
mod output_sbom;
pub mod pkgconfig;
pub mod rustdoc;
pub mod standard_lib;
mod timings;
Expand Down
Loading
Loading