I'm trying to integrate ccache on my project which doesn't support clang modules. So I disabled clang modules in my main xcode project like below.
But for cocoapods generated project files, clang modules are enabled by default. Even if I change this setting, cocoapods will change it back on next pod update.
Is there anyway to let pod know that I want to fall back to the old behavior before apple introduced clang modules? Turn off CLANG_ENABLE_MODULES, and link system frameworks used by other pod generated static library for me in my main project automatically, like AVFoundation, MapKit, etc
Are you a Chinese developer? Have you seen this article before?
https://zhuanlan.zhihu.com/p/27584726
It's a tutorial of using ccache to speed up Xcode build process.It also provide the config of cocoapods.
I copied the code here, to let others who don't know Chinese and encounter the same problem know how to solve this problem.
post_install do |installer_representation|
installer_representation.pods_project.targets.each do |target|
target.build_configurations.each do |config|
#关闭 Enable Modules (Translation:Close Enable Modules)
config.build_settings['CLANG_ENABLE_MODULES'] = 'NO'
# 在生成的 Pods 项目文件中加入 CC 参数,路径的值根据你自己的项目来修改(Translation: Add CC parameter to pods project. You can change the path to whatever you want.)
config.build_settings['CC'] = '$(PODS_ROOT)/../ccache-clang'
end
end
end
but this configuration only turn off CLANG_ENABLE_MODULES.
As far as I know, there is no way to link system frameworks when using ccache and cocoapods.
Hope it helps.
If you are creating a custom pod, in your podspec file, write something like this,
Pod::Spec.new do |s|
# some configuration
s.pod_target_xcconfig = {
'OTHER_LDFLAGS' => '-lObjC', # if you created a category for a class from other lib
'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
'CLANG_ENABLE_MODULES' => 'NO', # here is what you want
'CLANG_WARN_DOCUMENTATION_COMMENTS' => 'NO',
'GCC_C_LANGUAGE_STANDARD' => 'gnu17'
}
end
Related
We have created a CocoaPod which is an XCFramework that has dependencies on other CocoaPods. When we run the demo example app or install the pod in a new app, it works, however this is logged to the console on launch (repeated for many classes):
objc[38875]: Class OTSubscriber is implemented in both
/Users/MyUser/Library/Developer/CoreSimulator/Devices/8DD81910-DD40-4BD7-9355-8A0C78EFD32E/data/Containers/Bundle/Application/60E8C18A-37DC-4C2B-AEB3-E88C3A7C4D96/MyCocoaPod_Example.app/Frameworks/MyFramework.framework/MyFramework
(0x10e3fd660) and
/Users/MyUser/Library/Developer/CoreSimulator/Devices/8DD81910-DD40-4BD7-9355-8A0C78EFD32E/data/Containers/Bundle/Application/60E8C18A-37DC-4C2B-AEB3-E88C3A7C4D96/MyCocoaPod_Example.app/MyCocoaPod_Example
(0x10c8abd80). One of the two will be used. Which one is undefined.
This class is from OpenTok, which is a dependency specified for the pod used in the framework. The message seems to reveal CocoaPods is installing the dependencies on the app in addition to the framework, causing this issue. The app itself shouldn't have any dependencies except this framework.
Perhaps something was done incorrectly in the pod creation process? These are the steps we took:
Create an Xcode framework project, add a Podfile listing its dependencies, build out the framework's functionality
Create an XCFramework from the framework's xcworkspace
Create the pod using pod lib create MyCocoaPod choosing iOS, Swift, include demo, none and no for testing
Update the Podspec:
Pod::Spec.new do |s|
s.name = 'MyCocoaPod'
s.version = '1.0.0'
s.summary = 'Summary'
s.description = <<-DESC
'Description'
DESC
s.homepage = 'https://myhomepage.com'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'Author' => 'auther#somedomain.com' }
s.ios.deployment_target = '12.0'
s.source = { :git => 'https://github.com/user/git-repo.git', :tag => s.version.to_s }
s.vendored_frameworks = 'MyFramework.xcframework'
s.swift_version = '5.5.2'
s.dependency 'OpenTok', '2.21.3'
# Needed to pass lint validation
s.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
s.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
end
Drag and drop MyFramework.xcframework into Pods/Development Pods/MyCocoPod
Update the example's Podfile to specify BUILD_LIBRARY_FOR_DISTRIBUTION = YES:
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
end
Run pod install in Example directory - note this will cause the framework to be moved to the root level in Finder and under a Frameworks group in Xcode
Update the example app's code to import and use MyFramework
Commit, tag, and push the changes to the repo
Push the Podspec to the specs repo
Not sure if this is your case but maybe you are falling in a scenario which happened to me,
meaning a dynamic framework that depends on a static framework. In such scenario, your dynamic framework would end up embedding the static one in his resulting binary. Then, in order to import your dynamic framework in the project, you will import with the setting “Embed and sign” for example, as that’s indeed a dynamic one, along with the other static framework which your dynamic one depends on. This causes the duplicated implementation ( your app including the static dependency + the dynamic one embedding inside the same dependency.
What you could do if this is your case, is to make sure that the dynamic framework configuration is changed to be static (static xcframework to be precise) , maybe outside cocoa pod as first step if that simplifies. Code wise would be the same, but it will “link” to the dependency (OpenTok for example) rather than embedding it. As result, once imported in the app, it should be imported only once, as your custom framework links to it and does not embeds it, finally avoiding the duplicated implementation. (static frameworks are imported with “Do not embed” which means that they will be merged in compile time to the app executable)
I have a Podfile, that when constructing the Pods.xcodeProj ends up with an included xcframework that is a Pods.xcodeproj file reference, that I need to add as a target reference to one of the pods built targets.
I think it's possible to do such a thing in the Podfile post_install phase, but I cannot figure out the xcodeproj gem syntax required to (A) find the Nami.xcframework reference I need to add to the target, then (B) add that file reference to the desired target (see image below for the framework I wish to adjust target membership for, I basically just want to automate checking that target membership box).
My start to this Podfile script looks like:
post_install do |installer|
nami_target = installer.pods_project.targets { |f| f.name == "react-native-nami-sdk" }
#Pseudocode begins here, this is what I cannot figure out
nami_xcframework_fileref = ??
nami_target.addBuildReference(nami_xcframework)
end
Thanks for any help on this, I've found a number of example pod file scripts but none seem to do quite what I am trying to do.
I managed to figure out the full script I needed, the Podfile post_install script below does exactly what I was looking for.
Note that a key was that while you can examine targets by using the .name property, for file references only .path will always have contents you can examine, .name is often blank. Also another key item, is that you need to add the file reference to the frameworks_build_phase aspect of the target.
The final script (added to the end of a Podfile):
post_install do |installer|
puts("Attempting to add Nami.xcframework reference to react-native-nami-sdk project.")
installer.pods_project.targets.each do |target|
if target.name == "react-native-nami-sdk"
puts("Found react-native-nami-sdk target.")
all_filerefs = installer.pods_project.files
all_filerefs.each do |fileref|
if fileref.path.end_with? "Nami.xcframework"
puts("Found Nami.xcframework fileref.")
build_phase = target.frameworks_build_phase
puts("Determining if react-native-nami-sdk build phase needs correction.")
unless build_phase.files_references.include?(fileref)
puts("Adding Nami.xcframework to react-native-nami-sdk target")
build_phase.add_file_reference(fileref)
end
end
end
end
end
end
I renamed my Existing library to github, I changed everything and things are working fine apart from it's not validating my library now by - pod spec lint KJCircularSlider.podspec for trunk push. I checked my folder structure and it looks perfect, anyone can help me what can be the actual issue?
Here is my library if you want to check folder structure - KJCircularSlider
Here is my podspec file.
Pod::Spec.new do |s|
s.name = 'KJCircularSlider'
s.version = '0.1.0'
s.summary = 'Circular slider - to slide from 0 to 100 in circular shape'
# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = <<-DESC
TODO: Add long description of the pod here.
It's circular slider, It provides circular shape to slide around from 0 to 100 percent, You can use it when you required a circular shape on slider rather than traditional iOS line shape slider.
DESC
s.homepage = 'https://github.com/KiranJasvanee/KJCircularSlider'
# s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'Kiran Jasvanee' => 'kiran.jasvanee#yahoo.com' }
s.source = { :git => 'https://github.com/KiranJasvanee/KJCircularSlider.git', :tag => s.version.to_s }
# s.social_media_url = 'https://twitter.com/KiranJasvanee'
s.ios.deployment_target = '9.0'
s.source_files = 'Classes/**/*'
# s.resource_bundles = {
# 'KJCircularSlider' => ['KJCircularSlider/Assets/*.png']
# }
# s.public_header_files = 'Pod/Classes/**/*.h'
# s.frameworks = 'UIKit', 'MapKit'
# s.dependency 'AFNetworking', '~> 2.3'
end
I've solved my issue by changing version number of my pod.
I've renamed my KJCurveSlider library to KJCircularSlider, because of major changes in library I wouldn't be able to push it using pod trunk push. I was constantly receiving following error when I tried to validate using pod spec lint library.podspec, nevertheless I had mention perfect path of s.source_files in podspec
- ERROR | [iOS] file patterns: Thesource_filespattern did not match any file.
Then I updated version from 0.1.0 to 0.2.0, it validated successfully
I cleared the cache for my Pod and it worked!
pod cache clean YOUR_POD_NAME
the problem can occur if you have your pod source (Classes) and .podspec nested in some directory (for example /RepositoryName/Classes). So pod spec lint won't find it, regardless .podspec file is near /Classes folder.
So, optinally you can do something like this:
s.source_files = '**/Classes/**/*.{swift}'
so **/ this part does search inside nested folders.
Another option is that pod cached, you can do
pod cache clean YOUR_POD_NAME
or clean Pods cache directory
/Users/<#ur user name#>/Library/Caches/CocoaPods/Pods
P.S.
I don't think that changing the version of the pod is the right answer, because, probably all it does, force pods to use a new cache. It is not the correct answer, because you probably don't want to push a new version, but still fix the problem?
I've met this problem too. The path I set for s.source_files = 'Pod/Classes/**/*' is absolutely right. I got
The 'source_files' pattern did not match any file` error
because there's no file within classes folder. After putting my library files in it, problem solved.
For me I tried to change the Classes directory to Sources to make it future compatible with Swift Package Manager, and got this error.
- ERROR | [iOS] file patterns: The `source_files` pattern did not match any file.
the line from my podspec:
s.source_files = 'EvolvSDK/Sources/**/*'
and my file structure looked as such:
|-EvolvSDK
|-sources/
|-Utility/
|-Log.swift
I changed the sources directory name to classes and changed my podspec:
s.source_files = 'EvolvSDK/Classes/**/*'
Now it passes validation. the confusing part is that the directory is lowercase, and the podspec has uppercase. If anyone knows why that is, please add a comment as this is my first cocoapod and I'm trying to understand how it all works.
I encountered this error after creating a new pod with the pod lib create command. Wouldn't pass out of the box. For me, having the 'Classes' in the file path broke it. I changed nothing about the setup, yet it still wouldn't pass validation. I changed s.source_files = 'MyLib/Classes/*' to s.source_files = 'MyLib/**/*' and it passed. What it is, it is.
Something to keep in mind is that pod spec lint will pretty much ignore any local files other than the podspec, and try to clone/copy whatever the spec.source is set to in order to run its diagnostics.
One possible source for this error is if for some reason the spec.source is inaccessible (say, the exact tag that you specify isn't present in the repository, like a 1.0 versus v1.0 mismatch).
So making sure the repo/tag is accessible is a good debugging step if nothing else makes sense.
Also note that the result of the cloning/copying operation will be cached, stored under the pod's name/version combination, so if you make fixes without incrementing the version, you will have to clear out the cache before the fixes will work.
I and my team are stuck in a strange situation involving a base project + private pods with some protocols inside.
Our problem is we can't access some of the (protocol) identifiers (defined in a private pod) from our base app code.
Apparently our problem seems to be exactly the same as the one described in these 2 stack overflow threads, but their solutions haven't worked with us.
Thread 1: Source files not found in Swift
Thread 2: CocoaPod installed but doesn't see Swift code
The skeleton we're using is this one:
Our Commons pod (with the protocol we can't see from our base app) is defined with this .podspec file:
Pod::Spec.new do |s|
s.name = "Commons"
s.version = "0.1.10"
s.summary = "Commons framework"
s.description = <<-DESC "Commons framework"
DESC
s.homepage = "http://EXAMPLE/Commons"
s.license = { :type => "Commercial" }
s.author = { "Author" => "author#mail.mail" }
s.source = { :git => "GITLAB_PRIVATE_URL/commons-iOS-Pod.git", :tag => s.version }
s.source_files = "Commons", "Commons/**/*.{h,m,swift}"
s.exclude_files = "Commons/Exclude"
end
From our base app, we have the following Podfile (to get our Commons pod onto our main xcworkspace).
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
target 'ios-appbase' do
# Comment this line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
pod 'Alamofire'
pod 'ViewDeck'
pod 'JLRoutes'
pod 'Commons', :git => 'GITLAB_PRIVATE_URL/commons-iOS-Pod.git', :tag => '0.1.4', :branch => 'develop'
pod 'RestManager', :git => 'GITLAB_PRIVATE_URL/RestManager-iOS-Pod.git', :tag => '0.1.3'
pod 'BaseClasses', :git => 'GITLAB_PRIVATE_URL/BaseClasses-iOS-Pod.git', :tag => '0.1.3'
pod 'DesignManager', :git => 'GITLAB_PRIVATE_URL/DesignManager-iOS-Pod.git', :tag => '0.1.2'
end
We've defined our protocol as public (as it's expected to be done, because it's living inside the 'Pods' project).
What else should be looking into?
PS: Not only our custom protocol is "invisible" from our main app, but also protocols defined inside Alamofire, which is another Pod included in our main app. We try to use them and XCode complains at compile time.
Thanks in advance.
Greetings.
EDIT1: Narrowing our problems, we think it's something happening in compilation time. Why? Because XCode is able to solve the faulty symbols pressing CMD+Click (two protocols defined on our Pods file structure), but the compiler can't do it and it's the one complaining with the "Use of undeclared type" error.
Whops, success (!?)
The protocol we were defining was living inside a Framework Pod, so: What were we doing wrong?
Apparently we needed to import the name of the Framework (not the class name of the protocol (!) ). Kind of a newbie error (?).
Once we typed "import Commons" on the top part of our swift file, all "undefined xxxxxx" errors disappeared.
Not sure though if we needed this specific import part because the imported Pod was a Framework project, or we just hit the nail by chance.
I have the impression some other Classes and stuff imported from some other Pods we're using, don't need an import part, and you can directly use them from the start. So our missunderstanding might have been caused by this (?).
Anyway, and as I said before, these are newbie problems using "custom pods + swift + Frameworks + somehow complex escalable .app architectures".
Let's hope this problem and its (alleged solution) sheds some light onto future developers being in a similar situation.
Greetings.
I am trying to use Cocoapods with some custom configurations in an iOS project.
I have 3 (Dev, Stage, Prod) and each of them has some custom GCC_PREPROCESSOR_DEFINITIONS.
I have seen around people suggesting to us #include <path-to-pods.xcconfig>, but this seems to the old way to do this.
I have seen Cocoapods 0.39 is automatically generating its config files based on my configurations and adding them to my targets automatically (and this is good).
This is also confirmed by this article who is talking about a "new way" to create Podfiles.
The problem is these files don't contain my configurations.
I was trying to use xcodeproj and link_with, but without success.
Does anyone know what is the correct way to deal with Cocoapods + custom xcconfig files?
The problem is that CocoaPods is based on xcconfig files and sets the actual variables. But these values cannot be used in any way when the full configuration is in xcconfig files like:
#include "../Pods/Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig"
GCC_PREPROCESSOR_DEFINITIONS = ...
In this case GCC_PREPROCESSOR_DEFINITIONS overwrites the previous value.
Here is the way to solve it:
Update the Podfile to re-define the GCC_PREPROCESSOR_DEFINITIONS value with PODS_ prefix on post_install:
post_install do |installer|
work_dir = Dir.pwd
Dir.glob("Pods/Target Support Files/Pods-Demo/*.xcconfig") do |xc_config_filename|
full_path_name = "#{work_dir}/#{xc_config_filename}"
xc_config = File.read(full_path_name)
new_xc_config = new_xc_config.sub(/GCC_PREPROCESSOR_DEFINITIONS/, 'PODS_GCC_PREPROCESSOR_DEFINITIONS')
File.open(full_path_name, 'w') { |file| file << new_xc_config }
end
end
Define xcconfig file in the next way:
#include "../Pods/Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig"
GCC_PREPROCESSOR_DEFINITIONS = $(PODS_GCC_PREPROCESSOR_DEFINITIONS) ...
In this case GCC_PREPROCESSOR_DEFINITIONS should contain PODS_GCC_PREPROCESSOR_DEFINITIONS & you custom values.