mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
generate multi platform targets
This commit is contained in:
@@ -89,11 +89,7 @@ extension ProjectSpec {
|
||||
settingPresets = jsonDictionary.json(atKeyPath: "settingPresets") ?? [:]
|
||||
let configs: [String: String] = jsonDictionary.json(atKeyPath: "configs") ?? [:]
|
||||
self.configs = configs.map { Config(name: $0, type: ConfigType(rawValue: $1)) }
|
||||
if jsonDictionary["targets"] == nil {
|
||||
targets = []
|
||||
} else {
|
||||
targets = try jsonDictionary.json(atKeyPath: "targets", invalidItemBehaviour: .fail)
|
||||
}
|
||||
self.targets = try Target.decodeTargets(jsonDictionary: jsonDictionary)
|
||||
schemes = try jsonDictionary.json(atKeyPath: "schemes")
|
||||
if jsonDictionary["options"] != nil {
|
||||
options = try jsonDictionary.json(atKeyPath: "options")
|
||||
|
||||
@@ -46,6 +46,76 @@ public struct Target {
|
||||
}
|
||||
}
|
||||
|
||||
extension Target {
|
||||
|
||||
static func decodeTargets(jsonDictionary: JSONDictionary) throws -> [Target] {
|
||||
guard jsonDictionary["targets"] != nil else {
|
||||
return []
|
||||
}
|
||||
let array: [JSONDictionary] = try jsonDictionary.json(atKeyPath: "targets", invalidItemBehaviour: .fail)
|
||||
|
||||
var targets: [JSONDictionary] = []
|
||||
|
||||
let platformReplacement = "$platform"
|
||||
|
||||
for json in array {
|
||||
|
||||
if let platforms = json["platform"] as? [String] {
|
||||
|
||||
for platform in platforms {
|
||||
var platformTarget = json
|
||||
|
||||
func replacePlatform(_ dictionary: JSONDictionary) -> JSONDictionary {
|
||||
var replaced = dictionary
|
||||
for (key, value) in dictionary {
|
||||
switch value {
|
||||
case let dictionary as JSONDictionary:
|
||||
replaced[key] = replacePlatform(dictionary)
|
||||
case let string as String:
|
||||
replaced[key] = string.replacingOccurrences(of: platformReplacement, with: platform)
|
||||
case let array as [JSONDictionary]:
|
||||
replaced[key] = array.map(replacePlatform)
|
||||
case let array as [String]:
|
||||
replaced[key] = array.map { $0.replacingOccurrences(of: platformReplacement, with: platform) }
|
||||
default: break
|
||||
}
|
||||
}
|
||||
return replaced
|
||||
}
|
||||
|
||||
platformTarget = replacePlatform(platformTarget)
|
||||
|
||||
platformTarget["platform"] = platform
|
||||
let platformSuffix = platformTarget["platformSuffix"] as? String ?? "_\(platform)"
|
||||
let platformPrefix = platformTarget["platformPrefix"] as? String ?? ""
|
||||
let name = platformTarget["name"] as? String ?? ""
|
||||
platformTarget["name"] = platformPrefix + name + platformSuffix
|
||||
|
||||
var settings = platformTarget["settings"] as? JSONDictionary ?? [:]
|
||||
if settings["configs"] != nil || settings["presets"] != nil || settings["base"] != nil {
|
||||
var base = settings["base"] as? JSONDictionary ?? [:]
|
||||
if base["PRODUCT_NAME"] == nil {
|
||||
base["PRODUCT_NAME"] = name
|
||||
}
|
||||
settings["base"] = base
|
||||
} else {
|
||||
if settings["PRODUCT_NAME"] == nil {
|
||||
settings["PRODUCT_NAME"] = name
|
||||
}
|
||||
}
|
||||
platformTarget["settings"] = settings
|
||||
|
||||
targets.append(platformTarget)
|
||||
}
|
||||
} else {
|
||||
targets.append(json)
|
||||
}
|
||||
}
|
||||
|
||||
return try targets.map { try Target(jsonDictionary: $0) }
|
||||
}
|
||||
}
|
||||
|
||||
extension Target: Equatable {
|
||||
|
||||
public static func ==(lhs: Target, rhs: Target) -> Bool {
|
||||
|
||||
@@ -64,6 +64,28 @@ func specLoadingTests() {
|
||||
try expect(target.dependencies[2]) == .framework("path")
|
||||
}
|
||||
|
||||
$0.it("parsed cross platform targets") {
|
||||
let targetDictionary: [String: Any] = [
|
||||
"name":"Framework",
|
||||
"platform": ["iOS", "tvOS"],
|
||||
"type": "framework",
|
||||
"sources": ["Framework", "Framework $platform"],
|
||||
"settings": ["SETTING": "value_$platform"],
|
||||
]
|
||||
|
||||
let spec = try getProjectSpec(["targets":[targetDictionary]])
|
||||
var target_iOS = Target(name: "Framework_iOS", type: .framework, platform: .iOS)
|
||||
var target_tvOS = Target(name: "Framework_tvOS", type: .framework, platform: .tvOS)
|
||||
|
||||
target_iOS.sources = ["Framework","Framework iOS"]
|
||||
target_tvOS.sources = ["Framework","Framework tvOS"]
|
||||
target_iOS.settings = ["PRODUCT_NAME": "Framework", "SETTING": "value_iOS"]
|
||||
target_tvOS.settings = ["PRODUCT_NAME": "Framework", "SETTING": "value_tvOS"]
|
||||
|
||||
try expect(spec.targets.count) == 2
|
||||
try expect(spec.targets) == [target_iOS, target_tvOS]
|
||||
}
|
||||
|
||||
$0.it("parses schemes") {
|
||||
let schemeDictionary: [String: Any] = [
|
||||
"build": ["targets": [
|
||||
@@ -138,5 +160,6 @@ func specLoadingTests() {
|
||||
let parsedSpec = try getProjectSpec(["options": ["carthageBuildPath": "../Carthage/Build"]])
|
||||
try expect(parsedSpec) == expected
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,30 @@ This will provide default build settings for a certain platform. It can be any o
|
||||
- macOS
|
||||
- watchOS
|
||||
|
||||
**Multi Platform targets**
|
||||
|
||||
You can also specify an array of platforms. This will generate a target for each platform.
|
||||
If you reference the string `$platform` anywhere within the target spec, that will be replaced with the platform.
|
||||
|
||||
The generated targets by default will have a suffix of `_$platform` applied, you can change this by specifying a `platformSuffix` or `platformPrefix`.
|
||||
|
||||
If no `PRODUCT_NAME` build setting is specified for a target, this will be set to the target name, so that this target can be imported under a single name.
|
||||
|
||||
```
|
||||
name: MyFramework
|
||||
sources: MyFramework
|
||||
platform: [iOS, tvOS]
|
||||
type: framework
|
||||
settings:
|
||||
base:
|
||||
INFOPLIST_FILE: MyApp/Info.plist
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.myapp
|
||||
MY_SETTING: platform $platform
|
||||
presets:
|
||||
- $platform
|
||||
```
|
||||
The above will generate 2 targets named `MyFramework_iOS` and `MyFramework_tvOS`, with all the relevant platform build settings. They will both have a `PRODUCT_NAME` of `MyFramework`
|
||||
|
||||
### Sources
|
||||
Specifies the source directories for a target. This can either be a single path or a list of paths. Applicable source files, resources, headers, and lproj files will be parsed appropriately
|
||||
|
||||
|
||||
Reference in New Issue
Block a user