Skip to content

Conversation

@royitaqi
Copy link
Contributor

@royitaqi royitaqi commented Oct 27, 2025

Change

The default behavior is to not copy such swiftmodules into the dSYM, as perviously implemented in 96f95c9. This patch adds the option to override the behavior, so that such swiftmodules can be copied into the dSYM.

This is useful when the dSYM will be used on a machine which has a different Xcode/SDK than where the swiftmodules were built. Without this, when LLDB is asked to "p/po" a Swift variable, the underlying Swift compiler code would rebuild the dependent .swiftmodule files of the Swift stdlibs, which takes ~1 minute in some cases.

Test

Shell tests:

royshi-mac-office ~/public_llvm/build % bin/llvm-lit              \
    ../llvm-project/llvm/test/tools/dsymutil/cmdline.test         \
    ../llvm-project/llvm/test/tools/dsymutil/ARM/swiftmodule.test \
    ../llvm-project/llvm/test/tools/dsymutil/ARM/swiftmodule-include-from-interface.test

-- Testing: 3 tests, 3 workers --
PASS: LLVM :: tools/dsymutil/cmdline.test (1 of 3)
PASS: LLVM :: tools/dsymutil/ARM/swiftmodule-include-from-interface.test (2 of 3)
PASS: LLVM :: tools/dsymutil/ARM/swiftmodule.test (3 of 3)

Testing Time: 6.07s

Total Discovered Tests: 3
  Passed: 3 (100.00%)

--

Manually tested by running dsymutil to build a dSYM with and without the option and then checking the size of the __swift_ast section.

Without change:

royshi-mac-office ~/fbsource % ~/public_llvm/build/bin/dsymutil buck-out/v2/gen/fbsource/6aca8cf7b38a80d6/fbobjc/Apps/Internal/FocusPlayground/__FocusPlayground__/FocusPlayground.app/Frameworks/Features.framework/Features
royshi-mac-office ~/fbsource % otool -lv buck-out/v2/gen/fbsource/6aca8cf7b38a80d6/fbobjc/Apps/Internal/FocusPlayground/__FocusPlayground__/FocusPlayground.app/Frameworks/Features.framework/Features.dSYM/Contents/Resources/DWARF/Features | grep -B 1 -A 3 __swift_ast
Section
  sectname __swift_ast
   segname __DWARF
      addr 0x000000000001c000
      size 0x0000000000033dc4   <-- This is small.

With change:

royshi-mac-office ~/fbsource % ~/public_llvm/build/bin/dsymutil buck-out/v2/gen/fbsource/6aca8cf7b38a80d6/fbobjc/Apps/Internal/FocusPlayground/__FocusPlayground__/FocusPlayground.app/Frameworks/Features.framework/Features --include-swiftmodules-from-interface
royshi-mac-office ~/fbsource % otool -lv buck-out/v2/gen/fbsource/6aca8cf7b38a80d6/fbobjc/Apps/Internal/FocusPlayground/__FocusPlayground__/FocusPlayground.app/Frameworks/Features.framework/Features.dSYM/Contents/Resources/DWARF/Features | grep -B 1 -A 3 __swift_ast
Section
  sectname __swift_ast
   segname __DWARF
      addr 0x000000000001c000
      size 0x000000000205feec   <-- Notice the large increase in section size.

@llvmbot
Copy link
Member

llvmbot commented Oct 27, 2025

@llvm/pr-subscribers-debuginfo

Author: Roy Shi (royitaqi)

Changes

The default behavior is to not copy such swiftmodules into the dSYM, as perviously set by 96f95c9.

This patch adds the option to override the behavior, so that such swiftmodules are copied into the dSYM. This is useful when the dSYM will be used on a machine which has a different Xcode/SDK.


Full diff: https://github.com/llvm/llvm-project/pull/165293.diff

5 Files Affected:

  • (modified) llvm/test/tools/dsymutil/cmdline.test (+1)
  • (modified) llvm/tools/dsymutil/DwarfLinkerForBinary.cpp (+4-3)
  • (modified) llvm/tools/dsymutil/LinkUtils.h (+7)
  • (modified) llvm/tools/dsymutil/Options.td (+8)
  • (modified) llvm/tools/dsymutil/dsymutil.cpp (+3)
diff --git a/llvm/test/tools/dsymutil/cmdline.test b/llvm/test/tools/dsymutil/cmdline.test
index 1574fe35f5254..0b0bce194d575 100644
--- a/llvm/test/tools/dsymutil/cmdline.test
+++ b/llvm/test/tools/dsymutil/cmdline.test
@@ -14,6 +14,7 @@ CHECK: -fat64
 CHECK: -flat
 CHECK: -gen-reproducer
 CHECK: -help
+CHECK: -include-swiftmodules-from-interface
 CHECK: -keep-function-for-static
 CHECK: -no-object-timestamp
 CHECK: -no-odr
diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index b91c27e6a0f86..ee1e9060657b0 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -794,9 +794,10 @@ bool DwarfLinkerForBinary::linkImpl(
         reportWarning("Could not parse binary Swift module: " +
                           toString(FromInterfaceOrErr.takeError()),
                       Obj->getObjectFilename());
-        // Only skip swiftmodules that could be parsed and are
-        // positively identified as textual.
-      } else if (*FromInterfaceOrErr) {
+        // Only skip swiftmodules that could be parsed and are positively
+        // identified as textual. Do so only when the option allows.
+      } else if (*FromInterfaceOrErr &&
+                 !Options.IncludeSwiftModulesFromInterface) {
         if (Options.Verbose)
           outs() << "Skipping compiled textual Swift interface: "
                  << Obj->getObjectFilename() << "\n";
diff --git a/llvm/tools/dsymutil/LinkUtils.h b/llvm/tools/dsymutil/LinkUtils.h
index ad5515a04333e..c333a3d4afee0 100644
--- a/llvm/tools/dsymutil/LinkUtils.h
+++ b/llvm/tools/dsymutil/LinkUtils.h
@@ -114,6 +114,13 @@ struct LinkOptions {
   /// Whether all remarks should be kept or only remarks with valid debug
   /// locations.
   bool RemarksKeepAll = true;
+
+  /// Whether or not to copy binary swiftmodules built from textual
+  /// .swiftinterface files into the dSYM bundle. These typically come only
+  /// from the SDK (since textual interfaces require library evolution) and
+  /// thus are a waste of space to copy into the bundle. Turn this on if the
+  /// swiftmodules are different from those in the SDK.
+  bool IncludeSwiftModulesFromInterface = false;
   /// @}
 
   LinkOptions() = default;
diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td
index ad35e55e33b12..e99bc12fa7fd8 100644
--- a/llvm/tools/dsymutil/Options.td
+++ b/llvm/tools/dsymutil/Options.td
@@ -202,6 +202,14 @@ def remarks_drop_without_debug: Flag<["--", "-"], "remarks-drop-without-debug">,
            "all remarks are kept.">,
   Group<grp_general>;
 
+def include_swiftmodules_from_interface: Flag<["--", "-"], "include-swiftmodules-from-interface">,
+  HelpText<"Whether or not to copy binary swiftmodules built from textual "
+  ".swiftinterface files into the dSYM bundle. These typically come only "
+  "from the SDK (since textual interfaces require library evolution) and "
+  "thus are a waste of space to copy into the bundle. Turn this on if the "
+  "swiftmodules are different from those in the SDK.">,
+  Group<grp_general>;
+
 def linker: Separate<["--", "-"], "linker">,
   MetaVarName<"<DWARF linker type>">,
   HelpText<"Specify the desired type of DWARF linker. Defaults to 'classic'">,
diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp
index 913077eb0b06d..688f6aaf3d0c9 100644
--- a/llvm/tools/dsymutil/dsymutil.cpp
+++ b/llvm/tools/dsymutil/dsymutil.cpp
@@ -391,6 +391,9 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
   Options.LinkOpts.RemarksKeepAll =
       !Args.hasArg(OPT_remarks_drop_without_debug);
 
+  Options.LinkOpts.IncludeSwiftModulesFromInterface =
+      Args.hasArg(OPT_include_swiftmodules_from_interface);
+
   if (opt::Arg *BuildVariantSuffix = Args.getLastArg(OPT_build_variant_suffix))
     Options.LinkOpts.BuildVariantSuffix = BuildVariantSuffix->getValue();
 

@royitaqi
Copy link
Contributor Author

royitaqi commented Oct 27, 2025

EDIT: The latest buildbot seems to pass. This may have been fixed in main.

A test failed when running ninja check-llvm. The same test seems to also fail on master (I'm on commit 263377a). So I assume it's unrelated to this patch.

royshi-mac-office ~/public_llvm/build % ninja check-llvm
[142/143] Running the LLVM regression tests
FAIL: LLVM :: tools/llvm-objcopy/ELF/strip-preserve-atime.test (1 of 60742)
******************** TEST 'LLVM :: tools/llvm-objcopy/ELF/strip-preserve-atime.test' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 9
/Users/royshi/public_llvm/build/bin/yaml2obj /Users/royshi/public_llvm/llvm-project/llvm/test/tools/llvm-objcopy/ELF/strip-preserve-atime.test -o /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp.1.o
# executed command: /Users/royshi/public_llvm/build/bin/yaml2obj /Users/royshi/public_llvm/llvm-project/llvm/test/tools/llvm-objcopy/ELF/strip-preserve-atime.test -o /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp.1.o
# RUN: at line 10
touch -a -t 199505050555.55 /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp.1.o
# executed command: touch -a -t 199505050555.55 /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp.1.o
# RUN: at line 11
/Users/royshi/public_llvm/build/bin/llvm-strip -p /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp.1.o -o /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp-preserved.1.o
# executed command: /Users/royshi/public_llvm/build/bin/llvm-strip -p /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp.1.o -o /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp-preserved.1.o
# RUN: at line 12
ls -lu /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp-preserved.1.o | /Users/royshi/public_llvm/build/bin/FileCheck /Users/royshi/public_llvm/llvm-project/llvm/test/tools/llvm-objcopy/ELF/strip-preserve-atime.test --check-prefix=CHECK-PRESERVE-ATIME
# executed command: ls -lu /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp-preserved.1.o
# executed command: /Users/royshi/public_llvm/build/bin/FileCheck /Users/royshi/public_llvm/llvm-project/llvm/test/tools/llvm-objcopy/ELF/strip-preserve-atime.test --check-prefix=CHECK-PRESERVE-ATIME
# .---command stderr------------
# | /Users/royshi/public_llvm/llvm-project/llvm/test/tools/llvm-objcopy/ELF/strip-preserve-atime.test:55:25: error: CHECK-PRESERVE-ATIME: expected string not found in input
# | # CHECK-PRESERVE-ATIME: {{[[:space:]]1995}}
# |                         ^
# | <stdin>:1:1: note: scanning from here
# | -rw-r--r--@ 1 royshi staff 280 Oct 27 13:51 /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp-preserved.1.o
# | ^
# | <stdin>:1:142: note: possible intended match here
# | -rw-r--r--@ 1 royshi staff 280 Oct 27 13:51 /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp-preserved.1.o
# |                                                                                                                                              ^
# |
# | Input file: <stdin>
# | Check file: /Users/royshi/public_llvm/llvm-project/llvm/test/tools/llvm-objcopy/ELF/strip-preserve-atime.test
# |
# | -dump-input=help explains the following input dump.
# |
# | Input was:
# | <<<<<<
# |             1: -rw-r--r--@ 1 royshi staff 280 Oct 27 13:51 /Users/royshi/public_llvm/build/test/tools/llvm-objcopy/ELF/Output/strip-preserve-atime.test.tmp-preserved.1.o
# | check:55'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
# | check:55'1                                                                                                                                                  ?              possible intended match
# | >>>>>>
# `-----------------------------
# error: command failed with exit status: 1

--

********************

@royitaqi
Copy link
Contributor Author

royitaqi commented Oct 28, 2025

@adrian-prantl Could you kindly review this patch when you have the time? It adds an option to skip the logic you added in 96f95c9. The default behavior remains unchanged.

@royitaqi
Copy link
Contributor Author

royitaqi commented Oct 30, 2025

FYI I plan to merge this patch tomorrow if no one else wants to take a look before then. The patch is simple and has tests, so I don't expect it to break anything.

cc @adrian-prantl , @JDevlieghere , @clayborg

@JDevlieghere
Copy link
Member

JDevlieghere commented Oct 30, 2025

FYI I plan to merge this patch tomorrow if no one else wants to take a look before then. The patch is simple and has tests, so I don't expect it to break anything.

Although I see where you're coming from, I feel obligated to point out that doing so wouldn't be in accordance with our code review policy, unless you got someone to LGTM it in the meantime. Plus all the reviewers were at the Developer Meeting so giving folks a bit more time seems appropriate. This is really @adrian-prantl's domain in dsymutil so I'd like him to sign off on it. This looks fine to me.

@royitaqi
Copy link
Contributor Author

TL;DR: SG. Let's give it another week so that folks (esp. @adrian-prantl) have the time to review.

Although I see where you're coming from, I feel obligated to point out that doing so wouldn't be in accordance with our code review policy,

Sorry that you had to jump out and stop me. I appreciate it.

I take it as a good chance to refresh my memory about the policy. Actually took me sometime to understand the long English sentences. I think the main spirit is to:

  1. allow plenty of time for reviews, and
  2. make sure that the "reviewers will almost surely be satisfied with the patch" before merging.

unless you got someone to LGTM it in the meantime.

FWIW, I was taking @rmaz 's approval as LGTM. I can see why it's not considered as a strong approval (since @adrian-prantl is the domain owner).

Plus all the reviewers were at the Developer Meeting so giving folks a bit more time seems appropriate. This is really @adrian-prantl's domain in dsymutil so I'd like him to sign off on it. This looks fine to me.

Yep make sense to me, esp. about the Developer Meeting. Would love @adrian-prantl 's review for sure (that's why I requested his review in the first place). Happy to wait.

@JDevlieghere
Copy link
Member

FWIW, I was taking @rmaz 's approval as LGTM. I can see why it's not considered as a strong approval (since @adrian-prantl is the domain owner).

Thanks for pointing that out, I hadn't noticed and I blame Github's UI for it. It doesn't show up as approved in the list of PRs, in the PR itself it shows up as a grey checkmark and it's also tucked away under "1 more reviewer" in the side bar. I'm a bit puzzled as to why since he's part of the LLVM org.

Sorry I missed it. We don't technically require code owners to sign off (though in practice we often do) so you would've been fine to merge with Richard's approval.

@jryans
Copy link
Member

jryans commented Oct 30, 2025

Thanks for pointing that out, I hadn't noticed and I blame Github's UI for it. It doesn't show up as approved in the list of PRs, in the PR itself it shows up as a grey checkmark and it's also tucked away under "1 more reviewer" in the side bar. I'm a bit puzzled as to why since he's part of the LLVM org.

I believe the reason GitHub is presenting rmaz's review in this way is that they are a member of the org triagers team, but not the committers team, so they do not have write access to the repo. If they had commit / write access, then their review would appear in the usual way you were expecting.

@JDevlieghere
Copy link
Member

I believe the reason GitHub is presenting rmaz's review in this way is that they are a member of the org triagers team, but not the committers team, so they do not have write access to the repo. If they had commit / write access, then their review would appear in the usual way you were expecting.

Thanks for the insights, that makes sense.

@royitaqi
Copy link
Contributor Author

Thank you both for the observations and insights. I didn't realize it's a gray checkmark until you pointed out. There is always something to learn everyday. :D You guys heave a great day~

@adrian-prantl
Copy link
Collaborator

Sorry for the delayed reply @royitaqi. As @JDevlieghere mentioned I'm still catching up with my review queue after the LLVM dev meeting. This patch is solving a real problem and I don't have an issue with bypassing the check per se, however, I also wanted to share with you that we are concurrently working on a different solution to the same problem:

The goal is to remove binary Swift modules from dSYMs altogether, because binary Swift modules — being version locked with the compiler — are at odds with the long-term archive promise of dSYM bundles. Instead, we will rely on binary Swift modules recording their binary Swift module dependencies (similar to how they record their clang dependencies, see swiftlang/swift#84412), and having a link from DWARF to every compile unit's own Swift module (see swiftlang/swift#85100). With that in place, we would then retire the linker's -add_ast_path option and dsymutil's handling of Swift modules and interfaces. I understand that that has some consequences for users maintaining their own build systems, but I'm confident it will actually make it much easier. The paths in DWARF are fully remappable, and/or can be CAS cache keys, so it will also play well with caching and reproducible builds.

Copy link
Collaborator

@adrian-prantl adrian-prantl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to accept the patch with the caveat that we're planning to remove the entire feature from dsymutil after a transition period. See my other comment. Feel free to reach out to me with any questions/concerns!

@royitaqi
Copy link
Contributor Author

@adrian-prantl: Thank you very much for sharing your plan. I appreciate it. I don't have much Swift experience, but it sounds like a much better path going forward.

after a transition period

Do you happen to have an ETA of when the transition will finish? This will help us decide if we still want to merge and cherry-pick the current patch for now (and later transit to your solution).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants