Add custom path to HEADER_SEARCH_PATHS using CocoaPods post install hook - ios

I am trying to add $(PLATFORM_DIR)/Developer/Library/Frameworks path to Specta target Header search paths using post install hook. This obviously is not vital, but it really annoys me to added this path manually each time I do "pod update".
I got to the following script:
post_install do |installer_representation|
installer_representation.project.targets.each do |target|
if target.name == 'Specta'
target.build_configurations.each do |config|
headers = config.build_settings['HEADER_SEARCH_PATHS']
if headers
config.build_settings['HEADER_SEARCH_PATHS'] += ' $(PLATFORM_DIR)/Developer/Library/Frameworks'
end
end
end
end
end
I would be really happy if someone could point me to the right direction, because I am really stuck.
P.S. I already noticed that this path is already added by CocoaPods, but still I am highly interested in how this can be done, since this knowledge can be useful later. Thanks!

Define a method in your Podfile:
def append_header_search_path(target, path)
target.build_configurations.each do |config|
# Note that there's a space character after `$(inherited)`.
config.build_settings["HEADER_SEARCH_PATHS"] ||= "$(inherited) "
config.build_settings["HEADER_SEARCH_PATHS"] << path
end
end
Then call the method in the post_install:
installer.pods_project.targets.each do |target|
if target.name == "Specta"
append_header_search_path(target, "$(PLATFORM_DIR)/Developer/Library/Frameworks")
end
end

Related

How can I define preprocessor flags in iOS project and use it in Swift code?

My Problem: I defined the preprocessor flag for my Xcode project, but it doesn't work as I used it in my Swift code.
What I've Done: I defined multiple Targets for my Xcode project (and multiple schemes as well) and for each target created a custom build configuration file (.xcconfig file). For each Target, I override SWIFT_ACTIVE_COMPILATION_CONDITIONS flag in my .xcconfig file.
My ca805.debug.xcconfig file is like this:
#include "Pods/Target Support Files/Pods-Common-ca805/Pods-Common-ca805.debug.xcconfig"
#include "base.debug.xcconfig"
// other configs
SWIFT_ACTIVE_COMPILATION_CONDITIONS = CA805
And I assigned each build configuration to each Target in .xcodeproj file.
In Swift code I used this flag like below:
#if CA805
print("I'm using CA805 target specific code")
#else
print("I'm using common code")
#endif
And it printed I'm using common code.
Also, I've tried to add SWIFT_ACTIVE_COMPILATION_CONDITIONS flag using Podfile but it didn't work:
platform :ios, '12.0'
use_frameworks!
abstract_target 'Common' do
project 'Main', 'base.debug' => :debug, 'base.release' => :release
use_frameworks!
# Pods for all targets
# ...
# Define Targets
target 'Main'
target 'ca805'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name.start_with?('Pods-Common')
target.build_configurations.each do |config|
if !config.name.start_with?('base')
target_name = target.name.split('-')[2].upcase
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', "#{target_name}=1"]
config.build_settings['OTHER_SWIFT_FLAGS'] ||= ['$(inherited)', "-D#{target_name}"]
config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] ||= ['$(inherited)', "#{target_name}"]
end
end
end
end
end
I checked Active Compilation Conditions section in my Target's Build Settings tab and something overrides my flag and I don't know the reason.
Active Compilation Conditions section in my project
Finally, I found a workaround for this issue. I modified .xcconfig files:
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name.start_with?('Pods-Common')
target.build_configurations.each do |config|
if !config.name.start_with?('base')
target_name = target.name.split('-')[2]
flag = target_name.upcase
puts "[Injecting flag:'#{flag}' to '#{target_name}.#{config.name.downcase}.xcconfig'"
xcconfig_path = config.base_configuration_reference.real_path
# read from xcconfig to build_settings dictionary
build_settings = Hash[*File.read(xcconfig_path).lines.map{|x| x.split(/\s*=\s*/, 2)}.flatten]
# modify FLAGS
build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] = "$(inherited) #{flag}"
# write build_settings dictionary to xcconfig
File.open(xcconfig_path, 'w') {|file| file.puts ''}
build_settings.each do |key, value|
File.open(xcconfig_path, 'a') {|file| file.puts "#{key} = #{value}"}
end
end
end
end
end
end

Post install hook for .podspec file

Hi I have private pod framework, I'm using, and till now it wasn't a problem because in pod file I can edit SWIFT_OPTIMIZATION_LEVEL like:
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if (target.name == "MyLib")
config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Onone'
end
end
end
end
but now I want to use this pod as dependency in my other pod so in .podspec file I Have
s.dependency 'MyLib', '~> 1.0'
So I can't do it in post_install Podfile because it doesn't exist. I tried to do this like
prepare = <<-PREPARECOMMAND
ruby SWIFT_OPTIMALIZATION.rb
PREPARECOMMAND
s.prepare_command = prepare
But it run to early and at the end it's not changed. I also tried to run this in
s.script_phase
It works but only after first failure, in first build it changes the optimisation and cancel, on second time it build. Is there any way to add post install hook to podspec?
s.pod_target_xcconfig = { 'SWIFT_OPTIMIZATION_LEVEL' => '-Onone' }

Cocoapod : Redefining preprocess macro using post install hook

I want to update my pod to let users activating/desactivating a feature.
To do this I've added a Preprocessor macro in my podspec :
s.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'FEATURE=1' }
Now, for a user the right thing to do (of what I've understood) should be to use a post install hook in the podfile to change the definition of FEATURE
post_install do |installer_representation|
installer_representation.project.targets.each do |target|
if target.name == "Pods-MyPod"
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'FEATURE=0']
end
end
end
end
But it did not do anything at all ... FEATURE value is still 1
Am I doing something wrong ?
EDIT :
I did take a look at this answer, but it did not help.
In the end, I found a working version.
post_install do |installer_representation|
installer_representation.pods_project.targets.each do |target|
if target.name == "Pods-MyPod"
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = ['COCOAPODS=1', 'FEATURE=0']
end
end
end
end

Cocoapods optimization level for schemes

Looking at the project file for Cocoapods Pods.xcodeproj it looks like every single scheme for every library (except for Debug scheme) has an optimization level of Fastest, Smallest.
Is there a quick and easy way to change the Podfile or some other configuration of Cocoapods so that the optimization level is None for specific schemes when I use pod install?
I use post_install hook in Podfile. Like this:
post_install do |installer|
installer.pods_project.build_configurations.each do |config|
if config.name.include?("Debug")
config.build_settings['GCC_OPTIMIZATION_LEVEL'] = '0'
config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Onone'
end
end
end
EDIT
GCC_OPTIMIZATION_LEVEL is ignored for Swift Pods. If you're using Swift Pods you also need to set SWIFT_OPTIMIZATION_LEVEL.
To anybody seeing this using cocoapods 0.38.0 or later:
Use "pods_project" instead of "project"
The previous answers use the word "project" (installer.project.build_configurations.each)
Project was deprecated and replaced with pods_project.
https://github.com/CocoaPods/CocoaPods/issues/3747
post_install do |installer|
installer.pods_project.build_configurations.each do |config|
if config.name.include?("Debug")
config.build_settings['GCC_OPTIMIZATION_LEVEL'] = '0'
end
end
end
If you also want the DEBUG macro added for debugging with assertions enabled, you can use the following script:
post_install do |installer|
installer.project.build_configurations.each do |config|
if config.name.include?("Debug")
# Set optimization level for project
config.build_settings['GCC_OPTIMIZATION_LEVEL'] = '0'
# Add DEBUG to custom configurations containing 'Debug'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
if !config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'].include? 'DEBUG=1'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'DEBUG=1'
end
end
end
installer.project.targets.each do |target|
target.build_configurations.each do |config|
if config.name.include?("Debug")
# Set optimization level for target
config.build_settings['GCC_OPTIMIZATION_LEVEL'] = '0'
# Add DEBUG to custom configurations containing 'Debug'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
if !config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'].include? 'DEBUG=1'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'DEBUG=1'
end
# Enable assertions for target
config.build_settings['ENABLE_NS_ASSERTIONS'] = 'YES'
config.build_settings['OTHER_CFLAGS'] ||= ['$(inherited)']
if config.build_settings['OTHER_CFLAGS'].include? '-DNS_BLOCK_ASSERTIONS=1'
config.build_settings['OTHER_CFLAGS'].delete('-DNS_BLOCK_ASSERTIONS=1')
end
end
end
end
end
Instead of post_install you can add following line to Podfile:
project 'ProjectName', 'DebugConfigurationName' => :debug

DEBUG preprocessor macro not defined for CocoaPods targets

I'm having issues with a pod called DCIntrospect-ARC which should only work in DEBUG mode. It checks if the DEBUG macro is defined before running. However, it is not defined in the CocoaPods target and even though I am running in debug mode in Xcode it fails to run because the DEBUG macro is not defined.
I can define the DEBUG macro in the podspec using
s.xcconfig = { "GCC_PREPROCESSOR_DEFINITIONS" => '$(inherited) DEBUG=1' }
but this defined DEBUG for all build configurations and not only the DEBUG configuration.
Is this a CocoaPods issue? Shouldn't the DEBUG macro generally be defined for Pods?
Can I work around this in the Podspec file and declare the DEBUG macro in the Debug build configuration only?
you can use the post_install hook in Podfile.
This hook allows you to make any last changes to the generated Xcode project before it is written to disk, or any other tasks you might want to perform.
http://guides.cocoapods.org/syntax/podfile.html#post_install
post_install do |installer_representation|
installer_representation.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if config.name != 'Release'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'DEBUG=1']
end
end
end
end
Thanks to John I completed my custom Podfile script, which also changes the optimization level to zero and enables assertions.
I've got multiple debug configurations (for ACC and PROD), so I needed to update several properties for debugging purposes.
post_install do |installer|
installer.pods_project.build_configurations.each do |config|
if config.name.include?("Debug")
# Set optimization level for project
config.build_settings['GCC_OPTIMIZATION_LEVEL'] = '0'
# Add DEBUG to custom configurations containing 'Debug'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
if !config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'].include? 'DEBUG=1'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'DEBUG=1'
end
end
end
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if config.name.include?("Debug")
# Set optimization level for target
config.build_settings['GCC_OPTIMIZATION_LEVEL'] = '0'
# Add DEBUG to custom configurations containing 'Debug'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
if !config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'].include? 'DEBUG=1'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'DEBUG=1'
end
# Enable assertions for target
config.build_settings['ENABLE_NS_ASSERTIONS'] = 'YES'
config.build_settings['OTHER_CFLAGS'] ||= ['$(inherited)']
if config.build_settings['OTHER_CFLAGS'].include? '-DNS_BLOCK_ASSERTIONS=1'
config.build_settings['OTHER_CFLAGS'].delete('-DNS_BLOCK_ASSERTIONS=1')
end
end
end
end
end
The accepted answer as of now doesn't work for Swift Pods.
Here is a one-line change to that answer that appears to work for both.
post_install do |installer_representation|
installer_representation.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if config.name != 'Release'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'DEBUG=1']
config.build_settings['OTHER_SWIFT_FLAGS'] = ['$(inherited)', '-DDEBUG']
end
end
end
end
I think the accepted answer is not so right for me. config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'DEBUG=1']
||= is used to assign a empty or nil variable, but if the config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] is not empty ?
The array cannot be modified at all. The value is ["POD_CONFIGURATION_PRODUCTION=1", "$(inherited)"] for me.
So I gave the complete anwser.
post_install do |installer_representation|
installer_representation.pods_project.build_configurations.each do |config|
if config.name == 'Release' || config.name == 'Production' || config.name == 'Release-InHouse'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= []
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] |= ['$(inherited)', 'NDEBUG=1']
end
end
end
||= [] make sure the variable is a valid array. and arrayA |= arrayB means arrayA + arrayB and rid the the repeated element, and then return to arrayA.
Even easier: just ensure you have the DEBUG=1 macro to your GCC_PREPROCESSOR_DEFINITIONS in your project in xCode for debug mode but not release mode. If you add it the the project level (not specific targets) it will be inherited by all targets (debug-test, custom targets, etc). This is set by default on new projects, and generally expected to be there. If you are missing it, that could have broad impact.
If it's still not working, ensure you also have $(inherited) in all your targets for GCC_PREPROCESSOR_DEFINITIONS. CocoaPods and DEBUG both count on that.

Resources