Skip to content

Commit

Permalink
Automatically generate framework imports
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Sep 1, 2023
1 parent 7681f6c commit 5d4c0d4
Show file tree
Hide file tree
Showing 110 changed files with 252 additions and 517 deletions.
19 changes: 19 additions & 0 deletions crates/header-translator/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ pub struct LibraryData {
#[serde(rename = "gnustep-library")]
#[serde(default)]
pub gnustep_library: Option<String>,
#[serde(default)]
#[serde(rename = "extra-docs")]
pub extra_docs: String,
#[serde(default)]
#[serde(rename = "additions")]
pub has_additions: bool,
#[serde(default)]
#[serde(rename = "fixes")]
pub has_fixes: bool,
#[serde(rename = "extra-features")]
#[serde(default)]
pub extra_features: Vec<String>,
Expand All @@ -82,6 +91,16 @@ pub struct LibraryData {
pub tvos: Option<semver::VersionReq>,
#[serde(default)]
pub watchos: Option<semver::VersionReq>,
#[serde(default)]
pub examples: Vec<Example>,
}

#[derive(Deserialize, Debug, Default, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct Example {
pub name: String,
#[serde(default)]
pub description: String,
}

#[derive(Deserialize, Debug, Default, Clone, PartialEq, Eq)]
Expand Down
9 changes: 5 additions & 4 deletions crates/header-translator/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ use std::fmt;
use crate::context::Context;
use crate::stmt::Stmt;

pub(crate) const FILE_PRELUDE: &str = r#"//! This file has been automatically generated by `objc2`'s `header-translator`.
//! DO NOT EDIT"#;

#[derive(Debug, PartialEq)]
pub struct File {
library_name: String,
Expand Down Expand Up @@ -41,7 +38,11 @@ impl File {

impl fmt::Display for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{FILE_PRELUDE}")?;
writeln!(
f,
"//! This file has been automatically generated by `objc2`'s `header-translator`."
)?;
writeln!(f, "//! DO NOT EDIT")?;

writeln!(f, "use crate::common::*;")?;
writeln!(f, "use crate::{}::*;", self.library_name)?;
Expand Down
67 changes: 60 additions & 7 deletions crates/header-translator/src/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ use std::io;
use std::path::Path;

use crate::config::LibraryData;
use crate::file::{File, FILE_PRELUDE};
use crate::file::File;

#[derive(Debug, PartialEq, Default)]
pub struct Library {
pub files: BTreeMap<String, File>,
link_name: String,
gnustep_library: Option<String>,
data: LibraryData,
}

impl Library {
pub fn new(name: &str, data: &LibraryData) -> Self {
Self {
files: BTreeMap::new(),
link_name: name.to_string(),
gnustep_library: data.gnustep_library.clone(),
data: data.clone(),
}
}

Expand All @@ -46,11 +46,63 @@ impl Library {
}
}

fn prepare_for_docs(s: &str) -> String {
s.trim().replace('\n', "\n//! ")
}

impl fmt::Display for Library {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{FILE_PRELUDE}")?;
writeln!(f, "#![allow(unused_imports)]")?;
writeln!(f, "#![allow(deprecated)]")?;
let name = self.data.name.as_deref().unwrap_or(&self.link_name);
writeln!(
f,
"// This file has been automatically generated by `objc2`'s `header-translator`."
)?;
writeln!(f, "// DO NOT EDIT")?;
writeln!(f)?;
writeln!(f, "//! # Bindings to the `{name}` framework")?;
if !self.data.extra_docs.is_empty() {
writeln!(f, "//!")?;
writeln!(f, "//! {}.", prepare_for_docs(&self.data.extra_docs))?;
}
if !self.data.examples.is_empty() {
writeln!(f, "//!")?;
writeln!(f, "//!")?;
let examples_plural = if self.data.examples.len() > 1 {
"s"
} else {
""
};
writeln!(f, "//! ## Example{examples_plural}")?;
for example in &self.data.examples {
writeln!(f, "//!")?;
writeln!(f, "//! {}.", prepare_for_docs(&example.description))?;
writeln!(f, "//!")?;
writeln!(f, "//! ```ignore")?;
writeln!(
f,
"#![doc = include_str!(\"../../../examples/{}.rs\")]",
example.name
)?;
writeln!(f, "//! ```")?;
}
}
if self.data.name.is_some() {
writeln!(f, "#![doc(alias = \"{}\")]", self.link_name)?;
}
writeln!(f)?;

if self.data.has_additions {
writeln!(f, "#[path = \"../../additions/{name}/mod.rs\"]")?;
writeln!(f, "mod additions;")?;
writeln!(f, "pub use self::additions::*;")?;
}
writeln!(f)?;
if self.data.has_fixes {
writeln!(f, "#[path = \"../../fixes/{name}/mod.rs\"]")?;
writeln!(f, "mod fixes;")?;
writeln!(f, "pub use self::fixes::*;")?;
}
writeln!(f)?;

// Link to the correct framework
//
Expand All @@ -60,14 +112,15 @@ impl fmt::Display for Library {
"#[cfg_attr(feature = \"apple\", link(name = \"{}\", kind = \"framework\"))]",
self.link_name
)?;
if let Some(gnustep_library) = &self.gnustep_library {
if let Some(gnustep_library) = &self.data.gnustep_library {
writeln!(
f,
"#[cfg_attr(feature = \"gnustep-1-7\", link(name = \"{}\", kind = \"dylib\"))]",
gnustep_library
)?;
}
writeln!(f, "extern \"C\" {{}}")?;
writeln!(f)?;

for name in self.files.keys() {
// NOTE: some SDK files have '+' in the file name
Expand Down
14 changes: 11 additions & 3 deletions crates/header-translator/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::fs;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

Expand Down Expand Up @@ -138,19 +139,26 @@ fn main() -> Result<(), BoxError> {
cache.update(&mut final_result);
drop(span);

let generated_dir = crate_src.join("generated");
fs::create_dir_all(&generated_dir)?;

for (library_name, files) in &final_result.libraries {
let _span = info_span!("writing", library_name).entered();
let output_path = crate_src.join("generated").join(library_name);
std::fs::create_dir_all(&output_path)?;
let output_path = generated_dir.join(library_name);
fs::create_dir_all(&output_path)?;
files.output(&output_path).unwrap();
}

final_result
.output_module(&generated_dir.join("mod.rs"))
.unwrap();

let span = info_span!("writing features").entered();
const FEATURE_SECTION_PATTERN:
&str = "# This section has been automatically generated by `objc2`'s `header-translator`.\n# DO NOT EDIT\n";
let mut cargo_toml = {
let path = crate_src.parent().unwrap().join("Cargo.toml");
std::fs::OpenOptions::new()
fs::OpenOptions::new()
.read(true)
.write(true)
.append(true)
Expand Down
16 changes: 16 additions & 0 deletions crates/header-translator/src/output.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::fmt::{self, Write};
use std::fs;
use std::path::Path;
use std::str::FromStr;

use crate::config::{Config, LibraryData};
Expand Down Expand Up @@ -30,6 +33,19 @@ impl Output {
);
}

pub fn output_module(&self, path: &Path) -> fmt::Result {
let mut f = String::new();

for library_name in self.libraries.keys() {
writeln!(&mut f, "#[cfg(feature = \"{library_name}\")]")?;
writeln!(&mut f, "pub mod {library_name};")?;
}

fs::write(path, f).unwrap();

Ok(())
}

pub fn cargo_features(&self, config: &Config) -> BTreeMap<String, Vec<String>> {
let mut features = BTreeMap::new();

Expand Down
46 changes: 46 additions & 0 deletions crates/header-translator/translation-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ tvos = "9.0"
[library.AppKit]
imports = ["CoreData", "Foundation"]
gnustep-library = "gnustep-gui"
fixes = true
extra-features = [
# Temporary, since some structs and statics use these
"AppKit_NSApplication",
Expand All @@ -45,8 +46,17 @@ extra-features = [
macos = "10.0"
maccatalyst = "13.0"

[[library.AppKit.examples]]
name = "delegate"
description = "Implementing `NSApplicationDelegate` for a custom class"

[[library.AppKit.examples]]
name = "nspasteboard"
description = "An example showing basic and a bit more advanced usage of `NSPasteboard`"

[library.AuthenticationServices]
imports = ["AppKit", "Foundation"]
fixes = true
# Temporary, since some structs and statics use these
extra-features = ["Foundation_NSURL"]
macos = "10.15"
Expand Down Expand Up @@ -191,6 +201,14 @@ ios = "11.0"
[library.Foundation]
imports = []
gnustep-library = "gnustep-base"
extra-docs = """
This is the [`std`] equivalent for Objective-C, containing essential data
types, collections, and operating-system services.
See [Apple's documentation](https://developer.apple.com/documentation/foundation?language=objc)
"""
additions = true
fixes = true
extra-features = [
"objective-c",
"block",
Expand All @@ -211,8 +229,17 @@ ios = "2.0"
tvos = "9.0"
watchos = "2.0"

[[library.Foundation.examples]]
name = "basic_usage"
description = "Basic usage of a few Foundation types"

[[library.Foundation.examples]]
name = "speech_synthesis"
description = "An example showing how to define your own interfaces to parts that may be missing in `icrate`"

[library.GameController]
imports = ["AppKit", "Foundation"]
fixes = true
extra-features = [
"GameController_GCControllerAxisInput",
"GameController_GCControllerButtonInput",
Expand Down Expand Up @@ -255,11 +282,13 @@ ios = "11.0"

[library.InputMethodKit]
imports = ["AppKit", "Foundation"]
fixes = true
macos = "10.5"
maccatalyst = "13.0"

[library.LocalAuthentication]
imports = ["Foundation"]
fixes = true
macos = "10.10"
maccatalyst = "13.0"
ios = "8.0"
Expand All @@ -285,6 +314,7 @@ macos = "12.0"

[library.MapKit]
imports = ["AppKit", "Contacts", "CoreLocation", "Foundation"]
fixes = true
extra-features = [
"MapKit_MKDirectionsResponse",
"MapKit_MKETAResponse",
Expand All @@ -307,11 +337,17 @@ watchos = "5.0"

[library.Metal]
imports = ["Foundation"]
additions = true
fixes = true
macos = "10.11"
maccatalyst = "13.0"
ios = "8.0"
tvos = "9.0"

[[library.Metal.examples]]
name = "metal"
description = "Drawing a rotating triangle"

[library.MetalFX]
imports = ["Metal"]
macos = "13.0"
Expand All @@ -332,6 +368,7 @@ tvos = "9.0"

[library.MetricKit]
imports = ["Foundation"]
fixes = true
macos = "12.0"
maccatalyst = "13.0"
ios = "13.0"
Expand All @@ -351,6 +388,11 @@ macos = "10.4"

[library.QuartzCore]
name = "CoreAnimation"
fixes = true
extra-docs = """
This actually lives in the `QuartzCore` framework, but `CoreAnimation` is
the name that people use to refer to it.
"""
imports = ["Foundation"]
macos = "10.3"
maccatalyst = "13.0"
Expand Down Expand Up @@ -398,11 +440,15 @@ watchos = "3.0"

[library.WebKit]
imports = ["AppKit", "Foundation"]
fixes = true
extra-features = ["Foundation_NSAttributedString"]
macos = "10.2"
maccatalyst = "13.0"
ios = "16.0"

[[library.WebKit.examples]]
name = "browser"

###
### Attributes that change a function/method's calling convention.
###
Expand Down
4 changes: 0 additions & 4 deletions crates/icrate/src/Accessibility/mod.rs

This file was deleted.

4 changes: 0 additions & 4 deletions crates/icrate/src/AdServices/mod.rs

This file was deleted.

4 changes: 0 additions & 4 deletions crates/icrate/src/AdSupport/mod.rs

This file was deleted.

Loading

0 comments on commit 5d4c0d4

Please sign in to comment.