aboutsummaryrefslogtreecommitdiff
path: root/src/fpm_command_line.f90
diff options
context:
space:
mode:
Diffstat (limited to 'src/fpm_command_line.f90')
-rw-r--r--src/fpm_command_line.f901140
1 files changed, 1140 insertions, 0 deletions
diff --git a/src/fpm_command_line.f90 b/src/fpm_command_line.f90
new file mode 100644
index 0000000..9e9a572
--- /dev/null
+++ b/src/fpm_command_line.f90
@@ -0,0 +1,1140 @@
+!># Definition of the command line interface
+!>
+!> This module uses [M_CLI2](https://github.com/urbanjost/M_CLI2) to define
+!> the command line interface.
+!> To define a command line interface create a new command settings type
+!> from the [[fpm_cmd_settings]] base class or the respective parent command
+!> settings.
+!>
+!> The subcommand is selected by the first non-option argument in the command
+!> line. In the subcase block the actual command line is defined and transferred
+!> to an instance of the [[fpm_cmd_settings]], the actual type is used by the
+!> *fpm* main program to determine which command entry point is chosen.
+!>
+!> To add a new subcommand add a new case to select construct and specify the
+!> wanted command line and the expected default values.
+!> Some of the following points also apply if you add a new option or argument
+!> to an existing *fpm* subcommand.
+!> At this point you should create a help page for the new command in a simple
+!> catman-like format as well in the ``set_help`` procedure.
+!> Make sure to register new subcommands in the ``fpm-manual`` command by adding
+!> them to the manual character array and in the help/manual case as well.
+!> You should add the new command to the synopsis section of the ``fpm-list``,
+!> ``fpm-help`` and ``fpm --list`` help pages below to make sure the help output
+!> is complete and consistent as well.
+module fpm_command_line
+use fpm_environment, only : get_os_type, get_env, &
+ OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, &
+ OS_CYGWIN, OS_SOLARIS, OS_FREEBSD
+use M_CLI2, only : set_args, lget, sget, unnamed, remaining, specified
+use fpm_strings, only : lower, split, fnv_1a
+use fpm_filesystem, only : basename, canon_path, to_fortran_name
+use fpm_compiler, only : get_default_compile_flags
+use,intrinsic :: iso_fortran_env, only : stdin=>input_unit, &
+ & stdout=>output_unit, &
+ & stderr=>error_unit
+implicit none
+
+private
+public :: fpm_cmd_settings, &
+ fpm_build_settings, &
+ fpm_install_settings, &
+ fpm_new_settings, &
+ fpm_run_settings, &
+ fpm_test_settings, &
+ fpm_update_settings, &
+ get_command_line_settings
+
+type, abstract :: fpm_cmd_settings
+ logical :: verbose=.true.
+end type
+
+integer,parameter :: ibug=4096
+type, extends(fpm_cmd_settings) :: fpm_new_settings
+ character(len=:),allocatable :: name
+ logical :: with_executable=.false.
+ logical :: with_test=.false.
+ logical :: with_lib=.true.
+ logical :: with_example=.false.
+ logical :: with_full=.false.
+ logical :: with_bare=.false.
+ logical :: backfill=.true.
+end type
+
+type, extends(fpm_cmd_settings) :: fpm_build_settings
+ logical :: list=.false.
+ logical :: show_model=.false.
+ character(len=:),allocatable :: compiler
+ character(len=:),allocatable :: profile
+ character(len=:),allocatable :: build_name
+ character(len=:),allocatable :: flag
+end type
+
+type, extends(fpm_build_settings) :: fpm_run_settings
+ character(len=ibug),allocatable :: name(:)
+ character(len=:),allocatable :: args
+ character(len=:),allocatable :: runner
+ logical :: example
+end type
+
+type, extends(fpm_run_settings) :: fpm_test_settings
+end type
+
+type, extends(fpm_build_settings) :: fpm_install_settings
+ character(len=:), allocatable :: prefix
+ character(len=:), allocatable :: bindir
+ character(len=:), allocatable :: libdir
+ character(len=:), allocatable :: includedir
+ logical :: no_rebuild
+end type
+
+!> Settings for interacting and updating with project dependencies
+type, extends(fpm_cmd_settings) :: fpm_update_settings
+ character(len=ibug),allocatable :: name(:)
+ logical :: fetch_only
+ logical :: clean
+end type
+
+character(len=:),allocatable :: name
+character(len=:),allocatable :: os_type
+character(len=ibug),allocatable :: names(:)
+character(len=:),allocatable :: tnames(:)
+
+character(len=:), allocatable :: version_text(:)
+character(len=:), allocatable :: help_new(:), help_fpm(:), help_run(:), &
+ & help_test(:), help_build(:), help_usage(:), help_runner(:), &
+ & help_text(:), help_install(:), help_help(:), help_update(:), &
+ & help_list(:), help_list_dash(:), help_list_nodash(:)
+character(len=20),parameter :: manual(*)=[ character(len=20) ::&
+& ' ', 'fpm', 'new', 'build', 'run', &
+& 'test', 'runner', 'install', 'update', 'list', 'help', 'version' ]
+
+character(len=:), allocatable :: val_runner, val_build, val_compiler, val_flag, val_profile
+
+contains
+ subroutine get_command_line_settings(cmd_settings)
+ class(fpm_cmd_settings), allocatable, intent(out) :: cmd_settings
+
+ character(len=4096) :: cmdarg
+ integer :: i
+ integer :: widest
+ type(fpm_install_settings), allocatable :: install_settings
+
+ call set_help()
+ ! text for --version switch,
+ select case (get_os_type())
+ case (OS_LINUX); os_type = "OS Type: Linux"
+ case (OS_MACOS); os_type = "OS Type: macOS"
+ case (OS_WINDOWS); os_type = "OS Type: Windows"
+ case (OS_CYGWIN); os_type = "OS Type: Cygwin"
+ case (OS_SOLARIS); os_type = "OS Type: Solaris"
+ case (OS_FREEBSD); os_type = "OS Type: FreeBSD"
+ case (OS_UNKNOWN); os_type = "OS Type: Unknown"
+ case default ; os_type = "OS Type: UNKNOWN"
+ end select
+ version_text = [character(len=80) :: &
+ & 'Version: 0.2.0, alpha', &
+ & 'Program: fpm(1)', &
+ & 'Description: A Fortran package manager and build system', &
+ & 'Home Page: https://github.com/fortran-lang/fpm', &
+ & 'License: MIT', &
+ & os_type]
+ ! find the subcommand name by looking for first word on command
+ ! not starting with dash
+ cmdarg=' '
+ do i = 1, command_argument_count()
+ call get_command_argument(i, cmdarg)
+ if(adjustl(cmdarg(1:1)) .ne. '-')exit
+ enddo
+
+ ! now set subcommand-specific help text and process commandline
+ ! arguments. Then call subcommand routine
+ select case(trim(cmdarg))
+
+ case('run')
+ call set_args('&
+ & --target " " &
+ & --list F &
+ & --all F &
+ & --profile " "&
+ & --example F&
+ & --runner " " &
+ & --compiler "'//get_env('FPM_COMPILER','gfortran')//'" &
+ & --flag:: " "&
+ & --verbose F&
+ & --',help_run,version_text)
+
+ call check_build_vals()
+
+ if( size(unnamed) .gt. 1 )then
+ names=unnamed(2:)
+ else
+ names=[character(len=len(names)) :: ]
+ endif
+
+
+ if(specified('target') )then
+ call split(sget('target'),tnames,delimiters=' ,:')
+ names=[character(len=max(len(names),len(tnames))) :: names,tnames]
+ endif
+
+ ! convert --all to '*'
+ if(lget('all'))then
+ names=[character(len=max(len(names),1)) :: names,'*' ]
+ endif
+
+ ! convert special string '..' to equivalent (shorter) '*'
+ ! to allow for a string that does not require shift-key and quoting
+ do i=1,size(names)
+ if(names(i).eq.'..')names(i)='*'
+ enddo
+
+ allocate(fpm_run_settings :: cmd_settings)
+ val_runner=sget('runner')
+ if(specified('runner') .and. val_runner.eq.'')val_runner='echo'
+ cmd_settings=fpm_run_settings(&
+ & args=remaining,&
+ & build_name=val_build,&
+ & profile=val_profile,&
+ & compiler=val_compiler, &
+ & flag=val_flag, &
+ & example=lget('example'), &
+ & list=lget('list'),&
+ & name=names,&
+ & runner=val_runner,&
+ & verbose=lget('verbose') )
+
+ case('build')
+ call set_args( '&
+ & --profile " " &
+ & --list F &
+ & --show-model F &
+ & --compiler "'//get_env('FPM_COMPILER','gfortran')//'" &
+ & --flag:: " "&
+ & --verbose F&
+ & --',help_build,version_text)
+
+ call check_build_vals()
+
+ allocate( fpm_build_settings :: cmd_settings )
+ cmd_settings=fpm_build_settings( &
+ & build_name=val_build,&
+ & profile=val_profile,&
+ & compiler=val_compiler, &
+ & flag=val_flag, &
+ & list=lget('list'),&
+ & show_model=lget('show-model'),&
+ & verbose=lget('verbose') )
+
+ case('new')
+ call set_args('&
+ & --src F &
+ & --lib F &
+ & --app F &
+ & --test F &
+ & --example F &
+ & --backfill F &
+ & --full F &
+ & --bare F &
+ & --verbose:V F',&
+ & help_new, version_text)
+ select case(size(unnamed))
+ case(1)
+ write(stderr,'(*(g0,/))')'<ERROR> directory name required'
+ write(stderr,'(*(7x,g0,/))') &
+ & '<USAGE> fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|[--full|--bare] [--backfill]'
+ stop 1
+ case(2)
+ name=trim(unnamed(2))
+ case default
+ write(stderr,'(g0)')'<ERROR> only one directory name allowed'
+ write(stderr,'(7x,g0)') &
+ & '<USAGE> fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| [--full|--bare] [--backfill]'
+ stop 2
+ end select
+ !*! canon_path is not converting ".", etc.
+ name=canon_path(name)
+ if( .not.is_fortran_name(to_fortran_name(basename(name))) )then
+ write(stderr,'(g0)') [ character(len=72) :: &
+ & '<ERROR> the fpm project name must be made of up to 63 ASCII letters,', &
+ & ' numbers, underscores, or hyphens, and start with a letter.']
+ stop 4
+ endif
+
+ allocate(fpm_new_settings :: cmd_settings)
+ if (any( specified([character(len=10) :: 'src','lib','app','test','example','bare'])) &
+ & .and.lget('full') )then
+ write(stderr,'(*(a))')&
+ &'<ERROR> --full and any of [--src|--lib,--app,--test,--example,--bare]', &
+ &' are mutually exclusive.'
+ stop 5
+ elseif (any( specified([character(len=10) :: 'src','lib','app','test','example','full'])) &
+ & .and.lget('bare') )then
+ write(stderr,'(*(a))')&
+ &'<ERROR> --bare and any of [--src|--lib,--app,--test,--example,--full]', &
+ &' are mutually exclusive.'
+ stop 3
+ elseif (any( specified([character(len=10) :: 'src','lib','app','test','example']) ) )then
+ cmd_settings=fpm_new_settings(&
+ & backfill=lget('backfill'), &
+ & name=name, &
+ & with_executable=lget('app'), &
+ & with_lib=any([lget('lib'),lget('src')]), &
+ & with_test=lget('test'), &
+ & with_example=lget('example'), &
+ & verbose=lget('verbose') )
+ else ! default if no specific directories are requested
+ cmd_settings=fpm_new_settings(&
+ & backfill=lget('backfill') , &
+ & name=name, &
+ & with_executable=.true., &
+ & with_lib=.true., &
+ & with_test=.true., &
+ & with_example=lget('full'), &
+ & with_full=lget('full'), &
+ & with_bare=lget('bare'), &
+ & verbose=lget('verbose') )
+ endif
+
+ case('help','manual')
+ call set_args('&
+ & --verbose F &
+ & ',help_help,version_text)
+ if(size(unnamed).lt.2)then
+ if(unnamed(1).eq.'help')then
+ unnamed=[' ', 'fpm']
+ else
+ unnamed=manual
+ endif
+ elseif(unnamed(2).eq.'manual')then
+ unnamed=manual
+ endif
+ widest=256
+ allocate(character(len=widest) :: help_text(0))
+ do i=2,size(unnamed)
+ select case(unnamed(i))
+ case(' ' )
+ case('fpm ' )
+ help_text=[character(len=widest) :: help_text, help_fpm]
+ case('new ' )
+ help_text=[character(len=widest) :: help_text, help_new]
+ case('build ' )
+ help_text=[character(len=widest) :: help_text, help_build]
+ case('install' )
+ help_text=[character(len=widest) :: help_text, help_install]
+ case('run ' )
+ help_text=[character(len=widest) :: help_text, help_run]
+ case('test ' )
+ help_text=[character(len=widest) :: help_text, help_test]
+ case('runner' )
+ help_text=[character(len=widest) :: help_text, help_runner]
+ case('list ' )
+ help_text=[character(len=widest) :: help_text, help_list]
+ case('update ' )
+ help_text=[character(len=widest) :: help_text, help_update]
+ case('help ' )
+ help_text=[character(len=widest) :: help_text, help_help]
+ case('version' )
+ help_text=[character(len=widest) :: help_text, version_text]
+ case default
+ help_text=[character(len=widest) :: help_text, &
+ & '<ERROR> unknown help topic "'//trim(unnamed(i))//'"']
+ !!& '<ERROR> unknown help topic "'//trim(unnamed(i)).'not found in:',manual]
+ end select
+ enddo
+ call printhelp(help_text)
+
+ case('install')
+ call set_args('--profile " " --no-rebuild F --verbose F --prefix " " &
+ & --list F &
+ & --compiler "'//get_env('FPM_COMPILER','gfortran')//'" &
+ & --flag:: " "&
+ & --libdir "lib" --bindir "bin" --includedir "include"', &
+ help_install, version_text)
+
+ call check_build_vals()
+
+ allocate(install_settings)
+ install_settings = fpm_install_settings(&
+ list=lget('list'), &
+ build_name=val_build, &
+ profile=val_profile,&
+ compiler=val_compiler, &
+ flag=val_flag, &
+ no_rebuild=lget('no-rebuild'), &
+ verbose=lget('verbose'))
+ call get_char_arg(install_settings%prefix, 'prefix')
+ call get_char_arg(install_settings%libdir, 'libdir')
+ call get_char_arg(install_settings%bindir, 'bindir')
+ call get_char_arg(install_settings%includedir, 'includedir')
+ call move_alloc(install_settings, cmd_settings)
+
+ case('list')
+ call set_args('&
+ & --list F&
+ & --verbose F&
+ &', help_list, version_text)
+ call printhelp(help_list_nodash)
+ if(lget('list'))then
+ call printhelp(help_list_dash)
+ endif
+ case('test')
+ call set_args('&
+ & --target " " &
+ & --list F&
+ & --profile " "&
+ & --runner " " &
+ & --compiler "'//get_env('FPM_COMPILER','gfortran')//'" &
+ & --flag:: " "&
+ & --verbose F&
+ & --',help_test,version_text)
+
+ call check_build_vals()
+
+ if( size(unnamed) .gt. 1 )then
+ names=unnamed(2:)
+ else
+ names=[character(len=len(names)) :: ]
+ endif
+
+ if(specified('target') )then
+ call split(sget('target'),tnames,delimiters=' ,:')
+ names=[character(len=max(len(names),len(tnames))) :: names,tnames]
+ endif
+
+ ! convert special string '..' to equivalent (shorter) '*'
+ ! to allow for a string that does not require shift-key and quoting
+ do i=1,size(names)
+ if(names(i).eq.'..')names(i)='*'
+ enddo
+
+ allocate(fpm_test_settings :: cmd_settings)
+ val_runner=sget('runner')
+ if(specified('runner') .and. val_runner.eq.'')val_runner='echo'
+ cmd_settings=fpm_test_settings(&
+ & args=remaining, &
+ & build_name=val_build, &
+ & profile=val_profile, &
+ & compiler=val_compiler, &
+ & flag=val_flag, &
+ & example=.false., &
+ & list=lget('list'), &
+ & name=names, &
+ & runner=val_runner, &
+ & verbose=lget('verbose') )
+
+ case('update')
+ call set_args('--fetch-only F --verbose F --clean F', &
+ help_update, version_text)
+
+ if( size(unnamed) .gt. 1 )then
+ names=unnamed(2:)
+ else
+ names=[character(len=len(names)) :: ]
+ endif
+
+ allocate(fpm_update_settings :: cmd_settings)
+ cmd_settings=fpm_update_settings(name=names, &
+ fetch_only=lget('fetch-only'), verbose=lget('verbose'), &
+ clean=lget('clean'))
+
+ case default
+
+ call set_args('&
+ & --list F&
+ & --verbose F&
+ &', help_fpm, version_text)
+ ! Note: will not get here if --version or --usage or --help
+ ! is present on commandline
+ help_text=help_usage
+ if(lget('list'))then
+ help_text=help_list_dash
+ elseif(len_trim(cmdarg).eq.0)then
+ write(stdout,'(*(a))')'Fortran Package Manager:'
+ write(stdout,'(*(a))')' '
+ call printhelp(help_list_nodash)
+ else
+ write(stderr,'(*(a))')'<ERROR> unknown subcommand [', &
+ & trim(cmdarg), ']'
+ call printhelp(help_list_dash)
+ endif
+ call printhelp(help_text)
+
+ end select
+ contains
+
+ subroutine check_build_vals()
+ character(len=:), allocatable :: flags
+
+ val_compiler=sget('compiler')
+ if(val_compiler.eq.'') then
+ val_compiler='gfortran'
+ endif
+
+ val_flag = " " // sget('flag')
+ val_profile = sget('profile')
+ if (val_flag == '') then
+ call get_default_compile_flags(val_compiler, val_profile == "release", val_flag)
+ else
+ select case(val_profile)
+ case("release", "debug")
+ call get_default_compile_flags(val_compiler, val_profile == "release", flags)
+ val_flag = flags // val_flag
+ end select
+ end if
+ allocate(character(len=16) :: val_build)
+ write(val_build, '(z16.16)') fnv_1a(val_flag)
+
+ end subroutine check_build_vals
+
+ subroutine printhelp(lines)
+ character(len=:),intent(in),allocatable :: lines(:)
+ integer :: iii,ii
+ if(allocated(lines))then
+ ii=size(lines)
+ if(ii .gt. 0 .and. len(lines).gt. 0) then
+ write(stdout,'(g0)')(trim(lines(iii)), iii=1, ii)
+ else
+ write(stdout,'(a)')'<WARNING> *printhelp* output requested is empty'
+ endif
+ endif
+ end subroutine printhelp
+
+ end subroutine get_command_line_settings
+
+ function is_fortran_name(line) result (lout)
+ ! determine if a string is a valid Fortran name ignoring trailing spaces
+ ! (but not leading spaces)
+ character(len=*),parameter :: int='0123456789'
+ character(len=*),parameter :: lower='abcdefghijklmnopqrstuvwxyz'
+ character(len=*),parameter :: upper='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ character(len=*),parameter :: allowed=upper//lower//int//'_'
+ character(len=*),intent(in) :: line
+ character(len=:),allocatable :: name
+ logical :: lout
+ name=trim(line)
+ if(len(name).ne.0)then
+ lout = .true. &
+ & .and. verify(name(1:1), lower//upper) == 0 &
+ & .and. verify(name,allowed) == 0 &
+ & .and. len(name) <= 63
+ else
+ lout = .false.
+ endif
+ end function is_fortran_name
+
+ subroutine set_help()
+ help_list_nodash=[character(len=80) :: &
+ '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 ', &
+ ' install Install project ', &
+ ' ', &
+ ' Enter "fpm --list" for a brief list of subcommand options. Enter ', &
+ ' "fpm --help" or "fpm SUBCOMMAND --help" for detailed descriptions. ', &
+ ' ']
+ help_list_dash = [character(len=80) :: &
+ ' ', &
+ ' build [--compiler COMPILER_NAME] [--profile PROF] [--flag FFLAGS] [--list] ', &
+ ' help [NAME(s)] ', &
+ ' new NAME [[--lib|--src] [--app] [--test] [--example]]| ', &
+ ' [--full|--bare][--backfill] ', &
+ ' update [NAME(s)] [--fetch-only] [--clean] [--verbose] ', &
+ ' list [--list] ', &
+ ' run [[--target] NAME(s) [--example] [--profile PROF] [--flag FFLAGS] [--all] ', &
+ ' [--runner "CMD"] [--compiler COMPILER_NAME] [--list] [-- ARGS] ', &
+ ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--runner "CMD"] [--list]', &
+ ' [--compiler COMPILER_NAME] [-- ARGS] ', &
+ ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH] [options] ', &
+ ' ']
+ help_usage=[character(len=80) :: &
+ '' ]
+ help_runner=[character(len=80) :: &
+ 'NAME ', &
+ ' --runner(1) - a shared option for specifying an application to launch ', &
+ ' executables. ', &
+ ' ', &
+ 'SYNOPSIS ', &
+ ' fpm run|test --runner CMD ... -- SUFFIX_OPTIONS ', &
+ ' ', &
+ 'DESCRIPTION ', &
+ ' The --runner option allows specifying a program to launch ', &
+ ' executables selected via the fpm(1) subcommands "run" and "test". This ', &
+ ' gives easy recourse to utilities such as debuggers and other tools ', &
+ ' that wrap other executables. ', &
+ ' ', &
+ ' These external commands are not part of fpm(1) itself as they vary ', &
+ ' from platform to platform or require independent installation. ', &
+ ' ', &
+ 'OPTION ', &
+ ' --runner ''CMD'' quoted command used to launch the fpm(1) executables. ', &
+ ' Available for both the "run" and "test" subcommands. ', &
+ ' If the keyword is specified without a value the default command ', &
+ ' is "echo". ', &
+ ' -- SUFFIX_OPTIONS additional options to suffix the command CMD and executable ', &
+ ' file names with. ', &
+ 'EXAMPLES ', &
+ ' Use cases for ''fpm run|test --runner "CMD"'' include employing ', &
+ ' the following common GNU/Linux and Unix commands: ', &
+ ' ', &
+ ' INTERROGATE ', &
+ ' + nm - list symbols from object files ', &
+ ' + size - list section sizes and total size. ', &
+ ' + ldd - print shared object dependencies ', &
+ ' + ls - list directory contents ', &
+ ' + stat - display file or file system status ', &
+ ' + file - determine file type ', &
+ ' PERFORMANCE AND DEBUGGING ', &
+ ' + gdb - The GNU Debugger ', &
+ ' + valgrind - a suite of tools for debugging and profiling ', &
+ ' + time - time a simple command or give resource usage ', &
+ ' + timeout - run a command with a time limit ', &
+ ' COPY ', &
+ ' + install - copy files and set attributes ', &
+ ' + tar - an archiving utility ', &
+ ' ALTER ', &
+ ' + rm - remove files or directories ', &
+ ' + chmod - change permissions of a file ', &
+ ' + strip - remove unnecessary information from strippable files ', &
+ ' ', &
+ ' For example ', &
+ ' ', &
+ ' fpm test --runner gdb ', &
+ ' fpm run --runner "tar cvfz $HOME/bundle.tgz" ', &
+ ' fpm run --runner ldd ', &
+ ' fpm run --runner strip ', &
+ ' fpm run --runner ''cp -t /usr/local/bin'' ', &
+ ' ', &
+ ' # options after executable name can be specified after the -- option ', &
+ ' fpm --runner cp run -- /usr/local/bin/ ', &
+ ' # generates commands of the form "cp $FILENAME /usr/local/bin/" ', &
+ ' ', &
+ ' # bash(1) alias example: ', &
+ ' alias fpm-install=\ ', &
+ ' "fpm run --profile release --runner ''install -vbp -m 0711 -t ~/.local/bin''" ', &
+ ' fpm-install ', &
+ '' ]
+ help_fpm=[character(len=80) :: &
+ 'NAME ', &
+ ' fpm(1) - A Fortran package manager and build system ', &
+ ' ', &
+ 'SYNOPSIS ', &
+ ' fpm SUBCOMMAND [SUBCOMMAND_OPTIONS] ', &
+ ' ', &
+ ' fpm --help|--version|--list ', &
+ ' ', &
+ 'DESCRIPTION ', &
+ ' fpm(1) is a package manager that helps you create Fortran projects ', &
+ ' from source -- it automatically determines dependencies! ', &
+ ' ', &
+ ' Most significantly fpm(1) lets you draw upon other fpm(1) packages ', &
+ ' in distributed git(1) repositories as if the packages were a basic ', &
+ ' part of your default programming environment, as well as letting ', &
+ ' you share your projects with others in a similar manner. ', &
+ ' ', &
+ ' All output goes into the directory "build/" which can generally be ', &
+ ' removed and rebuilt if required. Note that if external packages are ', &
+ ' being used you need network connectivity to rebuild from scratch. ', &
+ ' ', &
+ 'SUBCOMMANDS ', &
+ ' Valid fpm(1) subcommands are: ', &
+ ' ', &
+ ' + build Compile the packages into the "build/" directory. ', &
+ ' + new Create a new Fortran package directory with sample files. ', &
+ ' + update Update the project dependencies. ', &
+ ' + run Run the local package binaries. defaults to all binaries for ', &
+ ' that release. ', &
+ ' + test Run the tests. ', &
+ ' + help Alternate method for displaying subcommand help. ', &
+ ' + list Display brief descriptions of all subcommands. ', &
+ ' + install Install project ', &
+ ' ', &
+ ' Their syntax is ', &
+ ' ', &
+ ' build [--profile PROF] [--flag FFLAGS] [--list] [--compiler COMPILER_NAME]', &
+ ' new NAME [[--lib|--src] [--app] [--test] [--example]]| ', &
+ ' [--full|--bare][--backfill] ', &
+ ' update [NAME(s)] [--fetch-only] [--clean] ', &
+ ' run [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] [--example]', &
+ ' [--all] [--runner "CMD"] [--compiler COMPILER_NAME] [-- ARGS] ', &
+ ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] ', &
+ ' [--runner "CMD"] [--compiler COMPILER_NAME] [-- ARGS] ', &
+ ' help [NAME(s)] ', &
+ ' list [--list] ', &
+ ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH] [options]', &
+ ' ', &
+ 'SUBCOMMAND OPTIONS ', &
+ ' --profile PROF selects the compilation profile for the build.',&
+ ' Currently available profiles are "release" for',&
+ ' high optimization and "debug" for full debug options.',&
+ ' If --flag is not specified the "debug" flags are the',&
+ ' default. ',&
+ ' --flag FFLAGS selects compile arguments for the build. These are',&
+ ' added to the profile options if --profile is specified,',&
+ ' else these options override the defaults.',&
+ ' Note object and .mod directory locations are always',&
+ ' built in.',&
+ ' --list List candidates instead of building or running them. On ', &
+ ' the fpm(1) command this shows a brief list of subcommands.', &
+ ' --runner CMD Provides a command to prefix program execution paths. ', &
+ ' --compiler COMPILER_NAME Compiler name. The environment variable ', &
+ ' FPM_COMPILER sets the default. ', &
+ ' -- ARGS Arguments to pass to executables. ', &
+ ' ', &
+ 'VALID FOR ALL SUBCOMMANDS ', &
+ ' --help Show help text and exit ', &
+ ' --verbose Display additional information when available ', &
+ ' --version Show version information and exit. ', &
+ ' ', &
+ 'EXAMPLES ', &
+ ' sample commands: ', &
+ ' ', &
+ ' fpm new mypackage --app --test ', &
+ ' fpm build ', &
+ ' fpm test ', &
+ ' fpm run ', &
+ ' fpm run --example ', &
+ ' fpm new --help ', &
+ ' fpm run myprogram --profile release -- -x 10 -y 20 --title "my title"', &
+ ' fpm install --prefix ~/.local ', &
+ ' ', &
+ 'SEE ALSO ', &
+ ' ', &
+ ' + The fpm(1) home page is at https://github.com/fortran-lang/fpm ', &
+ ' + Registered fpm(1) packages are at https://fortran-lang.org/packages ', &
+ ' + The fpm(1) TOML file format is described at ', &
+ ' https://github.com/fortran-lang/fpm/blob/master/manifest-reference.md ', &
+ '']
+ help_list=[character(len=80) :: &
+ 'NAME ', &
+ ' list(1) - list summary of fpm(1) subcommands ', &
+ ' ', &
+ 'SYNOPSIS ', &
+ ' fpm list [-list] ', &
+ ' ', &
+ ' fpm list --help|--version ', &
+ ' ', &
+ 'DESCRIPTION ', &
+ ' Display a short description for each fpm(1) subcommand. ', &
+ ' ', &
+ 'OPTIONS ', &
+ ' --list display a list of command options as well. This is the ', &
+ ' same output as generated by "fpm --list". ', &
+ ' ', &
+ 'EXAMPLES ', &
+ ' display a short list of fpm(1) subcommands ', &
+ ' ', &
+ ' fpm list ', &
+ ' fpm --list ', &
+ '' ]
+ help_run=[character(len=80) :: &
+ 'NAME ', &
+ ' run(1) - the fpm(1) subcommand to run project applications ', &
+ ' ', &
+ 'SYNOPSIS ', &
+ ' fpm run [[--target] NAME(s) [--profile PROF] [--flag FFLAGS]', &
+ ' [--compiler COMPILER_NAME] [--runner "CMD"] [--example]', &
+ ' [--list] [--all] [-- ARGS]', &
+ ' ', &
+ ' fpm run --help|--version ', &
+ ' ', &
+ 'DESCRIPTION ', &
+ ' Run the applications in your fpm(1) package. By default applications ', &
+ ' in /app or specified as "executable" in your "fpm.toml" manifest are ', &
+ ' used. Alternatively demonstration programs in example/ or specified in', &
+ ' the "example" section in "fpm.toml" can be executed. The applications ', &
+ ' are automatically rebuilt before being run if they are out of date. ', &
+ ' ', &
+ 'OPTIONS ', &
+ ' --target NAME(s) list of application names to execute. No name is ', &
+ ' required if only one target exists. If no name is ', &
+ ' supplied and more than one candidate exists or a ', &
+ ' name has no match a list is produced and fpm(1) ', &
+ ' exits. ', &
+ ' ', &
+ ' Basic "globbing" is supported where "?" represents ', &
+ ' any single character and "*" represents any string. ', &
+ ' Note The glob string normally needs quoted to ', &
+ ' the special characters from shell expansion. ', &
+ ' --all Run all examples or applications. An alias for --target ''*''. ', &
+ ' --example Run example programs instead of applications. ', &
+ ' --profile PROF selects the compilation profile for the build.',&
+ ' Currently available profiles are "release" for',&
+ ' high optimization and "debug" for full debug options.',&
+ ' If --flag is not specified the "debug" flags are the',&
+ ' default. ',&
+ ' --flag FFLAGS selects compile arguments for the build. These are',&
+ ' added to the profile options if --profile is specified,',&
+ ' else these options override the defaults.',&
+ ' Note object and .mod directory locations are always',&
+ ' built in.',&
+ ' --compiler COMPILER_NAME Specify a compiler name. The default is ', &
+ ' "gfortran" unless set by the environment ', &
+ ' variable FPM_COMPILER. ', &
+ ' --runner CMD A command to prefix the program execution paths with. ', &
+ ' see "fpm help runner" for further details. ', &
+ ' --list list pathname of candidates instead of running them. Note ', &
+ ' out-of-date candidates will still be rebuilt before being ', &
+ ' listed. ', &
+ ' -- ARGS optional arguments to pass to the program(s). The same ', &
+ ' arguments are passed to all program names specified. ', &
+ ' ', &
+ 'EXAMPLES ', &
+ ' fpm(1) - run or display project applications: ', &
+ ' ', &
+ ' fpm run # run a target when only one exists or list targets ', &
+ ' fpm run --list # list all targets, running nothing. ', &
+ ' fpm run --all # run all targets, no matter how many there are. ', &
+ ' ', &
+ ' # run default program built or to be built with the compiler command ', &
+ ' # "f90". If more than one app exists a list displays and target names', &
+ ' # are required. ', &
+ ' fpm run --compiler f90 ', &
+ ' ', &
+ ' # run example programs instead of the application programs. ', &
+ ' fpm run --example ''*'' ', &
+ ' ', &
+ ' # run a specific program and pass arguments to the command ', &
+ ' fpm run myprog -- -x 10 -y 20 --title "my title line" ', &
+ ' ', &
+ ' # run production version of two applications ', &
+ ' fpm run --target prg1,prg2 --profile release ', &
+ ' ', &
+ ' # install executables in directory (assuming install(1) exists) ', &
+ ' fpm run --runner ''install -b -m 0711 -p -t /usr/local/bin'' ', &
+ '' ]
+ help_build=[character(len=80) :: &
+ 'NAME ', &
+ ' build(1) - the fpm(1) subcommand to build a project ', &
+ ' ', &
+ 'SYNOPSIS ', &
+ ' fpm build [--profile PROF] [--flag FFLAGS] [--compiler COMPILER_NAME] [-list]', &
+ ' ', &
+ ' fpm build --help|--version ', &
+ ' ', &
+ 'DESCRIPTION ', &
+ ' The "fpm build" command ', &
+ ' o Fetches any dependencies ', &
+ ' o Scans your sources ', &
+ ' o Builds them in the proper order ', &
+ ' ', &
+ ' The Fortran source files are assumed by default to be in ', &
+ ' o src/ for modules and procedure source ', &
+ ' o app/ main program(s) for applications ', &
+ ' o test/ main program(s) and support files for project tests ', &
+ ' o example/ main program(s) for example programs ', &
+ ' Changed or new files found are rebuilt. The results are placed in ', &
+ ' the build/ directory. ', &
+ ' ', &
+ ' Non-default pathnames and remote dependencies are used if ', &
+ ' specified in the "fpm.toml" file. ', &
+ ' ', &
+ 'OPTIONS ', &
+ ' --profile PROF selects the compilation profile for the build.',&
+ ' Currently available profiles are "release" for',&
+ ' high optimization and "debug" for full debug options.',&
+ ' If --flag is not specified the "debug" flags are the',&
+ ' default. ',&
+ ' --flag FFLAGS selects compile arguments for the build. These are',&
+ ' added to the profile options if --profile is specified,',&
+ ' else these options override the defaults.',&
+ ' Note object and .mod directory locations are always',&
+ ' built in.',&
+ ' --compiler COMPILER_NAME Specify a compiler name. The default is ', &
+ ' "gfortran" unless set by the environment ', &
+ ' variable FPM_COMPILER. ', &
+ ' --list list candidates instead of building or running them ', &
+ ' --show-model show the model and exit (do not build) ', &
+ ' --help print this help and exit ', &
+ ' --version print program version information and exit ', &
+ ' ', &
+ 'EXAMPLES ', &
+ ' Sample commands: ', &
+ ' ', &
+ ' fpm build # build with debug options ', &
+ ' fpm build --profile release # build with high optimization ', &
+ '' ]
+
+ help_help=[character(len=80) :: &
+ 'NAME ', &
+ ' help(1) - the fpm(1) subcommand to display help ', &
+ ' ', &
+ 'SYNOPSIS ', &
+ ' fpm help [fpm] [new] [build] [run] [test] [help] [version] [manual] ', &
+ ' [runner] ', &
+ ' ', &
+ 'DESCRIPTION ', &
+ ' The "fpm help" command is an alternative to the --help parameter ', &
+ ' on the fpm(1) command and its subcommands. ', &
+ ' ', &
+ 'OPTIONS ', &
+ ' NAME(s) A list of topic names to display. All the subcommands ', &
+ ' have their own page (new, build, run, test, ...). ', &
+ ' ', &
+ ' The special name "manual" displays all the fpm(1) ', &
+ ' built-in documentation. ', &
+ ' ', &
+ ' The default is to display help for the fpm(1) command ', &
+ ' itself. ', &
+ ' ', &
+ 'EXAMPLES ', &
+ ' Sample usage: ', &
+ ' ', &
+ ' fpm help # general fpm(1) command help ', &
+ ' fpm help version # show program version ', &
+ ' fpm help new # display help for "new" subcommand ', &
+ ' fpm help manual # All fpm(1) built-in documentation ', &
+ ' ', &
+ '' ]
+ help_new=[character(len=80) :: &
+ 'NAME ', &
+ ' new(1) - the fpm(1) subcommand to initialize a new project ', &
+ 'SYNOPSIS ', &
+ ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| ', &
+ ' [--full|--bare][--backfill] ', &
+ ' fpm new --help|--version ', &
+ ' ', &
+ 'DESCRIPTION ', &
+ ' "fpm new" creates and populates a new programming project directory. ', &
+ ' It ', &
+ ' o creates a directory with the specified name ', &
+ ' o runs the command "git init" in that directory ', &
+ ' o populates the directory with the default project directories ', &
+ ' o adds sample Fortran source files ', &
+ ' o adds a ".gitignore" file for ignoring the build/ directory ', &
+ ' (where fpm-generated output will be placed) ', &
+ ' ', &
+ ' The default file structure (that will be automatically scanned) is ', &
+ ' ', &
+ ' NAME/ ', &
+ ' fpm.toml ', &
+ ' .gitignore ', &
+ ' src/ ', &
+ ' NAME.f90 ', &
+ ' app/ ', &
+ ' main.f90 ', &
+ ' test/ ', &
+ ' check.f90 ', &
+ ' example/ ', &
+ ' demo.f90 ', &
+ ' ', &
+ ' Using this file structure is highly encouraged, particularly for ', &
+ ' small packages primarily intended to be used as dependencies. ', &
+ ' ', &
+ ' If you find this restrictive and need to customize the package ', &
+ ' structure you will find using the --full switch creates a ', &
+ ' heavily annotated manifest file with references to documentation ', &
+ ' to aid in constructing complex package structures. ', &
+ ' ', &
+ ' Remember to update the information in the sample "fpm.toml" ', &
+ ' file with your name and e-mail address. ', &
+ ' ', &
+ 'OPTIONS ', &
+ ' NAME the name of the project directory to create. The name ', &
+ ' must be made of up to 63 ASCII letters, digits, underscores, ', &
+ ' or hyphens, and start with a letter. ', &
+ ' ', &
+ ' The default is to create the src/, app/, and test/ directories. ', &
+ ' If any of the following options are specified then only the ', &
+ ' selected subdirectories are generated: ', &
+ ' ', &
+ ' --lib,--src create directory src/ and a placeholder module ', &
+ ' named "NAME.f90" for use with subcommand "build". ', &
+ ' --app create directory app/ and a placeholder main ', &
+ ' program for use with subcommand "run". ', &
+ ' --test create directory test/ and a placeholder program ', &
+ ' for use with the subcommand "test". Note that sans ', &
+ ' "--lib" it really does not have anything to test. ', &
+ ' --example create directory example/ and a placeholder program ', &
+ ' for use with the subcommand "run --example". ', &
+ ' It is only created by default if "--full is" specified. ', &
+ ' ', &
+ ' So the default is equivalent to ',&
+ ' ', &
+ ' fpm NAME --lib --app --test ', &
+ ' ', &
+ ' --backfill By default the directory must not exist. If this ', &
+ ' option is present the directory may pre-exist and ', &
+ ' only subdirectories and files that do not ', &
+ ' already exist will be created. For example, if you ', &
+ ' previously entered "fpm new myname --lib" entering ', &
+ ' "fpm new myname -full --backfill" will create any missing', &
+ ' app/, example/, and test/ directories and programs. ', &
+ ' ', &
+ ' --full By default a minimal manifest file ("fpm.toml") is ', &
+ ' created that depends on auto-discovery. With this ', &
+ ' option a much more extensive manifest sample is written ', &
+ ' and the example/ directory is created and populated. ', &
+ ' It is designed to facilitate creating projects that ', &
+ ' depend extensively on non-default build options. ', &
+ ' ', &
+ ' --bare A minimal manifest file ("fpm.toml") is created and ', &
+ ' a ".gitignore" and "README.md" file is created but no ', &
+ ' directories or sample Fortran is generated. ', &
+ ' ', &
+ ' --help print this help and exit ', &
+ ' --version print program version information and exit ', &
+ ' ', &
+ 'EXAMPLES ', &
+ ' Sample use ', &
+ ' ', &
+ ' fpm new myproject # create new project directory and seed it ', &
+ ' cd myproject # Enter the new directory ', &
+ ' # and run commands such as ', &
+ ' fpm build ', &
+ ' fpm run # run lone example application program ', &
+ ' fpm test # run example test program(s) ', &
+ ' fpm run --example # run lone example program ', &
+ ' ', &
+ ' fpm new A --full # create example/ and an annotated fpm.toml as well', &
+ ' fpm new A --bare # create no directories ', &
+ ' create any missing files in current directory ', &
+ ' fpm new `pwd` --full --backfill ', &
+ '' ]
+ help_test=[character(len=80) :: &
+ 'NAME ', &
+ ' test(1) - the fpm(1) subcommand to run project tests ', &
+ ' ', &
+ 'SYNOPSIS ', &
+ ' fpm test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS]', &
+ ' [--compiler COMPILER_NAME ] [--runner "CMD"] [--list][-- ARGS]', &
+ ' ', &
+ ' fpm test --help|--version ', &
+ ' ', &
+ 'DESCRIPTION ', &
+ ' Run applications you have built to test your project. ', &
+ ' ', &
+ 'OPTIONS ', &
+ ' --target NAME(s) optional list of specific test names to execute. ', &
+ ' The default is to run all the tests in test/ ', &
+ ' or the tests listed in the "fpm.toml" file. ', &
+ ' ', &
+ ' Basic "globbing" is supported where "?" represents ', &
+ ' any single character and "*" represents any string. ', &
+ ' Note The glob string normally needs quoted to ', &
+ ' protect the special characters from shell expansion.', &
+ ' --profile PROF selects the compilation profile for the build.',&
+ ' Currently available profiles are "release" for',&
+ ' high optimization and "debug" for full debug options.',&
+ ' If --flag is not specified the "debug" flags are the',&
+ ' default. ',&
+ ' --flag FFLAGS selects compile arguments for the build. These are',&
+ ' added to the profile options if --profile is specified,',&
+ ' else these options override the defaults.',&
+ ' Note object and .mod directory locations are always',&
+ ' built in.',&
+ ' --compiler COMPILER_NAME Specify a compiler name. The default is ', &
+ ' "gfortran" unless set by the environment ', &
+ ' variable FPM_COMPILER. ', &
+ ' --runner CMD A command to prefix the program execution paths with. ', &
+ ' see "fpm help runner" for further details. ', &
+ ' --list list candidates instead of building or running them ', &
+ ' -- ARGS optional arguments to pass to the test program(s). ', &
+ ' The same arguments are passed to all test names ', &
+ ' specified. ', &
+ ' ', &
+ 'EXAMPLES ', &
+ 'run tests ', &
+ ' ', &
+ ' # run default tests in /test or as specified in "fpm.toml" ', &
+ ' fpm test ', &
+ ' ', &
+ ' # run using compiler command "f90" ', &
+ ' fpm test --compiler f90 ', &
+ ' ', &
+ ' # run a specific test and pass arguments to the command ', &
+ ' fpm test mytest -- -x 10 -y 20 --title "my title line" ', &
+ ' ', &
+ ' fpm test tst1 tst2 --profile PROF # run production version of two tests', &
+ '' ]
+ help_update=[character(len=80) :: &
+ 'NAME', &
+ ' update(1) - manage project dependencies', &
+ '', &
+ 'SYNOPSIS', &
+ ' fpm update [--fetch-only] [--clean] [--verbose] [NAME(s)]', &
+ '', &
+ 'DESCRIPTION', &
+ ' Manage and update project dependencies. If no dependency names are', &
+ ' provided all the dependencies are updated automatically.', &
+ '', &
+ 'OPTIONS', &
+ ' --fetch-only Only fetch dependencies, do not update existing projects', &
+ ' --clean Do not use previous dependency cache', &
+ ' --verbose Show additional printout', &
+ '', &
+ 'SEE ALSO', &
+ ' The fpm(1) home page at https://github.com/fortran-lang/fpm', &
+ '' ]
+ help_install=[character(len=80) :: &
+ 'NAME', &
+ ' install(1) - install fpm projects', &
+ '', &
+ 'SYNOPSIS', &
+ ' fpm install [--profile PROF] [--flag FFLAGS] [--list] [--no-rebuild]', &
+ ' [--prefix DIR] [--bindir DIR] [--libdir DIR] [--includedir DIR]', &
+ ' [--verbose]', &
+ '', &
+ 'DESCRIPTION', &
+ ' Subcommand to install fpm projects. Running install will export the', &
+ ' current project to the selected prefix, this will by default install all', &
+ ' executables (tests and examples are excluded) which are part of the projects.', &
+ ' Libraries and module files are only installed for projects requiring the', &
+ ' installation of those components in the package manifest.', &
+ '', &
+ 'OPTIONS', &
+ ' --list list all installable targets for this project,', &
+ ' but do not install any of them', &
+ ' --profile PROF selects the compilation profile for the build.',&
+ ' Currently available profiles are "release" for',&
+ ' high optimization and "debug" for full debug options.',&
+ ' If --flag is not specified the "debug" flags are the',&
+ ' default. ',&
+ ' --flag FFLAGS selects compile arguments for the build. These are',&
+ ' added to the profile options if --profile is specified,',&
+ ' else these options override the defaults.',&
+ ' Note object and .mod directory locations are always',&
+ ' built in.',&
+ ' --no-rebuild do not rebuild project before installation', &
+ ' --prefix DIR path to installation directory (requires write access),', &
+ ' the default prefix on Unix systems is $HOME/.local', &
+ ' and %APPDATA%\local on Windows', &
+ ' --bindir DIR subdirectory to place executables in (default: bin)', &
+ ' --libdir DIR subdirectory to place libraries and archives in', &
+ ' (default: lib)', &
+ ' --includedir DIR subdirectory to place headers and module files in', &
+ ' (default: include)', &
+ ' --verbose print more information', &
+ '', &
+ 'EXAMPLES', &
+ ' 1. Install release version of project:', &
+ '', &
+ ' fpm install --profile release', &
+ '', &
+ ' 2. Install the project without rebuilding the executables:', &
+ '', &
+ ' fpm install --no-rebuild', &
+ '', &
+ ' 3. Install executables to a custom prefix into the exe directory:', &
+ '', &
+ ' fpm install --prefix $PWD --bindir exe', &
+ '' ]
+ end subroutine set_help
+
+ subroutine get_char_arg(var, arg)
+ character(len=:), allocatable, intent(out) :: var
+ character(len=*), intent(in) :: arg
+ var = sget(arg)
+ if (len_trim(var) == 0) deallocate(var)
+ end subroutine get_char_arg
+
+end module fpm_command_line