RL项目代码的根目录的CMakefile解读
项目的基本信息
在cmake_minimum_required
中指定了cmake的最小版本,这里指定了为2.8.11,目前cmake最新版本为3.29,这个rl库的0.7.0版本比较老,采用c++的标准只支持到c++11,后面我们分析编译选项时候就可以看出来。project
指定了项目的名称,这个项目叫做rl,下面的三个set设置了三个变量的值,由最后一行的set使用,cmake使用变量的方式都是先定义,然后使用${变量}
的方式使用其变量的值。在 CMake 中,${}
用于引用变量的值。它告诉 CMake 你想要使用变量的值,而不是变量的名字。
cmake_minimum_required(VERSION 2.8.11)
project(rl)
set(VERSION_MAJOR 0)
set(VERSION_MINOR 7)
set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
项目的编译信息
下面这是一条 CMake 指令,用于将当前源目录下的 cmake 子目录添加到 CMAKE_MODULE_PATH 变量中。CMAKE_MODULE_PATH 是一个路径列表,CMake 会在这些路径中查找模块文件(.cmake 文件)。CMAKE_MODULE_PATH是cmake定义的,指引CMake 会在这些路径中查找模块文件(.cmake 文件)。
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(CheckCXXCompilerFlag)
:这个模块用于检查给定的 C++ 编译器标志是否被编译器支持。include(CMakeDependentOption)
:这个模块提供了一种定义依赖于其他选项的选项的方法。include(CMakePackageConfigHelpers)
:这个模块有助于创建 CMake 的包配置文件。include(GNUInstallDirs)
:这个模块定义了 GNU 系统的安装目录。
include(CheckCXXCompilerFlag)
include(CMakeDependentOption)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
检查c++标准
这里是检查是否支持c++11标准,支持就让编译器开c++11编译,否则使用c++0x,C++0x 是 C++11 标准在正式发布之前的名称。在 2011 年正式批准之前,这个标准被非正式地称为 C++0x。
if(NOT CMAKE_VERSION VERSION_LESS 3.1)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
else()
check_cxx_compiler_flag("-std=c++0x" HAS_CXX_COMPILER_FLAG_STDCXX0X)
if(HAS_CXX_COMPILER_FLAG_STDCXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
endif()
check_cxx_compiler_flag("-std=c++11" HAS_CXX_COMPILER_FLAG_STDCXX11)
if(HAS_CXX_COMPILER_FLAG_STDCXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
endif()
下面是一些在Windows平台下的编译的一些修改
你这段代码是在 CMake 中为 Windows 平台添加一些预处理器定义。以下是每个定义的简要说明:
_CRT_SECURE_NO_WARNINGS
:禁用与不安全的 C 运行时函数(如strcpy
、sprintf
等)相关的警告。_SCL_SECURE_NO_WARNINGS
:禁用与不安全的标准 C++ 库函数(如std::copy
等)相关的警告。_USE_MATH_DEFINES
:在包含cmath
头文件之前定义此宏,以便启用数学常量(如M_PI
)。_WIN32_WINNT=0x501
:定义 Windows 版本为 Windows XP(0x501 对应 Windows XP)。NOMINMAX
:防止 Windows 头文件定义min
和max
宏,以避免与标准库中的std::min
和std::max
冲突。WIN32_LEAN_AND_MEAN
:减少包含在 Windows 头文件中的内容,以加快编译速度并减少命名冲突。
if(WIN32)
add_definitions(
-D_CRT_SECURE_NO_WARNINGS
-D_SCL_SECURE_NO_WARNINGS
-D_USE_MATH_DEFINES
-D_WIN32_WINNT=0x501
-DNOMINMAX
-DWIN32_LEAN_AND_MEAN
)
endif()
编译选项设置
这里设置了boost的版本期间,在这个区间内的boost版本编译说明RL认为这些库可以编译
set(Boost_ADDITIONAL_VERSIONS "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57")
include
这里找到模块是${CMAKE_CURRENT_SOURCE_DIR}/cmake这里面的,即当前目录下的cmake文件里面的内容,找的.cmake
文件是Qt4AutomocMocOptionsBoost
。
include(Qt4AutomocMocOptionsBoost)
细看这里面的内容就是当你在 CMakeLists.txt 文件中设置 CMAKE_AUTOMOC_MOC_OPTIONS 时,这些选项会被传递给 moc 工具,主要是一些和boost库有关的设定
list(
APPEND
CMAKE_AUTOMOC_MOC_OPTIONS
-DBOOST_TT_HAS_BIT_AND_HPP_INCLUDED
(省略)
)
从option开始就是关于一些编译选项的描述,其实这里的选项都是cmakefile或者.cmake中写好的,你可以理解为函数,当选项写成on的时候就是执行跳转执行这个函数
option(BUILD_DEMOS "Build demos" ON)
option(BUILD_DOCUMENTATION "Build documentation" OFF)
option(BUILD_EXTRAS "Build extras" ON)
option(BUILD_RL_MATH "Build mathematics component" ON)
option(BUILD_RL_UTIL "Build utility component" ON)
option(BUILD_RL_XML "Build XML abstraction layer component" ON)
option(BUILD_TESTS "Build tests" ON)
编译中的cmake_dependent_option
cmake_dependent_option(<option> "<help_text>" <value> "<depends>" <force>)
其中
- option:选项的名称。
- help_text:选项的描述信息。
- value:当依赖条件满足时,选项的默认值(ON 或 OFF)。
- depends:依赖条件,是一个由分号分隔的选项或变量列表,整个字符串用双引号包含起来。
- force:当依赖条件不满足时,选项的值(ON 或 OFF)。
让我们回到cmakefile文件,下面的这些 cmake_dependent_option
定义了需要构建依赖的选项,例如第一条如果 BUILD_RL_MATH;BUILD_RL_UTIL
为 ON
满足条件,那么他这里就打开,否则就关闭
cmake_dependent_option(BUILD_RL_HAL "Build hardware abstraction layer component" ON "BUILD_RL_MATH;BUILD_RL_UTIL" OFF)
cmake_dependent_option(BUILD_RL_KIN "Build Denavit-Hartenberg kinematics component" ON "BUILD_RL_MATH;BUILD_RL_XML" OFF)
cmake_dependent_option(BUILD_RL_MDL "Build rigid body kinematics and dynamics component" ON "BUILD_RL_MATH;BUILD_RL_XML" OFF)
cmake_dependent_option(BUILD_RL_SG "Build scene graph abstraction component" ON "BUILD_RL_MATH;BUILD_RL_UTIL;BUILD_RL_XML" OFF)
cmake_dependent_option(BUILD_RL_PLAN "Build path planning component" ON "BUILD_RL_KIN;BUILD_RL_MATH;BUILD_RL_MDL;BUILD_RL_SG;BUILD_RL_UTIL;BUILD_RL_XML" OFF)
总的来说选项有:
选项 | 描述 | 值 |
---|---|---|
-D BUILD_DEMOS=ON | 启用/禁用构建演示应用程序。 | ON/OFF |
-D BUILD_DOCUMENTATION=OFF | 启用/禁用构建 API 文档。 | ON/OFF |
-D BUILD_EXTRAS=ON | 启用/禁用构建额外的应用程序。 | ON/OFF |
-D BUILD_RL_HAL=ON | 启用/禁用构建 RL::HAL 库及其依赖项。 | ON/OFF |
-D BUILD_RL_KIN=ON | 启用/禁用构建 RL::KIN 库及其依赖项。 | ON/OFF |
-D BUILD_RL_MATH=ON | 启用/禁用构建 RL::MATH 库及其依赖项。 | ON/OFF |
-D BUILD_RL_MDL=ON | 启用/禁用构建 RL::MDL 库及其依赖项。 | ON/OFF |
-D BUILD_RL_PLAN=ON | 启用/禁用构建 RL::PLAN 库及其依赖项。 | ON/OFF |
-D BUILD_RL_SG=ON | 启用/禁用构建 RL::SG 库及其依赖项。 | ON/OFF |
-D BUILD_RL_UTIL=ON | 启用/禁用构建 RL::UTIL 库及其依赖项。 | ON/OFF |
-D BUILD_RL_XML=ON | 启用/禁用构建 RL::XML 库及其依赖项。 | ON/OFF |
-D BUILD_SHARED_LIBS=ON | 启用/禁用构建共享库。 | ON/OFF |
-D BUILD_TESTS=ON | 启用/禁用构建测试应用程序。 | ON/OFF |
-D USE_QT5=ON | 如果可用,优先使用 Qt5 而不是 Qt4。 | ON/OFF |
编译CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
这段代码是在 CMake 中根据不同的条件设置 BUILD_SHARED_LIBS
选项。如果在 Windows 平台上且 CMake 版本小于 3.4,则将 BUILD_SHARED_LIBS
设置为 OFF
。如果在 Windows 平台上且 CMake 版本不小于 3.4,则定义一个选项 BUILD_SHARED_LIBS
,默认值为 OFF
,并将 CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
设置为 BUILD_SHARED_LIBS
的值。对于其他平台,定义一个选项 BUILD_SHARED_LIBS
,默认值为 ON
。先说为啥需要再Windows上设置这个变量,感兴趣的可以看一下这个问题下的回答Stackflow关于创建 DLL 时导出所有符号,简单说就是Windows下导出shared_libs
之前巨麻烦,在cmake3.4
之后引入了上面那个CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
变量之后才简化了流程。所以这里如果cmake不为3.4版本,则直接关掉生产动态库。至于Linux或者其他操作系统就没有啥问题了。
if(WIN32 AND CMAKE_VERSION VERSION_LESS 3.4)
set(BUILD_SHARED_LIBS OFF)
elseif(WIN32 AND NOT CMAKE_VERSION VERSION_LESS 3.4)
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ${BUILD_SHARED_LIBS})
else()
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
endif()
增加子文件夹
下面这段代码是增加子文件,具体的内容我们之后再分析阅读:
include_directories(BEFORE src/rl/std)
add_subdirectory(src/rl/std)
add_subdirectory(src)
add_subdirectory(examples)
if(BUILD_DEMOS)
add_subdirectory(demos)
endif()
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
add_subdirectory(doc)
-
include_directories(BEFORE src/rl/std)
:
将src/rl/std
目录添加到包含路径中,并且优先于其他包含目录。这意味着在编译过程中,编译器会首先搜索这个目录中的头文件。 -
add_subdirectory(src/rl/std)
:
将src/rl/std
目录添加为一个子目录,并处理该目录中的 CMakeLists.txt 文件。 -
add_subdirectory(src)
:
将src
目录添加为一个子目录,并处理该目录中的 CMakeLists.txt 文件。 -
add_subdirectory(examples)
:
将examples
目录添加为一个子目录,并处理该目录中的 CMakeLists.txt 文件。 -
if(BUILD_DEMOS) add_subdirectory(demos) endif()
:
如果BUILD_DEMOS
选项为ON
,则将demos
目录添加为一个子目录,并处理该目录中的 CMakeLists.txt 文件。 -
if(BUILD_TESTS) enable_testing() add_subdirectory(tests) endif()
:
如果BUILD_TESTS
选项为ON
,则启用测试功能,并将tests
目录添加为一个子目录,并处理该目录中的 CMakeLists.txt 文件。 -
add_subdirectory(doc)
:
将doc
目录添加为一个子目录,并处理该目录中的 CMakeLists.txt 文件。
配置安装文件
这段代码会生成一个配置安装信息的文件,rl-config.cmake.in
这是输入模板文件,它通常包含一些占位符,这些占位符将在配置过程中被替换为实际的值。rl-config.cmake
这是输出文件。配置过程会生成这个文件,并将输入模板文件中的占位符替换为实际的值。
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/rl-${VERSION}
这是安装目的地。生成的配置文件将被安装到这个指定的目录中。${CMAKE_INSTALL_LIBDIR}
是一个变量,通常表示安装库文件的目录。
configure_package_config_file(
rl-config.cmake.in rl-config-install.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/rl-${VERSION}
)
导出和安装部分
这些cmake代码是生成一些安装和包的导出的一些cmake文件,我们之后再细细解读,因为里面涉及到很多编译之后的安装和接口问题,等我们逐步分析完代码之后再回过来分析。
export(
TARGETS ${TARGETS}
NAMESPACE rl::
FILE ${CMAKE_CURRENT_BINARY_DIR}/rl-export.cmake
)
configure_package_config_file(
rl-config.cmake.in rl-config-install.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/rl-${VERSION}
)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/rl-config-install.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/rl-${VERSION}
RENAME rl-config.cmake
COMPONENT development
)
省略其他
CPack配置
include(CPackConfig)
这里包含了CPack的配置文件CPackConfig.cmake。这个文件通常包含了有关如何生成安装包的配置信息。
include(CPack)
这里面包含了CPack模块本身,通过包含这个模块,可以使用CPack提供的功能来生成各种类型的安装包,例如ZIP文件、DEB包、RPM包等。然后,只需要运行make package或ninja package(取决于你使用的构建系统),CPack就会生成相应的安装包。不能少了这个CPack,因为CPackConfig
提供了信息,交给CPack
处理。
include(CPackConfig)
include(CPack)