Skip to content

Commit

Permalink
Make objc2 optional when translating frameworks
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Dec 19, 2024
1 parent 8ba2a96 commit 210befc
Show file tree
Hide file tree
Showing 67 changed files with 248 additions and 157 deletions.
6 changes: 5 additions & 1 deletion crates/header-translator/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,18 @@ impl MacroLocation {

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroEntity {
/// The name and location of the macro definition.
pub(crate) id: ItemIdentifier,
pub(crate) is_function_like: bool,
}

impl MacroEntity {
pub fn from_entity(entity: &Entity<'_>, context: &Context<'_>) -> Self {
let definition = entity.get_definition();
Self {
id: ItemIdentifier::new(entity, context),
// Try to get location from the definition itself, but if that
// doesn't exist, let's just get it from the entity.
id: ItemIdentifier::new(definition.as_ref().unwrap_or(entity), context),
is_function_like: entity.is_function_like_macro(),
}
}
Expand Down
80 changes: 50 additions & 30 deletions crates/header-translator/src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,18 @@ impl Location {
// These types are redefined in the framework crate itself.
"Darwin.MacTypes" => "__builtin__".into(),

// int8_t, int16_t etc., translated to i8, i16 etc.
"_stdint" => "__builtin__".into(),
// Implementation of the above
"DarwinFoundation.types.machine_types" => "__builtin__".into(),

// `core::ffi` types
"DarwinFoundation.types.machine_types" => "__core__.ffi".into(),
"_Builtin_stdarg.va_list" => {
error!("va_list is not yet supported");
warn!("va_list is not yet supported");
"__core__.ffi".into()
}
// c_float and c_double
"_float" | "_Builtin_float" => "__core__.ffi".into(),

// `libc`
name if name.starts_with("sys_types") => "__libc__".into(),
Expand Down Expand Up @@ -169,26 +175,6 @@ impl Location {
}
}

/// The place from where a given item exists.
pub fn import(&self, config: &Config, emission_library: &str) -> Option<Cow<'static, str>> {
match self.library_name() {
"__builtin__" => None,
// TODO: Use `core::xyz` here.
"__core__" => None,
// Rare enough that it's written directly instead of
// glob-imported, see `ItemIdentifier::path`.
"__bitflags__" | "__libc__" | "block" => None,
"ObjectiveC" => Some("objc2::__framework_prelude".into()),
// Not currently needed, but might be useful to emit
// `Some("crate")` here in the future.
library if library == emission_library => None,
library => {
let krate = &config.library(library).krate;
Some(krate.replace('-', "_").into())
}
}
}

// Feature names are based on the file name, not the whole path to the feature.
pub fn cargo_toml_feature(&self, config: &Config, emission_library: &str) -> Option<String> {
match self.library_name() {
Expand Down Expand Up @@ -240,7 +226,11 @@ impl Location {

// FIXME: This is currently wrong for nested umbrella frameworks
// (specifically MetalPerformanceShaders).
fn cfg_feature<'a>(&self, config: &'a Config, emission_library: &str) -> Option<Cow<'a, str>> {
pub fn cfg_feature<'a>(
&self,
config: &'a Config,
emission_library: &str,
) -> Option<Cow<'a, str>> {
match self.library_name() {
"__builtin__" | "__core__" => None,
library if library == emission_library => {
Expand Down Expand Up @@ -317,10 +307,14 @@ impl<N: ToOptionString> ItemIdentifier<N> {
.get_location()
.unwrap_or_else(|| panic!("no entity location: {entity:?}"))
.get_expansion_location()
.file
.expect("expanded location file");
.file;

let mut location = Location::from_file(file);
let mut location = if let Some(file) = file {
Location::from_file(file)
} else {
// Assume item to be a built-in macro like __nonnull if no file.
Location::new("__builtin__")
};

// Defined in multiple places for some reason.
if let Some("IOSurfaceRef" | "__IOSurface") = name.to_option() {
Expand Down Expand Up @@ -399,14 +393,14 @@ impl ItemIdentifier {
pub fn core_ffi(name: &str) -> Self {
Self {
name: name.into(),
location: Location::new("ObjectiveC"), // Temporary
location: Location::new("__core__.ffi"),
}
}

pub fn core_ptr(name: &str) -> Self {
pub fn core_ptr_nonnull() -> Self {
Self {
name: name.into(),
location: Location::new("ObjectiveC"), // Temporary
name: "NonNull".into(),
location: Location::new("__core__.ptr"),
}
}

Expand All @@ -433,6 +427,32 @@ impl ItemIdentifier {
self.location.library_name() == "Foundation" && self.name == "NSComparator"
}

/// The import needed for a given item to exist.
pub fn import(&self, config: &Config, emission_library: &str) -> Option<Cow<'static, str>> {
match self.library_name() {
"__builtin__" => None,
"__core__" => match &*self.location().module_path {
"__core__.ffi" => Some("core::ffi::*".into()),
"__core__.ptr" if self.name == "NonNull" => Some("core::ptr::NonNull".into()),
_ => {
error!("unknown __core__: {self:?}");
None
}
},
// Rare enough that it's written directly instead of
// glob-imported, see `ItemIdentifier::path` below.
"__bitflags__" | "__libc__" | "block" => None,
"ObjectiveC" => Some("objc2::__framework_prelude::*".into()),
// Not currently needed, but might be useful to emit
// `Some("crate")` here in the future.
library if library == emission_library => None,
library => {
let krate = &config.library(library).krate;
Some(format!("{}::*", krate.replace('-', "_")).into())
}
}
}

pub fn path(&self) -> impl fmt::Display + '_ {
struct ItemIdentifierPath<'a>(&'a ItemIdentifier);

Expand Down
10 changes: 10 additions & 0 deletions crates/header-translator/src/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ impl Library {
}
}

// Encode need the inner encode impl to be available.
if self.data.required_crates.contains("objc2") {
for (krate, (_, _, krate_features)) in &mut dependencies {
let data = config.library_from_crate(krate);
if !data.required_crates.contains("objc2") && !data.skipped {
krate_features.insert("objc2".into());
}
}
}

dependencies
}

Expand Down
22 changes: 13 additions & 9 deletions crates/header-translator/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,25 +80,29 @@ impl Module {
.iter()
.flat_map(|stmt| stmt.required_items_inner())
.filter_map(|item| {
item.location()
.import(config, emission_library)
.map(|import_data| (item.library_name().to_string(), import_data))
item.import(config, emission_library).map(|import| {
(
import,
(
item.location().cfg_feature(config, emission_library),
item.library_name().to_string(),
),
)
})
})
.collect();

let emission_config = &config.library(emission_library);
for (library_name, import) in imports {
let krate = &config.library(&library_name).krate;
let required = emission_config.required_crates.contains(krate);
if !required {
writeln!(f, "#[cfg(feature = {krate:?})]")?;
for (import, (cfg_feature, library_name)) in imports {
if let Some(cfg_feature) = cfg_feature {
writeln!(f, "#[cfg(feature = {cfg_feature:?})]")?;
}
let mut platform_cfg = PlatformCfg::from_config(emission_config);
platform_cfg.dependency(config.library(&library_name));
if let Some(cfg) = platform_cfg.cfgs() {
writeln!(f, "#[cfg({cfg})]")?;
}
writeln!(f, "use {import}::*;")?;
writeln!(f, "use {import};")?;
}
writeln!(f)?;
writeln!(f, "use crate::*;")?;
Expand Down
4 changes: 2 additions & 2 deletions crates/header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1159,7 +1159,7 @@ impl Ty {
} => {
let mut items = pointee.required_items();
if *nullability == Nullability::NonNull {
items.push(ItemIdentifier::core_ptr("NonNull"));
items.push(ItemIdentifier::core_ptr_nonnull());
}
items
}
Expand All @@ -1172,7 +1172,7 @@ impl Ty {
let mut items = to.required_items();
items.push(id.clone());
if *nullability == Nullability::NonNull {
items.push(ItemIdentifier::core_ptr("NonNull"));
items.push(ItemIdentifier::core_ptr_nonnull());
}
items
}
Expand Down
55 changes: 45 additions & 10 deletions crates/header-translator/src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1544,15 +1544,10 @@ impl Stmt {
for (_, field_ty) in fields {
items.extend(field_ty.required_items());
}
items.push(ItemIdentifier::objc("Encoding"));
items
}
// Variants manage required items themselves
Self::EnumDecl { ty, .. } => {
let mut items = ty.required_items();
items.push(ItemIdentifier::objc("Encoding"));
items
}
Self::EnumDecl { ty, .. } => ty.required_items(),
Self::ConstDecl { ty, value, .. } => {
let mut items = ty.required_items();
items.extend(value.required_items());
Expand Down Expand Up @@ -1600,6 +1595,7 @@ impl Stmt {
.iter()
.flat_map(|method| method.required_items())
.collect(),
Self::StructDecl { .. } => vec![ItemIdentifier::objc("Encoding")],
Self::EnumDecl { kind, variants, .. } => {
let mut items: Vec<_> = variants
.iter()
Expand All @@ -1608,6 +1604,7 @@ impl Stmt {
if let Some(UnexposedAttr::Options) = kind {
items.push(ItemIdentifier::bitflags());
}
items.push(ItemIdentifier::objc("Encoding"));
items
}
_ => vec![],
Expand Down Expand Up @@ -1720,6 +1717,13 @@ impl Stmt {
return Ok(());
}

let cfg = cfg_gate_ln(
[ItemIdentifier::objc("extern_class")],
[self.location()],
config,
self.location(),
);
write!(f, "{cfg}")?;
writeln!(f, "extern_class!(")?;
writeln!(f, " /// {}", id.doc_link())?;
write!(f, " #[unsafe(super(")?;
Expand Down Expand Up @@ -1772,6 +1776,13 @@ impl Stmt {
category_name,
methods,
} => {
let cfg = cfg_gate_ln(
[ItemIdentifier::objc("extern_methods")],
[self.location()],
config,
self.location(),
);
write!(f, "{cfg}")?;
writeln!(f, "extern_methods!(")?;
if let Some(source_superclass) = source_superclass {
writeln!(
Expand Down Expand Up @@ -1845,6 +1856,13 @@ impl Stmt {
cls_required_items,
methods,
} => {
let cfg = cfg_gate_ln(
[ItemIdentifier::objc("extern_category")],
[self.location()],
config,
self.location(),
);
write!(f, "{cfg}")?;
writeln!(f, "extern_category!(")?;

if let Some(actual_name) = actual_name {
Expand Down Expand Up @@ -2038,6 +2056,13 @@ impl Stmt {
required_sendable: _,
required_mainthreadonly,
} => {
let cfg = cfg_gate_ln(
[ItemIdentifier::objc("extern_protocol")],
[self.location()],
config,
self.location(),
);
write!(f, "{cfg}")?;
writeln!(f, "extern_protocol!(")?;

writeln!(f, " /// {}", id.doc_link())?;
Expand Down Expand Up @@ -2141,6 +2166,11 @@ impl Stmt {
writeln!(f, "}}")?;
writeln!(f)?;

let mut required_items = self.required_items();
required_items.push(ItemIdentifier::objc("Encoding"));
let cfg_encoding =
cfg_gate_ln(required_items, [self.location()], config, self.location());

let encoding = FormatterFn(|f| {
write!(
f,
Expand All @@ -2155,9 +2185,9 @@ impl Stmt {
});

// SAFETY: The struct is marked `#[repr(C)]`.
write!(f, "{}", self.cfg_gate_ln(config))?;
write!(f, "{cfg_encoding}")?;
writeln!(f, "{}", unsafe_impl_encode(&id.name, encoding))?;
write!(f, "{}", self.cfg_gate_ln(config))?;
write!(f, "{cfg_encoding}")?;
writeln!(f, "{}", unsafe_impl_refencode(&id.name))?;

if let Some(true) = sendable {
Expand Down Expand Up @@ -2316,12 +2346,17 @@ impl Stmt {
_ => panic!("invalid enum kind"),
}

let mut required_items = self.required_items();
required_items.push(ItemIdentifier::objc("Encoding"));
let cfg_encoding =
cfg_gate_ln(required_items, [self.location()], config, self.location());

// SAFETY: The enum is either a `#[repr(transparent)]` newtype
// over the type, or a `#[repr(REPR)]`, where REPR is a valid
// repr with the same size and alignment as the type.
write!(f, "{}", self.cfg_gate_ln(config))?;
write!(f, "{cfg_encoding}")?;
writeln!(f, "{}", unsafe_impl_encode(&id.name, ty.enum_encoding()))?;
write!(f, "{}", self.cfg_gate_ln(config))?;
write!(f, "{cfg_encoding}")?;
writeln!(f, "{}", unsafe_impl_refencode(&id.name))?;

if let Some(true) = sendable {
Expand Down
7 changes: 0 additions & 7 deletions crates/objc2/src/__framework_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@
// Note: While this is not public, it is still a breaking change to remove
// entries in here, since framework crates rely on it.

pub use core::ffi::{
c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
c_ulong, c_ulonglong, c_ushort, c_void,
};
pub use core::marker::PhantomData;
pub use core::ptr::NonNull;

pub use crate::encode::{Encode, Encoding, RefEncode};
pub use crate::ffi::{NSInteger, NSIntegerMax, NSUInteger, NSUIntegerMax};
pub use crate::rc::{Allocated, DefaultRetained, Retained};
Expand Down
4 changes: 2 additions & 2 deletions framework-crates/objc2-accessibility/Cargo.toml

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

4 changes: 2 additions & 2 deletions framework-crates/objc2-app-kit/Cargo.toml

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

Loading

0 comments on commit 210befc

Please sign in to comment.