CMake is a cross-platform build system which generates build files for use by native build systems for different platforms. On UNIX-like systems it generates makefiles. CMake provides easier per-project build configuration, a more standard build environment across different platforms, additional testing infrastructure, and out-of-source compilation.
Out-of-source compilation uses a separate object directory for build results while leaving the original source directory untouched. This makes it possible to perform multiple simultaneous builds for multiple platforms from one single source directory, and to more easily see which files have changed when committing new code.
To begin building with CMake start with a clean workspace. Set your I3_PORTS and JAVA_HOME environment variables. You’ll also need LD_LIBRARY_PATH set to include the architecture-dependent directory containing libzip.so for anything that will require Java (the following examples use bash as an example):
$ export I3_PORTS=~/IceCube/i3tools
$ export JAVA_HOME=/usr/java/j2sdk1.4.2
$ export LD_LIBRARY_PATH=${JAVA_HOME}/jre/lib/amd64
With cmake one does “out-of-source” builds. This makes it easier to build several configurations against one set of source, and to be sure that the build process does not modify the source itself (e.g. no temporary files end up laying around in your checkout. So create a work directory and check out source to a directory called src:
mkdir -p ~/IceCube/meta-projects/offline-software/trunk
cd ~/IceCube/meta-projects/offline-software/trunk
svn co http://code.icecube.wisc.edu/svn/meta-projects/offline-software/trunk src
Note the “src” on the end of the svn co command
Create the object directory parallel to the source directory and execute cmake in the object directory to create the build environment:
$ pwd
~/IceCube/meta-projects/offline-software/trunk
$ mkdir build
$ ls
build src
$ cd build
$ $I3_PORTS/bin/cmake ../src
<lots of cmake output omitted>
-- Configuring done
-- Generating done
-- Build files have been written to: ~/IceCube/meta-projects/offline-software/build
At this point the contents of the object directory should look somewhat like that of the source directory. Main differences:
$ ls
CMakeCache.txt cmake_install.cmake glshovel/ pfclasses/
CMakeFiles/ coordinate-service/ icepick/ pfreader/
DOMcalibrator/ daq-decode/ icetray/ phys-services/
I3Db/ dataclasses/ interfaces/ tarball_hook.sh*
Makefile dataio/ jebclasses/ twr-decode/
Testing/ docs/ lib/ twrclasses/
amanda-core/ env-shell.sh* log4cplus.conf util/
bin/ examples/ mutineer/
cmake/ filter-tools/ payload-parsing/
And the source directory will have been untouched:
$ ls ../src
CMakeLists.txt@ dataclasses/ icepick/ pfclasses/
DOMcalibrator/ dataio/ icetray/ pfreader/
I3Db/ docs/ interfaces/ phys-services/
amanda-core/ examples/ jebclasses/ tarball_hook.sh.in
cmake/ filter-tools/ twr-decode/ util/
coordinate-service/ mutineer/ twrclasses/
daq-decode/ glshovel/ payload-parsing/
While still in the build directory execute make:
$ pwd
~/IceCube/meta-projects/offline-software/build
$ make
After make returns your build results will be in the object directory. Assuming no builds are made inside of the original source directory that directory can be reused for other builds, even if the platforms or build configurations differ.
The make target help will provide a list of valid targets in the CMake-generated Makefile:
$ pwd
~/IceCube/meta-projects/offline-software/build
$ make help
The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
<more targets omitted>
Having run cmake and generated a ‘’build’’ directory full of makefiles, one sets build options by editing the cmake cache. You can start the editor with “make edit_cache”, or by invoking the cache editor, ccmake, directly:
cd ~/Icecube/meta-projects/offline-software/trunk/build
make edit_cache
A handy curses app will pop up allowing you to change the values of various configuration variables. As you move the cursor over them a description is shown at the bottom of the window:
BDB_FOUND OFF
BDB_INCLUDE_DIR BDB_INCLUDE_DIR-NOTFOUND
BDB_LIBRARIES
BOOST_FOUND ON
BOOST_INCLUDE_DIR /Users/troy/ports/include/boos
BOOST_LIBRARIES /Users/troy/ports/lib/boost-1.
BUILD_AMANDA-CORE ON
BUILD_ANALYSIS-TREE ON
BUILD_COORDINATE-SERVICE ON
BUILD_DAQ-DECODE ON
BUILD_DATACLASSES ON
BUILD_DATAIO ON
BUILD_DOMCALIBRATOR ON
BUILD_EXAMPLES ON
BUILD_I3DB ON
BDB_FOUND: BDB found successfully
Press [enter] to edit option CMake Version 2.4 - patch 6
Press [c] to configure
Press [h] for help Press [q] to quit without generating
Press [t] to toggle advanced mode (Currently Off)
After you have set things as you like them press c to run the configuration. You may have to do this twice. When cmake feels ready to generate makefiles, an option g will appear in the menu. Press g to generate the new makefiles and exit.
If you know what you want to set, you can also just do so from the command line. For instance, I have checked out source to directory src/ and am in a parallel directory build/. I want to build the “release” variant, the one with optimizations on, i issue:
cmake -DCMAKE_BUILD_TYPE:STRING=Release ../src
You will notice that the type of the variable is represented after the colon. Almost everything can be handled with STRING and BOOL. For BOOL, use the values ON and OFF.
Not all of the variables are useful. Here are some that are:
Option | Description | Default |
---|---|---|
BUILD_PROJECT | Toggles the build of project PROJECT. e.g. BUILD_ICETRAY, BUILD_DATAIO. One should appear per project in the current workspace. | ON |
|
Use ccache (if detected) | OFF |
|
Use distcc (if detected) | OFF |
|
Use the gfilt stl error message decryptor | ON |
|
Use the new gold linker from GNU binutils. EXPERIMENTAL | OFF |
|
What kind of build you want. The choices are Release, Debug, RelWithDebInfo, MinSizeRel, RelWithAssert, Coverage, or empty for none of the above. | Release |
If you issue the ccmake command t the advanced variables will be shown. The most useful of these are:
Option | Description |
---|---|
|
Shows commands used while building. Useful for debugging cmake. |
Though you can also make the build verbose at any time by adding VERBOSE=1 to the command line:
make dataio-pybindings VERBOSE=1
These cache variables are stored in a file CMakeCache.txt in the build directory. You may modify this file directly instead of using make edit_cache or the ccmake utility as above.
If you do so, cmake will detect that this file has been modified and automatically regenerate your makefiles. However if you add or remove files that a glob should match, e.g.:
i3_add_library(mylib private/mylib/*.cxx)
there is no way for cmake to know that a new file (e.g. private/mylib/newfile.cxx exists that should match private/mylib/*.cxx, as this regular expression no longer exists. It has been expanded into e.g. ‘’private/mylib/file1.cxx private/mylib/file2.cxx’‘. There are two ways to handle this:
Don’t use globs: list the files explicitly, e.g.:
i3_add_library(mylib private/mylib/file1.cxx private/mylib/file2.cxx).
This way to add/remove files one edits a CMakeLists.txt and cmake will detect that the file has been modified, and regenerate the makefiles.
make rebuild_cache: The make target rebuild_cache will cause the makefiles to be regenerated. During this process the globs from each CMakeLists.txt will again be expanded and things will work.
Note
If you add or remove projects you must run make rebuild_cache. This is because the list of projects in the workspace is, as with the lists of files above, collected with a glob.
Projects that have test executables or scripts will have their tests run when make test is issued. Test binaries are found in $I3_BUILD/bin, the workspace target test-bins will build these test binaries.
There is also a generated file runtests.py in $I3_BUILD/bin. This is a test driver script that you can use to run individual tests or groups of tests.:
% ./bin/runtests.py --help
Usage: runtests.py [options]
Options:
-h, --help show this help message and exit
-p PROJECTS, --project=PROJECTS
List of projects to run tests on
-s, --scripts-only Run only test scripts
-u, --units-only Run only compiled unit tests
-v, --verbose Show verbose output
For example, to run the test scripts for project dataio, issue:
% ./bin/runtests.py -p dataio -s
27 projects loaded.
0:0 ... dataio/scripts/a_nocompression.py
1:0 ... dataio/scripts/b_default.py