pointfreeco / swift-composable-architecture

A library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind.
https://www.pointfree.co/collections/composable-architecture
MIT License
11.88k stars 1.37k forks source link

Linking TCA breaks on-device Xcode Previews #57

Closed LK closed 4 years ago

LK commented 4 years ago

Describe the bug Adding TCA as a dependency prevents on-device Xcode Previews from launching.

To Reproduce This reproduces on the provided examples (I tried it on TicTacToe), but for a simple repro:

  1. Create a new SwiftUI project
  2. Observe that on-device Xcode Previews [kinda] work
  3. Add TCA as a dependency
  4. Observe that trying to start an on-device Xcode Preview fails with the following error:
    SchemeBuildError: Failed to build the scheme "test-tca"

    linker command failed with exit code 1 (use -v to see invocation)

    Link /Users/lenny/Library/Developer/Xcode/DerivedData/test-tca-guucwvzxaqerknctxnxofuhkuzfc/Build/Intermediates.noindex/Previews/test-tca/Products/Debug-iphoneos/PackageFrameworks/ComposableArchitectureTestSupport.framework/ComposableArchitectureTestSupport:
    ld: warning: Could not find or use auto-linked library 'XCTestSwiftSupport'
    ld: warning: Could not find or use auto-linked framework 'XCTest'
    Undefined symbols for architecture arm64:
      "__swift_FORCE_LOAD_$_XCTestSwiftSupport", referenced from:
          __swift_FORCE_LOAD_$_XCTestSwiftSupport_$_ComposableArchitectureTestSupport in ComposableArchitectureTestSupport.o
      "XCTest.XCTFail(_: Swift.String, file: Swift.StaticString, line: Swift.UInt) -> ()", referenced from:
          (extension in ComposableArchitectureTestSupport):ComposableArchitectureTestSupport.TestStore< where B: Swift.Equatable>.assert(_: ComposableArchitectureTestSupport.TestStore<A, B, C, D, E>.Step..., file: Swift.StaticString, line: Swift.UInt) -> () in ComposableArchitectureTestSupport.o
    ld: symbol(s) not found for architecture arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

Note that this happens even if the ComposableArchitectureTestSupport is not added to any target.

Expected behavior Xcode Previews continues to work as expected.

Screenshots N/A

Environment

Additional context I'm no expert on how the Xcode build system works, but I didn't see anything obviously wrong in the build config at first glance; I'm not sure how or why it's trying to link ComposableArchitectureTestSupport. I then assumed this was a bug with the Xcode build system, but after trying it on another repository with a test support target (https://github.com/spotify/Mobius.swift) it seems like they don't have the same issue, so maybe there's something deeper going on.

LK commented 4 years ago

(I should add that I tried the traditional โ‡งโŒ˜K/DerivedData incantations, but no luck)

stephencelis commented 4 years ago

@LK Thanks for the report!

I think this might have to do with the fact that we've explicitly marked the products as .dynamic (it's the only thing I see that differs from the Mobius package):

https://github.com/pointfreeco/swift-composable-architecture/blob/13ad378da204bd4ec96eed5ac1832ac67048f6b3/Package.swift#L16

I'm unable to verify, though, because for whatever reason I can't get any preview working on my device ๐Ÿ˜…

Removing .dynamic might fix things, though. The error message I get on master with .dynamic is same as the one you're seeing with ComposableArchitectureTestSupport, while the error message I get after removing .dynamic is identical to the error I get on a fresh project with zero dependencies (and makes no mention of ComposableArchitectureTestSupport).

Can you try the following to see if you can verify?

  1. Clone swift-composable-architecture
  2. Open ComposableArchitecture.xcworkspace
  3. Update its Package.swift to remove type: .dynamic from both ComposableArchitecture and ComposableArchitectureTestSupport
  4. Update the SwiftUICaseStudies project's build phases by removing and re-adding ComposableArchitecture (otherwise it'll be pointing to the "old" package) and add a development team to its signing capabilities
  5. Build to device and see if you can get previews to work
LK commented 4 years ago

Good catch @stephencelis, that did fix on-device Previews in the SwiftUICaseStudies project. However this breaks any project that's split up into multiple frameworks:

Swift package product 'ComposableArchitecture' is linked as a static library by 'AppCore' and 2 other targets. This will result in duplication of library code.

stephencelis commented 4 years ago

Yep ๐Ÿ˜” This is why we made that configuration in the first place, hoping to get around SPM quirks.

A related issue is happening in this PR: https://github.com/pointfreeco/swift-composable-architecture/pull/52

The short of it is that it's not really safe to define a target like ComposableArchitectureTestSupport that depends on a target like ComposableArchitecture from the same package. Apple knows about this issue, but the only current SPM workaround that we can depend on will require us to move ComposableArchitectureTestSupport to its own package/repo, making the user experience of adopting the library slightly more annoying. Hopefully Apple can come up with a solution to this soon! (Next month? ๐Ÿคž)

In the meantime, Brandon and I will chat next steps in how we wanna address this.

mbrandonw commented 4 years ago

We're working on fixing this in #70, which has consolidated everything we know about the issue. Gonna close this in favor of tracking that one!

stephencelis commented 4 years ago

@LK We think we have a fix! Can you try things out on this branch? https://github.com/pointfreeco/swift-composable-architecture/pull/71

LK commented 4 years ago

@stephencelis SwiftUICaseStudies works now. Trying to run the TicTacToe app on device crashes on launch with this error (yet it works fine in the simulator):

dyld: Library not loaded: @rpath/AppCore.framework/AppCore
  Referenced from: /private/var/containers/Bundle/Application/59760678-5C85-4F63-8ABE-F14701F34A6C/TicTacToe.app/TicTacToe
  Reason: image not found

Trying to start an on-device Xcode Preview from the TicTacToe project fails with the following error:

GenericHumanReadableError: unexpected error occurred

frameworkModeUnsupported

(Regular Xcode Previews in the sidebar still work, though.)

Not sure if related but I also get a slew of these warnings: image

stephencelis commented 4 years ago

Trying to run the TicTacToe app on device crashes on launch with this error (yet it works fine in the simulator):

dyld: Library not loaded: @rpath/AppCore.framework/AppCore
  Referenced from: /private/var/containers/Bundle/Application/59760678-5C85-4F63-8ABE-F14701F34A6C/TicTacToe.app/TicTacToe
  Reason: image not found

Trying to start an on-device Xcode Preview from the TicTacToe project fails with the following error:

GenericHumanReadableError: unexpected error occurred

frameworkModeUnsupported

(Regular Xcode Previews in the sidebar still work, though.)

Good catch! I'll play around with it but this may just be another Xcode previews bug around modularized apps. If we can't fix we'll file a feedback.

Not sure if related but I also get a slew of these warnings:

Those warnings are unrelated. We should probably clean them up, though.

LK commented 4 years ago

Sounds good! To clarify, the first error comes from trying to run the entire app like normal; the second error is specific to Xcode Previews.

stephencelis commented 4 years ago

@LK You're right. TicTacToe wasn't in building order for device anyhow. We've pushed a fix for that but the frameworkModeUnsupported points to a current limitation in Xcode previews and frameworks in general. If you pull the latest master you might be able to build the RootView...