Skip to content

Commit 12850c2

Browse files
chrfalchmeta-codesync[bot]
authored andcommitted
add building blocks to symbolicate precompiled React.xcframework (facebook#54032)
Summary: Pull Request resolved: facebook#54032 This commit adds building blocks to support the symbolication of the XCFrameworks on request. Symbol files are big and only needed if you need to debug React Native itself - f.ex. if you are a framework developer like Expo. This change introduces some helper function that are needed to handle the dSYMS: - `processDSYMs` the main function that unzip the symbols and prepare the framework for them - `remap_sourcemaps_for_symbols` a support function that creates a mapping symbol -> file so that the debug can interpret them properly - `generate_plist_content` a support function that generates the plist with all the mappings These functions are used in the next commit of the stack. ## Changelog: [Internal] - Added building blocks to support symbolication Test Plan: These functions are used in the next commit. We split the commit to simplify the review. See the Test plan of the next commit to test them. Reviewed By: cortinico Differential Revision: D83753189 Pulled By: cipolleschi fbshipit-source-id: 5d8027f5393a4e5a11f1b736c9901d40e7c5139b
1 parent 0a71b43 commit 12850c2

File tree

1 file changed

+148
-1
lines changed
  • packages/react-native/scripts/cocoapods

1 file changed

+148
-1
lines changed

packages/react-native/scripts/cocoapods/rncore.rb

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,161 @@ def self.podspec_source_download_prebuild_stable_tarball()
120120
if @@build_from_source
121121
return
122122
end
123-
124123
url = stable_tarball_url(@@react_native_version, :debug)
125124
rncore_log("Using tarball from URL: #{url}")
126125
download_stable_rncore(@@react_native_path, @@react_native_version, :debug)
127126
download_stable_rncore(@@react_native_path, @@react_native_version, :release)
128127
return {:http => url}
129128
end
130129

130+
def self.process_dsyms(frameworkTarball, dSymsTarball)
131+
if !@@download_dsyms
132+
return
133+
end
134+
135+
if @@react_native_path == ""
136+
rncore_log("react_native_path is not set", :error)
137+
return
138+
end
139+
140+
if @@react_native_version == ""
141+
rncore_log("react_native_version is not set", :error)
142+
return
143+
end
144+
145+
if @@build_from_source
146+
return
147+
end
148+
149+
# gunzip the dSymsTarball and the frameworkTarball into a temporary folder
150+
# and then copy the dSYMs into the framework folder and then tar/gz the framework folder again
151+
# into the same location as the original frameworkTarball
152+
153+
rncore_log("Adding symbols #{Pathname.new(dSymsTarball).relative_path_from(Pathname.pwd).to_s} to framework tarball #{Pathname.new(frameworkTarball).relative_path_from(Pathname.pwd).to_s}")
154+
155+
FileUtils.mkdir_p(File.dirname(frameworkTarball))
156+
FileUtils.cp(frameworkTarball, "#{frameworkTarball}.orig")
157+
158+
rncore_log(" Backed up original tarballs")
159+
160+
begin
161+
# Now let's gunzip the framework tarball into a .tar file
162+
# Get filename and foldername from the tarball path
163+
frameworkFolder = File.dirname(frameworkTarball)
164+
frameworkFilename = File.basename(frameworkTarball, ".tar.gz")
165+
frameworkTarPath = File.join(frameworkFolder, frameworkFilename + ".tar")
166+
167+
# Now gunzip the tarball into the frameworkFolder - this will remove the .gz file and leave us with a .tar file
168+
rncore_log(" Unpacking framework tarball")
169+
`gunzip "#{frameworkTarball}"`
170+
171+
# Now let's untar the dSyms tarball into a temporary folder / dSYMs subfolder
172+
dsyms_tmp_dir = "#{artifacts_dir}/dSYMs"
173+
rncore_log(" Unpacking dSYMs to temporary folder")
174+
`mkdir -p "#{dsyms_tmp_dir}" && tar -xzf "#{dSymsTarball}" -C "#{dsyms_tmp_dir}"`
175+
176+
# Now we need to remap the symbol files to be relative to the framework folder
177+
remap_sourcemaps_for_symbols(dsyms_tmp_dir)
178+
179+
# Add the dSYMs folder to the framework folder
180+
rncore_log(" Adding dSYMs to framework tarball")
181+
`(cd "$(dirname "#{dsyms_tmp_dir}")" && mkdir -p React.xcframework && cp -r "$(basename "#{dsyms_tmp_dir}")" React.xcframework/dSYMs && tar -rf "#{frameworkTarPath}" React.xcframework/dSYMs && rm -rf React.xcframework)`
182+
183+
# Now gzip the framework tarball again - remember to use the .tar file and not the .gz file
184+
rncore_log(" Packing #{Pathname.new(frameworkTarPath).relative_path_from(Pathname.pwd).to_s}")
185+
`gzip -1 "#{frameworkTarPath}"`
186+
187+
# Clean up the temporary folder
188+
FileUtils.remove_entry(dsyms_tmp_dir)
189+
rncore_log(" Processed dSYMs into framework tarball #{Pathname.new(frameworkTarball).relative_path_from(Pathname.pwd).to_s}")
190+
191+
# Remove backup of original tarballs
192+
FileUtils.rm_f("#{frameworkTarball}.orig")
193+
194+
rescue => e
195+
rncore_log("Failed to process dSYMs: #{e.message}", :error)
196+
# Restore the original tarballs
197+
FileUtils.mv("#{frameworkTarball}.orig", frameworkTarball) if File.exist?("#{frameworkTarball}.orig")
198+
rncore_log("Restored original tarballs", :error)
199+
abort "Couldn't process dSYMs: #{e.message}"
200+
end
201+
end
202+
203+
def self.remap_sourcemaps_for_symbols(symbolsPath)
204+
rncore_log(" Remapping dSYMs to be relative to framework folder")
205+
206+
# Find all .dSYM bundles in the symbols path
207+
dsym_bundles = []
208+
Dir.glob(File.join(symbolsPath, "**", "*.dSYM")).each do |path|
209+
if File.directory?(path)
210+
# Check if it's a valid dSYM bundle with Info.plist
211+
info_plist = File.join(path, 'Contents', 'Info.plist')
212+
dsym_bundles << path if File.exist?(info_plist)
213+
end
214+
end
215+
216+
return if dsym_bundles.empty?
217+
218+
# Define source path mappings - from absolute build paths to relative framework paths
219+
mappings = [
220+
# Make sure to make react_native_path absolute
221+
["/Users/runner/work/react-native/react-native/packages/react-native", "#{File.expand_path(@@react_native_path)}"],
222+
]
223+
224+
dsym_bundles.each do |dsym_path| begin
225+
# Get UUIDs for this dSYM bundle
226+
uuid_output = `dwarfdump --uuid "#{dsym_path}" 2>/dev/null`
227+
uuids = uuid_output.scan(/UUID:\s+([0-9A-F-]{36})/i).flatten
228+
229+
next if uuids.empty?
230+
231+
# Create Resources directory if it doesn't exist
232+
resources_dir = File.join(dsym_path, 'Contents', 'Resources')
233+
FileUtils.mkdir_p(resources_dir)
234+
235+
# Generate plist content with path mappings
236+
plist_content = generate_plist_content(mappings)
237+
238+
# Write plist for each UUID
239+
uuids.each do |uuid|
240+
plist_path = File.join(resources_dir, "#{uuid}.plist")
241+
File.write(plist_path, plist_content)
242+
end
243+
244+
rescue => e
245+
rncore_log(" Failed to process dSYM #{dsym_path}: #{e.message}", :error)
246+
end
247+
end
248+
249+
rncore_log(" Completed dSYM remapping for #{dsym_bundles.length} bundles")
250+
end
251+
252+
def self.generate_plist_content(mappings)
253+
# Generate the source path remapping entries
254+
remapping_entries = mappings.map do |from, to|
255+
" <key>#{from}</key><string>#{to}</string>"
256+
end.join("\n")
257+
258+
# Use the first mapping for legacy keys
259+
first_from, first_to = mappings.first
260+
261+
return <<~PLIST
262+
<?xml version="1.0" encoding="UTF-8"?>
263+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
264+
<plist version="1.0">
265+
<dict>
266+
<key>DBGVersion</key><string>3</string>
267+
<key>DBGBuildSourcePath</key><string>#{first_from}</string>
268+
<key>DBGSourcePath</key><string>#{first_to}</string>
269+
<key>DBGSourcePathRemapping</key>
270+
<dict>
271+
#{remapping_entries}
272+
</dict>
273+
</dict>
274+
</plist>
275+
PLIST
276+
end
277+
131278
def self.stable_tarball_url(version, build_type)
132279
## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded.
133280
## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.

0 commit comments

Comments
 (0)