# https://github.com/jcampbell05/xcake # http://www.rubydoc.info/github/jcampbell05/xcake/master/file/docs/Cakefile.md # this is a sample Cakefile for a fictional project that is called "CakeMania" #=== # just helper variables to use these values in a consistent way across whole file iOSdeploymentTarget = "8.0" currentSwiftVersion = "3.0.1" # to set "Use Legacy Swift ..." to "No" companyIdentifier = "com.CakeMania" developmentTeamId = "XYZXYZ" # for automatic debug signing in Xcode 8 testSuffix = "Tst" testSuffixUI = "UI" + testSuffix provProfAdHoc = "XXX" provProfAppStore = "YYY" #=== 3d-party integration keys (global variables) # The values below will be used to set "user-defined" build settings # for build configurations on target level, # so we can reuse the same, lets say, "test" FB key # within several "test" configurations (for example, the same test key # would be used for "Debug" and "Staging" configurations), and can easily # see what is the value/key we use for testing and production, # and even update it in future if needed. # "FACEBOOK_KEY" facebookProdKey = "888888888888888" facebookTestKey = "999999999999999" #=== # lets define high level project settings project.name = "CakeMania" project.class_prefix = "CMN" project.organization = "CakeMania Inc." #=== # Below we explicitly define the list of project build configurations. # If you do not define it explicitly, Xcake will implicitly define default ones, # that are equivalent to this: # # project.debug_configuration :Debug # project.release_configuration :Release # project.debug_configuration :Debug # for local development/debugging only, pointing to "test.*" API server project.release_configuration :Staging # for alpha and beta AdHoc builds, pointing to "test.*" API server project.release_configuration :RC # for release candidate AdHoc builds, pointing to "rc.*" API server project.release_configuration :Production # for App Store ready AdHoc builds, pointing to "www." API server project.release_configuration :AppStore # for App Store builds, pointing to "www." API server # Note, that Xcake will also automatically create set of project "Schemes" - # one for each build configuration, their names will be constructed from # project name and configuration name, separated by dash, like this: # # "-" # # NOTE: every scheme will have the same build configiuration # for all phases (Run, Test, Profile, Archive). If you need different build configurations # based on phase - lets say one configuration for Run, but different one for Archive - # consider to have different build configurations (and as result - build shemes) for these purposes # (as proposed in this sample file). # # For this example, shemes will be: # # "CakeMania-Debug" # "CakeMania-Staging" # "CakeMania-RC" # "CakeMania-Production" # "CakeMania-AppStore" #=== DEFAULT target settings # Below we define "project level" build configurations. # REMEMBER this entiire file is just an interpretable script, # and the structure below is just a loop. # At every iteration we have reference to one # of the build configurations defined above explicitly or implicitly. # In this case, we set the same build settings to each configuration, # but, if we need to have some settings to be different for different # configurations, then you can use "if" expression to set different build settings # dependiong on "configuration.name" (we will see example of that in target settings below in this document). project.all_configurations.each do |configuration| # the settings listed below are just a copy # of what Xcode sets explicitly in a newly created Xcode # project file in comparison with default values # (the values that are marked with bold font). configuration.settings["ENABLE_BITCODE"] = "YES" configuration.settings["SDKROOT"] = "iphoneos" configuration.settings["GCC_DYNAMIC_NO_PIC"] = "NO" configuration.settings["OTHER_CFLAGS"] = "$(inherited) -DNS_BLOCK_ASSERTIONS=1" configuration.settings["GCC_C_LANGUAGE_STANDARD"] = "gnu99" configuration.settings["CLANG_ENABLE_MODULES"] = "YES" configuration.settings["CLANG_ENABLE_OBJC_ARC"] = "YES" configuration.settings["ENABLE_NS_ASSERTIONS"] = "NO" configuration.settings["ENABLE_STRICT_OBJC_MSGSEND"] = "YES" configuration.settings["CLANG_WARN_EMPTY_BODY"] = "YES" configuration.settings["CLANG_WARN_BOOL_CONVERSION"] = "YES" configuration.settings["CLANG_WARN_CONSTANT_CONVERSION"] = "YES" configuration.settings["GCC_WARN_64_TO_32_BIT_CONVERSION"] = "YES" configuration.settings["CLANG_WARN_INT_CONVERSION"] = "YES" configuration.settings["GCC_WARN_ABOUT_RETURN_TYPE"] = "YES_ERROR" configuration.settings["GCC_WARN_UNINITIALIZED_AUTOS"] = "YES_AGGRESSIVE" configuration.settings["CLANG_WARN_UNREACHABLE_CODE"] = "YES" configuration.settings["GCC_WARN_UNUSED_FUNCTION"] = "YES" configuration.settings["GCC_WARN_UNUSED_VARIABLE"] = "YES" configuration.settings["CLANG_WARN_DIRECT_OBJC_ISA_USAGE"] = "YES_ERROR" configuration.settings["CLANG_WARN__DUPLICATE_METHOD_MATCH"] = "YES" configuration.settings["GCC_WARN_UNDECLARED_SELECTOR"] = "YES" configuration.settings["CLANG_WARN_OBJC_ROOT_CLASS"] = "YES_ERROR" configuration.settings["CURRENT_PROJECT_VERSION"] = "1" # just default non-empty value configuration.settings["DEFINES_MODULE"] = "YES" # http://stackoverflow.com/a/27251979 configuration.settings["SWIFT_OPTIMIZATION_LEVEL"] = "-Onone" configuration.settings["CLANG_WARN_INFINITE_RECURSION"] = "YES" # Xcode 8 configuration.settings["CLANG_WARN_SUSPICIOUS_MOVE"] = "YES" # Xcode 8 configuration.settings["ENABLE_STRICT_OBJC_MSGSEND"] = "YES" # Xcode 8 configuration.settings["GCC_NO_COMMON_BLOCKS"] = "YES" configuration.settings["ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES"] = "$(inherited)" # "YES" configuration.settings["SWIFT_VERSION"] = currentSwiftVersion #=== if configuration.name == "RC" || configuration.name == "AppStore" configuration.settings["DEBUG_INFORMATION_FORMAT"] = "dwarf-with-dsym" configuration.settings["SWIFT_OPTIMIZATION_LEVEL"] = "-Owholemodule" # Xcode 8 end end #=== Targets # So far, we've defined poject settings and # project level build configuration settings # (which define defaults for target level build configurations). # # Now it's time to define target-level build settings. # Below we define "application"-type target and # put all it's settings (including definition or related unit test targets) # inside "application_for ... do ... end" structure. target do |target| target.name = project.name target.language = :swift target.type = :application target.platform = :ios target.deployment_target = iOSdeploymentTarget #=== # Now lets set target-level build settigns. # Again, the structure below is just a loop, # everything between "target.all_configurations.each do |configuration|" # and corresponding "end" (see below on the same level in the very bottom of the file) # is body of this loop, that repeats every iteration. This loop goes through # the list of build configurations (defined above) and on each iteration # we have variable "configuration" that contains reference to one # of the build configurations in CONTEXT of the TARGET. This is equivalent of setting # build settings on target-level in Xcode (you can access it if you choose to # see build settigns by "Levels", not "Combined"). # Imagine we have project folder structure like this: # # - Cakefile # - Info/ # | - CakeMania.plist # | - CakeManiaTst.plist # | - CakeManiaUITst.plist # - Lib/ # | - ... # - Res/ # | - CakeMania.entitlements # | - CakeMania-test.entitlements # | - ... # | - CakeMania.xcassets/ # | - ... # | - AppIcon.appiconset/ # | - ... # | - ... # - Src/ # | - ... # | - ObjC/ # | - Prefix.pch # | - CakeMania-Bridging-Header.h # | - ... # - Tst/ # | - ... # - UITst/ # | - ... # target.all_configurations.each do |configuration| #=== Build Settings - Core configuration.product_bundle_identifier = companyIdentifier + "." + target.name configuration.supported_devices = :universal configuration.settings["INFOPLIST_FILE"] = "Info/" + target.name + ".plist" configuration.settings["PRODUCT_NAME"] = "$(TARGET_NAME)" configuration.settings["CODE_SIGN_ENTITLEMENTS"] = "Res/CakeMania.entitlements" configuration.settings["GCC_PREFIX_HEADER"] = "Src/ObjC/Prefix.pch" # configuration.settings["FRAMEWORK_SEARCH_PATHS"] = "$(inherited)" configuration.settings["LIBRARY_SEARCH_PATHS"] = "$(inherited) $(SRCROOT)/Lib/**" configuration.settings["ASSETCATALOG_COMPILER_APPICON_NAME"] = "AppIcon" # configuration.settings["ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME"] = "Brand Assets" configuration.settings["SWIFT_OBJC_BRIDGING_HEADER"] = "Src/ObjC/CakeMania-Bridging-Header.h" configuration.settings["OTHER_LDFLAGS"] = "$(inherited) -ObjC" # make configuration name available in run time: configNameFlag = "CONFIG_" + configuration.name.upcase configuration.settings["GCC_PREPROCESSOR_DEFINITIONS"] = "$(inherited) " + configNameFlag + "=1" # Obj-C support configuration.settings["OTHER_SWIFT_FLAGS"] = "$(inherited) -D" + configNameFlag # Swift support # This will show "Automatic" in Xcode, # relies on proper/valid "PROVISIONING_PROFILE" value: # configuration.settings["CODE_SIGN_IDENTITY[sdk=iphoneos*]"] = nil # DEPRECATED # Xcode 8 automati c signing support configuration.settings["CODE_SIGN_IDENTITY[sdk=iphoneos*]"] = "iPhone Developer" configuration.settings["DEVELOPMENT_TEAM"] = developmentTeamId #=== Build Settings - Per-configuration # NOTE: any configuration-specific settings below will override # common settings that you already applied above inside this # "target.all_configurations.each do |configuration|" block if configuration.name == "Debug" #=== Config configuration.settings["CODE_SIGN_ENTITLEMENTS"] = "Res/CakeMania-test.entitlements" #=== Config - User Defined Build Settings configuration.settings["FACEBOOK_KEY"] = facebookTestKey end #=== if configuration.name == "Staging" #=== Config configuration.settings["PROVISIONING_PROFILE"] = provProfAdHoc configuration.settings["CODE_SIGN_ENTITLEMENTS"] = "Res/CakeMania-test.entitlements" #=== Config - User Defined Build Settings configuration.settings["FACEBOOK_KEY"] = facebookTestKey end #=== if configuration.name == "RC" #=== Config configuration.settings["PROVISIONING_PROFILE"] = provProfAdHoc configuration.settings["CODE_SIGN_ENTITLEMENTS"] = "Res/CakeMania-test.entitlements" #=== Config - User Defined Build Settings configuration.settings["FACEBOOK_KEY"] = facebookTestKey end #=== if configuration.name == "Production" #=== Config configuration.settings["PROVISIONING_PROFILE"] = provProfAdHoc # AdHoc #=== Config - User Defined Build Settings configuration.settings["FACEBOOK_KEY"] = facebookProdKey end #=== if configuration.name == "AppStore" #=== Config configuration.settings["PROVISIONING_PROFILE"] = provProfAppStore #=== Config - User Defined Build Settings configuration.settings["FACEBOOK_KEY"] = facebookProdKey end end #=== Extra System Frameworks # Here is how we tell Xcake to include Apple system framework # into the target. # NOTE: "target.system_frameworks" is an array, that always have at least # "Foundation" and "UIKit", os it's always non-empty and we should not initialize it # before adding something there, so we jsut add values, one at a time (one per each line below). target.system_frameworks << "AdSupport" target.system_frameworks << "QuartzCore" #=== Source Files # Here is how we tell Xcake where to look for source files # which need to be added into the target. Moreover, the folder struture # will be re-created with Xcode groups. # NOTE: "target.include_files" is an array, that is empty by default # (no source files will be added to the target). So it's our responsibility # to initialize this array (with "=" operand) before adding values/elements # into it (with "<<" operand). Remember, this file is a Ruby script, and # that's just how Ruby works. target.include_files = ["Src/**/*.*"] # initialize array with 1 element target.include_files << "Lib/**/*.*" # add value into already non-empty array target.include_files << "Res/**/*.*" # add another value #=== Tests # Below we define unit tests target for the application target. # "unit_tests_for" is a reserved word, then you put variable that contains reference # to the application target that you want to create unit tests for, it's "target" in our case. # The "test_target" is reference to the newly created unit test target # so we can configure it as we want - set name, build configurations (at least info plist file) # and its source files, or course. The rules of how we work with test target (set its settings) # are the same, as we work with application target. unit_tests_for target do |test_target| test_target.name = target.name + testSuffix test_target.all_configurations.each do |configuration| configuration.settings["INFOPLIST_FILE"] = "Info/" + test_target.name + ".plist" end #=== Source Files test_target.include_files = [testSuffix + "/**/*.*"] # we set array with 1 element here! end #=== # Below we define UI tests target for the application target. # See https://github.com/jcampbell05/xcake/issues/44 ui_tests_for target do |test_target| test_target.name = target.name + testSuffixUI test_target.all_configurations.each do |configuration| configuration.settings["INFOPLIST_FILE"] = "Info/" + test_target.name + ".plist" end #=== Source Files test_target.include_files = [testSuffixUI + "/**/*.*"] # we set array with 1 element here! end end