IMP logo
IMP Tutorial
Using IMP as a C++ library

Introduction

IMP is most commonly used as a Python library, controlled by writing Python scripts. To add additional functionality to IMP, usually a new IMP module is added.

However, IMP can also be used in other C++ code as a C++ library. This can be useful, for example, in writing command line tools that use IMP functionality.

In this tutorial, we will demonstrate how to compile and link a simple C++ program against the IMP library using the CMake build system. (CMake is not required to build C++ code - the C++ compiler can be run directly if desired - but CMake takes care of adding the various search paths for headers and libraries that the C++ compiler requires.)

First, download the files for this tutorial by using the "Clone or download" link at the tutorial's GitHub page.

Test program

First, let's look at the C++ program that will use IMP functionality, simple.cpp:

#include <fstream>
#include <IMP.h>
#include <IMP/algebra.h>
#include <IMP/core.h>
#include <IMP/flags.h>
int main(int argc, char *argv[]) {
IMP::setup_from_argv(argc, argv,
"Simple example of using the IMP C++ library.");
// Create two "untyped" particles
IMP::ParticleIndex p1 = m->add_particle("p1");
IMP::ParticleIndex p2 = m->add_particle("p2");
// "Decorate" the particles with x,y,z attributes (point-like
// particles)
IMP::core::XYZ d1 = IMP::core::XYZ::setup_particle(m, p1);
IMP::core::XYZ d2 = IMP::core::XYZ::setup_particle(m, p2);
// Use some XYZ-specific functionality (set coordinates)
d1.set_coordinates(IMP::algebra::Vector3D(10.0, 10.0, 10.0));
d2.set_coordinates(IMP::algebra::Vector3D(-10.0, -10.0, -10.0));
std::cout << d1 << " " << d2 << std::endl;
return 0;
}

This is a very simple C++ program that uses IMP to create an IMP::Model, make two particles in that model, and set their XYZ coordinates using the IMP::core::XYZ decorator. It is essentially identical to the first part of the simple Python example in the IMP manual.

FindIMP CMake module

The FindIMP.cmake file, in the tools subdirectory, is a script that helps CMake find your IMP installation. When IMP is built or installed, it creates a file called IMPConfig.cmake which contains information about how IMP was configured and where all the parts of IMP can be found.

  • If IMP is built from source (and not installed) that file can be found in IMP's CMake build directory (the same directory where IMP's setup_environment.sh is).
  • If IMP is installed, that file is placed under the library directory, for example in /usr/lib64/cmake/IMP/.

The FindIMP.cmake file searches common locations for the IMPConfig.cmake file. It can be copied verbatim into your own CMake projects.

FindRMF CMake module

We don't use RMF in this tutorial, but if it is needed, there is a separate FindRMF.cmake file to help CMake find it. See the npctransport repository for an example of its use.

CMake script (CMakeLists.txt)

The main control script for CMake is CMakeLists.txt. This is a very simple file that instructs CMake to find IMP, and build an executable from our input file simple.cpp. If you have not used CMake before, the CMake tutorial is a good introduction. Let's look at the parts in turn:

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/tools)
find_package(IMP REQUIRED)

This uses CMake's standard find_package command to locate IMP. It relies on the FindIMP.cmake file from above, so first we need to set CMAKE_MODULE_PATH so that it can find that file.

include(${IMP_USE_FILE})

Once IMP is found, the IMP_USE_FILE CMake variable is set to the path of a file that is part of the IMP installation containing IMP-related CMake functions. We can use this file with the standard CMake include command.

include_directories(SYSTEM ${IMP_INCLUDE_DIR})
include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR})
include_directories(SYSTEM ${Boost_INCLUDE_DIR})

We can now add the IMP header files to the compiler's search path using CMake's include_directories command. The SYSTEM option here tells the compiler not to warn about any issues in the IMP headers (these should be addressed in IMP itself, not in this project). Since IMP also uses the Eigen and Boost packages we also need to add the directories these headers are stored in, as these may not be the same.

add_executable(simple simple.cpp)

Next, we tell CMake that we want to make a single executable, simple, by compiling the simple.cpp C++ file.

target_link_libraries(simple ${IMP_kernel_LIBRARY} ${IMP_core_LIBRARY})

Finally, we tell CMake that when we link the simple executable, we need to link it against the IMP kernel and the IMP::core module.

Build and run

We can now configure this project from the top-level directory (the one containing simple.cpp and CMakeLists.txt) by making a build directory and running CMake in it:

mkdir build
cd build
cmake ..

If this fails to find IMP, you can set the IMP_DIR environment variable or CMake variable to the path containing IMPConfig.cmake to help it out:

cmake .. -DIMP_DIR=/home/user/imp/release

Once CMake completes successfully, we can build and run our program in the normal way, for example using

make
./simple

On Linux and Mac systems CMake will typically generate makefiles. You can have it generate files for other build systems using the -G option. For example, cmake -G Ninja will generate files for the Ninja build tool, which is typically faster than traditional make for larger projects.

CC BY-SA logo