polyhorn_cli/ios/xcodegen/mod.rs
1//! Rust-wrapper around the third-party `xcodegen` utility (installed through
2//! Homebrew) that makes it possible to generate Xcode project files
3//! programmatically. Note: the documentation within this module is taken
4//! directly from the original excellent documentation of `xcodegen`.
5
6use serde::{Deserialize, Serialize};
7use std::collections::{HashMap, HashSet};
8
9/// Contains the `xcodegen` specification of a project.
10#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
11pub struct Project {
12 /// Name of the generated project.
13 pub name: String,
14
15 /// The list of targets in the project mapped by name.
16 pub targets: HashMap<String, Target>,
17}
18
19/// Represents a target that is built within a project.
20#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
21pub struct Target {
22 /// Product type of the target.
23 #[serde(rename = "type")]
24 pub product_type: ProductType,
25
26 /// Platform of the target.
27 pub platform: HashSet<Platform>,
28
29 /// The deployment target (e.g. `9.2`). If this is not specified the value
30 /// from the project set in `Options.deploymentTarget.PLATFORM` will be used.
31 #[serde(rename = "deploymentTarget")]
32 pub deployment_targets: HashMap<Platform, String>,
33
34 /// Source directories of the target.
35 pub sources: Vec<TargetSource>,
36
37 /// Target specific build settings. Default platform and product type
38 /// settings will be applied first before any custom settings defined here.
39 /// Other context dependant settings will be set automatically as well.
40 pub settings: HashMap<String, String>,
41
42 /// Dependencies for the target.
43 pub dependencies: Vec<Dependency>,
44}
45
46/// This will provide default build settings for a certain product type.
47#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
48pub enum ProductType {
49 /// Represents a regular application.
50 #[serde(rename = "application")]
51 Application,
52
53 /// Represents an App Clip.
54 #[serde(rename = "application-on-demand-install-capable")]
55 ApplicationOnDemandInstallCapable,
56}
57
58/// Indicates the platform that a target's product can run on.
59#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
60pub enum Platform {
61 /// Represents an application or extension that runs on iOS.
62 #[serde(rename = "iOS")]
63 IOS,
64
65 /// Represents an application or extension that runs on macOS.
66 #[serde(rename = "macOS")]
67 MacOS,
68
69 /// Represents an application or extension that runs on tvOS.
70 #[serde(rename = "tvOS")]
71 TVOS,
72
73 /// Represents an application or extension that runs on watchOS.
74 #[serde(rename = "watchOS")]
75 WatchOS,
76}
77
78/// Represents a source location that is included for a particular target within
79/// an Xcode project.
80#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
81pub struct TargetSource {
82 /// The path of the source file or directory.
83 pub path: String,
84}
85
86/// Represents a dependency of a target. Currently, only frameworks are
87/// supported. Note that framework dependencies are also used by `xcodegen` to
88/// refer to static libraries (despite the fact that frameworks are dynamic).
89#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
90#[serde(untagged)]
91pub enum Dependency {
92 /// Represents a framework dependency.
93 Framework {
94 /// Name or path of framework to link.
95 framework: String,
96
97 /// Whether or not to include a copy of the framework within the app's
98 /// bundle. This should be false for a static library because it's
99 /// unnecessary to include the `lib*.a` file in the bundle and
100 /// additionally, Apple might reject apps that do ship static libraries
101 /// that are not linked to the executable.
102 embed: bool,
103 },
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_spec() {
112 let project = Project {
113 name: "Example".to_owned(),
114 targets: vec![(
115 "Example".to_owned(),
116 Target {
117 product_type: ProductType::Application,
118 platform: vec![Platform::IOS].into_iter().collect(),
119 deployment_targets: vec![(Platform::IOS, "8.0".to_owned())]
120 .into_iter()
121 .collect(),
122 sources: vec![TargetSource {
123 path: "Sources".to_owned(),
124 }],
125 settings: vec![
126 (
127 "LIBRARY_SEARCH_PATHS".to_owned(),
128 "../x86_64-apple-ios/debug".to_owned(),
129 ),
130 ("OTHER_LDFLAGS".to_owned(), "-ObjC".to_owned()),
131 ]
132 .into_iter()
133 .collect(),
134 dependencies: vec![Dependency::Framework {
135 framework: "libexample.a".to_owned(),
136 embed: false,
137 }],
138 },
139 )]
140 .into_iter()
141 .collect(),
142 };
143
144 let result = serde_yaml::to_string(&project).unwrap();
145 println!("Result: {}", result);
146 }
147}