# Overview

This document describes how you can build libcinder and your application using cmake. This is Cinder's officially supported build system on most POSIX platforms, though in general you can use cinder's cmake system on any platform. See the section on platform-specific notes for details.

# Table of Contents

- Building libcinder with CMake
  - Command-line Options
- Building your application with CMake
  - Printing verbose information when building your application
- CinderBlocks and CMake
  - Using CinderBlocks
  - Writing CMake support for a CinderBlock
- Using CLion to build libcinder and your application
  - Running a Cinder sample directly from Cinder's main project.
- Structure of Cinder's CMake Files
  - configure.cmake
  - Configuring libcinder
- CMake Best Practices
  - Assign compiler configurations to targets
  - Keep the code style consistent
- Platform Specific Notes
  - Microsoft Windows

# Building libcinder with CMake

To build libcinder from the command line, first make sure you have CMake version 3.0 or later installed. Then the process is similar to most other cmake projects you may have used, for example you can do the following from within the main cinder repo path:

    mkdir build
    cd build
    cmake ..
    make -j4

Upon completion, this will generate a static libcinder binary within the `$(CINDER_PATH)/lib` folder for your application to link against. By default you'll be building for Debug configuration, to build release you change the above `cmake` command to:

    cmake -DCMAKE_BUILD_TYPE=Release ..
    make -j4

The runtime output directory for different configurations will automatically end up within different folders (e.g. `lib/macosx/Debug/libcinder.a` and `lib/macosx/Release/libcinder.a`), so multiple configurations can live side by side.

### Command-line Options

There are a few project configuration settings you can change by either editing the `CMakeCache.txt` file (or using some GUI to do this), or from the command line with the `-D` option. All settings related to cinder are prefixed with `CINDER_`. Some of the more common settings are listed below, take a look in the `CMakeCache.txt` file for a full and updated list.

`CINDER_VERBOSE`: prints out verbose information from within Cinder's CMake scripts during configuration.

`CINDER_TARGET`: Sets the target to compile to. This defaults to one appropriate for the current operating system, but in some cases, for example Android, you must set it manually (i.e. `cmake -DCINDER_TARGET=android ..`).

`CINDER_TARGET_GL`: Sets the target OpenGL version. Usually defaults to `ogl` (desktop modern OpenGL), but other valid options are `es2`, `es3`, and `es31`. These are useful when you are building for something like the Raspberry Pi.

`CINDER_BUILD_TESTS`: Builds the unit tests (You can then run the tests from the command line with `make test` / `make check`).

`CINDER_BUILD_SAMPLE`: Specify the name of a single sample to build, after libcinder successfully builds. It will end up in the current build folder. For example, adding the option `-DCINDER_BUILD_SAMPLE=BasicApp` will also build the BasicApp sample and place it at `build/Debug/BasicApp/BasicApp.app`.

`CINDER_BUILD_ALL_SAMPLES`: Specifying `True` here will tell CMake to try to build all of the samples within cinder's samples directory. Be prepared to wait a while.

# Building your application with CMake

Often the best thing to do when adding CMake support to your own project is to look at one of the samples as a starting point. You'll find the `CMakeLists.txt` file will be at `proj/cmake/CMakeListst.txt`. You can still build it from the base directory of your project if you choose, with something like:

    cd my_project
    mkdir build
    cd build
    cmake ../proj/cmake
    make -j4

To simplify configuring your project and the many platform-specific particulars, we use a utility function called `ci_make_app()`, which takes a number of arguments to build your application. For example, here is the CMakeLists.txt file used for building the `_opengl/ObjLoader` sample:

    cmake_minimum_required( VERSION 3.0 FATAL_ERROR )
    set( CMAKE_VERBOSE_MAKEFILE ON )

    project( opengl-ObjLoader )

    get_filename_component( CINDER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../.." ABSOLUTE )
    get_filename_component( APP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../" ABSOLUTE )

    include( "${CINDER_PATH}/proj/cmake/modules/cinderMakeApp.cmake" )

    ci_make_app(
        APP_NAME    "ObjLoader"
        CINDER_PATH ${CINDER_PATH}
        SOURCES     ${APP_PATH}/src/ObjLoaderApp.cpp
        INCLUDES    ${APP_PATH}/include
        RESOURCES   ${APP_PATH}/../../data/models/8lbs.obj
    )

It is quite brief, but you can see that we've specified a number of common things necessary when building a custom application, such as source files and include paths.

Arguments to `ci_make_app()` include:

`APP_NAME`: Defines the name of your application. Defaults to the current `${PROJECT_NAME}`.

`CINDER_PATH`: Relative path to cinder's root directory, used to find the `cinder` module via CMake's `find_package()` system. Required.

`SOURCES`: list of source files. Required.

`INCLUDES`: list of include directories

`ASSETS_PATH`: path to your assets folder (see explanation of assets here. This will automatically be found if your project folder structure follows the standard pattern. Note that by default, this gets symlinked next to your built application, however specifying `-DCINDER_COPY_ASSETS=On` at the command line will cause the assets to be copied over instead.

`RESOURCES`: list of resources, which are handled in a platform specific manner (see explanation of resources here.

`BLOCKS`: list of CinderBlocks that your application depends on. These can be specified by either a relative or absolute path, or by providing the name of one of the blocks that ships with cinder (e.g. lives in the `$(CINDER_PATH)/blocks` folder).

`LIBRARIES`: list of lib files to be linked (via `target_link_libraries()`).

### Printing verbose information when building your application

`ci_make_app()` also respects the `CINDER_VERBOSE` variable, so if that is on then you will see much more configuration information.

# CinderBlocks and CMake

### Using CinderBlocks

As mentioned above, you can provide a list of CinderBlocks to `ci_make_app()` `BLOCKS` argument, which will then attempt to first find the block by either relative or absolute path, and then within Cinder's `blocks` folder (by its name alone).

### Writing CMake support for a CinderBlock

The basic pattern we use for CinderBlock support is CMake's packages system, specific the `Package Configuration File` variant. For a concrete example, take a look at the OSC block's OSCConfig.cmake file.

First and foremost, `ci_make_app()` finds a file by looking for it at a specific location, within the block's `proj/cmake/` folder, and you must use the block's name as the prefix to `*Config.cmake`. Then, we define that it is a library with the `add_library( OSC ${source_files} )` command, along with any other dependencies on the block.

In the case of a header-only CinderBlock, there won't be a target, but you can still specify the include and library dependencies with `BLOCK_NAME_INCLUDE_DIRS` and `BLOCK_NAME_LIBRARIES`. Also note that, as in the case of the TUIO block, a block configuration can specify that it depends on another block with CMake's `add_dependencies()`.

# Using CLion to build libcinder and your application

Aside from the command line, you can also use JetBrains CLion to build and work on both libcinder and your application. `CLion` is a sophisticated C++ IDE with many nice syntax features around context-aware searching and refactoring, so it makes for a nice environment to code on your Cinder tasks.

To build libcinder with CLion, open the main Cinder path within the IDE, wait for the initial symbol indexing to finish, and select `Run -> Build`. This will by default build the Debug configuration; to change that to Release, you can modify the CMakeCache.txt file (along with any other Cinder cache options) by navigating to the CMake panel at the bottom and finding the button on the left that says 'Open CMakeCache File', and changing the `CMAKE_BUILD_TYPE` setting to `Release` there.

Note that by default, CLion will output build files into a folder called `cmake-build-debug`. If you want to change this to the usual `build`, which will automatically get ignored by Cinder's `.gitignore` file, then navigate to `Preferences -> Build, Execution, Deployment`, and change the field called 'Generation path:' to 'build'.

### Running a Cinder sample directly from Cinder's main project.

There are a couple CMakeCache.txt options that will allow you to conveniently build and run a sample that ships with Cinder alongside building the main library. First, you can set the option `CINDER_BUILD_SAMPLE` to any of the sample names (ex. `CINDER_BUILD_SAMPLE=_opengl/Cube`), and then you will be able to run that sample by selecting it in the the `Select/Run Configuration` drop-down in the top right. Alternatively, you could set `CINDER_BUILD_ALL_SAMPLES=On`, which will load the configurations for all Cinder samples, and you can then run any one of them from within the IDE.

# Structure of Cinder's CMake Files

This section provides an overview of how CMake build support is structured within the Cinder repo.

Cinder's CMake scripts live in the common folder proj/cmake. The root `CMakeLists.txt` file is largely there so that it is easy to find, and so that our build configuration plays nicely with CMake-based IDEs like CLion.

### configure.cmake

One of the first things that we do is to `include()` the common `configure.cmake` file, which is shared by Cinder, libraries that depend on Cinder, and applications. It defines some global variables such as:

- `CINDER_TARGET`, if it hasn't been defined by the user. See above section on Command-line Options for details.
- A platform-specific variable: one of `CINDER_LINUX`, `CINDER_MAC`, `CINDER_MSW`, `CINDER_COCOA_TOUCH` or `CINDER_ANDROID`.
- `CINDER_TARGET_GL`, if it hasn't been defined by the user. See above section on Command-line Options for details.
- Defines some useful OpenGL variables such as `CINDER_GL_CORE`, `CINDER_GL_ES`, etc. (see `configure.cmake` for the full list).
- Sets the `CMAKE_BUILD_TYPE` to `Debug` if the user hasn't specified one.
- Provides some shared cache options like `CINDER_VERBOSE`.
- Sets a couple variables, `CINDER_TARGET_SUBFOLDER` and `CINDER_LIB_DIRECTORY`, which define where the output binaries will be generated for each target.

In short, `configure.cmake` is meant to provide a a place where common variables can be declared based on the same commands for any cinder-based project, including cinder itself.

### Configuring libcinder

The next thing we do is configure the platform independent aspects of the `cinder` target. These steps live in libcinder_configure.cmake and libcinder_source_files.cmake. The platform-specific configuration is broken out into separate sources (ex. platform_linux.cmake to ease extending the build system to new platforms. This way you can see source files that only pertain to a specific platform by viewing its specific `platform_*.cmake` file.

Finally, we create the actual `cinder` target within libcinder_target.cmake, which among other things contains the commands to `add_libary( cinder ... )`. Also importantly, this file is responsible for exporting dependency information and creating a `cinderConfig.cmake` file that will later be used with `find_package()` by libraries and applications that depend on Cinder.

# CMake Best Practices

Below are some guidelines for how we've been working on the CMake build setup within Cinder, which are useful to read over if you plan on making contributions and want to streamline your pull requests.

#### Assign compiler configurations to targets

We try to 'leak' as little compiler configuration as possible. This means using things methods like, for example, `target_include_directories( target ... )` instead of the older `include_directories( ... )` and then relying on CMake's package system to apply the settings based on dependencies. This pertains to both developing on CMake for libcinder and CinderBlocks.

#### Keep the code style consistent

As with all community projects, it makes things easier to keep a consistent style. CMake might be a funky language, but we've more or less developed our own readable way to write in it, which is based on the spacing described in Cinder's styleguide as much as possible.

# Platform Specific Notes

### Microsoft Windows

As of this writing, we do not support building from CMake-generated Makefiles on Windows, simply because the GCC toolchain is too difficult to set up there with a compiler that supports the features we need (C++11). The best approach there is to use the provided Visual Studio project files, as explained here. You can however generate new Visual Studio project files from CMake, if that suits your needs.