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.

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.

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 projectbuild_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.