Skip to content

Commit

Permalink
"Copy only when installing" for "Embed App Extensions" (#948)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
RomanPodymov authored Oct 2, 2020
1 parent 1626352 commit 742fe69
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion Docs/ProjectSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 16 additions & 16 deletions Sources/XcodeGenKit/PBXProjGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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] = [:]
Expand Down Expand Up @@ -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) }
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
81 changes: 78 additions & 3 deletions Tests/XcodeGenKitTests/ProjectGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 742fe69

Please sign in to comment.