Cocoapods: pods are always installed for iOS 8 deployment target instead of iOS 9

Created on 8 Jan 2018  路  51Comments  路  Source: CocoaPods/CocoaPods

Report

What did you do?

  1. Create a new Xcode 9.2 project "example" for iOS Swift
  2. Change deployment target to iOS 9.0
  3. Use a Podfile with:
platform :ios, '9.0'
use_frameworks!

abstract_target 'default_pods' do
    pod 'AFNetworking', '~> 3'
    target 'example'
end
  1. Run pod install or pod update

What did you expect to happen?

AFNetworking is installed with a Deployment Target of iOS 9.0.

What happened instead?

AFNetworking is installed with a Deployment Target of iOS 8.0, which causes noticeable warnings like _/Users/coeur/example/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m:163:30: 'setResumingHandler:' is only available on iOS 9.0 or newer_

Even if I manually change the Pods project Deployment Target to iOS 9.0, a simple pod update will reset it to iOS 8.0.

CocoaPods Environment

  • CocoaPods 1.4.0.rc.1 (also reproduced with CocoaPods 1.3.1)
  • Xcode 9.2 & High Sierra

Project that demonstrates the issue

https://github.com/Coeur/CocoaPods7314

awaiting input

Most helpful comment

I found the following workaround, adding a post_install hook:

platform :ios, '9.0'
use_frameworks!

abstract_target 'default_pods' do
    pod 'AFNetworking', '~> 3'
    target 'example'
end

post_install do |pi|
    pi.pods_project.targets.each do |t|
        t.build_configurations.each do |config|
            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0'
        end
    end
end

All 51 comments

I found the following workaround, adding a post_install hook:

platform :ios, '9.0'
use_frameworks!

abstract_target 'default_pods' do
    pod 'AFNetworking', '~> 3'
    target 'example'
end

post_install do |pi|
    pi.pods_project.targets.each do |t|
        t.build_configurations.each do |config|
            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0'
        end
    end
end

Can you please provide a sample project and use the template given to you when you file a new issue?

@dnkoutso Done, with a screenshot.

@Coeur still dont think its a CocoaPods bug. The podspec of AFNetworking sets deployment target to 7.0 but I think because you are using Xcode 9.2 which does not contain iOS 7.0 it defaults to the next available version.

https://github.com/CocoaPods/Specs/blob/d0ec5a65e80656c8d78e12ff19f251df879e0bc2/Specs/a/7/5/AFNetworking/3.1.0/AFNetworking.podspec.json#L21

Podspecs can define their own deployment target which gets set by the CocoaPods library.

I do not see any particular issue with CocoaPods library here. Will close this one but please reply here if you feel strongly there is an issue here...

Yes, Xcode 9 drops iOS 7.0 support so that's why you get iOS 8.0 instead despite the podspec mentioning 7.0

https://stackoverflow.com/questions/45640715/how-to-set-up-xcode-9-for-iphone-4-and-iphone-4s-development

@dnkoutso , you mean that in a Podspec, I can only forcibly define an _exact_ Deployment Target, I can't simply define the _minimal_ supported Deployment Target?

When I write a Podspec, I use platforms.ios to define what is _at least_ required to build, not to define what _must_ be built.

In all case, no matter the Podspec, it is an integration bug from CocoaPods to build for iOS 8+ when we want an iOS 9+ project.

@dnkoutso @Coeur
How to specify two different platforms in a pod,
I have two target, respectively, support for iOS 8 and iOS 9, how to distinguish?

I do not think this is supported currently.

@Jinxiansen , it doesn't even work for one single platform as described by this bug report. But if one day there is support for multi platforms, then the documentation will tell you. One suggestion could be:

abstract_target 'default_pods' do
    target 'One' do
        platform :ios, '8.0'
    end
    target 'Two' do
        platform :ios, '9.0'
    end
end

It's pure suggestion for the future: this is in no way a working piece of configuration in 2018

@Jinxiansen don't forget you have to do pod install (or pod deintegrate && pod install) to get the post_install to execute at least once. It will not work with only pod update.

I think the deployment target version should be equal to the user target version.

If the pod target's deployment version is equal to iOS 9 which define by user target, the dependency will use their new api if they check the deploy version:

#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1100)
            configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:configurationIdentifier];
#else
            configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:configurationIdentifier];
#endif

The code from the AFNetworking. In the podspec, there is a platforms":{"ios":"7.0","osx":"10.9","tvos":"9.0"}. So the pod target is deploy to iOS 7.0, and the macro will always be false! AFNetworking will always use the old api.

@dnkoutso

So, I have UICKeychainStore in Pods.xcodeproj.

Pods.xcodeproj has deployments targets:

Pods (Project) -> 9.0
UICKeychainStore -> 8.0

My App deployment target -> 9.3

I would like to keep them in sync in case of aesthetics.

@Coeur
If you can't reopen issue and it have not solved yet, it is time to make open-radar for CocoaPods.

+1

I was hoping the deployment target would be defined according to the platform specified.

platform :ios, '9.0'

Coeur's multiple platforms script seems wrong. I write a new one.

post_install do |pi|
    # https://github.com/CocoaPods/CocoaPods/issues/7314
    fix_deployment_target(pi)
end

def fix_deployment_target(pod_installer)
    if !pod_installer
        return
    end
    puts "Make the pods deployment target version the same as our target"

    project = pod_installer.pods_project
    deploymentMap = {}
    project.build_configurations.each do |config|
        deploymentMap[config.name] = config.build_settings['IPHONEOS_DEPLOYMENT_TARGET']
    end
    # p deploymentMap

    project.targets.each do |t|
        puts "  #{t.name}"
        t.build_configurations.each do |config|
            oldTarget = config.build_settings['IPHONEOS_DEPLOYMENT_TARGET']
            newTarget = deploymentMap[config.name]
            if oldTarget == newTarget
                next
            end
            puts "    #{config.name} deployment target: #{oldTarget} => #{newTarget}"
            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = newTarget
        end
    end
end

Add this to the Podfile, then pod install may generate output like

...
Generating Pods project
Make the pods deployment target version the same as our target
  AFNetworking
    Release deployment target: 7.0 => 9.0
    Debug deployment target: 7.0 => 9.0
    Alpha deployment target: 7.0 => 9.0
  FLEX
    Release deployment target: 8.0 => 9.0
    Debug deployment target: 8.0 => 9.0
    Alpha deployment target: 8.0 => 9.0
...

@BB9z, I'm unsure what you mean by "seems wrong", as I'm successfully using the 7 lines workaround from my January 8th post.

But best thing would be to have the fix at CocoaPods level, so if you're confident you should make a pull request to fix CocoaPods regarding this.

@Coeur assume we had a podfile:

target 'One' do
    platform :ios, '8.0'
    pod 'A'    # A has a deployment target 6.0, we want it build with 8.0
    pod 'B'   # B has a deployment target 7.0, we want it build with 8.0
end

target 'Two' do
    platform :ios, '9.0'
    pod 'A'    # A has a deployment target 6.0, we want it build with 9.0
    pod 'B'    # B has a deployment target 7.0, we want it build with 9.0
end

In my options, your script will define the deployment targets for "One" and "Two" respectively. But actually, you change nothing. t.name is the name of the pod target, not our application.

pi.pods_project.targets.each do |t|
  # t is pod target, not our app target
  p t.name # will log A and B
end

@BB9z The workaround from my January 8th post (second post of this thread) is certainly not for mixing deployment targets: it's for the issue reported in the preceeding post (first post of this thread), with a single desired deployment target (iOS 9 for instance).

I don't understand why people are diverging the discussion on supporting multiple deployment target when it doesn't even work correctly for one single unique deployment target: if the target is built for 9.0, then the Pods should build for 9.0, not for 8.0. That's all there is in this issue report.

It's nice to want to support more stuff, but it should come as fixes to the actual CocoaPods gem, not as complex workarounds in people's Podfile. This is an issue ticket, not a StackOverflow post. :)

It seems that it would make sense to bump the deployment target to the user project's value if it is higher than the podspec's deployment target. @dnkoutso can you think of any issues that may arise from doing that?

@amorde If person has one project/workspace for several targets ( for example, several "typical" targets ), these targets could be out of sync in "deployment target dimension", but Pods are shared between these "typical" targets.

Typical targets are either app extensions or cloned apps ( some teams have clones of their main app for rebranding reasons before "big daddy money income").

ah, I forgot that a target can specify a deployment target _lower_ than the project one. bummer.

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.

I believe the issue is duplicated with this one: https://github.com/CocoaPods/CocoaPods/issues/8069 but for my opinion current issue is better described

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.

@stale please keep it open.

Could somebody tell me why the CP use the min deployment version which be defined in the podspec. I could not find the reason.

@Whirlwind

Well, I can try... the truth is in License...

Read carefully...

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR...

Any ETA on a fix for this? It's extremely frustrating to have this revert every time we do a pod install or pod update.

@GiantBlue76 with a post_install hook, as shown in the second post of the thread, the configuration is kept even after pod install or pod update.

And no, there won't be any ETA until someone gets their hands at a pull request. Could be you, could be anyone.

@GiantBlue76 with a post_install hook, as shown in the second post of the thread, the configuration is kept even after pod install or pod update.

And no, there won't be any ETA until someone gets their hands at a pull request. Could be you, could be anyone.

Thank you! This is a sufficient workaround. Much appreciated!

We should be treating this as a _minimum_, but there are certain situations this isn't handled properly.

I'll have a PR up for this relatively soon - targeting 1.8.0 release for this

I updated the script mentioned in this comment for those who:

  • Use the new generate_multiple_pod_projects feature
  • Want to prevent warnings for pods which have too low deployment target versions

To use this script run

pod deintegrate
pod install
source 'https://cdn.jsdelivr.net/cocoa/'

# This is your app's deployment target version
DEPLOYMENT_VERSION = '12.0'.freeze
DEPLOYMENT_TARGET_KEY = 'IPHONEOS_DEPLOYMENT_TARGET'.freeze
# All pods will have at least this version to prevent Xcode warnings
PODS_MIN_DEPLOYMENT_VERSION = '8.0'.freeze

platform :ios, DEPLOYMENT_VERSION
use_modular_headers!

install! 'cocoapods',
         generate_multiple_pod_projects: true,
         incremental_installation: true

target 'YourTarget' do
 # Insert your pods

  target 'YourTargetTests' do
    inherit! :complete
    # Insert your test pods

  end
end

def fix_deployment_targets(installer)
  installer.generated_projects.each do |project|
    project.targets.each do |target|
      target.build_configuration_list.build_configurations.each do |config|
        if config.build_settings[DEPLOYMENT_TARGET_KEY].to_f < PODS_MIN_DEPLOYMENT_VERSION.to_f
          config.build_settings[DEPLOYMENT_TARGET_KEY] = PODS_MIN_DEPLOYMENT_VERSION
          puts "Successfully set #{DEPLOYMENT_TARGET_KEY} of target #{target.name} for config #{config.display_name} to #{PODS_MIN_DEPLOYMENT_VERSION}"
        end
      end
    end
  end
end

post_install do |installer|
  fix_deployment_targets installer
end

My 2 cents: CocoaPods should not change a defined minimum deployment target. There is no bug here other than user error: trying to use a library with an unsupported minimum deployment target. The correct answer to this problem is for AFNetworking to drop support for iOS 7. FWIW it looks like they did do this recently: https://github.com/AFNetworking/AFNetworking/commit/b3c4a78aca208f4dae596968b3dffb39bb44efa6

Edit to add: On further thought, I'd almost consider it a bug that CocoaPods set the deployment target to 8 to begin with, if the podspec said 7. It should either fail to pod install altogether or correctly set the version to 7 and let Xcode fail to compile (refusing to pod install would be "nicer" IMO).

After thinking about this some more I agree with the above. CocoaPods is doing the right thing by following what the podspec claims to support, and if pod consumers want to change that they can do so using a post_install hook. At this point I don't consider this a bug.

@amorde The first line of the Podfile being platform :ios, '9.0', setting the xcconfig for an older version of iOS is the issue.

@Coeur that is the target platform for your project, not for each Pod that you want to include. It informs CocoaPods which compatible versions of dependencies to pull in.

There seems to be a misconception among folks in this thread about what a minimum deployment target means and the effects of setting one.

There are runtime API availability checks that can be used to properly support multiple versions of iOS in a single executable. The minimum deployment target lets a library or application run correctly on that version or higher. Furthermore updating the minimum deployment target can cause complication to fail (for deprecated methods that are removed), therefore it is not a good idea for a tool like this to change it.

@icecrystal23 please give us an example of such compilation failure when raising the minimum deployment target up.

If we (@amorde, @icecrystal23) consider it's not a bug, then we should change the documentation of platform in the Podfile to be clear that platform :ios, '9.0' isn't going to do what many people want.

We could write something like:

platform

Specifies the platform for which a static library should be built, but NOT the deployment target for which it should be built (the number in platform :ios, '9.0' is only to find a compatible version of the pod). The actual deployment target will be lower than specified, will have unused symbols and will cause you a lot of headache. To properly set the minimum deployment target, please always manually add a workaround like:

post_install do |pi|
   pi.pods_project.targets.each do |t|
       t.build_configurations.each do |bc|
           bc.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0'
       end
   end
end

where '9.0' is your actual minimum deployment target.

Looks like the most common error I see is actually a warning, but we tend to have "Treat warnings as errors" enabled so it causes failures in our libraries. Example, when moving the deployment target from 10 to 11:
'bottomLayoutGuide' was deprecated in iOS 11.0: Use view.safeAreaLayoutGuide.bottomAnchor instead of bottomLayoutGuide.topAnchor

Note that this will cause the behavior to be wrong even if it doesn't actually cause compilation to fail (ie, if you treat it as a warning instead of an error).

+1 to updating the documentation, however I still disagree with the assumption that the behavior you want is the behavior many people want. Either way, the documentation should be correct and clear about what the setting actually does.

+1 to this is a bug.

I write a SDK, and it supports iOS 6 and later. But I don't hope that user compile it with iOS 6, and I hope the user compile it with the latest iOS version ( or they support deploy version, eg: iOS 10).

I did many things to support new api to get better development way. But now, the CocoaPods will never compile the Pods target to use new api. As a SDK owner, I could not let my user use new api, it is too bad.

And, I am a developer for a app, too. I still hope use new api, but the CocoaPods could not support it. It is too bad.

Of cause, I could write a post_install to fix it. But It is not a good way. I have 3 app targets with different deploy target version, it is too hard to write a hook.

Maybe, we could have a dsl to choice the way to user.

@icecrystal23

Am I right that you are talking about these two sets:

|Pod Deployment target|SDK Version|App Deployment Target|
|---|---|---|
|10.0|12.3|11.0|
|11.0|12.3|11.0|

Next, you are talking that behavior will be different if you switch these settings from set 1 to set 2 ( by updating dependency deployment target version to your app deployment target. ).

Is it correct now?

Next, in these assumptions, your app will be installed on devices with OS version _greater than or equal_ to App Deployment Target.

  1. So, if an old framework has small deployment target and uses old symbols that _are_ removed or _obsoleted_ or _deprecated_ in newer OS versions, it _will compile_ and perfectly linked to your project?

  2. But if you increase deployment target of this framework, it will cause errors and warnings and will block further development in case of deprecated/removed/obsoleted old stuff?

@lolgear mostly yeah. The point is that the library was developed using a specific minimum deployment target in mind. It will compile and link and work fine in an app with a higher minimum deployment target.

I did a little testing with a sample app and changing the minimum deployment target around. It appears that bottomLayoutGuide seems to function correctly no matter which target is chosen. Changing the minimum deployment target to something higher seems to have no effect other than causing compilation warnings.

I don't understand what benefit would be gained from updating the minimum deployment target to something higher than what the library was written for. New APIs can still be accessed using availability APIs, like this:

if #available(iOS 11.0, *) { /* do new stuff */ } else { /* do old stuff */ }

@icecrystal23

I don't understand what benefit would be gained from updating the minimum deployment target to something higher than what the library was written for. [...]

I've posted this in #4859, but it seems very relevant here:

Since I have a deployment target of iOS 12 in my main app, my app doesn't build arm 32-bit code, but since some of the pods have a much lower deployment target they do. This leaves me with linking errors when I'm trying to archive the app, and the only fix I've found is to bump the deployment target to 12 on all my pods as well.

I think it would be very neat if CocoaPods could always propagate my platform :ios, '12.0' down to the individual pods deployment target. That way all pods would be optimized to run for the appropriate platform!

https://github.com/CocoaPods/CocoaPods/issues/4859#issuecomment-500838635

@LinusU you are then consuming the Pods in a way not intended by the authors. You can choose to apply that workaround, but it is not a good general policy that should be blindly applied to all pods.

@icecrystal23 you're probably wrong about that: pod authors may support MULTIPLE versions of iOS, while the podspec only let us define the minimum one.

[...] but it is not a good general policy that should be blindly applied to all pods.

I don't really see how that is sustainable, should I _only_ use pods that specifically targets iOS 12? That seems quite strange. Surely there should be no ill effects by compiling with a newer deployment target? 馃

You guys are still acting like you can't run a library built for iOS 8 on iOS 12. You can. It is a minimum deployment target. Meaning the library supports iOS 8 and newer.

I don't know what linker errors you are getting, but in general you can compile and link with older minimum targets just fine.

@LinusU A workaround for the specific issue of dropping 32-bit code when targeting iOS 11+ is to set ARCHS = "$(ARCHS_STANDARD_64_BIT)" in your app target. CocoaPods _does_ automatically copy this setting to all Pods targets. (Xcode will give an "update to recommended settings" warning about this, but that seems like a lesser evil.)

@Westacular that's amazing, thanks!!

edit: I haven't been able to trigger this, would you mind elaborating on when it does that?

Xcode will give an "update to recommended settings" warning about this, but that seems like a lesser evil.

edit2: Ahhhh, read that the other way around, I thought that Xcode would ask me to go to ARCHS_STANDARD_64_BIT if I targeted iOS 11+ 馃槃

Hmm, I wonder why it doesn't use ARCHS_STANDARD_64_BIT for iOS 11+ then 馃

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.

This issue will be auto-closed because there hasn't been any activity for a few months. Feel free to open a new one if you still experience this problem :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

soleares picture soleares  路  3Comments

intelliot picture intelliot  路  3Comments

iosdev-republicofapps picture iosdev-republicofapps  路  3Comments

marzapower picture marzapower  路  3Comments

Mingmingmew picture Mingmingmew  路  3Comments