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
constants.rb, and project_helper.rb where
COMMON_BUILD_SETTINGS is accessed via
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
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
💡 Suggestions, questions, comments? Please submit a PR!.