Compare commits

...

5 Commits

Author SHA1 Message Date
Bartosz Polaczyk 11eabdab3d Merge pull request #188 from polac24/bartosz/20230310-lipo
Introduce xclipo to mock lipo
2023-03-21 09:55:30 -04:00
Bartosz Polaczyk de24e609ef Delete leftover comment 2023-03-11 10:34:24 -05:00
Bartosz Polaczyk 850983cbde Fix formatting 2023-03-11 10:21:42 -05:00
Bartosz Polaczyk 0064335cc7 Introduce WatchApp to the Standalone E2E project 2023-03-11 10:16:47 -05:00
Bartosz Polaczyk 1ddadcb361 Add xclipo 2023-03-11 10:15:29 -05:00
21 changed files with 478 additions and 65 deletions
+2 -2
View File
@@ -51,8 +51,8 @@
"repositoryURL": "https://github.com/tuist/XcodeProj.git",
"state": {
"branch": null,
"revision": "c75c3acc25460195cfd203a04dde165395bf00e0",
"version": "8.7.1"
"revision": "fae27b48bc14ff3fd9b02902e48c4665ce5a0793",
"version": "8.9.0"
}
},
{
+15 -2
View File
@@ -16,7 +16,7 @@ let package = Package(
.package(url: "https://github.com/marmelroy/Zip.git", from: "2.1.2"),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.0"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "0.0.1"),
.package(url: "https://github.com/tuist/XcodeProj.git", from: "8.7.1"),
.package(url: "https://github.com/tuist/XcodeProj.git", from: "8.9.0"),
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
],
targets: [
@@ -40,6 +40,10 @@ let package = Package(
name: "xclibtool",
dependencies: ["XCRemoteCache", "xclibtoolSupport"]
),
.target(
name: "xclipo",
dependencies: ["XCRemoteCache"]
),
.target(
name: "xcpostbuild",
dependencies: ["XCRemoteCache"]
@@ -62,7 +66,16 @@ let package = Package(
.target(
// Wrapper target that builds all binaries but does nothing in runtime
name: "Aggregator",
dependencies: ["xcprebuild", "xcswiftc", "xclibtool", "xcpostbuild", "xcprepare", "xcld", "xcldplusplus"]
dependencies: [
"xcprebuild",
"xcswiftc",
"xclibtool",
"xcpostbuild",
"xcprepare",
"xcld",
"xcldplusplus",
"xclipo",
]
),
.testTarget(
name: "XCRemoteCacheTests",
+2 -1
View File
@@ -195,6 +195,7 @@ Configure Xcode targets that **should use** XCRemoteCache:
* `CC` - `xccc_file` from your `.rcinfo` configuration (e.g. `xcremotecache/xccc`)
* `SWIFT_EXEC` - location of `xcprepare` (e.g. `xcremotecache/xcswiftc`)
* `LIBTOOL` - location of `xclibtool` (e.g. `xcremotecache/xclibtool`)
* `LIPO` - location of `xclipo` (e.g. `xcremotecache/xclipo`)
* `LD` - location of `xcld` (e.g. `xcremotecache/xcld`)
* `LDPLUSPLUS` - location of `xcldplusplus` (e.g. `xcremotecache/xcldplusplus`)
* `XCRC_PLATFORM_PREFERRED_ARCH` - `$(LINK_FILE_LIST_$(CURRENT_VARIANT)_$(PLATFORM_PREFERRED_ARCH):dir:standardizepath:file:default=arm64)`
@@ -267,7 +268,7 @@ $ xcremotecache/xcprepare mark --configuration Debug --platform iphonesimulator
That command creates an empty file on a remote server which informs that for given sha, configuration, platform, Xcode versions etc. all artifacts are available.
_Note that for the `producer` mode, the prebuild build phase and `xccc`, `xcld`, `xcldplusplus`, `xclibtool` wrappers become no-op, so it is recommended to not add them for the `producer` mode._
_Note that for the `producer` mode, the prebuild build phase and `xccc`, `xcld`, `xcldplusplus`, `xclibtool`, `xclipo` wrappers become no-op, so it is recommended to not add them for the `producer` mode._
##### 7. Generalize `-Swift.h` (Optional only if using static library with a bridging header with public `NS_ENUM` exposed from ObjC)
+1 -1
View File
@@ -10,7 +10,7 @@ DERIVED_DATA_DIR = File.join('.build').freeze
RELEASES_ROOT_DIR = File.join('releases').freeze
EXECUTABLE_NAME = 'XCRemoteCache'
EXECUTABLE_NAMES = ['xclibtool', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc', 'xcld', 'xcldplusplus']
EXECUTABLE_NAMES = ['xclibtool', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc', 'xcld', 'xcldplusplus', 'xclipo']
PROJECT_NAME = 'XCRemoteCache'
SWIFTLINT_ENABLED = true
@@ -19,31 +19,42 @@
import Foundation
enum XCLibtoolCreateUniversalBinaryError: Error {
enum XCCreateUniversalBinaryError: Error {
/// Missing ar libraries that should constitute an universal build
case missingInputLibrary
}
/// Wrapper for `libtool` call for creating an universal binary
class XCLibtoolCreateUniversalBinary: XCLibtoolLogic {
/// Wrapper for `libtool`/`lipo` call for creating an universal binary
class XCCreateUniversalBinary: XCLibtoolLogic {
private let output: URL
private let tempDir: URL
private let firstInputURL: URL
private let toolName: String
private let fallbackCommand: String
init(output: String, inputs: [String]) throws {
init(
output: String,
inputs: [String],
toolName: String,
fallbackCommand: String
) throws {
self.output = URL(fileURLWithPath: output)
guard let firstInput = inputs.first else {
throw XCLibtoolCreateUniversalBinaryError.missingInputLibrary
throw XCCreateUniversalBinaryError.missingInputLibrary
}
let firstInputURL = URL(fileURLWithPath: firstInput)
// inputs are place in $TARGET_TEMP_DIR/Objects-normal/$ARCH/Binary/$TARGET_NAME.a
// TODO: find better (stable) technique to determine `$TARGET_TEMP_DIR`
errorLog("\(firstInputURL.absoluteString)")
tempDir = firstInputURL
.deletingLastPathComponent()
.deletingLastPathComponent()
.deletingLastPathComponent()
.deletingLastPathComponent()
self.firstInputURL = firstInputURL
self.toolName = toolName
self.fallbackCommand = fallbackCommand
}
func run() {
@@ -55,7 +66,7 @@ class XCLibtoolCreateUniversalBinary: XCLibtoolLogic {
config = try XCRemoteCacheConfigReader(srcRootPath: srcRoot.path, fileReader: fileManager)
.readConfiguration()
} catch {
errorLog("Libtool initialization failed with error: \(error). Fallbacking to libtool")
errorLog("\(toolName) initialization failed with error: \(error). Fallbacking to \(fallbackCommand)")
fallbackToDefault()
}
@@ -74,22 +85,21 @@ class XCLibtoolCreateUniversalBinary: XCLibtoolLogic {
// that these are already an universal binary
try fileManager.spt_forceLinkItem(at: firstInputURL, to: output)
} catch {
errorLog("Libtool failed with error: \(error). Fallbacking to libtool")
errorLog("\(toolName) failed with error: \(error). Fallbacking to \(fallbackCommand)")
do {
try fileManager.removeItem(at: markerURL)
fallbackToDefault()
} catch {
exit(1, "FATAL: libtool failed with error: \(error)")
exit(1, "FATAL: \(fallbackCommand) failed with error: \(error)")
}
}
}
private func fallbackToDefault() -> Never {
let args = ProcessInfo().arguments
let command = "libtool"
let paramList = [command] + args.dropFirst()
let paramList = [fallbackCommand] + args.dropFirst()
let cargs = paramList.map { strdup($0) } + [nil]
execvp(command, cargs)
execvp(fallbackCommand, cargs)
/// C-function `execv` returns only when the command fails
exit(1)
@@ -44,7 +44,12 @@ public class XCLibtool {
stepDescription: "Libtool"
)
case .createUniversalBinary(let output, let inputs):
logic = try XCLibtoolCreateUniversalBinary(output: output, inputs: inputs)
logic = try XCCreateUniversalBinary(
output: output,
inputs: inputs,
toolName: "Libtool",
fallbackCommand: "libtool"
)
}
}
@@ -0,0 +1,50 @@
// Copyright (c) 2023 Spotify AB.
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
import Foundation
/// Wrapper for a `lipo` tool that creates a fat archive
public class XCLipo {
private let logic: XCLibtoolLogic
public init(
output: String,
inputs: [String],
fallbackCommand: String,
stepDescription: String
) throws {
errorLog("\(output)")
errorLog("\(inputs.joined(separator: ","))")
logic = try XCCreateUniversalBinary(
output: output,
inputs: inputs,
toolName: stepDescription,
fallbackCommand: fallbackCommand
)
}
/// Handles a `-create` action which is responsible to create a fat archive
/// If remote cache can reuse artifacts from a remote cache, it just links any of input
/// files to the destination (output) location because the binary in XCRC artifact already
/// contains a fat library
/// If a remote artifact cannot be reused, a fallback to the `lipo` command is performed
public func run() {
logic.run()
}
}
@@ -50,6 +50,7 @@ class XcodeProjBuildSettingsIntegrateAppender: BuildSettingsIntegrateAppender {
result["CC"] = wrappers.cc.path
result["LD"] = wrappers.ld.path
result["LIBTOOL"] = wrappers.libtool.path
result["LIPO"] = wrappers.lipo.path
result["LDPLUSPLUS"] = wrappers.ldplusplus.path
}
@@ -52,6 +52,7 @@ extension IntegrateContext {
cc: binariesDir.appendingPathComponent("xccc"),
swiftc: binariesDir.appendingPathComponent("xcswiftc"),
libtool: binariesDir.appendingPathComponent("xclibtool"),
lipo: binariesDir.appendingPathComponent("xclipo"),
ld: binariesDir.appendingPathComponent("xcld"),
ldplusplus: binariesDir.appendingPathComponent("xcldplusplus"),
prebuild: binariesDir.appendingPathComponent("xcprebuild"),
@@ -25,6 +25,7 @@ struct XCRCBinariesPaths {
let cc: URL
let swiftc: URL
let libtool: URL
let lipo: URL
let ld: URL
let ldplusplus: URL
let prebuild: URL
+71
View File
@@ -0,0 +1,71 @@
// Copyright (c) 2023 Spotify AB.
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
import Foundation
import XCRemoteCache
/// Wrapper for a `lipo` program that links any of input binaries to the destination paths
/// Fallbacks to a standard `lipo` when the Ramote cache is not applicable (e.g. modified sources)
public class XCLipoMain {
public init() { }
public func main() {
let args = ProcessInfo().arguments
var output: String?
var create = false
var inputs: [String] = []
var i = 1
while i < args.count {
switch args[i] {
case "-output":
output = args[i + 1]
i += 1
case "-create":
create = true
default:
inputs.append(args[i])
}
i += 1
}
let lipoCommand = "lipo"
guard let output = output, !inputs.isEmpty, create else {
print("Fallbacking to compilation using \(lipoCommand).")
let args = ProcessInfo().arguments
let paramList = [lipoCommand] + args.dropFirst()
let cargs = paramList.map { strdup($0) } + [nil]
execvp(lipoCommand, cargs)
/// C-function `execv` returns only when the command fails
exit(1)
}
do {
try XCLipo(
output: output,
inputs: inputs,
fallbackCommand: lipoCommand,
stepDescription: "xclipo"
).run()
} catch {
exit(1, "Failed with: \(error). Args: \(args)")
}
}
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright (c) 2023 Spotify AB.
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
import XCRemoteCache
XCLipoMain().main()
@@ -34,6 +34,7 @@ class XcodeProjBuildSettingsIntegrateAppenderTests: XCTestCase {
cc: binariesDir.appendingPathComponent("xccc"),
swiftc: binariesDir.appendingPathComponent("xcswiftc"),
libtool: binariesDir.appendingPathComponent("xclibtool"),
lipo: binariesDir.appendingPathComponent("lipo"),
ld: binariesDir.appendingPathComponent("xcld"),
ldplusplus: binariesDir.appendingPathComponent("xcldplusplus"),
prebuild: binariesDir.appendingPathComponent("xcprebuild"),
@@ -3,9 +3,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -29,15 +29,15 @@ module CocoapodsXCRemoteCacheModifier
FAT_ARCHIVE_NAME_INFIX = 'arm64-x86_64'
XCRC_COOCAPODS_ROOT_KEY = 'XCRC_COOCAPODS_ROOT'
# List of plugins' user properties that should not be copied to .rcinfo
# List of plugins' user properties that should not be copied to .rcinfo
CUSTOM_CONFIGURATION_KEYS = [
'enabled',
'enabled',
'xcrc_location',
'exclude_targets',
'exclude_build_configurations',
'final_target',
'check_build_configuration',
'check_platform',
'check_build_configuration',
'check_platform',
'modify_lldb_init',
'fake_src_root',
]
@@ -45,19 +45,19 @@ module CocoapodsXCRemoteCacheModifier
class XCRemoteCache
@@configuration = nil
def self.configure(c)
def self.configure(c)
@@configuration = c
end
def self.set_configuration_default_values
default_values = {
'mode' => 'consumer',
'enabled' => true,
'enabled' => true,
'xcrc_location' => "XCRC",
'exclude_build_configurations' => [],
'check_build_configuration' => 'Debug',
'check_platform' => 'iphonesimulator',
'modify_lldb_init' => true,
'check_platform' => 'iphonesimulator',
'modify_lldb_init' => true,
'xccc_file' => "#{BIN_DIR}/xccc",
'remote_commit_file' => "#{BIN_DIR}/arc.rc",
'exclude_targets' => [],
@@ -75,12 +75,12 @@ module CocoapodsXCRemoteCacheModifier
def self.validate_configuration()
required_values = [
'cache_addresses',
'cache_addresses',
'primary_repo',
'check_build_configuration',
'check_platform'
]
missing_configuration_values = required_values.select { |v| !@@configuration.key?(v) }
unless missing_configuration_values.empty?
throw "XCRemoteCache not fully configured. Make sure all required fields are provided. Missing fields are: #{missing_configuration_values.join(', ')}."
@@ -105,7 +105,7 @@ module CocoapodsXCRemoteCacheModifier
end
# @param target [Target] target to apply XCRemoteCache
# @param repo_distance [Integer] distance from the git repo root to the target's $SRCROOT
# @param repo_distance [Integer] distance from the git repo root to the target's $SRCROOT
# @param xc_location [String] path to the dir with all XCRemoteCache binaries, relative to the repo root
# @param xc_cc_path [String] path to the XCRemoteCache clang wrapper, relative to the repo root
# @param mode [String] mode name ('consumer', 'producer', 'producer-fast' etc.)
@@ -128,6 +128,7 @@ module CocoapodsXCRemoteCacheModifier
config.build_settings['LIBTOOL'] = ["$SRCROOT/#{srcroot_relative_xc_location}/xclibtool"]
config.build_settings['LD'] = ["$SRCROOT/#{srcroot_relative_xc_location}/xcld"]
config.build_settings['LDPLUSPLUS'] = ["$SRCROOT/#{srcroot_relative_xc_location}/xcldplusplus"]
config.build_settings['LIPO'] = ["$SRCROOT/#{srcroot_relative_xc_location}/xclipo"]
config.build_settings['SWIFT_USE_INTEGRATED_DRIVER'] = ['NO']
config.build_settings['XCREMOTE_CACHE_FAKE_SRCROOT'] = fake_src_root
@@ -156,7 +157,7 @@ module CocoapodsXCRemoteCacheModifier
prebuild_script.dependency_file = "$(TARGET_TEMP_DIR)/prebuild.d"
# Move prebuild (last element) to the position before compile sources phase (to make it real 'prebuild')
if !existing_prebuild_script
if !existing_prebuild_script
compile_phase_index = target.build_phases.index(target.source_build_phase)
target.build_phases.insert(compile_phase_index, target.build_phases.delete(prebuild_script))
end
@@ -184,7 +185,7 @@ module CocoapodsXCRemoteCacheModifier
]
postbuild_script.dependency_file = "$(TARGET_TEMP_DIR)/postbuild.d"
# Move postbuild (last element) to the position after compile sources phase (to make it real 'postbuild')
if !existing_postbuild_script
if !existing_postbuild_script
compile_phase_index = target.build_phases.index(target.source_build_phase)
target.build_phases.insert(compile_phase_index + 1, target.build_phases.delete(postbuild_script))
end
@@ -214,6 +215,7 @@ module CocoapodsXCRemoteCacheModifier
config.build_settings.delete('CC') if config.build_settings.key?('CC')
config.build_settings.delete('SWIFT_EXEC') if config.build_settings.key?('SWIFT_EXEC')
config.build_settings.delete('LIBTOOL') if config.build_settings.key?('LIBTOOL')
config.build_settings.delete('LIPO') if config.build_settings.key?('LIPO')
config.build_settings.delete('LD') if config.build_settings.key?('LD')
config.build_settings.delete('LDPLUSPLUS') if config.build_settings.key?('LDPLUSPLUS')
config.build_settings.delete('SWIFT_USE_INTEGRATED_DRIVER') if config.build_settings.key?('SWIFT_USE_INTEGRATED_DRIVER')
@@ -226,9 +228,9 @@ module CocoapodsXCRemoteCacheModifier
end
# User project is not generated from scratch (contrary to `Pods`), delete all previous XCRemoteCache phases
target.build_phases.delete_if {|phase|
target.build_phases.delete_if {|phase|
# Some phases (e.g. PBXSourcesBuildPhase) don't have strict name check respond_to?
if phase.respond_to?(:name)
if phase.respond_to?(:name)
phase.name != nil && phase.name.start_with?("[XCRC]")
end
}
@@ -240,9 +242,9 @@ module CocoapodsXCRemoteCacheModifier
end
def self.download_xcrc_if_needed(local_location)
required_binaries = ['xcld', 'xcldplusplus', 'xclibtool', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc']
required_binaries = ['xcld', 'xcldplusplus', 'xclibtool', 'xclipo', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc']
binaries_exist = required_binaries.reduce(true) do |exists, filename|
file_path = File.join(local_location, filename)
file_path = File.join(local_location, filename)
exists = exists && File.exist?(file_path)
end
@@ -256,13 +258,13 @@ module CocoapodsXCRemoteCacheModifier
if !system("unzip #{local_package_location} -d #{local_location}")
throw "Unzipping XCRemoteCache failed"
end
end
end
def self.download_latest_xcrc_release(local_package_location)
release_url = 'https://api.github.com/repos/spotify/XCRemoteCache/releases/latest'
asset_url = nil
URI.open(release_url) do |f|
assets_array = JSON.parse(f.read)['assets']
# Pick fat archive
@@ -270,7 +272,7 @@ module CocoapodsXCRemoteCacheModifier
asset_url = asset_array['url']
end
if asset_url.nil?
if asset_url.nil?
throw "Downloading XCRemoteCache failed"
end
@@ -283,7 +285,7 @@ module CocoapodsXCRemoteCacheModifier
def self.add_cflags!(options, key, value)
return if options.fetch('OTHER_CFLAGS',[]).include?(value)
options['OTHER_CFLAGS'] = remove_cflags!(options, key) << "#{key}=#{value}"
options['OTHER_CFLAGS'] = remove_cflags!(options, key) << "#{key}=#{value}"
end
def self.remove_cflags!(options, key)
@@ -295,7 +297,7 @@ module CocoapodsXCRemoteCacheModifier
def self.add_swiftflags!(options, key, value)
return if options.fetch('OTHER_SWIFT_FLAGS','').include?(value)
options['OTHER_SWIFT_FLAGS'] = remove_swiftflags!(options, key) + " #{key} #{value}"
options['OTHER_SWIFT_FLAGS'] = remove_swiftflags!(options, key) + " #{key} #{value}"
end
def self.remove_swiftflags!(options, key)
@@ -336,7 +338,7 @@ module CocoapodsXCRemoteCacheModifier
File.open(lldbinit_path) { |file|
while(line = file.gets) != nil
line = line.strip
if line == LLDB_INIT_COMMENT
if line == LLDB_INIT_COMMENT
# skip current and next lines
file.gets
next
@@ -351,7 +353,7 @@ module CocoapodsXCRemoteCacheModifier
def self.add_lldbinit_rewrite(lines_content, user_proj_directory,fake_src_root)
all_lines = lines_content.clone
all_lines << LLDB_INIT_COMMENT
all_lines << "settings set target.source-map #{fake_src_root} #{user_proj_directory}"
all_lines << "settings set target.source-map #{fake_src_root} #{user_proj_directory}"
all_lines << ""
all_lines
end
@@ -413,8 +415,8 @@ module CocoapodsXCRemoteCacheModifier
# Remote cache is still disabled - no need to force Pods projects/targets regeneration
next
end
# Force rebuilding all Pods project, because XCRC build steps and settings need to be added to Pods project/targets
# Force rebuilding all Pods project, because XCRC build steps and settings need to be added to Pods project/targets
# It is relevant only when 'incremental_installation' is enabled, otherwise installed_cache_path does not exist on a disk
installed_cache_path = installer_context.sandbox.project_installation_cache_path
if !was_previously_enabled && File.exist?(installed_cache_path)
@@ -431,7 +433,7 @@ module CocoapodsXCRemoteCacheModifier
user_project = installer_context.umbrella_targets[0].user_project
begin
begin
user_proj_directory = File.dirname(user_project.path)
set_configuration_default_values
@@ -494,12 +496,12 @@ module CocoapodsXCRemoteCacheModifier
end
# Manual Pods/.rcinfo generation
# all paths in .rcinfo are relative to the root so paths used in Pods.xcodeproj need to be aligned
pods_path = Pathname.new(pods_proj_directory)
root_path = Pathname.new(user_proj_directory)
root_path_to_pods = root_path.relative_path_from(pods_path)
pods_rcinfo = root_rcinfo.merge({
'remote_commit_file' => "#{root_path_to_pods}/#{remote_commit_file}",
'xccc_file' => "#{root_path_to_pods}/#{xccc_location}"
@@ -511,7 +513,7 @@ module CocoapodsXCRemoteCacheModifier
# Enabled/disable XCRemoteCache for the main (user) project
begin
# TODO: Do not compile xcc again. `xcprepare` compiles it in pre-install anyway
# TODO: Do not compile xcc again. `xcprepare` compiles it in pre-install anyway
prepare_result = YAML.load`#{xcrc_location_absolute}/xcprepare --configuration #{check_build_configuration} --platform #{check_platform}`
unless prepare_result['result'] || mode != 'consumer'
# Uninstall the XCRemoteCache for the consumer mode
@@ -3,9 +3,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -13,5 +13,5 @@
# limitations under the License.
module CocoapodsXcremotecache
VERSION = "0.0.14"
VERSION = "0.0.15"
end
@@ -16,6 +16,8 @@
36201A2A2843B3D3002FF70F /* MixedTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36201A292843B3D3002FF70F /* MixedTarget.swift */; };
36201A362843B435002FF70F /* libMixedTarget.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 36201A272843B3D3002FF70F /* libMixedTarget.a */; };
36201A392843BDDC002FF70F /* StandaloneObjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 36201A382843BDDC002FF70F /* StandaloneObjc.m */; };
4E10D63029BBFD8000A8655C /* WatchExtensionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E10D62F29BBFD8000A8655C /* WatchExtensionExtension.swift */; };
4E10D63229BBFD8000A8655C /* WatchExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E10D63129BBFD8000A8655C /* WatchExtension.swift */; };
4EE6CF4929B6C1A000AEE1B4 /* StaticFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EE6CF4829B6C1A000AEE1B4 /* StaticFramework.h */; settings = {ATTRIBUTES = (Public, ); }; };
4EE6CF5329B6C1AF00AEE1B4 /* StaticFrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE6CF5229B6C1AF00AEE1B4 /* StaticFrameworkFile.swift */; };
/* End PBXBuildFile section */
@@ -28,6 +30,13 @@
remoteGlobalIDString = 36201A262843B3D3002FF70F;
remoteInfo = MixedTarget;
};
4E10D63729BBFD8E00A8655C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36201A042843B3C3002FF70F /* Project object */;
proxyType = 1;
remoteGlobalIDString = 4EE6CF4529B6C1A000AEE1B4;
remoteInfo = StaticFramework;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -67,9 +76,10 @@
36201A302843B414002FF70F /* SomeObjC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SomeObjC.h; sourceTree = "<group>"; };
36201A372843BDDC002FF70F /* StandaloneObjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StandaloneObjc.h; sourceTree = "<group>"; };
36201A382843BDDC002FF70F /* StandaloneObjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StandaloneObjc.m; sourceTree = "<group>"; };
4E628CA229B8066500AF2DB0 /* SandaloneWatchAppExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SandaloneWatchAppExtension.swift; sourceTree = "<group>"; };
4E628CA429B8066500AF2DB0 /* SandaloneWatchApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SandaloneWatchApp.swift; sourceTree = "<group>"; };
4E628CA629B8066500AF2DB0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4E10D62D29BBFD8000A8655C /* WatchExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.extensionkit-extension"; includeInIndex = 0; path = WatchExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
4E10D62F29BBFD8000A8655C /* WatchExtensionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchExtensionExtension.swift; sourceTree = "<group>"; };
4E10D63129BBFD8000A8655C /* WatchExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchExtension.swift; sourceTree = "<group>"; };
4E10D63329BBFD8000A8655C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4EE6CF4629B6C1A000AEE1B4 /* StaticFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = StaticFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4EE6CF4829B6C1A000AEE1B4 /* StaticFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StaticFramework.h; sourceTree = "<group>"; };
4EE6CF5229B6C1AF00AEE1B4 /* StaticFrameworkFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticFrameworkFile.swift; sourceTree = "<group>"; };
@@ -91,6 +101,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4E10D62A29BBFD8000A8655C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
4EE6CF4329B6C1A000AEE1B4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -107,7 +124,7 @@
36201A0E2843B3C3002FF70F /* StandaloneApp */,
36201A282843B3D3002FF70F /* MixedTarget */,
4EE6CF4729B6C1A000AEE1B4 /* StaticFramework */,
4E628CA129B8066500AF2DB0 /* SandaloneWatchApp */,
4E10D62E29BBFD8000A8655C /* WatchExtension */,
36201A0D2843B3C3002FF70F /* Products */,
36201A352843B435002FF70F /* Frameworks */,
);
@@ -119,6 +136,7 @@
36201A0C2843B3C3002FF70F /* StandaloneApp.app */,
36201A272843B3D3002FF70F /* libMixedTarget.a */,
4EE6CF4629B6C1A000AEE1B4 /* StaticFramework.framework */,
4E10D62D29BBFD8000A8655C /* WatchExtension.appex */,
);
name = Products;
sourceTree = "<group>";
@@ -156,14 +174,14 @@
name = Frameworks;
sourceTree = "<group>";
};
4E628CA129B8066500AF2DB0 /* SandaloneWatchApp */ = {
4E10D62E29BBFD8000A8655C /* WatchExtension */ = {
isa = PBXGroup;
children = (
4E628CA229B8066500AF2DB0 /* SandaloneWatchAppExtension.swift */,
4E628CA429B8066500AF2DB0 /* SandaloneWatchApp.swift */,
4E628CA629B8066500AF2DB0 /* Info.plist */,
4E10D62F29BBFD8000A8655C /* WatchExtensionExtension.swift */,
4E10D63129BBFD8000A8655C /* WatchExtension.swift */,
4E10D63329BBFD8000A8655C /* Info.plist */,
);
path = SandaloneWatchApp;
path = WatchExtension;
sourceTree = "<group>";
};
4EE6CF4729B6C1A000AEE1B4 /* StaticFramework */ = {
@@ -226,6 +244,24 @@
productReference = 36201A272843B3D3002FF70F /* libMixedTarget.a */;
productType = "com.apple.product-type.library.static";
};
4E10D62C29BBFD8000A8655C /* WatchExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4E10D63429BBFD8000A8655C /* Build configuration list for PBXNativeTarget "WatchExtension" */;
buildPhases = (
4E10D62929BBFD8000A8655C /* Sources */,
4E10D62A29BBFD8000A8655C /* Frameworks */,
4E10D62B29BBFD8000A8655C /* Resources */,
);
buildRules = (
);
dependencies = (
4E10D63829BBFD8E00A8655C /* PBXTargetDependency */,
);
name = WatchExtension;
productName = WatchExtension;
productReference = 4E10D62D29BBFD8000A8655C /* WatchExtension.appex */;
productType = "com.apple.product-type.extensionkit-extension";
};
4EE6CF4529B6C1A000AEE1B4 /* StaticFramework */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4EE6CF5129B6C1A000AEE1B4 /* Build configuration list for PBXNativeTarget "StaticFramework" */;
@@ -262,6 +298,9 @@
CreatedOnToolsVersion = 13.2.1;
LastSwiftMigration = 1320;
};
4E10D62C29BBFD8000A8655C = {
CreatedOnToolsVersion = 14.2;
};
4EE6CF4529B6C1A000AEE1B4 = {
CreatedOnToolsVersion = 14.2;
LastSwiftMigration = 1420;
@@ -284,6 +323,7 @@
36201A0B2843B3C3002FF70F /* StandaloneApp */,
36201A262843B3D3002FF70F /* MixedTarget */,
4EE6CF4529B6C1A000AEE1B4 /* StaticFramework */,
4E10D62C29BBFD8000A8655C /* WatchExtension */,
);
};
/* End PBXProject section */
@@ -299,6 +339,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4E10D62B29BBFD8000A8655C /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
4EE6CF4429B6C1A000AEE1B4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -353,6 +400,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4E10D62929BBFD8000A8655C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4E10D63029BBFD8000A8655C /* WatchExtensionExtension.swift in Sources */,
4E10D63229BBFD8000A8655C /* WatchExtension.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4EE6CF4229B6C1A000AEE1B4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -369,6 +425,11 @@
target = 36201A262843B3D3002FF70F /* MixedTarget */;
targetProxy = 36201A332843B431002FF70F /* PBXContainerItemProxy */;
};
4E10D63829BBFD8E00A8655C /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 4EE6CF4529B6C1A000AEE1B4 /* StaticFramework */;
targetProxy = 4E10D63729BBFD8E00A8655C /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -607,6 +668,62 @@
};
name = Release;
};
4E10D63529BBFD8000A8655C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WatchExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = WatchExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
"@executable_path/../../../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.xcremotecache.WatchExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Debug;
};
4E10D63629BBFD8000A8655C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WatchExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = WatchExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
"@executable_path/../../../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.xcremotecache.WatchExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Release;
};
4EE6CF4F29B6C1A000AEE1B4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -710,6 +827,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4E10D63429BBFD8000A8655C /* Build configuration list for PBXNativeTarget "WatchExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4E10D63529BBFD8000A8655C /* Debug */,
4E10D63629BBFD8000A8655C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4EE6CF5129B6C1A000AEE1B4 /* Build configuration list for PBXNativeTarget "StaticFramework" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1420"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4E10D61129BBF2FA00A8655C"
BuildableName = "SampleWatchApp.app"
BlueprintName = "SampleWatchApp"
ReferencedContainer = "container:StandaloneApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4E10D61129BBF2FA00A8655C"
BuildableName = "SampleWatchApp.app"
BlueprintName = "SampleWatchApp"
ReferencedContainer = "container:StandaloneApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4E10D61129BBF2FA00A8655C"
BuildableName = "SampleWatchApp.app"
BlueprintName = "SampleWatchApp"
ReferencedContainer = "container:StandaloneApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4E10D61129BBF2FA00A8655C"
BuildableName = "SampleWatchApp.app"
BlueprintName = "SampleWatchApp"
ReferencedContainer = "container:StandaloneApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EXAppExtensionAttributes</key>
<dict>
<key>EXExtensionPointIdentifier</key>
<string>com.apple.appintents-extension</string>
</dict>
</dict>
</plist>
@@ -0,0 +1,2 @@
import AppIntents
@@ -0,0 +1,4 @@
import AppIntents
struct WatchExtensionExtension: AppIntentsExtension {
}
+3 -3
View File
@@ -58,7 +58,7 @@ namespace :e2e do
system("pwd")
system("#{XCRC_BINARIES}/xcprepare integrate --input StandaloneApp.xcodeproj --mode producer --final-producer-target StandaloneApp")
# Build the project to fill in the cache
build_project(nil, "StandaloneApp.xcodeproj", 'StaticFramework', 'watch', 'watchOS')
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS')
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp')
system("#{XCRC_BINARIES}/xcprepare stats --reset --format json")
end
@@ -74,14 +74,14 @@ namespace :e2e do
prepare_for_standalone(consumer_srcroot)
Dir.chdir(consumer_srcroot) do
system("#{XCRC_BINARIES}/xcprepare integrate --input StandaloneApp.xcodeproj --mode consumer")
build_project(nil, "StandaloneApp.xcodeproj", 'StaticFramework', 'watch', 'watchOS', {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer"})
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer"})
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer"})
valide_hit_rate
puts 'Building standalone consumer with local change...'
# Extra: validate local compilation of the Standalone ObjC code
system("echo '' >> StandaloneApp/StandaloneObjc.m")
build_project(nil, "StandaloneApp.xcodeproj", 'StaticFramework', 'watch', 'watchOS', {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local"})
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local"})
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local"})
end