Wednesday, March 04, 2020

Conditional Compilation in Xcode

Recently I have interest in C/C++ #ifdef macro features in Swift. The main reason is that I have some debug codes through out my project for test and debug purpose. For example, I like to add deinit destruction with print() codes in classes to test memory leaks. Since those destructors have no purpose to clean up resources, I have to comment out them in production compilation.

In Swift, there are some conditional compilation features to including or excluding block of codes. For example, the following codes using #available to test if the current iOS matches required version.

if #available(iOS 11.0, *)

Further investigation, I find out that Swift does support #if statements to provide conditional compilation. The following are steps to implement the feature.

Define Custom Compilation Flags

The first step is to define customized complication flags in Xcode project. In the section of Build Settings, find Swift Compiler - Custom Flags (make sure All and Combined are enabled on top tab bar).

Then, you can add custom flag variables. Here are two examples of DEBUG_PRINT and DEBUG_DEINIT. For each flag, add -D before it, like "-D DEBUG_DEINIT -D DEBUG_PRINT"

Note: in the picture, I defined those two with _X as suffix to disable them. If I want to enable them in compilation, I remove _X.

Use Custom Compilation Flags in Swift

To use #if feature, it is quite straightforward. For example, there is the conditional compilation block for destructor:

  1. // MARK: - CTOR
  3. deinit {
  4.  Logger.debug() {
  5.    String("\(CopyMoveViewController.className) deinit")
  6.  }
  7. }
  8. #endif
and here is an example of conditional compilation block for some codes:

  1. class Logger {
  2.  ...
  3.  static func debug(_ message: () -> String) {
  4.    #if DEBUG_PRINT
  5.    print(message())
  6.    #elseif DEBUG_DEINIT
  7.    print(message())
  8.    #endif
  9.  }
  10. }

Now I don't need to comment out some debug codes when I need to compile my project to production release target. The only thing I need to do is to disable those flags in my Xcode project file.