CMake中的if命令用于有条件地执行一组命令,其格式如下:
if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()
根据Condition syntax评估if子句的条件参数(<condition>)。如果结果为true,则执行if块(block)中的命令。否则,以相同方式处理可选的elseif块.最后,如果没有条件为true,则执行可选else块中的命令。
Condition Syntax:以下语法适用于if、elsif和while子句的条件参数。
复合条件(compound condition)按以下优先顺序进行评估:
(1).括号(Parentheses).
(2).一元测试(unary tests),例如EXISTS、COMMAND和DEFINED。
(3).二元测试(binary tests),例如EQUAL,LESS,LESS_EQUAL,GREATER,GREATER_EQUAL,STREQUAL,STRLESS,STRLESS_EQUAL,STRGREATER,STRGREATER_EQUAL, VERSION_EQUAL,VERSION_LESS,VERSION_LESS_EQUAL,VERSION_GREATER,VERSION_GREATER_EQUAL, PATH_EQUAL和MATCHES.
(4).一元逻辑运算符(unary logical operator):NOT
(5).二元逻辑运算符(binary logical operators):AND和OR,从左到右,没有任何短路(without any short-circuit)。
1.Basic Expressions:
(1).if(<constant>):如果常量为1, ON, YES, TRUE, Y或非零数(包括浮点数),则为true。如果常量为0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, 空字符串或以后缀-NOTFOUND结尾,则为false.命名布尔常量不区分大小写。如果参数不是这些特定常量之一,则将其视为变量或字符串,并适用以下两种形式之一。
(2).if(<variable>):如果给定一个定义非false常量的值的变量,则为true。否则为false,包括变量未定义时。注意:宏参数不是变量。环境变量也不能以这种方式测试,例如if(ENV{some_var})将始终评估为false.
(3).if(<string>):带引号的字符串始终评估为false,除非:字符串的值是真正的常量之一,或者Policy CMP0054为设置为NEW,并且字符串的值恰好是受CMP0054行为影响的变量名称。
if(ON)
message("on") # print
endif()
if(OFF)
message("off") # won't print
endif()
if(YES)
message("yes") # print
endif()
if(NO)
message("no") # won't print
endif()
if(true)
message("true") # print
endif()
if(TRUE)
message("TRUE") # print
endif()
if(FALSE)
message("FALSE") # won't print
endif()
set(ENV{CMAKE_PREFIX_PATH} "github/fengbingchun")
if(ENV{CMAKE_PREFIX_PATH})
message("env") # won't print
endif()
if("csdn")
message("csdn") # won't print
endif()
2.Logic Operators:
(1).if(NOT <condition>):如果条件不为ture,,则为true.
(2).if(<cond1> AND <cond2>):如果这两个条件都被单独被认为是true,则为true.
(3).if(<cond1> OR <cond2>):如果任一条件单独被认为是true,则为true.
(4).if((condition) AND (condition OR (condition))):首先评估括号内的条件,然后像其它示例一样评估其它条件。在有嵌套括号的地方,最里面的小括号作为条件的一部分被评估。
set(var "csdn")
if(NOT var2)
message("not var2") # print
endif()
if(var OR var2)
message("var OR var2") # print
endif()
if(var AND var2)
message("var AND var2") # won't print
endif()
3.Existence Checks:
(1).if(COMMAND command-name):如果给定的name是可以调用的命令、宏或函数,则为true.
(2).if(POLICY policy-id):如果给定的name是存在的policy(形式为CMP<NNNN>),则为true.
(3).if(TARGET target-name):如果给定的name是通过调用(在任何目录中)add_executable, add_library, 或add_custom_target命令创建的现有逻辑目标名称(existing logical target name),则为true.
(4).if(TEST test-name):如果给定的name是由add_test命令创建的现有测试名称(existing test name),则为true.
(5).if(DEFINED <name>|CACHE{<name>}|ENV{<name>}):如果定义了给定<name>的变量、缓存变量或环境变量,则为true.变量的值无关紧要。注意:宏参数不是变量。无法直接测试<name>是否为非缓存变量。如果存在缓存或非缓存变量someName,则表达式if(DEFINED someName)将评估为true.相比之下,表达式if(DEFINED CACHE{someName})仅在缓存变量someName存在时才为true。如果你需要知道是否存在非缓存变量,则需要测试两个表达式:if(DEFINED someName AND NOT DEFINED CACHE{someName})
(6).if(<variable|string> IN_LIST <variable>):如果给定元素包含在命名列表变量(named list variable)中,则为true.
function(func)
message("hello func")
endfunction()
if(COMMAND func)
message("func") # print
endif()
if(POLICY CMP0010)
message("policy") # print
endif()
find_package(OpenCV 3.4.2) # -- Found OpenCV: /opt/opencv3.4.2 (found suitable version "3.4.2", minimum required is "3.4.2")
if(TARGET opencv_core)
message("opencv_core") # print
endif()
set(var OFF) # 变量的值无关紧要
if(DEFINED var)
message("defined var") # print
endif()
set(var2 )
if(DEFINED var2)
message("defined var2") # won't print
endif()
4.File Operations:
(1).if(EXISTS path-to-file-or-directory):如果指定的文件或目录存在,则为true。仅针对显式完整路径(Behavior is well-defined only for explicit full paths).解析符号链接,如果符号链接的目标存在,则为true.
(2).if(file1 IS_NEWER_THAN file2):如果file1比file2新,或两个文件中的一个不存在,则为true。仅针对完整路径。如果文件时间戳完全相同,则IS_NEWER_THAN比较返回true,这包括为file1和file2传递相同文件名的情况。
(3).if(IS_DIRECTORY path-to-directory):如果给定name是目录,则为true。仅针对完整路径。
(4).if(IS_SYMLINK file-name):如果给定name是符号链接,则为true.仅针对完整路径。
(5).if(IS_ABSOLUTE path):如果给定路径是绝对路径,则为true。注意以下特殊情况:空路径评估为false。在windows主机上,任何以驱动器号和冒号(例如 C:)、正斜杠或反斜杠开头的路径都将评估为true.这意味着像C:no\base\dir这样的路径将评估为true.在非windows主机上,任何以波浪号(~)开头的路径都为true.
if(EXISTS /home/spring/GitHub/Linux_Code_Test/Samples_CMake/messy_usage)
message("exists messy_usage") # print
endif()
if(EXISTS ../../Samples_Make)
message("exists samples_make") # won't print
endif()
if(/home/spring/GitHub/Linux_Code_Test/Samples_CMake/messy_usage/test_find_package.cmake IS_NEWER_THAN /home/spring/GitHub/Linux_Code_Test/Samples_CMake/messy_usage/test_xxxx.cmake)
message("is newer") # print
endif()
if(IS_DIRECTORY /home/spring/GitHub)
message("is directory")
endif()
if(IS_SYMLINK /usr/bin/gcc) # /usr/bin/gcc -> gcc-11*
message("is symlink") # print
endif()
if(IS_ABSOLUTE ~/.bashrc)
message("is absolute") # print
endif()
5.Comparisons:
(1).if(<variable|string> MATCHES regex):如果给定的字符串或变量的值与给定的正则表达式匹配(matches),则为true.
(2).if(<variable|string> LESS <variable|string>):如果给定的字符串或变量的值是有效数字且小于右侧的数字,则为true.
(3).if(<variable|string> GREATER <variable|string>):如果给定的字符串或变量的值是有效数字且大于右侧的数字,则为true.
(4).if(<variable|string> EQUAL <variable|string>):如果给定的字符串或变量的值是有效数字且等于右侧的数字,则为true.
(5).if(<variable|string> LESS_EQUAL <variable|string>):如果给定的字符串或变量的值是有效数字且小于或等于右侧的数字,则为true.
(6).if(<variable|string> GREATER_EQUAL <variable|string>):如果给定的字符串或变量的值是有效数字且大于或等于右侧的数字,则为true.
(7).if(<variable|string> STRLESS <variable|string>):如果给定的字符串或变量的值按字典顺序(lexicographically)小于右侧的字符串或变量,则为true.
(8).if(<variable|string> STRGREATER <variable|string>):如果给定的字符串或变量的值按字典顺序(lexicographically)大于右侧的字符串或变量,则为true.
(9).if(<variable|string> STREQUAL <variable|string>):如果给定的字符串或变量的值按字典顺序(lexicographically)等于右侧的字符串或变量,则为true.
(10).if(<variable|string> STRLESS_EQUAL <variable|string>):如果给定的字符串或变量的值按字典顺序(lexicographically)小于或等于右侧的字符串或变量,则为true.
(11).if(<variable|string> STRGREATER_EQUAL <variable|string>):如果给定的字符串或变量的值按字典顺序(lexicographically)大于或等于右侧的字符串或变量,则为true.
if("cSdN" MATCHES [A-Za-z])
message("matches") # print
endif()
set(var1 4.1)
set(var2 4.2)
if(var1 LESS var2)
message("less") # print
endif()
if(var2 GREATER var1)
message("greater") # print
endif()
if(var1 EQUAL var1)
message("equal") # print
endif()
set(var3 "abc")
set(var4 "ABC")
if(var4 STRLESS var3)
message("strless") # print
endif()
if(var4 STRLESS_EQUAL var3)
message("strelss equal") # print
endif()
if(var3 STRGREATER var4)
message("strgreater") # print
endif()
6.Version Comparisons:按组件的整数版本号比较(版本格式为major[.minor[.patch[.tweak]]],省略的组件被视为零)。任何非整数版本组件或版本组件的非整数结尾部分都会在该点有效截断字符串。
(1).if(<variable|string> VERSION_LESS <variable|string>):如果给定的字符串或变量的值小于右侧的值,则为true.
(2).if(<variable|string> VERSION_GREATER <variable|string>):如果给定的字符串或变量的值大于右侧的值,则为true.
(3).if(<variable|string> VERSION_EQUAL <variable|string>):如果给定的字符串或变量的值等于右侧的值,则为true.
(4).if(<variable|string> VERSION_LESS_EQUAL <variable|string>):如果给定的字符串或变量的值小于或等于右侧的值,则为true.
(5).if(<variable|string> VERSION_GREATER_EQUAL <variable|string>):如果给定的字符串或变量的值大于或等于右侧的值,则为true.
set(cv_version1 4.2.1)
set(cv_version2 4.2.5)
if(cv_version1 VERSION_LESS cv_version2)
message("version less") # print
endif()
if(cv_version2 VERSION_GREATER cv_version1)
message("versoin greater") # print
endif()
7.Path Comparisons:if(<variable|string> PATH_EQUAL <variable|string>),逐个组件比较两个路径。只有当两条路径的每个组件都匹配时,两条路径比较的结果才为true.多个路径分隔符有效折叠成一个分隔符,但注意反斜杠不会转换为正斜杠。
由于对多个路径分隔符的处理,基于组件的比较优于基于字符串的比较。
执行上述测试代码需要3个文件:build.sh, CMakeLists.txt, test_if.cmake
build.sh内容如下:
#! /bin/bash
# supported input parameters(cmake commands)
params=(function macro cmake_parse_arguments \
find_library find_path find_file find_program find_package \
cmake_policy cmake_minimum_required project include \
string list set foreach message option if while return \
math file)
usage()
{
echo "Error: $0 needs to have an input parameter"
echo "supported input parameters:"
for param in ${params[@]}; do
echo " $0 ${param}"
done
exit -1
}
if [ $# != 1 ]; then
usage
fi
flag=0
for param in ${params[@]}; do
if [ $1 == ${param} ]; then
flag=1
break
fi
done
if [ ${flag} == 0 ]; then
echo "Error: parameter \"$1\" is not supported"
usage
exit -1
fi
if [[ ! -d "build" ]]; then
mkdir build
cd build
else
cd build
fi
echo "==== test $1 ===="
# test_set.cmake: cmake -DTEST_CMAKE_FEATURE=$1 --log-level=verbose ..
# test_option.cmake: cmake -DTEST_CMAKE_FEATURE=$1 -DBUILD_PYTORCH=ON ..
cmake -DTEST_CMAKE_FEATURE=$1 ..
# It can be executed directly on the terminal, no need to execute build.sh, for example: cmake -P test_set.cmake
CMakeLists.txt内容如下:
cmake_minimum_required(VERSION 3.22)
project(cmake_feature_usage)
message("#### current cmake version: ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
include(test_${TEST_CMAKE_FEATURE}.cmake)
message("==== test finish ====")
test_if.cmake:为上面的所有示例代码
可能的执行结果如下图所示: