nil}2018-02-15T00:00:00-09:00{"modified_time"=>nil}" />
Problem: I have an Xcode project for an app that has many custom build configuations beyond just Debug and Release. That app is being developed together with an SDK, for which we use CocoaPods as its distribution mechanism as well as for devpod setup. In the SDK, I wanted some of these custom configurations to compile with no Swift optimizations so I could debug, while other configurations intended for release should have whole module optimization enabled.
I already knew that I could set build settings from a podspec, but I’ve never done this per configuration. I found this Stack Overflow answer, where unfortunately the author notes that conditional variable assignment doesn’t work with podspecs’ pod_target_xcconfig
. (Check out this GitHub issue on CocoaPods support for conditional variable assignment.)
In my particular case, needing to override SWIFT_OPTIMIZATION_LEVEL
presents an additional challenge. Contrary to the findings of the SO post, I did see an xcconfig written to Pods/Target Support Files
with all the configuration-specific settings, and saw it reflected in Xcode’s Build Settings GUI editor. Here’s the issue: CocoaPods hardcodes the default values for this setting, but writes them to the pbxproj Target-level settings, thus overriding my xcconfig settings. If they instead wrote it to the Project-level, they’d be overridable by anything set in pod_target_xcconfig
. (See PROJECT_DEFAULT_BUILD_SETTINGS
and COMMON_BUILD_SETTINGS
in constants.rb
, and project_helper.rb where COMMON_BUILD_SETTINGS
is accessed via new_target
-> configuration_list
-> common_build_settings
.)
Fortunately, there’s the venerable post_install
hook, where we can modify targets’ build settings, just like was once required for SWIFT_VERSION
(That workaround has since been obviated with the root specification swift_version
as of cocoapods 1.4.0–ctrl-f ‘Swift Version DSL`, it’s a ways down. The catch here is that the SDK maintainers must take up this change.).
So, in my Podfile, I wrote the following:
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == 'MyDevPod'
target.build_configurations.each do |config|
if config.name == 'My-First-Config'
config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Onone'
elsif config.name == 'My-Second-Config'
config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Owholemodule'
# ...
# and so on for the other configurations
# ...
end
end
end
end
end
This is also recommended by a few folks in a discussion in particular about SWIFT_OPTIMIZATION_LEVEL
. There’s even a plugin. It’s certainly a fine solution, and in general the approach enables all sorts of customizations.
But then I found out about the Podfile’s project
directive with build_configurations
hash (h/t to mokacoding’s article on the subject, which is almost 4 years old now–the only difference being that xcodeproj
has been renamed to project
). So, I was able to remove the post_install
hook in favor of this one-liner at the top of my Podfile:
project 'MyProject', 'My-First-Config' => :debug, 'My-Second-Config' => :release # and so on for the other configurations
This works because CP have coded the desired settings between Debug and Release, so that the project
build_configurations
hash maps to the settings I had set using post_install
previously. I prefer defining these in a first-class Podfile construct like project
as opposed to a more arbitrary-code solution such as post_install
.
🙏🏻 Enjoy the post? Please help support more like it by buying me a cup of coffee!.
💡 Suggestions, questions, comments? Please submit a PR!.