Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Xcode SPM failed to demangle superclass

My app is composed of many projects (frameworks), one for each main feature and a common framework with all sorts of things that I need to access in multiple of my features.

I'm using Xcode 11's Swift Package Manager to add dependencies.

The common framework contains a RxSwift dependency, which I use throughout the whole project.

I'm facing problems when I try to use RxTest in any of my feature frameworks.

If I add RxTest via SPM to the test target directly and run the tests, I get

failed to demangle superclass of 'class name' from mangled name 'other class name'

and many

Class 'class name' is implemented in both 'common framework path' and 'test target path'

where all these classes are Rx related. The 'failed to demangle' error crashes the test and only occurs when I try to initialize a RxTest class.

If I add RxTest to the common framework, the tests run fine, but when I run the app, I get

dyld: Library not loaded: @rpath/XCTest.framework/XCTest

Which makes sense, because I'm adding a test framework to a non-test framework, and it's not something good to do.

So basically, I wasn't able to get a configuration where both the tests and the app run fine. Either the app runs or the tests run.

How can I get this working? Is there a way to include RxTest on the common framework only when I build it on a test target? Or should RxTest only be included on the test targets and I'm missing some configuration?

like image 736
dtmokada Avatar asked Oct 21 '19 13:10

dtmokada


2 Answers

Xcode with SPM dependencies cannot handle same SPM dependency in multiple targets that are dependent on each other right now. Each dependency needs to be only in single target at the moment. I dont know why as of now, but I'll try investigate more and file bug if it is not filed yet.

like image 161
Zdeněk Topič Avatar answered Nov 11 '22 03:11

Zdeněk Topič


Your issue is likely that the library is using static linking instead of dynamic linking. In SwiftPM you can specify a library as being static or dynamic if you want or you can just let the build system decide which is what most packages do. Xcode seems to favor the static approach when it builds with SwiftPM which results in the build issues you are experiencing.

If you modify the Package.swift to have RxTest be a dynamic library instead it should work. You can easily test this by cloning RxSwift and modifying this line:

.library(name: "RxTest", targets: ["RxTest"]),

into:

.library(name: "RxTest", type: .dynamic, targets: ["RxTest"]),

and then dragging the local copy of RxSwift into your Xcode Project Navigator. It will then use your local copy of the package instead of the one cloned by Xcode.

Once you do this you can link it against any targets you need and it should work. If that does actually fix the problem then your long term solutions are likely:

1) Have a fork that simply changes it to a dynamic library.

2) Convince the RxSwift community to change their products to dynamic or to vend dynamic versions in addition to the default.

3) Don't use RxTest or similar things in multiple places.


It is also worth noting, that Xcode 11.3 and earlier do not support archiving with dynamic Swift Packages. So if you go down the dynamic route you will have to wait for Xcode 11.4.

like image 1
bscothern Avatar answered Nov 11 '22 03:11

bscothern