OpenJDK configure文件代码片段conf_option处理逻辑

  |   0 评论   |   842 浏览

shell for循环对于 命令行参数的特殊语法

下面这段代码所在位置: http://hg.openjdk.java.net/jdk8u/jdk8u/file/a323800a7172/common/autoconf/configure

# 位置:
# 代码行数 154 行
for conf_option
do

  # Process (and remove) our own extensions that will not be passed to autoconf
  case $conf_option in
    --openjdk-target=*)
      conf_openjdk_target=`expr "X$conf_option" : '[^=]*=\(.*\)'`
      ;;
    --debug-configure)
      if test "x$conf_debug_configure" != xrecursive; then
        conf_debug_configure=true
        export conf_debug_configure
      fi
      ;;
    *)
      conf_processed_arguments=("${conf_processed_arguments[@]}" "$conf_option")
      ;;
  esac

  # Store all variables overridden on the command line
  case $conf_option in
    [^-]*=*)
      # Add name of variable to CONFIGURE_OVERRIDDEN_VARIABLES list inside !...!.
      conf_env_var=`expr "x$conf_option" : 'x\([^=]*\)='`
      CONFIGURE_OVERRIDDEN_VARIABLES="$CONFIGURE_OVERRIDDEN_VARIABLES!$conf_env_var!"
      ;;
  esac

  # Save the arguments, intelligently quoted for CONFIGURE_COMMAND_LINE.
  case $conf_option in
    *=*)
      conf_option_name=`expr "x$conf_option" : 'x\([^=]*\)='`
      conf_option_name=$(shell_quote "$conf_option_name")
      conf_option_value=`expr "x$conf_option" : 'x[^=]*=\(.*\)'`
      conf_option_value=$(shell_quote "$conf_option_value")
      conf_quoted_arguments=("${conf_quoted_arguments[@]}" "$conf_option_name=$conf_option_value")
      ;;
    *)
      conf_quoted_arguments=("${conf_quoted_arguments[@]}" "$(shell_quote "$conf_option")")
      ;;
  esac

  # Check for certain autoconf options that require extra action
  case $conf_option in
    -build | --build | --buil | --bui | --bu |-build=* | --build=* | --buil=* | --bui=* | --bu=*)
      conf_legacy_crosscompile="$conf_legacy_crosscompile $conf_option" ;;
    -target | --target | --targe | --targ | --tar | --ta | --t | -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
      conf_legacy_crosscompile="$conf_legacy_crosscompile $conf_option" ;;
    -host | --host | --hos | --ho | -host=* | --host=* | --hos=* | --ho=*)
      conf_legacy_crosscompile="$conf_legacy_crosscompile $conf_option" ;;
    -help | --help | --hel | --he | -h)
      conf_print_help=true ;;
  esac
done

刚看到这段代码的时候,有些百思不得其解. 如果是对的, 自己如何测试好像都运行不到这里. 如果不对,这个代码也不至于在 OpenJDK 的源代码中存活了这么久. 从下面的注释来看.

  • 处理(或者移除) 那些我们自己的扩展,但是不能传递给autoConf的参数.
  • 存储那些从命令行覆盖的参数.
  • 检查某些AutoConf选项, 主要是指的那个有额外动作的参数选项.

其实现在从注释来看. 大概可以猜到这些变量是指的从参数传递进来的变量. 但是困于这个奇怪的写法:

for conf_option
do
done;

这个写法是没有完整的 for循环的写法的. 不确定这个写法是否正确. 也做了尝试,直接使用变量来调试这样相同结构的demo .当然是失败告终了. 当时也有些迷惑,就没有接着再尝试参数的场景. 最后在与别人多次讨论后. 在杨易的群里面找到了答案. 实际上这个是对于遍历命令行参数或者是函数传入参数时的一种常见的语法. (真的是太常见了,以至于我这种不常写shell的人没见过这种语法.) 下面是找到了一个参考资料,这个是链接: https://docstore.mik.ua/orelly/unix3/upt/ch35_21.htm

内容如下:

image.png

实际是一个很小的问题.还是怪自己学艺不精. 既然写到这,把上面的那段代码逻辑顺便解释一下吧:

第一 移除参数相关的代码

# Process (and remove) our own extensions that will not be passed to autoconf
  case $conf_option in
    --openjdk-target=*)
      # 对于target参数, 用变量: conf_openjdk_target 存储起来
      conf_openjdk_target=`expr "X$conf_option" : '[^=]*=\(.*\)'`
      ;;
    --debug-configure)
      # 对于 --debug-cofigure参数 , 影响于变量: conf_debug_configure , 并且把它导出到环境变量.
      if test "x$conf_debug_configure" != xrecursive; then
        conf_debug_configure=true
        export conf_debug_configure
      fi
      ;;
    *)
      # 对于以上的两种参数以外的参数, 都是可以传递给 configure可以处理的参数
      # 这些参数直接保存到数组: conf_processed_arguments
      conf_processed_arguments=("${conf_processed_arguments[@]}" "$conf_option")
      ;;
  esac

同样,这里使用到了命令:expr 这个是一个相对不是很常用.大家也比较熟悉的命令. 一般用于表达式求值,这个可能是大家最熟悉的功能. 比如我们看到这个教程给的功能也是这样: https://www.runoob.com/linux/linux-comm-expr.html

1、计算字串长度

> expr length “this is a test”
 14

2、抓取字串

> expr substr “this is a test” 3 5
is is

3、抓取第一个字符数字串出现的位置

> expr index "sarasara"  a
 2

4、整数运算

> expr 14 % 9
 5
 > expr 10 + 10

但是这里实际的使用是一个正则匹配后的字符串提取.下面是一个参考资料:

https://www.cnblogs.com/f-ck-need-u/p/7231832.html

expr命令可以实现数值运算、数值或字符串比较、字符串匹配、字符串提取、字符串长度计算等功能。它还具有几个特殊功能,判断变量或参数是否为整数、是否为空、是否为0等。

因此平时接触到的可能就是数值运算了 . 这里实际使用的是字符串匹配功能.

'STRING : REGEX'
     执行模式匹配。两端参数会转换为字符格式,且第二个参数被视为正则表达式(GNU基本正则),它默认会隐含前缀"^"。随后将第一个参数和正则模式做匹配。
 
     如果匹配成功,且REGEX使用了'\('和'\)',则此表达式返回匹配到的,如果未使用'\('和'\)',则返回匹配的字符数。
 
     如果匹配失败,如果REGEX中使用了'\('和'\)',则此表达式返回空字符串,否则返回为0。
 
     只有第一个'\(...\)'会引用返回的值;其余的'\(...\)'只在正则表达式分组时有意义。
 
     在正则表达式中,'\+','\?'和'\|'分表代表匹配一个或多个,0个或1个以及两端任选其一的意思。

注意下面的示例:

[root@xuexi ~]# expr abcde : 'ab\(.*\)'
cde

[root@xuexi ~]# expr abcde : 'ab\(.\)'
c

[root@xuexi ~]# expr abcde : 'ab.*'  
5

[root@xuexi ~]# expr abcde : 'ab.'   
3

[root@xuexi ~]# expr abcde : '.*cd*'
4

注意,由于REGEX中隐含了"^",所以使得匹配时都是从string首字符开始的。

[root@xuexi ~]# expr abcde : 'cd.*'  
0

因此这是里的:expr "X$conf_option" : '[^=]*=\(.*\)' 实际是非等号开始的字符集的最大长度.(实际就是把 =前面的部分全部匹配到),中间一个等号, 后面的任意字符进行全匹配. 且是加了括号.因此, 这里取到了这个传入参数面的值. (因为是 --开头的参数项是直接以等号结束的有值的方式进行传递的.) 然后把值用变量: conf_openjdk_target 保存起来.

第二 存储从命令行覆盖的变量

代码如下:

# Store all variables overridden on the command line
  case $conf_option in
    [^-]*=*)
      # Add name of variable to CONFIGURE_OVERRIDDEN_VARIABLES list inside !...!.
      conf_env_var=`expr "x$conf_option" : 'x\([^=]*\)='`
      CONFIGURE_OVERRIDDEN_VARIABLES="$CONFIGURE_OVERRIDDEN_VARIABLES!$conf_env_var!"
      ;;
  esac

所有的非 -option或者 --option以外的参数,且是 a=b这一类的参数. (从形式上看,是一个变量的赋值,也就是一个覆盖.)

  • 把这类变量的名称提取出来,存储到:conf_env_var 中 .
  • 然后再把:conf_env_var 串到:CONFIGURE_OVERRIDDEN_VARIABLES 中.

第三 给参数加上逃逸处理

# Save the arguments, intelligently quoted for CONFIGURE_COMMAND_LINE.
  case $conf_option in
    *=*)
      conf_option_name=`expr "x$conf_option" : 'x\([^=]*\)='`		# 取参数名
      conf_option_name=$(shell_quote "$conf_option_name")		# 加引号,进行逃逸处理.
      conf_option_value=`expr "x$conf_option" : 'x[^=]*=\(.*\)'`	# 取参数值
      conf_option_value=$(shell_quote "$conf_option_value")		# 加引号,进行逃逸处理.
      conf_quoted_arguments=("${conf_quoted_arguments[@]}" 		"$conf_option_name=$conf_option_value")
 									# 添加到数组中去
      ;;
    *)
      # 对于不存在等号的参数.直接逃逸处理.并加到数组中去
      conf_quoted_arguments=("${conf_quoted_arguments[@]}" "$(shell_quote "$conf_option")")
      ;;
  esac

第四 检查一些 需要额外action的 autoconf选项

# Check for certain autoconf options that require extra action
  case $conf_option in
    -build | --build | --buil | --bui | --bu |-build=* | --build=* | --buil=* | --bui=* | --bu=*)
      conf_legacy_crosscompile="$conf_legacy_crosscompile $conf_option" ;;
    -target | --target | --targe | --targ | --tar | --ta | --t | -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
      conf_legacy_crosscompile="$conf_legacy_crosscompile $conf_option" ;;
    -host | --host | --hos | --ho | -host=* | --host=* | --hos=* | --ho=*)
      conf_legacy_crosscompile="$conf_legacy_crosscompile $conf_option" ;;
    -help | --help | --hel | --he | -h)
      conf_print_help=true ;;
  esac

以上,就是整篇文章的全部内容.

评论

发表评论


取消