# catkin install space include directories for legacy code

From documentation, the catkin implementation and previous answers I conclude that it is intentional, that in a catkin package you cannot export any subdirectories of <INSTALL_SPACE>/install in the install space. Any such relative directories (passed to catkin_package with the INCLUDE_DIRS argument) are ignored.

This works fine if you follow the convention to install files into <INSTALL_SPACE>/install/package/ and always include headers with #include <package/header.h>.

However, I have a bunch of legacy code for which I added a bunch of interdependent catkin packages definitions that builds those libraries. It works fine with the devel space. The legacy code is broken up into different modules, but all modules include headers directly with foo.h, not <MODULE>/foo.h or similar. It relies on the build system to setup include paths correctly according to module dependencies. Working in the devel space I a achieve this by exporting the according subdirectory containing the header files as INCLUDE_DIRS. In the install space, I would still want to install the header files into a subdirectory <INSTALL_SPACE>/include/<package>, however I cannot export that subdirectory in catkin_package.

The solutions I see are:

1. Place all headers in the toplevel <INSTALL_SPACE>/include/. This is undesirable for possible clashes with other pacakges.
2. Add a cmake extras file to each package that amends the package_INCLUDE_DIRS variable (not sure if that works) or even directly calls include_directories(...) (which violates the apparent cmake convention that finding a package does not directly manipulate build configuration like include_directories). This seems a bit hacky, but might get the desired behaviour.
3. Install all header files into a common subdirectory <INSTALL_SPACE>/include/foo-project and set that up as an include directory in a common cmake macro that is called by all CMakeLists.txt (I already have such a macro anyway). Again, not that elegant and not exactly what I want (all packages having their own include sub-folder the install space).

Any suggestions on how to do this properly?

EDIT: In response to @dirk-thomas's answer:

The INCLUDE in the original question was a typo. I meant INCLUDE_DIRS. Just fixed it.

And it is possible to pass any custom value there, e.g. catkin_package(INCLUDE_DIRS foo) if you want <CMAKE_INSTALL_PREFIX>/foo to end up in the include dirs list. There is no need to use a custom CMake extras file for this.

This is exactly what I want to do, but it does not seem to work for the install space. It seems that catkin is removing all relative paths that would add custom subfolders <CMAKE_INSTALL_PREFIX>/include/foo and adds just the default <CMAKE_INSTALL_PREFIX>/include. Absolute paths are not changed / filtered. The responsible code section seems to be here, which is exactly the else branch you linked to also, but as far as I can see, it does not actually use the relative_dir in that else branch (maybe that is a bug in catkin?).

2 As you already stated a CMake config file should not directly manipulate the build configuration.

This seems to do the ...

edit retag close merge delete

Setting up package_INCLUDE_DIRS is the cmake way to do this. You should be able to do it in catkin but I'm not quite sure if you can do it with the existing macros or if you have to use cmake_extras

( 2016-04-25 03:23:21 -0500 )edit

Sort by » oldest newest most voted

Thanks @ahendrix for you comment. For the record: appending to package_INCLUDE_DIRS in the cmake extras works as expected (it also ends up in catkin_INCLUDE_DIRS). The solution I went with for now is installing all headers into one common sub-directory as in my option 3 above. I append this to the INCLUDE_DIRS in the cmake extras of my one "common" pacakge, that all other packages depend on. This way I don't have to add cmake extras to every single package, but still stick with the cmake convention of having all include dirs on project_INCLUDE_DIRS (through the build-export-depends on the "common" pacakge). Any additional comments and insights are still welcome.

Edit: For future reference, I added a filter common_pkg-extras.cmake.installspace.in in the folder cmake of my common_pkg with content:

if(_COMMON_LIB_EXTRAS_INCLUDED_)
return()
endif()
set(_COMMON_LIB_EXTRAS_INCLUDED_ TRUE)

list(APPEND common_lib_INCLUDE_DIRS "\${common_lib_DIR}/../../../@CATKIN_GLOBAL_INCLUDE_DESTINATION@/MyProjectSubfolder")


Edit2: As @dirk-thomas pointed out, the additions in cmake-extras will of course not be reflected in the generated .pc files. For me, this is not an issue currently.

more

The way to export include directories in catkin is with catkin_package(INCLUDE_DIRS ...) (not as mentioned in the question with INCLUDE).

These paths can be absolute ( https://github.com/ros/catkin/blob/1b... ) (which is usually not recommended) as well as relative ( https://github.com/ros/catkin/blob/1b... ).

Updated block: For every relative include directory it is being assumed that the headers will be installed into the FHS compliant location <CMAKE_INSTALL_PREFIX>/include. A value other then include will only affect the devel space but not the install space. After installation the header files need to be in the path under include to use this. For your use case where you don't want to update the include directives you actually have to use a custom CMake config file.

Regarding your three options I would say none is the way to go:

1. As you already stated is undesirable for possible clashes with other packages.

2. As you already stated a CMake config file should not directly manipulate the build configuration. Also this would implicitly clash with other packages if multiple packages add paths which contain the same relative headers.

3. Setting the package specific subfolder as an include directory defeats the separation (same as 2.). Header files of multiple packages with the same relative paths still collide.

Therefore you should:

• install header files to a package specific subfolder (commonly the name of the subfolder has the same name as the package).

• only export the include folder as the include directory which requires all headers to be included with the package specific subfolder: package_name/my_header.h

more

This is a useful answer but it does not reflect the OP's constraint of not modifying lots of existing code.

( 2016-04-25 11:48:50 -0500 )edit

Since all proposed solutions (while keeping the legacy code unmodified) are suffering from header file collisions I wanted to point that out. There is no way to keep the legacy includes while still fixing the collision problem.

( 2016-04-25 12:12:58 -0500 )edit

"There is no way to keep the legacy includes while still fixing the collision problem." Why would you say that? If I install the headers of each package in a pacakge-specific subfolder in the install space and export the correct INCLUDE_DIRS (which is not working for me as you describe it though),

( 2016-04-25 14:54:05 -0500 )edit

then I would have achieved exactly that, no?

( 2016-04-25 14:54:23 -0500 )edit

If the include directives do not use the package specific folder then the headers from multiple packages might still collide if they have the same relative path.

( 2016-04-25 15:22:12 -0500 )edit

In general, you are absolutelz right. In my case, I know that for that subset of packages belonging to the legacy project there will be no clash. See the update to my question for a response to your posted answer. Either there is a bug in catkin, or I did not properly understand what you meant.

( 2016-04-25 16:11:14 -0500 )edit

You are absolutely right. Sorry for the confusion. catkin assumes that all headers are being installed under include and only adds that folder to the include dirs. For custom include directories you still needs a CMake config file. The generated .pc file wouldn't reflect your changes though.

( 2016-04-25 16:46:17 -0500 )edit

Thanks for the update. I have read as much from the documentation. I don't quite understand the reasoning (other than enforcing a convetion), but using a extras file is fine. Good point about the .pc file (I don't need it though).

( 2016-04-25 17:08:38 -0500 )edit