-
Notifications
You must be signed in to change notification settings - Fork 945
Cinder CMake Documentation
#Overview
This document describes how you can build libcinder and your application using cmake. This is our officially supported way to build system on most Posix platforms, while in general you can use cinder's cmake system on any platform. See the section on platform-specific notes for details.
- Building libcinder with CMake
- Building your application with CMake
- CinderBlocks and CMake
- Using CLion to build libcinder and your application
- Structure of Cinder's CMake Files
- Platform Specific Notes
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 deposit 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 (i.e. lib/macosx/Debug/libcinder.a
and lib/macosx/Release/libcinder.a
), so multiple configurations can live side by side.
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 runt he tests from the command line with make test
).
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 (for me currently) 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. Might take a while!
The best thing to do when adding cmake to your own project is to look at one of the samples, or start with a template from TinderBox. For both, you'll find that the CMakeLists.txt
file to 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 necessities on different platforms, 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 get found if you're starting with a standard application template created by TinderBox. 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()
).
ci_make_app()
also listens to the CINDER_VERBOSE
variable, so if that is on then you will see much more configuration information.
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).
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 that 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()
.
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 going 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 you to Preferences -> Build, Execution, Deployment
, and change the field called 'Generation path:' to 'build'.
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.
This section provides an overview of how we've structures the cmake build support 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 IDE like CLion.
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
orCINDER_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 full list). - Sets the
CMAKE_BUILD_TYPE
toDebug
if the user hasn't specified one. - Provides some shared cache options like
CINDER_VERBOSE
. - Sets a couple variables,
CINDER_TARGET_SUBFOLDER
andCINDER_LIB_DIRECTORY
, which define where the output binaries will be deposited 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.
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.
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.
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.
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.
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.