CocoaPods / CocoaPods

The Cocoa Dependency Manager.
https://cocoapods.org/
Other
14.57k stars 2.63k forks source link

Pods that are used by embedded dynamic frameworks can't be found in linked targets. #6284

Open craigmarvelley opened 7 years ago

craigmarvelley commented 7 years ago

Report

What did you do?

I've an iOS application (Objective-C) which is composed of three main targets, testing aside: the app itself, a share extension, and an embedded dynamic framework. The framework exists to share code between the app and the share extension, and it has dependencies on third-party frameworks managed by CocoaPods. Both the app target and the extension target will be including classes from the framework, and so also including the framework's dependencies.

I'm able to run pod install just fine and everything seems to be generated OK (though I'm not 100% sure as to which Build Phase scripts should be present on which targets), but when building the app I get errors related to the dependency libraries.

What did you expect to happen?

I expect both the app and extension targets to be able to link to the framework target (which could be anything, but I'll reference AFNetworking for example), and reference the dependencies included by it.

What happened instead?

When asking CocoaPods to use static libraries, I get the following error:

/Users/craig/Code/ios/FrameworkDependencyDemo/SharedFramework/SharedClass.h:10:9: Include of non-modular header inside framework module 'SharedFramework.SharedClass'

After reading around I tried configuring CocoaPods with use_frameworks!, but then I get the following errors instead:

/Users/craig/Code/ios/FrameworkDependencyDemo/SharedFramework/SharedClass.h:10:9: 'AFNetworking/AFNetworking.h' file not found /Users/craig/Code/ios/FrameworkDependencyDemo/ShareExtension/ShareViewController.h:11:9: Could not build module 'SharedFramework'

The same issue occurs if only the app target's code references the shared framework. It's important to note that the error occurs as Xcode is building either the app target or the extension target – the shared framework itself builds fine.

I looked at the Embed Pods Frameworks build step shell script for the app target and AFNetworking is in there at the bottom:

if [[ "$CONFIGURATION" == "Debug" ]]; then
  install_framework "$BUILT_PRODUCTS_DIR/AFNetworking/AFNetworking.framework"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
  install_framework "$BUILT_PRODUCTS_DIR/AFNetworking/AFNetworking.framework"
fi
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
  wait
fi

Though I noticed that AFNetworking's dependencies aren't in there – which might be related to #6123 or #6245?

I also came across #4254 which looks similar, but adding the de-duplication flag to a config file didn't address the issue for me (assuming I added it correctly).

Essentially my question is – is this approach supported? I couldn't find an explicit example anywhere in the documentation, and it seems like a common use case to me, but perhaps this is expected behaviour? If not, is this a bug, or am I missing some configuration somewhere? Thanks!

CocoaPods Environment

Stack

   CocoaPods : 1.2.0.beta.1
        Ruby : ruby 2.3.2p217 (2016-11-15 revision 56796) [x86_64-darwin15]
    RubyGems : 2.5.2
        Host : Mac OS X 10.11.6 (15G1108)
       Xcode : 8.1 (8B62)
         Git : git version 2.9.3 (Apple Git-75)
Ruby lib dir : /usr/local/Cellar/ruby/2.3.2/lib
Repositories : master - https://github.com/CocoaPods/Specs.git @ 1ca34e62c1b5bb3f19ee1c499d7de71611faa7fa

Installation Source

Executable Path: /usr/local/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

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

use_frameworks!

target 'FrameworkDependencyDemo' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  # Pods for FrameworkDependencyDemo

end

target 'SharedFramework' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  # Pods for SharedFramework
  pod 'AFNetworking'

end

target 'ShareExtension' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  # Pods for ShareExtension

end

Project that demonstrates the issue

https://github.com/craigmarvelley/FrameworkDependencyDemo

benasher44 commented 7 years ago

Hi @craigmarvelley! This should be fixed in #6216, which is on master and will be available in an upcoming release. I have a sample project setup that I think matches your setup here: https://github.com/benasher44/CocoaPodsLibExample. Can you try using CocoaPods master (and that sample setup as a reference) and see if that works for you?

craigmarvelley commented 7 years ago

Thanks for the assistance @benasher44 :) Your sample project builds for me, and there's an improvement with my sample project in that the framework's class and its dependencies are now fully resolved in the app target.

The extension target, however, still won't build. Looking at the build log it seems that the extension is being built before the framework. I've tried adding the framework as a target dependency of the extension as we've done with the app target and it now builds after the framework, but the original issue persists – AFNetworking's umbrella header isn't found.

I hacked the extension's Pod xcconfig file to include

FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/AFNetworking"

and

OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/AFNetworking/AFNetworking.framework/Headers"
OTHER_LDFLAGS = $(inherited) -framework "AFNetworking"

to match the app and framework Pod xcconfig files, and it built. So there's possibly an issue with CocoaPods not detecting that it needs to also relate the framework's dependencies to the extension?

craigmarvelley commented 7 years ago

Further to this: just noticed that in my proper app my unit test target is suffering from the same problem – it's unable to link to dependencies of the main app target in which it is embedded when use_frameworks! is on. Going back to static libraries solves the problem.

benasher44 commented 7 years ago

I have an idea for a solution, but it may take me some time to get to working on this fix. I haven't had as much time to sit down and work on larger CP fixes, so I appreciate your patience on this one!

craigmarvelley commented 7 years ago

No problem, appreciate you taking the time to look at it! Anything you need that I can help with, let me know.

peterwarbo commented 7 years ago

Any progress on this issue or is the only solution at the moment to create a framework project (not just a framework target) like here: https://github.com/benasher44/CocoaPodsLibExample ?

benasher44 commented 7 years ago

@petergoldstein I've been spread pretty thin for the last few months, so I haven't had time to look at this yet. I'm not sure a framework project will work any better than a framework target. The issue is that CocoaPods doesn't handle dependencies that are 2 levels deep into dependent targets (i.e. a pod that's used by framework, which is only used by an extension; framework pods would have to be embedded alongside the extensions in its apps, if that makes sense).

stale[bot] commented 7 years ago

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.

craigmarvelley commented 7 years ago

Would you mind keeping this open please, in the hope that it could be addressed at some point?

endocrimes commented 7 years ago

Looks like this got closed before https://github.com/CocoaPods/CocoaPods/commit/625156b57c9bc19c2abfc5928e7b866f753cb0d8 landed.

craig-miller commented 7 years ago

Is there a workaround?

vidugloeck commented 7 years ago

I have the same Problem. @craig-miller I think you could create a new pod with the dependencies declared in the podspec and publish it to a private pod repo. But this was actually my attempt on trying to avoid that. Has anyone a better idea?

kajensen commented 6 years ago

Why has this not been fixed yet?

dnkoutso commented 6 years ago

@kajensen if you want it fixed the fastest way to get it fixed is by contributing. CocoaPods is maintained and improved from free time of various people.

kajensen commented 6 years ago

Fair enough. Just confusing to me with how popular CP is that using an embedded framework in a project with cocoapods has been broken for 12 months.

Can you point me to where to get started? Seems like a high barrier to entry to start working on something like CP

dnkoutso commented 6 years ago

@kajensen unfortunately there is not enough documentation on the architecture of cocoapods. It's a good point you raise regarding someone who has experience to write one up. I might be doing that. In the meantime clone this repo and begin from installer.rb which is responsible for performing all steps with when pod install (or even pod update) executes.

Akhu commented 6 years ago

Hi everyone, Any news on this particular issue ? Thanks :)

che1404 commented 6 years ago

Hi, same problem here. Please let us know if we can provide more information to help solving this. Thanks!

lilyball commented 6 years ago

I'm hitting this issue as well. It does seem that the root cause is the appex xcconfig file is missing the configuration for the dependencies (it's missing FRAMEWORK_SEARCH_PATHS, OTHER_CFLAGS, and OTHER_LDFLAGS, though in my limited testing on the first is necessary for the build to succeed). Curiously, it's also missing OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" even though it has the equivalent for GCC_PREPROCESSOR_DEFINITIONS.

This makes me wonder if the appex xcconfig generation is somehow completely separate from the normal xcconfig generation? Because I can't think of any reason why OTHER_SWIFT_FLAGS would have been intentionally omitted here.

poetmountain commented 6 years ago

This issue has hit me as well when trying to build a shared framework to support an extension.

sgtsquiggs commented 6 years ago

I also have this issue. An ugly workaround is to copy your Framework's dependencies to your App's dependencies; this becomes very ugly when you have a static framework (GoogleMaps for example) and now you have a static library doubly linked.

To resolve this, Cocoapods will need to inspect the project for Target B and see that Target A is being imported by Target B, and link libraries accordingly.

lilyball commented 6 years ago

My current workaround is to add a post_install hook that manually fixes up the properties on my appex targets and re-saves the xcconfigs back to disk.

Jignesh1805 commented 6 years ago

Hi dnkoutso , Please can help me . Regarding third party framework add in podspec file .

JulesMoorhouse commented 6 years ago

Sigh, this really big issue for me :(

ljbdelacruz commented 5 years ago

when creating new project i also ecounter this problem can some please help me with this much appreciated tried uninstalling and installing the xcode same problem but works fine in simulator

screen shot 2018-10-30 at 10 02 21 pm
Jignesh1805 commented 5 years ago

when creating new project i also ecounter this problem can some please help me with this much appreciated tried uninstalling and installing the xcode same problem but works fine in simulator

screen shot 2018-10-30 at 10 02 21 pm

Hi ... Please see me your .podspec file

Jignesh1805 commented 5 years ago

when creating new project i also ecounter this problem can some please help me with this much appreciated tried uninstalling and installing the xcode same problem but works fine in simulator

screen shot 2018-10-30 at 10 02 21 pm

Hi ... Please see me your .podspec file

Add this line you can solve this issue s.resources = "/*/.{png,jpeg,jpg,storyboard,xib}"

dominik-hadl commented 5 years ago

@lilyball Could you please share your post_install for others to use if possible? I am struggling with the same issue and it is very annoying.

lilyball commented 5 years ago

@nickskull Here's what our post_install does. We haven't touched it in a while so I don't know if there are any other build settings it should be doing, but this has been working so far. It's pretty gross though.

post_install do |installer|
  pods_dependency = installer.aggregate_targets.find { |aggregate_target| aggregate_target.label == "Pods-DependentFramework" }
  if pods_dependency.nil? then
    Pod::UI::warn "Could not find aggregate target for Pods-DependentFramework; appex targets will likely fail to build"
    return
  end

  # Fix up app extensions
  ["Pods-App-MessageExtension", "Pods-App-TodayExtension"].each do |app_label|
    pods_aggregate_target = installer.aggregate_targets.find { |aggregate_target| aggregate_target.label == app_label }
    if pods_aggregate_target.nil? then
      Pod::UI::warn "Could not find aggregate target for #{app_label}; appex target will likely fail to build"
      next
    end
    pods_aggregate_target.xcconfigs.each do |configuration, xcconfig|
      pods_dependency_xcconfig = pods_dependency.xcconfigs[configuration]
      if pods_dependency_xcconfig.nil?
        Pod::UI::warn "Could not find xcconfig for Pods-DependentFramework configuration #{configuration}"
        next
      end

      # The frameworks property controls the OTHER_LDFLAGS
      if xcconfig.frameworks.intersect?(pods_dependency_xcconfig.frameworks) then
        Pod::UI::warn "#{app_label} (#{configuration}) and Pods-DependentFramework both contain framework(s) #{xcconfig.frameworks.intersection(pods_dependency_xcconfig.frameworks).inspect}",
                      ["Check if CocoaPods has fixed the issue with propagating dependencies from DependentFramework to the app extensions.",
                        "If so, update the Podfile to remove the code for doing this manually."]
      end
      xcconfig.frameworks.merge(pods_dependency_xcconfig.frameworks)

      # Update FRAMEWORK_SEARCH_PATHS
      if !merge_build_setting(xcconfig, pods_dependency_xcconfig, "FRAMEWORK_SEARCH_PATHS") then
        Pod::UI::warn "DependentFramework (#{configuration}) does not define FRAMEWORK_SEARCH_PATHS",
                      ["The Podfile should be updated."]
      end

      # Update OTHER_CFLAGS
      if !merge_build_setting(xcconfig, pods_dependency_xcconfig, "OTHER_CFLAGS") then
        Pod::UI::warn "DependentFramework (#{configuration}) does not define OTHER_CFLAGS",
                      ["The Podfile should be updated."]
      end

      # Copy OTHER_SWIFT_FLAGS
      if !["", "$(inherited)"].find_index(xcconfig.attributes.fetch("OTHER_SWIFT_FLAGS", "")).nil? then
        other_swift_flags = pods_dependency_xcconfig.attributes.fetch("OTHER_SWIFT_FLAGS", "")
        if ["", "$(inherited)"].find_index(other_swift_flags).nil? then
          xcconfig.merge!("OTHER_SWIFT_FLAGS" => other_swift_flags)
        else
          Pod::UI::warn "DependentFramework (#{configuration}) does not define OTHER_SWIFT_FLAGS",
                        ["The Podfile should be updated."]
        end
      else
        Pod::UI::warn "#{app_label} (#{configuration}) defines OTHER_SWIFT_FLAGS",
                      ["It's defined as '#{xcconfig.attributes["OTHER_SWIFT_FLAGS"]}'",
                        "The Podfile should be updated."]
      end

      # Save back to disk as CocoaPods has already written it out itself.
      xcconfig.save_as(pods_aggregate_target.xcconfig_path(configuration))
    end # pods_aggregate_target.xcconfigs.each
  end # [app targets].each
end

Also we're still on CocoaPods 1.5.3 (due to an issue which the just-released 1.6.2 finally fixes so we'll be trying that out shortly), so I'm not sure if CocoaPods 1.6.x or 1.7.x affects what we're doing here at all.