Skip to content

Latest commit

 

History

History
222 lines (170 loc) · 9.45 KB

README_zh.md

File metadata and controls

222 lines (170 loc) · 9.45 KB

argparse-f

现代Fortran的命令行参数解析器,使用了面向对象特性。

示例

program test
    use iso_fortran_env, only: stdout => output_unit
    use argparse
    implicit none
    character(len=10), parameter :: program_name = "qcalc"
    type(argparser) :: args
    args = argparser("A quantum physics calculation program.")
    call args%set_program_name(program_name)
    call args%add_help_option()
    call args%add_sc_option("-v", "--version", "show version info", show_version_info)
    call args%add_option_logical("-o", "--openmp", "use openmp or not") ! logical option has no default
    call args%add_option_logical("-m", "--mpi", "use mpi or not")
    call args%add_option_integer("-t", "--thread", "thread number,\nit is valid only if openmp is set", 1)
    call args%add_option_integer("-p", "--process", "process number,\nit is valid only if mpi is set", 1)
    call args%add_option_string("", "--chemical", "chemical formula", "H2O") ! short name can be empty
    call args%add_named_argument_string("input", "initialize file")
    call args%add_named_argument_string("output", "output file")
    call args%parse()

    if (args%has_option("--openmp")) then
        print '(A,I2,A)', "openmp is used, and we use ", args%get_option_integer("-t"), " threads"
    end if
    if (args%has_option("--mpi")) then
        print '(A,I2,A)', "mpi is used, and we use ", args%get_option_integer("-p"), " processes"
    end if
    print '(A,A)', "the calculated chemical is ", trim(args%get_option_string("--chemical"))
    print '(A,A)', "the input file is ", trim(args%get_argument_string("input"))
    print '(A,A)', "the output file is ", trim(args%get_argument_string("output"))

    ! you can also print the cached `args` into INI file
    ! print '(/,A)', "All of the options and arguments are shown below"
    ! call args%print_as_ini(stdout, .true.)
contains
    subroutine show_version_info
        print "(A)", trim(program_name)//" version 0.1.0"
    end subroutine show_version_info
end program test

将其编译成qclac,使用方式如下

> qclac -?
usage: qcalc [options] [=input] [=output]

A quantum physics calculation program.

options:
  -?, --help               show this help message
  -v, --version            show version info
  -o, --openmp             use openmp or not
  -m, --mpi                use mpi or not
  -t, --thread             (integer [=1]) thread number,
                           it is valid only if openmp is set
  -p, --process            (integer [=1]) process number,
                           it is valid only if mpi is set
  --chemical               (string [=H2O]) chemical formula

named arguments:
  input                    (string) initialize file
  output                   (string) output file
> qclac -om -t 16 input=input.txt output=out.bin
openmp is used, and we use 16 threads
mpi is used, and we use  1 processes
the calculated chemical is H2O
the input file is input.txt
the output file is out.bin

使用

最简单的方法是复制src/argparse-f.f90文件到你的项目中。推荐使用fpm

[dependencies]
argparse-f = { git="https://github.com/0382/argparse-f.git" }

此外,argparse-f也支持Meson构建系统。

解析规则

在我的库里面,命令行参数分为两大类(可选的选项,和必选的参数),每类又分为两种,总共四种命令行参数。

option(选项)

选项,从语义上来说是可选的。它分成两种:一般选项和短路选项。

一般选项

用如下方式添加一般选项:

call args%add_option_integer("-t", "--thread", "thread number", 1)

其中第一个参数是短选项名,是可以为空字符串的,如果非空,则必须是一个'-'后接单个字符;第二个是长选项名,不能为空字符串,必须以"--"开头。第三个是帮助信息,最后一个是该选项的默认值。

当前版本一般选项仅支持五种数据类型:logical, integer, real, real(kind=8), character(len=*) (添加real(8)的方法是add_option_double,添加character(len=*)的方法是add_option_string)。

除了bool型的option,其余的option添加时都要给定默认的值。 对于bool型,不需要默认值,检查到命令行参数有这个选项,就是true否则为false。例如

ls -l

此时-l选项为true。而其他类型选项需要在其后面加上参数,比如

greet --name Alice --age 24

于是--name选项的值为"Alice"--age选项的值为24

短路选项

短路选项(short circuit option)按照如下方式添加

call args%add_sc_option("-v", "--version", "show version info", show_version_info)
contains
subroutine show_version_info
    print "(A)", trim(program_name)//" version 0.1.0"
end subroutine show_version_info

短路选项仅支持bool类型,添加该选项时需要给定一个回调函数,必须是无参数的subroutine。短路选项是最先搜索解析一种命令行参数。比如

git --help
gcc -v

只要命令行参数包含了这类参数,则调用回调函数,并立即(正常)退出程序。

argument(参数)

参数,和选项相反是必须提供的。如果某个参数没有提供,则程序会报错并退出。参数分为位置参数和命名参数两种

当前版本参数仅支持四种数据类型:integer, real, real(kind=8), character(len=*)。不支持logical类型,实际上logical类型用选项是更合适的。

位置参数

按照位置获取的参数,例如

ffplay video.mp4

video.mp4就是一个位置参数。如果使用ffplay程序没有指定这个位置参数,那么程序就发生错误并退出。

按照如下方式添加位置参数

call args%add_argument_string("input", "initialize file")

该函数的第一个哑元表示参数的名字,第二个表示帮助信息。

命名参数

这是为了解决我个人工作中遇到的情况而定义的。它的使用方式例如

greet name=Alice age=24

显然这样使用参数非常繁琐,不应该作为轻量级的命令行程序使用。但是可以放在一个较重的工程中,并且运行的时候是用脚本调用程序而不是直接在命令行使用。这个时候,使用命名参数可以让你的脚本更具可读性。

使用如下方式添加命名参数 Add named argument like this:

call args%add_named_argument_string("input", "initialize file")

解析命令行参数时,先解析命名参数,剩下的自动按照顺序赋值给位置参数。命名参数不必按照设置的顺序指定。

获取结果

选项

使用类似args%get_option_logical(name)的方法获取结果选项的结果,这里的name既可以长名字也可以短名字。对于logical类型的选项,特别提供了args%has_option(name)函数。

参数

使用类似args%get_argument_logical(name)的方法获取结果参数的结果。命名参数和位置参数的名字不允许冲突,所以获取的时候可以不用区分,就没有get_named_argument_xxx版本的函数了。

杂项

冲突

短路选项和一般选项的名字不允许冲突。命名参数和位置参数的名字也不允许冲突。

这是为了实现linux一些基本命令行工具类似的效果。比如

ls -lah

同时指定了-l, -a-h选项。只有logical类型的选项才能够这样指定。

这也是为什么选项的短名字仅允许一个字符。

自定义帮助选项

使用args%add_help_option()可以添加默认的帮助选项,它使用的名字是-?--help。如果你不喜欢这个名字,可以添加自定义的帮助选项

call args%add_sc_option("-h", "--help", "show this help message", print_help)
contains
subroutine print_help
    call args%print_help()
end subroutine

默认使用-?而不是-h是为了给其他的选项留出选择空间。

多行的帮助信息

有的时候我们的帮助信息很长,如果写在一行但是控制台的宽度不够造成换行会很难看。你可以在帮助信息里面加上\n作为换行标识。当然Fortran是没有转义字符的,不过这不重要。这个包会根据\n自动添加换行和空格使得帮助信息更好看。

打印获取的结果

你可以将argparser获取的结果打印为INI文件格式

call args%print_as_ini(stdout, .true.)

这个函数的第二个参数表示是否打印注释,如果为.true.那么会把帮助信息打印为注释。

print_uasgeset_program_name

如果你运行程序不带任何命令行参数同时程序应该需要argument,那么argparser会调用print_usage并退出。print_usage实际上就是print_help的第一行信息,算是一个简短的帮助信息。set_program_name仅仅影响print_usage时显示的程序名字,如果不调用这个函数,那么会使用argv[0]

参考

这个包和我自己写的c++包argparse工作方式是类似的。这两个包都受到了c++包cmdline以及python标准库的argparse模块的启发。