"Copy only when installing" for "Embed App Extensions" (#948)

* Added onlyCopyExtensionsOnInstall

* Fix for Xcode 12

* Fixed PBXCopyFilesBuildPhase for "Embed App Extensions"

* Test for onlyCopyExtensionsOnInstall

* Update CHANGELOG.md

* Update ProjectSpec.md

* Refactoring

* More tests for onlyCopyExtensionsOnInstall

* Reverted

* Refactoring with getPBXCopyFilesBuildPhase

* Deleted similar tests

* onlyCopyExtensionsOnInstall -> onlyCopyFilesOnInstall

* Update ProjectSpec.md

* Update CHANGELOG.md

* Update ProjectGeneratorTests.swift
This commit is contained in:
Roman Podymov 2020-10-02 09:48:32 +02:00 committed by GitHub
parent 162635243c
commit 742fe69c5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 20 deletions

View File

@ -16,6 +16,7 @@
- Allow SDK dependencies to be embedded. [#922](https://github.com/yonaskolb/XcodeGen/pull/922) @k-thorat
- Allow creating intermediary groups outside of the project directory. [#892](https://github.com/yonaskolb/XcodeGen/pull/892) @segiddins
- Fix appex's Runpath Search Paths under macOS target. [#952](https://github.com/yonaskolb/XcodeGen/pull/952) @rinsuki
- `onlyCopyFilesOnInstall` is extended for the Embed App Extensions build phase. [#948](https://github.com/yonaskolb/XcodeGen/pull/948) @RomanPodymov
## 2.17.0

View File

@ -250,7 +250,7 @@ Settings are merged in the following order: groups, base, configs.
- [ ] **transitivelyLinkDependencies**: **Bool** - If this is not specified the value from the project set in [Options](#options)`.transitivelyLinkDependencies` will be used.
- [ ] **directlyEmbedCarthageDependencies**: **Bool** - If this is `true` Carthage dependencies will be embedded using an `Embed Frameworks` build phase instead of the `copy-frameworks` script. Defaults to `true` for all targets except iOS/tvOS/watchOS Applications.
- [ ] **requiresObjCLinking**: **Bool** - If this is `true` any targets that link to this target will have `-ObjC` added to their `OTHER_LDFLAGS`. This is required if a static library has any catagories or extensions on Objective-C code. See [this guide](https://pewpewthespells.com/blog/objc_linker_flags.html#objc) for more details. Defaults to `true` if `type` is `library.static`. If you are 100% sure you don't have catagories or extensions on Objective-C code (pure Swift with no use of Foundation/UIKit) you can set this to `false`, otherwise it's best to leave it alone.
- [ ] **onlyCopyFilesOnInstall**: **Bool**  If this is `true`, the `Embed Frameworks` build phase will have the "Copy only when installing" chekbox checked. Defaults to `false`.
- [ ] **onlyCopyFilesOnInstall**: **Bool**  If this is `true`, the `Embed Frameworks` and `Embed App Extensions` (if available) build phases will have the "Copy only when installing" chekbox checked. Defaults to `false`.
- [ ] **preBuildScripts**: **[[Build Script](#build-script)]** - Build scripts that run *before* any other build phases
- [ ] **postCompileScripts**: **[[Build Script](#build-script)]** - Build scripts that run after the Compile Sources phase
- [ ] **postBuildScripts**: **[[Build Script](#build-script)]** - Build scripts that run *after* any other build phases

View File

@ -13,6 +13,8 @@ public class PBXProjGenerator {
let projectDirectory: Path?
let carthageResolver: CarthageDependencyResolver
public static let copyFilesActionMask: UInt = 8
var sourceGenerator: SourceGenerator!
var targetObjects: [String: PBXTarget] = [:]
@ -979,6 +981,17 @@ public class PBXProjGenerator {
return sourceFilesByCopyFiles.mapValues { getBuildFilesForSourceFiles($0) }
}
func getPBXCopyFilesBuildPhase(dstSubfolderSpec: PBXCopyFilesBuildPhase.SubFolder, name: String, files: [PBXBuildFile]) -> PBXCopyFilesBuildPhase {
return PBXCopyFilesBuildPhase(
dstPath: "",
dstSubfolderSpec: dstSubfolderSpec,
name: name,
buildActionMask: target.onlyCopyFilesOnInstall ? PBXProjGenerator.copyFilesActionMask : PBXBuildPhase.defaultBuildActionMask,
files: files,
runOnlyForDeploymentPostprocessing: target.onlyCopyFilesOnInstall ? true : false
)
}
copyFilesBuildPhasesFiles.merge(getBuildFilesForCopyFilesPhases()) { $0 + $1 }
buildPhases += try target.preBuildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) }
@ -1076,13 +1089,8 @@ public class PBXProjGenerator {
if !extensions.isEmpty {
let copyFilesPhase = addObject(
PBXCopyFilesBuildPhase(
dstPath: "",
dstSubfolderSpec: .plugins,
name: "Embed App Extensions",
files: extensions
)
let copyFilesPhase = addObject(
getPBXCopyFilesBuildPhase(dstSubfolderSpec: .plugins, name: "Embed App Extensions", files: extensions)
)
buildPhases.append(copyFilesPhase)
@ -1105,16 +1113,8 @@ public class PBXProjGenerator {
copyFrameworksReferences += getBuildFilesForPhase(.frameworks)
if !copyFrameworksReferences.isEmpty {
let copyFilesActionMask: UInt = 8
let copyFilesPhase = addObject(
PBXCopyFilesBuildPhase(
dstPath: "",
dstSubfolderSpec: .frameworks,
name: "Embed Frameworks",
buildActionMask: target.onlyCopyFilesOnInstall ? copyFilesActionMask : PBXBuildPhase.defaultBuildActionMask,
files: copyFrameworksReferences,
runOnlyForDeploymentPostprocessing: target.onlyCopyFilesOnInstall ? true : false
)
getPBXCopyFilesBuildPhase(dstSubfolderSpec: .frameworks, name: "Embed Frameworks", files: copyFrameworksReferences)
)
buildPhases.append(copyFilesPhase)

View File

@ -805,16 +805,91 @@ class ProjectGeneratorTests: XCTestCase {
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
let buildPhases = nativeTarget.buildPhases
let embedFrameworkPhase = pbxProject
let embedFrameworksPhase = pbxProject
.copyFilesBuildPhases
.filter { buildPhases.contains($0) }
.first { $0.dstSubfolderSpec == .frameworks }
let phase = try unwrap(embedFrameworkPhase)
try expect(phase.buildActionMask) == 8
let phase = try unwrap(embedFrameworksPhase)
try expect(phase.buildActionMask) == PBXProjGenerator.copyFilesActionMask
try expect(phase.runOnlyForDeploymentPostprocessing) == true
}
$0.it("copies files only on install in the Embed App Extensions step") {
let appExtension = Target(
name: "AppExtension",
type: .appExtension,
platform: .tvOS
)
let app = Target(
name: "App",
type: .application,
platform: .tvOS,
dependencies: [
Dependency(type: .target, reference: "AppExtension")
],
onlyCopyFilesOnInstall: true
)
let project = Project(name: "test", targets: [app, appExtension])
let pbxProject = try project.generatePbxProj()
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
let buildPhases = nativeTarget.buildPhases
let embedAppExtensionsPhase = pbxProject
.copyFilesBuildPhases
.filter { buildPhases.contains($0) }
.first { $0.dstSubfolderSpec == .plugins }
let phase = try unwrap(embedAppExtensionsPhase)
try expect(phase.buildActionMask) == PBXProjGenerator.copyFilesActionMask
try expect(phase.runOnlyForDeploymentPostprocessing) == true
}
$0.it("copies files only on install in the Embed Frameworks and Embed App Extensions steps") {
let appExtension = Target(
name: "AppExtension",
type: .appExtension,
platform: .tvOS
)
let app = Target(
name: "App",
type: .application,
platform: .tvOS,
dependencies: [
Dependency(type: .target, reference: "AppExtension"),
Dependency(type: .framework, reference: "FrameworkA.framework"),
Dependency(type: .framework, reference: "FrameworkB.framework", embed: false),
],
onlyCopyFilesOnInstall: true
)
let project = Project(name: "test", targets: [app, appExtension])
let pbxProject = try project.generatePbxProj()
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
let buildPhases = nativeTarget.buildPhases
let embedFrameworksPhase = pbxProject
.copyFilesBuildPhases
.filter { buildPhases.contains($0) }
.first { $0.dstSubfolderSpec == .frameworks }
let embedFrameworksPhaseValue = try unwrap(embedFrameworksPhase)
try expect(embedFrameworksPhaseValue.buildActionMask) == PBXProjGenerator.copyFilesActionMask
try expect(embedFrameworksPhaseValue.runOnlyForDeploymentPostprocessing) == true
let embedAppExtensionsPhase = pbxProject
.copyFilesBuildPhases
.filter { buildPhases.contains($0) }
.first { $0.dstSubfolderSpec == .plugins }
let embedAppExtensionsPhaseValue = try unwrap(embedAppExtensionsPhase)
try expect(embedAppExtensionsPhaseValue.buildActionMask) == PBXProjGenerator.copyFilesActionMask
try expect(embedAppExtensionsPhaseValue.runOnlyForDeploymentPostprocessing) == true
}
$0.it("sets -ObjC for targets that depend on requiresObjCLinking targets") {
let requiresObjCLinking = Target(
name: "requiresObjCLinking",