Skip to content

Commit

Permalink
Add the MetalPerformanceShaders framework
Browse files Browse the repository at this point in the history
The exact semantics of Cargo features in umbrella frameworks are still
undecided, see #640.

So for now I've gone with the solution that required the least
code-changes, which is that each file still gets its own feature.
  • Loading branch information
madsmtm committed Dec 15, 2024
1 parent bbaee24 commit b09d17b
Show file tree
Hide file tree
Showing 19 changed files with 1,017 additions and 62 deletions.
22 changes: 11 additions & 11 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions Cargo.lock

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

2 changes: 0 additions & 2 deletions crates/header-translator/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@ pub struct LibraryConfig {
pub framework: String,
#[serde(rename = "crate")]
pub krate: String,
#[serde(rename = "umbrella-header")]
pub umbrella_header: Option<String>,
/// Dependencies are optional by default, this can be used to make a
/// dependency required.
///
Expand Down
57 changes: 49 additions & 8 deletions crates/header-translator/src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::BTreeSet;

use clang::source::Module;
use clang::source::{File, Module};
use clang::Entity;

use crate::cfgs::PlatformCfg;
Expand Down Expand Up @@ -152,6 +152,49 @@ impl Location {
})
}

pub fn from_file(file: File<'_>) -> Self {
// Get from module first if available
if let Some(module) = file.get_module() {
return Location::from_module(module);
}

let path = file.get_path();

if !path.to_string_lossy().contains("System/Library/Frameworks") {
// Likely a built-in macro from stddef.h, stdarg.h or assert.h.
return Location::from_components(vec!["System".into()]);
}

// The item likely comes from a private sub-framework, so let's try
// to parse framework names from the sub-framework here.
let mut components: Vec<Cow<'_, str>> = path
.components()
.map(|component| component.as_os_str())
.skip_while(|s| !s.as_encoded_bytes().ends_with(b".sdk"))
.skip(1)
.map(|s| s.to_str().expect("component to_str"))
.filter(|s| !matches!(*s, "System" | "Library" | "Frameworks" | "Headers"))
.map(|component| component.strip_suffix(".framework").unwrap_or(component))
.map(|component| component.strip_suffix(".h").unwrap_or(component))
.map(|s| s.to_string().into())
.collect();

if let [.., second_last, last] = &*components {
if second_last == last {
// Remove umbrella header
components.pop();
}
}

Self::from_components(components)
}

pub(crate) fn components(
&self,
) -> impl DoubleEndedIterator<Item = &str> + ExactSizeIterator + '_ {
self.path_components.iter().map(|c| &**c)
}

pub(crate) fn from_components(path_components: Vec<Cow<'static, str>>) -> Self {
Self { path_components }
}
Expand Down Expand Up @@ -195,7 +238,10 @@ impl Location {
}
} else {
let file_name = self.file_name();
let required = config.libraries[emission_library]
let required = config
.libraries
.get(emission_library)
.unwrap_or_else(|| panic!("{emission_library} not found in libraries"))
.required_dependencies
.contains(krate);
LocationLibrary::InExternalLibrary {
Expand Down Expand Up @@ -275,12 +321,7 @@ impl<N: ToOptionString> ItemIdentifier<N> {
.file
.expect("expanded location file");

let mut location = if let Some(module) = file.get_module() {
Location::from_module(module)
} else {
// If file module is not available, the item is likely a built-in macro.
Location::from_components(vec!["System".into()])
};
let mut location = Location::from_file(file);

// Defined in multiple places for some reason.
if let Some("IOSurfaceRef" | "__IOSurface") = name.to_option() {
Expand Down
31 changes: 14 additions & 17 deletions crates/header-translator/src/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::config::LibraryConfig;
use crate::display_helper::FormatterFn;
use crate::module::Module;
use crate::Config;
use crate::Location;
use crate::VERSION;

#[derive(Debug, PartialEq)]
Expand All @@ -24,7 +25,7 @@ pub struct Library {
pub data: LibraryConfig,
}

type Dependencies<'c> = BTreeMap<&'c str, (bool, String, BTreeSet<String>)>;
pub(crate) type Dependencies<'c> = BTreeMap<&'c str, (bool, String, BTreeSet<String>)>;

impl Library {
pub fn new(name: &str, data: &LibraryConfig) -> Self {
Expand All @@ -35,26 +36,20 @@ impl Library {
}
}

pub fn add_module(&mut self, components: Vec<String>) {
pub fn add_module(&mut self, location: Location) {
let mut current = &mut self.module;
for component in components {
current = current.submodules.entry(component).or_default();
for component in location.components().skip(1) {
current = current.submodules.entry(component.into()).or_default();
}
}

pub fn module_mut(&mut self, mut module: clang::source::Module<'_>) -> &mut Module {
let mut components = vec![];
while let Some(parent) = module.get_parent() {
components.insert(0, module.get_name());
module = parent;
}

pub fn module_mut(&mut self, location: Location) -> &mut Module {
let mut current = &mut self.module;
for component in components {
current = match current.submodules.entry(component) {
for component in location.components().skip(1) {
current = match current.submodules.entry(component.into()) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
error!(?module, "expected module to be available in library");
error!(?location, "expected module to be available in library");
entry.insert(Default::default())
}
};
Expand Down Expand Up @@ -382,9 +377,11 @@ see that for related crates.", self.data.krate, self.link_name)?;
add_newline_at_end(&mut cargo_toml["features"]);

// Own features
let mut generated_features = self
.module
.required_cargo_features_inner(config, &self.link_name);
let mut generated_features = self.module.required_cargo_features_inner(
config,
&self.link_name,
&dependency_map[&*self.link_name],
);

let _ = generated_features.insert(
"all".to_string(),
Expand Down
17 changes: 6 additions & 11 deletions crates/header-translator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use tracing_subscriber::util::SubscriberInitExt;
use tracing_tree::HierarchicalLayer;

use header_translator::{
global_analysis, run_cargo_fmt, Config, Context, Library, LibraryConfig, MacroEntity,
global_analysis, run_cargo_fmt, Config, Context, Library, LibraryConfig, Location, MacroEntity,
MacroLocation, Stmt,
};

Expand Down Expand Up @@ -304,15 +304,9 @@ fn parse_framework(tu: TranslationUnit<'_>, context: &mut Context<'_>, library:
match entity.get_kind() {
EntityKind::InclusionDirective if preprocessing => {
let file = entity.get_file().expect("inclusion directive has file");
if let Some(mut module) = file.get_module() {
let mut components = vec![];
while let Some(parent) = module.get_parent() {
components.insert(0, module.get_name());
module = parent;
}
if module.get_name() == library.data.framework {
library.add_module(components);
}
let location = Location::from_file(file);
if location.library_name() == library.data.framework {
library.add_module(location);
}
}
EntityKind::MacroExpansion if preprocessing => {
Expand All @@ -337,8 +331,9 @@ fn parse_framework(tu: TranslationUnit<'_>, context: &mut Context<'_>, library:
.get_expansion_location()
.file
.expect("expanded location file");
let location = Location::from_file(file);

let module = library.module_mut(file.get_module().expect("file module"));
let module = library.module_mut(location);
for stmt in Stmt::parse(&entity, context) {
module.add_stmt(stmt);
}
Expand Down
35 changes: 25 additions & 10 deletions crates/header-translator/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{fmt, fs};
use crate::cfgs::PlatformCfg;
use crate::display_helper::FormatterFn;
use crate::id::{cfg_gate_ln, Location};
use crate::library::Dependencies;
use crate::stmt::Stmt;
use crate::{Config, ItemIdentifier};

Expand Down Expand Up @@ -45,6 +46,7 @@ impl Module {
&self,
config: &Config,
emission_library: &str,
dependencies: &Dependencies<'_>,
) -> BTreeMap<String, BTreeSet<String>> {
let mut required_features: BTreeMap<String, BTreeSet<String>> = BTreeMap::new();

Expand All @@ -59,15 +61,23 @@ impl Module {
.library(config, emission_library)
.cargo_toml_feature()
{
if feature == "bitflags" {
if let Some((true, _, _)) = dependencies.get("bitflags") {
continue;
}
}
// Feature names are based on the file name, not the
// whole path to the feature.
features.insert(feature);
}
}
}
required_features.insert(clean_name(file_name), features);
required_features
.extend(module.required_cargo_features_inner(config, emission_library));
required_features.extend(module.required_cargo_features_inner(
config,
emission_library,
dependencies,
));
}

required_features
Expand Down Expand Up @@ -120,22 +130,27 @@ impl Module {
FormatterFn(move |f| {
for (name, module) in &self.submodules {
let name = clean_name(name);
write!(f, "#[cfg(feature = \"{name}\")]")?;
if module.submodules.is_empty() {
write!(f, "#[cfg(feature = \"{name}\")]")?;
writeln!(f, "#[path = \"{name}.rs\"]")?;
writeln!(f, "mod __{name};")?;
} else {
write!(f, "#[cfg(feature = \"{name}\")]")?;
writeln!(f, "mod {name};")?;
writeln!(f, "#[path = \"{name}/mod.rs\"]")?;
}
writeln!(f, "mod __{name};")?;
}

writeln!(f)?;

for (file_name, file) in &self.submodules {
for stmt in &file.stmts {
for (module_name, module) in &self.submodules {
if !module.submodules.is_empty() {
write!(f, "#[cfg(feature = \"{module_name}\")]")?;
write!(f, "pub use self::__{}::*;", clean_name(module_name))?;
continue;
}

for stmt in &module.stmts {
if let Some(item) = stmt.provided_item() {
item.location().assert_file(file_name);
item.location().assert_file(module_name);

let mut items = stmt.required_items();
items.push(item.clone());
Expand All @@ -153,7 +168,7 @@ impl Module {
write!(
f,
"{visibility} use self::__{}::{{{}}};",
clean_name(file_name),
clean_name(module_name),
item.name,
)?;
}
Expand Down
5 changes: 4 additions & 1 deletion crates/header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,9 @@ impl Ty {
ty = modified;
} else {
error!("expected unexposed / attributed type to have modified type");
ty = ty.get_canonical_type();
name = ty.get_display_name();
break;
}
}

Expand Down Expand Up @@ -691,7 +694,7 @@ impl Ty {
Self::AnyProtocol
} else {
let decl = ItemRef::new(&declaration, context);
if decl.id.name != name {
if decl.id.name != name.strip_prefix("const ").unwrap_or(&name) {
error!(?name, "invalid interface name");
}
Self::Class {
Expand Down
8 changes: 8 additions & 0 deletions crates/header-translator/src/unexposed_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ impl UnexposedAttr {
| "MLCOMPUTE_AVAILABLE_STARTING_BUT_DEPRECATED_MACOS14"
| "MLCOMPUTE_CLASS_AVAILABLE_STARTING"
| "MLCOMPUTE_ENUM_AVAILABLE_STARTING"
| "MPS_AVAILABLE_STARTING"
| "MPS_AVAILABLE_STARTING_BUT_DEPRECATED"
| "MPS_CLASS_AVAILABLE_STARTING"
| "MPS_ENUM_AVAILABLE_STARTING"
| "MPS_ENUM_AVAILABLE_STARTING_BUT_DEPRECATED"
| "MPS_UNAVAILABLE"
| "MODELCOLLECTION_SUNSET"
| "MP_API"
| "MP_DEPRECATED"
Expand Down Expand Up @@ -215,6 +221,7 @@ impl UnexposedAttr {
| "AVKIT_INIT_UNAVAILABLE"
| "CA_CANONICAL_DEPRECATED"
| "CB_CM_API_AVAILABLE"
| "DEPRECATED_ATTRIBUTE"
| "MP_INIT_UNAVAILABLE"
| "CF_AUTOMATED_REFCOUNT_UNAVAILABLE"
| "CG_OBSOLETE"
Expand All @@ -232,6 +239,7 @@ impl UnexposedAttr {
| "CF_SWIFT_UNAVAILABLE_FROM_ASYNC"
| "DISPATCH_SWIFT_NAME"
| "IOSFC_SWIFT_NAME"
| "MPS_SWIFT_NAME"
| "NS_REFINED_FOR_SWIFT_ASYNC"
| "NS_SWIFT_ASYNC_NAME"
| "NS_SWIFT_ASYNC_THROWS_ON_FALSE"
Expand Down
1 change: 1 addition & 0 deletions crates/objc2/src/topics/about_generated/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `CoreVideo` / `objc2-core-video`.
- `EventKitUI` / `objc2-event-kit-ui`.
- `IOSurface` / `objc2-io-surface`.
- `MetalPerformanceShaders` / `objc2-metal-performance-shaders`.
- `ScreenSaver` / `objc2-screen-saver`.
* Added `#[must_use]` attributes where the C headers have them.

Expand Down
1 change: 1 addition & 0 deletions crates/objc2/src/topics/about_generated/list_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
| `Metal` | [![`objc2-metal`](https://badgen.net/crates/v/objc2-metal)](https://crates.io/crates/objc2-metal) | [![docs.rs](https://docs.rs/objc2-metal/badge.svg)](https://docs.rs/objc2-metal/) |
| `MetalFX` | [![`objc2-metal-fx`](https://badgen.net/crates/v/objc2-metal-fx)](https://crates.io/crates/objc2-metal-fx) | [![docs.rs](https://docs.rs/objc2-metal-fx/badge.svg)](https://docs.rs/objc2-metal-fx/) |
| `MetalKit` | [![`objc2-metal-kit`](https://badgen.net/crates/v/objc2-metal-kit)](https://crates.io/crates/objc2-metal-kit) | [![docs.rs](https://docs.rs/objc2-metal-kit/badge.svg)](https://docs.rs/objc2-metal-kit/) |
| `MetalPerformanceShaders` | [![`objc2-metal-performance-shaders`](https://badgen.net/crates/v/objc2-metal-performance-shaders)](https://crates.io/crates/objc2-metal-performance-shaders) | [![docs.rs](https://docs.rs/objc2-metal-performance-shaders/badge.svg)](https://docs.rs/objc2-metal-performance-shaders/) |
| `MetricKit` | [![`objc2-metric-kit`](https://badgen.net/crates/v/objc2-metric-kit)](https://crates.io/crates/objc2-metric-kit) | [![docs.rs](https://docs.rs/objc2-metric-kit/badge.svg)](https://docs.rs/objc2-metric-kit/) |
| `MultipeerConnectivity` | [![`objc2-multipeer-connectivity`](https://badgen.net/crates/v/objc2-multipeer-connectivity)](https://crates.io/crates/objc2-multipeer-connectivity) | [![docs.rs](https://docs.rs/objc2-multipeer-connectivity/badge.svg)](https://docs.rs/objc2-multipeer-connectivity/) |
| `NaturalLanguage` | [![`objc2-natural-language`](https://badgen.net/crates/v/objc2-natural-language)](https://crates.io/crates/objc2-natural-language) | [![docs.rs](https://docs.rs/objc2-natural-language/badge.svg)](https://docs.rs/objc2-natural-language/) |
Expand Down
Loading

0 comments on commit b09d17b

Please sign in to comment.