Combining two CMakeLists.txt file (ROS and Libtorch) - cmake

I am trying to combine two CMakeLists.txt files to compile a C++ program that has both ROS and Libtorch dependencies. The individual files are provided below:
Libtorch CMakeLists.txt file:
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(example-app)
find_package(Torch REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")
add_executable(example-app example-app.cpp)
target_link_libraries(example-app "${TORCH_LIBRARIES}")
set_property(TARGET example-app PROPERTY CXX_STANDARD 14)
# The following code block is suggested to be used on Windows.
# According to https://github.com/pytorch/pytorch/issues/25457,
# the DLLs need to be copied to avoid memory errors.
if (MSVC)
file(GLOB TORCH_DLLS "${TORCH_INSTALL_PREFIX}/lib/*.dll")
add_custom_command(TARGET example-app
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${TORCH_DLLS}
$<TARGET_FILE_DIR:example-app>)
endif (MSVC)
I found this here: https://pytorch.org/cppdocs/installing.html
ROS CMakeListis.txt file:
cmake_minimum_required(VERSION 2.8.3)
project(fly_bot_cpp)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
geometry_msgs
tf
gazebo_msgs
)
include_directories(
include
${catkin_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
)
add_executable(example src/example.cpp)
target_link_libraries(example ${catkin_LIBRARIES})
The program example-app.cpp has both libraries of ROS and LibTorch.
So here is what i tried to do:
cmake_minimum_required(VERSION 2.8.3)
project(fly_bot_cpp)
set(CMAKE_PREFIX_PATH="home/jarvis/libtorch;/opt/ros/melodic")
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
geometry_msgs
tf
rospy
message_generation
)
find_package(Torch REQUIRED)
include_directories(
include
${catkin_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
)
add_executable(test_quad src/test_quad.cpp)
target_link_libraries(test_quad ${catkin_LIBRARIES} "${TORCH_LIBRARIES}")
set_property(TARGET test_quad PROPERTY CXX_STANDARD 14)
The code test_quad.cpp (previously referred to as example-app.cpp) contains ros header files and torch header files:
#include "ros/ros.h"
#include <torch/torch.h>
.
.
.
However, I get the following error.
fatal error: torch/torch.h: No such file or directory
#include <torch/torch.h>
^~~~~~~~~~~~~~~
compilation terminated.
Can someone please help me out??
Thank you so much.

Remove the quotes around ${TORCH_LIBRARIES} in your target_link_libraries.
The line should look like this
target_link_libraries(test_quad ${catkin_LIBRARIES} ${TORCH_LIBRARIES})
This should resolve the torch header.
Please also take a look at this post to find some more answers to where you might get stuck in the future-https://answers.ros.org/question/347885/combining-cmakeliststxt-of-libtorch-and-cmakeliststxt-of-ros-package/#
I hope this answer is helpful to someone new coming onboard to ros and libtorch :)

Related

CMake - How to get include directories of external project?

I tried to used https://github.com/julianxhokaxhiu/SteamworksSDKCI to use steam api on a simple SFML application (helloworld).
I wanted to use cmake to learn it, but I am struggling to understand how the provided CMakeLists and Find*.cmake file are expected to be used.
Currently, I have modified the CMakeLists to change the INSTALL_DIR
INSTALL_DIR "${CMAKE_BINARY_DIR}/../../vendor"
and my CMakeLists is :
cmake_minimum_required(VERSION 3.19)
project(SfmlWithCMake VERSION 1.0)
include(FetchContent)
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake_steam")
# Configure external project
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/cmake_steam)
execute_process(
COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR}/cmake_steam
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/cmake_steam
)
# Build external project
execute_process(
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/cmake_steam
)
set(BUILD_SHARED_LIBS OFF)
FetchContent_Declare(
SFML
GIT_REPOSITORY https://github.com/SFML/SFML.git
GIT_TAG 2.5.1
)
FetchContent_MakeAvailable(SFML)
find_package(STEAMWORKSSDK REQUIRED)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED true)
# Generate config.h
configure_file(config.h.in config.h)
add_executable(
SfmlWithCMake
main.cpp
)
get_target_property(STEAMSDK STEAMWORKSSDK::STEAMWORKSSDK INCLUDE_DIRECTORIES)
target_include_directories(
SfmlWithCMake
PRIVATE
"${PROJECT_BINARY_DIR}"
"${STEAMSDK}"
)
target_link_libraries(
SfmlWithCMake
sfml-graphics
STEAMWORKSSDK::STEAMWORKSSDK
-static gcc stdc++ winpthread -dynamic
)
install(TARGETS SfmlWithCMake DESTINATION bin)
How to get include directories?
I do not succeed to add the steam include to the target_include_directories.
Here the ${STEAMSDK} is my last attempt to get the directory.
If I replace this by ${PROJECT_BINARY_DIR}/vendor/include, everything works.
Also, why does the SFML include are automatically added to my target include directories and not the steam one?
Am I using the Find*.cmake file the right way?
I understood that ExternalProject_Add was performed at build time and thus, as the find_package is needed at configue time, I added the two "execute_process". But, the readme on github only says to do the find package and add the target to target_link_libraries...
Thanks.

Hot do I link MPFR in CMake?

I'm totally new to cmake, I'm on MacOs and I'm trying to build a c++ library and I need to link my executables to mpfr in order to make it work
This is my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.19)
project(my_project)
set(CMAKE_CXX_STANDARD 14)
add_executable(my_project main.cpp)
find_package(GSL REQUIRED)
target_link_libraries(my_project GSL::gsl GSL::gslcblas)
find_package(Boost REQUIRED)
target_link_libraries(my_project Boost::boost)
find_package(MPFR REQUIRED) # <- It fails here!
target_link_libraries(my_project MPFR::mpfr)
When I try to build my project with CLion I get the following error:
CMake Error at CMakeLists.txt:13 (find_package):
By not providing "FindMPFR.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "MPFR", but
CMake did not find one.
Could not find a package configuration file provided by "MPFR" with any of
the following names:
MPFRConfig.cmake
mpfr-config.cmake
Add the installation prefix of "MPFR" to CMAKE_PREFIX_PATH or set
"MPFR_DIR" to a directory containing one of the above files. If "MPFR"
provides a separate development package or SDK, be sure it has been
installed.
After some research I found out that Cmake was linking correctly both GSL and Boost because there are both a /usr/local/share/cmake/Modules/FindGSL.cmake and a /usr/local/share/cmake/Modules/FindBoost.cmake file, So I looked online for a FindMPFR.cmake file to insert into the /usr/local/share/cmake/Modules/ directory, I tried with this one but the error remains the same. What am I doing wrong?
Edit:
Ok now my CMakeLists.txt file looks like this:
cmake_minimum_required(VERSION 3.19)
project(my_project)
set(CMAKE_CXX_STANDARD 14)
add_executable(my_project main.cpp )
# Append the cmake/ directory to the CMAKE_MODULE_PATH
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(GSL REQUIRED)
message(STATUS "GSL Found: ${GSL_FOUND}")
target_link_libraries(my_project GSL::gsl GSL::gslcblas)
find_package(Boost REQUIRED)
message(STATUS "Boost Found: ${Boost_FOUND}")
target_link_libraries(my_project Boost::boost)
find_package(MPFR REQUIRED)
message(STATUS "MPFR Found: ${MPFR_FOUND}")
target_link_libraries(my_project ${MPFR_LIBRARIES})
And it works fine :)

Unable to compile C++ program with tf2_ros header inclusion

I have installed ros2 dashing diademata. I wrote a ROS2 node using C++14. I would like to read static_tf by creating a buffer and TransformListener
I am getting the following error when I include, #include "tf2_ros/buffer.h" If I do not include, I do not get any error.
The error is as follows
In file included from /opt/ros/dashing/include/tf2/LinearMath/Vector3.h:21:0,
from /opt/ros/dashing/include/tf2/LinearMath/Matrix3x3.h:19,
from /opt/ros/dashing/include/tf2/LinearMath/Transform.h:21,
from /opt/ros/dashing/include/tf2/buffer_core.h:35,
from /opt/ros/dashing/include/tf2_ros/buffer_interface.h:37,
from /opt/ros/dashing/include/tf2_ros/buffer.h:35,
from /module/src/example/include/example/example.h:17,
from /module/src/example/src/example.cpp:7:
/opt/ros/dashing/include/tf2/LinearMath/Scalar.h: In function ‘tf2Scalar tf2Log(tf2Scalar)’:
/opt/ros/dashing/include/tf2/LinearMath/Scalar.h:187:66: error: expression cannot be used as a function
TF2SIMD_FORCE_INLINE tf2Scalar tf2Log(tf2Scalar x) { return log(x); }
CMakeLists.txt is as follows
cmake_minimum_required(VERSION 3.5)
project(curb_odometry)
# Default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic -Wdeprecated-declarations -Wunused-parameter)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(nav_msgs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(tf2_ros REQUIRED)
find_package(tf2 REQUIRED)
find_package(message_filters REQUIRED)
find_package(Boost REQUIRED COMPONENTS system)
find_package (Eigen3 3.3 REQUIRED NO_MODULE)
include_directories(include
${Boost_INCLUDE_DIRS}
${tf2_ros_INCLUDE_DIRS}
${rclcpp_INCLUDE_DIRS}
${sensor_msgs_INCLUDE_DIRS}
${geometry_msgs_INCLUDE_DIRS}
${nav_msgs_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${EIGEN3_INCLUDE_DIR}
${message_filters_INCLUDE_DIR}
)
link_directories(${Boost_LIBRARY_DIRS})
add_executable(example src/example.cpp src/curb_detection.cpp src/curb_odometry.cpp)
target_link_libraries(example ${Boost_LIBRARIES} )
target_include_directories(example PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
ament_target_dependencies(
example
"rclcpp"
"sensor_msgs"
"geometry_msgs"
"nav_msgs"
"std_msgs"
"boost"
"message_filters"
"geometry2"
"tf2_ros"
"tf2"
)
install(TARGETS example
EXPORT export_${PROJECT_NAME}
DESTINATION lib/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# uncomment the line when a copyright and license is not present in all source files
#set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# uncomment the line when this package is not in a git repo
#set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
Looks like the error is coming from tf library. Any help in this regard will be appreciable.

CMake for protobuf library

I make my own example following this. But I don't want to make library, but just generate header and source files from .proto file.
So, I just change:
CMakeLists.txt
PROJECT(rpc)
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
SET(CMAKE_CXX_FLAGS "-g -Wall -Werror -std=c++11")
ADD_SUBDIRECTORY(proto)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
ADD_EXECUTABLE(main main.cpp)
#TARGET_LINK_LIBRARIES(main proto ${PROTOBUF_LIBRARY})
TARGET_LINK_LIBRARIES(main ${PROTOBUF_LIBRARY}) #<==== I changed here
proto/CMakeLists.txt
INCLUDE(FindProtobuf)
FIND_PACKAGE(Protobuf REQUIRED)
INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER message.proto)
#ADD_LIBRARY(proto ${PROTO_HEADER} ${PROTO_SRC}) #I don't compile lib anymore
But it doesn't generate header and source files from .proto. So it cannot compile. I think when using add_subdirectory, it doesn't run command protobuf_generate_cpp. Any idea is appreciated.
You can either add ${PROTO_HEADER} ${PROTO_SRC} directly to ADD_EXECUTABLE(main) call or add the following line to proto/CMakeLists.txt:
add_custom_target(gen_proto ALL DEPENDS ${PROTO_HEADER} ${PROTO_SRC})

PROTOBUF_GENERATE_CPP not generating src and header files

My cmake configuration is not generating any protobuf src and header files.
I've already checked if the proto files can be found.
Cmakelists.txt
cmake_minimum_required(VERSION 3.0.2)
..
include(FindProtobuf REQUIRED)
file(GLOB PROTO_DEF "${CMAKE_CURRENT_SOURCE_DIR}/protobuf/*/*.proto")
foreach(file ${PROTO_DEF})
if(EXISTS ${file})
MESSAGE("YES")
else()
MESSAGE("NO")
endif()
endforeach()
SET(PROTOBUF_GENERATE_CPP_APPEND_PATH PROTOBUF)
SET(PROTOBUF_PROTOC_EXECUTABLE protoc.exe)
..
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_INCL ${PROTO_DEF})
..
add_library(${PROJECT_NAME} STATIC ${INCLUDES} ${INTERNAL_INCLUDES} ${SRC} ${PROTO_SRC} ${PROTO_INCL})
target_link_libraries(${PROJECT_NAME} ${PROTOBUF_LIBRARIES})
I have checked the FindProtobuf.cmake and half way through:
foreach(FIL ${ARGN})
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
get_filename_component(FIL_WE ${FIL} NAME_WE)
list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc")
list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h")
MESSAGE(1 ${CMAKE_CURRENT_BINARY_DIR})
MESSAGE(2 ${_protobuf_include_path})
MESSAGE(3 ${ABS_FIL})
MESSAGE(4 ${PROTOBUF_PROTOC_EXECUTABLE})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc"
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h"
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL}
DEPENDS ${ABS_FIL}
COMMENT "Running C++ protocol buffer compiler on ${FIL}"
VERBATIM )
endforeach()
You can see i've added the 4 message commands, the script reaches this point and variables show good values.
The proto files do have a depencency to the library, thus the command should get executed !?
Any ideas on this problem?
update
replacing the add_custom_command with
EXEC_PROGRAM(${PROTOBUF_PROTOC_EXECUTABLE} ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL}
does generate the source and header files, must i manually activate the custom_commmands?
Regards Auke
The add_custom_command is fired (for my project) during compilation time.
Adding
SET_SOURCE_FILES_PROPERTIES(${PROTO_SRC} ${PROTO_INCL} PROPERTIES GENERATED TRUE)
gives cmake info that the files will be generated.
Alternative if you have an external proto folder:
file(GLOB PROTOBUF_FILELIST ${PROTO_INCLUDE_DIR}/*.proto)
foreach( proto_file ${PROTOBUF_FILELIST} )
get_filename_component(proto_name ${proto_file} NAME_WE)
get_filename_component(proto_path ${PROTO_INCLUDE_DIR} ABSOLUTE)
set_source_files_properties("${proto_path}/${proto_name}.pb.cc"
"${proto_path}/${proto_name}.pb.h"
PROPERTIES GENERATED TRUE)
endforeach()
See that:
https://cmake.org/cmake/help/v3.20/module/FindProtobuf.html
Example:
find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS EXPORT_MACRO DLL_EXPORT foo.proto)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS DESCRIPTORS PROTO_DESCS foo.proto)
protobuf_generate_python(PROTO_PY foo.proto)
add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS})
target_link_libraries(bar ${Protobuf_LIBRARIES})
Note The protobuf_generate_cpp and protobuf_generate_python functions and add_executable() or add_library() calls only work properly within the same directory.
This problem only happens when the target is a library (using add_library, add_executable seems to be fine). The PROTOBUF_GENERATE_CPP will defer the generation of protobuf sources and headers when building the library. A workaround is to define a custom target and add it as a dependency to the lib target. e.g.
add_custom_target(proto_dep DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})
add_library(${PROJECT_NAME} STATIC ${OTHER_SRCS})
add_dependencies(${PROJECT_NAME} proto_dep)
target_link_libraries(${PROJECT_NAME} PRIVATE gRPC::grpc++ gRPC::grpc++_reflection protobuf::libprotobuf)