Skip to content

Commit

Permalink
Re-implement dSYM copying and stripping to the pod target itself.
Browse files Browse the repository at this point in the history
  • Loading branch information
dnkoutso committed Feb 20, 2020
1 parent 907d559 commit 028e1bb
Show file tree
Hide file tree
Showing 12 changed files with 405 additions and 334 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre`

##### Bug Fixes

* Re-implement `dSYM` copying and stripping to avoid duplicate parsing.
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#9185](https://github.com/CocoaPods/CocoaPods/issues/9185)

* Also apply Xcode 11 `XCTUnwrap` fix to library and framework targets that weakly link `XCTest`.
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#9518](https://github.com/CocoaPods/CocoaPods/pull/9518)
Expand Down
1 change: 1 addition & 0 deletions lib/cocoapods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ module Generator
autoload :Constant, 'cocoapods/generator/constant'
autoload :CopyResourcesScript, 'cocoapods/generator/copy_resources_script'
autoload :DummySource, 'cocoapods/generator/dummy_source'
autoload :ScriptPhaseConstants, 'cocoapods/generator/script_phase_constants'
autoload :EmbedFrameworksScript, 'cocoapods/generator/embed_frameworks_script'
autoload :PrepareArtifactsScript, 'cocoapods/generator/prepare_artifacts_script'
autoload :FileList, 'cocoapods/generator/file_list'
Expand Down
14 changes: 2 additions & 12 deletions lib/cocoapods/generator/copy_resources_script.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,7 @@ def script
end

INSTALL_RESOURCES_FUNCTION = <<EOS
#!/bin/sh
set -e
set -u
set -o pipefail
function on_error {
echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
}
trap 'on_error $LINENO' ERR
#{Pod::Generator::ScriptPhaseConstants::DEFAULT_SCRIPT_PHASE_HEADER}
if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
# If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
Expand All @@ -123,9 +115,7 @@ def script
XCASSET_FILES=()
# This protects against multiple targets copying the same framework dependency at the same time. The solution
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
#{Pod::Generator::ScriptPhaseConstants::RSYNC_PROTECT_TMP_FILES}
case "${TARGETED_DEVICE_FAMILY:-}" in
1,2)
Expand Down
316 changes: 122 additions & 194 deletions lib/cocoapods/generator/embed_frameworks_script.rb

Large diffs are not rendered by default.

204 changes: 97 additions & 107 deletions lib/cocoapods/generator/prepare_artifacts_script.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,113 +59,103 @@ def generate
#
def script
script = <<-SH.strip_heredoc
#!/bin/sh
set -e
set -u
set -o pipefail
function on_error {
echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
}
trap 'on_error $LINENO' ERR
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
# frameworks to, so exit 0 (signalling the script phase was successful).
exit 0
fi
# This protects against multiple targets copying the same framework dependency at the same time. The solution
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
ARTIFACT_LIST_FILE="${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt"
cat > $ARTIFACT_LIST_FILE
BCSYMBOLMAP_DIR="BCSymbolMaps"
record_artifact()
{
echo "$1" >> $ARTIFACT_LIST_FILE
}
install_artifact()
{
local source="$1"
local destination="$2"
local record=${3:-false}
# Use filter instead of exclude so missing patterns don't throw errors.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \\"- CVS/\\" --filter \\"- .svn/\\" --filter \\"- .git/\\" --filter \\"- .hg/\\" \\"${source}\\" \\"${destination}\\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" "${source}" "${destination}"
if [[ "$record" == "true" ]]; then
artifact="${destination}/$(basename "$source")"
record_artifact "$artifact"
fi
}
# Copies a framework to derived data for use in later build phases
install_framework()
{
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
local source="${BUILT_PRODUCTS_DIR}/$1"
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
elif [ -r "$1" ]; then
local source="$1"
fi
local record_artifact=${2:-true}
local destination="${CONFIGURATION_BUILD_DIR}"
if [ -L "${source}" ]; then
echo "Symlinked..."
source="$(readlink "${source}")"
fi
install_artifact "$source" "$destination" "$record_artifact"
if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
# Locate and install any .bcsymbolmaps if present
find "${source}/${BCSYMBOLMAP_DIR}/" -name "*.bcsymbolmap"|while read f; do
install_artifact "$f" "$destination" "true"
done
fi
}
install_xcframework() {
local basepath="$1"
local embed="$2"
shift
local paths=("$@")
# Locate the correct slice of the .xcframework for the current architectures
local target_path=""
local target_arch="$ARCHS"
local target_variant=""
if [[ "$PLATFORM_NAME" == *"simulator" ]]; then
target_variant="simulator"
fi
if [[ "$EFFECTIVE_PLATFORM_NAME" == *"maccatalyst" ]]; then
target_variant="maccatalyst"
fi
for i in ${!paths[@]}; do
if [[ "${paths[$i]}" == *"$target_arch"* ]] && [[ "${paths[$i]}" == *"$target_variant"* ]]; then
# Found a matching slice
echo "Selected xcframework slice ${paths[$i]}"
target_path=${paths[$i]}
break;
fi
done
if [[ -z "$target_path" ]]; then
echo "warning: [CP] Unable to find matching .xcframework slice in '${paths[@]}' for the current build architectures ($ARCHS)."
return
fi
install_framework "$basepath/$target_path" "$embed"
}
#{Pod::Generator::ScriptPhaseConstants::DEFAULT_SCRIPT_PHASE_HEADER}
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
# frameworks to, so exit 0 (signalling the script phase was successful).
exit 0
fi
#{Pod::Generator::ScriptPhaseConstants::RSYNC_PROTECT_TMP_FILES}
ARTIFACT_LIST_FILE="${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt"
cat > $ARTIFACT_LIST_FILE
BCSYMBOLMAP_DIR="BCSymbolMaps"
record_artifact()
{
echo "$1" >> $ARTIFACT_LIST_FILE
}
install_artifact()
{
local source="$1"
local destination="$2"
local record=${3:-false}
# Use filter instead of exclude so missing patterns don't throw errors.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \\"- CVS/\\" --filter \\"- .svn/\\" --filter \\"- .git/\\" --filter \\"- .hg/\\" \\"${source}\\" \\"${destination}\\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" "${source}" "${destination}"
if [[ "$record" == "true" ]]; then
artifact="${destination}/$(basename "$source")"
record_artifact "$artifact"
fi
}
# Copies a framework to derived data for use in later build phases
install_framework()
{
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
local source="${BUILT_PRODUCTS_DIR}/$1"
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
elif [ -r "$1" ]; then
local source="$1"
fi
local record_artifact=${2:-true}
local destination="${CONFIGURATION_BUILD_DIR}"
if [ -L "${source}" ]; then
echo "Symlinked..."
source="$(readlink "${source}")"
fi
install_artifact "$source" "$destination" "$record_artifact"
if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
# Locate and install any .bcsymbolmaps if present
find "${source}/${BCSYMBOLMAP_DIR}/" -name "*.bcsymbolmap"|while read f; do
install_artifact "$f" "$destination" "true"
done
fi
}
install_xcframework() {
local basepath="$1"
local embed="$2"
shift
local paths=("$@")
# Locate the correct slice of the .xcframework for the current architectures
local target_path=""
local target_arch="$ARCHS"
local target_variant=""
if [[ "$PLATFORM_NAME" == *"simulator" ]]; then
target_variant="simulator"
fi
if [[ "$EFFECTIVE_PLATFORM_NAME" == *"maccatalyst" ]]; then
target_variant="maccatalyst"
fi
for i in ${!paths[@]}; do
if [[ "${paths[$i]}" == *"$target_arch"* ]] && [[ "${paths[$i]}" == *"$target_variant"* ]]; then
# Found a matching slice
echo "Selected xcframework slice ${paths[$i]}"
target_path=${paths[$i]}
break;
fi
done
if [[ -z "$target_path" ]]; then
echo "warning: [CP] Unable to find matching .xcframework slice in '${paths[@]}' for the current build architectures ($ARCHS)."
return
fi
install_framework "$basepath/$target_path" "$embed"
}
SH
contents_by_config = Hash.new do |hash, key|
Expand Down
55 changes: 55 additions & 0 deletions lib/cocoapods/generator/script_phase_constants.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module Pod
module Generator
module ScriptPhaseConstants
DEFAULT_SCRIPT_PHASE_HEADER = <<-SH.strip_heredoc.freeze
#!/bin/sh
set -e
set -u
set -o pipefail
function on_error {
echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
}
trap 'on_error $LINENO' ERR
SH

RSYNC_PROTECT_TMP_FILES = <<-SH.strip_heredoc.freeze
# This protects against multiple targets copying the same framework dependency at the same time. The solution
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")aa
SH

STRIP_INVALID_ARCHITECTURES_METHOD = <<-SH.strip_heredoc.freeze
# Used as a return value for each invocation of `strip_invalid_archs` function.
STRIP_BINARY_RETVAL=0
# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
# Get architectures for current target binary
binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
# Intersect them with the architectures we are building for
intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\\n' | sort | uniq -d)"
# If there are no archs supported by this binary then warn the user
if [[ -z "$intersected_archs" ]]; then
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
STRIP_BINARY_RETVAL=1
return
fi
stripped=""
for arch in $binary_archs; do
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary"
stripped="$stripped $arch"
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
STRIP_BINARY_RETVAL=0
}
SH
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class TargetIntegrator
#
COPY_PODS_RESOURCES_PHASE_NAME = 'Copy Pods Resources'.freeze

# @return [String] the name of the copy dSYM files phase
#
COPY_DSYM_FILES_PHASE_NAME = 'Copy dSYMs'.freeze

# @return [Integer] the maximum number of input and output paths to use for a script phase
#
MAX_INPUT_OUTPUT_PATHS = 1000
Expand Down Expand Up @@ -239,7 +243,7 @@ def remove_copy_resources_script_phase_from_target(native_target)
# The value to set for show environment variables in the log during execution of this script phase or
# `nil` for not setting the value at all.
#
# @return [void]
# @return [PBXShellScriptBuildPhase] The exixting or newly created shell script build phase.
#
def create_or_update_shell_script_build_phase(native_target, script_phase_name, show_env_vars_in_log = '0')
build_phases = native_target.build_phases.grep(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
Expand All @@ -263,7 +267,9 @@ def create_or_update_shell_script_build_phase(native_target, script_phase_name,
def create_or_update_user_script_phases(script_phases, native_target)
script_phase_names = script_phases.map { |k| k[:name] }
# Delete script phases no longer present in the target.
native_target_script_phases = native_target.shell_script_build_phases.select { |bp| !bp.name.nil? && bp.name.start_with?(USER_BUILD_PHASE_PREFIX) }
native_target_script_phases = native_target.shell_script_build_phases.select do |bp|
!bp.name.nil? && bp.name.start_with?(USER_BUILD_PHASE_PREFIX)
end
native_target_script_phases.each do |script_phase|
script_phase_name_without_prefix = script_phase.name.sub(USER_BUILD_PHASE_PREFIX, '')
unless script_phase_names.include?(script_phase_name_without_prefix)
Expand Down Expand Up @@ -375,15 +381,12 @@ def resource_output_paths(resource_input_paths)
def framework_output_paths(framework_input_paths)
framework_input_paths.flat_map do |framework_path|
framework_output_path = "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/#{File.basename(framework_path.source_path)}"
dsym_output_path = if (dsym_input_path = framework_path.dsym_path)
"${DWARF_DSYM_FOLDER_PATH}/#{File.basename(dsym_input_path)}"
end
bcsymbol_output_paths = unless framework_path.bcsymbolmap_paths.nil?
framework_path.bcsymbolmap_paths.map do |bcsymbolmap_path|
"${BUILT_PRODUCTS_DIR}/#{File.basename(bcsymbolmap_path)}"
end
end
[framework_output_path, dsym_output_path, *bcsymbol_output_paths]
[framework_output_path, *bcsymbol_output_paths]
end.compact.uniq
end
end
Expand Down Expand Up @@ -520,7 +523,7 @@ def add_embed_frameworks_script_phase
input_paths = input_paths_by_config[input_paths_key] = [script_path]
input_paths << ARTIFACT_LIST_FILE if target.includes_xcframeworks?
framework_paths.each do |path|
input_paths.concat(path.all_paths)
input_paths.concat([path.source_path, path.bcsymbolmap_paths].flatten.compact)
end

output_paths_key = XCFileListConfigKey.new(target.embed_frameworks_script_output_files_path(config), target.embed_frameworks_script_output_files_relative_path)
Expand Down
4 changes: 2 additions & 2 deletions lib/cocoapods/installer/xcode/pods_project_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,10 @@ def install_aggregate_targets(project, aggregate_targets)
#
def integrate_targets(pod_target_installation_results)
pod_installations_to_integrate = pod_target_installation_results.values.select do |pod_target_installation_result|
pod_target = pod_target_installation_result.target
!pod_target_installation_result.test_native_targets.empty? ||
!pod_target_installation_result.app_native_targets.empty? ||
pod_target.contains_script_phases?
pod_target_installation_result.target.contains_script_phases? ||
pod_target_installation_result.target.framework_paths.values.flatten.any? { |paths| !paths.dsym_path.nil? }
end
return if pod_installations_to_integrate.empty?

Expand Down
Loading

0 comments on commit 028e1bb

Please sign in to comment.