Skip to content

Building with CMake

Antoine Villeret edited this page Jul 2, 2015 · 19 revisions

Table of Contents

Motivation

Make a reliable cross-platform build-system for Jamoma. The minimal CMake version required is 3.0.

CMake basics

Reference

Setup :

git clone https://github.com/Jamoma/Jamoma
# ...[clone Core, Implementations/Max & Implementations/PureData, switch everything to dev]...
mkdir build
cd build

Release build on OS X with full package :

cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_JAMOMAMAX:Bool=True -DBUILD_JAMOMAPD:Bool=True ../Jamoma 
make package -j16

Release build on Linux :

cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_JAMOMAPD:Bool=True ../Jamoma 
make package -j16

Release build on Win32 with full package :

cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_JAMOMAMAX:Bool=True -G "Visual Studio 12 2013" ../Jamoma
msbuild PACKAGE.vcxproj  /p:Configuration=Release /m

Release build on Win64 with full package :

cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_JAMOMAMAX:Bool=True -G "Visual Studio 12 2013" -A x64 ../Jamoma
msbuild PACKAGE.vcxproj  /p:Configuration=Release /m

Build tree

CMake is not a build system per se, but more a meta-build system, in the sense that CMake's work is to generate platform-specific build scripts, in the format chosen by the user. One can for instance generate:

  • Makefiles / Ninja (a faster(about 10% for Jamoma) make replacement by google)
  • XCode projects
  • Visual Studio solutions
  • Code::blocks, Eclipse and project files for other common IDEs

The basic syntax is :

cmake [options] ..path to a folder containing a CMakeLists.txt.. 

For Jamoma, there is a CMakeLists.txt in the umbrella repository, and another in JamomaCore. When built from umbrella, only JamomaCore will be built by default. You can enable other implentation build with switches.

CMake will then generate a build tree in the folder it is called from. It is good practice to make an out-of-source build (and for Jamoma it is critical since the Max package and some test files will be copied from the source folder to the build tree).

For instance :

git clone https://github.com/Jamoma/Jamoma
pushd Jamoma
git submodule update --init
git submodule foreach git checkout dev
git submodule foreach git pull
cd  Implementations/PureData
git submodule update --init
popd
mkdir build
cd build
cmake ../Jamoma

Will generate a build tree in the build folder. The rest of this document will assume that the folder hierarchy is as follows :

base folder \
 build
 Jamoma \
    Core, etc...

Targets

CMake operate with targets. When there is a CMake command to add a library, a test, or an executable, CMake will generate targets. They will map to project files for the IDE generators, or simple make targets. For instance, there are specific targets for all the core libraries (Foundation, Modular, Graph, etc...) and all the extensions. There are also some useful targets either automatically generated by CMake in every case or added for the Jamoma project. For instance :

- `ExperimentalTest` to batch-run unit tests
- `code_coverage` to run code coverage on the unit tests (added by me).
- `ALL_BUILD` behaves like `make all`
- `CLEAN` behaves like `make clean`
- `INSTALL` behaves like `make install`
- `PACKAGE` creates a platform-specific package/installer (DMG on OS X, NSIS installer on Windows, Debian / RPM package on Linux...) with the things that are to be installed by `INSTALL`.

Build operations and variables

Common switches

Debug / Release

cmake -DCMAKE_BUILD_TYPE=Debug [...]
cmake -DCMAKE_BUILD_TYPE=Release [...]

JamomaMax

cmake -DBUILD_JAMOMAMAX=ON [...]

JamomaPd

cmake -DBUILD_JAMOMAPD=ON [...]

Local deployment

When developping for Max or Puredata it is often useful to keep the Max/Pd package the application uses up-to-date after each build. You can use make package then open the archive and manually copy the file to ~/Documents/Max*/Package. But this could be boring if you are building Jamoma several times a day. Instead you can set the installation folder with -DJAMOMAPD_INSTALL_FOLDER=/absolute/path/to/Where/you/want. And then run cmake on cmake_install.cmakewith the requiered component.

For instance, to install JamomaPd in the default user's package folder on OS X :

cmake -DBUILD_JAMOMAPD=ON -DJAMOMAPD_INSTALL_FOLDER=$HOME/Library/Pd ../Jamoma-CMake
make
cmake -DCMAKE_INSTALL_COMPONENT=JamomaPd -P cmake_install.cmake

Then to load Jamoma into PureData, add "Jamoma" to the library to load at startup. You can do that by launching Pd with pd -lib Jamoma or by adding it in the Preferences->Startup panel or even by putting a [Jamoma] object somewhere in your patch.

And to install Max package to the default user's package folder on OS X :

cmake -DBUILD_JAMOMAMAX=ON -DJAMOMAMAX_INSTALL_FOLDER=$HOME/Documents/Max/Package ../Jamoma-CMake
make
cmake -DCMAKE_INSTALL_COMPONENT=JamomaMax -P cmake_install.cmake

Thanks to the Max's extension mechanism, Jamoma will be automatically loaded at startup.

Code coverage

This requires gcovr, lcov, and a Debug build.

cmake -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE=True [...]

Generators and platform-specific variables

Generators are chosen with the -G command line switch. cmake --help will print all the available generators for the platform.

OS X

Calling CMake without generators generates Makefiles by default. To generate XCode projects :

cmake -G "XCode" ../Jamoma/

A Jamoma.xcodeproj file is then generated in the current folder, that can be opened with XCode (however there are still problems with '~' and '=' in the name of externals, I have to check them out).

It is possible to build from the command line :

xcodebuild -target [The target, like ALL_BUILD or Foundation]

To generate XCode projects targeted for iOS : (still experimental, I only quickly tested this with the simulator and not everything builds. Also, it will only build JamomaCore.)

# iOS
cmake -G "Xcode" -DCMAKE_TOOLCHAIN_FILE=../Jamoma/Core/Shared/CMake/toolchains/iOS.cmake ../Jamoma/Core 
# Simulator
cmake -G "Xcode" -DIOS_PLATFORM=SIMULATOR -DCMAKE_TOOLCHAIN_FILE=../Jamoma/Core/Shared/CMake/toolchains/iOS.cmake ../Jamoma/Core 

To generate fat binaries (by default CMake only generates x64) :

cmake "-DCMAKE_OSX_ARCHITECTURES=x86_64;i386" ../Jamoma

This switch is automatically enabled when building JamomaMax.

To build tests statically linked : (this has to be reviewed, I haven't checked it since about two months)

cmake -DSTATIC_TESTING ../Jamoma

Windows

By default, CMake will look for an installed version of Visual Studio and generate solutions & projects for this version. To specify a version :

cmake -DCMAKE_BUILD_TYPE=[Debug or Release] -G "Visual Studio 12 2013" ../Jamoma/
cmake -DCMAKE_BUILD_TYPE=[Debug or Release] -G "Visual Studio 12 2013" -A x64 ../Jamoma/ # In progress

Jamoma has been tested with VS2013 but might work with VS2012.

This will generate a Jamoma.sln in the current folder.

To build, either :

  • Open the created VS solution and build from the IDE.
  • msbuild [ALL_BUILD/PACKAGE/...].vcxproj /p:Configuration=[Debug or Release, according to the configuration that was used for CMake] /m

Linux

cmake ../Jamoma
make -j[number of processors]

Android

This requires the (heavy) Android SDK / NDK, and the Android toolchain file : https://github.com/taka-no-me/android-cmake/tree/experimental. But after that it's as straightforward as it is for Linux.

Rapsberry Pi (Cross Compilation)

The easiest way to build Jamoma for Raspberry Pi from Ubuntu 64bit is to checkout the toolchain here : https://github.com/avilleret/tools/tree/Jamoma with :

git clone -b Jamoma https://github.com/avilleret/tools.git

It is based on the official Rapsberry Pi toolchain to which I added Jamoma dependencies.

Then configure the build with the following :

mkdir build 
cd build
mkdir RPi-bin
cmake -DCMAKE_TOOLCHAIN_FILE=../Shared/CMake/toolchains/arm-linux-gnueabihf.cmake -DJAMOMAPD_INSTALL_FOLDER=${PWD}/RPi-bin -DCROSS_COMPILER_PATH=${PWD}/../tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/ .. 
make
make install

This will produce a Jamoma package in the build/RPi-bin folder that you can copy to your Raspberry Pi's ~/pd-externals folder.

Mingw-w64 (crosscompilation for Windows 32bit from Linux)

You need a cutting edge version of the toolchain, at least the 4.0.2-4. Look at mingw-w64.org to find one for your OS.

Then configure your project with something like (for JamomaPuredata) :

cmake -DBUILD_JAMOMAPD=ON -DBUILD_JAMOMAMAX=OFF -DCMAKE_TOOLCHAIN_FILE=../PureData/Shared/CMake/toolchains/mingw-64.cmake -DJAMOMA_CORE_SRC_PATH=`realpath ${PWD}/../PureData/JamomaCore` -DPD_MAIN_PATH="$PWD/pd" -DCMAKE_INSTALL_PREFIX="$PWD/JamomaInstall"  ../PureData/

Note that for building JamomaPuredata, you need Pd source and pass the path to the source with -DPD_MAIN_PATH="$PWD/pd" option. Of course you need to adjust all the paths to yours.

Writing CMakeLists.txt for Jamoma subprojects

-> For a library (a simple one): https://github.com/jamoma/JamomaCore/blob/dev/Graph/library/CMakeLists.txt

-> For an extension : (showcases use of external libraries) https://github.com/jamoma/JamomaCore/blob/dev/DSP/extensions/AudioEngine/CMakeLists.txt

-> For a Max external : https://github.com/jamoma/JamomaMax/blob/dev/source/j.cue/CMakeLists.txt

Using Jamoma from external projects using CMake.

A CMake configuration file for the Jamoma project is generated. This allows other apps that would like to use Jamoma to do things as straightforward as :

project (aProject)
find_package(Jamoma 0.6 REQUIRED) #Jamoma has to be installed somewhere.

add_executable(anExecutable "main.cpp")
target_link_libraries(anExecutable WIN32 MACOSX_BUNDLE Jamoma::Foundation Jamoma::Modular)

It is also possible to generate OS X .app bundles with the Jamoma libs & extensions correctly copied

# Make a copy at build time in the CMake-generated .app
copy_in_bundle_jamoma(anExecutable ${CMAKE_BINARY_DIR}/anExecutable.app "Foundation;Modular" "MIDI;Minuit;OSC;SystemLib")
# When installing, set the correct RPATHs in the executable, plug-ins and libraries.
fixup_bundle_jamoma(${CMAKE_INSTALL_PREFIX}/anExecutable.app anExecutable "Foundation;Modular")

This is in two steps because, basically, when building an app that involves both Qt and Jamoma, the official CMake Qt scripts will override the RPATHs in ways incompatible with Jamoma, hence we have to re-overwrite them afterwards.

Known problems & TODO

  • Run the Ruby tests from CMake.
  • Maybe run the Max/MSP integrations tests too ?
  • Check that the iOS build works correctly.
  • Document the CMake code, and do a full check-up.
  • Windows x64 build.
  • Windows : copy MSVC100D.dll, PortAudio.dll, libsndfile.dll on the package.
  • Use the FOLDER command to make nice folders in IDEs.
  • Optimize the way things are linked together (for now some extensions may link with unneeded libraries, especially in JamomaMax world).
  • Document the extensions that don't build on some platforms because of missing libraries (e.g. no portaudio at all on Android).