CMake Usage

From Wiki for iCub and Friends
Jump to: navigation, search

Every iCub module should come with a CMake script called CMakeLists.txt.

This makes it easier for people in very different environments to compile the code.

Important: before reading further you make sure you understand the difference between internal and external modules. The former are modules that are compiled in the main iCub build, together with other modules (i.e. inside main). The latter are modules that use iCub as a package and are compiled separately (in the repository they are placed in the directory called contrib). This distinction has become more important in the new build system, see Better Repository for a detailed explanation.

The instructions are still valid but refer to modules that are external to the main build. For instructions about internal modules you should look at Better Repository. At the end of the page, in particular, are reported cmake template files that should work in most cases.

Getting started

We assume you have cmake installed correctly. See instruction in the manual to do so.

Simple start

If your module is independent of others in the repository at the code level, you don't have to do anything special. Here's about the simplest CMakeLists.txt possible:

PROJECT(example)
ADD_EXECUTABLE(example main.cpp)

This would compile source code from main.cpp, e.g:

#include <stdio.h>
int main() {
  printf("CMake the world a better place!\n");
  return 0;
}

and create a program called "example".

Using libraries

If you need YARP, make sure you have the YARP_DIR environment variable set, and then use:

FIND_PACKAGE(YARP REQUIRED)

If you have some dependencies on the rest of the iCub repository, then define the ICUB_DIR environment variable to point to the repository, and use:

FIND_PACKAGE(ICUB)

It is possible to say "FIND_PACKAGE(ICUB REQUIRED)", if your code absolutely positively won't work any other way except with as part of the iCub project. At the moment, there is no good reason to ever specify "REQUIRED" here.

What exactly does the ICUB package do? It sets up paths so you can access all internal libraries within the iCub repository. For example, you could use the "simio" library (present in $ICUB_DIR/src/simio, and giving a portable version of Windows conio.h) by doing:

FIND_PACKAGE(SIMIO REQUIRED)
INCLUDE_DIRECTORIES(${SIMIO_INCLUDE_DIRS})
LINK_LIBRARIES(${SIMIO_LIBRARIES})

Note the INCLUDE_DIRECTORIES and LINK_LIBRARIES lines. For just about every library, you need to do this to explicitly tell CMake that you want to be able to see the library's include directories, and you want to link against its binaries. The details of this can vary from library to library, although at least within iCub we're trying to be consistent with the usage above.

For non-iCub libraries, the basic pattern is similar. For example, if you need OpenCV, do:

FIND_PACKAGE(OpenCV REQUIRED)
INCLUDE_DIRECTORIES(${OPENCV_INCLUDE_DIR})
LINK_LIBRARIES(${OPENCV_LIBRARIES})

Note that capitalization and pluralization is a bit inconsistent in this case. To figure this out, look for a file called "FindOpenCV.cmake" on your computer. Another option is to look at the CMakeLists.txt files of related modules in the repository. Adding your module to the global build Ideally, all modules should be compilable either individually or as part of the full repository. When you are happy that your module compiles well on Windows and Linux, you can add a line to $ICUB_DIR/src/CMakeLists.txt:

ADD_SUBDIRECTORY(put_your_new_directory_name_here)

It will now be compiled as part of the full repository.

That's about all you have to do for executables. For libraries, you need to do a bit more. Making a new library When you create a library, e.g. $ICUB_DIR/src/intelligence, you need to do a little work to make it easy for that library to be used from other modules. Make sure you include an INTELLIGENCEConfig.cmake file in that directory. It should look something like this:

IF (NESTED_BUILD)
  SET(INTELLIGENCE_LIBRARIES intelligence)
ELSE (NESTED_BUILD)
  FIND_LIBRARY(INTELLIGENCE_LIBRARIES intelligence ${INTELLIGENCE_DIR})
ENDIF (NESTED_BUILD)
SET(INTELLIGENCE_INCLUDE_DIRS ${INTELLIGENCE_DIR})

Then add a line like this in $ICUB_DIR/ICUBConfig.cmake:

SET(INTELLIGENCE_DIR ${ICUB_DIR}/src/intelligence)

Now your library will be easy to use as part of the iCub collection, or completely separately from it. Users of your library should use the line:

FING_PACKAGE(INTELLIGENCE REQUIRED)

All libraries in iCub should define at least the LIBRARYNAME_INCLUDE_DIRS and LIBRARYNAME_LIBRARIES variables as described here (always use the plural names, even if there is just one include path or library).

Personal tools
Namespaces

Variants
Actions
Navigation
Print/export
Toolbox