Improve handling of dSYM bundles
- Use `AppleBinaryInfo` to support `macos_command_line_application`
- Locate the dSYM bundle by the primary artifact path - they should be in the same folder (siblings). This allows us to avoid the reliance on `bazel-bin` which doesn't work depending on the configuration transition.
- Rename the bundle to be what Xcode expects it to be (vs. keeping the Bazel name)
PiperOrigin-RevId: 311542552
diff --git a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
index 3d0e35c..cf29804 100644
--- a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
+++ b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
@@ -20,6 +20,7 @@
load(
":tulsi/tulsi_aspects_paths.bzl",
+ "AppleBinaryInfo",
"AppleBundleInfo",
"AppleTestInfo",
"IosExtensionBundleInfo",
@@ -915,6 +916,17 @@
),
]
+def _bundle_dsym_path(apple_bundle):
+ """Compute the dSYM path for the bundle.
+
+ Due to b/110264170 dSYMs are not fully exposed via a provider. We instead
+ rely on the fact that `rules_apple` puts them next to the bundle just like
+ Xcode.
+ """
+ bin_path = apple_bundle.archive.dirname
+ dsym_name = apple_bundle.bundle_name + apple_bundle.bundle_extension + ".dSYM"
+ return bin_path + "/" + dsym_name
+
def _collect_bundle_info(target):
"""Returns Apple bundle info for the given target, None if not a bundle."""
if AppleBundleInfo in target:
@@ -922,6 +934,7 @@
has_dsym = (apple_common.AppleDebugOutputs in target)
return struct(
archive_root = apple_bundle.archive_root,
+ dsym_path = _bundle_dsym_path(apple_bundle),
bundle_name = apple_bundle.bundle_name,
bundle_extension = apple_bundle.bundle_extension,
has_dsym = has_dsym,
@@ -1038,6 +1051,7 @@
embedded_bundles = depset(direct_embedded_bundles, transitive = transitive_embedded_bundles)
artifact = None
+ dsym_path = None
bundle_name = None
archive_root = None
infoplist = None
@@ -1045,35 +1059,41 @@
bundle_info = target[AppleBundleInfo]
artifact = bundle_info.archive.path
+ dsym_path = _bundle_dsym_path(bundle_info)
archive_root = bundle_info.archive_root
infoplist = bundle_info.infoplist
bundle_name = bundle_info.bundle_name
- elif (target_kind == "macos_command_line_application" or
- target_kind == "cc_binary" or target_kind == "cc_test"):
- # Special support for macos_command_line_application and cc_* targets
- # which do not have an AppleBundleInfo provider.
-
- # Both the dSYM binary and executable binary don't have an extension, so
- # pick the first extension-less file not in a DWARF folder.
+ elif AppleBinaryInfo in target:
+ # Support for non-bundled binary targets such as
+ # `macos_command_line_application`. These still have dSYMs support and
+ # should be located next to the binary.
+ artifact = target[AppleBinaryInfo].binary.path
+ dsym_path = artifact + ".dSYM"
+ elif (target_kind == "cc_binary" or target_kind == "cc_test"):
+ # Special support for cc_* targets which do not have AppleBinaryInfo or
+ # AppleBundleInfo providers.
+ #
+ # At the moment these don't have support for dSYMs (b/124859331), but
+ # in case they do in the future we filter out the dSYM files.
artifacts = [
- x.path
+ x
for x in target.files.to_list()
if x.extension == "" and
"Contents/Resources/DWARF" not in x.path
]
if len(artifacts) > 0:
- artifact = artifacts[0]
+ artifact = artifacts[0].path
else:
# Special support for *_library targets, which Tulsi allows building at
# the top-level.
artifacts = [
- x.path
+ x
for x in target.files.to_list()
if x.extension == "a"
]
if len(artifacts) > 0:
- artifact = artifacts[0]
+ artifact = artifacts[0].path
# Collect generated files for bazel_build.py to copy under Tulsi root.
all_files_depsets = []
@@ -1109,15 +1129,12 @@
transitive = transitive_generated_files,
)
- has_dsym = False
- if hasattr(ctx.fragments, "objc"):
- # Check the fragment directly, as macos_command_line_application does not
- # propagate apple_common.AppleDebugOutputs.
- has_dsym = ctx.fragments.objc.generate_dsym
+ has_dsym = apple_common.AppleDebugOutputs in target
info = _struct_omitting_none(
artifact = artifact,
archive_root = archive_root,
+ dsym_path = dsym_path,
generated_sources = [(x.path, x.short_path) for x in generated_files.to_list()],
bundle_name = bundle_name,
embedded_bundles = embedded_bundles.to_list(),
diff --git a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects_paths.bzl b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects_paths.bzl
index a79a7c5..14c7669 100644
--- a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects_paths.bzl
+++ b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects_paths.bzl
@@ -19,6 +19,7 @@
load(
"@build_bazel_rules_apple//apple:providers.bzl",
+ _AppleBinaryInfo = "AppleBinaryInfo",
_AppleBundleInfo = "AppleBundleInfo",
_IosExtensionBundleInfo = "IosExtensionBundleInfo",
)
@@ -32,6 +33,8 @@
)
# Re-export providers.
+AppleBinaryInfo = _AppleBinaryInfo
+
AppleBundleInfo = _AppleBundleInfo
AppleTestInfo = _AppleTestInfo
diff --git a/src/TulsiGenerator/Scripts/bazel_build.py b/src/TulsiGenerator/Scripts/bazel_build.py
index 8263732..2499972 100755
--- a/src/TulsiGenerator/Scripts/bazel_build.py
+++ b/src/TulsiGenerator/Scripts/bazel_build.py
@@ -397,7 +397,6 @@
def __init__(self, build_settings):
self.build_settings = build_settings
self.verbose = 0
- self.build_path = None
self.bazel_bin_path = None
self.codesign_attributes = {}
@@ -526,9 +525,6 @@
self.direct_debug_prefix_map = 'DirectDebugPrefixMap' in features
self.normalized_prefix_map = 'DebugPathNormalization' in features
- self.build_path = os.path.join(self.bazel_bin_path,
- os.environ.get('TULSI_BUILD_PATH', ''))
-
# Path to the Build Events JSON file uses pid and is removed if the
# build is successful.
filename = '%d_%s' % (os.getpid(), BazelBuildBridge.BUILD_EVENTS_FILE)
@@ -971,7 +967,7 @@
self._RsyncBundle(full_name, bundle_path, output_path)
else:
_PrintXcodeWarning('Could not find bundle %s in main bundle. ' %
- (bundle_name + bundle_extension) +
+ (full_name) +
'Device-level Instruments debugging will be '
'disabled for this bundle. Please report a '
'Tulsi bug and attach a full Xcode build log.')
@@ -1204,7 +1200,8 @@
def _InstallDSYMBundles(self, output_dir, outputs_data):
"""Copies any generated dSYM bundles to the given directory."""
# Indicates that our aspect reports a dSYM was generated for this build.
- has_dsym = outputs_data[0]['has_dsym']
+ primary_output_data = outputs_data[0]
+ has_dsym = primary_output_data['has_dsym']
if not has_dsym:
return 0, None
@@ -1215,9 +1212,20 @@
# Declares the Xcode-generated name of our main target's dSYM.
# This environment variable is always set, for any possible Xcode output
# that could generate a dSYM bundle.
- target_dsym = os.environ.get('DWARF_DSYM_FILE_NAME')
- if target_dsym:
- dsym_to_process = set([(self.build_path, target_dsym)])
+ #
+ # Note that this may differ from the Bazel name as Tulsi may modify the
+ # Xcode `BUNDLE_NAME`, so we need to make sure we use Bazel as the source
+ # of truth for Bazel's dSYM name, but copy it over to where Xcode expects.
+ xcode_target_dsym = os.environ.get('DWARF_DSYM_FILE_NAME')
+ dsym_to_process = set()
+ if xcode_target_dsym:
+ dsym_path = primary_output_data.get('dsym_path')
+ if dsym_path:
+ dsym_to_process.add((dsym_path, xcode_target_dsym))
+ else:
+ _PrintXcodeWarning(
+ 'Unable to resolve dSYM paths for main bundle %s'
+ % primary_output_data)
# Collect additional dSYM bundles generated by the dependencies of this
# build such as extensions or frameworks.
@@ -1226,28 +1234,26 @@
for bundle_info in data.get('embedded_bundles', []):
if not bundle_info['has_dsym']:
continue
- # Uses the parent of archive_root to find dSYM bundles associated with
- # app/extension/df bundles. Currently hinges on implementation of the
- # build rules.
- dsym_path = os.path.dirname(bundle_info['archive_root'])
- bundle_full_name = (bundle_info['bundle_name'] +
- bundle_info['bundle_extension'])
- dsym_filename = '%s.dSYM' % bundle_full_name
- child_dsyms.add((dsym_path, dsym_filename))
+ dsym_path = bundle_info.get('dsym_path')
+ if dsym_path:
+ child_dsyms.add((dsym_path, os.path.basename(dsym_path)))
+ else:
+ _PrintXcodeWarning(
+ 'Unable to resolve dSYM paths for embedded bundle %s'
+ % bundle_info)
dsym_to_process.update(child_dsyms)
dsyms_found = []
- for dsym_path, dsym_filename in dsym_to_process:
- input_dsym_full_path = os.path.join(dsym_path, dsym_filename)
- output_full_path = os.path.join(output_dir, dsym_filename)
+ for input_dsym_full_path, xcode_dsym_name in dsym_to_process:
+ output_full_path = os.path.join(output_dir, xcode_dsym_name)
exit_code, path = self._InstallBundle(input_dsym_full_path,
output_full_path)
if exit_code:
- _PrintXcodeWarning('Failed to install dSYM "%s" (%s)'
- % (dsym_filename, exit_code))
+ _PrintXcodeWarning('Failed to install dSYM to "%s" (%s)'
+ % (input_dsym_full_path, exit_code))
elif path is None:
- _PrintXcodeWarning('Could not find a dSYM bundle named "%s"'
- % dsym_filename)
+ _PrintXcodeWarning('Did not find a dSYM bundle at %s'
+ % input_dsym_full_path)
else:
dsyms_found.append(path)