How to integrate TCA framework as of 0.1.3

Hi,

I tried, to the best of my ability, not open this discussion, as something tells me it's not related to TCA :pray:

In the second item of the 0.1.3 release notes, it says that:

Changed: ComposableArchitecture is no longer an explicitly dynamic library. This unfortunately means you will need to reintegrate the library into your application. You can reintegrate by removing and re-adding the library to your application or shared framework target. If you included ComposableArchitecture in more than one shared framework targets you will need to consolidate the static library dependency in a single shared framework target per Apple's recommendation.

Now, how do I properly use TCA in a Test target?

From my understanding, I created a Shared framework, and then added TCA to Dependencies and Link Binary With Libraries:

- Shared.framework
    > ComposableArchitecture

Then, in a Feature target framework, I added the Shared framework to Dependencies, Link Binary With Libraries and Embed Frameworks.

- Feature
    > Shared

Everything seems to be working as expected, however, when including the Shared framework to a FeatureTests target:

- FeatureTests
    > Shared

I start getting lots of these, when compiling for testing:

Undefined symbols for architecture x86_64:
  "ComposableArchitecture.Effect.init(value: A) -> ComposableArchitecture.Effect<A, B>", referenced from:
      SignInTests.SignInTests.setUpWithError() throws -> () in SignInTests.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Now, if I remove Shared, from the FeatureTests, and instead add the ComposableArchitecture to Dependencies and Link Binary With Libraries:

- FeatureTests
    > ComposableArchitecture

It now seems to be working fine. I'm not sure I understand why this is happening. Shouldn't I be able to use Shared? It's expected, right?

What's more interesting is, if I now remove the ComposableArchitecture again from the FeatureTests target, and re-add the Shared framework, things will unexpectedly work as it would be... initially expected. (btw, I do clean Derived Data and test individual components with clean:true in fastlane) ..this is absolutly bananas.

I've been at it last night for a couple of hours, and today again with a "fresh focus" and still feel things are off. This is a project with 14 targets so far, 28 with tests, plus some...

I'm finally able to use TCA for testing (so far), but the workflow to get there? I need to include TCA to my Tests targets, remove it, and re-add the Sharedframework. I must be doing something wrong here!

I had no idea SPM was this fragile. Maybe it's me? Does anyone spot something that I'm doing incorrectly here?

Thank you

:wave:

IMO build settings are always the trickiest part of the job, so others may have a better idea of what's going on.

Can you check out the Tic-Tac-Toe demo app and try to figure out what's different? We've updated it to work with this style of "shared" framework since it is heavily modularized. It uses a TicTacToeCommon framework to share the static ComposableArchitecture library. I wonder if the build failure has anything to do with if/which/where/how frameworks/libraries are embedded in your tree of dependencies.

3 Likes

I haven't noticed that change! I will most definitely check that, thank you.

Hi there! :wave:

I ran into similar build errors, for example

Undefined symbols for architecture x86_64:
"(extension in ComposableArchitecture):Combine.Publisher.eraseToEffect() -> ComposableArchitecture.Effect<A.Output, A.Failure>", referenced from:
SomeKindOfFramework.offlineRandomFact() -> ComposableArchitecture.Effect<Swift.String?, Swift.Never> in SomeKindOfFile.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Watching the PointFree videos of the Composable Architecture, I've taken the PrimeTime project's structure as an example for my project. I've split up each "feature" into separate frameworks. TCA is added using SPM. I then imported TCA in a source file of one of the framework, and so far it built. After consuming data types of the TCA, for example the Effect type, I ran into that error.

Googling here and there didn't help.

Finally I ran into this post and read what Stephen suggested.
So following the approach used in Tic-Tac-Toe demo app ("shared" framework) solved that build error.

I'm just wondering why such error occurred even though TCA is added to the project using SPM. I would expect that it would be available to any frameworks added to the project, but maybe I'm missing some knowledge on SPM.

Did you link TCA with your framework?

Yes, I did. That will also generate an error. Example follows:

given that MyFirstTCAapp is the main target and WeatherApi is the framework
(and TCA is added using SPM)
then

Swift package product 'ComposableArchitecture' is linked as a static library by 'MyFirstTCAapp' and 'WeatherApi'. This will result in duplication of library code.

I think that makes sense:

  • if you don't link explicitly, you'll get the linker errors from your initial post since the TCA library isn't being linked at all
  • if you do have multiple clients which end up in the same process, you'll get duplicated symbols at runtime since the library is static. Eventually, SwiftPM may step in here automatically and build the "ComposableArchitecture" product dynamically, but that's not a feature that's available today. That's where the manually created dynamic framework helps.
1 Like