-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-2660] Teach the driver to accept multiple swiftmodules as linker inputs, for static linking #45265
Comments
@belkadan, this is the JIRA for the front-end work you wanted to consider for better handling command line options for this. I'll let you fill in the blanks with exactly what you wanted. One of the items discussed was adding whatever was needed on the driver side to properly spit out linker options that could be consumed by the appropriate linker. |
Thanks, Todd. I think the first goal is to teach the driver that swiftmodule inputs should only be merged if you pass -emit-module, and that they should be considered linker inputs otherwise. We can treat the "plug me into another linker" part separately. |
Tagging as StarterBug to increase the chances of someone getting to it before me, though for this one I don't think it's necessary to save it for a newcomer. This is a slightly ambitious starter bug, but the steps aren't too hard:
I'm sure it's not that easy in practice, but it seems digestible. |
I've been trying to learn more about lib/Driver, and this seems like a meaty task that's too good to pass up. I'll start working on this tonight. Of course, others should feel free to grab it from me if they'd like. 🙂 |
Sorry for the slow progress here – it took me a while to understand the goals of the task.
The output from a "merge module" action is used as the input to a link action when producing a library: $ swiftc -c -g Foo.swift -emit-library -driver-print-actions
0: input, "Foo.swift", swift
1: compile, {0}, object
2: merge-module, {1}, swiftmodule
3: link, {1, 2}, image
4: generate-dSYM, {3}, dSYM We can see how the input is passed to the linker by using $ swiftc -c -g Foo.swift -emit-library -driver-print-jobs
/Users/bgesiak/GitHub/apple/build/Ninja-DebugAssert/swift-macosx-x86_64/bin/swift -frontend -c -primary-file Foo.swift -target x86_64-apple-macosx10.9 -enable-objc-interop -g -emit-module-doc-path /var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Foo-4c5e4c.swiftdoc -color-diagnostics -parse-as-library -module-name Foo -emit-module-path /var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Foo-4c5e4c.swiftmodule -o /var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Foo-4c5e4c.o
/Users/bgesiak/GitHub/apple/build/Ninja-DebugAssert/swift-macosx-x86_64/bin/swift -frontend -emit-module /var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Foo-4c5e4c.swiftmodule -parse-as-library -target x86_64-apple-macosx10.9 -enable-objc-interop -g -emit-module-doc-path /var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Foo-acf884.swiftdoc -color-diagnostics -module-name Foo -o /var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Foo-acf884.swiftmodule
/usr/bin/ld /var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Foo-4c5e4c.o -add_ast_path /var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Foo-acf884.swiftmodule -dylib -force_load /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_macosx.a -framework CoreFoundation -lobjc -lSystem -arch x86_64 -L /Users/bgesiak/GitHub/apple/build/Ninja-DebugAssert/swift-macosx-x86_64/lib/swift/macosx -rpath /Users/bgesiak/GitHub/apple/build/Ninja-DebugAssert/swift-macosx-x86_64/lib/swift/macosx -macosx_version_min 10.9.0 -no_objc_category_merging -o libFoo.dylib
/usr/bin/dsymutil libFoo.dylib -o libFoo.dylib.dSYM That's a lot to take in, but here's the relevant part of the link job: /usr/bin/ld -add_ast_path /var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Foo-acf884.swiftmodule ... So it's my understanding that, for this task, we'd like to allow the driver to do the following: $ swiftc -c -g Bar.swift Foo.swiftmodule -emit-library -L Foo.dylib ...which would result in a link action that looks like this: /usr/bin/ld \
/var/folders/ry/2ryfdsb56b30092626qprw6d3rb3ss/T/Bar-4c5e4c.o \
-add_ast_path Foo.swiftmodule \
... Namely, .swiftmodule arguments should be passed to the linker with
It's my understanding that when
Does this all sound right, @belkadan? |
I spent a little more time reading the original task https://bugs.swift.org/browse/SR-2637, and I think I have a better understanding now. $ swiftc Foo.swift -emit-object -parse-as-library
$ swiftc Foo.swift -emit-module -emit-module-path `pwd`/Foo.swiftmodule
$ swiftc main.swift -emit-object
$ swiftc main.o Foo.o Foo.swiftmodule -g
<unknown>:0: error: cannot load module 'Foo' as 'main'
<unknown>:0: error: merge-module command failed with exit code 1 (use -v to see invocation) It's my understanding that the goal of this task is to prevent the above error, which occurs because the merge module step attempts to merge Foo.swiftmodule into main.swiftmodule: $ swiftc main.o Foo.o Foo.swiftmodule -g -driver-print-actions
0: input, "main.o", object
1: input, "Foo.o", object
2: input, "Foo.swiftmodule", swiftmodule
3: merge-module, {2}, swiftmodule
4: link, {0, 1, 3}, image
5: generate-dSYM, {4}, dSYM $ swiftc main.o Foo.o Foo.swiftmodule -g -driver-print-jobs
swift -frontend -emit-module Foo.swiftmodule -parse-as-library -g -module-name main -o /tmp/main.swiftmodule
/usr/bin/ld main.o Foo.o -add_ast_path /tmp/main.swiftmodule -o main
/usr/bin/dsymutil main -o main.dSYM Instead, I understand this task to mean that Foo.swiftmodule should be treated as an input to the linker – so I guess something like this: $ swiftc main.o Foo.o Foo.swiftmodule -g -driver-print-actions
0: input, "main.o", object
1: input, "Foo.o", object
2: input, "Foo.swiftmodule", swiftmodule
3: link, {0, 1, 2}, image
4: generate-dSYM, {3}, dSYM $ swiftc main.o Foo.o Foo.swiftmodule -g -driver-print-jobs
/usr/bin/ld main.o Foo.o -add_ast_path Foo.swiftmodule -o main
/usr/bin/dsymutil main -o main.dSYM Does that sound right? By the way, as noted in the other task, without $ swiftc main.o Foo.o Foo.swiftmodule
<unknown>:0: error: unexpected input file: out/Foo.swiftmodule |
That's mostly it.
(or something with multiple .swift files and an output file map). I'm happy to disconnect -g from whether or not we do anything with swiftmodules. There'll be a bunch of assertions to remove, though—in the first implementation we wanted to be very sure we didn't accidentally try to stick partial modules in the final build product! |
I'm taking a break from this for now, so I'll free up this task in case anyone else would like to try it. 🙂 |
Thanks for taking a whack at it, Brian! |
@swift-ci create |
Comment by Steven Hepting (JIRA) matthew carroll (JIRA User) We are looking forward to any progress updates you might have on this one! Relevant issue in Buck: facebook/buck#423 |
I took another look at this. Thanks to Todd for attaching such a great sample project. It didn't work with Swift ToT, so I updated it: https://github.com/modocache/SR-2660 Here's the thing, though: the updated sample project works for me when using Swift 98ba6a4 (Oct 18 ToT) and swift-lldb 7fc171f (Oct 13 ToT). The linker is invoked with So, based on the evidence I have, I think this must have been fixed, perhaps accidentally, at some point. My next steps are:
|
Oh I see, Todd fixed this in apple/swift-lldb@88e778c6abf65dba49d0a028f2f9f794407d6d1a, and he left a comment on the original issue. Great! So I just need to modify the driver. Once I do that, I'd like to test whether Buck's issue is fixed. Is there an easy way to do that, I wonder? |
I sent up #12507 as a first attempt at addressing one of the two driver improvements Jordan mentioned in an earlier comment. |
Brian, with pull request #12507 merged, what is missing here now? |
Thanks for the follow-up, @adrian-prantl! There are two pieces of work left, I think:
|
Yep, this is where I think we should go. |
Hi Brian, did you manage to package up the reproducer? I'm verifying that dsymutil works with multiple AST nodes and I'd like to ensure it works with your test case too, rather than with just something artificial. |
Hi! I apologize for the initial estimate, it turns out the project in question uses a lot of internal Buck functions and so it's not as easy as I thought to split out and attach here. I'll try to do so this week. As I mentioned above, I wasn't able to reproduce the issue until I generated an Xcode project via Buck and attached a debugger, so I think it'll be a valuable bug once we can narrow down what's going wrong. |
Brian, do you think it would be possible for you to just post a simplified build log of your testcase? We would like to help recreating your testcase but it isn't clear to me what the ingredients are. Let me lay out what I understand so far and perhaps you can tell me where my assumptions and your testcase are different:
Thanks! |
(Oops, sorry, I must have accidentally hit a JIRA keyboard shortcut that briefly assigned this task to me.) Sure @adrian-prantl, that's a good idea. I'll try to answer what I can.
Thanks for your help, and sorry I don't have a clean project I can share with you yet. For now, I'll attach the build logs you requested, as well as the source code (but none of the .xcodeproj or build files) of the example project. Hope this helps for now! I'll also try to upload a clear reproduction case as soon as I can. |
Thanks for your patience on this one! The original reporter of the Buck+Swift bug is on vacation until November 6th. In the meantime, I'm trying to produce a small sample project. I also sent up #12708 hopefully this is close to what @belkadan had in mind for handling top-level |
Comment by Milen Dzhumerov (JIRA) Apologies for not being able to attach a repro case earlier, I'm currently busy with another work stream that demands all my attention. I will try my best to setup a repro Xcode project as soon as I can. |
Comment by Milen Dzhumerov (JIRA) @adrian-prantl @modocache I've created a repro Xcode project from scratch that mimics how Buck would generate it (but without using Buck at all). |
Thanks, milen (JIRA User)! I can confirm that the problem reproduces for me – placing a breakpoint at Running I'm able to work around the error by adding the following to the Xcode project's TestApp target's OTHER_LDFLAGS = (
"-Xlinker",
"-add_ast_path",
"-Xlinker",
"$(BUILT_PRODUCTS_DIR)/Bar.swiftmodule/x86_64.swiftmodule",
"-Xlinker",
"-add_ast_path",
"-Xlinker",
"$(BUILT_PRODUCTS_DIR)/Foo.swiftmodule/x86_64.swiftmodule",
); This results in |
Hi Brian, Milen, Thanks a lot for attaching the reproducer. I had another look at this using Xcode 9.3 beta. It make sense that without the ASTs being added by the linker they don't end up in the debug map. If you want to verify this yourself, you can run: dsymutil -dump-debug-map <binary> With the linker flags added manually, I'm able to break in both static libs. I put a breakpoint at Foo.swift:14 and Bar.swift:19 as you suggested. (lldb) po self
Bar.BarObject
(lldb) po self
FooStruct
- version : 5 Can you confirm that this scenario also works for you using the latest Xcode? The difference with dynamic libraries is that Xcode calls libtool instead of the linker to create the static archive. The latter doesn't know what to do with this add_ast_path flag (or the AST for that matter). This explains why you have to pass the ASTs explicitly when linking the final binary. |
Comment by Steven Hepting (JIRA) Are there any more updates on progress for this bug? |
@JDevlieghere The radar for this is resolved, is the bug as well? |
I believe so. Brian or Milen, can you please verify this works for your use case? |
Comment by Milen Dzhumerov (JIRA) I have now verified that this works as expected. |
Attachment: Download
Environment
Apple Swift version 3.0 (swiftlang-800.0.46.2 clang-800.0.38)
Target: x86_64-apple-macosx10.9
Additional Detail from JIRA
md5: 6b6c547b0589245db749baf930bc2e1b
blocks:
cloned from:
is duplicated by:
Issue Description:
Suppose we have an Objective-C program that uses two Swift modules. We would like to debug this program with LLDB without having a dSYM for faster builds.
Each Swift module consist of a
.swiftmodule
,.o
, and the.h
header.We then link the two Swift objects and Objective-C objects into the final binary. It looks like LLDB needs to have .swiftmodule information for debugging, so we include references as AST entries.
When we run LLDB on this binary and set breakpoints inside of the code for Foo and Bar modules, only the Foo types are picked up by LLDB. It only reads the first AST reference, ignoring others. If we swap the order of add_ast_path options we get symbols from the other module.
The full build is in attached zip file. Unpack and run build.sh. In its output, you will see that
frame variable self
command only correctly prints the variable for one module, not both.The text was updated successfully, but these errors were encountered: