Installing Modules Using CMake
Overview
Teaching: 25 min
Exercises: 10 minQuestions
What is the CMake standard build workflow?
How do I modify this workflow to suit my needs?
Objectives
Understand the basics of the CMake standard build procedure.
Install an example module using the CMake build system.
Adapting our workflow for projects using CMake
A newer tool that is growing in popularity for building software with complex sets of dependencies is CMake, by KitWare.
CMake is powerful because it allows developers to create install procedures that automatically find and include a large
number of dependencies that may be installed differently on different machines. The cmake command itself is meant to
be something of a replacement for the configure command, making the build procedure into cmake; make; make install.
Using the same basic workflow that we did for the GNU installation procedure, we can install self-managed modules using CMake as well. We will use Luscus for our example this time, a tool for displaying and editing molecular systems in a graphical user interface. Let’s begin by downloading the source code into a new directory and unpacking it:
$ mkdir ~/software.source/luscus
$ cd ~/software.source/luscus
$ wget https://downloads.sourceforge.net/project/luscus/luscus_0.8.6.tar.gz
$ tar xvf luscus_0.8.6.tar.gz
$ cd luscus_0.8.6
$ ls
backup_file.c gv_about.c gv_gtk_atom_list.c gv_notebook.c mcube.h surface.c
build/ gv_atoms.c gv_gtk.h gv_system.c molcas024001.png surface.h
center16.xpm gv_atoms.h gv_gtk_help.c icon_revert20.xpm molcas024001.xpm TODO
center.xpm gveps.c gv_gtk_make_graph.c install_diffdens.sh mystring.c vstring.c
CITATION.txt gveps.h gv_gtk_multiview.c INSTALL.txt pixeldata.c vstring.h
CMakeLists.txt gv_fragments.c gv_gtk_multiview.h License.txt plugins/ write_file.c
config_files/ gv_functions.h gv_gtk_xyz_editor.c luscus_gtk_handle.c plugins_babel/
DOC/ gv_geom.c gv.h luscus_gtk_util.c read_file.c
findsym.c gv_glx.h gv.h.in luscus.h.in read_file_org.c
findsym.h gvgrp.c gv_menubar.c main.c screenshot.c
gtk_gui.c gvgrp.h gv_menubar_org.c mcube.c stdext.c
Again, we see that there is an INSTALL.txt file containing installation instructions. This one is a little more
verbose so we won’t be using as reference today, but it contains all of the same information. Two other items to
note in this directory are the CMakeLists.txt file, and the build directory, both of which are part of the cmake
build procedure. The CMakeLists.txt file contains the logic for finding dependencies and configuring the build, and
the build directory is typically where we work from when building a cmake project. It is important not to build the
code directly in the root directory of the project with cmake, as this can cause all sorts of errors. So the standard
approach is to build the software from a build subdirectory. Often you will have to make it yourself, but this project
provides it for us.
Continuing with the installation procedure, let’s move into the empty build directory:
$ cd build
The cmake tool is installed as a module, so we need to load it. The most basic way to call cmake is to run:
$ module load cmake
$ cmake DIR
where DIR is the location of the CMakeLists.txt file. In this case, that’s the parent directory of build, so we would call
$ cmake ..
We also need to specify any installation options that we want at this point. The equivalent to the --prefix command
is -DCMAKE_INSTALL_PREFIX, and we can set the compilers to use via environment variables as we did with make. To
see all of the options available, we can run the command:
$ ccmake ..
This will drop us into a menu where we can see the options that cmake will accept. Once in this menu we need to hit
c to generate the list of properties. Once this is done we can hit t to show the full list of variables used for
this build. In this case we will only be changing the install prefix, so we can hit q to quit without making changes.
This project can use gcc as well, so we can use the same procedure as before to set the CC environment variable, as
well as the CXX environment variable for compiling both C and C++ code.
$ module load gcc/7.2.0
$ export CC=$(which gcc)
$ export CXX=$(which g++)
$ cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/software.install/luscus/0.8.6
$ make
$ make install
This software also needs some configuration files to be copied over to the installation directory that aren’t included in the operations run by make install.
This isn’t uncommon, so watch out for this in the developer’s installation documentation.
In this case, we can copy over the needed files via:
$ cp -r config_files $HOME/software.install/luscus/0.8.6/luscus_homedir
Once the installation step is complete, we can create our modulefile as before:
$ mkdir ~/modulefiles.local/luscus
$ nano ~/modulefiles.local/luscus/0.8.6
#%Module
module load gcc/7.2.0
set basedir "/users/3/dunn0404/software.install/luscus/0.8.6"
prepend-path PATH $basedir/bin
setenv LUSCUS_DIR $basedir/luscus_homedir
This modulefile adds a couple of new bits of information. First, we didn’t include cmake as one of the modules to
load as a dependency. That is because cmake is almost never used when actually running the software it builds, so
it is safe to omit. Second, we are setting an internal variable to the modulefile with the set directive. This
is because we want to modify two environment variables, and we can save typing and reduce chances for error by
storing the root directory of the luscus install to basedir, and referencing it later in the file with
$basedir. Finally, we are introducing the setenv directive, which creates a new environment variable (or completely
overwrites an old one) to se the value of LUSCUS_DIR, which is a variable needed by luscus at runtime.
And finally we can record the install procedure in our recipe file:
$ nano ~/software.source/luscus/README.recipe
# dunn0404 - April 12, 2022
# luscus v0.8.6 with gcc/7.2.0
wget https://downloads.sourceforge.net/project/luscus/luscus_0.8.6.tar.gz
tar xvf luscus_0.8.6.tar
cd luscus_0.8.6/build
module load cmake
module load gcc/7.2.0
export CC=$(which gcc)
export CXX=$(which g++)
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/software.install/luscus/0.8.6
make
make install
Key Points
CMake is a more modern and advanced build system that is popular for packages with complex sets of dependencies.
We can still customize it to our needs for the same modulefile workflow we’ve been using.