详解ROS中的CMakeLists
详解ROS中的CMakeLists
在ROS(Robot Operating System)中,CMakeLists.txt文件是项目构建配置文件,它定义了如何构建ROS包中的可执行文件、库文件以及如何处理依赖关系等。CMakeLists.txt文件使用CMake语法编写,CMake是一个跨平台的构建系统,用于自动化编译、链接和打包过程。
下面我们详细介绍ROS中CMakeLists.txt的常用配置项:
- 最低CMake版本要求:这行代码定义了项目所需的最低CMake版本。在ROS中,通常需要CMake 2.8.3及以上版本
1
cmake_minimum_required(VERSION 2.8.3)
- 项目名称:这里定义了项目的名称,通常与ROS包名相同。
1
project(my_ros_package)
- 查找依赖包:find_package()函数用于查找项目所需的依赖包。REQUIRED关键字表示必须找到这些依赖包,否则构建过程将失败。COMPONENTS关键字后面的参数是需要查找的依赖包列表。
1
2
3
4
5
6find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
) - 声明构建依赖和运行时依赖:catkin_package()函数用于声明项目的构建依赖和运行时依赖。INCLUDE_DIRS指定头文件的目录,LIBRARIES指定项目生成的库文件,CATKIN_DEPENDS声明了项目在构建和运行时所依赖的其他ROS包。
1
2
3
4
5catkin_package(
INCLUDE_DIRS include
LIBRARIES my_ros_package
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
) - 添加头文件目录:include_directories()函数用于指定项目的头文件目录。这里包括了include目录和catkin_INCLUDE_DIRS(包含所有依赖包的头文件目录)。
1
2
3
4include_directories(
include
${catkin_INCLUDE_DIRS}
) - 添加可执行文件:add_executable()函数用于添加可执行文件。第一个参数是可执行文件的名称,第二个参数是源文件路径。
1
add_executable(my_node src/my_node.cpp)
- 链接库文件:target_link_libraries()函数用于为指定的可执行文件链接库文件。在本例中,为my_node可执行文件链接catkin_LIBRARIES,即所有依赖包的库文件。
1
2
3target_link_libraries(my_node
${catkin_LIBRARIES}
) - 添加依赖:add_dependencies()函数用于为指定的可执行文件添加依赖。在本例中,为my_node添加了项目导出目标和catkin_EXPORTED_TARGETS的依赖。
1
add_dependencies(my_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
- 安装
在CMakeLists.txt中,可以使用install()函数指定在构建过程中生成的可执行文件、库文件、头文件以及其他相关文件的安装路径。这些安装路径与ROS的devel和install目录有关。
例如,可以通过以下方式安装可执行文件、库文件和头文件:1
2
3
4
5
6
7
8
9
10
11
12install(TARGETS my_node
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
install(TARGETS my_library
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
)
install(DIRECTORY include/${PROJECT_NAME}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
)
- 安装其他资源文件:
除了可执行文件、库文件和头文件外,还可以安装其他资源文件,例如launch文件、配置文件和地图文件等。以下是一些示例:这些配置选项为ROS项目中的CMakeLists.txt文件提供了基本框架。根据项目的具体需求,可以对这些选项进行调整和扩展。例如,可以为项目添加自定义消息、服务和动作定义,配置不同的库文件和可执行文件,以及安装其他所需资源。1
2
3
4
5
6
7
8
9
10
11install(DIRECTORY launch/
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
)
install(DIRECTORY config/
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config
)
install(DIRECTORY maps/
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/maps
)
综上所述,ROS中的CMakeLists.txt文件负责管理构建过程,包括依赖关系、可执行文件、库文件、头文件等。为了使项目正常运行,需要正确地配置CMakeLists.txt文件。
自定义消息、服务和动作定义的处理
接下来,我们将深入探讨ROS中的CMakeLists.txt文件,包括自定义消息、服务和动作定义的处理。
- 自定义消息(msg):
要创建自定义消息,需要在项目的msg目录中定义.msg文件。接下来,在CMakeLists.txt中,将以下内容添加到find_package()函数中:然后添加如下指令来指定要生成的自定义消息文件:1
message_generation
接下来,调用generate_messages()函数来生成消息文件:1
2
3
4add_message_files(
FILES
MyCustomMessage.msg
)这里,DEPENDENCIES指定了自定义消息所依赖的其他消息包。1
2
3
4generate_messages(
DEPENDENCIES
std_msgs
) - 自定义服务(srv):
与自定义消息类似,自定义服务需要在项目的srv目录中定义.srv文件。然后,在CMakeLists.txt中,将以下内容添加到find_package()函数中:接着添加如下指令来指定要生成的自定义服务文件:1
2message_generation
接下来,调用generate_messages()函数来生成服务文件:1
2
3
4
5add_service_files(
FILES
MyCustomService.srv
)1
2
3
4
5generate_messages(
DEPENDENCIES
std_msgs
) 自定义动作(action):
要创建自定义动作,需要在项目的action目录中定义.action文件。在CMakeLists.txt中,将以下内容添加到find_package()函数中:1
2actionlib_msgs
然后添加如下指令来指定要生成的自定义动作文件:
1
2
3
4
5add_action_files(
FILES
MyCustomAction.action
)接着,调用generate_messages()函数来生成动作文件:
1
2
3
4
5generate_messages(
DEPENDENCIES
std_msgs actionlib_msgs
)在处理自定义消息、服务和动作时,还需要在catkin_package()函数中添加CATKIN_DEPENDS message_runtime以声明运行时依赖:
1
2
3
4
5catkin_package(
...
CATKIN_DEPENDS message_runtime
)总之,ROS的CMakeLists.txt文件涵盖了项目构建过程中的各个方面,包括依赖关系、可执行文件、库文件、头文件以及自定义消息、服务和动作。正确配置CMakeLists.txt文件,可确保ROS项目的顺利构建和运行。
高级配置选项和技巧
现在让我们继续深入探讨ROS中CMakeLists.txt的一些高级配置选项和技巧。
设置编译标志:
在CMakeLists.txt中,可以为项目设置编译标志。例如,可以使用以下指令为C++源文件启用C++11标准:1
2
3set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
如果要设置特定的编译器选项,可以使用set()函数:1
2set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
上述代码将为项目启用了所有警告(-Wall)以及额外警告(-Wextra)。
- 添加自定义CMake模块:
在某些情况下,可能需要使用自定义CMake模块来扩展项目的构建过程。为此,可以在项目的cmake目录中创建自定义CMake模块,并在CMakeLists.txt中使用list(APPEND …)和find_package()函数将其添加到CMAKE_MODULE_PATH:1
2
3list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
find_package(MyCustomCMakeModule REQUIRED)
- 条件编译:
在某些情况下,可能需要根据特定条件启用或禁用项目中的某些功能。可以使用option()函数和if()语句来实现这一目标:1
2
3
4
5
6
7option(ENABLE_MY_FEATURE "Enable my custom feature" OFF)
if(ENABLE_MY_FEATURE)
# Add custom code or configuration for the feature
add_definitions(-DENABLE_MY_FEATURE)
endif()
上述代码定义了一个名为ENABLE_MY_FEATURE的选项,默认值为OFF。如果选项被启用,将会添加一个预处理器定义ENABLE_MY_FEATURE。
- 为项目添加测试:
在ROS项目中,可以使用catkin_add_gtest()函数和gtest库为项目添加单元测试。首先,确保在find_package()函数中添加了rostest组件:1
2
3
4
5find_package(catkin REQUIRED COMPONENTS
...
rostest
)
然后添加测试可执行文件和链接库:1
2
3catkin_add_gtest(my_test test/my_test.cpp)
target_link_libraries(my_test ${catkin_LIBRARIES} my_library)
以上示例中,my_test是测试的名称,test/my_test.cpp是测试源文件,而my_library是测试所需链接的库。
这些高级配置选项和技巧可以帮助你在ROS项目中实现更复杂的构建过程。理解这些选项的用途和功能,将有助于创建更可扩展和可维护的ROS项目。
实现一些实用功能和配置
接下来,我们将讨论如何在ROS中的CMakeLists.txt文件中实现一些实用功能和配置:
- 添加Python可执行文件:
在ROS项目中,你可能需要添加Python脚本作为可执行文件。首先,确保在find_package()函数中添加了rospy组件:1
2
3
4
5find_package(catkin REQUIRED COMPONENTS
...
rospy
)
然后,可以使用catkin_install_python()函数将Python脚本安装为可执行文件:1
2
3
4catkin_install_python(PROGRAMS scripts/my_python_script.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
- 添加动态链接库(动态库):
有时候,可能需要在ROS项目中创建动态链接库。为此,可以使用add_library()函数和SHARED关键字:1
2add_library(my_shared_library SHARED src/my_shared_library.cpp)
接着,为生成的库文件添加安装目标:1
2
3
4install(TARGETS my_shared_library
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
)
- 链接系统库:
在某些情况下,可能需要链接系统库。可以使用find_library()函数查找系统库,并使用target_link_libraries()函数将其链接到目标:1
2
3
4
5
6
7
8
9
10find_library(MY_SYSTEM_LIBRARY
NAMES my_system_library
PATHS /path/to/libraries
)
target_link_libraries(my_executable
${catkin_LIBRARIES}
${MY_SYSTEM_LIBRARY}
)
- 链接Boost库:
在ROS项目中,可能需要使用Boost库。为此,首先确保在find_package()函数中添加了Boost组件:然后,将Boost库添加到target_link_libraries()函数中:1
2
3
4
5find_package(Boost REQUIRED COMPONENTS
system
thread
)1
2
3
4
5target_link_libraries(my_executable
${catkin_LIBRARIES}
${Boost_LIBRARIES}
) - 使用环境变量:
在CMakeLists.txt中,可以通过$ENV{VAR_NAME}语法访问环境变量。例如,以下代码从环境变量MY_VAR获取值并将其存储在CMake变量my_var中:1
2set(my_var $ENV{MY_VAR})
了解这些实用功能和配置将有助于处理ROS项目中的各种需求。这些示例可以根据项目需求进行调整和扩展,以便更好地适应特定的构建环境和依赖关系。现在让我们继续探讨ROS中CMakeLists.txt文件的一些其他实用功能和技巧。
使用外部项目
在ROS项目中,可能需要使用外部项目的代码和资源。CMake具有一个名为ExternalProject的模块,可用于下载、构建和安装外部项目。首先,需要在CMakeLists.txt中包含ExternalProject模块:1
2include(ExternalProject)
接下来,使用ExternalProject_Add()函数定义外部项目:1
2
3
4
5
6ExternalProject_Add(my_external_project
GIT_REPOSITORY "https://github.com/user/my_external_project.git"
GIT_TAG "master"
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/external
)
这里,my_external_project是外部项目的名称,GIT_REPOSITORY和GIT_TAG指定了项目的源代码仓库和分支。CMAKE_ARGS用于传递给外部项目的CMake构建的参数,其中CMAKE_INSTALL_PREFIX指定了安装路径。
使用pkg-config:
有时,可能需要使用pkg-config工具查询库的编译和链接标志。CMake提供了一个名为PkgConfig的模块,可用于与pkg-config交互。首先,需要在CMakeLists.txt中包含PkgConfig模块:1
2find_package(PkgConfig REQUIRED)
然后,可以使用pkg_check_modules()函数查询库信息:1
2pkg_check_modules(MY_LIBRARY_PKGCONFIG REQUIRED my_library)
接下来,可以使用查询到的信息为目标设置编译和链接标志:1
2
3target_include_directories(my_executable PRIVATE ${MY_LIBRARY_PKGCONFIG_INCLUDE_DIRS})
target_link_libraries(my_executable ${catkin_LIBRARIES} ${MY_LIBRARY_PKGCONFIG_LIBRARIES})
在ROS中使用Eigen库:
在ROS项目中,可能需要使用Eigen库进行线性代数计算。首先,确保在find_package()函数中添加了Eigen3组件:1
2find_package(Eigen3 REQUIRED)
然后,将Eigen库添加到target_include_directories()函数中:1
2
3
4
5target_include_directories(my_executable
PRIVATE
${EIGEN3_INCLUDE_DIRS}
)
这些实用功能和技巧可以帮助您在ROS项目中处理各种需求和依赖项。了解如何使用这些功能可以使您的项目更具灵活性和可扩展性,同时确保与其他库和软件包的兼容性。请注意,这些示例可能需要根据项目的具体需求进行调整。
使用OpenCV库
在ROS项目中,可能需要使用OpenCV库进行计算机视觉处理。首先,在find_package()函数中添加OpenCV组件:1
2find_package(OpenCV REQUIRED)
接下来,在target_link_libraries()函数中链接OpenCV库:1
2target_link_libraries(my_executable ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
设置安装规则
在ROS项目中,通过使用install()函数,可以将构建的可执行文件、库文件、头文件和其他资源文件安装到目标目录,以方便分发和部署。下面是一些常见的安装规则示例:
安装可执行文件:1
2
3
4install(TARGETS my_executable
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
安装库文件:
1 |
|
安装头文件:1
2
3
4install(DIRECTORY include/${PROJECT_NAME}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
)
安装资源文件(如配置文件、launch文件等):1
2
3
4install(DIRECTORY config launch
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
)
在CMakeLists.txt中添加自定义命令
有时,可能需要在构建过程中执行一些自定义操作,如生成代码或处理资源文件。可以使用add_custom_command()函数在CMakeLists.txt中定义自定义命令:1
2
3
4
5
6add_custom_command(
OUTPUT generated_file.cpp
COMMAND my_generator_tool --input=input_file --output=generated_file.cpp
DEPENDS input_file
)
上述代码指定了一个自定义命令,它在generated_file.cpp文件不存在或input_file文件发生更改时,运行my_generator_tool工具。
使用message、service和action文件生成代码
ROS中的消息、服务和动作定义文件需要生成相应的C++、Python等语言的代码。在CMakeLists.txt中,可以使用以下函数生成代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# Generate message code
add_message_files(
FILES
MyMessage.msg
)
# Generate service code
add_service_files(
FILES
MyService.srv
)
# Generate action code
add_action_files(
FILES
MyAction.action
)
生成代码之前,需要确保在find_package()函数中添加了message_generation、actionlib_msgs等组件:1
2
3
4
5
6find_package(catkin REQUIRED COMPONENTS
...
message_generation
actionlib_msgs
)
然后,使用generate_messages()函数生成代码:1
2
3
4
5
6generate_messages(
DEPENDENCIES
std_msgs
actionlib_msgs
)
使用message、service和action文件的依赖关系:
有时候,一个ROS软件包可能依赖于另一个软件包中定义的消息、服务或动作。在这种情况下,需要确保在find_package()函数中添加了相应的组件:1
2
3
4
5find_package(catkin REQUIRED COMPONENTS
...
other_package_msgs
)
此外,还需要将依赖关系添加到catkin_package()函数中:1
2
3
4
5catkin_package(
...
CATKIN_DEPENDS other_package_msgs
)
使用CMake的message()函数
在CMakeLists.txt文件中,可以使用message()函数打印调试信息。这对于调试构建过程中的问题很有帮助。message()函数接受不同的严重性级别,例如:STATUS、WARNING和FATAL_ERROR。1
2
3
4message(STATUS "This is a status message")
message(WARNING "This is a warning message")
message(FATAL_ERROR "This is a fatal error message")
通过掌握这些实用功能和技巧,可以帮助您在ROS项目中应对各种需求和依赖。了解如何使用这些功能可以使您的项目更具灵活性和可扩展性,同时确保与其他库和软件包的兼容性。请注意,这些示例可能需要根据项目的具体需求进行调整。