Giter VIP home page Giter VIP logo

m_cli2's Introduction

M_CLI2.f90 and associated files

M_CLI2

Name

M_CLI2 - parse Unix-like command line arguments from Fortran

Description

M_CLI2(3f) is a Fortran module that will crack the command line when given a prototype string that looks very much like an invocation of the program. Calls are then made for each parameter name to set the variables appropriately in the program.

Example Program

This short program defines a command that can be called using conventional Unix-style syntax for short and long parameters:

   ./show -x 10 -y -20 -p 10,20,30 --title "plot of stuff" -L
   ./show -lL
   ./show  --title="my new title" 
   ./show  -T "my new title" 
   program show
   use M_CLI2, only : set_args, get_args, sget, igets, set_mode
   implicit none
   real                          :: x,y,z
   logical                       :: l, lbig
   integer,allocatable           :: p(:)
   character(len=:),allocatable  :: title
   namelist /args/x,y,z,l,lbig,p,title ! just for printing
      call set_mode('strict')
      !
      ! Define command and default values and parse supplied command line options
      call set_args('-x 1 -y 2.0 -z 3.5e0 -p 11,-22,33 --title:T "my title" -l F -L F')
      !
      ! multiple scalar non-allocatable values can be done in one call if desired
      call get_args('x',x,'y',y,'z',z,'l',l,'L',lbig)
      ! allocatable arrays and allocatable string lengths need called by themselves
      call get_args('title',title)
      call get_args('p',p)

      ! you can alternatively use convenience functions for allocatable arrays and strings.
      ! The functions are particularly useful in expressions and as arguments on
      ! procedure calls
      title=sget('title') ! string 
      p=igets('p') ! integer array
      !
      ! All ready to go, print it as a namelist so everything is labeled
      write(*,args)
   end program show

running with no options shows the defaults

&ARGS
 X=  1.00000000    ,
 Y=  2.00000000    ,
 Z=  3.50000000    ,
 L=F,
 LBIG=F,
 P=11         ,-22        ,33         ,
 TITLE="my title",
 /

An arbitrary number of strings such as filenames may be passed in on the end of commands; you can query whether an option was supplied; and get_args(3f)-related routines can be used for refining options such as requiring lists of a specified size.

These parameters are defined automatically

    --help
    --usage
    --verbose
    --version

You must supply text for the optional "--help" and "--version" keywords, as described under SET_ARGS(3f).

docs

Documentation

manpages

man-pages

  • HTML man-pages index of individual procedures
  • HTML book-form of pages consolidated using JavaScript
  • manpages.zip for installing wherever the man(1) command is available
  • manpages.tgz is an alternative tar(1) format archive

developer documentation

logs

standalone command-line documentation program

The 3.2.0 release of the command-line parser module M_CLI2 has a standalone program available that will display the help text for the procedures as a substitute for the man(1) pages.

If the program is placed in your search path you can enter

fpm-m_cli2 --help
# if an fpm user
fpm m_cli2 --help

for a description of usage. An example to build it on a typical Linux platform would be

# create a scratch directory for the build
mkdir temp
cd temp
# get the documentation program
curl https://raw.githubusercontent.com/urbanjost/index/main/bootstrap/fpm-m_cli2.f90
# compile the program
gfortran fpm-m_cli2.f90 -o fpm-m_cli2
# copy it to somewhere in your path
mv fpm-m_cli2 $HOME/.local/bin/

gmake

Download and Build with Make(1)

Compile the M_CLI2 module and build all the example programs.

   git clone https://github.com/urbanjost/M_CLI2.git
   cd M_CLI2/src
   # change Makefile if not using one of the listed compilers

   # for gfortran
   make clean
   make gfortran

   # for ifort
   make clean
   make ifort

   # for nvfortran
   make clean
   make nvfortran

   # display other options (test, run, doxygen, ford, ...)
   make help

To install you then generally copy the *.mod file and *.a file to an appropriate directory. Unfortunately, the specifics vary but in general if you have a directory $HOME/.local/lib and copy those files there then you can generally enter something like

     gfortran -L$HOME/.local/lib -lM_CLI2  myprogram.f90 -o myprogram

There are different methods for adding the directory to your default load path, but frequently you can append the directory you have placed the files in into the colon-separated list of directories in the $LD_LIBRARY_PATH or $LIBRARY_PATH environment variable, and then the -L option will not be required (or it's equivalent in your programming environment).

       export LD_LIBRARY_PATH=$HOME/.local/lib:$LD_LIBRARY_PATH

NOTE: If you use multiple Fortran compilers you may need to create a different directory for each compiler. I would recommend it, such as $HOME/.local/lib/gfortran/.

Creating a shared library

If you desire a shared library as well, for gfortran you may enter

     make clean gfortran gfortran_install

and everything needed by gfortran will be placed in libgfortran/ that you may add to an appropriate area, such as $HOME/.local/lib/gfortran/.

     make clean ifort ifort_install # same for ifort

does the same for the ifort compiler and places the output in libifort/.

Specifics may vary

NOTE: The build instructions above are specific to a ULS (Unix-Like System) and may differ, especially for those wishing to generate shared libraries (which varies significantly depending on the programming environment). For some builds it is simpler to make a Makefile for each compiler, which might be required for a more comprehensive build unless you are very familiar with gmake(1).

If you always use one compiler it is relatively simple, otherwise make sure you know what your system requires and change the Makefile as appropriate.

parse

Build with FPM

Alternatively, fpm(1) users may download the github repository and build it with fpm ( as described at Fortran Package Manager )

        git clone https://github.com/urbanjost/M_CLI2.git
        cd M_CLI2
        fpm test   # build and test the module
        fpm install # install the module (in the default location)

or just list it as a dependency in your fpm.toml project file.

        [dependencies]
        M_CLI2        = { git = "https://github.com/urbanjost/M_CLI2.git" }

Supports Meson

Alternatively, meson(1) users may download the github repository and build it with meson ( as described at Meson Build System )

        git clone https://github.com/urbanjost/M_CLI2.git
        cd M_CLI2
        meson setup _build
        meson test -C _build  # build and test the module

        # install the module (in the <DIR> location)
        # --destdir is only on newer versions of meson
        meson install -C _build --destdir <DIR>
        # older method if --destdir is not available
        env DESTDIR=<DIR> meson install -C _build

or just list it as a subproject dependency in your meson.build project file.

        M_CLI2_dep = subproject('M_CLI2').get_variable('M_CLI2_dep')

Functional Specification

This is how the interface works --

  • Pass in a string to set_args(3f) that looks almost like the command you would use to execute the program except with all keywords and default values specified.

  • you add calls to the get_args(3f) procedure or one of its variants. The alternative convenience procedures (rget(3f),sget(3f),iget(3f) ...) allow you to use a simple function-based interface model. There are special routines for when you want to use fixed length. CHARACTER variables or fixed-size arrays instead of the allocatable variables best used with get_args(3f)).

    Now when you call the program all the values in the prototype should be updated using values from the command line and queried and ready to use in your program.

demos

Demo Programs

These demo programs provide templates for the most common usage:

  • demo3 Example of basic use
  • demo1 Using the convenience functions
  • demo9 Long and short names using --LONGNAME:SHORTNAME.
  • demo2 Putting everything including help and version information into a contained procedure.
  • demo17 Using unnamed options as filenames or strings
  • demo16 Using unnamed values as numbers

Optional Modes

  • demo15 Allowing bundling short Boolean keys using "strict" mode
  • demo14 Case-insensitive long keys
  • demo12 Enabling response files
  • demo13 Equivalencing dash to underscore in keynames

Niche examples

  • demo8 Parsing multiple keywords in a single call to get_args(3f)
  • demo4 COMPLEX type values
  • demo7 Controlling array delimiter characters
  • demo6 How to create a command with subcommands
  • demo5 extended description of using CHARACTER type values

Response files

Response files are supported as described in the documentation for set_args. They are a system-independent way to create short abbreviations for long complex commands. This option is generally not needed by programs with just a few options, but can be particularly useful for programs with dozens of options where various values are frequently reused.

Commit Tests

commit 598e44164eee383b8a0775aa75b7d1bb100481c3 was tested on 2020-11-22 with

  • GNU Fortran (GCC) 8.3.1 20191121 (Red Hat 8.3.1-5)
  • ifort (IFORT) 19.1.3.304 20200925
  • nvfortran 20.7-0 LLVM 64-bit target on x86-64 Linux

commit 8fe841d8c0c1867f88847e24009a76a98484b31a was tested on 2021-09-29 with

  • GNU Fortran (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0
  • ifort (IFORT) 2021.3.0 20210609
  • nvfortran 21.5-0 LLVM 64-bit target on x86-64 Linux -tp nehalem

commit 732bcadf95e753ccdf025cec2c08d776ea2534c2 was tested on 2023-02-10 with

  • ifort (IFORT) 2021.8.0 20221119
  • GNU Fortran (Ubuntu 11.1.0-1ubuntu1~20.04) 11.1.0

Last update: Saturday, February 4th, 2023 1:12:54 AM UTC-05:00

m_cli2's People

Contributors

awvwgk avatar lkedward avatar urbanjost avatar zoziha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

lkedward zoziha

m_cli2's Issues

Fails to build with GFortran 5.3.0

Kind of a very special niche problem, since conda-forge's GCC toolchain for Windows is stuck at 5.3.0.

Compilation of fpm fails for M_CLI2:

f951.exe: Warning: -fPIC ignored for target (all code is position independent)
build\dependencies\M_CLI2\src\M_CLI2.f90:2973:29:

       xarray((i+1)/2)=cmplx( darray(i),darray(i+1) )
                             1
Warning: Conversion from REAL(8) to default-kind COMPLEX(4) at (1) might lose precision, consider using the KIND argument [-Wconversion]
build\dependencies\M_CLI2\src\M_CLI2.f90:3330:24:

 subroutine journal(where, g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, sep)
                        1
Warning: Unused dummy argument 'where' at (1) [-Wunused-dummy-argument]
build\dependencies\M_CLI2\src\M_CLI2.f90:2020:0:

 function separator2() result(sep)
 ^
Warning: 'separator2' defined but not used [-Wunused-function]
build\dependencies\M_CLI2\src\M_CLI2.f90:1087:0:

 subroutine set_usage(keyword,description,value)
 ^
Warning: 'set_usage' defined but not used [-Wunused-function]
build\dependencies\M_CLI2\src\M_CLI2.f90:6035:0:

    sg=unnamed
 ^
internal compiler error: in gimplify_var_or_parm_decl, at gimplify.c:1801
libbacktrace could not find executable to open
Please submit a full bug report,
with preprocessed source if appropriate.
See <https://sourceforge.net/projects/msys2> for instructions.

This has very low priority.

meson.build doesn't install m_cli2.mod file

The meson.build succsesfully build m_cli2 library and install it with appropriate symlinks but there is no rule to install m_cli2.mod file that is required as header to use the dynamic library.

weird behaviour on x86 (OpenBSD)

On OpenBSD x86 architecture, I have a weird behaviour when using M_CLI2.

I first noticed it while build fpm on x86, and next reduced the example code to the following:

program show
  use M_CLI2, only : set_args, lget, rget, sget, igets
  implicit none
  call set_args('-l F')
  print *, "lget", lget('l')
end program show

Please note, that there is no problem with real and rget (I don't specialy tested others types).

On x86_64, the program seems to work well:

$ ./test                                                                
 lget F
$ ./test -l
 lget T
$ ./test -l xxx
 lget T
$ ./test -h                                                                  
./test --version F
 --usage F
 --help F
 --version F -l F

On x86, I have the following behaviour:

$ ./test      
 lget*get_anyarray_l* expected one value found 3
$ ./test -l
 lget T
$ ./test -l xxx
 lget*get_anyarray_l* bad logical expression for l=XXX
 F
$ ./test -h  
 lget T

I tested with both gfortan 8.4.0 and gfortran 11.2.0 (both available on OpenBSD) with the same result.

Adding an option to pass a flag

I just tried adding --flag to fpm and found that M_CLI2 won't let me do:

fpm run -- build --flag "-O2"

As it will result in an unknown short keyword error:

UNKNOWN COMPOUND SHORT KEYWORD:O in -O3
KEYWORD    SHORT PRESENT VALUE
version       v  F        [F]
verbose          F        [F]
usage         u  F        [F]
show-model       F        [F]
release          F        [F]
list             F        [F]
help          h  F        [F]
flag             T        [" "]
compiler         F        ["gfortran"]

UNNAMED
000001[build ]

Any pointers on how we can elegantly implement this?

Response file

I'm not entirely sure where this exactly originates and where to find a good documentation on this, but some compilers and build tools support a “response file.” Usually the syntax is

prog @file1.rsp @file2.rsp

where file1.rsp, file2.rsp, ... contain the command line arguments separated by newlines and can be combined with normal command lines arguments. Some implementations allow further references to other response files in the response file. I did find some documentation for MSBuild.exe on rsp-files and some notes at the ninja build manpage.

This might be an interesting feature for this library since it would allow to store (maybe even load and/or dump) command lines as a file, which makes it useful for testing or storing frequently needed (complicated) command lines.

Fails to compile with NAG

Changed gfortran in src/Makefile to nagfor and used make -C src, build fails with:

Extension: M_CLI2.f90, line 1152: Line longer than 132 characters
Extension: M_CLI2.f90, line 1703: Line longer than 132 characters
Warning: M_CLI2.f90, line 2354: Unused dummy variable WHERE
Questionable: M_CLI2.f90, line 3288: Variable IFOK set but never referenced
Warning: M_CLI2.f90, line 5102: INT16 explicitly imported into GET_GENERIC but not used
Warning: M_CLI2.f90, line 5102: INT32 explicitly imported into GET_GENERIC but not used
Warning: M_CLI2.f90, line 5102: INT64 explicitly imported into GET_GENERIC but not used
Warning: M_CLI2.f90, line 5102: INT8 explicitly imported into GET_GENERIC but not used
Warning: M_CLI2.f90, line 5102: REAL128 explicitly imported into GET_GENERIC but not used
Warning: M_CLI2.f90, line 5102: REAL32 explicitly imported into GET_GENERIC but not used
Warning: M_CLI2.f90, line 5258: INPUT_UNIT explicitly imported into M_CLI2 (as STDIN) but not used
Questionable: M_CLI2.f90, line 809: Last statement of DO loop body is an unconditional EXIT statement
Questionable: M_CLI2.f90, line 1301: Last statement of DO loop body is an unconditional CYCLE statement
Error: M_CLI2.f90, line 2494: Missing field width for L edit descriptor
Error: M_CLI2.f90, line 2557: Missing field width for L edit descriptor
[NAG Fortran Compiler error termination, 2 errors, 13 warnings]

Error occurs for:

type is (logical); write(line(istart:),'(1l)') generic

type is (logical); write(line(istart:),'("[",*(1l,1x))') generic

Fails to compile with PGI

Tried to compile this project with the PGI compilers. This didn't work, in case it is helpful I will share my workflow for the setup and test to reproduce the compiler errors.

NVHPC 20.7:

  1. Install with
wget https://developer.download.nvidia.com/hpc-sdk/nvhpc_2020_207_Linux_x86_64_cuda_11.0.tar.gz
tar xpzf nvhpc_2020_207_Linux_x86_64_cuda_11.0.tar.gz
NVHPC_SILENT=true NVHPC_INSTALL_DIR=/opt/nvidia/hpc_sdk NVHPC_INSTALL_TYPE=single sudo nvhpc_2020_207_Linux_x86_64_cuda_11.0/install
  1. Load the PGI compilers with
module use /opt/nvidia/hpc_sdk/modulefiles
module load nvhpc
  1. Adjust compiler from gfortran to nvfortran
  2. make -C src
NVFORTRAN-S-0000-Internal compiler error. size_of: attempt to get size of assumed size character       0  (M_CLI2.f90: 2012)
  0 inform,   0 warnings,   1 severes, 0 fatal for get_anyarray_cc
NVFORTRAN-S-0000-Internal compiler error. size_of: attempt to get size of assumed size character       0  (M_CLI2.f90: 2043)
NVFORTRAN-S-0000-Internal compiler error. size_of: attempt to get size of assumed size character       0  (M_CLI2.f90: 2043)
  0 inform,   0 warnings,   2 severes, 0 fatal for get_args_fixed_length_a_array
NVFORTRAN-S-0081-Illegal selector - KIND value must be non-negative  (M_CLI2.f90: 2493)
NVFORTRAN-S-0155-Duplicate TYPE IS real (M_CLI2.f90: 2493)
  0 inform,   0 warnings,   2 severes, 0 fatal for print_generic
NVFORTRAN-S-0081-Illegal selector - KIND value must be non-negative  (M_CLI2.f90: 2555)
NVFORTRAN-S-0155-Duplicate TYPE IS real (M_CLI2.f90: 2555)
  0 inform,   0 warnings,   2 severes, 0 fatal for print_generic

NVHPC 20.9:

  1. Install with
wget https://developer.download.nvidia.com/hpc-sdk/20.9/nvhpc_2020_209_Linux_x86_64_cuda_11.0.tar.gz
tar xpzf nvhpc_2020_209_Linux_x86_64_cuda_11.0.tar.gz
NVHPC_SILENT=true NVHPC_INSTALL_DIR=/opt/nvidia/hpc_sdk NVHPC_INSTALL_TYPE=single sudo nvhpc_2020_209_Linux_x86_64_cuda_11.0/install
  1. Load the PGI compilers with
module use /opt/nvidia/hpc_sdk/modulefiles
module load nvhpc
  1. Adjust compiler from gfortran to nvfortran
  2. make -C src
NVFORTRAN-S-0155-ALLOCATE Type-Specification is incompatible with type of object  strings (M_CLI2.f90: 1836)
NVFORTRAN-S-0155-ALLOCATE Type-Specification is incompatible with type of object  strings (M_CLI2.f90: 1841)
  0 inform,   0 warnings,   2 severes, 0 fatal for get_fixed_length_any_size_cxxxx
NVFORTRAN-S-0081-Illegal selector - KIND value must be non-negative  (M_CLI2.f90: 2293)
NVFORTRAN-S-0155-Duplicate TYPE IS real (M_CLI2.f90: 2293)
  0 inform,   0 warnings,   2 severes, 0 fatal for print_generic
NVFORTRAN-S-0081-Illegal selector - KIND value must be non-negative  (M_CLI2.f90: 2355)
NVFORTRAN-S-0155-Duplicate TYPE IS real (M_CLI2.f90: 2355)
  0 inform,   0 warnings,   2 severes, 0 fatal for print_generic

Add meson support

Description

Meson has released version 1.0.0 and is mature.
M_CLI2 currently supports fpm, adding Meson build support would be a good option as well, just like fpm and CMake, Meson is also effective at establishing source file dependencies.


Thanks, M_CLI2 works great. I added Meson support for M_CLI2 under this branch.
If this sounds good to you @urbanjost , I'll add a PR for that.

can M_CLI2 generate completion files automatically?

#bash-shell completion scripts (using complete(1) and compgen(1)) would be very nice, and bash is almost ubiquitous except for some MSWindows environments.

So it a special switch were built in like --CLI_bash_completion you could call the program and it would write out a basic completion script that you could source or write to a file to expand upon or put in standard system location.

Response file not working from powershell terminal

I was experimenting response file for fpm and running command like fpm @build from a powershell terminal on Windows.
The issue is that @ has a special meaning in powershell and the command cannot be interpreted. It only returns the help for fpm

Fortran Package Manager:
 
USAGE: fpm [ SUBCOMMAND [SUBCOMMAND_OPTIONS] ]|[--list|--help|--version]
       where SUBCOMMAND is commonly new|build|run|test

 subcommand may be one of

  build     Compile the package placing results in the "build" directory
  help      Display help
  list      Display this list of subcommand descriptions
  new       Create a new Fortran package directory with sample files    
  run       Run the local package application programs
  test      Run the test programs
  update    Update and manage project dependencies
...

Workaround

sections in the rsp containing hyphens are perfectly fine, so I can run fpm @gfortran-build.
Or, I can also use the classical cmd prompt.

There is probably not much to do here, but I thought I report the issue for the record in case someone faces the same problem.

Remove `allocatable` attributes of `help_text`, `version_text` arguments in `set_args` subroutine?

First of all, thank you @urbanjost for writing this library, it's very cool.

In the process of using the M_CLI2 library, I found that the allocatable attributes of help_text and version_text do not seem to be so necessary.

Removing the allocatable attributes makes the set_args interface more lenient, allowing the user to enter an array of constant strings (character(*), parameter :: help_text(*) = [...]).
I made such a modification (a commit), and it looks like there are no apparent issues.

program main

    use M_CLI2
    character(*), parameter :: help_text(*) = [character(10) :: "help1", "help2"]
    character(:), allocatable :: version_text(:)

    version_text = [character(10) :: "version1", "version2"]
    call set_args("", help_text, version_text)

end program main

Before:

>> fpm run -- --help
M_CLI2.F90                             done.
libdemo.a                              done.
main.f90                               failed.
[  75%]Compiling...
app\main.f90:8:22:

    8 |     call set_args("", help_text, version_text)
      |                      1
Error: Actual argument at (1) to allocatable or pointer dummy argument 'help_text' must have a deferred length type parameter if 
and only if the dummy has one
<ERROR> Compilation failed for object " app_main.f90.o "
<ERROR>stopping due to failed compilation
STOP 1

After:

>> fpm run -- --help
M_CLI2.F90                             done.
libdemo.a                              done.
main.f90                               done.
demo.exe                               done.
[100%] Project compiled successfully.
help1
help2

Bundled short options

From the docs it is unclear if short options may be bundled, e.g. -a -b specified as -ab.

Makefile: no rule to build m_cli2 shared library

The current Makefile doesn't provide rule to build m_cli2 shared library that results in impossibility to use M_CLI2 as unbundled package or module (system installed) due to undefined reference errors.

Using gfortran I had to build it manually initially passed into F90FLAGS of Makefile the option -fPIC to build proper object file M_CLI2.o that than could be linked to shared (passing it's SONAME too) library by

gfortran -Wl,-soname,libm_cli2.so.1 -shared -o libm_cli2.so.1 M_CLI2.o

and then creating symlink libm_cli2.so pointed to libm_cli2.so.1.

Please add additional Makefile rules to build shared library for appropriate compilers.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.