# 1 IF NOT和IF NOT DEFINED的区别?
# 2 环境变量
# 3 .cmake脚本
# 4 if (NOT EXISTS有什么用?
# 5 CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
# 6 CMAKE_CXX_FLAGS
# 7 execute_process
1 IF ( NOT和IF ( NOT DEFINED的区别?
在CMake脚本中,IF (NOT ...) 和 IF (NOT DEFINED ...) 是两种用于条件判断的结构,但它们检查的内容不同。
1.1 IF (NOT ...):
这个结构用于检查某个条件是否为假(即“非”该条件)。这里的条件可以
例如:SET(MY_VAR "some_value")IF (NOT MY_VAR)# 这部分代码不会被执行,因为MY_VAR已被定义且非空ENDIF()# 或者检查一个比较表达式的结果IF (NOT (MY_VAR STREQUAL "expected_value"))# 如果MY_VAR的值不等于"expected_value",则执行这部分代码ENDIF()
在这个上下文中,NOT 是逻辑非操作符,用于反转条件的真假值
1.2 IF (NOT DEFINED ...):
这个结构专门用于检查一个变量是否未被定义。如果变量未定义,则条件为真;如果变量已定义(无论其值是什么),则条件为假。
IF (NOT DEFINED MY_UNDEFINED_VAR)# 这部分代码会被执行,因为MY_UNDEFINED_VAR未被定义
ENDIF()SET(MY_DEFINED_VAR "any_value")
IF (NOT DEFINED MY_DEFINED_VAR)# 这部分代码不会被执行,因为MY_DEFINED_VAR已被定义
ENDIF()
在这个上下文中,NOT DEFINED 是一个特殊的检查,用于确定变量是否存在。
1.3
总结来说,IF (NOT ...) 是一个更通用的条件判断结构,可以用于检查各种条件的真假值(包括变量是否存在且非空),而 IF (NOT DEFINED ...) 是一个专门用于检查变量是否未定义的结构。选择使用哪一个取决于你想要检查的具体条件。
2 环境变量
SET(ROS_ROOT $ENV{ROS_ROOT})
从环境变量中读取 ROS_ROOT 的值,并将这个值赋给 CMake 变量 ROS_ROOT。
这里有几个关键点需要注意:
- 环境变量:$ENV{...} 是 CMake 中访问环境变量的语法。它允许你从操作系统的环境变量中读取值,并在 CMake 配置过程中使用这些值。
env
或printenv
:可以查看ubuntu下的环境变量
3 .cmake脚本
INCLUDE(${PROJ_SOURCE_DIR}/orocos-rtt.cmake OPTIONAL)
在CMake中,INCLUDE 命令用于包含另一个CMake脚本文件,这样可以将一些通用的配置或函数定义等放入单独的文件中,然后在多个CMakeLists.txt中重用。OPTIONAL 关键字是CMake 3.12及更高版本
中引入的,用于处理包含文件时可能遇到的情况,特别是当包含的文件不存在时。
使用OPTIONAL可以使你的CMake配置更加健壮,特别是在处理可选的组件或插件时。这样,即使某些可选的CMake脚本文件不存在,整个项目的构建过程也不会因此中断。
例如,在你的项目中,orocos-rtt.cmake 可能包含了一些与Orocos RTT(Robot Control Middleware)相关的配置。如果Orocos RTT不是项目必需的,或者只在某些特定的构建配置中才需要,那么使用OPTIONAL就可以确保当Orocos RTT不可用或未配置时,项目的其他部分仍然可以正常构建。
4 if (NOT EXISTS有什么用?
在CMake中,if 语句用于基于某些条件执行不同的代码块。NOT EXISTS 是一个条件表达式,用于检查指定的文件或目录是否不存在。
if (NOT EXISTS <some_file_or_directory>)# 如果文件或目录不存在,则执行这里的命令
endif()
这里的 <some_file_or_directory>
应该被替换为你想要检查的文件或目录的路径
。如果该文件或目录在CMake运行时不存在,那么if 语句内的命令将被执行。
例如,你可能想要在项目中包含一些可选的库或组件,而这些库或组件的CMake配置文件可能不是总是存在的。你可以使用if (NOT EXISTS ...)
来检查这些配置文件是否存在,如果不存在,则跳过包含它们的命令或执行一些替代的命令。
# 假设我们有一个可选的库,其配置文件可能不存在set(OPTIONAL_LIB_CONFIG "${CMAKE_SOURCE_DIR}/optional-lib-config.cmake")# 检查配置文件是否存在if (NOT EXISTS ${OPTIONAL_LIB_CONFIG})message(STATUS "Optional library config file not found, skipping...")# 这里可以执行一些替代的命令,或者什么都不做else()# 如果配置文件存在,则包含它include(${OPTIONAL_LIB_CONFIG})endif()
在这个例子中,如果optional-lib-config.cmake文件不存在,CMake将输出一条状态消息,并跳过包含该文件的命令。如果文件存在,则正常包含并执行其中的命令。
请注意,if 语句在CMake中有时可能会因为条件表达式的复杂性而变得难以阅读和维护。因此,尽量保持条件简单明了,并在可能的情况下使用变量来简化表达式。
5 CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
在 CMake 中是一个用于判断 CMAKE_INSTALL_PREFIX 变量是否被设置为默认值的标志。CMAKE_INSTALL_PREFIX 是 CMake 的一个内置变量,它定义了安装目标(如可执行文件、库文件等)时的前缀路径。这个前缀路径决定了安装目标在系统中的最终位置。
具体来说,CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
的作用如下:
- 判断默认值:在 CMake 配置过程中,CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT 可以被用来检查
CMAKE_INSTALL_PREFIX
是否被用户显式设置过,还是仍然保持着其默认值。这通常用于在 CMakeLists.txt 或其他 CMake 脚本中做出条件性的配置决策。 - 提供灵活性:通过检查这个标志,CMake 脚本可以根据 CMAKE_INSTALL_PREFIX 是否被修改过,来执行不同的安装逻辑。例如,如果
CMAKE_INSTALL_PREFIX
保持默认值,脚本可能会选择一个特定的安装目录;如果它被修改了,则使用用户指定的目录。 - 增强可移植性:在跨平台的项目中,
CMAKE_INSTALL_PREFIX
的默认值可能因操作系统而异(例如,在 UNIX 系统上通常是/usr/local
,在 Windows 上则可能是一个基于Program Files
的路径)。通过检查CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
,CMake 脚本可以更加智能地处理这些平台差异,从而增强项目的可移植性。
在 CMake 脚本中使用 CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
的一个典型场景是,在项目配置阶段根据 CMAKE_INSTALL_PREFIX
是否被设置为默认值来设置一些额外的配置参数或执行一些特定的安装逻辑。例如:
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)# 如果 CMAKE_INSTALL_PREFIX 保持默认值,则设置一个新的安装前缀set(CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/install" CACHE PATH "${PROJECT_SOURCE_DIR}/install" FORCE)
endif()
在这个例子中,如果 CMAKE_INSTALL_PREFIX
没有被用户显式设置过,那么它将被设置为项目源代码目录下的 install
子目录。这提供了一种方便的方式来为用户提供一个默认的安装位置,同时仍然允许用户通过命令行参数或 CMake GUI 来覆盖这个默认值。
6 CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS 是一个在 CMake 中使用的变量,它用于指定编译 C++ 代码时传递给编译器的标志(flags)。这些标志可以控制编译器的行为,比如优化级别、警告级别、是否生成调试信息等。
在 CMakeLists.txt 文件中设置 CMAKE_CXX_FLAGS 变量,可以为整个项目设置默认的编译器标志。例如,如果你想增加编译时的警告级别,可以这样设置:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
这里 -Wall 和 -Wextra 是 GCC 和 Clang 编译器用来增加警告级别的标志。
此外,CMake 还支持为不同的构建类型(如 Debug 和 Release)设置不同的编译器标志。这可以通过设置 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_CXX_FLAGS_RELEASE 等变量来实现。例如
# 为 Debug 构建类型设置编译器标志
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0")# 为 Release 构建类型设置编译器标志
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -DNDEBUG")
在这个例子中,-g 标志用于生成调试信息,-O0 表示不进行任何优化,适用于 Debug 构建;而 -O2 表示进行中等级别的优化,-DNDEBUG 用于定义 NDEBUG 宏,通常用于禁用断言,适用于 Release 构建。
通过设置这些变量,开发者可以灵活地控制项目的编译行为,以满足不同的需求和目标。
7 execute_process
if (NOT IS_SYMLINK ${CMAKE_CURRENT_SOURCE_DIR}/install )# Note: we use WORKING_DIRECTORYexecute_process ( COMMAND ${CMAKE_COMMAND} -E remove_directory installCOMMAND ${CMAKE_COMMAND} -E create_symlink ../install installWORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}OUTPUT_QUIET ERROR_QUIET)
endif()
在 CMake 脚本中,您提供的代码段旨在检查 ${CMAKE_CURRENT_SOURCE_DIR}/install
是否为一个符号链接(symlink),如果不是,则执行两个命令:首先删除 install 目录(如果存在),然后创建一个指向 ../install 的符号链接。这里有几个要点需要注意:
-
检查符号链接:
CMake 本身没有直接的命令来检查一个路径是否是符号链接。通常,这种检查需要在脚本中使用平台特定的命令或脚本语言特性来完成。不过,在您的代码中,IF (NOT IS_SYMLINK ${CMAKE_CURRENT_SOURCE_DIR}/install) 这一行实际上是有问题的,因为 CMake 的标准语法中并没有 IS_SYMLINK 这样的判断。这意味着这行代码在 CMake 中不会按预期工作。
-
删除目录和创建符号链接:
execute_process
命令用于执行外部命令或脚本。在您的例子中,它用于执行 CMake 自带的 -E remove_directory 和 -E create_symlink 命令。这些命令分别用于删除目录和创建符号链接。WORKING_DIRECTORY
:
此选项指定了 execute_process 命令的工作目录。在您的例子中,它被设置为 ${CMAKE_CURRENT_SOURCE_DIR},即当前 CMake 源目录。OUTPUT_QUIET ERROR_QUIET
:
这些选项用于抑制命令的标准输出和错误输出。这意味着即使命令执行失败,用户也不会在 CMake 的配置输出中看到任何错误信息。
由于 IS_SYMLINK
不是 CMake 的有效命令或变量,您需要找到另一种方法来检查 install
是否为符号链接。这通常涉及到调用平台特定的命令(如 Unix 上的 test -L 或 Windows 上的 cmd /c dir /AL)并通过 execute_process 来捕获其结果。
以下是一个在 Unix 系统上检查符号链接的示例(注意,这只是一个概念验证,可能需要根据您的具体需求进行调整):
execute_process(COMMAND test -L "${CMAKE_CURRENT_SOURCE_DIR}/install"RESULT_VARIABLE IS_SYMLINK_RESULTOUTPUT_QUIET ERROR_QUIET)if (NOT IS_SYMLINK_RESULT EQUAL 0)# Not a symlink or test command failed (not likely in this context)execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_SOURCE_DIR}/install"COMMAND ${CMAKE_COMMAND} -E create_symlink "../install" "${CMAKE_CURRENT_SOURCE_DIR}/install"WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}OUTPUT_QUIET ERROR_QUIET)endif()