2017-07-23 21:58:03 +03:00
|
|
|
import Foundation
|
|
|
|
import PathKit
|
2018-01-24 10:22:46 +03:00
|
|
|
import ProjectSpec
|
2019-06-07 23:36:48 +03:00
|
|
|
import XcodeProj
|
2017-07-23 21:58:03 +03:00
|
|
|
import Yams
|
2020-02-07 02:40:24 +03:00
|
|
|
import Version
|
2017-07-23 21:58:03 +03:00
|
|
|
|
|
|
|
public class PBXProjGenerator {
|
|
|
|
|
2018-04-12 16:13:40 +03:00
|
|
|
let project: Project
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-04-12 16:13:40 +03:00
|
|
|
let pbxProj: PBXProj
|
2019-10-09 10:08:28 +03:00
|
|
|
let projectDirectory: Path?
|
2019-02-07 22:55:37 +03:00
|
|
|
let carthageResolver: CarthageDependencyResolver
|
|
|
|
|
2018-01-24 10:22:46 +03:00
|
|
|
var sourceGenerator: SourceGenerator!
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
var targetObjects: [String: PBXTarget] = [:]
|
|
|
|
var targetAggregateObjects: [String: PBXAggregateTarget] = [:]
|
2018-09-25 14:11:04 +03:00
|
|
|
var targetFileReferences: [String: PBXFileReference] = [:]
|
2018-11-02 09:55:24 +03:00
|
|
|
var sdkFileReferences: [String: PBXFileReference] = [:]
|
2019-08-13 14:51:47 +03:00
|
|
|
var packageReferences: [String: XCRemoteSwiftPackageReference] = [:]
|
2018-07-23 14:57:17 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
var carthageFrameworksByPlatform: [String: Set<PBXFileElement>] = [:]
|
|
|
|
var frameworkFiles: [PBXFileElement] = []
|
2019-11-18 12:07:46 +03:00
|
|
|
var bundleFiles: [PBXFileElement] = []
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-11-12 20:52:11 +03:00
|
|
|
var generated = false
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2020-02-02 01:44:56 +03:00
|
|
|
private var projects: [ProjectReference: PBXProj] = [:]
|
|
|
|
|
2019-10-21 21:08:48 +03:00
|
|
|
public init(project: Project, projectDirectory: Path? = nil) {
|
2018-04-12 16:13:40 +03:00
|
|
|
self.project = project
|
2019-02-07 22:55:37 +03:00
|
|
|
carthageResolver = CarthageDependencyResolver(project: project)
|
2019-01-24 15:34:54 +03:00
|
|
|
pbxProj = PBXProj(rootObject: nil, objectVersion: project.objectVersion)
|
2019-10-09 10:08:28 +03:00
|
|
|
self.projectDirectory = projectDirectory
|
2019-10-08 14:00:41 +03:00
|
|
|
sourceGenerator = SourceGenerator(project: project,
|
|
|
|
pbxProj: pbxProj,
|
2019-10-08 16:52:51 +03:00
|
|
|
projectDirectory: projectDirectory)
|
2018-01-24 10:22:46 +03:00
|
|
|
}
|
|
|
|
|
2019-08-13 14:51:47 +03:00
|
|
|
@discardableResult
|
2018-10-16 13:35:31 +03:00
|
|
|
func addObject<T: PBXObject>(_ object: T, context: String? = nil) -> T {
|
2018-09-25 14:11:04 +03:00
|
|
|
pbxProj.add(object: object)
|
2018-10-16 13:35:31 +03:00
|
|
|
object.context = context
|
2018-09-25 14:08:11 +03:00
|
|
|
return object
|
2017-08-25 14:48:07 +03:00
|
|
|
}
|
|
|
|
|
2017-07-23 21:58:03 +03:00
|
|
|
public func generate() throws -> PBXProj {
|
2017-11-12 20:52:11 +03:00
|
|
|
if generated {
|
|
|
|
fatalError("Cannot use PBXProjGenerator to generate more than once")
|
|
|
|
}
|
|
|
|
generated = true
|
2018-01-24 10:22:46 +03:00
|
|
|
|
2018-04-12 16:13:40 +03:00
|
|
|
for group in project.fileGroups {
|
2017-11-12 20:52:11 +03:00
|
|
|
try sourceGenerator.getFileGroups(path: group)
|
2017-09-23 23:38:50 +03:00
|
|
|
}
|
2020-03-18 15:32:24 +03:00
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
let buildConfigs: [XCBuildConfiguration] = project.configs.map { config in
|
2018-04-12 16:13:40 +03:00
|
|
|
let buildSettings = project.getProjectBuildSettings(config: config)
|
2018-09-25 14:11:04 +03:00
|
|
|
var baseConfiguration: PBXFileReference?
|
|
|
|
if let configPath = project.configFiles[config.name],
|
|
|
|
let fileReference = sourceGenerator.getContainedFileReference(path: project.basePath + configPath) as? PBXFileReference {
|
|
|
|
baseConfiguration = fileReference
|
2017-09-23 23:48:50 +03:00
|
|
|
}
|
2018-10-01 05:53:16 +03:00
|
|
|
let buildConfig = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
XCBuildConfiguration(
|
|
|
|
name: config.name,
|
|
|
|
buildSettings: buildSettings
|
|
|
|
)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2018-09-25 14:11:04 +03:00
|
|
|
buildConfig.baseConfiguration = baseConfiguration
|
|
|
|
return buildConfig
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
2017-07-26 13:51:55 +03:00
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
let configName = project.options.defaultConfig ?? buildConfigs.first?.name ?? ""
|
2018-10-01 05:53:16 +03:00
|
|
|
let buildConfigList = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
XCConfigurationList(
|
2018-09-25 14:11:04 +03:00
|
|
|
buildConfigurations: buildConfigs,
|
2018-03-19 23:13:31 +03:00
|
|
|
defaultConfigurationName: configName
|
2018-01-24 10:22:46 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
var derivedGroups: [PBXGroup] = []
|
2018-07-23 14:57:17 +03:00
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let mainGroup = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
PBXGroup(
|
|
|
|
children: [],
|
|
|
|
sourceTree: .group,
|
2018-04-12 16:13:40 +03:00
|
|
|
usesTabs: project.options.usesTabs,
|
|
|
|
indentWidth: project.options.indentWidth,
|
|
|
|
tabWidth: project.options.tabWidth
|
2018-01-24 10:22:46 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let pbxProject = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
PBXProject(
|
2018-04-12 16:13:40 +03:00
|
|
|
name: project.name,
|
2018-09-25 14:11:04 +03:00
|
|
|
buildConfigurationList: buildConfigList,
|
2019-05-07 19:43:17 +03:00
|
|
|
compatibilityVersion: project.compatibilityVersion,
|
2018-09-25 14:11:04 +03:00
|
|
|
mainGroup: mainGroup,
|
2018-04-12 16:13:40 +03:00
|
|
|
developmentRegion: project.options.developmentLanguage ?? "en"
|
2018-01-24 10:22:46 +03:00
|
|
|
)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
pbxProj.rootObject = pbxProject
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-04-12 16:13:40 +03:00
|
|
|
for target in project.targets {
|
2018-01-24 10:22:46 +03:00
|
|
|
let targetObject: PBXTarget
|
|
|
|
|
|
|
|
if target.isLegacy {
|
|
|
|
targetObject = PBXLegacyTarget(
|
|
|
|
name: target.name,
|
|
|
|
buildToolPath: target.legacy?.toolPath,
|
|
|
|
buildArgumentsString: target.legacy?.arguments,
|
|
|
|
passBuildSettingsInEnvironment: target.legacy?.passSettings ?? false,
|
2018-09-25 14:11:04 +03:00
|
|
|
buildWorkingDirectory: target.legacy?.workingDirectory,
|
|
|
|
buildPhases: []
|
2018-01-24 10:22:46 +03:00
|
|
|
)
|
|
|
|
} else {
|
2018-09-25 14:11:04 +03:00
|
|
|
targetObject = PBXNativeTarget(name: target.name, buildPhases: [])
|
2018-01-24 10:22:46 +03:00
|
|
|
}
|
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
targetObjects[target.name] = addObject(targetObject)
|
2017-12-26 13:47:18 +03:00
|
|
|
|
2018-01-21 15:16:14 +03:00
|
|
|
var explicitFileType: String?
|
|
|
|
var lastKnownFileType: String?
|
2018-09-25 14:08:11 +03:00
|
|
|
let fileType = Xcode.fileType(path: Path(target.filename))
|
2018-01-30 11:13:28 +03:00
|
|
|
if target.platform == .macOS || target.platform == .watchOS || target.type == .framework {
|
2018-01-21 15:16:14 +03:00
|
|
|
explicitFileType = fileType
|
|
|
|
} else {
|
|
|
|
lastKnownFileType = fileType
|
|
|
|
}
|
|
|
|
|
2018-04-13 19:06:05 +03:00
|
|
|
if !target.isLegacy {
|
2018-10-01 05:53:16 +03:00
|
|
|
let fileReference = addObject(
|
2018-04-13 19:06:05 +03:00
|
|
|
PBXFileReference(
|
|
|
|
sourceTree: .buildProductsDir,
|
|
|
|
explicitFileType: explicitFileType,
|
|
|
|
lastKnownFileType: lastKnownFileType,
|
|
|
|
path: target.filename,
|
|
|
|
includeInIndex: false
|
2018-10-16 13:35:31 +03:00
|
|
|
),
|
|
|
|
context: target.name
|
2018-01-24 10:22:46 +03:00
|
|
|
)
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-10-15 14:55:59 +03:00
|
|
|
targetFileReferences[target.name] = fileReference
|
2018-04-13 19:06:05 +03:00
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
|
2018-08-19 06:47:27 +03:00
|
|
|
for target in project.aggregateTargets {
|
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let aggregateTarget = addObject(
|
2018-08-19 06:47:27 +03:00
|
|
|
PBXAggregateTarget(
|
|
|
|
name: target.name,
|
|
|
|
productName: target.name
|
|
|
|
)
|
|
|
|
)
|
|
|
|
targetAggregateObjects[target.name] = aggregateTarget
|
|
|
|
}
|
|
|
|
|
2019-08-13 14:51:47 +03:00
|
|
|
for (name, package) in project.packages {
|
2020-03-19 17:29:46 +03:00
|
|
|
switch package {
|
2020-03-05 14:40:01 +03:00
|
|
|
case let .remote(url, versionRequirement):
|
|
|
|
let packageReference = XCRemoteSwiftPackageReference(repositoryURL: url, versionRequirement: versionRequirement)
|
|
|
|
packageReferences[name] = packageReference
|
|
|
|
addObject(packageReference)
|
|
|
|
case let .local(path):
|
|
|
|
try sourceGenerator.createLocalPackage(path: Path(path))
|
|
|
|
}
|
2019-08-13 14:51:47 +03:00
|
|
|
}
|
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let productGroup = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
PBXGroup(
|
2018-09-25 14:11:04 +03:00
|
|
|
children: targetFileReferences.valueArray,
|
2018-01-24 10:22:46 +03:00
|
|
|
sourceTree: .group,
|
|
|
|
name: "Products"
|
|
|
|
)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2018-07-23 14:57:17 +03:00
|
|
|
derivedGroups.append(productGroup)
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2020-02-02 01:44:56 +03:00
|
|
|
let sortedProjectReferences = project.projectReferences.sorted { $0.name < $1.name }
|
|
|
|
let subprojectFileReferences: [PBXFileReference] = sortedProjectReferences.map { projectReference in
|
|
|
|
let projectPath = Path(projectReference.path)
|
|
|
|
|
|
|
|
return addObject(
|
|
|
|
PBXFileReference(
|
|
|
|
sourceTree: .group,
|
|
|
|
name: projectReference.name,
|
|
|
|
lastKnownFileType: Xcode.fileType(path: projectPath),
|
|
|
|
path: projectPath.normalize().string
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if subprojectFileReferences.count > 0 {
|
|
|
|
let subprojectsGroups = addObject(
|
|
|
|
PBXGroup(
|
|
|
|
children: subprojectFileReferences,
|
|
|
|
sourceTree: .group,
|
|
|
|
name: "Projects"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
derivedGroups.append(subprojectsGroups)
|
|
|
|
|
|
|
|
let subprojects: [[String: PBXFileElement]] = subprojectFileReferences.map { projectReference in
|
|
|
|
let group = addObject(
|
|
|
|
PBXGroup(
|
|
|
|
children: [],
|
|
|
|
sourceTree: .group,
|
|
|
|
name: "Products"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return [
|
|
|
|
"ProductGroup": group,
|
|
|
|
"ProjectRef": projectReference
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
pbxProject.projects = subprojects
|
|
|
|
}
|
|
|
|
|
|
|
|
try project.targets.forEach(generateTarget)
|
|
|
|
try project.aggregateTargets.forEach(generateAggregateTarget)
|
|
|
|
|
2017-07-25 01:32:36 +03:00
|
|
|
if !carthageFrameworksByPlatform.isEmpty {
|
|
|
|
var platforms: [PBXGroup] = []
|
2018-09-25 14:11:04 +03:00
|
|
|
for (platform, files) in carthageFrameworksByPlatform {
|
2018-10-01 05:53:16 +03:00
|
|
|
let platformGroup: PBXGroup = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
PBXGroup(
|
2020-02-02 01:54:59 +03:00
|
|
|
children: Array(files),
|
2018-01-24 10:22:46 +03:00
|
|
|
sourceTree: .group,
|
|
|
|
path: platform
|
|
|
|
)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2018-09-25 14:08:11 +03:00
|
|
|
platforms.append(platformGroup)
|
2017-07-25 01:32:36 +03:00
|
|
|
}
|
2018-10-01 05:53:16 +03:00
|
|
|
let carthageGroup = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
PBXGroup(
|
2018-09-25 14:11:04 +03:00
|
|
|
children: platforms,
|
2018-01-24 10:22:46 +03:00
|
|
|
sourceTree: .group,
|
|
|
|
name: "Carthage",
|
2019-03-24 12:23:49 +03:00
|
|
|
path: carthageResolver.buildPath
|
2018-01-24 10:22:46 +03:00
|
|
|
)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2018-09-25 14:11:04 +03:00
|
|
|
frameworkFiles.append(carthageGroup)
|
2017-07-25 01:32:36 +03:00
|
|
|
}
|
|
|
|
|
2017-07-25 02:02:54 +03:00
|
|
|
if !frameworkFiles.isEmpty {
|
2018-10-01 05:53:16 +03:00
|
|
|
let group = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
PBXGroup(
|
|
|
|
children: frameworkFiles,
|
|
|
|
sourceTree: .group,
|
|
|
|
name: "Frameworks"
|
|
|
|
)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2018-07-23 14:57:17 +03:00
|
|
|
derivedGroups.append(group)
|
2017-11-12 20:52:11 +03:00
|
|
|
}
|
|
|
|
|
2019-11-18 12:07:46 +03:00
|
|
|
if !bundleFiles.isEmpty {
|
|
|
|
let group = addObject(
|
|
|
|
PBXGroup(
|
|
|
|
children: bundleFiles,
|
|
|
|
sourceTree: .group,
|
|
|
|
name: "Bundles"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
derivedGroups.append(group)
|
|
|
|
}
|
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
mainGroup.children = Array(sourceGenerator.rootGroups)
|
2017-11-12 20:52:11 +03:00
|
|
|
sortGroups(group: mainGroup)
|
2020-04-28 18:32:10 +03:00
|
|
|
setupGroupOrdering(group: mainGroup)
|
2018-07-23 14:57:17 +03:00
|
|
|
// add derived groups at the end
|
|
|
|
derivedGroups.forEach(sortGroups)
|
2018-09-25 14:11:04 +03:00
|
|
|
mainGroup.children += derivedGroups
|
2020-02-02 01:54:59 +03:00
|
|
|
.sorted(by: PBXFileElement.sortByNamePath)
|
2018-09-25 14:11:04 +03:00
|
|
|
.map { $0 }
|
2017-11-12 20:52:11 +03:00
|
|
|
|
2020-01-21 00:47:31 +03:00
|
|
|
let assetTags = Set(project.targets
|
|
|
|
.map { target in
|
|
|
|
target.sources.map { $0.resourceTags }.flatMap { $0 }
|
|
|
|
}.flatMap { $0 }
|
|
|
|
).sorted()
|
|
|
|
|
|
|
|
var projectAttributes: [String: Any] = ["LastUpgradeCheck": project.xcodeVersion]
|
2018-04-12 16:13:40 +03:00
|
|
|
.merged(project.attributes)
|
2020-01-21 00:47:31 +03:00
|
|
|
|
|
|
|
if !assetTags.isEmpty {
|
|
|
|
projectAttributes["knownAssetTags"] = assetTags
|
|
|
|
}
|
2020-02-26 07:26:05 +03:00
|
|
|
|
|
|
|
let knownRegions = sourceGenerator.knownRegions.sorted()
|
|
|
|
pbxProject.knownRegions = knownRegions.isEmpty ? ["en"] : knownRegions
|
|
|
|
|
2019-08-13 14:51:47 +03:00
|
|
|
pbxProject.packages = packageReferences.sorted { $0.key < $1.key }.map { $1 }
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2019-09-23 10:41:31 +03:00
|
|
|
let allTargets: [PBXTarget] = targetObjects.valueArray + targetAggregateObjects.valueArray
|
2018-09-25 14:11:04 +03:00
|
|
|
pbxProject.targets = allTargets
|
2018-09-25 14:08:11 +03:00
|
|
|
.sorted { $0.name < $1.name }
|
|
|
|
pbxProject.attributes = projectAttributes
|
2018-09-25 14:11:04 +03:00
|
|
|
pbxProject.targetAttributes = generateTargetAttributes()
|
2018-04-12 16:13:40 +03:00
|
|
|
return pbxProj
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
2018-01-24 10:22:46 +03:00
|
|
|
|
2018-07-22 13:27:58 +03:00
|
|
|
func generateAggregateTarget(_ target: AggregateTarget) throws {
|
2018-07-22 10:37:16 +03:00
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
let aggregateTarget = targetAggregateObjects[target.name]!
|
2018-08-19 06:47:27 +03:00
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
let configs: [XCBuildConfiguration] = project.configs.map { config in
|
2018-07-22 10:37:16 +03:00
|
|
|
|
|
|
|
let buildSettings = project.getBuildSettings(settings: target.settings, config: config)
|
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
var baseConfiguration: PBXFileReference?
|
2018-07-22 10:37:16 +03:00
|
|
|
if let configPath = target.configFiles[config.name] {
|
2018-09-25 14:11:04 +03:00
|
|
|
baseConfiguration = sourceGenerator.getContainedFileReference(path: project.basePath + configPath) as? PBXFileReference
|
2018-07-22 10:37:16 +03:00
|
|
|
}
|
|
|
|
let buildConfig = XCBuildConfiguration(
|
|
|
|
name: config.name,
|
2018-09-25 14:11:04 +03:00
|
|
|
baseConfiguration: baseConfiguration,
|
2018-07-22 10:37:16 +03:00
|
|
|
buildSettings: buildSettings
|
|
|
|
)
|
2018-10-01 05:53:16 +03:00
|
|
|
return addObject(buildConfig)
|
2018-07-22 10:37:16 +03:00
|
|
|
}
|
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
let dependencies = target.targets.map { generateTargetDependency(from: target.name, to: $0) }
|
2018-07-22 10:37:16 +03:00
|
|
|
|
2020-02-25 03:57:36 +03:00
|
|
|
let defaultConfigurationName = project.options.defaultConfig ?? project.configs.first?.name ?? ""
|
2018-10-01 05:53:16 +03:00
|
|
|
let buildConfigList = addObject(XCConfigurationList(
|
2018-09-25 14:11:04 +03:00
|
|
|
buildConfigurations: configs,
|
2020-02-25 03:57:36 +03:00
|
|
|
defaultConfigurationName: defaultConfigurationName
|
2018-07-22 10:37:16 +03:00
|
|
|
))
|
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
var buildPhases: [PBXBuildPhase] = []
|
2018-07-22 10:37:16 +03:00
|
|
|
buildPhases += try target.buildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) }
|
|
|
|
|
2018-08-19 06:47:27 +03:00
|
|
|
aggregateTarget.buildPhases = buildPhases
|
2018-09-25 14:11:04 +03:00
|
|
|
aggregateTarget.buildConfigurationList = buildConfigList
|
2018-08-19 06:47:27 +03:00
|
|
|
aggregateTarget.dependencies = dependencies
|
2018-07-22 10:37:16 +03:00
|
|
|
}
|
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
func generateTargetDependency(from: String, to target: String) -> PBXTargetDependency {
|
2018-09-25 14:11:04 +03:00
|
|
|
guard let targetObject = targetObjects[target] ?? targetAggregateObjects[target] else {
|
2018-08-19 06:47:27 +03:00
|
|
|
fatalError("target not found")
|
|
|
|
}
|
2019-06-07 23:37:25 +03:00
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let targetProxy = addObject(
|
2018-07-22 10:37:16 +03:00
|
|
|
PBXContainerItemProxy(
|
2019-06-07 23:37:25 +03:00
|
|
|
containerPortal: .project(pbxProj.rootObject!),
|
|
|
|
remoteGlobalID: .object(targetObject),
|
2018-07-22 10:37:16 +03:00
|
|
|
proxyType: .nativeTarget,
|
|
|
|
remoteInfo: target
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let targetDependency = addObject(
|
2018-07-22 10:37:16 +03:00
|
|
|
PBXTargetDependency(
|
2018-09-25 14:11:04 +03:00
|
|
|
target: targetObject,
|
|
|
|
targetProxy: targetProxy
|
2018-07-22 10:37:16 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
return targetDependency
|
|
|
|
}
|
|
|
|
|
2020-02-02 01:44:56 +03:00
|
|
|
func generateExternalTargetDependency(from: String, to target: String, in project: String, platform: Platform) throws -> (PBXTargetDependency, Target, PBXReferenceProxy) {
|
|
|
|
guard let projectReference = self.project.getProjectReference(project) else {
|
|
|
|
fatalError("project not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
let pbxProj = try getPBXProj(from: projectReference)
|
|
|
|
|
|
|
|
guard let targetObject = pbxProj.targets(named: target).first else {
|
|
|
|
fatalError("target not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
let projectFileReferenceIndex = self.pbxProj.rootObject!
|
|
|
|
.projects
|
|
|
|
.map { $0["ProjectRef"] as? PBXFileReference }
|
|
|
|
.firstIndex { $0?.path == Path(projectReference.path).normalize().string }
|
|
|
|
|
|
|
|
guard let index = projectFileReferenceIndex,
|
|
|
|
let projectFileReference = self.pbxProj.rootObject?.projects[index]["ProjectRef"] as? PBXFileReference,
|
|
|
|
let productsGroup = self.pbxProj.rootObject?.projects[index]["ProductGroup"] as? PBXGroup else {
|
|
|
|
fatalError("Missing subproject file reference")
|
|
|
|
}
|
|
|
|
|
|
|
|
let targetProxy = addObject(
|
|
|
|
PBXContainerItemProxy(
|
|
|
|
containerPortal: .fileReference(projectFileReference),
|
|
|
|
remoteGlobalID: .object(targetObject),
|
|
|
|
proxyType: .nativeTarget,
|
|
|
|
remoteInfo: target
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
let productProxy = addObject(
|
|
|
|
PBXContainerItemProxy(
|
|
|
|
containerPortal: .fileReference(projectFileReference),
|
|
|
|
remoteGlobalID: .object(targetObject.product!),
|
|
|
|
proxyType: .reference,
|
|
|
|
remoteInfo: target
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2020-04-23 20:23:58 +03:00
|
|
|
var path = targetObject.productNameWithExtension()
|
|
|
|
|
|
|
|
if targetObject.productType == .staticLibrary,
|
|
|
|
let tmpPath = path, !tmpPath.hasPrefix("lib") {
|
|
|
|
path = "lib\(tmpPath)"
|
|
|
|
}
|
|
|
|
|
2020-02-02 01:44:56 +03:00
|
|
|
let productReferenceProxy = addObject(
|
|
|
|
PBXReferenceProxy(
|
|
|
|
fileType: Xcode.fileType(path: Path(targetObject.productNameWithExtension()!)),
|
2020-04-23 20:23:58 +03:00
|
|
|
path: path,
|
2020-02-02 01:44:56 +03:00
|
|
|
remote: productProxy,
|
|
|
|
sourceTree: .buildProductsDir
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
productsGroup.children.append(productReferenceProxy)
|
|
|
|
|
|
|
|
let targetDependency = addObject(
|
|
|
|
PBXTargetDependency(
|
2020-04-23 20:25:25 +03:00
|
|
|
name: targetObject.name,
|
2020-02-02 01:44:56 +03:00
|
|
|
targetProxy: targetProxy
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
guard let productType = targetObject.productType,
|
|
|
|
let buildConfigurations = targetObject.buildConfigurationList?.buildConfigurations,
|
|
|
|
let defaultConfigurationName = targetObject.buildConfigurationList?.defaultConfigurationName,
|
|
|
|
let defaultConfiguration = buildConfigurations.first(where: { $0.name == defaultConfigurationName }) ?? buildConfigurations.first else {
|
|
|
|
|
|
|
|
fatalError("Missing target info")
|
|
|
|
}
|
|
|
|
|
|
|
|
let buildSettings = defaultConfiguration.buildSettings
|
|
|
|
let settings = Settings(buildSettings: buildSettings, configSettings: [:], groups: [])
|
|
|
|
let deploymentTargetString = buildSettings[platform.deploymentTargetSetting] as? String
|
2020-02-07 02:40:24 +03:00
|
|
|
let deploymentTarget = deploymentTargetString == nil ? nil : try Version.parse(deploymentTargetString!)
|
2020-02-02 01:44:56 +03:00
|
|
|
let requiresObjCLinking = (buildSettings["OTHER_LDFLAGS"] as? String)?.contains("-ObjC") ?? (productType == .staticLibrary)
|
|
|
|
let dependencyTarget = Target(
|
|
|
|
name: targetObject.name,
|
|
|
|
type: productType,
|
|
|
|
platform: platform,
|
|
|
|
productName: targetObject.productName,
|
|
|
|
deploymentTarget: deploymentTarget,
|
|
|
|
settings: settings,
|
|
|
|
requiresObjCLinking: requiresObjCLinking
|
|
|
|
)
|
|
|
|
|
|
|
|
return (targetDependency, dependencyTarget, productReferenceProxy)
|
|
|
|
}
|
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
func generateBuildScript(targetName: String, buildScript: BuildScript) throws -> PBXShellScriptBuildPhase {
|
2018-07-22 10:37:16 +03:00
|
|
|
|
|
|
|
let shellScript: String
|
|
|
|
switch buildScript.script {
|
|
|
|
case let .path(path):
|
|
|
|
shellScript = try (project.basePath + path).read()
|
|
|
|
case let .script(script):
|
|
|
|
shellScript = script
|
|
|
|
}
|
|
|
|
|
|
|
|
let shellScriptPhase = PBXShellScriptBuildPhase(
|
|
|
|
name: buildScript.name ?? "Run Script",
|
|
|
|
inputPaths: buildScript.inputFiles,
|
|
|
|
outputPaths: buildScript.outputFiles,
|
2019-01-23 17:40:45 +03:00
|
|
|
inputFileListPaths: buildScript.inputFileLists,
|
|
|
|
outputFileListPaths: buildScript.outputFileLists,
|
2018-07-22 10:37:16 +03:00
|
|
|
shellPath: buildScript.shell ?? "/bin/sh",
|
2018-09-25 14:11:04 +03:00
|
|
|
shellScript: shellScript,
|
|
|
|
runOnlyForDeploymentPostprocessing: buildScript.runOnlyWhenInstalling,
|
|
|
|
showEnvVarsInLog: buildScript.showEnvVars
|
2018-07-22 10:37:16 +03:00
|
|
|
)
|
2018-10-01 05:53:16 +03:00
|
|
|
return addObject(shellScriptPhase)
|
2018-07-22 10:37:16 +03:00
|
|
|
}
|
2018-12-18 14:37:22 +03:00
|
|
|
|
2018-11-05 19:35:15 +03:00
|
|
|
func generateCopyFiles(targetName: String, copyFiles: TargetSource.BuildPhase.CopyFilesSettings, buildPhaseFiles: [PBXBuildFile]) -> PBXCopyFilesBuildPhase {
|
|
|
|
let copyFilesBuildPhase = PBXCopyFilesBuildPhase(
|
|
|
|
dstPath: copyFiles.subpath,
|
|
|
|
dstSubfolderSpec: copyFiles.destination.destination,
|
|
|
|
files: buildPhaseFiles
|
|
|
|
)
|
|
|
|
return addObject(copyFilesBuildPhase)
|
2018-09-14 21:13:25 +03:00
|
|
|
}
|
2018-07-22 10:37:16 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
func generateTargetAttributes() -> [PBXTarget: [String: Any]] {
|
2018-01-24 10:22:46 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
var targetAttributes: [PBXTarget: [String: Any]] = [:]
|
2018-01-24 10:22:46 +03:00
|
|
|
|
2018-12-05 11:13:18 +03:00
|
|
|
let testTargets = pbxProj.nativeTargets.filter { $0.productType == .uiTestBundle || $0.productType == .unitTestBundle }
|
|
|
|
for testTarget in testTargets {
|
2018-03-27 09:18:29 +03:00
|
|
|
|
2018-03-27 06:21:15 +03:00
|
|
|
// look up TEST_TARGET_NAME build setting
|
|
|
|
func testTargetName(_ target: PBXTarget) -> String? {
|
2018-09-25 14:11:04 +03:00
|
|
|
guard let buildConfigurations = target.buildConfigurationList?.buildConfigurations else { return nil }
|
2018-03-27 09:18:29 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
return buildConfigurations
|
2018-05-12 08:10:18 +03:00
|
|
|
.compactMap { $0.buildSettings["TEST_TARGET_NAME"] as? String }
|
2018-03-27 06:21:15 +03:00
|
|
|
.first
|
|
|
|
}
|
2018-03-27 09:18:29 +03:00
|
|
|
|
2018-12-05 11:13:18 +03:00
|
|
|
guard let name = testTargetName(testTarget) else { continue }
|
2018-09-25 14:11:04 +03:00
|
|
|
guard let target = self.pbxProj.targets(named: name).first else { continue }
|
2018-01-24 10:22:46 +03:00
|
|
|
|
2018-12-05 11:13:18 +03:00
|
|
|
targetAttributes[testTarget, default: [:]].merge(["TestTargetID": target])
|
2018-03-27 06:21:15 +03:00
|
|
|
}
|
2018-03-27 09:18:29 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
func generateTargetAttributes(_ target: ProjectTarget, pbxTarget: PBXTarget) {
|
2018-03-27 07:47:23 +03:00
|
|
|
if !target.attributes.isEmpty {
|
2018-09-25 14:11:04 +03:00
|
|
|
targetAttributes[pbxTarget, default: [:]].merge(target.attributes)
|
2018-03-27 07:47:23 +03:00
|
|
|
}
|
2018-03-27 09:18:29 +03:00
|
|
|
|
2018-03-27 07:47:23 +03:00
|
|
|
func getSingleBuildSetting(_ setting: String) -> String? {
|
2018-05-12 08:10:18 +03:00
|
|
|
let settings = project.configs.compactMap {
|
2018-10-05 19:12:51 +03:00
|
|
|
project.getCombinedBuildSetting(setting, target: target, config: $0) as? String
|
2018-03-27 07:47:23 +03:00
|
|
|
}
|
2018-04-12 16:13:40 +03:00
|
|
|
guard settings.count == project.configs.count,
|
2018-03-27 07:47:23 +03:00
|
|
|
let firstSetting = settings.first,
|
2018-03-27 09:18:29 +03:00
|
|
|
settings.filter({ $0 == firstSetting }).count == settings.count else {
|
|
|
|
return nil
|
2018-03-27 07:47:23 +03:00
|
|
|
}
|
|
|
|
return firstSetting
|
|
|
|
}
|
2018-03-27 09:18:29 +03:00
|
|
|
|
2018-03-27 07:47:23 +03:00
|
|
|
func setTargetAttribute(attribute: String, buildSetting: String) {
|
|
|
|
if let setting = getSingleBuildSetting(buildSetting) {
|
2018-09-25 14:11:04 +03:00
|
|
|
targetAttributes[pbxTarget, default: [:]].merge([attribute: setting])
|
2018-03-27 07:47:23 +03:00
|
|
|
}
|
|
|
|
}
|
2018-03-27 09:18:29 +03:00
|
|
|
|
2018-03-27 07:47:23 +03:00
|
|
|
setTargetAttribute(attribute: "ProvisioningStyle", buildSetting: "CODE_SIGN_STYLE")
|
|
|
|
setTargetAttribute(attribute: "DevelopmentTeam", buildSetting: "DEVELOPMENT_TEAM")
|
2018-01-05 05:02:47 +03:00
|
|
|
}
|
2018-01-24 10:22:46 +03:00
|
|
|
|
2018-07-22 13:27:58 +03:00
|
|
|
for target in project.aggregateTargets {
|
2018-09-25 14:11:04 +03:00
|
|
|
guard let pbxTarget = targetAggregateObjects[target.name] else {
|
2018-07-22 13:27:58 +03:00
|
|
|
continue
|
|
|
|
}
|
2018-09-25 14:11:04 +03:00
|
|
|
generateTargetAttributes(target, pbxTarget: pbxTarget)
|
2018-07-22 13:27:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for target in project.targets {
|
2018-09-25 14:11:04 +03:00
|
|
|
guard let pbxTarget = targetObjects[target.name] else {
|
2018-07-22 13:27:58 +03:00
|
|
|
continue
|
|
|
|
}
|
2018-09-25 14:11:04 +03:00
|
|
|
generateTargetAttributes(target, pbxTarget: pbxTarget)
|
2018-07-22 13:27:58 +03:00
|
|
|
}
|
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
return targetAttributes
|
2018-01-05 05:02:47 +03:00
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
func sortGroups(group: PBXGroup) {
|
2017-11-12 20:52:11 +03:00
|
|
|
// sort children
|
2018-09-25 14:11:04 +03:00
|
|
|
let children = group.children
|
2017-11-12 20:52:11 +03:00
|
|
|
.sorted { child1, child2 in
|
2018-09-25 14:08:11 +03:00
|
|
|
let sortOrder1 = child1.getSortOrder(groupSortPosition: project.options.groupSortPosition)
|
|
|
|
let sortOrder2 = child2.getSortOrder(groupSortPosition: project.options.groupSortPosition)
|
2018-07-24 15:59:24 +03:00
|
|
|
|
2018-10-15 14:55:59 +03:00
|
|
|
if sortOrder1 != sortOrder2 {
|
2018-07-24 15:59:24 +03:00
|
|
|
return sortOrder1 < sortOrder2
|
2018-10-15 14:55:59 +03:00
|
|
|
} else {
|
2020-02-02 01:46:17 +03:00
|
|
|
if (child1.name, child1.path) != (child2.name, child2.path) {
|
2020-02-02 01:54:59 +03:00
|
|
|
return PBXFileElement.sortByNamePath(child1, child2)
|
2018-10-15 14:55:59 +03:00
|
|
|
} else {
|
2018-10-16 13:35:31 +03:00
|
|
|
return child1.context ?? "" < child2.context ?? ""
|
2018-10-15 14:55:59 +03:00
|
|
|
}
|
2017-11-12 20:52:11 +03:00
|
|
|
}
|
2018-04-12 16:32:40 +03:00
|
|
|
}
|
2018-09-25 14:11:04 +03:00
|
|
|
group.children = children.filter { $0 != group }
|
2017-11-12 20:52:11 +03:00
|
|
|
|
|
|
|
// sort sub groups
|
2018-09-25 14:11:04 +03:00
|
|
|
let childGroups = group.children.compactMap { $0 as? PBXGroup }
|
2017-11-12 20:52:11 +03:00
|
|
|
childGroups.forEach(sortGroups)
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
2020-04-28 18:32:10 +03:00
|
|
|
|
|
|
|
public func setupGroupOrdering(group: PBXGroup) {
|
|
|
|
let groupOrdering = project.options.groupOrdering.first { groupOrdering in
|
|
|
|
let groupName = group.nameOrPath
|
|
|
|
|
|
|
|
if groupName == groupOrdering.pattern {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if let regex = groupOrdering.regex {
|
|
|
|
return regex.isMatch(to: groupName)
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if let order = groupOrdering?.order {
|
|
|
|
let files = group.children.filter { $0 is PBXFileReference }
|
|
|
|
var groups = group.children.filter { $0 is PBXGroup }
|
|
|
|
|
|
|
|
var filteredGroups = [PBXFileElement]()
|
|
|
|
|
|
|
|
for groupName in order {
|
|
|
|
guard let group = groups.first(where: { $0.nameOrPath == groupName }) else {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
filteredGroups.append(group)
|
|
|
|
groups.removeAll { $0 == group }
|
|
|
|
}
|
|
|
|
|
|
|
|
filteredGroups += groups
|
|
|
|
|
|
|
|
switch project.options.groupSortPosition {
|
|
|
|
case .top:
|
|
|
|
group.children = filteredGroups + files
|
|
|
|
case .bottom:
|
|
|
|
group.children = files + filteredGroups
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort sub groups
|
|
|
|
let childGroups = group.children.compactMap { $0 as? PBXGroup }
|
|
|
|
childGroups.forEach(setupGroupOrdering)
|
|
|
|
}
|
2017-12-26 12:56:02 +03:00
|
|
|
|
2020-02-02 01:44:56 +03:00
|
|
|
func getPBXProj(from reference: ProjectReference) throws -> PBXProj {
|
|
|
|
if let cachedProject = projects[reference] {
|
|
|
|
return cachedProject
|
|
|
|
}
|
|
|
|
let pbxproj = try XcodeProj(pathString: (project.basePath + Path(reference.path).normalize()).string).pbxproj
|
|
|
|
projects[reference] = pbxproj
|
|
|
|
return pbxproj
|
|
|
|
}
|
|
|
|
|
2018-01-24 10:22:46 +03:00
|
|
|
func generateTarget(_ target: Target) throws {
|
2019-02-07 22:55:37 +03:00
|
|
|
let carthageDependencies = carthageResolver.dependencies(for: target)
|
2017-08-27 00:40:42 +03:00
|
|
|
|
2018-07-18 00:29:04 +03:00
|
|
|
let sourceFiles = try sourceGenerator.getAllSourceFiles(targetType: target.type, sources: target.sources)
|
2018-10-11 16:07:21 +03:00
|
|
|
.sorted { $0.path.lastComponent < $1.path.lastComponent }
|
2017-07-26 13:40:25 +03:00
|
|
|
|
2017-12-26 12:56:02 +03:00
|
|
|
var plistPath: Path?
|
2017-12-20 04:10:13 +03:00
|
|
|
var searchForPlist = true
|
2018-07-20 21:28:11 +03:00
|
|
|
var anyDependencyRequiresObjCLinking = false
|
2017-08-27 13:28:18 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
var dependencies: [PBXTargetDependency] = []
|
|
|
|
var targetFrameworkBuildFiles: [PBXBuildFile] = []
|
2018-08-08 15:43:46 +03:00
|
|
|
var frameworkBuildPaths = Set<String>()
|
2018-09-25 14:11:04 +03:00
|
|
|
var copyFilesBuildPhasesFiles: [TargetSource.BuildPhase.CopyFilesSettings: [PBXBuildFile]] = [:]
|
|
|
|
var copyFrameworksReferences: [PBXBuildFile] = []
|
|
|
|
var copyResourcesReferences: [PBXBuildFile] = []
|
2019-11-20 10:24:05 +03:00
|
|
|
var copyBundlesReferences: [PBXBuildFile] = []
|
2018-09-25 14:11:04 +03:00
|
|
|
var copyWatchReferences: [PBXBuildFile] = []
|
2019-08-13 14:51:47 +03:00
|
|
|
var packageDependencies: [XCSwiftPackageProductDependency] = []
|
2018-09-25 14:11:04 +03:00
|
|
|
var extensions: [PBXBuildFile] = []
|
2018-07-25 01:15:33 +03:00
|
|
|
var carthageFrameworksToEmbed: [String] = []
|
2020-03-19 17:29:46 +03:00
|
|
|
var localPackageReferences: [String] = project.packages.compactMap { $0.value.isLocal ? $0.key : nil }
|
2018-07-03 14:45:00 +03:00
|
|
|
|
2018-07-03 21:34:20 +03:00
|
|
|
let targetDependencies = (target.transitivelyLinkDependencies ?? project.options.transitivelyLinkDependencies) ?
|
|
|
|
getAllDependenciesPlusTransitiveNeedingEmbedding(target: target) : target.dependencies
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2019-04-05 08:41:38 +03:00
|
|
|
let targetSupportsDirectEmbed = !(target.platform.requiresSimulatorStripping &&
|
2019-04-05 09:47:15 +03:00
|
|
|
(target.type.isApp || target.type == .watch2Extension))
|
2019-04-05 08:41:38 +03:00
|
|
|
let directlyEmbedCarthage = target.directlyEmbedCarthageDependencies ?? targetSupportsDirectEmbed
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-07-25 01:15:33 +03:00
|
|
|
func getEmbedSettings(dependency: Dependency, codeSign: Bool) -> [String: Any] {
|
|
|
|
var embedAttributes: [String] = []
|
|
|
|
if codeSign {
|
|
|
|
embedAttributes.append("CodeSignOnCopy")
|
|
|
|
}
|
|
|
|
if dependency.removeHeaders {
|
|
|
|
embedAttributes.append("RemoveHeadersOnCopy")
|
|
|
|
}
|
|
|
|
return ["ATTRIBUTES": embedAttributes]
|
|
|
|
}
|
2017-08-03 21:03:56 +03:00
|
|
|
|
2018-09-28 16:46:46 +03:00
|
|
|
func getDependencyFrameworkSettings(dependency: Dependency) -> [String: Any]? {
|
|
|
|
var linkingAttributes: [String] = []
|
|
|
|
if dependency.weakLink {
|
|
|
|
linkingAttributes.append("Weak")
|
|
|
|
}
|
|
|
|
return !linkingAttributes.isEmpty ? ["ATTRIBUTES": linkingAttributes] : nil
|
|
|
|
}
|
|
|
|
|
2020-02-07 01:36:53 +03:00
|
|
|
func processTargetDependency(_ dependency: Dependency, dependencyTarget: Target, embedFileReference: PBXFileElement?) {
|
2020-02-02 01:44:56 +03:00
|
|
|
let dependencyLinkage = dependencyTarget.type.defaultLinkage
|
|
|
|
let link = dependency.link ??
|
|
|
|
((dependencyLinkage == .dynamic && target.type != .staticLibrary) ||
|
|
|
|
(dependencyLinkage == .static && target.type.isExecutable))
|
2018-06-27 15:18:12 +03:00
|
|
|
|
2020-02-07 01:36:53 +03:00
|
|
|
if link, let dependencyFile = embedFileReference {
|
2020-02-02 01:44:56 +03:00
|
|
|
let buildFile = addObject(
|
|
|
|
PBXBuildFile(file: dependencyFile, settings: getDependencyFrameworkSettings(dependency: dependency))
|
|
|
|
)
|
|
|
|
targetFrameworkBuildFiles.append(buildFile)
|
2018-08-19 06:47:27 +03:00
|
|
|
|
2020-02-02 01:44:56 +03:00
|
|
|
if !anyDependencyRequiresObjCLinking
|
|
|
|
&& dependencyTarget.requiresObjCLinking ?? (dependencyTarget.type == .staticLibrary) {
|
|
|
|
anyDependencyRequiresObjCLinking = true
|
|
|
|
}
|
|
|
|
}
|
2019-09-27 11:48:16 +03:00
|
|
|
|
2020-04-07 18:14:42 +03:00
|
|
|
let embed = dependency.embed ?? target.type.shouldEmbed(dependencyTarget.type)
|
2020-02-02 01:44:56 +03:00
|
|
|
if embed {
|
|
|
|
let embedFile = addObject(
|
|
|
|
PBXBuildFile(
|
|
|
|
file: embedFileReference,
|
|
|
|
settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? !dependencyTarget.type.isExecutable)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2020-02-02 01:44:56 +03:00
|
|
|
)
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2020-02-02 01:44:56 +03:00
|
|
|
if dependencyTarget.type.isExtension {
|
|
|
|
// embed app extension
|
|
|
|
extensions.append(embedFile)
|
|
|
|
} else if dependencyTarget.type.isFramework {
|
|
|
|
copyFrameworksReferences.append(embedFile)
|
|
|
|
} else if dependencyTarget.type.isApp && dependencyTarget.platform == .watchOS {
|
|
|
|
copyWatchReferences.append(embedFile)
|
|
|
|
} else if dependencyTarget.type == .xpcService {
|
|
|
|
copyFilesBuildPhasesFiles[.xpcServices, default: []].append(embedFile)
|
|
|
|
} else {
|
|
|
|
copyResourcesReferences.append(embedFile)
|
2017-10-17 04:18:28 +03:00
|
|
|
}
|
2020-02-02 01:44:56 +03:00
|
|
|
}
|
|
|
|
}
|
2018-07-03 14:45:00 +03:00
|
|
|
|
2020-02-02 01:44:56 +03:00
|
|
|
for dependency in targetDependencies {
|
2017-08-24 18:41:55 +03:00
|
|
|
|
2020-02-02 01:44:56 +03:00
|
|
|
let embed = dependency.embed ?? target.shouldEmbedDependencies
|
|
|
|
|
|
|
|
switch dependency.type {
|
|
|
|
case .target:
|
|
|
|
let dependencyTargetReference = try TargetReference(dependency.reference)
|
|
|
|
|
|
|
|
switch dependencyTargetReference.location {
|
|
|
|
case .local:
|
|
|
|
let dependencyTargetName = dependency.reference
|
|
|
|
let targetDependency = generateTargetDependency(from: target.name, to: dependencyTargetName)
|
|
|
|
dependencies.append(targetDependency)
|
|
|
|
guard let dependencyTarget = project.getTarget(dependencyTargetName) else { continue }
|
2020-02-07 01:36:53 +03:00
|
|
|
processTargetDependency(dependency, dependencyTarget: dependencyTarget, embedFileReference: targetFileReferences[dependencyTarget.name])
|
2020-02-02 01:44:56 +03:00
|
|
|
case .project(let dependencyProjectName):
|
|
|
|
let dependencyTargetName = dependencyTargetReference.name
|
|
|
|
let (targetDependency, dependencyTarget, dependencyProductProxy) = try generateExternalTargetDependency(from: target.name, to: dependencyTargetName, in: dependencyProjectName, platform: target.platform)
|
|
|
|
dependencies.append(targetDependency)
|
|
|
|
processTargetDependency(dependency, dependencyTarget: dependencyTarget, embedFileReference: dependencyProductProxy)
|
2017-08-03 21:03:56 +03:00
|
|
|
}
|
|
|
|
|
2017-08-27 12:53:16 +03:00
|
|
|
case .framework:
|
2019-12-26 09:27:23 +03:00
|
|
|
if !dependency.implicit {
|
|
|
|
let buildPath = Path(dependency.reference).parent().string.quoted
|
|
|
|
frameworkBuildPaths.insert(buildPath)
|
|
|
|
}
|
2018-12-18 14:37:22 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
let fileReference: PBXFileElement
|
2017-11-21 15:51:04 +03:00
|
|
|
if dependency.implicit {
|
2017-12-26 13:47:18 +03:00
|
|
|
fileReference = sourceGenerator.getFileReference(
|
|
|
|
path: Path(dependency.reference),
|
2018-04-12 16:13:40 +03:00
|
|
|
inPath: project.basePath,
|
2017-12-26 13:47:18 +03:00
|
|
|
sourceTree: .buildProductsDir
|
|
|
|
)
|
2017-11-21 09:47:57 +03:00
|
|
|
} else {
|
2017-12-26 13:47:18 +03:00
|
|
|
fileReference = sourceGenerator.getFileReference(
|
|
|
|
path: Path(dependency.reference),
|
2018-04-12 16:13:40 +03:00
|
|
|
inPath: project.basePath
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2017-11-21 09:47:57 +03:00
|
|
|
}
|
2017-08-24 18:41:55 +03:00
|
|
|
|
2019-08-28 21:52:27 +03:00
|
|
|
if dependency.link ?? (target.type != .staticLibrary) {
|
2019-03-06 00:53:21 +03:00
|
|
|
let buildFile = addObject(
|
|
|
|
PBXBuildFile(file: fileReference, settings: getDependencyFrameworkSettings(dependency: dependency))
|
|
|
|
)
|
2019-03-25 13:10:39 +03:00
|
|
|
|
2019-03-06 00:53:21 +03:00
|
|
|
targetFrameworkBuildFiles.append(buildFile)
|
|
|
|
}
|
2019-03-25 13:10:39 +03:00
|
|
|
|
2017-07-25 02:02:54 +03:00
|
|
|
if !frameworkFiles.contains(fileReference) {
|
|
|
|
frameworkFiles.append(fileReference)
|
|
|
|
}
|
2017-08-24 18:41:55 +03:00
|
|
|
|
|
|
|
if embed {
|
2018-10-01 05:53:16 +03:00
|
|
|
let embedFile = addObject(
|
2018-09-25 14:11:04 +03:00
|
|
|
PBXBuildFile(file: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true))
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2018-09-25 14:11:04 +03:00
|
|
|
copyFrameworksReferences.append(embedFile)
|
2017-08-24 18:41:55 +03:00
|
|
|
}
|
2019-04-08 13:00:40 +03:00
|
|
|
case .sdk(let root):
|
2018-11-02 09:55:24 +03:00
|
|
|
|
|
|
|
var dependencyPath = Path(dependency.reference)
|
|
|
|
if !dependency.reference.contains("/") {
|
|
|
|
switch dependencyPath.extension ?? "" {
|
|
|
|
case "framework":
|
|
|
|
dependencyPath = Path("System/Library/Frameworks") + dependencyPath
|
|
|
|
case "tbd":
|
|
|
|
dependencyPath = Path("usr/lib") + dependencyPath
|
2019-09-10 17:09:27 +03:00
|
|
|
case "dylib":
|
|
|
|
dependencyPath = Path("usr/lib") + dependencyPath
|
2018-11-02 09:55:24 +03:00
|
|
|
default: break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let fileReference: PBXFileReference
|
|
|
|
if let existingFileReferences = sdkFileReferences[dependency.reference] {
|
|
|
|
fileReference = existingFileReferences
|
|
|
|
} else {
|
2019-04-08 13:00:40 +03:00
|
|
|
let sourceTree: PBXSourceTree
|
|
|
|
if let root = root {
|
|
|
|
sourceTree = .custom(root)
|
|
|
|
} else {
|
|
|
|
sourceTree = .sdkRoot
|
|
|
|
}
|
2018-11-02 09:55:24 +03:00
|
|
|
fileReference = addObject(
|
2018-11-04 14:30:34 +03:00
|
|
|
PBXFileReference(
|
2019-04-08 13:00:40 +03:00
|
|
|
sourceTree: sourceTree,
|
2018-11-04 14:30:34 +03:00
|
|
|
name: dependencyPath.lastComponent,
|
|
|
|
lastKnownFileType: Xcode.fileType(path: dependencyPath),
|
|
|
|
path: dependencyPath.string
|
|
|
|
)
|
2018-11-02 09:55:24 +03:00
|
|
|
)
|
|
|
|
sdkFileReferences[dependency.reference] = fileReference
|
|
|
|
frameworkFiles.append(fileReference)
|
|
|
|
}
|
|
|
|
|
|
|
|
let buildFile = addObject(
|
2018-11-04 14:30:34 +03:00
|
|
|
PBXBuildFile(
|
|
|
|
file: fileReference,
|
|
|
|
settings: getDependencyFrameworkSettings(dependency: dependency)
|
|
|
|
)
|
2018-11-02 09:55:24 +03:00
|
|
|
)
|
|
|
|
targetFrameworkBuildFiles.append(buildFile)
|
2018-07-03 14:45:00 +03:00
|
|
|
|
2019-11-07 20:03:26 +03:00
|
|
|
case .carthage(let findFrameworks, let linkType):
|
2019-03-24 14:31:47 +03:00
|
|
|
let findFrameworks = findFrameworks ?? project.options.findCarthageFrameworks
|
|
|
|
let allDependencies = findFrameworks
|
2019-02-07 22:55:37 +03:00
|
|
|
? carthageResolver.relatedDependencies(for: dependency, in: target.platform) : [dependency]
|
|
|
|
allDependencies.forEach { dependency in
|
|
|
|
|
2020-02-07 02:40:24 +03:00
|
|
|
let platformPath = Path(carthageResolver.buildPath(for: target.platform, linkType: linkType))
|
2019-02-07 22:55:37 +03:00
|
|
|
var frameworkPath = platformPath + dependency.reference
|
|
|
|
if frameworkPath.extension == nil {
|
|
|
|
frameworkPath = Path(frameworkPath.string + ".framework")
|
|
|
|
}
|
|
|
|
let fileReference = self.sourceGenerator.getFileReference(path: frameworkPath, inPath: platformPath)
|
2017-07-25 01:32:36 +03:00
|
|
|
|
2019-03-24 12:23:49 +03:00
|
|
|
self.carthageFrameworksByPlatform[target.platform.carthageName, default: []].insert(fileReference)
|
2019-11-10 03:56:23 +03:00
|
|
|
|
2020-04-13 14:44:14 +03:00
|
|
|
let isStaticLibrary = target.type == .staticLibrary
|
2020-05-01 20:54:12 +03:00
|
|
|
let isCarthageStaticLink = (dependency.carthageLinkType == .static || dependency.carthageLinkType == .staticBinary)
|
2020-04-13 14:44:14 +03:00
|
|
|
if dependency.link ?? (!isStaticLibrary && !isCarthageStaticLink) {
|
2019-02-07 22:55:37 +03:00
|
|
|
let buildFile = self.addObject(
|
|
|
|
PBXBuildFile(file: fileReference, settings: getDependencyFrameworkSettings(dependency: dependency))
|
|
|
|
)
|
|
|
|
targetFrameworkBuildFiles.append(buildFile)
|
|
|
|
}
|
2018-11-02 11:16:02 +03:00
|
|
|
}
|
2019-10-27 14:37:41 +03:00
|
|
|
// Embedding handled by iterating over `carthageDependencies` below
|
2019-08-13 14:51:47 +03:00
|
|
|
case .package(let product):
|
2020-03-03 15:33:18 +03:00
|
|
|
let packageReference = packageReferences[dependency.reference]
|
|
|
|
|
|
|
|
// If package's reference is none and there is no specified package in localPackages,
|
|
|
|
// then ignore the package specified as dependency.
|
2020-03-05 17:36:00 +03:00
|
|
|
if packageReference == nil, !localPackageReferences.contains(dependency.reference) {
|
2020-03-05 17:05:46 +03:00
|
|
|
continue
|
2019-08-13 14:51:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
let productName = product ?? dependency.reference
|
|
|
|
let packageDependency = addObject(
|
|
|
|
XCSwiftPackageProductDependency(productName: productName, package: packageReference)
|
|
|
|
)
|
|
|
|
packageDependencies.append(packageDependency)
|
|
|
|
|
2019-09-27 11:48:16 +03:00
|
|
|
let link = dependency.link ?? (target.type != .staticLibrary)
|
|
|
|
if link {
|
|
|
|
let buildFile = addObject(
|
|
|
|
PBXBuildFile(product: packageDependency)
|
|
|
|
)
|
|
|
|
targetFrameworkBuildFiles.append(buildFile)
|
2019-11-27 21:42:14 +03:00
|
|
|
} else {
|
|
|
|
let targetDependency = addObject(
|
|
|
|
PBXTargetDependency(product: packageDependency)
|
|
|
|
)
|
|
|
|
dependencies.append(targetDependency)
|
2019-09-27 11:48:16 +03:00
|
|
|
}
|
2020-02-25 14:20:25 +03:00
|
|
|
|
2020-02-26 17:02:13 +03:00
|
|
|
if dependency.embed == true {
|
2020-02-25 14:20:25 +03:00
|
|
|
let embedFile = addObject(
|
|
|
|
PBXBuildFile(product: packageDependency,
|
|
|
|
settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true))
|
|
|
|
)
|
|
|
|
copyFrameworksReferences.append(embedFile)
|
|
|
|
}
|
2019-11-18 12:07:46 +03:00
|
|
|
case .bundle:
|
|
|
|
// Static and dynamic libraries can't copy resources
|
|
|
|
guard target.type != .staticLibrary && target.type != .dynamicLibrary else { break }
|
|
|
|
|
|
|
|
let fileReference = sourceGenerator.getFileReference(
|
|
|
|
path: Path(dependency.reference),
|
|
|
|
inPath: project.basePath,
|
|
|
|
sourceTree: .buildProductsDir
|
|
|
|
)
|
|
|
|
|
|
|
|
let pbxBuildFile = PBXBuildFile(file: fileReference, settings: nil)
|
|
|
|
let buildFile = addObject(pbxBuildFile)
|
2019-11-20 10:24:05 +03:00
|
|
|
copyBundlesReferences.append(buildFile)
|
2019-11-18 12:07:46 +03:00
|
|
|
|
|
|
|
if !bundleFiles.contains(fileReference) {
|
|
|
|
bundleFiles.append(fileReference)
|
|
|
|
}
|
2018-07-25 01:15:33 +03:00
|
|
|
}
|
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-07-25 01:15:33 +03:00
|
|
|
for dependency in carthageDependencies {
|
2019-11-10 03:56:23 +03:00
|
|
|
|
2019-04-05 08:41:38 +03:00
|
|
|
let embed = dependency.embed ?? target.shouldEmbedCarthageDependencies
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2020-05-01 20:54:12 +03:00
|
|
|
let platformPath = Path(carthageResolver.buildPath(for: target.platform, linkType: dependency.carthageLinkType ?? .default))
|
2018-07-25 01:15:33 +03:00
|
|
|
var frameworkPath = platformPath + dependency.reference
|
|
|
|
if frameworkPath.extension == nil {
|
|
|
|
frameworkPath = Path(frameworkPath.string + ".framework")
|
|
|
|
}
|
|
|
|
let fileReference = sourceGenerator.getFileReference(path: frameworkPath, inPath: platformPath)
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2020-05-01 20:54:12 +03:00
|
|
|
if (dependency.carthageLinkType == .static || dependency.carthageLinkType == .staticBinary) {
|
2019-11-07 20:03:26 +03:00
|
|
|
let embedFile = addObject(
|
|
|
|
PBXBuildFile(file: fileReference, settings: getDependencyFrameworkSettings(dependency: dependency))
|
|
|
|
)
|
|
|
|
targetFrameworkBuildFiles.append(embedFile)
|
|
|
|
} else if embed {
|
2018-07-25 01:15:33 +03:00
|
|
|
if directlyEmbedCarthage {
|
2018-10-01 05:53:16 +03:00
|
|
|
let embedFile = addObject(
|
2018-09-25 14:11:04 +03:00
|
|
|
PBXBuildFile(file: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true))
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2018-09-25 14:11:04 +03:00
|
|
|
copyFrameworksReferences.append(embedFile)
|
2018-08-19 07:22:42 +03:00
|
|
|
} else {
|
2018-07-25 01:15:33 +03:00
|
|
|
carthageFrameworksToEmbed.append(dependency.reference)
|
2017-10-01 03:23:45 +03:00
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
var buildPhases: [PBXBuildPhase] = []
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
func getBuildFilesForSourceFiles(_ sourceFiles: [SourceFile]) -> [PBXBuildFile] {
|
2019-11-10 03:56:23 +03:00
|
|
|
sourceFiles
|
2018-01-24 10:22:46 +03:00
|
|
|
.reduce(into: [SourceFile]()) { output, sourceFile in
|
2018-10-08 14:08:49 +03:00
|
|
|
if !output.contains(where: { $0.fileReference === sourceFile.fileReference }) {
|
2018-01-24 10:22:46 +03:00
|
|
|
output.append(sourceFile)
|
|
|
|
}
|
2018-01-03 12:58:42 +03:00
|
|
|
}
|
2018-10-11 16:07:21 +03:00
|
|
|
.map { addObject($0.buildFile) }
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
func getBuildFilesForPhase(_ buildPhase: BuildPhase) -> [PBXBuildFile] {
|
2018-07-17 23:37:40 +03:00
|
|
|
let filteredSourceFiles = sourceFiles
|
|
|
|
.filter { $0.buildPhase?.buildPhase == buildPhase }
|
|
|
|
return getBuildFilesForSourceFiles(filteredSourceFiles)
|
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
func getBuildFilesForCopyFilesPhases() -> [TargetSource.BuildPhase.CopyFilesSettings: [PBXBuildFile]] {
|
2018-07-17 23:37:40 +03:00
|
|
|
var sourceFilesByCopyFiles: [TargetSource.BuildPhase.CopyFilesSettings: [SourceFile]] = [:]
|
|
|
|
for sourceFile in sourceFiles {
|
|
|
|
guard case let .copyFiles(copyFilesSettings)? = sourceFile.buildPhase else { continue }
|
|
|
|
sourceFilesByCopyFiles[copyFilesSettings, default: []].append(sourceFile)
|
|
|
|
}
|
|
|
|
return sourceFilesByCopyFiles.mapValues { getBuildFilesForSourceFiles($0) }
|
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-09-14 21:47:27 +03:00
|
|
|
copyFilesBuildPhasesFiles.merge(getBuildFilesForCopyFilesPhases()) { $0 + $1 }
|
2018-09-18 20:13:01 +03:00
|
|
|
|
|
|
|
buildPhases += try target.preBuildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) }
|
|
|
|
|
2018-09-14 21:47:27 +03:00
|
|
|
buildPhases += copyFilesBuildPhasesFiles
|
|
|
|
.filter { $0.key.phaseOrder == .preCompile }
|
|
|
|
.map { generateCopyFiles(targetName: target.name, copyFiles: $0, buildPhaseFiles: $1) }
|
2018-09-19 14:10:25 +03:00
|
|
|
|
2018-09-14 18:27:57 +03:00
|
|
|
let headersBuildPhaseFiles = getBuildFilesForPhase(.headers)
|
2018-10-08 09:29:09 +03:00
|
|
|
if !headersBuildPhaseFiles.isEmpty {
|
2019-11-06 23:09:20 +03:00
|
|
|
if target.type.isFramework || target.type == .dynamicLibrary {
|
2018-10-08 09:29:09 +03:00
|
|
|
let headersBuildPhase = addObject(PBXHeadersBuildPhase(files: headersBuildPhaseFiles))
|
|
|
|
buildPhases.append(headersBuildPhase)
|
|
|
|
} else {
|
|
|
|
headersBuildPhaseFiles.forEach { pbxProj.delete(object: $0) }
|
|
|
|
}
|
2018-09-14 18:27:57 +03:00
|
|
|
}
|
2017-08-01 19:40:40 +03:00
|
|
|
|
2017-11-13 00:17:08 +03:00
|
|
|
let sourcesBuildPhaseFiles = getBuildFilesForPhase(.sources)
|
2020-04-06 21:37:37 +03:00
|
|
|
let shouldSkipSourcesBuildPhase = sourcesBuildPhaseFiles.isEmpty && target.type.canSkipCompileSourcesBuildPhase
|
2019-01-16 05:23:25 +03:00
|
|
|
if !shouldSkipSourcesBuildPhase {
|
|
|
|
let sourcesBuildPhase = addObject(PBXSourcesBuildPhase(files: sourcesBuildPhaseFiles))
|
|
|
|
buildPhases.append(sourcesBuildPhase)
|
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-09-18 20:13:01 +03:00
|
|
|
buildPhases += try target.postCompileScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) }
|
2018-12-18 14:37:22 +03:00
|
|
|
|
2019-11-20 10:24:05 +03:00
|
|
|
let resourcesBuildPhaseFiles = getBuildFilesForPhase(.resources) + copyResourcesReferences
|
2017-11-13 00:17:08 +03:00
|
|
|
if !resourcesBuildPhaseFiles.isEmpty {
|
2018-10-01 05:53:16 +03:00
|
|
|
let resourcesBuildPhase = addObject(PBXResourcesBuildPhase(files: resourcesBuildPhaseFiles))
|
2018-09-25 14:11:04 +03:00
|
|
|
buildPhases.append(resourcesBuildPhase)
|
2017-11-13 00:17:08 +03:00
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-10-05 19:12:51 +03:00
|
|
|
let swiftObjCInterfaceHeader = project.getCombinedBuildSetting("SWIFT_OBJC_INTERFACE_HEADER_NAME", target: target, config: project.configs[0]) as? String
|
2020-04-15 03:55:56 +03:00
|
|
|
let swiftInstallObjCHeader = project.getBoolBuildSetting("SWIFT_INSTALL_OBJC_HEADER", target: target, config: project.configs[0]) ?? true // Xcode default
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-08-01 16:26:04 +03:00
|
|
|
if target.type == .staticLibrary
|
|
|
|
&& swiftObjCInterfaceHeader != ""
|
2020-04-15 03:55:56 +03:00
|
|
|
&& swiftInstallObjCHeader
|
2018-08-01 16:26:04 +03:00
|
|
|
&& sourceFiles.contains(where: { $0.buildPhase == .sources && $0.path.extension == "swift" }) {
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-08-01 16:26:04 +03:00
|
|
|
let inputPaths = ["$(DERIVED_SOURCES_DIR)/$(SWIFT_OBJC_INTERFACE_HEADER_NAME)"]
|
|
|
|
let outputPaths = ["$(BUILT_PRODUCTS_DIR)/include/$(PRODUCT_MODULE_NAME)/$(SWIFT_OBJC_INTERFACE_HEADER_NAME)"]
|
2018-10-01 05:53:16 +03:00
|
|
|
let script = addObject(
|
2018-08-01 16:26:04 +03:00
|
|
|
PBXShellScriptBuildPhase(
|
|
|
|
name: "Copy Swift Objective-C Interface Header",
|
|
|
|
inputPaths: inputPaths,
|
|
|
|
outputPaths: outputPaths,
|
|
|
|
shellPath: "/bin/sh",
|
|
|
|
shellScript: "ditto \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n"
|
|
|
|
)
|
|
|
|
)
|
2018-09-25 14:11:04 +03:00
|
|
|
buildPhases.append(script)
|
2018-08-01 16:26:04 +03:00
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-09-14 21:47:27 +03:00
|
|
|
buildPhases += copyFilesBuildPhasesFiles
|
|
|
|
.filter { $0.key.phaseOrder == .postCompile }
|
|
|
|
.map { generateCopyFiles(targetName: target.name, copyFiles: $0, buildPhaseFiles: $1) }
|
2018-12-18 14:37:22 +03:00
|
|
|
|
2018-09-14 22:31:55 +03:00
|
|
|
if !carthageFrameworksToEmbed.isEmpty {
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-09-14 22:31:55 +03:00
|
|
|
let inputPaths = carthageFrameworksToEmbed
|
2019-11-07 20:03:26 +03:00
|
|
|
.map { "$(SRCROOT)/\(carthageResolver.buildPath(for: target.platform, linkType: .dynamic))/\($0)\($0.contains(".") ? "" : ".framework")" }
|
2018-09-14 22:31:55 +03:00
|
|
|
let outputPaths = carthageFrameworksToEmbed
|
|
|
|
.map { "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/\($0)\($0.contains(".") ? "" : ".framework")" }
|
2019-03-24 12:23:49 +03:00
|
|
|
let carthageExecutable = carthageResolver.executable
|
2018-11-05 19:35:15 +03:00
|
|
|
let carthageScript = addObject(
|
2018-09-14 22:31:55 +03:00
|
|
|
PBXShellScriptBuildPhase(
|
|
|
|
name: "Carthage",
|
|
|
|
inputPaths: inputPaths,
|
|
|
|
outputPaths: outputPaths,
|
|
|
|
shellPath: "/bin/sh",
|
|
|
|
shellScript: "\(carthageExecutable) copy-frameworks\n"
|
|
|
|
)
|
|
|
|
)
|
2018-11-05 19:35:15 +03:00
|
|
|
buildPhases.append(carthageScript)
|
2018-09-14 22:31:55 +03:00
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-08-03 21:06:21 +03:00
|
|
|
if !targetFrameworkBuildFiles.isEmpty {
|
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let frameworkBuildPhase = addObject(
|
2018-01-28 12:01:47 +03:00
|
|
|
PBXFrameworksBuildPhase(files: targetFrameworkBuildFiles)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2018-09-25 14:11:04 +03:00
|
|
|
buildPhases.append(frameworkBuildPhase)
|
2017-08-03 21:06:21 +03:00
|
|
|
}
|
|
|
|
|
2020-02-02 02:39:35 +03:00
|
|
|
if !copyBundlesReferences.isEmpty {
|
|
|
|
let copyBundlesPhase = addObject(PBXCopyFilesBuildPhase(
|
|
|
|
dstSubfolderSpec: .resources,
|
|
|
|
name: "Copy Bundle Resources",
|
|
|
|
files: copyBundlesReferences
|
|
|
|
))
|
|
|
|
buildPhases.append(copyBundlesPhase)
|
|
|
|
}
|
|
|
|
|
2017-08-03 21:06:21 +03:00
|
|
|
if !extensions.isEmpty {
|
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let copyFilesPhase = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
PBXCopyFilesBuildPhase(
|
|
|
|
dstPath: "",
|
|
|
|
dstSubfolderSpec: .plugins,
|
2018-07-25 03:13:21 +03:00
|
|
|
name: "Embed App Extensions",
|
2018-01-24 10:22:46 +03:00
|
|
|
files: extensions
|
|
|
|
)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2017-08-03 21:06:21 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
buildPhases.append(copyFilesPhase)
|
2017-08-03 21:06:21 +03:00
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2018-05-17 03:18:46 +03:00
|
|
|
copyFrameworksReferences += getBuildFilesForPhase(.frameworks)
|
2017-10-17 06:59:44 +03:00
|
|
|
if !copyFrameworksReferences.isEmpty {
|
2017-08-03 21:06:21 +03:00
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let copyFilesPhase = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
PBXCopyFilesBuildPhase(
|
|
|
|
dstPath: "",
|
|
|
|
dstSubfolderSpec: .frameworks,
|
2018-07-25 03:13:21 +03:00
|
|
|
name: "Embed Frameworks",
|
2018-01-24 10:22:46 +03:00
|
|
|
files: copyFrameworksReferences
|
|
|
|
)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2017-08-03 21:06:21 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
buildPhases.append(copyFilesPhase)
|
2017-08-03 21:06:21 +03:00
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
|
2017-10-17 07:28:08 +03:00
|
|
|
if !copyWatchReferences.isEmpty {
|
|
|
|
|
2018-10-01 05:53:16 +03:00
|
|
|
let copyFilesPhase = addObject(
|
2018-01-24 10:22:46 +03:00
|
|
|
PBXCopyFilesBuildPhase(
|
|
|
|
dstPath: "$(CONTENTS_FOLDER_PATH)/Watch",
|
|
|
|
dstSubfolderSpec: .productsDirectory,
|
2018-07-25 03:13:21 +03:00
|
|
|
name: "Embed Watch Content",
|
2018-01-24 10:22:46 +03:00
|
|
|
files: copyWatchReferences
|
|
|
|
)
|
2017-12-26 13:47:18 +03:00
|
|
|
)
|
2017-10-17 07:28:08 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
buildPhases.append(copyFilesPhase)
|
2017-10-17 07:28:08 +03:00
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-05-13 10:13:48 +03:00
|
|
|
let buildRules = target.buildRules.map { buildRule in
|
2018-10-01 05:53:16 +03:00
|
|
|
addObject(
|
2018-05-13 10:13:48 +03:00
|
|
|
PBXBuildRule(
|
|
|
|
compilerSpec: buildRule.action.compilerSpec,
|
|
|
|
fileType: buildRule.fileType.fileType,
|
|
|
|
isEditable: true,
|
|
|
|
filePatterns: buildRule.fileType.pattern,
|
|
|
|
name: buildRule.name ?? "Build Rule",
|
|
|
|
outputFiles: buildRule.outputFiles,
|
|
|
|
outputFilesCompilerFlags: buildRule.outputFilesCompilerFlags,
|
|
|
|
script: buildRule.action.script
|
2018-06-08 08:21:21 +03:00
|
|
|
)
|
2018-09-25 14:11:04 +03:00
|
|
|
)
|
2018-05-13 10:13:48 +03:00
|
|
|
}
|
|
|
|
|
2018-09-18 20:13:01 +03:00
|
|
|
buildPhases += try target.postBuildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) }
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
let configs: [XCBuildConfiguration] = project.configs.map { config in
|
2018-07-20 20:30:46 +03:00
|
|
|
var buildSettings = project.getTargetBuildSettings(target: target, config: config)
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-09-29 18:51:29 +03:00
|
|
|
// Set CODE_SIGN_ENTITLEMENTS
|
|
|
|
if let entitlements = target.entitlements {
|
|
|
|
buildSettings["CODE_SIGN_ENTITLEMENTS"] = entitlements.path
|
|
|
|
}
|
|
|
|
|
2018-11-26 14:06:30 +03:00
|
|
|
// Set INFOPLIST_FILE if not defined in settings
|
|
|
|
if !project.targetHasBuildSetting("INFOPLIST_FILE", target: target, config: config) {
|
|
|
|
if let info = target.info {
|
|
|
|
buildSettings["INFOPLIST_FILE"] = info.path
|
|
|
|
} else if searchForPlist {
|
2018-07-20 20:30:46 +03:00
|
|
|
plistPath = getInfoPlist(target.sources)
|
|
|
|
searchForPlist = false
|
|
|
|
}
|
|
|
|
if let plistPath = plistPath {
|
2019-10-09 10:08:28 +03:00
|
|
|
buildSettings["INFOPLIST_FILE"] = (try? plistPath.relativePath(from: projectDirectory ?? project.basePath)) ?? plistPath
|
2018-07-20 20:30:46 +03:00
|
|
|
}
|
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-07-20 20:30:46 +03:00
|
|
|
// automatically calculate bundle id
|
|
|
|
if let bundleIdPrefix = project.options.bundleIdPrefix,
|
2018-10-05 19:12:51 +03:00
|
|
|
!project.targetHasBuildSetting("PRODUCT_BUNDLE_IDENTIFIER", target: target, config: config) {
|
2018-07-20 20:30:46 +03:00
|
|
|
let characterSet = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "-.")).inverted
|
|
|
|
let escapedTargetName = target.name
|
|
|
|
.replacingOccurrences(of: "_", with: "-")
|
|
|
|
.components(separatedBy: characterSet)
|
|
|
|
.joined(separator: "")
|
|
|
|
buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] = bundleIdPrefix + "." + escapedTargetName
|
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-07-20 20:30:46 +03:00
|
|
|
// automatically set test target name
|
2020-02-26 18:26:35 +03:00
|
|
|
if target.type == .uiTestBundle,
|
2018-10-05 19:12:51 +03:00
|
|
|
!project.targetHasBuildSetting("TEST_TARGET_NAME", target: target, config: config) {
|
2018-07-20 20:30:46 +03:00
|
|
|
for dependency in target.dependencies {
|
|
|
|
if dependency.type == .target,
|
|
|
|
let dependencyTarget = project.getTarget(dependency.reference),
|
2018-12-05 11:13:18 +03:00
|
|
|
dependencyTarget.type.isApp {
|
2018-07-20 20:30:46 +03:00
|
|
|
buildSettings["TEST_TARGET_NAME"] = dependencyTarget.name
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-12-05 11:13:58 +03:00
|
|
|
// automatically set TEST_HOST
|
|
|
|
if target.type == .unitTestBundle,
|
|
|
|
!project.targetHasBuildSetting("TEST_HOST", target: target, config: config) {
|
|
|
|
for dependency in target.dependencies {
|
|
|
|
if dependency.type == .target,
|
|
|
|
let dependencyTarget = project.getTarget(dependency.reference),
|
|
|
|
dependencyTarget.type.isApp {
|
2019-10-24 19:12:00 +03:00
|
|
|
if dependencyTarget.platform == .macOS {
|
|
|
|
buildSettings["TEST_HOST"] = "$(BUILT_PRODUCTS_DIR)/\(dependencyTarget.productName).app/Contents/MacOS/\(dependencyTarget.productName)"
|
|
|
|
} else {
|
|
|
|
buildSettings["TEST_HOST"] = "$(BUILT_PRODUCTS_DIR)/\(dependencyTarget.productName).app/\(dependencyTarget.productName)"
|
|
|
|
}
|
2018-12-05 11:13:58 +03:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-20 21:28:11 +03:00
|
|
|
// objc linkage
|
|
|
|
if anyDependencyRequiresObjCLinking {
|
|
|
|
let otherLinkingFlags = "OTHER_LDFLAGS"
|
|
|
|
let objCLinking = "-ObjC"
|
|
|
|
if var array = buildSettings[otherLinkingFlags] as? [String] {
|
|
|
|
array.append(objCLinking)
|
|
|
|
buildSettings[otherLinkingFlags] = array
|
|
|
|
} else if let string = buildSettings[otherLinkingFlags] as? String {
|
|
|
|
buildSettings[otherLinkingFlags] = [string, objCLinking]
|
|
|
|
} else {
|
|
|
|
buildSettings[otherLinkingFlags] = ["$(inherited)", objCLinking]
|
|
|
|
}
|
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-07-20 20:30:46 +03:00
|
|
|
// set Carthage search paths
|
2018-08-08 15:43:46 +03:00
|
|
|
let configFrameworkBuildPaths: [String]
|
2018-07-20 20:30:46 +03:00
|
|
|
if !carthageDependencies.isEmpty {
|
2020-05-01 20:54:12 +03:00
|
|
|
var carthagePlatformBuildPaths: Set<String> = []
|
2019-11-07 20:03:26 +03:00
|
|
|
if carthageDependencies.contains(where: { $0.carthageLinkType == .static }) {
|
|
|
|
let carthagePlatformBuildPath = "$(PROJECT_DIR)/" + carthageResolver.buildPath(for: target.platform, linkType: .static)
|
2020-05-01 20:54:12 +03:00
|
|
|
carthagePlatformBuildPaths.insert(carthagePlatformBuildPath)
|
2019-11-07 20:03:26 +03:00
|
|
|
}
|
|
|
|
if carthageDependencies.contains(where: { $0.carthageLinkType == .dynamic }) {
|
|
|
|
let carthagePlatformBuildPath = "$(PROJECT_DIR)/" + carthageResolver.buildPath(for: target.platform, linkType: .dynamic)
|
2020-05-01 20:54:12 +03:00
|
|
|
carthagePlatformBuildPaths.insert(carthagePlatformBuildPath)
|
2019-11-07 20:03:26 +03:00
|
|
|
}
|
2020-05-01 20:54:12 +03:00
|
|
|
if carthageDependencies.contains(where: { $0.carthageLinkType == .staticBinary }) {
|
|
|
|
let carthagePlatformBuildPath = "$(PROJECT_DIR)/" + carthageResolver.buildPath(for: target.platform, linkType: .staticBinary)
|
|
|
|
carthagePlatformBuildPaths.insert(carthagePlatformBuildPath)
|
|
|
|
}
|
|
|
|
configFrameworkBuildPaths = Array(carthagePlatformBuildPaths) + frameworkBuildPaths.sorted()
|
2018-08-08 15:43:46 +03:00
|
|
|
} else {
|
2019-09-23 10:41:31 +03:00
|
|
|
configFrameworkBuildPaths = frameworkBuildPaths.sorted()
|
2018-08-08 15:43:46 +03:00
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-08-08 15:43:46 +03:00
|
|
|
// set framework search paths
|
|
|
|
if !configFrameworkBuildPaths.isEmpty {
|
|
|
|
let frameworkSearchPaths = "FRAMEWORK_SEARCH_PATHS"
|
2018-07-20 20:30:46 +03:00
|
|
|
if var array = buildSettings[frameworkSearchPaths] as? [String] {
|
2018-08-08 15:43:46 +03:00
|
|
|
array.append(contentsOf: configFrameworkBuildPaths)
|
2018-07-20 20:30:46 +03:00
|
|
|
buildSettings[frameworkSearchPaths] = array
|
|
|
|
} else if let string = buildSettings[frameworkSearchPaths] as? String {
|
2018-08-08 15:43:46 +03:00
|
|
|
buildSettings[frameworkSearchPaths] = [string] + configFrameworkBuildPaths
|
2018-07-20 20:30:46 +03:00
|
|
|
} else {
|
2018-08-08 15:43:46 +03:00
|
|
|
buildSettings[frameworkSearchPaths] = ["$(inherited)"] + configFrameworkBuildPaths
|
2018-07-20 20:30:46 +03:00
|
|
|
}
|
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2018-09-25 14:11:04 +03:00
|
|
|
var baseConfiguration: PBXFileReference?
|
|
|
|
if let configPath = target.configFiles[config.name],
|
2018-10-01 06:19:29 +03:00
|
|
|
let fileReference = sourceGenerator.getContainedFileReference(path: project.basePath + configPath) as? PBXFileReference {
|
2018-09-25 14:11:04 +03:00
|
|
|
baseConfiguration = fileReference
|
2018-07-20 20:30:46 +03:00
|
|
|
}
|
|
|
|
let buildConfig = XCBuildConfiguration(
|
|
|
|
name: config.name,
|
|
|
|
buildSettings: buildSettings
|
|
|
|
)
|
2018-09-25 14:11:04 +03:00
|
|
|
buildConfig.baseConfiguration = baseConfiguration
|
2018-10-01 05:53:16 +03:00
|
|
|
return addObject(buildConfig)
|
2018-07-20 20:30:46 +03:00
|
|
|
}
|
2018-08-19 07:22:42 +03:00
|
|
|
|
2020-02-25 03:57:36 +03:00
|
|
|
let defaultConfigurationName = project.options.defaultConfig ?? project.configs.first?.name ?? ""
|
2018-10-01 05:53:16 +03:00
|
|
|
let buildConfigList = addObject(XCConfigurationList(
|
2018-09-25 14:11:04 +03:00
|
|
|
buildConfigurations: configs,
|
2020-02-25 03:57:36 +03:00
|
|
|
defaultConfigurationName: defaultConfigurationName
|
2018-07-20 20:30:46 +03:00
|
|
|
))
|
2018-01-24 10:22:46 +03:00
|
|
|
|
2018-09-25 14:08:11 +03:00
|
|
|
let targetObject = targetObjects[target.name]!
|
2018-01-24 10:22:46 +03:00
|
|
|
|
2018-10-15 14:55:59 +03:00
|
|
|
let targetFileReference = targetFileReferences[target.name]
|
2018-01-24 10:22:46 +03:00
|
|
|
|
|
|
|
targetObject.name = target.name
|
2018-09-25 14:11:04 +03:00
|
|
|
targetObject.buildConfigurationList = buildConfigList
|
2018-01-24 10:22:46 +03:00
|
|
|
targetObject.buildPhases = buildPhases
|
|
|
|
targetObject.dependencies = dependencies
|
|
|
|
targetObject.productName = target.name
|
2018-05-13 10:13:48 +03:00
|
|
|
targetObject.buildRules = buildRules
|
2019-08-13 14:51:47 +03:00
|
|
|
targetObject.packageProductDependencies = packageDependencies
|
2018-10-15 14:55:59 +03:00
|
|
|
targetObject.product = targetFileReference
|
2018-01-24 10:22:46 +03:00
|
|
|
if !target.isLegacy {
|
|
|
|
targetObject.productType = target.type
|
2017-12-19 00:26:49 +03:00
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
|
|
|
|
2017-12-20 20:04:23 +03:00
|
|
|
func getInfoPlist(_ sources: [TargetSource]) -> Path? {
|
2019-11-10 03:56:23 +03:00
|
|
|
sources
|
2017-12-20 04:10:13 +03:00
|
|
|
.lazy
|
2018-04-12 16:13:40 +03:00
|
|
|
.map { self.project.basePath + $0.path }
|
2018-09-13 16:05:51 +03:00
|
|
|
.compactMap { (path) -> Path? in
|
2017-12-20 04:10:13 +03:00
|
|
|
if path.isFile {
|
|
|
|
return path.lastComponent == "Info.plist" ? path : nil
|
|
|
|
} else {
|
|
|
|
return path.first(where: { $0.lastComponent == "Info.plist" })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.first
|
|
|
|
}
|
|
|
|
|
2018-07-03 21:34:20 +03:00
|
|
|
func getAllDependenciesPlusTransitiveNeedingEmbedding(target topLevelTarget: Target) -> [Dependency] {
|
2018-06-29 06:32:54 +03:00
|
|
|
// this is used to resolve cyclical target dependencies
|
|
|
|
var visitedTargets: Set<String> = []
|
|
|
|
var dependencies: [String: Dependency] = [:]
|
|
|
|
var queue: [Target] = [topLevelTarget]
|
|
|
|
while !queue.isEmpty {
|
|
|
|
let target = queue.removeFirst()
|
|
|
|
if visitedTargets.contains(target.name) {
|
|
|
|
continue
|
|
|
|
}
|
2018-07-03 14:45:00 +03:00
|
|
|
|
2018-06-29 06:32:54 +03:00
|
|
|
let isTopLevel = target == topLevelTarget
|
2018-07-03 14:45:00 +03:00
|
|
|
|
2018-06-29 06:32:54 +03:00
|
|
|
for dependency in target.dependencies {
|
|
|
|
// don't overwrite dependencies, to allow top level ones to rule
|
2018-09-25 14:08:11 +03:00
|
|
|
if dependencies[dependency.reference] != nil {
|
2018-06-29 06:32:54 +03:00
|
|
|
continue
|
|
|
|
}
|
2018-07-03 14:45:00 +03:00
|
|
|
|
2018-06-29 06:32:54 +03:00
|
|
|
// don't want a dependency if it's going to be embedded or statically linked in a non-top level target
|
|
|
|
// in .target check we filter out targets that will embed all of their dependencies
|
2020-04-07 18:14:42 +03:00
|
|
|
// For some more context about the `dependency.embed != true` lines, refer to https://github.com/yonaskolb/XcodeGen/pull/820
|
2018-06-29 06:32:54 +03:00
|
|
|
switch dependency.type {
|
2018-11-02 09:55:24 +03:00
|
|
|
case .sdk:
|
|
|
|
dependencies[dependency.reference] = dependency
|
2019-08-13 14:51:47 +03:00
|
|
|
case .framework, .carthage, .package:
|
2020-04-07 18:14:42 +03:00
|
|
|
if isTopLevel || dependency.embed != true {
|
2018-06-29 06:32:54 +03:00
|
|
|
dependencies[dependency.reference] = dependency
|
|
|
|
}
|
|
|
|
case .target:
|
2020-02-02 01:44:56 +03:00
|
|
|
let dependencyTargetReference = try! TargetReference(dependency.reference)
|
|
|
|
|
|
|
|
switch dependencyTargetReference.location {
|
|
|
|
case .local:
|
2020-04-07 18:14:42 +03:00
|
|
|
if isTopLevel || dependency.embed != true {
|
2020-02-02 01:44:56 +03:00
|
|
|
if let dependencyTarget = project.getTarget(dependency.reference) {
|
|
|
|
dependencies[dependency.reference] = dependency
|
|
|
|
if !dependencyTarget.shouldEmbedDependencies {
|
|
|
|
// traverse target's dependencies if it doesn't embed them itself
|
|
|
|
queue.append(dependencyTarget)
|
|
|
|
}
|
|
|
|
} else if project.getAggregateTarget(dependency.reference) != nil {
|
|
|
|
// Aggregate targets should be included
|
|
|
|
dependencies[dependency.reference] = dependency
|
2018-06-29 06:32:54 +03:00
|
|
|
}
|
2020-02-02 01:44:56 +03:00
|
|
|
}
|
|
|
|
case .project:
|
2020-04-07 18:14:42 +03:00
|
|
|
if isTopLevel || dependency.embed != true {
|
2018-08-22 17:35:59 +03:00
|
|
|
dependencies[dependency.reference] = dependency
|
2018-06-29 06:32:54 +03:00
|
|
|
}
|
|
|
|
}
|
2019-11-18 12:07:46 +03:00
|
|
|
case .bundle:
|
|
|
|
if isTopLevel {
|
|
|
|
dependencies[dependency.reference] = dependency
|
|
|
|
}
|
2018-06-29 06:32:54 +03:00
|
|
|
}
|
|
|
|
}
|
2018-07-03 14:45:00 +03:00
|
|
|
|
2018-06-29 06:32:54 +03:00
|
|
|
visitedTargets.update(with: target.name)
|
|
|
|
}
|
2018-07-03 14:45:00 +03:00
|
|
|
|
2018-06-29 06:32:54 +03:00
|
|
|
return dependencies.sorted(by: { $0.key < $1.key }).map { $0.value }
|
|
|
|
}
|
2017-07-23 21:58:03 +03:00
|
|
|
}
|
2018-03-01 13:52:25 +03:00
|
|
|
|
|
|
|
extension Target {
|
|
|
|
|
|
|
|
var shouldEmbedDependencies: Bool {
|
2019-11-10 03:56:23 +03:00
|
|
|
type.isApp || type.isTest
|
2018-03-01 13:52:25 +03:00
|
|
|
}
|
2019-09-23 10:44:06 +03:00
|
|
|
|
2019-04-05 08:41:38 +03:00
|
|
|
var shouldEmbedCarthageDependencies: Bool {
|
2019-11-10 03:56:23 +03:00
|
|
|
(type.isApp && platform != .watchOS)
|
2019-04-05 08:41:38 +03:00
|
|
|
|| type == .watch2Extension
|
|
|
|
|| type.isTest
|
|
|
|
}
|
2018-03-01 13:52:25 +03:00
|
|
|
}
|
2018-07-24 15:59:24 +03:00
|
|
|
|
2018-07-26 16:20:39 +03:00
|
|
|
extension Platform {
|
|
|
|
/// - returns: `true` for platforms that the app store requires simulator slices to be stripped.
|
|
|
|
public var requiresSimulatorStripping: Bool {
|
|
|
|
switch self {
|
|
|
|
case .iOS, .tvOS, .watchOS:
|
|
|
|
return true
|
|
|
|
case .macOS:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-24 15:59:24 +03:00
|
|
|
extension PBXFileElement {
|
|
|
|
|
|
|
|
public func getSortOrder(groupSortPosition: SpecOptions.GroupSortPosition) -> Int {
|
|
|
|
if type(of: self).isa == "PBXGroup" {
|
|
|
|
switch groupSortPosition {
|
|
|
|
case .top: return -1
|
|
|
|
case .bottom: return 1
|
|
|
|
case .none: return 0
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-07 20:03:26 +03:00
|
|
|
|
|
|
|
private extension Dependency {
|
|
|
|
var carthageLinkType: Dependency.CarthageLinkType? {
|
|
|
|
switch type {
|
|
|
|
case .carthage(_, let linkType):
|
|
|
|
return linkType
|
|
|
|
default:
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|