Skip to content

Commit

Permalink
Improve dSYM handling for XCFrameworks
Browse files Browse the repository at this point in the history
Changes:
- Ensure all dSYMs are archived, not only files that match the naming scheme of framework slices
- Correctly handle dSYM files that do not have the extension `.framework.dSYM`
- Ensure dSYMS are stored in the correct directory when archiving
  • Loading branch information
amorde committed Feb 17, 2020
1 parent 800e021 commit 139aa10
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 33 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -15,6 +15,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
* 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)

* Fix dSYM handling for XCFrameworks.
[Eric Amorde](https://github.com/amorde)
[#9530](https://github.com/CocoaPods/CocoaPods/issues/9530)


## 1.9.0.beta.3 (2020-02-04)
Expand Down
34 changes: 26 additions & 8 deletions lib/cocoapods/generator/embed_frameworks_script.rb
Expand Up @@ -129,27 +129,29 @@ def script
# Copies and strips a vendored dSYM
install_dsym() {
local source="$1"
warn_missing_arch=${2:-true}
if [ -r "$source" ]; then
# Copy the dSYM into a the targets temp dir.
# Copy the dSYM into the targets temp dir.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \\"- CVS/\\" --filter \\"- .svn/\\" --filter \\"- .git/\\" --filter \\"- .hg/\\" --filter \\"- Headers\\" --filter \\"- PrivateHeaders\\" --filter \\"- Modules\\" \\"${source}\\" \\"${DERIVED_FILES_DIR}\\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
local basename
basename="$(basename -s .framework.dSYM "$source")"
binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
basename="$(basename -s .dSYM "$source")"
binary_name="$(ls "$source/Contents/Resources/DWARF")"
binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
strip_invalid_archs "$binary"
strip_invalid_archs "$binary" "$warn_missing_arch"
fi
if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
# Move the stripped file into its final destination.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \\"- CVS/\\" --filter \\"- .svn/\\" --filter \\"- .git/\\" --filter \\"- .hg/\\" --filter \\"- Headers\\" --filter \\"- PrivateHeaders\\" --filter \\"- Modules\\" \\"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\\" \\"${DWARF_DSYM_FOLDER_PATH}\\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
else
# The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
fi
fi
}
Expand Down Expand Up @@ -180,13 +182,16 @@ def script
# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
warn_missing_arch=${2:-true}
# 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)."
if [[ "$warn_missing_arch" == "true" ]]; then
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
fi
STRIP_BINARY_RETVAL=0
return
fi
Expand All @@ -212,7 +217,8 @@ def script
install_framework "$artifact"
;;
*.dSYM)
install_dsym "$artifact"
# Suppress arch warnings since XCFrameworks will included many dSYM files
install_dsym "$artifact" "false"
;;
*.bcsymbolmap)
install_bcsymbolmap "$artifact"
Expand Down Expand Up @@ -259,6 +265,18 @@ def script
SH
script
end

# @param [Xcode::FrameworkPaths] framework_path
# the framework path containing the dSYM
#
# @return [String, Nil] the name of the dSYM binary, if found
#
def dsym_binary_name(framework_path)
return nil if framework_path.dsym_path.nil?
if (path = Pathname.glob(framework_path.dsym_path.join('Contents/Resources/DWARF', '**/*')).first)
File.basename(path)
end
end
end
end
end
37 changes: 26 additions & 11 deletions lib/cocoapods/generator/prepare_artifacts_script.rb
Expand Up @@ -136,7 +136,8 @@ def script
install_xcframework() {
local basepath="$1"
local embed="$2"
local dsym_folder="$2"
local embed="$3"
shift
local paths=("$@")
Expand Down Expand Up @@ -165,6 +166,17 @@ def script
fi
install_framework "$basepath/$target_path" "$embed"
if [[ -z "$dsym_folder" || ! -d "$dsym_folder" ]]; then
return
fi
dsyms=($(ls "$dsym_folder"))
local target_dsym=""
for i in ${!dsyms[@]}; do
install_artifact "$dsym_folder/${dsyms[$i]}" "$CONFIGURATION_BUILD_DIR" "true"
done
}
SH
Expand All @@ -187,11 +199,11 @@ def script
contents_by_config[config] << %( install_xcframework #{args}\n)
end

dsyms = PrepareArtifactsScript.dsym_paths(xcframework.path)
dsyms.each do |path|
source = shell_escape("${PODS_ROOT}/#{path.relative_path_from(sandbox_root)}")
contents_by_config[config] << %( install_artifact #{source} "${TARGET_BUILD_DIR}" "true"\n)
end
# dsyms = PrepareArtifactsScript.dsym_paths(xcframework.path)
# dsyms.each do |path|
# source = shell_escape("${PODS_ROOT}/#{path.relative_path_from(sandbox_root)}")
# contents_by_config[config] << %( install_artifact #{source} "${TARGET_BUILD_DIR}" "true"\n)
# end
end
end

Expand All @@ -215,6 +227,12 @@ def shell_escape(value)

def install_xcframework_args(root, slices, static)
args = [shell_escape("${PODS_ROOT}/#{root.relative_path_from(sandbox_root)}")]
if (dsym_folder = PrepareArtifactsScript.dsym_folder(root))
dsym_folder_arg = shell_escape("${PODS_ROOT}/#{dsym_folder.relative_path_from(sandbox_root)}")
else
dsym_folder_arg = '""'
end
args << dsym_folder_arg
embed = static ? 'false' : 'true'
args << shell_escape(embed)
slices.each do |slice|
Expand All @@ -229,14 +247,11 @@ class << self
#
# @return [Array<Pathname>] all found .dSYM paths
#
def dsym_paths(xcframework_path)
def dsym_folder(xcframework_path)
basename = File.basename(xcframework_path, '.xcframework')
dsym_basename = basename + '.dSYMs'
path = xcframework_path.dirname + dsym_basename
return [] unless File.directory?(path)

pattern = path + '*.dSYM'
Dir.glob(pattern).map { |s| Pathname.new(s) }
Pathname.new(path) if File.directory?(path)
end
end
end
Expand Down
24 changes: 10 additions & 14 deletions spec/unit/generator/prepare_artifacts_script_spec.rb
Expand Up @@ -7,7 +7,7 @@ module Pod
generator = PrepareArtifactsScript.new({ 'Debug' => [xcframework] }, temporary_sandbox.root, Platform.ios)
generator.send(:script).should.include <<-SH.strip_heredoc
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "true" "ios-armv7_arm64/CoconutLib.framework" "ios-i386_x86_64-simulator/CoconutLib.framework"
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "" "true" "ios-armv7_arm64/CoconutLib.framework" "ios-i386_x86_64-simulator/CoconutLib.framework"
fi
SH
end
Expand All @@ -17,25 +17,25 @@ module Pod
generator = PrepareArtifactsScript.new({ 'Debug' => [xcframework] }, temporary_sandbox.root, Platform.macos)
generator.send(:script).should.include <<-SH.strip_heredoc
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "true" "macos-x86_64/CoconutLib.framework"
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "" "true" "macos-x86_64/CoconutLib.framework"
fi
SH
generator = PrepareArtifactsScript.new({ 'Debug' => [xcframework] }, temporary_sandbox.root, Platform.ios)
generator.send(:script).should.include <<-SH.strip_heredoc
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "true" "ios-armv7_arm64/CoconutLib.framework" "ios-i386_x86_64-simulator/CoconutLib.framework"
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "" "true" "ios-armv7_arm64/CoconutLib.framework" "ios-i386_x86_64-simulator/CoconutLib.framework"
fi
SH
generator = PrepareArtifactsScript.new({ 'Debug' => [xcframework] }, temporary_sandbox.root, Platform.watchos)
generator.send(:script).should.include <<-SH.strip_heredoc
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "true" "watchos-i386-simulator/CoconutLib.framework" "watchos-armv7k_arm64_32/CoconutLib.framework"
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "" "true" "watchos-i386-simulator/CoconutLib.framework" "watchos-armv7k_arm64_32/CoconutLib.framework"
fi
SH
generator = PrepareArtifactsScript.new({ 'Debug' => [xcframework] }, temporary_sandbox.root, Platform.tvos)
generator.send(:script).should.include <<-SH.strip_heredoc
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "true" "tvos-x86_64-simulator/CoconutLib.framework" "tvos-arm64/CoconutLib.framework"
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "" "true" "tvos-x86_64-simulator/CoconutLib.framework" "tvos-arm64/CoconutLib.framework"
fi
SH
end
Expand All @@ -47,25 +47,21 @@ module Pod
# Second argument to `install_xcframework` is a boolean indicating whether to embed the framework
generator.send(:script).should.include <<-SH.strip_heredoc
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "false" "ios-armv7_arm64/CoconutLib.framework" "ios-i386_x86_64-simulator/CoconutLib.framework"
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "" "false" "ios-armv7_arm64/CoconutLib.framework" "ios-i386_x86_64-simulator/CoconutLib.framework"
fi
SH
end

it 'installs dSYMs if found' do
xcframework = Xcode::XCFramework.new(fixture('CoconutLib.xcframework'))
dsym_path = xcframework.path.dirname + 'CoconutLib.dSYMs'
PrepareArtifactsScript.stubs(:dsym_paths).returns([
dsym_path + 'A.dSYM',
dsym_path + 'B.dSYM',
])
PrepareArtifactsScript.stubs(:dsym_folder).returns(dsym_path)
generator = PrepareArtifactsScript.new({ 'Debug' => [xcframework] }, temporary_sandbox.root, Platform.ios)
results = generator.generate
results.should.include <<-SH.strip_heredoc
install_artifact "${PODS_ROOT}/../../spec/fixtures/CoconutLib.dSYMs/A.dSYM" "${TARGET_BUILD_DIR}" "true"
SH
results.should.include <<-SH.strip_heredoc
install_artifact "${PODS_ROOT}/../../spec/fixtures/CoconutLib.dSYMs/B.dSYM" "${TARGET_BUILD_DIR}" "true"
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_xcframework "${PODS_ROOT}/../../spec/fixtures/CoconutLib.xcframework" "${PODS_ROOT}/../../spec/fixtures/CoconutLib.dSYMs" "true" "ios-armv7_arm64/CoconutLib.framework" "ios-i386_x86_64-simulator/CoconutLib.framework"
fi
SH
end
end
Expand Down

0 comments on commit 139aa10

Please sign in to comment.