Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicate classes in tests from generated xcconfigs for test targets with target dependencies #6065

Closed
1 task done
morganchen12 opened this issue Oct 21, 2016 · 37 comments 路 Fixed by #6437
Closed
1 task done
Assignees
Labels
r:frameworks Related to support for Frameworks s2:confirmed Issues that have been confirmed by a CocoaPods contributor t2:defect These are known bugs. The issue should also contain steps to reproduce. PRs welcome!

Comments

@morganchen12
Copy link

morganchen12 commented Oct 21, 2016

馃寛

  • I've read and understood the CONTRIBUTING guidelines and have done my best effort to follow.

Report

What did you do?

I have a dynamic framework project with a handful of dependencies and a unit test target that lists the framework as a target dependency. My Podfile looks like this:

target 'FirebaseDatabaseUI' do
  use_frameworks!

  # Pods for Database
  pod 'Firebase/Database'

  target 'FirebaseDatabaseUITests' do
    inherit! :search_paths
  end
end

I noticed in one of the betas (definitely before 1.1.0.rc.2, I think around 1.1.0.beta.2) that duplicate classes from the dependencies were showing up in the unit tests runtime despite using inherit! :search_paths. After some hunting I found that CocoaPods was adding all of the test target's dependency's dependencies into the xcconfig file.

OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"icucore" -l"sqlite3" -l"z" 
  -framework "AddressBook" 
  -framework "CFNetwork" 
  -framework "CoreGraphics" 
  -framework "FirebaseAnalytics" 
  -framework "FirebaseCore" 
  -framework "FirebaseDatabase" 
  -framework "FirebaseInstanceID" 
  -framework "GoogleInterchangeUtilities" 
  -framework "GoogleSymbolUtilities" 
  -framework "GoogleUtilities" 
  -framework "Security" 
  -framework "StoreKit" 
  -framework "SystemConfiguration"

This issue is still present even if the tests target is moved out of its parent.

target 'FirebaseDatabaseUI' do
  use_frameworks!

  # Pods for Database
  pod 'Firebase/Database'
end

target 'FirebaseDatabaseUITests' do
  use_frameworks!
end

Deleting the -framework flags from the xcconfig file fixes the issue temporarily until the next pod install.

CocoaPods 1.0.1 doesn't have this issue, as it doesn't add any ld flags to the test target.

Workaround

Deliberately not inheriting the OTHER_LDFLAGS (Other Linker Flags) build setting from CocoaPods' generated xcconfigs (i.e. delete $(inherited) in the project file) avoids this issue, but produces ugly warnings when running pod install and may cause issues in future versions of CocoaPods.

Removing the target dependency in Xcode, running pod install, and then re-adding the target dependency also works around the issue.

What did you expect to happen?

I expected the test target to only inherit its parent's search paths and not include its parent's dependencies twice.

What happened instead?

I had duplicate classes in the runtime.

CocoaPods Environment

Stack

   CocoaPods : 1.1.1
        Ruby : ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
    RubyGems : 2.5.1
        Host : Mac OS X 10.11.6 (15G1004)
       Xcode : 8.0 (8A218a)
         Git : git version 2.10.0
Ruby lib dir : /Users/morganchen/.rbenv/versions/2.3.1/lib
Repositories : master - https://github.com/CocoaPods/Specs.git @ f0a7a1e1dde076ea332032c36e81d583e2b1fc6a

Installation Source

Executable Path: /Users/morganchen/.rbenv/versions/2.3.1/bin/pod

Plugins

cocoapods-deintegrate : 1.0.1
cocoapods-plugins     : 1.0.0
cocoapods-search      : 1.0.0
cocoapods-stats       : 1.0.0
cocoapods-trunk       : 1.1.1
cocoapods-try         : 1.1.0

Podfile

target 'FirebaseDatabaseUI' do
  use_frameworks!

  # Pods for Database
  pod 'Firebase/Database'

  target 'FirebaseDatabaseUITests' do
    inherit! :search_paths
  end
end

Project that demonstrates the issue

https://github.com/morganchen12/FirebaseUI-iOS/tree/pods-weird-behavior

Download this branch, run pod install, and then open FirebaseUI.xcworkspace and run tests in the FirebaseDatabaseUI scheme.

Thanks for your time!

@benasher44
Copy link
Member

benasher44 commented Oct 23, 2016

I'm not sure I understand the issue here. I can pull the project listed at: https://github.com/morganchen12/FirebaseUI-iOS/tree/pods-weird-behavior, and the test target builds and launches without issue. Maybe I can add some detail here that will help clarify what's going on though.

FirebaseDatabaseUI is a framework, which means that as of 1.1.0 CocoaPods is going to look for the target in the Podfile that depends on that framework. When CocoaPods finds it, it copies all of that framework's pods there in order to support building the target integrating the pod with the framework's dependencies. I believe the linker flags come along with it, but this doesn't seem like an issue to me, especially since I'm not seeing any warnings or errors about duplicate classes.

To further clarify, even though FirebaseDatabaseUITests is a test target, it does not have a host application. It just has the framework as a dependency, so it's treated like any other target that has a framework dependency.

@benasher44 benasher44 added the s1:awaiting input Waiting for input from the original author label Oct 23, 2016
@morganchen12
Copy link
Author

morganchen12 commented Oct 24, 2016

The tests should pass, but the console is filled with warnings of duplicate class implementations. You'll have to scroll up past the test output to see the warnings.

If you aren't getting any of these warnings, that's very confusing and I'm not sure what to make of it. 馃槥

objc[3039]: Class GSDK_GTMABPerson is implemented in both 
/Users/morganchen/Library/Developer/Xcode/DerivedData/FirebaseUI-
fwcyvciocjlrhqbyjmmybozelsll/Build/Products/Debug-
iphonesimulator/FirebaseDatabaseUI.framework/FirebaseDatabaseUI (0x1113b2880) and 
/Users/morganchen/Library/Developer/Xcode/DerivedData/FirebaseUI-
fwcyvciocjlrhqbyjmmybozelsll/Build/Products/Debug-
iphonesimulator/FirebaseDatabaseUITests.xctest/FirebaseDatabaseUITests (0x110f78888). One of
 the two will be used. Which one is undefined.

@benasher44
Copy link
Member

If you clear your derived data and try again, does that help?

@morganchen12
Copy link
Author

Nope, clearing CocoaPods cache doesn't help either. It also shows up on CI if we update our pod version to >=1.1.0.

@benasher44
Copy link
Member

@morganchen12 there could be an errant build setting in your test target that's causing this. If it's not too much effort, you might try just deleting your test target and creating a new one from scratch. You should be able to select all and easily re-add all of your test sources back to that target once you have the fresh one.

@morganchen12
Copy link
Author

I set up a new project and the issue still reproduces there.

I've worked around this by not inheriting the OTHER_LDFLAGS build setting from CocoaPods in the project file, so this is no longer a blocker for me--take your time if you have other important stuff to work on 馃憤

@benasher44
Copy link
Member

Oh I do see this now. It's in the console at launch time, as opposed to warnings at build time. I think I got confused. I'll look into this.

@benasher44 benasher44 added t2:defect These are known bugs. The issue should also contain steps to reproduce. PRs welcome! s2:confirmed Issues that have been confirmed by a CocoaPods contributor and removed s1:awaiting input Waiting for input from the original author labels Oct 25, 2016
@benasher44 benasher44 added the r:frameworks Related to support for Frameworks label Oct 25, 2016
@iblacksun
Copy link

Any updates for this issue?

@morganchen12 morganchen12 changed the title Strange behavior when generating xcconfigs for targets with target dependencies Duplicate classes in tests from generated xcconfigs for test targets with target dependencies Oct 31, 2016
@benasher44
Copy link
Member

Nope. I'll have more time to look into this in the next week and a half or so, but I haven't determined the root cause yet.

@iamcam
Copy link

iamcam commented Nov 7, 2016

I've noticed this issue as well (also with Firebase), though I couldn't pinpoint when it happened. I've spend some considerable time banging my head against the desk trying to figure this out (probably looking at this too long now), so I'm eager to get this cleared up.

I'll add one more data point: I'm trying to use most of Firebase from within an embedded iOS framework. Much of the same issues are equivalently identical - I must remove the the -framework {firebase} Other LD Flags as well as the $(inherited) flag from these targets:

  • Main application
  • Main application unit tests
  • Framework unit tests

The only place where these are kept is the framework's target, in which case all the -framework {firebase} and $(inherited) flags remain.

With this configuration I'm able to run the application without crashing (that is a side effect of the Class Foo is implemented in both... console output errors with the latest Firebase libs), and I can run unit tests on all testing targets without this error. I don't have UI tests, so I can't verify there.

The one downside, as mentioned, is all the Cocoapod warnings:

[!] The `App [Debug]` target overrides the `OTHER_LDFLAGS` build setting defined in `Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.

...etc for the various targets and schemes mentioned above. I thought perhaps creating a separate private pod might work, so I filed #6138, though I don't think that's a route I wish to go down if I can avoid it at this point of development.

Since I am not as familiar with what is actually going on under the hood, I'm concerned this may come back to bite me, not realizing I made a mistake and sinking even more time into something that could have been prevented.

Anyway, I hop this provides more insight. I'll keep a close eye on this, and I plan on looping Firebase engineering support into this, as I've also been in contact with them (though to no avail - their best advice was similar to the work-arounds in this ticket)

@iamcam
Copy link

iamcam commented Nov 8, 2016

@benasher44 Is it possible that fixing module map problem you mentioned in my linked bug report (#6138 ) would address this? (Sorry - this isn't my strong suit, but since I have the Firebase team's attention I might as well ask)

@benasher44
Copy link
Member

@iamcam nope! This is a different issue. Thanks for checking though!

@adriantofan
Copy link

In my case I can't use inherit! :search_paths because one of the imports fails to work (from GTMOAuth2). When I remove this flag I get duplicate symbols for unit test.

The only fix I found after many searches is to remove OTHER_LDFLAGS on the test target. I've tried with cocoapods 1.1.1 & 1.2.0.beta.1 .

@morganchen12
Copy link
Author

@adriantofan you can use inherit! :search_paths and manually work around the missing import if you'd like by manually adding the path to GTMOAuth2 in your xcodeproj's build settings under Framework Search Paths. Your issue is likely different than the one filed here, since inherit! :search_paths exists solely to avoid duplicating dependencies in a test target that embeds its parent. It just so happens that many CocoaPods issues share the symptom of duplicating classes in the tests runtime.

@ghost
Copy link

ghost commented Dec 1, 2016

Have there been any updates on this?

@benasher44
Copy link
Member

Nope! I do plan on looking at it, but I'm currently quite busy. Sorry! That said, this shouldn't cause any harm at runtime. Please let me know if this is causing anything other than just a log warning.

@rhodgkins
Copy link

Just thought I'd add some more info...

I think I'm having the same issue (with Firebase and GoogleSignIn pods), and while (so far) the app is fine, I think this issue is causing test to fail as I'm getting unrecognized selector sent to X on running some tests. I tried to create a small test reproduction project but this was fine - I'm assuming this is because of the last part of the warning

One of the two will be used. Which one is undefined.

So while the actual app is using the "wrong" class, the reproduction project is using the correct one :(

I am slightly concerned that there might be an issue with the main app further down the line similar to the issue causing the tests to fail!

The above workaround - removing $(inherited) from the test target causes a Missing required module 'Firebase' error when building the tests.

@morganchen12
Copy link
Author

morganchen12 commented Dec 2, 2016

@rhodgkins are you able to post a sample project somewhere? I think your tests should be able to run, you've just possibly misconfigured something.

@iblacksun
Copy link

@benasher44 This issue not only exist in test case.

If duplicate classes is singleton, program behavior is undefined

@benasher44
Copy link
Member

This'll only lead to undefined program behavior if you have multiple versions of the same framework your project, which seems unlikely? I still plan on attempting to fix this, but I still haven't found time to sit down and worker on larger CP changes in awhile. Sorry about that! There is a concrete repro case here though, which is great. Others are definitely welcome to take a crack at fixing this.

@pkrmf
Copy link

pkrmf commented Jan 26, 2017

@benasher44 I found out what is the root cause, at least thats what is happening to me. If I have a dynamic framework that has a dependency on a non dynamic framework(i am basically wrapping a vendor library with my APIs and some extra functionality). If I pod install my dynamic framework it will pull the dependency and I will get the error of the vendor class implemented multiple times. If I just pull the dependency directly(non dynamic) without my wrapper, then the error disappears. I updated the vendor's SDK to the latest version(which is a dynamic framework) and then the problem went away. I still have another vendor that I am wrapping and obviously that one still breaks. I have 2 options, not wrap the non dynamic libraries or ask them to provide me a dynamic framework. I don't know either if this problem is related to cocoapods since I havent tried to install them without cocoapods. I will try that and let you guys know.

@dnkoutso
Copy link
Contributor

Confirmed we hit that yesterday. This is particularly a problem when Reveal is added since its a static framework instead of a dynamic and performs a check to see if its loaded twice and will crash if it is.

Might be able to spend sometime and figure this out.

@morganchen12
Copy link
Author

@pkrmf, the issue you're running into is one inherent with static dependencies of dynamic dependencies and also why CocoaPods forbids static dependencies of dependencies. When your dynamic dependency is built, it must resolve its static dependencies at build time, so when yur dylib is finished building it contains all of the symbols from its static dependencies. If you then share dependencies with another dylib or your main app, you end up with duplicate symbols.

@pkrmf
Copy link

pkrmf commented Jan 26, 2017

@morganchen12 how can I prevent from that happening then?

@morganchen12
Copy link
Author

Your dynamic library's dependencies must also be dynamic. In general, avoid mixing static and dynamic dependencies and subdependencies.

@dnkoutso
Copy link
Contributor

dnkoutso commented Jan 26, 2017

@morganchen12 verified that #6437 fixes the warnings and also fixes Reveal-IOS issues with double linking.

static frameworks should not be linked to the targets if inherit! search_paths is set.

dynamic frameworks are OK to be linked twice and so are static libraries (I think)

@asinopoli-gpfw
Copy link

@morganchen12 why not do this also for static libraries? A static frameworks is basically a "packaged" static library

@Whirlwind
Copy link
Contributor

Whirlwind commented Feb 4, 2017

Still link all dependencies to my static framework/library: (CP 1.2.0)

target 'TestFramework' do
    pod 'SDWebImage'
    inherit! :search_paths
end

@dnkoutso
Copy link
Contributor

dnkoutso commented Feb 4, 2017

@Whirlwind can you provide a sample project please?

@iblacksun
Copy link

@dnkoutso This project https://github.com/iblacksun/AMapDemo can reproduce this issue.

  1. Clone repo.
  2. Run pod install

The console output lots of logs.

It's maybe related with ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES .

Below steps can fix this issue.

  1. Edit Pods-AMapDemo.debug.xcconfig, remove -framework "AMapFoundationKit" and -framework "MAMapKit"
  2. Edit target setting, set ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to $(inherited), logs gone.

@dnkoutso
Copy link
Contributor

dnkoutso commented Feb 4, 2017

@iblacksun cloned and used 1.2.0 of CocoaPods and the project built successfully. That is with Xcode 8.

Just another thing though, please create a new issue instead of us discussing on a closed issue.

@dnkoutso
Copy link
Contributor

dnkoutso commented Feb 9, 2017

@asinopoli-gpfw I think that's a good point and it should be fixed, re: pre-built static libs should be linked when inherit! :search_paths is used.

@Whirlwind
Copy link
Contributor

@dnkoutso Simple build static framework is success, but the static framework link another static library which from Pods. So when we link this static framework in another app, we will get duplicate symbols error.

I think that the correct way should be not link any library if my project is a static library/framework. The OTHER_LDFLAGS should be empty.

@dnkoutso
Copy link
Contributor

dnkoutso commented Feb 9, 2017

@Whirlwind I am about to make a PR that improves this and also fixes it for static libs. You are talking about if you have a transitive dependency correct?

@dnkoutso
Copy link
Contributor

dnkoutso commented Feb 9, 2017

@Whirlwind @asinopoli-gpfw not sure if you can apply this patch manually but this should take care of plenty of issues around static linking and inherit search paths

#6477

@Whirlwind
Copy link
Contributor

Maybe, I think that the static library/framework should not link any pods dependency by default!

The inherit search paths define is not required.

@rajohns08
Copy link

I'm still seeing this issue even with inherit! :search_paths:

#6895

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
r:frameworks Related to support for Frameworks s2:confirmed Issues that have been confirmed by a CocoaPods contributor t2:defect These are known bugs. The issue should also contain steps to reproduce. PRs welcome!
Projects
None yet
Development

Successfully merging a pull request may close this issue.