Writing a CMakeLists.txt for ROS - cmake

I am new to ROS (Indigo), and I want to write a C++ program to use the MoveIt! package.
However, I am confused as to what I need to have in my CMakeLists.txt file, such that the header and library files can be found.
For example, here is the file so far:
cmake_minimum_required(VERSION 2.8.1)
project(MicoMoveIt)
set(CMAKE_CXX_FLAGS "-std=c++11")
file(GLOB srcs *.cpp)
include_directories(/opt/ros/indigo/include)
link_directories(/opt/ros/indigo/lib)
add_executable(${PROJECT_NAME} ${srcs})
And my main.cpp file is:
#include <ros/ros.h>
#include <moveit/move_group_interface/move_group.h>
int main()
{
moveit::planning_interface::MoveGroup group("right_arm");
return 0;
}
But compiling this gives me the error:
/opt/ros/indigo/include/moveit/robot_model/joint_model.h:47: error: Eigen/Geometry: No such file or directory
#include <Eigen/Geometry>
^
So, I need to specify where to find these Eigen header files. But given that Eigen is a dependency of MoveIt!, then I shouldn't have to manually include all these header file directories.
How should I be writing the CMakeLists.txt file so that all header and library directories of dependencies are included?

Try with this changes:
cmake_minimum_required(VERSION 2.8.3)
project(<project_name>)
set(CMAKE_CXX_FLAGS "-std=c++11")
find_package(catkin REQUIRED COMPONENTS
<other_packages_you_need>
moveit_ros_planning_interface
)
catkin_package(CATKIN_DEPENDS)
include_directories(include ${catkin_INCLUDE_DIRS})
set(BINNAME <executable_name>)
set(SOURCES <cpp_source_files>)
add_executable (${BINNAME} ${SOURCES})
target_link_libraries(${BINNAME} ${catkin_LIBRARIES})
The key factor for your problem is the inclusion of package moveit_ros_planning_interface in the find_package() directive. Everytime you have to build some code, you have to add every package dependancies to your project (in this case you need the moveit interface package). Notice that the package.xml file plays a crucial role too.
Lastly you have to tell the linker to retrieve and link the libraries you are using in your project. To do so use target_link_libraries() and the useful catkin_LIBRARIES variable which almost does what you expected (you could manually add libraries, but it could be messy in big projects).
Have a look here and here for more info.
EDIT: in this case you do not need the link_directories() directive, which has to be used only when the linker has to know where to retrieve the external library.

Related

CMake "Cannot specify sources for target PROJECT_NAME which is not built by this project."

I am learning CMake but unfortunately most examples are either too simple, too complicated or the folder structure is different to what I'm designing.
I am getting an error but first I will explain the folder structure (please do critique):
MyProject
bin
build
src
ComponentA
ObjectA.cpp
CMakeLists.txt
ComponentB
ObjectB.cpp
CMakeLists.txt
CMakeLists.txt
main.cpp
CMakeLists.txt
I would like to be able to include some files using their absolute path, for example main.cpp might look like this:
#include <ComponentB/ObjectB.h>
int main()
{
ComponentB cb(1, 2, 3);
}
but within a source file I'd like to include it's header using the relative path:
#include <ComponentB.h>
ComponentB::ComponentB(int a, int b, int c) : _ca(a, b){}
(if this causes problems I can include using absolute paths)
My CMakeLists files look like:
MyProject/CMakeLists.txt:
cmake_minimum_required(VERSION 3.9.1)
project(MyProject)
add_subdirectory(src)
MyProject/src/CMakeLists.txt:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_ROOT_DIR}/bin)
add_executable(MyProject main.cpp)
add_subdirectory(ComponentA)
add_subdirectory(ComponentB)
MyProject/src/ComponentA/CMakeLists.txt:
target_sources(MyProject PUBLIC ComponentA.cpp)
MyProject/src/ComponentB/CMakeLists.txt:
target_sources(MyProject PUBLIC ComponentB.cpp)
target_include_directories(MyProject PUBLIC ComponentA)
However when I do:
cd build
cmake ..
I get this this error:
CMake Error at src/ComponentA/CMakeLists.txt:2 (target_sources):
Cannot specify sources for target "MyProject" which is not built by
this project.
CMake Error at src/ComponentB/CMakeLists.txt:2 (target_sources):
Cannot specify sources for target "MyProject" which is not built by
this project.
CMake Error at src/ComponentB/CMakeLists.txt:3 (target_include_directories):
Cannot specify include directories for target "MyProject" which is not
built by this project.
The ability for target_sources to add source files via relative path to a target in a different directory was added in CMake 3.13. Since you have specified a minimum version of 3.9.1, this will simply not work.
The policy in question is CMP0076, which is documented as follows:
New in version 3.13.
The target_sources() command converts relative paths to absolute.
In CMake 3.13 and above, the target_sources() command now converts relative source file paths to absolute paths in the following cases:
Source files are added to the target's INTERFACE_SOURCES property.
The target's SOURCE_DIR property differs from CMAKE_CURRENT_SOURCE_DIR.
It is the second bullet point that applies here.
You really ought to use a newer version of CMake. Anything more than a few versions behind the newest (3.23) is plain masochism.

Providing include directory outside source folder for static library users

I am developing a simple static C library for learning purposes using cmake.
Some projects like GLFW provide an include folder on the root, so library users can copy it and use it as an include directory.
In my library, I want to have an include folder on the root, so when I use the library on other projects, I can just copy this folder and set it as an include directory.
Here is a simplified folder structure of my library:
include
+--mylib.h
src
+--myheader.h
+--mysource.c
+--CMakeLists.txt
CmakeLists.txt
The src folder has my headers and implementation files, and a CMakeLists.txt for building a static library out of mysource.c.
The CMakeLists on the root folder just sets the project and adds src as a subdirectory.
I want the mylib.h file to have a #include <myheader.h>.
Here's a detour to talk about how I want to use it when it's done.
The idea is that when using the lib on another project, I can have something like this:
deps
+--include
+--mylib.h
src
+--main.c
And in the main.c file, include mylib.h and use what's defined on myheader.h
Here the detour ends, and I'm talking about my actual lib project again.
How can I achieve this using cmake? As far as I know, the mylib.h file needs to know it's including files from the src diretory, but I see no way of setting that, as for exemple in GLFW this directory does not have a CMakeLists.txt.
I am gonna quess that this is a design issue since it would make sense to you if you would have installed the library to a system before you tried to use it. That is, not using add_subdirectory() but find_library() at usage.
First, if you are using a external library, but not installing it, you would include all files in you deps-folder. All files then include source-files and so on and will be compiled besides you main.c. This is done with add_subdirectory(deps/MyLib) and later also included in you main-project.
Example:
add_subdirectory(deps/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
If you do not want to compile it all the time, then you must instruct cmake where it can find headers and library-files. Preferred way is to use find_library() which does some magic for you. Since you do not mention any installation i will assume that it does not exist and your only option is then to use add_subdirectory().
"I can just copy this folder and set it as an include directory."
CMake wants to handle these things for you so you should never copy headers around. You should either use add_subdirectory() to include a project/headers or make use of the find_library() which make sure you find where the headers are in the system.
I suggest that you push yourself to learn howto install a library into a system and how to utilize it later, but only by using find_library(). Then the library will be global for all projects and also not duplicated.
Adding some kind of psudo-code in hope it all makes more sense. Although it is around add_subdirectory() since the code for installing is quite large unfortunately.
CMakeLists.txt for main.c
cmake_minimum_required(VERSION 3.8)
project(MyLibTest)
add_executable(${PROJECT_NAME}
src/main.c
)
add_subdirectory(external/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
CMakeLists.txt for library
cmake_minimum_required(VERSION 3.8)
project(MyLib)
add_library(${PROJECT_NAME} STATIC
src/MyLib.c
)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
The structure for the project would then be:
/
external/MyLib
external/MyLib/src
MyLib.c
external/MyLib/include
MyLib.h
src
main.c
CMakeLists.txt

Adding compiler "#define" flags in sub_directory CMakeLists.txt

My directory structure of project is build with multi CMakeLists.txts.
root
CMakeLists.txt
Src
main.c
CMSIS_lib
calculate.c
calculate.h
CMakeLists.txt
cmake
toolchain.cmake
build
In my CMSIS_lib I build separately my dependency source files calculate.c
and calculate.h with CMSIS_lib/CMakeList.txt:
set(util_source_files
calculate.c
calculate.h
)
add_library(util ${util_source_files})
target_include_directories(util calculate.h)
In my root CMakeLists.txt:
cmake_minimum_required(VERSION 3.4)
project(main_projct)
set(TOOLCHAIN_PREFIX /opt/gcc-arm-none-eabi)
set(CMAKE_TOOLCHAIN_FILE cmake/toolchain.cmake)
add_subdirectory(CMSIS_lib)
add_executable(main_projct main.c)
target_link_libraries(main_projct util)
Problem is that I must tell my compiler to add a #define GUCCI in my calculate.h (In MakeFile I know there is flag to tell a header define with -DGUCCI). I would like to add this flag to my compiler in my CMSIS_lib/CMakeList.txt, because when the first CMSIS_lib/CMakeList.txt is done building, he will skip everything under #ifndef GUCCI in my calculate.h, and when added in root CMakeLists.txt with target_link_libraries() I will not have all defines configuration correctly.
I am using cross-compiler and in my toolchain.cmake I use to define compiler flags with command SET_TARGET_PROPERTIES(${TARGET} PROPERTIES COMPILE_DEFINITIONS GUCCI}"), but this is to late because this only is seen by my root CMakeLists.txt and not by my sub director CMakeLists.txt.
Your CMSIS_lib/CMakeLists.txt should look like this:
set(util_source_files
calculate.c
calculate.h
)
add_library(util ${util_source_files})
target_include_directories(util ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(util PUBLIC GUCCI)
Note target_compile_definitions line, with PUBLIC parameter: it instructs cmake to use -DGUCCI compiler option while compiling util, and all targets that are linked against util.
Also note change in target_include_directories. You placed header file as parameter, but you should place directory instead.

Add only headers of an imported module to a library in CMake

In CMake there are imported modules that are used to simply add external modules to local targets. For example if we want to use boost::filesystem library in our project we could have a CMakeLists.txt like this:
project(foo CXX)
find_packge(Boost REQUIRED COMPONENTS filesystem)
add_executable(foo main.cpp)
target_link_libraries(foo Boost::filesystem)
With above configuration CMake will add proper compiler options and include directories among required libraries to building process of the foo.
Now we have to build a library instead of an executable and we don't want to link boost::filesystem libraries to our library. We want only compiler options and include directories to be added to our target. Could we use imported modules concepts here? I mean that if we could use Boost::filesystem syntax for adding those options to our target?
project(foo CXX)
find_packge(Boost REQUIRED COMPONENTS filesystem)
add_library(foo STATIC foo.cpp)
# what should be wrote here to only add headers and configs to foo not the libs?
Turning my comments into an answer
add_library(STATIC) won't link the target_link_libraries() dependencies into itself.
In short, if two static libraries would include e.g. Boost::filesystem and then you link both of those libraries into an executable (where the external symbols get actually resolved) you would get duplicate symbol errors.
So CMake by default, does not add linker options like --whole-archive for gcc or LinkLibraryDependencies for VC.
target_link_libraries(foo Boost::filesystem) should work, it just describes the dependency resolved later when building a executable or shared library.
References
ld linker question: the --whole-archive option
CMake issue #9732: Cmake does not disable Link Libray Dependencies in the project settings

Making a CMake library accessible by other CMake packages automatically

I have one project that produces a library:
project (myCoolLibrary)
ADD_LIBRARY(my_cool_library SHARED ${mysources_SRC})
And another project that should be using this library:
find_package (myCoolLibrary REQUIRED)
INCLUDE_DIRECTORIES("${myCoolLibrary_INCLUDE_DIRS}" )
add_executable(myCoolExe ${my_sources_SRC} )
TARGET_LINK_LIBRARIES(myCoolExe ${myCoolLibrary_LIBRARIES} )
Is there a way that I can change the first file so that the second file works automatically? That by running CMake on the first file and then running make on the output, then running CMake on the second file, CMake is able to find the package?
An answer where I just give the address of where the first project is built to the second package is also acceptable.
Taking the code found in a blog post by #daniperez - Use CMake-enabled libraries in your CMake project (III) - I've come up with the following minimal solution:
myCoolLibrary/CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(myCoolLibrary)
function(my_export_target _target _include_dir)
file(
WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Config.cmake"
"
include(\"\$\{CMAKE_CURRENT_LIST_DIR\}/${_target}Targets.cmake\")
set_property(
TARGET ${_target}
APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES \"${_include_dir}\"
)
"
)
export(TARGETS ${_target} FILE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Targets.cmake")
# NOTE: The following call can pollute your PC's CMake package registry
# See comments/alternatives below
export(PACKAGE ${_target})
endfunction(my_export_target)
...
add_library(${PROJECT_NAME} SHARED ${mysources_SRC})
my_export_target(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}")
myCoolExe/CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(myCoolExe)
find_package(myCoolLibrary REQUIRED)
...
add_executable(${PROJECT_NAME} ${my_sources_SRC})
target_link_libraries(${PROJECT_NAME} myCoolLibrary)
To make it reusable I have packed everything into my_export_target(). And I'm friend of self-propagating properties like INTERFACE_INCLUDE_DIRECTORIES.
As commented by #ruslo, using export(PACKAGE ...) can pollute your package registry. So alternatively you can:
Write the target configuration files directly to some dedicated place specific for a certain toolchain
See e.g. How to install your custom CMake-Find module and 0003659: FIND_PACKAGE command improvements.
Set CMAKE_MODULE_PATH via the second project's CMake command line (injecting the search path(s) from the outside). If you are building the two projects anyway with a build script, then this is the most direct way to propagate the module search path(s).
Additional References
export()
CMake/Tutorials/Package Registry
Unable to find Eigen3 with CMake
How to instruct CMake to use the build architecture compiler