I have several Xcode workspaces, each containing several projects. The projects in these workspaces are related and need to reference several of the same CocoaPods.
I want to create a single common directory into which I can download one copy of each pod I use, but I can't figure out how to set up the podfile so that it does treats each workspace independently. What happens is that when two workspaces are named, the second one gets both non-pod projects.
To simplify things, I created two simple projects, FooProject and BarProject, each contained in its own workspace (FooWorkspace and BarWorkspace). For clarity, my directory structure looks like this:
+ Common
- Podfile
- Podfile.lock
+ Pods
+ Workspace1
- FooProject.xcodeproj
- FooWorkspace.xcworkspace
+ Workspace2
- BarProject.xcodeproj
- BarWorkspace.xcworkspace
Here's my podfile:
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
def common_pods
pod "ConsoleBanner"
end
target 'FooProject' do
project '../Workspace1/FooProject.xcodeproj'
workspace '../Workspace1/FooWorkspace.xcworkspace'
common_pods
end
target 'BarProject' do
project '../Workspace2/BarProject.xcodeproj'
workspace '../Workspace2/BarWorkspace.xcworkspace'
common_pods
end
This almost does the trick. It downloads the pod only one time and puts it in the shared directory below this file. The only problem is that it updates BarWorkspace to include not only BarProject and the Pods project, but also FooProject. The first project/workspace referenced in the podfile works properly.
I tried adding inherit! :none within the target blocks, but it didn't have any effect. I also considered creating separate podfiles as peers in the same directory, but it seems that podfile has to be named, exactly, podfile.
How can I have the projects from separate workspaces reference the same podfiles?
I'm going to answer my own question based on my research efforts over the last few days. Hopefully this is useful to someone else at some point.
It doesn't seem that you can create a podfile that applies to multiple workspaces. But the more I think about it, maybe this is the way it should be.
One podfile maps to a collection of pods. Each pod has a specific version number. Presumably, different projects you might work on could require different versions of the same pods. For example, suppose Project 1 uses Pod X, version 3.0. But Project 2, because of legacy requirements, cannot use version 3.0 of Pod X but instead must use version 2.0.
In this case, you would need two different podfiles, each pointing to totally distinct collections of pods.
If you have a collection of projects that are so tightly linked that you can guarantee that they all use exactly the same versions of each pod they depend on, then maybe it makes sense to put those projects all together into a single workspace. That's what I ended up doing.
I may be wrong about some of these details, and I would welcome corrections if so. I hope this writeup is useful for others getting started with CocoaPods.
Related
I have two frameworks 'GeneralABC' and 'GeneralXYZ'. Both of them have the same interface but different business logic. I define their module_name in podspec as General, so that other projects using my framework only need to define which General framework(GeneralABC or GeneralXYZ) they want to use in their Podfile, without changing their codes. (i.e. in their code file, they can always say import General)
In my example project, i have two targets, each target using different General framework. My Podfile is as follows:
target 'Example_ABC' do
pod 'GeneralABC'
end
target 'Example_XYZ' do
pod 'GeneralXYZ'
end
however when i try to build one of my target in xcode, I have got the following error
message
Multiple commands produce '/MYPATH/General.framework':
1) Target 'GeneralABC' has create directory command with output 'MYPATH/General.framework'
2) Target 'GeneralXYZ' has create directory command with output 'MYPATH/General.framework'
Multiple commands produce '/MYPATH/General.framework':
1)Target 'GeneralABC' has link command with output 'MYPATH/General.framework'
2)Target 'GeneralXYZ' has link command with output 'MYPATH/General.framework'
It can be solved by two approaches:
changing the workspace settings to legacy build system. however I don't think it is a solution in the future.
remove one of the target in the Podfile, and pod update every time we build the target. however, it is not so nice for maintenance and our build process.
is there any solution that i can manipulate my Podfile, so that i can fix the issue?
I appreciate very much of any suggestions.
Thank you for your attention!
I cannot find the exact solution that I want (1 pod file maintain all the targets). However, after some discussions with our teammates. we come up another kind of solution, so that we don't have to worry about the deprecated legacy build system.
solution are as follows:
create 2 podfile (i.e. 1 for target 'Example_ABC' the other for 'Example_XYZ')
create 2 workspace file (i.e. 1 for target 'Example_ABC' the other for 'Example_XYZ')
a mini shell script, that link the Podfile_ABC or Podfile_XYZ, when do the pod install/update/deintegrate
I have my own private specs repository with internal pods. I used to add prefixes to the pods, however now I'm migrating to Swift I'd like to get rid of them.
However if I get rid of the prefixes (e.g. JAMNetworking to Networking) and I specify two sources in the Podfile, I'm getting conflicts as Networking is a existing public pod from the master repository. I know one possible solution is to specify the git repository url next to each pod, but it's annoying for me to add the url for each pod so I'm searching for an elegant solution. I have some ideas, but none of them seemed to work:
A) Add a name to the source and specify the source name for each pod, e.g.
source 'master', 'https://github.com/CocoaPods/Specs.git'
source 'internal', 'https://myurl.git'
pod 'samePodName', 'master'
pod 'samePodName', 'internal'
B) create two definitions with the source specified inside:
def publicPods
source 'master', 'https://github.com/CocoaPods/Specs.git'
pod 'samePodName'
end
def internalPods
source 'internal', 'https://myurl.git'
pod 'samePodName'
end
target 'MyProject' do
publicPods
internalPods
end
Unfortunately this only takes one of the def as valid and ignore the other one...so in this case it would install the public one. If I switch after installing then uninstall the public one and installs the internal one.
C) Create multiple targets. It's returning an error about multiple targets with the same name.
Do you think it's possible to find an elegant solution without adding the url for each pod or avoiding adding prefixes?
The elegant solution at the moment is to retain your prefixes. Consider
a) It's commonly agreed that best practice is for your pod to be named identically to its exposed Swift module
b) Swift modules may not link to another module with a duplicated name
... which renders moot the question of how to manage duplicate pod names.
Erica Sadun came to the same conclusion here. Until something like the reverse-DNS identifier proposed therein comes to pass,
Package names need to be clear and specific, yes, but they should avoid terms that will overlap because when you have a package called SwiftString and every Bob, Jane, and Harry also has a package called SwiftString, name collisions are inevitable...
And, until then, prefer SadunSwiftString to SwiftString and avoid the issue from the start.
stick with the prefixes since the real problem here is Swift's lack of namespacing above the module level. And by the time that's resolved we'll all be using SPM, no doubt!
I am having an extremely frustrating issue with XCode 7.3 (however, this issue has persisted since I installed XCode 7.2) and Swift code, and I am hoping others have had this issue and know how to resolve it. Syntax highlighting and code completion work perfectly fine in Objective-C files, and also works fine when calling other Swift objects within Swift code. However, any Objective-C objects or methods mentioned in Swift code get no syntax highlighting, and XCode will not complete ANY Objective-C declared methods or properties. Everything compiles and runs just fine.
I should also add that I have also tried doing a completely clean install of XCode. I deleted all my derived data, deleted all XCode caches, and deleted my XCode preferences files (in addition to obviously deleting the XCode.app archive before re-installing).
It is making it extremely difficult to develop in Swift. I don't want to do this, but if I can't find a way to resolve this I'll be forced to go back to using Objective-C.
I have the same problem. But finally solved it.
I make two change, not sure which is the key point but you can try them all.
delete the module cache
Within the same folder as your project's Derived Data is a Module
Cache. When Code Completion stopped working, deleting this fixed it.
Close Xcode and delete the
~/Library/Developer/Xcode/DerivedData/ModuleCache directory.
change the Enable Modules value
Go to the Build Settings of your target, then search Enable
Modules
If it's Yes, change it to No, and you may get some build
error, just change it back to Yes.
After two steps above you should Clean(Shift+Command+K) your project.
For now you may fixed the problem.
So it seems the issue was with CocoaPods. I was using Cocoapods as a static library instead of as frameworks. Switching to frameworks (using use_frameworks! in my Podfile) and importing the libraries into Swift has resolved all my issues. I'm guessing all those third party library headers were just too much for XCode to process. Either way, the issue is now resolved. I hope this helps someone in the future.
This might not be necessary anymore but i still want to post this:
At the time of this post, the most recent version of cocoapods (1.0.0.beta.8) requires you to define pods for each Xcode target.
In my case I had a class compile for the project target and for a testing target. I added a pod only to the main target, because of laziness.
Now working in the code of class A I added the pod framework using import NAME and tried to use the classes of the framework. Xcode wouldn't highlight the particular code where I use the new classes, but compiling and running works fine. In the completion dialog the type of the variable was <<error type>>
The way to resolve this issue: in the Podfile add the newly added pod to all targets, the class A is member of.
Now Xcode finds the necessary frameworks for all targets and code highlighting works again.
EDIT 1:
A possible solution is defining a list of shared pods, like in my example:
platform :ios, '8.4'
use_frameworks!
inhibit_all_warnings!
def all_pods
pod 'MPMessagePack'
pod 'SwiftyDispatch'
pod 'BFKit'
pod 'Timepiece'
pod 'Alamofire'
pod 'AlamofireSwiftyJSON'
end
def testing_pods
pod 'Quick'
pod 'Nimble'
end
target 'App' do
all_pods
end
target 'AppLogicTests' do
all_pods
testing_pods
end
target 'AppUITests' do
pod 'RxTest'
all_pods
testing_pods
end
post_install do |installer|
installer.pods_project.targets.each do |target|
puts target.name
end
end
This will add all pods to all targets and adding all testing pods to the targets. Next to these I added 'RxTest' to the AppUITests.
(Chosen pods are examples of my projects, no advertising intended :-) )
We had the same issue in a mixed ObjC/Swift project. Tried all the suggestions about deleting derived data etc, to no avail. Sometimes it helped, but not in a reproducible way and after some time it stopped working.
The post of Galvin in this post put me on the track of the Module related build settings. However it was another setting that solved the code completion/coloring in a reproducible way: setting DEFINES_MODULE (under Packaging) from YES to NO for our main project was the solution.
Notes:
I expected this to break the ObjC/Swift interoperability in our project, but that still works. It seems that setting is only to be used for framework targets. (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html)
This project setting has not been changed for months, but the code completion issues came up only recently, both for my colleague and me.
If none of the above worked for you and you're using Cocoapods, you can try switching to Carthage.
I tried every suggestion I could find on Google to no avail. But consistently Cocoapods seemed to be coming up as a reason with many hacks in attempt to fix it. I have been reading up on Carthage, and how it doesn't modify your project, force you to use a workspace, or potentially fill your build folder with header files (which confuses Xcode and can cause the syntax highlighting and autocomplete to break).
After making the switch I haven't run into any issues yet, and to be honest I prefer the teensy bit of overhead to have a clean solution. This post really drove it home for me.
By default a CocoaPods installation makes Pods/Pods.xcodeproj. Is there a way I can set it to be called something else, like Pods/MyCustomPods.xcodeproj?
The scenario is that I have a workspace that contains multiple projects in multiple directories, and two of the projects there use CocoaPods. And not only would it then be confusing with two projects named Pods, but Xcode can't cope well with that and confuses the two projects.
Cheers
Nik
The approach with multiple Pods projects was incorrect. In this case, rather make a .xcorkspace and then point your Podfile at it
workspace 'MyCustom.xcworkspace'
then in each of your targets, point at the respective .xcodeproj:
target 'A' do
xcodeproj 'A.xcodeproj'
pod 'SamplePod'
end
target 'B' do
xcodeproj 'B.xcodeproj'
pod 'SamplePod'
pod 'OtherPod'
end
This works really well :-)
So my situation specifically uses the Objection dependency injection library. However, I believe this could be an issue for other libraries as well.
Platform
iOS 8.0 Xcode 6.1.1. Cocoapods 0.35. Objective-C.
Set up:
I have 4 projects. 3 universal frameworks and a test app (I'm creating an api). The test app does not utilize cocoapods (though some other app might).
All three of my frameworks need to use injection. I created a pod file that looks like
workspace 'workspace.xcworkspace'
platform :ios, '8.0'
xcodeproj 'path/to/proj/one'
xcodeproj 'path/to/proj/two'
xcodeproj 'path/to/proj/three'
target :Project1 do
pod 'Objection', '1.4'
end
target :Project2 do
pod 'Objection', '1.4'
end
target :Project3 do
pod 'Objection', '1.4'
pod 'SDWebImage', '~>3.7.1'
end
Problem
When I use this set up singletons don't work in Objection. However, they only don't work if they (the singleton class) is defined in project 1 and then I call [JSObjection createInjector]; in project 2 (the projects don't make a difference, it is that create is called in a different project to the definition).
Current theory
After battling with this for a while I believe it is due to the warning along the lines of:
Objection is defined in Project 1, Project 2 and Project 3.
Which one will be used undefined.
So when the class registers itself with the injection system (e.g through objection_register_singleton(ClassX)). It is using the JSObjection definition from its project, which might not be the one being used for a class that injects it (e.g. objection_requires_sel(#selector(myClassXObject))).
Question
I want to be able to use the iOS frameworks setup as, from what I understand, it is better overall than static libs. However, I also want to be able to use Cocoapods (and have any app, that uses my api, use Cocoapods).
How do I either a) share one definition across multiple frameworks or b) setup a framework as a Cocoapod (I've seen that this is being developed).
I would love to be able to keep the frameworks linked through the xcode workspace so when one is built the frameworks it depends on are also built. Though having said that, my api will probably become a Cocoapod at some point anyway.
Thanks in advance (and for reading to here)
Indigo