[Documentation] [TitleIndex] [WordIndex

Writing a ROS CMakeLists.txt file

This page documents the CMake API provided by rosbuild.

You might first want to see some examples.

We use CMake to build ROS packages. You need to install CMake on your system. Each package requires a file, called CMakeLists.txt to tell CMake how to build it. This file is analogous to a Makefile as used by make.

If you're unfamiliar with CMakeLists.txt, that's ok, because most ROS packages follow a very simple pattern that is described below. Of course, you can always use the full power of CMake, for which you may want to consult the CMake documentation.

NOTE: To support older platforms, we use only features that are available in CMake 2.4.6. Check the 2.4.6 docs to verify the availability of a feature you want to use.

API documentation

rosbuild.cmake

To use any of the ROS macros, you must first do this:

include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)

This line brings in the rosbuild.cmake file, which defines the macros described below.

Global variables

Some variables can be set before calling rosbuild_init():

rosbuild_init

rosbuild_init()

This macro should be called first. It does the following (assume ${pkg} is the name of the package, and ${dir} is the package directory):

Note that you are free to override the default output locations after invoking rosbuild_init(). E.g., if you want your binaries in ${pkg}/bin, you might do this:

rosbuild_init()
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

To put your libraries somewhere strange:

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/libraries)

NOTE: the rosbuild_init() macro does NOT bring in the compile or link flags that are exported by the package presently being built. It ONLY brings in the flags exported by the present package's dependencies. The flags in the export section of your manifest.xml are for use by others, not by you. If you need some of your package's exported flags when building the package itself, use the appropriate CMake calls in your CMakeLists.txt, such as include_directories() and target_link_libraries().

But see Linking against libraries built by other ROS packages for when not to use target_link_libraries().

Build macros

rosbuild_add_executable

rosbuild_add_executable(exe src1 src2...)

This macro declares an executable that is to be built. It is a simple wrapper around the standard CMake command add_executable(), and takes exactly the same arguments. In addition to invoking add_executable(), this macro invokes set_target_properties() and target_link_libraries() to incorporate the compile and link flags found by th rosbuild_init() macro.

NOTE: Do not call your executable test. This target name is reserved for unit testing, and CMake will fail if you try it. If you really want your executable to be called test, you can do it like so:

rosbuild_add_executable(mytest src/test.cpp)
set_target_properties(mytest PROPERTIES OUTPUT_NAME test)

But if you're building test programs, you should do it with rosbuild_add_gtest(); see below.

If you're building an executable that shouldn't be built in the make all step (e.g., if you intend to use rosbuild_add_gtest_build_flags()), then use CMake's EXCLUDE_FROM_ALL option, e.g.:

rosbuild_add_executable(mytest EXCLUDE_FROM_ALL src/test.cpp)
rosbuild_add_gtest_build_flags(mytest)

rosbuild_add_library

rosbuild_add_library(lib src1 src2...)

This macro declares a library that is to be built. It is a simple wrapper around the standard CMake command add_library(), and takes exactly the same arguments. In addition to invoking add_library(), this macro invokes set_target_properties() to incorporate the compile flags found by the rosbuild_init() macro.

Example usage:

cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
rosbuild_init()
rosbuild_add_library(XmlRpc src/XmlRpcClient.cpp
                   src/XmlRpcDispatch.cpp
                   src/XmlRpcServer.cpp
                   src/XmlRpcServerConnection.cpp
                   src/XmlRpcServerMethod.cpp
                   src/XmlRpcSocket.cpp
                   src/XmlRpcSource.cpp
                   src/XmlRpcUtil.cpp
                   src/XmlRpcValue.cpp)

NOTE: Do not call your library test. This target name is reserved for unit testing, and CMake will fail if you try it.

rosbuild_add_swigpy_library

New in 0.11

rosbuild_add_swigpy_library(target lib src1 src2...)

This macro is a variation o rosbuild_add_library() that should be used when building a SWIG-generated library that will be imported by Python. The first argument is a unique target name, which you can pass to things like target_link_libraries(). The rest of the arguments are the same as you would normally pass to rosbuild_add_library().

This macro will generate a library called _<lib>.<ext>, where <lib> is what you passed in, and <ext> is the appropriate extension for a shared library. On OS X, the extension is forced to .so, to allow module imports to work with the MacPorts version of Python.

Example usage:

cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
rosbuild_init()
find_package(PythonLibs REQUIRED)
rosbuild_add_swigpy_library(python_foo foo foo_swig_generated.cpp bar.cpp)
target_link_libraries(python_foo ${PYTHON_LIBRARIES})

This example will produce a library named _foo.so on most platforms.

NOTE: Do not call your target test. This target name is reserved for unit testing, and CMake will fail if you try it.

rosbuild_add_compile_flags

rosbuild_add_compile_flags(target flags)

This macro adds compile flags for the given target. You can use it to add things like warning or optimization settings, but don't use it to add library/include search paths, -D definitions, or libraries to link against. Use CMake builtin commands (link_directories(), include_directories(), add_definitions(), target_link_libraries()) for those cases.

But see Linking against libraries built by other ROS packages for when not to use target_link_libraries().

rosbuild_remove_compile_flags

rosbuild_remove_compile_flags(target flags)

This macro removes compile flags for the given target.

rosbuild_add_link_flags(target flags)

This macro adds link flags for the given target. You can use it to add things like profiling settings, but don't use it to add library/include search paths, -D definitions, or libraries to link against. Use CMake builtin commands (link_directories() include_directories(), add_definitions(), target_link_libraries()) for those cases.

But see Linking against libraries built by other ROS packages for when not to use target_link_libraries().

rosbuild_remove_link_flags(target flags)

This macro removes link flags for the given target.

rosbuild_add_boost_directories

rosbuild_add_boost_directories()

This macro adds the boost include/library directories to your search paths. You must call this macro if any of your code includes boost headers.

rosbuild_link_boost(target lib1 lib2 lib3 ...)

This macro adds the boost link flags to a target, given some boost libraries you want to link against. You must call this macro for each of your library and executable that uses one or more libraries from boost. Example:

rosbuild_link_boost(my_exe thread regex)

rosbuild_add_openmp_flags

rosbuild_add_openmp_flags(target)

This macro adds the necessary compile and link flags to a target so that OpenMP can be used.

rosbuild_invoke_rospack

rosbuild_invoke_rospack(pkg prefix varname rospack_args)

This macro invokes rospack. Specifically, it invokes:

rospack ${rospack_args) ${pkg}

It stores the result in the variable ${prefix}_${varname}. Failure to invoke rospack is fatal.

rosbuild_find_ros_package

rosbuild_find_ros_package(pkg)

This macro searches for the given ROS package. If the package is found, then the variable ${pkg_PACKAGE_PATH} is set to the absolute path to the package. If the package is not found, the variable is not set.

rosbuild_find_ros_stack

(New in 1.6.0)

rosbuild_find_ros_stack(stack)

This macro searches for the given ROS stack. If the stack is found, then the variable ${stack_STACK_PATH} is set to the absolute path to the stack. If the stack is not found, the variable is not set.

rosbuild_check_for_sse

(New in 1.1.8)

rosbuild_check_for_sse()

This macro determines the level of SSE support in the compiler. If SSE support is found, HAS_SSE_EXTENSIONS is set to True. Similarly, SSE2 and SSE3 support cause HAS_SSE2_EXTENSIONS and HAS_SSE3_EXTENSIONS to be set to True, respectively. If any level of SSE support is found, SSE_FLAGS will contain the flags required to use the highest level available.

For example, to compile a library with the highest level of SSE available:

rosbuild_check_for_sse()
rosbuild_add_library(foo foo.cpp)
rosbuild_add_compile_flags(foo ${SSE_FLAGS})

To check for SSE2 specifically:

rosbuild_check_for_sse()
if(HAS_SSE2_EXTENSIONS)
<do something SSE2-specific here>
endif(HAS_SSE2_EXTENSIONS)

rosbuild_include

(New in 1.1.8)

rosbuild_include(package module)

This macro includes CMake code exported by another package. Specifically, it includes a file called module.cmake from a directory exported by package. This mechanism allows you to extend the build system by providing your own CMake code to be used in other packages.

The package calling rosbuild_include() must depend on package. That package must depend directly on rosbuild and must export a directory to search for CMake files.

E.g., if package dynamic_reconfigure wants to allow other packages to include the file dynamic_reconfigure/cmake/cfgbuild.cmake, then its manifest should contain:

...
<depend package="rosbuild"/>
<export>
  <rosbuild cmake_directory="${prefix}/cmake"/>
</export>
...

Then package hokuyo_node, which depends on dynamic_reconfigure, can include that file like so:

rosbuild_include(dynamic_reconfigure cfgbuild)

rosbuild_add_lisp_executable

rosbuild_add_lisp_executable(output system_name entry_point)

Used to create a standalone Lisp executable. Your package must depend on roslisp_runtime. The executable will be called output. Running it will start the SBCL runtime, load in the ASDF system system_name, then call the function named by entry_point. See the roslisp documentation for more details.

Test macros

rosbuild provides a number macros to support testing. These macros allow you to define test programs that should be compiled (if necessary) and run during make test in your package. See UnitTesting for more information on testing.

rosbuild_add_gtest

(TIMEOUT option new in 1.1.8)

rosbuild_add_gtest(testexe src1 src2 ... [TIMEOUT timeout_secs])

This macro declares a Google Test (gtest) executable that is to be built. The arguments are the same a rosbuild_add_executable (in fact this macro calls through to rosbuild_add_executable). The named executable is built from the sources, and added as a dependency to the test target. This macro invokes rosbuild_add_gtest_build_flags(), which adds the gtest build flags to the named executable. To build the executable, use make tests.

If a test doesn't complete within a certain amount of time, it will be killed, and a test failure will be synthesized. By default, the time limit is 60 seconds. To set a different timeout, use the TIMEOUT option, e.g.:

# Give a slow test 3 minutes (180 seconds) to complete
rosbuild_add_gtest(myslowtest myslowtest.cpp TIMEOUT 180.0)

When make test is run, each gtest executable is run like so:

testexe --gtest_output=xml:${rosbuild_test_results_dir}/${PROJECT_NAME}/${_testname}.xml

The current working directory is the top of the package's source tree.

Test output is printed to the console, and also stored in XML format in $ROS_ROOT/test/test_results/${project}, where ${project} is the name of the ROS package.

Multiple tests may be declared.

NOTE: Do not call your test test. This target name is reserved for unit testing, and CMake will fail if you try it.

rosbuild_add_gtest_labeled

(TIMEOUT option new in 1.1.8)

rosbuild_add_gtest_labeled(label testexe src1 src2 ... [TIMEOUT timeout_secs])

This macro is the same a rosbuild_add_gtest(), except that it only declares the test if EITHER:

Use this macro to declare tests that should not run in certain situations. Most commonly used with a continuous integration system.

rosbuild_add_gtest_future

DEPRECATED and rendered non-functional in 1.7. Instead of using this macro, simply comment out tests that don't yet pass.

rosbuild_add_gtest_future(testexe src1 src2 ... [TIMEOUT timeout_secs])

This macro is the same a rosbuild_add_gtest(), except that the resulting test will be only be run during make test-future. Use this macro to declare tests that fail now, but should pass in the future, after an existing bug is fixed or missing feature implemented.

We segregate future tests from current tests so that the automated build and test system can accurately report health of the system, including giving meaningful email notification on test failure.

rosbuild_add_gtest_build_flags

rosbuild_add_gtest_build_flags(testexe)

This macro adds the build flags necessary to compile and link an executable against gtest. Use this macro when you want to build a gtest exectuable, but not declare it to be a test on its own. This commonly occurs when you're using rostest and your test executable uses gtest. In this case you want the test executable to be run via rostest, not on its own.

This macro also invokes rosbuild_declare_test(), which adds a dependency from the tests target on the executable. To build the executable, use make tests.

E.g., here we build an executable called rtest that uses gtest, and declare a rostest that uses it:

rosbuild_add_executable(rtest test/rtest.cpp test/test_constants.cpp)
rosbuild_add_gtest_build_flags(rtest)
rosbuild_add_rostest(test/rtest.xml)

The accompanying rostest XML file might look like this:

<launch>
  <node pkg="map_server" type="map_server"
        args="$(find map_server)/test/testmap.bmp 0.1"/>
  <test test-name="map_server_test" pkg="map_server" type="rtest"/>
</launch> 

rosbuild_add_pyunit

(TIMEOUT option new 1.1.8)

rosbuild_add_pyunit(file [TIMEOUT timeout_secs])

This macro declares a Python unittest executable that is to be run. Make sure you consult the ROS unittest documentation as there are some additional items your unittest script needs to call.

If a test doesn't complete within a certain amount of time, it will be killed, and a test failure will be synthesized. By default, the time limit is 60 seconds. To set a different timeout, use the TIMEOUT option, e.g.:

# Give a slow test 3 minutes (180 seconds) to complete
rosbuild_add_pyunit(myslowtest.py TIMEOUT 180.0)

When make test is run, each Python unit test is run like so:

python file --gtest_output=xml:${rosbuild_test_results_dir}/${PROJECT_NAME}/${_testname}.xml

The current working directory is the top of the package's source tree.

rosbuild_add_pyunit_labeled

(TIMEOUT option new in 1.1.8.)

rosbuild_add_pyunit_labeled(label file [TIMEOUT timeout_secs])

This macro is the same a rosbuild_add_pyunit(), except that it only declares the test if EITHER:

Use this macro to declare tests that should not run in certain situations. Most commonly used with a continuous integration system.

rosbuild_add_pyunit_future

DEPRECATED and rendered non-functional in 1.7. Instead of using this macro, simply comment out tests that don't yet pass. (TIMEOUT option new in 1.1.8)

rosbuild_add_pyunit_future(file [TIMEOUT timeout_secs])

This macro is the same a rosbuild_add_pyunit(), except that the resulting test will be only be run during make test-future. Use this macro to declare tests that fail now, but should pass in the future, after an existing bug is fixed or missing feature implemented.

We segregate future tests from current tests so that the automated build and test system can accurately report health of the system, including giving meaningful email notification on test failure.

rosbuild_add_rostest

rosbuild_add_rostest(xmlfile)

This macro declares a rostest test that is to be run when testing the package. When make test is run on the package, the given xmlfile will be passed to rostest. Output goes in $ROS_ROOT/test/test_results/${project}, where ${project} is the name of the ROS package.

rosbuild_add_rostest_labeled

rosbuild_add_rostest_labeled(label file)

This macro is the same a rosbuild_add_rostest(), except that it only declares the test if EITHER:

Use this macro to declare tests that should not run in certain situations. Most commonly used with a continuous integration system.

rosbuild_add_rostest_future

DEPRECATED and rendered non-functional in 1.7. Instead of using this macro, simply comment out tests that don't yet pass.

rosbuild_add_rostest_future(xmlfile)

This macro is the same a rosbuild_add_rostest(), except that the resulting test will be only be run during make test-future. Use this macro to declare tests that fail now, but should pass in the future, after an existing bug is fixed or missing feature implemented.

We segregate future tests from current tests so that the automated build and test system can accurately report health of the system, including giving meaningful email notification on test failure.

rosbuild_add_roslaunch_check

(New in ROS 1.1.2)

rosbuild_add_roslaunch_check(file_or_directory [var1=val] [var2=val2] ...)

This macro declares as a unit test a parse check of one or more roslaunch files. The parser (roslaunch/scripts/roslaunch-check) checks a number of aspects of launch files, in a manner similar to roswtf.

The first argument should be either a roslaunch file, or a directory. If it's a directory, then all *.launch files in that directory are checked.

Following the required first argument, you can optionally specify environment variables that will be set before running the parser. This feature is useful if you use $(env) in your roslaunch files. E.g., to test a roslaunch file with the environment variable ROBOT set to sim:

rosbuild_add_roslaunch_check(foo.launch ROBOT=sim)

NOTE: Do not call your file or directory test. This target name is reserved for unit testing, and CMake will fail if you try it. Instead, put your launch files into a directory with a different name, e.g., tests.

rosbuild_declare_test

rosbuild_declare_test(exe)

This macro declares that an executable is a test harness, which adds it to the make tests build. Use this macro to declare that an executable is only used in testing. This macro is automatically invoked for any executable that is declared via rosbuild_add_gtest(), rosbuild_add_gtest_future(), or rosbuild_add_gtest_build_flags(). So you only need to use this macro for an executable that is used in testing, but isn't a test itself; e.g., a node that is used in setting up a rostest.

This macro does not exclude building the executable from the make all build. To do this, you must supply the EXCLUDE_FROM_ALL option when calling rosbuild_add_executable().

rosbuild_count_cores

rosbuild_count_cores(num)

This macro calls out to Python to determine the number of physical cores on your machine, and writes this number into num. It's intended for use in gating tests that require a lot of processing. E.g., if you want to run a test only when you have at least 4 cores:

rosbuild_count_cores(cores)
if(cores GREATER 4 OR cores EQUAL 4)
  rosbuild_add_rostest(my_crazy_test.xml)
endif(cores GREATER 4 OR cores EQUAL 4)

rosbuild_check_for_display

rosbuild_check_for_display(var)

This macro checks for the presence of an X display (currently by looking at the exit status from calling xdpyinfo). It sets var to 1 if there is a display, and 0 otherwise. It's intended for us in gating tests that require an X display, e.g.:

rosbuild_check_for_display(disp)
if(disp)
  rosbuild_add_rostest(my_graphical_test.xml)
endif(disp)

rosbuild_check_for_vm

rosbuild_check_for_vm(result)

This macro determines whether the build is happening on a virtual machine. Currently, it just looks for "/proc/xen". The intended use is gating tests that have strict timing requirements. The assumption is that a non-VM will have low load.

E.g., to only run a test on a non-VM:

rosbuild_check_for_vm(vm)
if(NOT vm)
  rosbuild_add_rostest(my_strict_timing_test.xml)
endif(NOT vm)

Message / service macros

rosbuild_gensrv

rosbuild_gensrv()

This macro processes service specifications that defined locally in a package. It runs client library-specific code generators over all *.srv files found in the srv subdirectory of the package.

Example usage:

cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
rosbuild_init()
rosbuild_gensrv()
# the service provider
rosbuild_add_executable(deadreckon deadreckon.cpp)
# a dumb test client
rosbuild_add_executable(test_deadreckon_service test_deadreckon_service.cpp)

rosbuild_genmsg

rosbuild_genmsg()

This macro processes message specifications that defined locally in a package. It runs client library-specific code generators over all *.msg files found in the msg subdirectory of the package.

rosbuild_add_generated_msgs

rosbuild_add_generated_msgs(AutoGen1.msg AutoGen2.msg)

This macro sets up for auto-generation of one or more messages. It creates an expectation that the message files passed as arguments will be created during the build. This macro may be called more than once. Through CTurtle, this macro must be called before rosbuild_init(). Starting with Diamondback, it must be called before rosbuild_genmsg().

Auto-generating messages is an advanced topic; see the code in actionlib for an example.

rosbuild_add_generated_srvs

rosbuild_add_generated_srvs(AutoGen1.srv AutoGen2.srv)

This macro sets up for auto-generation of one or more services. It creates an expectation that the service files passed as arguments will be created during the build. This macro may be called more than once. Through CTurtle, this macro must be called before rosbuild_init(). Starting with Diamondback, it must be called before rosbuild_gensrv().

Auto-generating services is an advanced topic; see the code in actionlib for an example.

Version macros

rosbuild_get_stack_version

(New in ROS 1.3.1)

rosbuild_get_stack_version(var stackname)

This macro fetches the name of the stack stackname and puts it into var. If the version cannot be determined, it is a fatal error. This macro works by calling rosversion.

rosbuild_get_package_version

(New in ROS 1.3.1)

rosbuild_get_package_version(var pkgname)

This macro fetches the version of the stack that contains the package pkgname, and puts it into var. If the package is not in a stack, or if the stack's version cannot be determined, it is a fatal error. This macro works by calling rosbuild_get_stack_version(), with the output of rosstack contains pkgname.

Downloading files during the build

It is sometimes necessary to download files during the build. This is usually done to avoid checking large, often binary, files into Subversion. Some macros are provided to help in these cases

rosbuild_download_data

(New in 0.8; 3-argument form new in 0.9)

rosbuild_download_data(url filename md5sum)

DEPRECATED 2-argument form, without an md5sum:

rosbuild_download_data(url filename)

This macro sets up a target for downloading a file from url and saving it locally with the name filename, and checking the resulting file's md5 hash against md5sum. The target will fire on the all target, which means that it will happen during the main build of the package. There are no guarantees on ordering of steps within the all target (e.g., the download is not guaranteed to happen before a particular compilation step). The url should be fully-qualified (e.g., don't leave out the domain name), and the filename should be relative to your package directory.

The md5 hash is checked on every build; if it doesn't match, filename is deleted, and one attempt is made to re-download the file; if it still doesn't match, the build is aborted with an error.

If you're pulling from a web-accessible Subversion repository and want a particular revision of a file, you can use the standard Subversion URL syntax, !svn/bc/<revision_number>/. E.g., to download revision 6 of a map:

rosbuild_download_data(https://code.ros.org/svn/data/!svn/bc/6/trunk/willow_maps/willow-2010-02-18-0.025.pgm willow-2010-02-18-0.025.pgm b9c44f1d528c1ebd6a3f5b6720a5b8df)

Note for Willow Garage people: You should put your data at ipr:/var/www/pr.willowgarage.com/html/data, in a directory with the same name as your package.

rosbuild_download_test_data

(3-argument form new in 0.9)

rosbuild_download_test_data(url filename md5sum)

DEPRECATED 2-argument form, without an md5sum:

rosbuild_download_test_data(url filename)

This macro is the same as rosbuild_download_data(), except that it will fire on the tests target, which happens during the build of test programs, prior to running any tests.

Note for Willow Garage people: You should put your data at ipr:/var/www/pr.willowgarage.com/html/data, in a directory with the same name as your package.

rosbuild_untar_file

(new in 1.1.8)

rosbuild_untar_file(tarfile unpacked_name [target])

This macro sets up rules to unpack the file tarfile, using the command tar xf. The rule expects the file or directory unpacked_name to exist after unpacking; you would normally set this equal to the name of the top-level directory contained in tarfile. The optional target is a target that should be made to depend on the unpacking of tarfile. Common values for target are ALL (unpack during make) and tests (unpack during make test, prior to running any tests).

For example, to download a tar file of test data, and make sure that it's unpacked before running tests on it:

rosbuild_download_test_data(http://pr.willowgarage.com/data/${PROJECT_NAME}/test_session_results_fixture.tgz test_data/test_session_results_fixture.tgz a15e52b7b827ab7560bd42c98e7c5a93)
rosbuild_untar_file(test_data/test_session_results_fixture.tgz test_data/session_results_gold tests)

Special targets

rosbuild defines some special targets that you can use to encode dependencies in the build process.

rosbuild_premsgsrvgen

The rosbuild_premsgsrvgen target fires before doing message or service generation. By making this target depend on one of your targets, you can do work beforehand. A simple example, which will generate a file before message or service generation:

# Generate the file foo
add_custom_command(OUTPUT foo COMMAND touch foo)
# Create a target that depends on the generation of foo
add_custom_target(foo_target DEPENDS foo)
# Make message service generation depend on our target:
add_dependencies(rosbuild_premsgsrvgen foo)

rosbuild_precompile

The rosbuild_precompile target fires before compiling any C/C++ programs. By making this target depend on one of your targets, you can do work beforehand. A simple example, which will generate a file before compiling:

# Generate the file foo
add_custom_command(OUTPUT foo COMMAND touch foo)
# Create a target that depends on the generation of foo
add_custom_target(foo_target DEPENDS foo)
# Make compilation depend on our target:
add_dependencies(rosbuild_precompile foo)

Making stack distributions

The release unit in ROS is a stack. rosbuild offers support for making source distributions of stacks (more information).

rosbuild_make_distribution

rosbuild_make_distribution(version)

This macro performs the set up necessary to produce a source tarball of the stack, at the given version.


2022-05-28 12:57