Run pod install
, then try to compile with Xcode 9 beta 1.
All pod dependencies are compiled using Swift 3.2. Checking the Pods project, I'd expect to see all the various frameworks have the Swift Language Version
set to 3.2
The various frameworks in the Pods project have the build setting Swift Language Version
set to Swift 4.0
, and are compiled as such. Therefore, I'm seeing many compilation errors.
Is there a way for me to force Xcode to use a Swift version per pod?
CocoaPods : 1.2.0
Ruby : ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin16]
RubyGems : 2.5.1
Host : Mac OS X 10.12.4 (16E195)
Xcode : 9.0 (9M136h)
Git : git version 2.7.0
Ruby lib dir : /usr/local/Cellar/ruby/2.3.0/lib
Repositories : master - https://github.com/CocoaPods/Specs.git @ 5bd03fef224221ba8a5cdf67ba2102be7fe5216b
Executable Path: /usr/local/bin/pod
cocoapods-deintegrate : 1.0.1
cocoapods-plugins : 1.0.0
cocoapods-search : 1.0.0
cocoapods-stats : 1.0.0
cocoapods-trunk : 1.1.2
cocoapods-try : 1.1.0
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'Project' do
use_frameworks!
pod 'PureLayout', '~> 3.0.2'
pod 'Anchorage', :git => 'https://github.com/Raizlabs/Anchorage.git', :tag => '4.0.0'
pod 'BuddyBuildSDK'
pod 'SwiftTweaks', :git => 'https://github.com/Khan/SwiftTweaks.git', :tag => 'v2.0-beta.1'
pod 'RealmSwift'
pod 'SwiftGen'
pod 'NVActivityIndicatorView', '~> 3.6.1'
target 'ProjectTests' do
inherit! :search_paths
# Pods for testing
end
target 'ProjectUITests' do
inherit! :search_paths
# Pods for testing
end
# Enable DEBUG flag in Swift for SwiftTweaks
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == 'SwiftTweaks'
target.build_configurations.each do |config|
if config.name == 'Debug'
config.build_settings['OTHER_SWIFT_FLAGS'] = '-DDEBUG'
end
end
end
end
end
end
Probably needs to be updated to automatically use Swift 4.0. Xcode 9 is brand new however your post install hook should be a good workaround for now. This will be getting fixed.
@dnkoutso might finally be time to add something to the spec dsl, to know which version to integrate as :( - fallback to 3.x if not set?
yeap. seems like it.
Thing is, pods might support multiple swift versions, so pods should be able to specify a range of swift versions.
If a pod supports more than one swift version, a user should be able to specify which swift version they want in their Podfile? Or should that selection happen based on the (users) project's swift version?
Swift 3.2 and 4.0 can exist in a single project. In my opinion it makes no sense to compile a pod with Swift 3.2 when it also supports 4.0. A user's 3.2 target could use the 4.0 pod.
Yeah, we've been cautious because each Xcode release (7, 8 & 9 now) has had different rules about how it handles Swift, and the Swift toolchain. If we added rules at 7 and 8, both would be deprecated by the different 9 + Swift 3 +4 rules. So It's worth being super careful with adding DSL attributes in the Podfile for this.
Wouldn't that be a justification for adding a Podfile
override on a per Pod basis? In case a future Xcode version has some weird unsupported behaviour, the user can manually specifiy the swift version instead of waiting on a CocoaPods release?
The problem is that what we'd need to do changes with each release, because those constraints change, so it'd be deprecated quickly. The careful consideration needs to be that any additions to the Podfile can happen, but removals or changes to behaviour are a semver breaking change and need be done in a very long-term way
The solution will need careful consideration of course, but the time for one has come. Apple officially supports mixed dependencies with Swift 3.2 and 4. CocoaPods needs to be able to set the Swift version on a per-pod basis, there's no way around that now. I think a versioning scheme can be created that can work independently of Xcode versions with only minor updates needed over time to connect Swift versions with Xcode version. Frankly, I think it has been possible for years now, with the only real difficultly being how Xcode indicates version support. Even there, nothing has changed between Xcode 8 and 9, so I think SWIFT_VERSION
is here for good.
The problem is that what we'd need to do changes with each release
That's totally normal for Xcode development. imo you should see it the other way around: whatever you decide now only matters for one year, then it'll need to get changed anyway 馃槣
Sorry to nag but is a solution to this being worked on in a branch somewhere? Or is this being given serious consideration for attention soon?
I'm asking b/c XC9 will most likely be out in 2 months... if the patterns of past years are any indication. I'd like to migrate my app's code to Swift 4, and still use my Swift 3 pods. And did I mention that I really dislike post-install hooks?
Part of the cool thing about XC9 is that Swift3 and Swift4 can co-mingle like this. It would be awesome if Cocoapods could accommodate this. I recently started a brand-new project, and briefly considered using Swift 4, until I hit this problem. I understand that not everyone is starting new projects, or is interested in jumping to the latest Swift right now. But I don't think that I'm such an outlier as one who wants to upgrade to the latest Swift sooner rather than later.
So, I guess this is just my upvote in the hope of getting this addressed soon. Thanks for listening.
This may be the same issue, but in my podspec I have dependencies on pods that need to compile using Swift 3.2. The code of my pod (the one described by the podspec) needs Swift 4.0. If I build with Xcode9 (e.g., beta 4), I get no errors. If I attempt to build with Cocoapods prior to uploading a new pod version (pod lib lint --sources="https://github.com/crspybits/Specs.git,https://github.com/CocoaPods/Specs.git" --allow-warnings
), the build fails. E.g.:
- ERROR | [iOS] xcodebuild: Gloss/Sources/ExtensionArray.swift:76:63: error: initializer 'init()' is internal and cannot be referenced from a default argument value
Let me know, and I can open this as a separate issue if needed.
This feature looks like a good place for someone to try and contribute back, as I've heard of no-one looking at this.
@crspybits CP lints with whatever version of Xcode you had set for your CLI, so if it passed in XC9 then it passes That doesn't mean it would pass on 8, 7, 6 etc. It'd be folly for CP to try support something like that
I didn't realize that about lint. That makes some sense.
This appears not limited to lint though. I get the same issue with pod repo push crspybits-specs SyncServer.podspec --sources="https://github.com/crspybits/Specs.git,https://github.com/CocoaPods/Specs.git" --allow-warnings
(unless this also is running lint).
It seems that right now it's not possible to have a Cocoapod where the main code (specified in the .podspec) uses Swift 4 and dependent pods use, say, Swift 3.2. I am using Cocoapods version 1.2.1, so don't know if this changes with the forthcoming version update. Nope. Just installed 1.3.0.rc.1 and the situation is the same.
this works:
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == '<insert target name of your pod here>'
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '3.0'
end
end
end
end
It's not pretty but will do until they update your pods to Swift 4.
@DanielCreagh That's been a know solution for previous Swift versions, but the issue keeps appearing each year, which is why we're asking for a built in solution. Also, you'll have to look up what swift version is supported by each pod, and that if
test can become quite long if you have a project with many pods with mixed swift versions.
The best solution is if a pod can specify supported swift version(s), and CocoaPods does it's own thing automatically.
What's standing in the way of adding a property to the podspec that indicates Swift version compatibility? Apple is explicit about their support for gradually moving to Swift 4 and mixing different Swift versions where needed. The need for Cocoapods to properly support this will only grow, IMO.
I've made PromiseKit support Swift 3.0, 3.1, 3.2 & 4.0. I recommend all pod authors consider it: means whatever CocoaPods does is fine.
Edit: also considering the differences between Swift 3 and 4 are much less vast, and you can do #if swift(>=3.2)
since Swift 3 this is actually a pretty straight forward thing to do. It took me an hour to port PromiseKit in a backwards compatible way.
@mxcl - Do you have a guide on how to update a pod for a specific version of swift? We have some private in house pods that I've been asked to update to swift 4 and I can't find much online about it.
@niallwatchorn for PromiseKit I have an .xcodeproj
(so it works with Carthage as well), so I opened that with Xcode 9 and set the Swift Version to 4.0. If you don't have an xcodeproj then I'm not sure what to advise.
Then to ensure the support is maintained I have a hefty CI matrix.
Edit: Thinking about it, this doesn鈥檛 guarantee CocoaPods support (there may be minor differences due to the Podspec鈥檚 specifications). Really I should get the CI to run pod lib lint
for each configuration too.
Looks like no fix for this yet? We're at Xcode9 GM Seed...
A generalization on @DanielCreagh for those who don't know much Ruby (like me!):
post_install do |installer|
# Your list of targets here.
myTargets = ['AlignedCollectionViewFlowLayout', 'JVFloatLabeledTextField']
installer.pods_project.targets.each do |target|
if myTargets.include? target.name
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '3.2'
end
end
end
end
for those who don't know much Ruby (like me!):
Right. Me either. And that's my only frustration with finding issues in Cocoapods. (sorry, minor editorial here).
In my career, I've worked with several languages, but never Ruby. I'm 100% Swift now. So, when I see comments like "This feature looks like a good place for someone to try and contribute back"... I don't disagree, but I also don't feel like I'm equipped to do that. I have no experience with the language, no idea what the dev environment would be or how to debug it. It's a bit daunting.
Cocoapods is a colossal engineering achievement, and I absolutely love it and am eternally grateful to all of those who have worked on it so tirelessly. I wish there were a "Never done Ruby, and want to patch Cocoapods -- here's the guide". Does such a thing exist?
Did you check out the CocoaPods Guides website? We have 5 on contributing back to CocoaPods on the homepage. Obviously we can't cover everything, but it's been enough for most contributors.
thanks for the tip. I don't think I've ever scrolled down that far on the Guides page. Nice to know that the resource exists.
For most people this is what you want:
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '3.2'
end
end
end
This makes Xcode build all your pods with Swift 3.2.
Why do we need to add a property to the podspec? Isn't "specifying the version of Swift used in this pod" the explicit reason for the .swift-version
file?
The current solution for us is to simply use Swift 3.2 until all pods are compatible, to do so all I had to do was update my .swift-version
file from 3.0
to 3.2
and then run pod update
and things worked flawlessly!
@kdbertel .swift-version
is currently used only for linting pods. The Swift version the pod will be build with is derived from the project settings, as far as I can tell.
@mostafaberg That is an untenable solution when we have a dozen pods that we need to one-by-one convert up to Swift 4. We need the ability to control what version of Swift each pod is built with.
@robinkunde It appears to be the settings of the hosting application, which is problematic, because it means you can't have a Swift 3.2 application bring in a Swift 4 pod, or vice-versa.
@kdbertel That's possible, you can do similar in your Podfile. Where swift_32
contains the pods I want to lock to Swift 3.2 and swift4
contains the pods I want to lock to Swift 4. All other pods will use setting set by Xcode/CocoaPods.
swift_32 = ['RxSwift', 'RxCocoa']
swift4 = ['PalaverKit']
post_install do |installer|
installer.pods_project.targets.each do |target|
swift_version = nil
if swift_32.include?(target.name)
swift_version = '3.2'
end
if swift4.include?(target.name)
swift_version = '4.0'
end
if swift_version
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = swift_version
end
end
end
Of course, this isn't automatic behaviour. But it does allow you to migrate your pods over one-by-one in current versions of CocoaPods.
@kylef That requires the consuming application to happen to magically know what version of Swift all of its component pods are targeting, which is again untenable. A given pod needs to be able to specify what version of Swift it is targeting, so that consuming applications don't need to care.
I took over the UberRides
pod recently and migrated it to Swift 4, expecting I could support 3.2/4 codebases without having to make it compile in both Swift versions. In this case, I need to tell my Pod consumers using Swift 3.2 to add post_install
tags, which makes no sense.
the problem with the post_install hook solutions is that they are useless when running pod lib lint
or pod push
A possible solution could be for cocoapods to not override SWIFT_VERSION
at all.
Each pod that supports Swift 4 could explicitly define the following in its podspec file:
spec.xcconfig = { 'SWIFT_VERSION' => '4.0' }
In your project's podfile instead (just for the time being):
post_install do |installer|
installer.pods_project.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '3.2'
end
end
In this way, all the pods dependencies will default to SWIFT_VERSION = 3.2
, but pods that override that setting in their podspec will build using swift 4.0.
This is working perfectly for me now with a mix of some pods built with swift 4.0 and 3.2
post_install do |installer|
installer.pods_project.targets.each do |target|
if ['Kingfisher', 'RxSwift', 'RxCocoa'].include? target.name
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '3.2'
end
end
end
end
I agree with @orta and @jshier about being cautious to avoid adding to the Podfile DSL.
I also agree with @edjiang that it doesn't make sense for consumers of a CocoaPod to need to know its compatible Swift versions.
How about a solution like this?
Pod owners are encouraged to specify their highest supported version using:
spec.xcconfig = { 'SWIFT_VERSION' => '4.0' }
(as @valeriomazzeo mentioned above)
pod spec lint
should generate a warning if SWIFT_VERSION
is unspecified
pod install
should use set SWIFT_VERSION
to the oldest Xcode-supported version (currently 3.2
for Xcode 9) if it's unspecified in the PodspecSWIFT_VERSION
to something lower than the highest supported version for some reason are welcome to do so in the post_install
hook.@getaaron Sorry, but while that's pretty much the current workaround, it's certainly not an acceptable solution long term. CocoaPods users shouldn't have to care about what versions of Swift a dependency is compatible with except when their toolset doesn't support any of them.
Given that the Swift team has already stated that the next version of Swift with be a hybrid 4 / 5 compiler, it seems very likely the situation will remain unchanged from present, so a solution is needed long term. I suggest the following:
swift_versions
(name subject to bikeshedding), which contains the Swift versions a library is compatible with. For instance, Alamofire is currently compatible with 3.1, 3.2, and 4.0, so we'd list it like this: swift_versions = { '3.1', '3.2', '4.0' }
(or whatever the appropriate Ruby syntax would be). pod install
, CocoaPods would continue it's current behavior if there was no swift_versions
attribute from the pod and assign the project's SWIFT_VERSION
. However, if swift_versions
is present, it would attempt to see if the project's SWIFT_VERSION
is present in the list. If so, it would use that version. If not, one final check can be performed. CocoaPods can check to see if the project version and any of the swift_versions
exist in the hybrid pairs supported by the Swift compiler. So a project that uses Swift 4 can install Swift 3.2 libraries, even if those libraries only support 3.2.Only with fully native support for this sort of version mapping can CocoaPods produce a good user and library developer experience. Barring something like this, the manual experience will be buggy and frustrating.
It needs to be in the podspec: CocoaPods is a dependency manager; each pod specifies its dependencies so users can build them; one of those dependencies is the Swift version. Simple as that.
@valeriomazzeo shouldn't rather pod_target_xcconfig
be used instead of xcconfig
?
@fabb if you are talking about spec.xcconfig = { 'SWIFT_VERSION' => '4.0' }
it is to go in the podspec not in the podfile, anyway it's just an idea, because currently cocoapods override that value with the project settings.
@valeriomazzeo the xcconfig
attribute is deprecated: http://blog.cocoapods.org/CocoaPods-0.38/#split-of-xcconfig
@fabb interesting, so if either pod_target_xcconfig
or user_target_xcconfig
manage to overrides what cocoapods extract from the project_settings, it could be a workaround for the time being. Did you try?
No I did not try yet
I think I'm missing something obvious but the post install hook solution doesn't work for me, because cocoapods validates that the Swift versions are not the same:
[!] The following pods are integrated into targets that do not have the same Swift version:
The hook is not even executed at this point.
The following pods are integrated into targets that do not have the same Swift version
I think this means that your targets have a different Swift version set to that which you are asking for in your post_install
hook.
I have the same issue. I just manually set the swift version of some pods to 3.2 in xcode. Here I found there is something call post_install
, that is great.
In addition, I have another problem that pods seem to not compiling when I execute archive
. I got many errors say something like that class in pods not found. I use pod 1.3.1. But when I upgrade pod to 1.4.0 Beta.1 and do pod install
, the problem seem to solved.
@orta @DanToml and whoever else is currently maintaining CocoaPods:
Not to push too hard as a non-contributor here, but not adding some version of swift_versions
to the podspec DSL continues to degrade the CocoaPods user experience and is consistently generating issues here on GitHub. Just a look at the currently open issues shows a couple that wouldn't be an issue if the attribute existed, and I'm sure there have been some closed:
.swift-version
wouldn't even need to exist anymore.Plus the assorted issues from other projects citing those issues. These types of issues will keep occurring until a solution is had, especially around major new Swift version releases every year. So, are there plans to address this overarching issue? Is it valuable to discuss how such an attribute would work?
We need to think through what the correct approach is for altering the DSL to support this.
There could be a case where the podspec provides a range of swift versions it supports or even the Podfile to request a specific swift version like:
pod 'Something', :swift_version => '3.2.'
etc.
This is issue is not being ignored by the maintainers but everyone is working on their free time on this project so things are not going to be move as fast as expected.
I'll think about it personally further and consider a proposal.
@dnkoutso I recognize everyone does this in their spare time, but this thread hasn't seen much maintainer involvement, so it's hard to judge where the project stands in regards to this issue in general.
While a Podfile
attribute might be useful in some capacity, a podspec attribute is the most useful and appropriate solution here. I proposed a solution here. To me it seems to meet all of the needs for users and pod developers and requires only minimal maintenance moving forward (CP would need to update its mapping of Swift versions that can be built by the same compiler). Initial development would likely be harder than simpler solutions but it seems to be a more appropriate solution in the long run.
Thanks @jshier I might be closing all other issues and consolidating into a single issue around multiple Swift version support in CocoaPods. We are in the processing of getting 1.4.0 out of the door first which includes a bunch of new features, I am not sure if this will make it for 1.4.0.
I renamed this issue and thank you all for chiming in. I marked this as a feature enhancement to support multiple swift versions and allow per pod customization for swift version to use instead of applying the same swift version across the entire project.
We've reprioritized this for 1.4.0 instead.
This issue is superseded by #7134
@DanielCreagh You just save me, thank you very very very much!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If needed to support a bigger list of libraries you can use
swift4 = ['LibraryA', 'LibraryB']
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if swift4.include?(target.name)
config.build_settings['SWIFT_VERSION'] = '4.0'
end
end
end
end
To be clear, this has been implemented, and each pod should define a swift_version
.
For older pods that haven't been updated, I recommend the following bit of code in your Podfile
:
pods_with_specific_swift_versions = {
'IHKeyboardAvoiding' => '3.0',
'Fusuma' => '4.0',
}
post_install do |installer|
installer.pods_project.targets.each do |target|
if pods_with_specific_swift_versions.key? target.name
swift_version = pods_with_specific_swift_versions[target.name]
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = swift_version
end
end
end
end
I use another solution for iOS & tvOS projects (see this link for more details).
Add these lines to end of your Podfile (you can specify other libraries you want):
my_project_pods_swift_versions = Hash[
"3.0", ["PagingMenuController", "TCPickerView"],
"4.0", ["PromiseKit"]
]
def setup_all_swift_versions(target, pods_swift_versions)
pods_swift_versions.each { |swift_version, pods| setup_swift_version(target, pods, swift_version) }
end
def setup_swift_version(target, pods, swift_version)
if pods.any? { |pod| target.name.include?(pod) }
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = swift_version
end
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
setup_all_swift_versions(target, my_project_pods_swift_versions)
end
end
@RomanPodymov in the end, I decided to follow a different way to do it, using pre_install
instead of post_install
: see that post to get an idea on how to do it on pre_install.
Sorry, if my question is naive.
My project is still on Swift 4.2 and I've restricted pods to use 4.2 as well, rather than get on the latest version. But, active development of a few pods is happening only on Swift 5.0 & 5.1. As issues are being fixed on those, I'd like to migrate a few pods to Swift 5.0. Can I specify a pod to use the latest version but retain my project on 4.2?
Any advice is of great help. Thanks! :)
@mohan-shyam I think you can mix Swift 4.2 with 5.x, yes.
But don't ask questions on a closed issue: it's unlikely that you'll get more answers (even from me).
Yeah, it's my mistake to post a question here. But, just another one. @Coeur
How can I do that? Any articles that detail it out?
I knew you would ask this, and it's not Stack Overflow here. But exceptionally... please find an answer in this post, where you can simply add more if
cases if you want to mix things.
I'm really sorry. But, you are awesome!! @Coeur
Thanks much! 馃檹
No more questions... 馃
Most helpful comment
this works:
It's not pretty but will do until they update your pods to Swift 4.