Articles index

Go all in with xcconfig

August 23, 2017

By Jeff Johnson

Many Xcode projects are a mess. Just look at your project's build settings. Gross, right? The best way to clean up your build settings is to move them to xcconfig files. Move all of them to xcconfig files. My app Underpass has zero custom build settings in its project.pbxproj file. How is this achieved?

I'm going to look at the Underpass for Mac project. The Underpass for iOS project has a similar arrangement. For the Mac, I created four xcconfig files, the full contents of which are at the end of this post. I added the xcconfig files to the Xcode project but made sure not to add them to the app target, because you don't want those files copied into the app bundle. Then I configured the Xcode project to use the xcconfig files:

Xcode Project Info

Let's look at a few "tricks" I used in the build settings. First, I set INFOPLIST_EXPAND_BUILD_SETTINGS, which allows me to define the app's version numbers in the xcconfig and have them automatically expanded in the Info.plist file:

    <key>CFBundleShortVersionString</key>
    <string>$(UNDERPASS_SHORT_VERSION)</string>
    <key>CFBundleVersion</key>
    <string>$(UNDERPASS_VERSION)</string>

Notice also that I've included the version numbers and bundle identifier in the GCC_PREPROCESSOR_DEFINITIONS. This allows me to use those build settings as C string literals and NSString literals in my Objective-C code. For example, dispatch_queue_create(PRODUCT_BUNDLE_IDENTIFIER, DISPATCH_QUEUE_SERIAL) and [bundleVersion isEqualToString:@UNDERPASS_SHORT_VERSION]. Sweet!

Finally, I customize the PRODUCT_BUNDLE_IDENTIFIER build setting in my Debug configuration so that I can test the app without corrupting the app's production data.

If you found these tips useful, you may want to consider hiring me. This blog post is your free trial, but now you have to subscribe.


Shared.xcconfig:

UNDERPASS_VERSION = 1.0.3b1
UNDERPASS_SHORT_VERSION = 1.0.3
ALWAYS_SEARCH_USER_PATHS = NO
ARCHS = x86_64
CODE_SIGN_ENTITLEMENTS = nonsource/Underpass.entitlements
CLANG_ENABLE_MODULES = YES
CLANG_ENABLE_OBJC_ARC = YES
CLANG_MODULES_AUTOLINK = YES
COMBINE_HIDPI_IMAGES = YES
DEPLOYMENT_LOCATION = NO
DEVELOPMENT_TEAM = 8LT69JF8NZ
ENABLE_STRICT_OBJC_MSGSEND = YES
GCC_GENERATE_DEBUGGING_SYMBOLS = YES
GCC_NO_COMMON_BLOCKS = YES
GCC_PRECOMPILE_PREFIX_HEADER = YES
GCC_PREFIX_HEADER = shared/PrefixHeader.pch
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) PRODUCT_BUNDLE_IDENTIFIER=\"$(PRODUCT_BUNDLE_IDENTIFIER)\" UNDERPASS_VERSION=\"$(UNDERPASS_VERSION)\" UNDERPASS_SHORT_VERSION=\"$(UNDERPASS_SHORT_VERSION)\"
GCC_SYMBOLS_PRIVATE_EXTERN = YES
INFOPLIST_EXPAND_BUILD_SETTINGS = YES
INFOPLIST_FILE = nonsource/Info.plist
MACH_O_TYPE = mh_execute
MACOSX_DEPLOYMENT_TARGET = 10.11
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO
PRODUCT_BUNDLE_IDENTIFIER = com.underpassapp.underpass
PRODUCT_NAME = Underpass
SDKROOT = macosx10.12
WARNING_CFLAGS = -Wall -Wextra -Wno-unused-parameter
WRAPPER_EXTENSION = app
//Warnings
CLANG_WARN_ASSIGN_ENUM = YES
CLANG_WARN_DOCUMENTATION_COMMENTS = YES
CLANG_WARN_BOOL_CONVERSION = YES
CLANG_WARN_CONSTANT_CONVERSION = YES
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR
CLANG_WARN_EMPTY_BODY = YES
CLANG_WARN_ENUM_CONVERSION = YES
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES
CLANG_WARN_INFINITE_RECURSION = YES
CLANG_WARN_INT_CONVERSION = YES
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
CLANG_WARN_UNREACHABLE_CODE = YES
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
GCC_WARN_ABOUT_MISSING_NEWLINE = YES
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES
GCC_WARN_ABOUT_RETURN_TYPE = YES
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
GCC_WARN_MISSING_PARENTHESES = YES
GCC_WARN_SIGN_COMPARE = YES
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES
GCC_WARN_UNDECLARED_SELECTOR = YES
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE
GCC_WARN_UNUSED_FUNCTION = YES
GCC_WARN_UNUSED_LABEL = YES
GCC_WARN_UNUSED_PARAMETER = NO
GCC_WARN_UNUSED_VALUE = YES
GCC_WARN_UNUSED_VARIABLE = YES
GCC_WARN_64_TO_32_BIT_CONVERSION = YES

AppStore.xcconfig:

CODE_SIGN_IDENTITY = 3rd Party Mac Developer Application
COPY_PHASE_STRIP = YES
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
DEPLOYMENT_POSTPROCESSING = YES
GCC_OPTIMIZATION_LEVEL = s
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) UNDERPASS_APPSTORE
STRIP_INSTALLED_PRODUCT = YES
STRIP_STYLE = all
SEPARATE_STRIP = YES
VALIDATE_PRODUCT = YES

Debug.xcconfig:

CODE_SIGN_IDENTITY = Mac Developer
COPY_PHASE_STRIP = NO
DEBUG_INFORMATION_FORMAT = dwarf
DEPLOYMENT_POSTPROCESSING = NO
GCC_OPTIMIZATION_LEVEL = 0
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1
OTHER_CODE_SIGN_FLAGS = --timestamp=none
PRODUCT_BUNDLE_IDENTIFIER = com.underpassapp.underpass.debug
STRIP_INSTALLED_PRODUCT = NO

DeveloperID.xcconfig:

CODE_SIGN_IDENTITY = Developer ID Application: Jeff Johnson
COPY_PHASE_STRIP = YES
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
DEPLOYMENT_POSTPROCESSING = YES
GCC_OPTIMIZATION_LEVEL = s
STRIP_INSTALLED_PRODUCT = YES
STRIP_STYLE = all
SEPARATE_STRIP = YES
Articles index