Cakefile Syntax Reference

The Cakefile contains a lightweight DSL which provides the instructions on how to generate a project file. We adopt the convention over configuration and thus it can be very simple:

  application_for :ios, 8.0 do |target|
      target.name = "MyApp"
  end

and here is much more complicated one:

  debug_configuration :staging
  debug_configuration :debug
  release_configuration :release

  application_for :ios, 8.0 do |target|
    target.name = "test"
    target.all_configurations.each { |c| c.supported_devices = :iphone_only }

    unit_tests_for target
  end

As you can see, it is super easy to read; The goal of Xcake is to keep everything readable, efficient and concise.

Project

A project is automatically created from a Cakefile. To customize a Project you can easily access all of it's properties via the project method.

project do |p|
  p.project_name = "Project"
end

You can also directly set the properties without a block, like so:

project.project_name = "Project"

Properties

Project Name

Sets the filename for the project

project.name = "Project"

Class Prefix

Sets the class prefix for the project

project.class_prefix = "XC"

Organization

Sets the organization for the project.

project.organization = "Xcake Productions"

Targets

Targets are the way we make products such as Applications, Extensions, Libraries and Tests. Xcake provides some easy ways to produce these types of targets but also allows you to drop down a level if you need more power.

Applications

A project can specify any application targets such as iOS or Mac Apps.

iOS App:

application_for :ios, 8.0

Mac App:

application_for :mac, 8.0

Tests

We can also specify a testing targets for other targets as well:

application_for :mac, 8.0 do |target|
  unit_tests_for target
end

The above code will create a complementary unit tests target for the target. The unit tests target name will be default <target.name>Tests, so if your target.name is "MyFirstApp" then your unit tests target will be named "MyFirstAppTests", and Xcake will include any files that are placed under folder with the same name/path (if it exists).

If you want to manually control configuration of unit tests targets (and/or have multiple ones), then you should do like this:

application_for :mac, 8.0 do |target|

  unit_tests_for target do |test_target|

        test_target.name = "MyAwesomeTests"
        test_target.include_files = ["Tests/**/*.*"]

        # configure any other target-related properties
        # as you would do with application target

    end
end

UI Tests

To create UI tests target, you do everything the same as for unit tests, but instead of "unit_tests_for" use "ui_tests_for", like this:

application_for :mac, 8.0 do |target|

  ui_tests_for target do |test_target|

        test_target.name = "MyAwesomeUITests"
        test_target.include_files = ["UITests/**/*.*"]

        # configure any other target-related properties
        # as you would do with application target

    end
end

Watch

To create watch applications we can simply use the watch_app_for method:

application_for :mac, 8.0 do |target|
    watch_app_for target, 2.0
end

Custom Targets

If these aren't enough for you then you can specify a target and manually set up it's properties.

target do |target|
    target.name = "Target"
end

Properties

Name

Sets the name of the target

target.name = "Target"

Type

Sets the type of the target, Can be :application, :dynamic_library, :framework or :static_library.

target.type = :application

Platform

Sets the platform of the target. Can be :ios, :osx, :tvos or :watchos

target.platform = :ios

Deployment Target

Sets the deployment target for the platform.

target.deployment_target = 8.0

Language

Sets the primary language of the target, can be :objc or :swift.

target.language = :swift

Include Files

Sets the files to be included for a target, files and groups will be added to the project to match the file system.

Xcake implicity figures out which build phase to add the files to, meaning source code will be compiled and libraries linked.

See Here for file patterns

target.include_files = ["FolderOne/*.*"] # array
target.include_files << "FolderTwo/**/*.*" # add an item to array

Exclude Files

Sets the files to be excluded for a target, if no target uses these files they will be excluded from the project

See Here for file patterns

target.exclude_files = ["FolderToIgnore/*.*"] # array
target.exclude_files << "OtherFolderToIgnore/*.*" # add an item to array

Linked Targets

If you have another library or framework based target in the project you wish to use from another target (i.e in your application), you can indicate to xcake that you wish to link them using Linked Targets.

Xcake will make sue that the library is built and then linked to the target you wish to use it from.

target.linked_targets = [linked_target] # array

Here is a more illustrative example of how to link a library in the project so that it can be used from an application.


libraryTarget = target do |library_target|
# ...configuration here
end

application_for :ios, 10.0 do |application_target|
  application_target.linked_targets = [libraryTarget] # array
end

Build Phases

Xcake already implcitly creates build phases for you depending on how you configure your target however you can explicity create additional build phases depending on your needs.

Copy Files Build Phase

You can create a Copy Files build phase to copy files into a bundle.

target.copy_files_build_phase "Build Phase Name" do |phase|
  phase.files = ["PublicHeader.h"] # array
  phase.files << "OtherPublicHeader.h" # add an item to array
  phase.destination = :resources # can be any of `Constants::COPY_FILES_BUILD_PHASE_DESTINATIONS.keys`
end
Copy Headers Build Phase

You can create a Copy Headers build phase to expose headers for instance for a library.

target.headers_build_phase "Build Phase Name" do |phase|

  ## Public Headers
  phase.public = ["PublicHeader.h"] # array
  phase.public << "OtherPublicHeader.h" # add an item to array

  ## Private Headers
  phase.private = ["PrivateHeader.h"] # array
  phase.private << "OtherPrivateHeader.h" # add an item to array

  ## Project Only Header
  phase.project = ["ProjectHeader.h"] # array
  phase.project << "OtherProjectHeader.h" # add an item to array
end
Shell Script Build Phase

You can create a Shell Script build phase to run a script when building. The following creates a simple script printing Hello World:

target.shell_script_build_phase "Build Phase Name", "echo 'Hello World'"
end

You can optionally define input- and output (file list) paths, combinbed with a multi-line script, like this:

myScript = <<-SCRIPT
    echo "This is a multi-line script"
    echo "Hello World"
SCRIPT
target.shell_script_build_phase "Build Phase Name", myScript do |phase|
    phase.input_paths = ["$(SRCROOT)/$(TARGET_NAME)/**/*.txt"]
    phase.output_paths = ["$(SRCROOT)/$(TARGET_NAME)/OutputFiles/MyFile.txt"]
    phase.input_file_list_paths = ["$(SRCROOT)/$(TARGET_NAME)/**/*.xcfilelist"]
    phase.output_file_list_paths = ["$(SRCROOT)/$(TARGET_NAME)/OutputFiles/MyFileList.xcfilelist"]
end

Note: to move the build phase before all other build phases (right before the Compile Sources phase), use target.pre_shell_script_build_phase instead.

Configurations

Xcake allows you define a hierarchy of build configuations like you would in Xcode for the Project and the Targets.

Debug Configurations

For configurations used for internal testing we create a debug configuration, this comes with sensible defaults optimized for debugging (i.e Assertions enabled).

debug_configuration :staging

We can modify settings for each configuration easily.

debug_configuration :staging do |configuration|
  configuration.settings["KEY"] = "VALUE"
end

Release Configurations

For configurations used for release we create a release configuration, this comes with sensible defaults optimized for releasing (i.e Compiler optimizations enabled).

release_configuration :release

We can modify settings for each configuration easily.

release_configuration :release do |configuration|
  configuration.settings["KEY"] = "VALUE"
end

All Configurations

We can apply a particular shared setting across all of our configurations. Xcake provides a simply way of doing this via an "all" configuration.

This will return an array of all of the currently declared configurations.

all_configurations.each { |c| c.supported_devices = :iphone_only }

Targets

To modify settings for certain target, then its as simple as prefixing the target we want to modify the configuration for.


target.all_configurations.each { |c| c.supported_devices = :iphone_only }

debug_configuration :staging do |configuration|
  configuration.settings["KEY"] = "VALUE"
end

target.release_configuration :release do |configuration|
  configuration.settings["KEY"] = "VALUE"
end

Configuration Hiearchy

Xcake allows you to manage the configurations for the project and the target but it also has its own hiearchy of settings, which are in the following order (One at the top of the list are overwritten by ones at the bottom):

  • Default Settings These are the sensible defaults xcake provides for the configuration.

  • Custom Settings These are the settings set directly on the configuration.

Properties

Name

Sets the name of the configuration

configuration.name = "Release"

Configuration File

Sets the path to a XCConfig file to inherit build settings from.

configuration.configuration_file = "Files/Settings.xcconfig"

Build Settings

A hash of all the build settings for a configuration

configuration.settings["ENABLE_BITCODE"] = false

Build Settings Shortcuts

Xcake also provides some shortcuts for some common build settings.

Supported Devices

Allows you specify the devices an iOS App can run on, can be :iphone_only, :ipad_only or :universal

configuration.supported_devices = :iphone_only

Product Bundle Identifier

Allows you specify the product bundle identifier.

configuration.product_bundle_identifier = "com.test.app"

Preprocessor Definitions

Allows you to specify preprocessor definitions.

configuration.preprocessor_definitions["NAME"] = "VALUE"

Schemes

Xcake allows you to specify schemes for launching, testing, profiling and archiving targets.

When no schemes are specified for a target then Xcake will auto generate a scheme per configuration per target (i.e "Target-Debug" and "Target-Release")

Creating A Scheme

We can create a scheme with the name of the target like so:

target.scheme(target.name)

If we don't configure this scheme then it will default to the recommended Apple settings of using the debug build configurations for everything except the Archive action which will use the Release configuration.

We can modify settings for a scheme easily.

target.scheme(target.name) do |scheme|
  scheme.build_configuration = :staging
end

Properties

Name

Sets the name of the scheme

scheme.name = "MyApp"

Test Configuration

Sets the configuration to use when running tests

scheme.test_configuration = :debug

Launch Configuration

Sets the configuration to use when running tests

scheme.launch_configuration = :debug

Profile Configuration

Sets the configuration to use when profiling a target

scheme.profile_configuration = :debug

Analyze Configuration

Sets the configuration to use when analyzing a target

scheme.analyze_configuration = :debug

Archive Configuration

Sets the configuration to use when archiving

scheme.archive_configuration = :debug