CMake中macro的使用

      在https://blog.csdn.net/fengbingchun/article/details/127144948 中介绍了CMake中function的使用,这里介绍下macro的使用,它与function有很多的相似性。

      macro的定义格式如下:后面可作为命令供调用

macro(<name> [<arg1> ...])
  <commands>
endmacro()

      其中name是macro的名字,参数为arg1,arg2等。与function一样,macro名称也不区分大小写,但强烈建议使用macro定义中声明的相同名称。通常,macro使用全小写名称。示例代码段如下:

message("1.与function一样,macro名称也不区分大小写,但始终建议使用macro定义中声明的相同名称")
macro(csdn_addr)
    message("csdn addr: https://blog.csdn.net/fengbingchun")
endmacro()

csdn_addr()
CSDN_ADDR()
csdn_ADDR()

      macro参数:与function一样,macro也采用两种类型的参数:
      (1).命名参数或关键字参数(named or keyword arguments):是必须的,如果未提供将触发error。参数名称之间不需要逗号。示例代码段如下:

message("2.命名参数是必须的,如果未提供将触发error.参数名称之间不需要逗号")
macro(addr csdn github)
    message("csdn addr: ${csdn}")
    message("github addr: ${github}")
endmacro()

addr("https://blog.csdn.net/fengbingchun" "https://github.com/fengbingchun")

      (2).可选参数(optional arguments):可以使用一些预定义的变量访问可选参数,示例代码段如下:
      ARGC:参数总数(命名参数+可选参数)。
      ARGV:包含命名参数和可选参数的变量列表
      ARGN:仅包含可选参数的变量列表

message("3.可以使用一些预定义的变量访问可选参数:ARGC, ARGV, ARGN")
macro(name_list name1 name2)
    message("argument count: ${ARGC}")
    message("all arguments: ${ARGV}")
    message("optional arguments: ${ARGN}")
endmacro()

name_list(Jack Kate Jony Tom)
# only named arguments
name_list(Jack Kate)

      除了这三个变量之外,cmake还提供了ARGV0,ARGV1,ARGV2,...,这将具有传入参数的实际值。引用ARGC之外的ARGV#参数将导致未定义的行为。注意:这些在function中起作用,在macro中直接使用无效。在function中,它们是CMake意义上的真变量;在macro中,它们不是,它们是字符串替换,就像C预处理器对macro所做的那样。

message("4.cmake还提供了ARGV0,ARGV1,ARGV2,...,这将具有传入参数的实际值.引用ARGC之外的ARGV#参数将导致未定义的行为.这些在function中起作用,在macro中不作改动无效")
macro(programming_language name1 name2)
    # 在某些情况下,macro在使用特殊变量时会表现出奇怪的行为,注意:此处与function的差异
    if(${ARGV0}) # 好像不起作用
        message("ARGV0: ${ARGV0}")
    else()
        message("ARGV0 not defined")
    endif()

    math(EXPR last_index "${ARGC}-1")
    foreach(index RANGE 0 ${last_index})
        # 在某些情况下,macro在使用特殊变量时会表现出奇怪的行为,注意:此处与function的差异
        message("argument at index ${index}: ${ARGV${index}}")
    endforeach()

    # 通常,使用变量访问命名参数,使用ARGN访问可选参数
    message("name1: ${name1}")
    message("name2: ${name2}")

    # 注意:此处与function的差异
    set(list_var ${ARGN})
    #message("list var: ${list_var}")
    #foreach(arg IN LISTS ${ARGN}) # 好像不起作用
    foreach(arg IN LISTS list_var)
        message("optional name: ${arg}")
    endforeach()
endmacro()

programming_language(C++ Python Go Matlab)

      通常,使用变量访问命名参数,使用ARGN访问可选参数

      使用DEFINED关键字,你可以检查是否定义了给定的变量、缓存变量或环境变量。变量的值无关紧要。在某些情况下,macro在使用特殊变量时会表现出奇怪的行为。

message("5.使用DEFINED关键字,你可以检查是否定义了给定的变量、缓存变量或环境变量.变量的值无关紧要.在function中起作用,在macro中无效")
macro(foo_macro name)
    # 在某些情况下,macro在使用特殊变量时会表现出奇怪的行为,注意:此处与function的差异
    if(DEFINED name)
        message("macro argument name is defined")
    else()
        message("macro argument name is not defined")
    endif()
endmacro()

function(foo_func name)
    if(DEFINED name)
        message("func argument name is defined")
    else()
        message("func argument name is not defined")
    endif()
endfunction()

foo_macro(csdn)
foo_func(csdn)

      变量作用域(variable scope):与function不同,macro不会引入新的作用域在macro中声明的变量(参数除外)将在调用后可用。function在调用时始终引入新作用域(new scope)。对于macro,macro调用将替换为marco主体(macro body),并使用字符串替换(string substitution)替换参数。因此,在某些情况下,function和macro的行为不同。

message("6.与function不同,macro不会引入新的作用域.在macro中声明的变量(参数除外)将在调用后可用")
set(development_language "C++")

macro(set_development_language name)
    message("macro param: ${name}")
    message("macro name: ${development_language}")
    set(new_language "Python")
    set(development_language "Matlab")
    message("macro new language: ${new_language}")
endmacro()

set_development_language("Go")
message("development_language: ${development_language}")
message("new language: ${new_language}")

      return()命令:由于macro不会创建任何新作用域,因此调用return()将退出当前作用域

message("7.由于macro不会创建任何新作用域,因此调用return()将退出当前作用域,这里是退出当前的.cmake文件,注意与在function里的差异:退出当前的function")
macro(early_return)
    message("csdn")
    return()
    message("github") # it will not be printed
endmacro()

early_return() # 退出当前cmake文件
message("will never be executed")

      如果定义了一个已经存在的macro时,将覆盖上一个macro。可以使用"_"加macro name的方式访问上一个macro。如果再次重新定义同一个macro,"_"加macro name版本将调用先前定义的macro。原始macro将永远不可用。如果开发人员在编写macro时不知道该macro已用于某些cmake库macro,则原始macro有可能永远隐藏。

message("8.如果定义了一个已经存在的macro时,将覆盖上一个macro.可以使用\"_\"加macro name的方式访问上一个macro.如果再次重新定义同一个macro,\"_\"加macro name版本将调用先前定义的macro.原始macro将永远不可用.")
macro(csdn_addr)
    message("csdn addr: https://github.com/fengbingchun")
endmacro()

csdn_addr() # csdn addr: https://github.com/fengbingchun
_csdn_addr() # csdn addr: https://blog.csdn.net/fengbingchun

macro(csdn_addr)
    message("csdn addr: https://www.baidu.com/")
endmacro()

csdn_addr() # csdn addr: https://www.baidu.com/
_csdn_addr() # csdn addr: https://github.com/fengbingchun

      也可通过cmake的预定义的命令cmake_parse_arguments来解析macro的参数。

      function和macro的不同
      (1).变量作用域不同:function会引入新的作用域,而macro不会,即,默认,function内新增的变量外部不可见;而macro内新增的变量外部可见。
      (2).cmake提供的变量ARGV0,ARGV1,ARGV2,...,在function中有效,在macro中无效。在某些情况下,macro中的ARGN也不会生效,在macro中,它们是字符串替换,就像C预处理器对macro所做的那样。
      (3).function内调用return()命令是退出当前function;而macro内调用return()是退出当前cmake文件。建议在macro中完全避免使用return()。
      (4).CMAKE_CURRENT_FUNCTION, CMAKE_CURRENT_FUNCTION_LIST_DIR, CMAKE_CURRENT_FUNCTION_LIST_FILE, CMAKE_CURRENT_FUNCTION_LIST_LIN这些变量应用于function中而不是macro中。

      测试代码组织结构如下:

      build.sh内容如下:

#! /bin/bash

# supported input parameters
params=(function macro)

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 ===="
cmake -DTEST_CMAKE_FEATURE=$1 ..

      CMakeLists.txt内容如下:

CMAKE_MINIMUM_REQUIRED(VERSION 3.13)
PROJECT(cmake_feature_usage)

if(TEST_CMAKE_FEATURE STREQUAL "function")
	include(test_function.cmake)
elseif(TEST_CMAKE_FEATURE STREQUAL "macro")
	include(test_macro.cmake)
endif()

message("==== test finish ====")

     test_macro.cmake内容:为上面所示代码段

     执行结果如下图所示:

      GitHubhttps://github.com/fengbingchun/Linux_Code_Test

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值