-
+
type(error_t),
|
intent(out), |
@@ -723,7 +723,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/proc/warnwrite.html b/proc/warnwrite.html
index e4bf905ca5..eb5278c8c7 100644
--- a/proc/warnwrite.html
+++ b/proc/warnwrite.html
@@ -289,7 +289,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/proc/which.html b/proc/which.html
index 069eac5e24..bab4c52afe 100644
--- a/proc/which.html
+++ b/proc/which.html
@@ -344,7 +344,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/proc/windows_path.html b/proc/windows_path.html
index 9b6bc61e23..232cc110b7 100644
--- a/proc/windows_path.html
+++ b/proc/windows_path.html
@@ -285,7 +285,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/proc/write_response_file.html b/proc/write_response_file.html
index 616714eb6f..7c6cc57f6a 100644
--- a/proc/write_response_file.html
+++ b/proc/write_response_file.html
@@ -369,7 +369,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/program/main.html b/program/main.html
index 79ae8044ff..f9bdcca360 100644
--- a/program/main.html
+++ b/program/main.html
@@ -208,16 +208,16 @@ Uses
@@ -713,7 +713,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/search.html b/search.html
index 608efa308f..7068bcbb65 100644
--- a/search.html
+++ b/search.html
@@ -124,7 +124,7 @@ Search Results
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/build.f90.html b/sourcefile/build.f90.html
index 7a94284c28..0a0e3dafa7 100644
--- a/sourcefile/build.f90.html
+++ b/sourcefile/build.f90.html
@@ -450,7 +450,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/dependency.f90.html b/sourcefile/dependency.f90.html
index 294979675a..964ecd8469 100644
--- a/sourcefile/dependency.f90.html
+++ b/sourcefile/dependency.f90.html
@@ -1484,7 +1484,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/dependency.f90~2.html b/sourcefile/dependency.f90~2.html
index ca9c7cd2f1..b02edb7284 100644
--- a/sourcefile/dependency.f90~2.html
+++ b/sourcefile/dependency.f90~2.html
@@ -617,7 +617,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/downloader.f90.html b/sourcefile/downloader.f90.html
index 45fb754192..0186f50372 100644
--- a/sourcefile/downloader.f90.html
+++ b/sourcefile/downloader.f90.html
@@ -368,7 +368,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/error.f90.html b/sourcefile/error.f90.html
index f9ffcd4cf8..cd52861b56 100644
--- a/sourcefile/error.f90.html
+++ b/sourcefile/error.f90.html
@@ -419,7 +419,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/example.f90.html b/sourcefile/example.f90.html
index 097a7f29dd..e813ad66a7 100644
--- a/sourcefile/example.f90.html
+++ b/sourcefile/example.f90.html
@@ -414,7 +414,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/executable.f90.html b/sourcefile/executable.f90.html
index 711a12507d..fd86f84ad8 100644
--- a/sourcefile/executable.f90.html
+++ b/sourcefile/executable.f90.html
@@ -425,7 +425,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fortran.f90.html b/sourcefile/fortran.f90.html
index 9c5a19eb6e..ea0b3fdc9d 100644
--- a/sourcefile/fortran.f90.html
+++ b/sourcefile/fortran.f90.html
@@ -341,7 +341,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm.f90.html b/sourcefile/fpm.f90.html
index 3dd4852427..30fa74af72 100644
--- a/sourcefile/fpm.f90.html
+++ b/sourcefile/fpm.f90.html
@@ -964,7 +964,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_backend.f90.html b/sourcefile/fpm_backend.f90.html
index 44ca8bd7d0..63149e903a 100644
--- a/sourcefile/fpm_backend.f90.html
+++ b/sourcefile/fpm_backend.f90.html
@@ -612,7 +612,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_backend_console.f90.html b/sourcefile/fpm_backend_console.f90.html
index e800b8dd02..53d785a141 100644
--- a/sourcefile/fpm_backend_console.f90.html
+++ b/sourcefile/fpm_backend_console.f90.html
@@ -349,7 +349,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_backend_output.f90.html b/sourcefile/fpm_backend_output.f90.html
index d4f2ba0d41..ed3456bb34 100644
--- a/sourcefile/fpm_backend_output.f90.html
+++ b/sourcefile/fpm_backend_output.f90.html
@@ -414,7 +414,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_command_line.f90.html b/sourcefile/fpm_command_line.f90.html
index 98a80ed277..86f0648eee 100644
--- a/sourcefile/fpm_command_line.f90.html
+++ b/sourcefile/fpm_command_line.f90.html
@@ -1701,7 +1701,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_compiler.f90.html b/sourcefile/fpm_compiler.f90.html
index d91986e227..6bb38ac4bf 100644
--- a/sourcefile/fpm_compiler.f90.html
+++ b/sourcefile/fpm_compiler.f90.html
@@ -1489,7 +1489,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_environment.f90.html b/sourcefile/fpm_environment.f90.html
index cd61f6de76..1674e3c9b3 100644
--- a/sourcefile/fpm_environment.f90.html
+++ b/sourcefile/fpm_environment.f90.html
@@ -557,7 +557,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_filesystem.f90.html b/sourcefile/fpm_filesystem.f90.html
index 0f29316deb..caaa8bd637 100644
--- a/sourcefile/fpm_filesystem.f90.html
+++ b/sourcefile/fpm_filesystem.f90.html
@@ -1456,7 +1456,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_meta.f90.html b/sourcefile/fpm_meta.f90.html
index 342d744611..5e9bee24f3 100644
--- a/sourcefile/fpm_meta.f90.html
+++ b/sourcefile/fpm_meta.f90.html
@@ -1837,7 +1837,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_model.f90.html b/sourcefile/fpm_model.f90.html
index 43f68e5e2f..5d5109d9bd 100644
--- a/sourcefile/fpm_model.f90.html
+++ b/sourcefile/fpm_model.f90.html
@@ -635,7 +635,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_os.f90.html b/sourcefile/fpm_os.f90.html
index 0c2c5d7962..29caf7fcb0 100644
--- a/sourcefile/fpm_os.f90.html
+++ b/sourcefile/fpm_os.f90.html
@@ -494,7 +494,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_release.f90.html b/sourcefile/fpm_release.f90.html
index df242db9ae..d944ae3d2c 100644
--- a/sourcefile/fpm_release.f90.html
+++ b/sourcefile/fpm_release.f90.html
@@ -282,7 +282,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_settings.f90.html b/sourcefile/fpm_settings.f90.html
index 63bdcfbb9c..6ca33a3fdd 100644
--- a/sourcefile/fpm_settings.f90.html
+++ b/sourcefile/fpm_settings.f90.html
@@ -480,7 +480,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_source_parsing.f90.html b/sourcefile/fpm_source_parsing.f90.html
index 7cd1083fdb..d8b4ed14f0 100644
--- a/sourcefile/fpm_source_parsing.f90.html
+++ b/sourcefile/fpm_source_parsing.f90.html
@@ -963,7 +963,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_sources.f90.html b/sourcefile/fpm_sources.f90.html
index f9b4fdef21..b93f796ac4 100644
--- a/sourcefile/fpm_sources.f90.html
+++ b/sourcefile/fpm_sources.f90.html
@@ -490,7 +490,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_strings.f90.html b/sourcefile/fpm_strings.f90.html
index f69140c2b7..9b9922947a 100644
--- a/sourcefile/fpm_strings.f90.html
+++ b/sourcefile/fpm_strings.f90.html
@@ -1682,7 +1682,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/fpm_targets.f90.html b/sourcefile/fpm_targets.f90.html
index f9b989a3ab..ed80eb93ec 100644
--- a/sourcefile/fpm_targets.f90.html
+++ b/sourcefile/fpm_targets.f90.html
@@ -1321,7 +1321,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/git.f90.html b/sourcefile/git.f90.html
index 2e914ba99a..3e42c85bd3 100644
--- a/sourcefile/git.f90.html
+++ b/sourcefile/git.f90.html
@@ -578,7 +578,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/install.f90.html b/sourcefile/install.f90.html
index e995d2a01f..12dcfea924 100644
--- a/sourcefile/install.f90.html
+++ b/sourcefile/install.f90.html
@@ -344,7 +344,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/install.f90~2.html b/sourcefile/install.f90~2.html
index 6ec04bb511..ab02c8d20d 100644
--- a/sourcefile/install.f90~2.html
+++ b/sourcefile/install.f90~2.html
@@ -394,7 +394,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/installer.f90.html b/sourcefile/installer.f90.html
index f07e9bc0b1..3ab01ade1e 100644
--- a/sourcefile/installer.f90.html
+++ b/sourcefile/installer.f90.html
@@ -514,7 +514,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/library.f90.html b/sourcefile/library.f90.html
index acf2a2ef05..4d193ceab4 100644
--- a/sourcefile/library.f90.html
+++ b/sourcefile/library.f90.html
@@ -378,7 +378,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/main.f90.html b/sourcefile/main.f90.html
index 794df24223..13a7dfc4de 100644
--- a/sourcefile/main.f90.html
+++ b/sourcefile/main.f90.html
@@ -359,7 +359,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/manifest.f90.html b/sourcefile/manifest.f90.html
index dbdf846b6f..98931cb18c 100644
--- a/sourcefile/manifest.f90.html
+++ b/sourcefile/manifest.f90.html
@@ -421,7 +421,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/meta.f90.html b/sourcefile/meta.f90.html
index b87e3e69bd..c654ebcc31 100644
--- a/sourcefile/meta.f90.html
+++ b/sourcefile/meta.f90.html
@@ -457,7 +457,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/new.f90.html b/sourcefile/new.f90.html
index 48b4a77238..f16549f9bf 100644
--- a/sourcefile/new.f90.html
+++ b/sourcefile/new.f90.html
@@ -938,7 +938,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/package.f90.html b/sourcefile/package.f90.html
index 8d5bf2c521..0592ddd201 100644
--- a/sourcefile/package.f90.html
+++ b/sourcefile/package.f90.html
@@ -751,7 +751,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/preprocess.f90.html b/sourcefile/preprocess.f90.html
index d2b92d6436..785e4cf308 100644
--- a/sourcefile/preprocess.f90.html
+++ b/sourcefile/preprocess.f90.html
@@ -467,7 +467,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/profiles.f90.html b/sourcefile/profiles.f90.html
index ed2e203322..90282d912c 100644
--- a/sourcefile/profiles.f90.html
+++ b/sourcefile/profiles.f90.html
@@ -1193,7 +1193,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/publish.f90.html b/sourcefile/publish.f90.html
index 9d9df213a2..fd97e79f19 100644
--- a/sourcefile/publish.f90.html
+++ b/sourcefile/publish.f90.html
@@ -354,7 +354,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/test.f90.html b/sourcefile/test.f90.html
index 8e75c56c8d..88931df8da 100644
--- a/sourcefile/test.f90.html
+++ b/sourcefile/test.f90.html
@@ -414,7 +414,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/toml.f90.html b/sourcefile/toml.f90.html
index 5d0eab3be9..053ae7145e 100644
--- a/sourcefile/toml.f90.html
+++ b/sourcefile/toml.f90.html
@@ -400,7 +400,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/update.f90.html b/sourcefile/update.f90.html
index 4a3edf90e2..82c5a12e96 100644
--- a/sourcefile/update.f90.html
+++ b/sourcefile/update.f90.html
@@ -307,7 +307,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/sourcefile/versioning.f90.html b/sourcefile/versioning.f90.html
index a2249d0fb1..766878317d 100644
--- a/sourcefile/versioning.f90.html
+++ b/sourcefile/versioning.f90.html
@@ -666,7 +666,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/src/install.f90 b/src/install.f90
index 6175873937..69375a88be 100644
--- a/src/install.f90
+++ b/src/install.f90
@@ -1,108 +1,158 @@
-!> Implementation of the installation configuration.
-!>
-!> An install table can currently have the following fields
-!>
-!>```toml
-!>library = bool
-!>```
-module fpm_manifest_install
- use fpm_error, only : error_t, fatal_error, syntax_error
- use fpm_toml, only : toml_table, toml_key, toml_stat, get_value
+module fpm_cmd_install
+ use, intrinsic :: iso_fortran_env, only : output_unit
+ use fpm, only : build_model
+ use fpm_backend, only : build_package
+ use fpm_command_line, only : fpm_install_settings
+ use fpm_error, only : error_t, fatal_error, fpm_stop
+ use fpm_filesystem, only : join_path, list_files
+ use fpm_installer, only : installer_t, new_installer
+ use fpm_manifest, only : package_config_t, get_package_data
+ use fpm_model, only : fpm_model_t, FPM_SCOPE_APP
+ use fpm_targets, only: targets_from_sources, build_target_t, &
+ build_target_ptr, FPM_TARGET_EXECUTABLE, &
+ filter_library_targets, filter_executable_targets, filter_modules
+ use fpm_strings, only : string_t, resize
implicit none
private
- public :: install_config_t, new_install_config
+ public :: cmd_install
- !> Configuration data for installation
- type :: install_config_t
+contains
- !> Install library with this project
- logical :: library
+ !> Entry point for the fpm-install subcommand
+ subroutine cmd_install(settings)
+ !> Representation of the command line settings
+ type(fpm_install_settings), intent(inout) :: settings
+ type(package_config_t) :: package
+ type(error_t), allocatable :: error
+ type(fpm_model_t) :: model
+ type(build_target_ptr), allocatable :: targets(:)
+ type(installer_t) :: installer
+ type(string_t), allocatable :: list(:)
+ logical :: installable
+
+ call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
+ call handle_error(error)
+
+ call build_model(model, settings, package, error)
+ call handle_error(error)
+
+ call targets_from_sources(targets, model, settings%prune, error)
+ call handle_error(error)
+
+ installable = (allocated(package%library) .and. package%install%library) &
+ .or. allocated(package%executable)
+ if (.not.installable) then
+ call fatal_error(error, "Project does not contain any installable targets")
+ call handle_error(error)
+ end if
- contains
+ if (settings%list) then
+ call install_info(output_unit, targets)
+ return
+ end if
- !> Print information on this instance
- procedure :: info
+ if (.not.settings%no_rebuild) then
+ call build_package(targets,model,verbose=settings%verbose)
+ end if
- end type install_config_t
+ call new_installer(installer, prefix=settings%prefix, &
+ bindir=settings%bindir, libdir=settings%libdir, &
+ includedir=settings%includedir, &
+ verbosity=merge(2, 1, settings%verbose))
-contains
+ if (allocated(package%library) .and. package%install%library) then
+ call filter_library_targets(targets, list)
- !> Create a new installation configuration from a TOML data structure
- subroutine new_install_config(self, table, error)
+ if (size(list) > 0) then
+ call installer%install_library(list(1)%s, error)
+ call handle_error(error)
- !> Instance of the install configuration
- type(install_config_t), intent(out) :: self
+ call install_module_files(installer, targets, error)
+ call handle_error(error)
+ end if
+ end if
- !> Instance of the TOML data structure
- type(toml_table), intent(inout) :: table
+ if (allocated(package%executable)) then
+ call install_executables(installer, targets, error)
+ call handle_error(error)
+ end if
- !> Error handling
- type(error_t), allocatable, intent(out) :: error
+ end subroutine cmd_install
- call check(table, error)
- if (allocated(error)) return
+ subroutine install_info(unit, targets)
+ integer, intent(in) :: unit
+ type(build_target_ptr), intent(in) :: targets(:)
- call get_value(table, "library", self%library, .false.)
+ integer :: ii, ntargets
+ type(string_t), allocatable :: install_target(:), temp(:)
- end subroutine new_install_config
+ allocate(install_target(0))
+ call filter_library_targets(targets, temp)
+ install_target = [install_target, temp]
- !> Check local schema for allowed entries
- subroutine check(table, error)
+ call filter_executable_targets(targets, FPM_SCOPE_APP, temp)
+ install_target = [install_target, temp]
- !> Instance of the TOML data structure
- type(toml_table), intent(inout) :: table
+ ntargets = size(install_target)
- !> Error handling
- type(error_t), allocatable, intent(out) :: error
+ write(unit, '("#", *(1x, g0))') &
+ "total number of installable targets:", ntargets
+ do ii = 1, ntargets
+ write(unit, '("-", *(1x, g0))') install_target(ii)%s
+ end do
- type(toml_key), allocatable :: list(:)
- integer :: ikey
+ end subroutine install_info
- call table%get_keys(list)
- if (size(list) < 1) return
+ subroutine install_module_files(installer, targets, error)
+ type(installer_t), intent(inout) :: installer
+ type(build_target_ptr), intent(in) :: targets(:)
+ type(error_t), allocatable, intent(out) :: error
+ type(string_t), allocatable :: modules(:)
+ integer :: ii
+
+ call filter_modules(targets, modules)
- do ikey = 1, size(list)
- select case(list(ikey)%key)
- case default
- call syntax_error(error, "Key "//list(ikey)%key//" is not allowed in install table")
- exit
- case("library")
- continue
- end select
+ do ii = 1, size(modules)
+ call installer%install_header(modules(ii)%s//".mod", error)
+ if (allocated(error)) exit
end do
if (allocated(error)) return
- end subroutine check
-
- !> Write information on install configuration instance
- subroutine info(self, unit, verbosity)
+ end subroutine install_module_files
- !> Instance of the build configuration
- class(install_config_t), intent(in) :: self
-
- !> Unit for IO
- integer, intent(in) :: unit
+ subroutine install_executables(installer, targets, error)
+ type(installer_t), intent(inout) :: installer
+ type(build_target_ptr), intent(in) :: targets(:)
+ type(error_t), allocatable, intent(out) :: error
+ integer :: ii
- !> Verbosity of the printout
- integer, intent(in), optional :: verbosity
+ do ii = 1, size(targets)
+ if (is_executable_target(targets(ii)%ptr)) then
+ call installer%install_executable(targets(ii)%ptr%output_file, error)
+ if (allocated(error)) exit
+ end if
+ end do
+ if (allocated(error)) return
- integer :: pr
- character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
+ end subroutine install_executables
- if (present(verbosity)) then
- pr = verbosity
- else
- pr = 1
+ elemental function is_executable_target(target_ptr) result(is_exe)
+ type(build_target_t), intent(in) :: target_ptr
+ logical :: is_exe
+ is_exe = target_ptr%target_type == FPM_TARGET_EXECUTABLE .and. &
+ allocated(target_ptr%dependencies)
+ if (is_exe) then
+ is_exe = target_ptr%dependencies(1)%ptr%source%unit_scope == FPM_SCOPE_APP
end if
+ end function is_executable_target
- if (pr < 1) return
-
- write(unit, fmt) "Install configuration"
- write(unit, fmt) " - library install", &
- & trim(merge("enabled ", "disabled", self%library))
-
- end subroutine info
+ subroutine handle_error(error)
+ type(error_t), intent(in), optional :: error
+ if (present(error)) then
+ call fpm_stop(1,error%message)
+ end if
+ end subroutine handle_error
-end module fpm_manifest_install
+end module fpm_cmd_install
diff --git a/tipuesearch/tipuesearch_content.js b/tipuesearch/tipuesearch_content.js
index 7b208db3b9..c01f56d033 100644
--- a/tipuesearch/tipuesearch_content.js
+++ b/tipuesearch/tipuesearch_content.js
@@ -1 +1 @@
-var tipuesearch = {"pages":[{"title":" Fortran-lang/fpm ","text":"Fortran-lang/fpm Fortran package manager developer documentation The package manifest Command line interface The package model The build backend Generating this documentation Fortran package manager developer documentation This is the main documentation of the Fortran package manager ( fpm ).\nThis document serves as developer documentation of fpm itself and contains general advice for developing in the fpm code base. The package manifest The central object describing an fpm project is the package manifest fpm.toml .\nThe manifest is written in TOML, you can find the TOML specification at the official TOML homepage . The fpm.toml file targets project developers and maintainers to relieve them from writing build files for their packages.\nWith the package manifest a central place to collect information about the project is provided.\nIt contains the versioning and licensing meta data, as well as the information on external dependencies and the required build-tools or compiler settings. The manifest format specific to fpm projects is documented in the manifest reference . Note For a more practical but less complete guide on creating fpm projects see the packaging guide . The details of the TOML parsing are implemented with using the tomlf module.\nGenerally, the interface to all TOML related functions for fpm is found in the proxy module fpm_toml . All the manifest types are bundled in fpm_manifest .\nWhile the specific subtables for the package configuration are found in the src/fpm/manifest directory, they should be reexported in the fpm_manifest module if they should be elsewhere in fpm . Command line interface fpm is mainly used as a command line tool.\nTo work with an fpm project as a user you can completely rely on the command line. The command line interface is build with the M_CLI2 module and can be found in fpm_command_line . The package model Once front-end inputs have been received from the package manifest and command line interface, fpm will construct an\ninternal representation of the package and its dependencies. This internal representation is known as the package model .\nThe model and its associated data types should encapsulate all the information required to correctly build a package and\nshould be independent of the intended backend build system. Information stored in the model includes: build targets and\ntheir inter-dependencies; compiler and compiler flags; library linking information. For more information on the contents of the package model and the process for constructing it, please see fpm_model . The build backend Once a complete package model has been constructed, it can be passed to a backend for either performing the compilation\nand linking of targets, or for generating configuration files for a third-party build system.\nCurrently, only a native backend is implemented in fpm . See fpm_backend for more information. Generating this documentation This documentation is generated by FORD .\nFor more details on the project file and the comment markup in the source code visit the FORD documentation . To regenerate this documentation run: ford docs.md Developer Info fortran-lang/fpm contributors","tags":"home","loc":"index.html"},{"title":"fpm_global_settings – Fortran-lang/fpm ","text":"type, public :: fpm_global_settings Contents Variables config_file_name path_to_config_folder registry_settings Type-Bound Procedures full_path has_custom_location path_to_config_folder_or_empty Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: config_file_name Name of the global config file. The default is config.toml . character(len=:), public, allocatable :: path_to_config_folder Path to the global config file excluding the file name. type(fpm_registry_settings), public, allocatable :: registry_settings Registry configs. Type-Bound Procedures procedure, public, :: full_path private function full_path(self) result(result) The full path to the global config file. Arguments Type Intent Optional Attributes Name class( fpm_global_settings ), intent(in) :: self Return Value character(len=:), allocatable procedure, public, :: has_custom_location private elemental function has_custom_location(self) True if the global config file is not at the default location. Arguments Type Intent Optional Attributes Name class( fpm_global_settings ), intent(in) :: self Return Value logical procedure, public, :: path_to_config_folder_or_empty private pure function path_to_config_folder_or_empty(self) The path to the global config directory. Arguments Type Intent Optional Attributes Name class( fpm_global_settings ), intent(in) :: self Return Value character(len=:), allocatable","tags":"","loc":"type/fpm_global_settings.html"},{"title":"fortran_features_t – Fortran-lang/fpm ","text":"type, public :: fortran_features_t Enabled Fortran language features Contents Variables implicit_external implicit_typing source_form Source Code fortran_features_t Components Type Visibility Attributes Name Initial logical, public :: implicit_external = .false. Use implicit external interface logical, public :: implicit_typing = .false. Use default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Source Code type :: fortran_features_t !> Use default implicit typing logical :: implicit_typing = . false . !> Use implicit external interface logical :: implicit_external = . false . !> Form to use for all Fortran sources character (:), allocatable :: source_form end type fortran_features_t","tags":"","loc":"type/fortran_features_t.html"},{"title":"fpm_model_t – Fortran-lang/fpm ","text":"type, public :: fpm_model_t Type describing everything required to build\n the root package and its dependencies. Contents Variables archiver build_prefix c_compile_flags compiler cxx_compile_flags deps enforce_module_names external_modules fortran_compile_flags include_dirs include_tests link_flags link_libraries module_prefix package_name packages Source Code fpm_model_t Components Type Visibility Attributes Name Initial type( archiver_t ), public :: archiver Archiver object character(len=:), public, allocatable :: build_prefix Base directory for build character(len=:), public, allocatable :: c_compile_flags Command line flags passed to C for compilation type( compiler_t ), public :: compiler Compiler object character(len=:), public, allocatable :: cxx_compile_flags Command line flags passed to C++ for compilation type( dependency_tree_t ), public :: deps Project dependencies logical, public :: enforce_module_names = .false. Whether module names should be prefixed with the package name type( string_t ), public, allocatable :: external_modules (:) External modules used character(len=:), public, allocatable :: fortran_compile_flags Command line flags passed to fortran for compilation type( string_t ), public, allocatable :: include_dirs (:) Include directories logical, public :: include_tests = .true. Whether tests should be added to the build list character(len=:), public, allocatable :: link_flags Command line flags passed to the linker type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public :: module_prefix Prefix for all module names character(len=:), public, allocatable :: package_name Name of root package type(package_t), public, allocatable :: packages (:) Array of packages (including the root package) Source Code type :: fpm_model_t !> Name of root package character (:), allocatable :: package_name !> Array of packages (including the root package) type ( package_t ), allocatable :: packages (:) !> Compiler object type ( compiler_t ) :: compiler !> Archiver object type ( archiver_t ) :: archiver !> Command line flags passed to fortran for compilation character (:), allocatable :: fortran_compile_flags !> Command line flags passed to C for compilation character (:), allocatable :: c_compile_flags !> Command line flags passed to C++ for compilation character (:), allocatable :: cxx_compile_flags !> Command line flags passed to the linker character (:), allocatable :: link_flags !> Base directory for build character (:), allocatable :: build_prefix !> Include directories type ( string_t ), allocatable :: include_dirs (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> External modules used type ( string_t ), allocatable :: external_modules (:) !> Project dependencies type ( dependency_tree_t ) :: deps !> Whether tests should be added to the build list logical :: include_tests = . true . !> Whether module names should be prefixed with the package name logical :: enforce_module_names = . false . !> Prefix for all module names type ( string_t ) :: module_prefix end type fpm_model_t","tags":"","loc":"type/fpm_model_t.html"},{"title":"srcfile_t – Fortran-lang/fpm ","text":"type, public :: srcfile_t Type for describing a source file Contents Variables digest exe_name file_name include_dependencies link_libraries modules_provided modules_used parent_modules unit_scope unit_type Source Code srcfile_t Components Type Visibility Attributes Name Initial integer(kind=int64), public :: digest Current hash character(len=:), public, allocatable :: exe_name Name of executable for FPM_UNIT_PROGRAM character(len=:), public, allocatable :: file_name File path relative to cwd type( string_t ), public, allocatable :: include_dependencies (:) Files INCLUDEd by this source file type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: modules_provided (:) Modules provided by this source file (lowerstring) type( string_t ), public, allocatable :: modules_used (:) Modules USEd by this source file (lowerstring) type( string_t ), public, allocatable :: parent_modules (:) Parent modules (submodules only) integer, public :: unit_scope = FPM_SCOPE_UNKNOWN Target module-use scope integer, public :: unit_type = FPM_UNIT_UNKNOWN Type of source unit Source Code type srcfile_t !> File path relative to cwd character (:), allocatable :: file_name !> Name of executable for FPM_UNIT_PROGRAM character (:), allocatable :: exe_name !> Target module-use scope integer :: unit_scope = FPM_SCOPE_UNKNOWN !> Modules provided by this source file (lowerstring) type ( string_t ), allocatable :: modules_provided (:) !> Type of source unit integer :: unit_type = FPM_UNIT_UNKNOWN !> Parent modules (submodules only) type ( string_t ), allocatable :: parent_modules (:) !> Modules USEd by this source file (lowerstring) type ( string_t ), allocatable :: modules_used (:) !> Files INCLUDEd by this source file type ( string_t ), allocatable :: include_dependencies (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Current hash integer ( int64 ) :: digest end type srcfile_t","tags":"","loc":"type/srcfile_t.html"},{"title":"console_t – Fortran-lang/fpm ","text":"type, public :: console_t Console object Contents Variables n_line Type-Bound Procedures update_line write_line Source Code console_t Components Type Visibility Attributes Name Initial integer, public :: n_line = 1 Number of lines printed Type-Bound Procedures procedure, public, :: update_line => console_update_line Update a previously-written console line private subroutine console_update_line(console, line_no, str) Overwrite a previously-written line in standard output Arguments Type Intent Optional Attributes Name class( console_t ), intent(in) :: console Console object integer, intent(in) :: line_no Integer output from console_write_line character(len=*), intent(in) :: str New string to overwrite line procedure, public, :: write_line => console_write_line Write a single line to the console private subroutine console_write_line(console, str, line, advance) Write a single line to the standard output Arguments Type Intent Optional Attributes Name class( console_t ), intent(inout) :: console Console object character(len=*), intent(in) :: str String to write integer, intent(out), optional :: line Integer needed to later update console line logical, intent(in), optional :: advance Advancing output (print newline?) Source Code type console_t !> Number of lines printed integer :: n_line = 1 contains !> Write a single line to the console procedure :: write_line => console_write_line !> Update a previously-written console line procedure :: update_line => console_update_line end type console_t","tags":"","loc":"type/console_t.html"},{"title":"archiver_t – Fortran-lang/fpm ","text":"type, public :: archiver_t Definition of archiver object Contents Variables ar echo use_response_file verbose Type-Bound Procedures make_archive Source Code archiver_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: ar Path to archiver logical, public :: echo = .true. Print all command logical, public :: use_response_file = .false. Use response files to pass arguments logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure, public, :: make_archive Create static archive public subroutine make_archive (self, output, args, log_file, stat) Create an archive Todo For Windows OS, use the local delete_file_win32 in stead of delete_file .\nThis may be related to a bug in Mingw64-openmp and is expected to be resolved in the future,\nsee issue #707, #708 and #808. Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: self Instance of the archiver object character(len=*), intent(in) :: output Name of the archive to generate type( string_t ), intent(in) :: args (:) Object files to include into the archive character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Source Code type :: archiver_t !> Path to archiver character ( len = :), allocatable :: ar !> Use response files to pass arguments logical :: use_response_file = . false . !> Print all command logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Create static archive procedure :: make_archive end type archiver_t","tags":"","loc":"type/archiver_t.html"},{"title":"compiler_t – Fortran-lang/fpm ","text":"type, public :: compiler_t Definition of compiler object Contents Variables cc cxx echo fc id verbose Type-Bound Procedures compile_c compile_cpp compile_fortran enumerate_libraries get_default_flags get_feature_flag get_include_flag get_main_flags get_module_flag is_gnu is_intel is_unknown link name Source Code compiler_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cc Path to the C compiler character(len=:), public, allocatable :: cxx Path to the C++ compiler logical, public :: echo = .true. Print all commands character(len=:), public, allocatable :: fc Path to the Fortran compiler integer(kind=compiler_enum), public :: id = id_unknown Identifier of the compiler logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure, public, :: compile_c Compile a C object public subroutine compile_c (self, input, output, args, log_file, stat) Compile a C object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag procedure, public, :: compile_cpp Compile a CPP object public subroutine compile_cpp (self, input, output, args, log_file, stat) Compile a CPP object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag procedure, public, :: compile_fortran Compile a Fortran object public subroutine compile_fortran (self, input, output, args, log_file, stat) Compile a Fortran object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag procedure, public, :: enumerate_libraries Enumerate libraries, based on compiler and platform public function enumerate_libraries (self, prefix, libs) result(r) Enumerate libraries, based on compiler and platform Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: prefix type( string_t ), intent(in) :: libs (:) Return Value character(len=:), allocatable procedure, public, :: get_default_flags Get default compiler flags public function get_default_flags (self, release) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self logical, intent(in) :: release Return Value character(len=:), allocatable procedure, public, :: get_feature_flag Get feature flag public function get_feature_flag (self, feature) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: feature Return Value character(len=:), allocatable procedure, public, :: get_include_flag Get flag for include directories public function get_include_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable procedure, public, :: get_main_flags Get flags for the main linking command public subroutine get_main_flags (self, language, flags) Get special flags for the main linker Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: language character(len=:), intent(out), allocatable :: flags procedure, public, :: get_module_flag Get flag for module output directories public function get_module_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable procedure, public, :: is_gnu Check whether this is a GNU compiler public pure function is_gnu (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical procedure, public, :: is_intel Check whether this is an Intel compiler public pure function is_intel (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical procedure, public, :: is_unknown Check whether compiler is recognized public pure function is_unknown (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical procedure, public, :: link Link executable public subroutine link (self, output, args, log_file, stat) Link an executable Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag procedure, public, :: name => compiler_name Return compiler name public pure function compiler_name (self) result(name) Return a compiler name string Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string Source Code type :: compiler_t !> Identifier of the compiler integer ( compiler_enum ) :: id = id_unknown !> Path to the Fortran compiler character ( len = :), allocatable :: fc !> Path to the C compiler character ( len = :), allocatable :: cc !> Path to the C++ compiler character ( len = :), allocatable :: cxx !> Print all commands logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Get default compiler flags procedure :: get_default_flags !> Get flag for module output directories procedure :: get_module_flag !> Get flag for include directories procedure :: get_include_flag !> Get feature flag procedure :: get_feature_flag !> Get flags for the main linking command procedure :: get_main_flags !> Compile a Fortran object procedure :: compile_fortran !> Compile a C object procedure :: compile_c !> Compile a CPP object procedure :: compile_cpp !> Link executable procedure :: link !> Check whether compiler is recognized procedure :: is_unknown !> Check whether this is an Intel compiler procedure :: is_intel !> Check whether this is a GNU compiler procedure :: is_gnu !> Enumerate libraries, based on compiler and platform procedure :: enumerate_libraries !> Return compiler name procedure :: name => compiler_name end type compiler_t","tags":"","loc":"type/compiler_t.html"},{"title":"metapackage_t – Fortran-lang/fpm ","text":"type, public :: metapackage_t Type for describing a source file Contents Variables cflags cxxflags dependency external_modules fflags flags fortran has_build_flags has_c_flags has_cxx_flags has_dependencies has_external_modules has_fortran_flags has_include_dirs has_link_flags has_link_libraries has_run_command incl_dirs link_flags link_libs run_command version Type-Bound Procedures destroy new resolve Source Code metapackage_t Components Type Visibility Attributes Name Initial type( string_t ), public :: cflags type( string_t ), public :: cxxflags type( dependency_config_t ), public, allocatable :: dependency (:) List of Development dependency meta data.\nMetapackage dependencies are never exported from the model type( string_t ), public, allocatable :: external_modules (:) type( string_t ), public :: fflags type( string_t ), public :: flags List of compiler flags and options to be added type( fortran_features_t ), public, allocatable :: fortran Special fortran features logical, public :: has_build_flags = .false. logical, public :: has_c_flags = .false. logical, public :: has_cxx_flags = .false. logical, public :: has_dependencies = .false. logical, public :: has_external_modules = .false. logical, public :: has_fortran_flags = .false. logical, public :: has_include_dirs = .false. logical, public :: has_link_flags = .false. logical, public :: has_link_libraries = .false. logical, public :: has_run_command = .false. type( string_t ), public, allocatable :: incl_dirs (:) type( string_t ), public :: link_flags type( string_t ), public, allocatable :: link_libs (:) type( string_t ), public :: run_command type( version_t ), public, allocatable :: version Package version (if supported) Type-Bound Procedures procedure, public, :: destroy Clean metapackage structure private elemental subroutine destroy(this) Clean the metapackage structure Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this procedure, public, :: new => init_from_name Initialize the metapackage structure from its given name private subroutine init_from_name(this, name, compiler, error) Initialize a metapackage from the given name\nInitialize metapackage by name Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this character(len=*), intent(in) :: name type( compiler_t ), intent(in) :: compiler type( error_t ), intent(out), allocatable :: error generic, public, :: resolve => resolve_cmd, resolve_model, resolve_package_config private subroutine resolve_cmd(self, settings, error) Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(in) :: self class( fpm_cmd_settings ), intent(inout) :: settings type( error_t ), intent(out), allocatable :: error private subroutine resolve_model(self, model, error) Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(in) :: self type( fpm_model_t ), intent(inout) :: model type( error_t ), intent(out), allocatable :: error private subroutine resolve_package_config(self, package, error) Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(in) :: self type( package_config_t ), intent(inout) :: package type( error_t ), intent(out), allocatable :: error Source Code type , public :: metapackage_t !> Package version (if supported) type ( version_t ), allocatable :: version logical :: has_link_libraries = . false . logical :: has_link_flags = . false . logical :: has_build_flags = . false . logical :: has_fortran_flags = . false . logical :: has_c_flags = . false . logical :: has_cxx_flags = . false . logical :: has_include_dirs = . false . logical :: has_dependencies = . false . logical :: has_run_command = . false . logical :: has_external_modules = . false . !> List of compiler flags and options to be added type ( string_t ) :: flags type ( string_t ) :: fflags type ( string_t ) :: cflags type ( string_t ) :: cxxflags type ( string_t ) :: link_flags type ( string_t ) :: run_command type ( string_t ), allocatable :: incl_dirs (:) type ( string_t ), allocatable :: link_libs (:) type ( string_t ), allocatable :: external_modules (:) !> Special fortran features type ( fortran_features_t ), allocatable :: fortran !> List of Development dependency meta data. !> Metapackage dependencies are never exported from the model type ( dependency_config_t ), allocatable :: dependency (:) contains !> Clean metapackage structure procedure :: destroy !> Initialize the metapackage structure from its given name procedure :: new => init_from_name !> Add metapackage dependencies to the model procedure , private :: resolve_cmd procedure , private :: resolve_model procedure , private :: resolve_package_config generic :: resolve => resolve_cmd , resolve_model , resolve_package_config end type metapackage_t","tags":"","loc":"type/metapackage_t.html"},{"title":"build_target_ptr – Fortran-lang/fpm ","text":"type, public :: build_target_ptr Wrapper type for constructing arrays of build_target_t pointers Contents Variables ptr Source Code build_target_ptr Components Type Visibility Attributes Name Initial type( build_target_t ), public, pointer :: ptr => null() Source Code type build_target_ptr type ( build_target_t ), pointer :: ptr => null () end type build_target_ptr","tags":"","loc":"type/build_target_ptr.html"},{"title":"build_target_t – Fortran-lang/fpm ","text":"type, public :: build_target_t Type describing a generated build target Contents Variables compile_flags dependencies digest_cached features link_flags link_libraries link_objects macros output_dir output_file output_log_file output_name package_name schedule skip sorted source target_type touched version Source Code build_target_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: compile_flags Compile flags for this build target type( build_target_ptr ), public, allocatable :: dependencies (:) Resolved build dependencies integer(kind=int64), public, allocatable :: digest_cached Previous source file hash type( fortran_features_t ), public :: features Language features character(len=:), public, allocatable :: link_flags Link flags for this build target type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: link_objects (:) Objects needed to link this target type( string_t ), public, allocatable :: macros (:) List of macros character(len=:), public, allocatable :: output_dir File path of output directory character(len=:), public, allocatable :: output_file File path of build target object relative to cwd character(len=:), public, allocatable :: output_log_file File path of build log file relative to cwd character(len=:), public, allocatable :: output_name File path of build target object relative to output_dir character(len=:), public, allocatable :: package_name Name of parent package integer, public :: schedule = -1 Targets in the same schedule group are guaranteed to be independent logical, public :: skip = .false. Flag set if build target will be skipped (not built) logical, public :: sorted = .false. Flag set if build target is sorted for building type( srcfile_t ), public, allocatable :: source Primary source for this build target integer, public :: target_type = FPM_TARGET_UNKNOWN Target type logical, public :: touched = .false. Flag set when first visited to check for circular dependencies character(len=:), public, allocatable :: version Version number Source Code type build_target_t !> File path of build target object relative to cwd character (:), allocatable :: output_file !> File path of build target object relative to output_dir character (:), allocatable :: output_name !> File path of output directory character (:), allocatable :: output_dir !> File path of build log file relative to cwd character (:), allocatable :: output_log_file !> Name of parent package character (:), allocatable :: package_name !> Primary source for this build target type ( srcfile_t ), allocatable :: source !> Resolved build dependencies type ( build_target_ptr ), allocatable :: dependencies (:) !> Target type integer :: target_type = FPM_TARGET_UNKNOWN !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Objects needed to link this target type ( string_t ), allocatable :: link_objects (:) !> Link flags for this build target character (:), allocatable :: link_flags !> Compile flags for this build target character (:), allocatable :: compile_flags !> Flag set when first visited to check for circular dependencies logical :: touched = . false . !> Flag set if build target is sorted for building logical :: sorted = . false . !> Flag set if build target will be skipped (not built) logical :: skip = . false . !> Language features type ( fortran_features_t ) :: features !> Targets in the same schedule group are guaranteed to be independent integer :: schedule = - 1 !> Previous source file hash integer ( int64 ), allocatable :: digest_cached !> List of macros type ( string_t ), allocatable :: macros (:) !> Version number character (:), allocatable :: version end type build_target_t","tags":"","loc":"type/build_target_t.html"},{"title":"build_progress_t – Fortran-lang/fpm ","text":"type, public :: build_progress_t Build progress object Contents Variables console n_complete n_target output_lines plain_mode target_queue Constructor build_progress_t Type-Bound Procedures compiling_status completed_status success Source Code build_progress_t Components Type Visibility Attributes Name Initial type( console_t ), public :: console Console object for updating console lines integer, public :: n_complete Number of completed targets integer, public :: n_target Total number of targets scheduled integer, public, allocatable :: output_lines (:) Store needed when updating previous console lines logical, public :: plain_mode = .true. ‘Plain’ output (no colors or updating) type( build_target_ptr ), public, pointer :: target_queue (:) Queue of scheduled build targets Constructor public interface build_progress_t Constructor for build_progress_t private function new_build_progress(target_queue, plain_mode) result(progress) Initialise a new build progress object Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in), target :: target_queue (:) The queue of scheduled targets logical, intent(in), optional :: plain_mode Enable ‘plain’ output for progress object Return Value type( build_progress_t ) Progress object to initialise Type-Bound Procedures procedure, public, :: compiling_status => output_status_compiling Output ‘compiling’ status for build target private subroutine output_status_compiling(progress, queue_index) Output ‘compiling’ status for build target and overall percentage progress Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress Progress object integer, intent(in) :: queue_index Index of build target in the target queue procedure, public, :: completed_status => output_status_complete Output ‘complete’ status for build target private subroutine output_status_complete(progress, queue_index, build_stat) Output ‘complete’ status for build target and update overall percentage progress Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress Progress object integer, intent(in) :: queue_index Index of build target in the target queue integer, intent(in) :: build_stat Build status flag procedure, public, :: success => output_progress_success Output finished status for whole package private subroutine output_progress_success(progress) Output finished status for whole package Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress Source Code type build_progress_t !> Console object for updating console lines type ( console_t ) :: console !> Number of completed targets integer :: n_complete !> Total number of targets scheduled integer :: n_target !> 'Plain' output (no colors or updating) logical :: plain_mode = . true . !> Store needed when updating previous console lines integer , allocatable :: output_lines (:) !> Queue of scheduled build targets type ( build_target_ptr ), pointer :: target_queue (:) contains !> Output 'compiling' status for build target procedure :: compiling_status => output_status_compiling !> Output 'complete' status for build target procedure :: completed_status => output_status_complete !> Output finished status for whole package procedure :: success => output_progress_success end type build_progress_t","tags":"","loc":"type/build_progress_t.html"},{"title":"fpm_build_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_build_settings Contents Variables archiver build_tests c_compiler cflag compiler cxx_compiler cxxflag flag ldflag list profile prune show_model verbose working_dir Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_build_settings.html"},{"title":"fpm_clean_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_clean_settings Contents Variables clean_call clean_skip verbose working_dir Components Type Visibility Attributes Name Initial logical, public :: clean_call = .false. logical, public :: clean_skip = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_clean_settings.html"},{"title":"fpm_cmd_settings – Fortran-lang/fpm ","text":"type, public, abstract :: fpm_cmd_settings Contents Variables verbose working_dir Components Type Visibility Attributes Name Initial logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_cmd_settings.html"},{"title":"fpm_install_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_install_settings Contents Variables archiver bindir build_tests c_compiler cflag compiler cxx_compiler cxxflag flag includedir ldflag libdir list no_rebuild prefix profile prune show_model verbose working_dir Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: bindir logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: includedir character(len=:), public, allocatable :: ldflag character(len=:), public, allocatable :: libdir logical, public :: list = .false. logical, public :: no_rebuild character(len=:), public, allocatable :: prefix character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_install_settings.html"},{"title":"fpm_new_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_new_settings Contents Variables backfill name verbose with_bare with_example with_executable with_full with_lib with_test working_dir Components Type Visibility Attributes Name Initial logical, public :: backfill = .true. character(len=:), public, allocatable :: name logical, public :: verbose = .true. logical, public :: with_bare = .false. logical, public :: with_example = .false. logical, public :: with_executable = .false. logical, public :: with_full = .false. logical, public :: with_lib = .true. logical, public :: with_test = .false. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_new_settings.html"},{"title":"fpm_publish_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_publish_settings Contents Variables archiver build_tests c_compiler cflag compiler cxx_compiler cxxflag flag is_dry_run ldflag list profile prune show_model show_package_version show_upload_data token verbose working_dir Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag logical, public :: is_dry_run = .false. character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: show_package_version = .false. logical, public :: show_upload_data = .false. character(len=:), public, allocatable :: token logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_publish_settings.html"},{"title":"fpm_run_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_run_settings Contents Variables archiver args build_tests c_compiler cflag compiler cxx_compiler cxxflag example flag ldflag list name profile prune runner runner_args show_model verbose working_dir Type-Bound Procedures runner_command Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure, public, :: runner_command private function runner_command(cmd) result(run_cmd) Build a full runner command (executable + command-line arguments)\nGet executable\nAppend command-line arguments Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(in) :: cmd Return Value character(len=:), allocatable","tags":"","loc":"type/fpm_run_settings.html"},{"title":"fpm_test_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_run_settings ) :: fpm_test_settings Contents Variables archiver args build_tests c_compiler cflag compiler cxx_compiler cxxflag example flag ldflag list name profile prune runner runner_args show_model verbose working_dir Type-Bound Procedures runner_command Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure, public, :: runner_command private function runner_command(cmd) result(run_cmd) Build a full runner command (executable + command-line arguments)\nGet executable\nAppend command-line arguments Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(in) :: cmd Return Value character(len=:), allocatable","tags":"","loc":"type/fpm_test_settings.html"},{"title":"fpm_update_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_update_settings Settings for interacting and updating with project dependencies Contents Variables clean fetch_only name verbose working_dir Components Type Visibility Attributes Name Initial logical, public :: clean logical, public :: fetch_only character(len=ibug), public, allocatable :: name (:) logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_update_settings.html"},{"title":"string_t – Fortran-lang/fpm ","text":"type, public :: string_t Contents Variables s Constructor string_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: s Constructor public interface string_t private function new_string_t(s) result(string) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s Return Value type( string_t )","tags":"","loc":"type/string_t.html"},{"title":"version_t – Fortran-lang/fpm ","text":"type, public :: version_t Contents Type-Bound Procedures operator(.match.) operator(/=) operator(<) operator(<=) operator(==) operator(>) operator(>=) s Source Code version_t Type-Bound Procedures generic, public, :: operator(.match.) => match Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) private elemental function match(lhs, rhs) Try to match first version against second version Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical Version match following semantic versioning rules generic, public, :: operator(/=) => not_equals private elemental function not_equals(lhs, rhs) result(not_equal) Check two versions for inequality Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical Version mismatch generic, public, :: operator(<) => less private elemental function less(lhs, rhs) result(is_less) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is less generic, public, :: operator(<=) => less_equals private elemental function less_equals(lhs, rhs) result(is_less_equal) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is less or equal generic, public, :: operator(==) => equals private elemental function equals(lhs, rhs) result(is_equal) Check to version numbers for equality Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical Version match generic, public, :: operator(>) => greater private elemental function greater(lhs, rhs) result(is_greater) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is greater generic, public, :: operator(>=) => greater_equals private elemental function greater_equals(lhs, rhs) result(is_greater_equal) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is greater or equal procedure, public, :: s Create a printable string from a version data type private pure function s(self) result(string) Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: self Version number Return Value character(len=:), allocatable Character representation of the version Source Code type :: version_t private !> Version numbers found integer , allocatable :: num (:) contains generic :: operator ( == ) => equals procedure , private :: equals generic :: operator ( /= ) => not_equals procedure , private :: not_equals generic :: operator ( > ) => greater procedure , private :: greater generic :: operator ( < ) => less procedure , private :: less generic :: operator ( >= ) => greater_equals procedure , private :: greater_equals generic :: operator ( <= ) => less_equals procedure , private :: less_equals !> Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) generic :: operator (. match .) => match procedure , private :: match !> Create a printable string from a version data type procedure :: s end type version_t","tags":"","loc":"type/version_t.html"},{"title":"enum_descriptor – Fortran-lang/fpm ","text":"type, public :: enum_descriptor Possible git target Contents Variables branch default revision tag Source Code enum_descriptor Components Type Visibility Attributes Name Initial integer, public :: branch = 201 Branch in git repository integer, public :: default = 200 Default target integer, public :: revision = 203 Commit hash integer, public :: tag = 202 Tag in git repository Source Code type :: enum_descriptor !> Default target integer :: default = 200 !> Branch in git repository integer :: branch = 201 !> Tag in git repository integer :: tag = 202 !> Commit hash integer :: revision = 203 end type enum_descriptor","tags":"","loc":"type/enum_descriptor.html"},{"title":"git_target_t – Fortran-lang/fpm ","text":"type, public :: git_target_t Description of an git target Contents Variables descriptor object url Type-Bound Procedures checkout info Source Code git_target_t Components Type Visibility Attributes Name Initial integer, public :: descriptor = git_descriptor%default Kind of the git target character(len=:), public, allocatable :: object Additional descriptor of the git object character(len=:), public, allocatable :: url Target URL of the git repository Type-Bound Procedures procedure, public, :: checkout Fetch and checkout in local directory public subroutine checkout (self, local_path, error) Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target character(len=*), intent(in) :: local_path Local path to checkout in type( error_t ), intent(out), allocatable :: error Error procedure, public, :: info Show information on instance public subroutine info (self, unit, verbosity) Show information on git target Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: git_target_t !> Kind of the git target integer :: descriptor = git_descriptor % default !> Target URL of the git repository character ( len = :), allocatable :: url !> Additional descriptor of the git object character ( len = :), allocatable :: object contains !> Fetch and checkout in local directory procedure :: checkout !> Show information on instance procedure :: info end type git_target_t","tags":"","loc":"type/git_target_t.html"},{"title":"dependency_node_t – Fortran-lang/fpm ","text":"type, public, extends( dependency_config_t ) :: dependency_node_t Dependency node in the projects dependency tree Contents Variables cached done git name namespace path preprocess proj_dir requested_version revision update version Type-Bound Procedures get_from_registry info register Source Code dependency_node_t Components Type Visibility Attributes Name Initial logical, public :: cached = .false. Dependency was loaded from a cache logical, public :: done = .false. Dependency is handled type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency character(len=:), public, allocatable :: proj_dir Installation prefix of this dependencies type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. character(len=:), public, allocatable :: revision Checked out revision of the version control system logical, public :: update = .false. Dependency should be updated type( version_t ), public, allocatable :: version Actual version of this dependency Type-Bound Procedures procedure, public, :: get_from_registry Get dependency from the registry. private subroutine get_from_registry(self, target_dir, global_settings, error, downloader_) Get a dependency from the registry. Whether the dependency is fetched\nfrom a local, a custom remote or the official registry is determined\nby the global configuration settings. Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(in) :: self Instance of the dependency configuration. character(len=:), intent(out), allocatable :: target_dir The target directory of the dependency. type( fpm_global_settings ), intent(in) :: global_settings Global configuration settings. type( error_t ), intent(out), allocatable :: error Error handling. class( downloader_t ), intent(in), optional :: downloader_ Downloader instance. procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Call base object info Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(in) :: self Instance of the dependency configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout procedure, public, :: register Update dependency from project manifest. private subroutine register(self, package, root, fetch, revision, error) Update dependency from project manifest Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(inout) :: self Instance of the dependency node type( package_config_t ), intent(in) :: package Package configuration data character(len=*), intent(in) :: root Root directory of the project logical, intent(in) :: fetch Project has been fetched character(len=*), intent(in), optional :: revision Git revision of the project type( error_t ), intent(out), allocatable :: error Error handling Source Code type , extends ( dependency_config_t ) :: dependency_node_t !> Actual version of this dependency type ( version_t ), allocatable :: version !> Installation prefix of this dependencies character ( len = :), allocatable :: proj_dir !> Checked out revision of the version control system character ( len = :), allocatable :: revision !> Dependency is handled logical :: done = . false . !> Dependency should be updated logical :: update = . false . !> Dependency was loaded from a cache logical :: cached = . false . contains !> Update dependency from project manifest. procedure :: register !> Get dependency from the registry. procedure :: get_from_registry procedure , private :: get_from_local_registry !> Print information on this instance procedure :: info end type dependency_node_t","tags":"","loc":"type/dependency_node_t.html"},{"title":"dependency_tree_t – Fortran-lang/fpm ","text":"type, public :: dependency_tree_t Respresentation of a projects dependencies The dependencies are stored in a simple array for now, this can be replaced\nwith a binary-search tree or a hash table in the future. Contents Variables cache dep dep_dir ndep unit verbosity Type-Bound Procedures add dump find finished has load resolve update Source Code dependency_tree_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cache Cache file type( dependency_node_t ), public, allocatable :: dep (:) Flattend list of all dependencies character(len=:), public, allocatable :: dep_dir Installation prefix for dependencies integer, public :: ndep = 0 Number of currently registered dependencies integer, public :: unit = output_unit Unit for IO integer, public :: verbosity = 1 Verbosity of printout Type-Bound Procedures generic, public, :: add => add_project, add_project_dependencies, add_dependencies, add_dependency, add_dependency_node Overload procedure to add new dependencies to the tree private subroutine add_project(self, package, error) Add project dependencies, each depth level after each other. We implement this algorithm in an interative rather than a recursive fashion\nas a choice of design. Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( package_config_t ), intent(in) :: package Project configuration to add type( error_t ), intent(out), allocatable :: error Error handling private recursive subroutine add_project_dependencies(self, package, root, main, error) Add a project and its dependencies to the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( package_config_t ), intent(in) :: package Project configuration to add character(len=*), intent(in) :: root Current project root directory logical, intent(in) :: main Is the main project type( error_t ), intent(out), allocatable :: error Error handling private subroutine add_dependencies(self, dependency, error) Add a list of dependencies to the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_config_t ), intent(in) :: dependency (:) Dependency configuration to add type( error_t ), intent(out), allocatable :: error Error handling private subroutine add_dependency(self, dependency, error) Add a single dependency to the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_config_t ), intent(in) :: dependency Dependency configuration to add type( error_t ), intent(out), allocatable :: error Error handling private subroutine add_dependency_node(self, dependency, error) Add a single dependency node to the dependency tree\nDependency nodes contain additional information (version, git, revision) Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_node_t ), intent(in) :: dependency Dependency configuration to add type( error_t ), intent(out), allocatable :: error Error handling generic, public, :: dump => dump_to_file, dump_to_unit, dump_to_toml Writing of dependency tree private subroutine dump_to_file(self, file, error) Write dependency tree to file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_unit(self, unit, error) Write dependency tree to file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_toml(self, table, error) Write dependency tree to TOML datastructure Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public, :: find => find_name Find a dependency in the tree private pure function find_name(self, name) result(pos) Find a dependency in the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: self Instance of the dependency tree character(len=*), intent(in) :: name Dependency configuration to add Return Value integer Index of the dependency procedure, public, :: finished Depedendncy resolution finished private pure function finished(self) Check if we are done with the dependency resolution Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: self Instance of the dependency tree Return Value logical All dependencies are updated generic, public, :: has => has_dependency True if entity can be found private pure function has_dependency(self, dependency) True if dependency is part of the tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: self Instance of the dependency tree class( dependency_node_t ), intent(in) :: dependency Dependency configuration to check Return Value logical generic, public, :: load => load_from_file, load_from_unit, load_from_toml Reading of dependency tree private subroutine load_from_file(self, file, error) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_unit(self, unit, error) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_toml(self, table, error) Read dependency tree from TOML data structure Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public, :: resolve => resolve_dependencies, resolve_dependency Resolve dependencies private subroutine resolve_dependencies(self, root, error) Resolve all dependencies in the tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: root Current installation prefix type( error_t ), intent(out), allocatable :: error Error handling private subroutine resolve_dependency(self, dependency, global_settings, root, error) Resolve a single dependency node Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_node_t ), intent(inout) :: dependency Dependency configuration to add type( fpm_global_settings ), intent(in) :: global_settings Global configuration settings. character(len=*), intent(in) :: root Current installation prefix type( error_t ), intent(out), allocatable :: error Error handling generic, public, :: update => update_dependency, update_tree Update dependency tree private subroutine update_dependency(self, name, error) Update dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: name Name of the dependency to update type( error_t ), intent(out), allocatable :: error Error handling private subroutine update_tree(self, error) Update whole dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( error_t ), intent(out), allocatable :: error Error handling Source Code type :: dependency_tree_t !> Unit for IO integer :: unit = output_unit !> Verbosity of printout integer :: verbosity = 1 !> Installation prefix for dependencies character ( len = :), allocatable :: dep_dir !> Number of currently registered dependencies integer :: ndep = 0 !> Flattend list of all dependencies type ( dependency_node_t ), allocatable :: dep (:) !> Cache file character ( len = :), allocatable :: cache contains !> Overload procedure to add new dependencies to the tree generic :: add => add_project , add_project_dependencies , add_dependencies , & add_dependency , add_dependency_node !> Main entry point to add a project procedure , private :: add_project !> Add a project and its dependencies to the dependency tree procedure , private :: add_project_dependencies !> Add a list of dependencies to the dependency tree procedure , private :: add_dependencies !> Add a single dependency to the dependency tree procedure , private :: add_dependency !> Add a single dependency node to the dependency tree procedure , private :: add_dependency_node !> Resolve dependencies generic :: resolve => resolve_dependencies , resolve_dependency !> Resolve dependencies procedure , private :: resolve_dependencies !> Resolve dependency procedure , private :: resolve_dependency !> True if entity can be found generic :: has => has_dependency !> True if dependency is part of the tree procedure , private :: has_dependency !> Find a dependency in the tree generic :: find => find_name !> Find a dependency by its name procedure , private :: find_name !> Depedendncy resolution finished procedure :: finished !> Reading of dependency tree generic :: load => load_from_file , load_from_unit , load_from_toml !> Read dependency tree from file procedure , private :: load_from_file !> Read dependency tree from formatted unit procedure , private :: load_from_unit !> Read dependency tree from TOML data structure procedure , private :: load_from_toml !> Writing of dependency tree generic :: dump => dump_to_file , dump_to_unit , dump_to_toml !> Write dependency tree to file procedure , private :: dump_to_file !> Write dependency tree to formatted unit procedure , private :: dump_to_unit !> Write dependency tree to TOML data structure procedure , private :: dump_to_toml !> Update dependency tree generic :: update => update_dependency , update_tree !> Update a list of dependencies procedure , private :: update_dependency !> Update all dependencies in the tree procedure , private :: update_tree end type dependency_tree_t","tags":"","loc":"type/dependency_tree_t.html"},{"title":"installer_t – Fortran-lang/fpm ","text":"type, public :: installer_t Declaration of the installer type Contents Variables bindir copy includedir libdir move os prefix unit verbosity Type-Bound Procedures install install_executable install_header install_library make_dir run Source Code installer_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: bindir Binary dir relative to the installation prefix character(len=:), public, allocatable :: copy Command to copy objects into the installation prefix character(len=:), public, allocatable :: includedir Include directory relative to the installation prefix character(len=:), public, allocatable :: libdir Library directory relative to the installation prefix character(len=:), public, allocatable :: move Command to move objects into the installation prefix integer, public :: os Cached operating system character(len=:), public, allocatable :: prefix Path to installation directory integer, public :: unit = output_unit Output unit for informative printout integer, public :: verbosity = 1 Verbosity of the installer Type-Bound Procedures procedure, public, :: install Install a generic file into a subdirectory in the installation prefix private subroutine install(self, source, destination, error) Install a generic file into a subdirectory in the installation prefix Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: source Path to the original file character(len=*), intent(in) :: destination Path to the destination inside the prefix type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: install_executable Install an executable in its correct subdirectory private subroutine install_executable(self, executable, error) Install an executable in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: executable Path to the executable type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: install_header Install a header/module in its correct subdirectory private subroutine install_header(self, header, error) Install a header/module in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: header Path to the header type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: install_library Install a library in its correct subdirectory private subroutine install_library(self, library, error) Install a library in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: library Path to the library type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: make_dir Create a new directory in the prefix, type-bound for unit testing purposes private subroutine make_dir(self, dir, error) Create a new directory in the prefix Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: dir Directory to be created type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: run Run an installation command, type-bound for unit testing purposes private subroutine run(self, command, error) Run an installation command Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: command Command to be launched type( error_t ), intent(out), allocatable :: error Error handling Source Code type :: installer_t !> Path to installation directory character ( len = :), allocatable :: prefix !> Binary dir relative to the installation prefix character ( len = :), allocatable :: bindir !> Library directory relative to the installation prefix character ( len = :), allocatable :: libdir !> Include directory relative to the installation prefix character ( len = :), allocatable :: includedir !> Output unit for informative printout integer :: unit = output_unit !> Verbosity of the installer integer :: verbosity = 1 !> Command to copy objects into the installation prefix character ( len = :), allocatable :: copy !> Command to move objects into the installation prefix character ( len = :), allocatable :: move !> Cached operating system integer :: os contains !> Install an executable in its correct subdirectory procedure :: install_executable !> Install a library in its correct subdirectory procedure :: install_library !> Install a header/module in its correct subdirectory procedure :: install_header !> Install a generic file into a subdirectory in the installation prefix procedure :: install !> Run an installation command, type-bound for unit testing purposes procedure :: run !> Create a new directory in the prefix, type-bound for unit testing purposes procedure :: make_dir end type installer_t","tags":"","loc":"type/installer_t.html"},{"title":"downloader_t – Fortran-lang/fpm ","text":"type, public :: downloader_t This type could be entirely avoided but it is quite practical because it can be mocked for testing. Contents Type-Bound Procedures get_file get_pkg_data unpack upload_form Type-Bound Procedures procedure, public, nopass :: get_file private subroutine get_file(url, tmp_pkg_file, error) Download a file from a url using either curl or wget. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url character(len=*), intent(in) :: tmp_pkg_file type( error_t ), intent(out), allocatable :: error procedure, public, nopass :: get_pkg_data private subroutine get_pkg_data(url, version, tmp_pkg_file, json, error) Perform an http get request, save output to file, and parse json. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url type( version_t ), intent(in), allocatable :: version character(len=*), intent(in) :: tmp_pkg_file type(json_object), intent(out) :: json type( error_t ), intent(out), allocatable :: error procedure, public, nopass :: unpack private subroutine unpack(tmp_pkg_file, destination, error) Unpack a tarball to a destination. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: tmp_pkg_file Path to tarball. character(len=*), intent(in) :: destination Destination to unpack to. type( error_t ), intent(out), allocatable :: error Error handling. procedure, public, nopass :: upload_form private subroutine upload_form(endpoint, form_data, verbose, error) Perform an http post request with form data. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: endpoint Endpoint to upload to. type( string_t ), intent(in) :: form_data (:) Form data to upload. logical, intent(in) :: verbose Print additional information if true. type( error_t ), intent(out), allocatable :: error Error handling.","tags":"","loc":"type/downloader_t.html"},{"title":"error_t – Fortran-lang/fpm ","text":"type, public :: error_t Data type defining an error Contents Variables message Source Code error_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: message Error message Source Code type :: error_t !> Error message character ( len = :), allocatable :: message end type error_t","tags":"","loc":"type/error_t.html"},{"title":"install_config_t – Fortran-lang/fpm ","text":"type, public :: install_config_t Configuration data for installation Contents Variables library Type-Bound Procedures info Source Code install_config_t Components Type Visibility Attributes Name Initial logical, public :: library Install library with this project Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on install configuration instance Arguments Type Intent Optional Attributes Name class( install_config_t ), intent(in) :: self Instance of the build configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: install_config_t !> Install library with this project logical :: library contains !> Print information on this instance procedure :: info end type install_config_t","tags":"","loc":"type/install_config_t.html"},{"title":"example_config_t – Fortran-lang/fpm ","text":"type, public, extends( executable_config_t ) :: example_config_t Configuation meta data for an example Contents Variables dependency link main name source_dir Type-Bound Procedures info Source Code example_config_t Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( example_config_t ), intent(in) :: self Instance of the example configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type , extends ( executable_config_t ) :: example_config_t contains !> Print information on this instance procedure :: info end type example_config_t","tags":"","loc":"type/example_config_t.html"},{"title":"test_config_t – Fortran-lang/fpm ","text":"type, public, extends( executable_config_t ) :: test_config_t Configuation meta data for an test Contents Variables dependency link main name source_dir Type-Bound Procedures info Source Code test_config_t Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( test_config_t ), intent(in) :: self Instance of the test configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type , extends ( executable_config_t ) :: test_config_t contains !> Print information on this instance procedure :: info end type test_config_t","tags":"","loc":"type/test_config_t.html"},{"title":"fortran_config_t – Fortran-lang/fpm ","text":"type, public :: fortran_config_t Configuration data for Fortran Contents Variables implicit_external implicit_typing source_form Source Code fortran_config_t Components Type Visibility Attributes Name Initial logical, public :: implicit_external Enable implicit external interfaces logical, public :: implicit_typing Enable default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Source Code type :: fortran_config_t !> Enable default implicit typing logical :: implicit_typing !> Enable implicit external interfaces logical :: implicit_external !> Form to use for all Fortran sources character (:), allocatable :: source_form end type fortran_config_t","tags":"","loc":"type/fortran_config_t.html"},{"title":"dependency_config_t – Fortran-lang/fpm ","text":"type, public :: dependency_config_t Configuration meta data for a dependency Contents Variables git name namespace path preprocess requested_version Type-Bound Procedures info Source Code dependency_config_t Components Type Visibility Attributes Name Initial type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: self Instance of the dependency configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: dependency_config_t !> Name of the dependency character ( len = :), allocatable :: name !> Local target character ( len = :), allocatable :: path !> Namespace which the dependency belongs to. !> Enables multiple dependencies with the same name. !> Required for dependencies that are obtained via the official registry. character ( len = :), allocatable :: namespace !> The requested version of the dependency. !> The latest version is used if not specified. type ( version_t ), allocatable :: requested_version !> Requested macros for the dependency type ( preprocess_config_t ), allocatable :: preprocess (:) !> Git descriptor type ( git_target_t ), allocatable :: git contains !> Print information on this instance procedure :: info end type dependency_config_t","tags":"","loc":"type/dependency_config_t.html"},{"title":"package_config_t – Fortran-lang/fpm ","text":"type, public :: package_config_t Package meta data Contents Variables build dependency dev_dependency example executable fortran install library license meta name preprocess profiles test version Type-Bound Procedures info Source Code package_config_t Components Type Visibility Attributes Name Initial type( build_config_t ), public :: build Build configuration data type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data type( dependency_config_t ), public, allocatable :: dev_dependency (:) Development dependency meta data type( example_config_t ), public, allocatable :: example (:) Example meta data type( executable_config_t ), public, allocatable :: executable (:) Executable meta data type( fortran_config_t ), public :: fortran Fortran meta data type( install_config_t ), public :: install Installation configuration data type( library_config_t ), public, allocatable :: library Library meta data character(len=:), public, allocatable :: license License meta data type( metapackage_config_t ), public :: meta Metapackage data character(len=:), public, allocatable :: name Name of the package type( preprocess_config_t ), public, allocatable :: preprocess (:) Preprocess meta data type( profile_config_t ), public, allocatable :: profiles (:) Profiles meta data type( test_config_t ), public, allocatable :: test (:) Test meta data type( version_t ), public :: version Package version Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( package_config_t ), intent(in) :: self Instance of the package configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: package_config_t !> Name of the package character ( len = :), allocatable :: name !> Package version type ( version_t ) :: version !> Build configuration data type ( build_config_t ) :: build !> Metapackage data type ( metapackage_config_t ) :: meta !> Installation configuration data type ( install_config_t ) :: install !> Fortran meta data type ( fortran_config_t ) :: fortran !> License meta data character ( len = :), allocatable :: license !> Library meta data type ( library_config_t ), allocatable :: library !> Executable meta data type ( executable_config_t ), allocatable :: executable (:) !> Dependency meta data type ( dependency_config_t ), allocatable :: dependency (:) !> Development dependency meta data type ( dependency_config_t ), allocatable :: dev_dependency (:) !> Profiles meta data type ( profile_config_t ), allocatable :: profiles (:) !> Example meta data type ( example_config_t ), allocatable :: example (:) !> Test meta data type ( test_config_t ), allocatable :: test (:) !> Preprocess meta data type ( preprocess_config_t ), allocatable :: preprocess (:) contains !> Print information on this instance procedure :: info end type package_config_t","tags":"","loc":"type/package_config_t.html"},{"title":"executable_config_t – Fortran-lang/fpm ","text":"type, public :: executable_config_t Configuation meta data for an executable Contents Variables dependency link main name source_dir Type-Bound Procedures info Source Code executable_config_t Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(in) :: self Instance of the executable configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: executable_config_t !> Name of the resulting executable character ( len = :), allocatable :: name !> Source directory for collecting the executable character ( len = :), allocatable :: source_dir !> Name of the source file declaring the main program character ( len = :), allocatable :: main !> Dependency meta data for this executable type ( dependency_config_t ), allocatable :: dependency (:) !> Libraries to link against type ( string_t ), allocatable :: link (:) contains !> Print information on this instance procedure :: info end type executable_config_t","tags":"","loc":"type/executable_config_t.html"},{"title":"metapackage_config_t – Fortran-lang/fpm ","text":"type, public :: metapackage_config_t Configuration data for metapackages Contents Variables minpack mpi openmp stdlib Source Code metapackage_config_t Components Type Visibility Attributes Name Initial type( metapackage_request_t ), public :: minpack fortran-lang minpack type( metapackage_request_t ), public :: mpi Request MPI support type( metapackage_request_t ), public :: openmp Request OpenMP support type( metapackage_request_t ), public :: stdlib Request stdlib support Source Code type :: metapackage_config_t !> Request MPI support type ( metapackage_request_t ) :: mpi !> Request OpenMP support type ( metapackage_request_t ) :: openmp !> Request stdlib support type ( metapackage_request_t ) :: stdlib !> fortran-lang minpack type ( metapackage_request_t ) :: minpack end type metapackage_config_t","tags":"","loc":"type/metapackage_config_t.html"},{"title":"metapackage_request_t – Fortran-lang/fpm ","text":"type, public :: metapackage_request_t Configuration data for a single metapackage request Contents Variables name on version Source Code metapackage_request_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: name Metapackage name logical, public :: on = .false. Request flag character(len=:), public, allocatable :: version Version Specification string Source Code type :: metapackage_request_t !> Request flag logical :: on = . false . !> Metapackage name character ( len = :), allocatable :: name !> Version Specification string character ( len = :), allocatable :: version end type metapackage_request_t","tags":"","loc":"type/metapackage_request_t.html"},{"title":"library_config_t – Fortran-lang/fpm ","text":"type, public :: library_config_t Configuration meta data for a library Contents Variables build_script include_dir source_dir Type-Bound Procedures info Source Code library_config_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: build_script Alternative build script to be invoked type( string_t ), public, allocatable :: include_dir (:) Include path prefix character(len=:), public, allocatable :: source_dir Source path prefix Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( library_config_t ), intent(in) :: self Instance of the library configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: library_config_t !> Source path prefix character ( len = :), allocatable :: source_dir !> Include path prefix type ( string_t ), allocatable :: include_dir (:) !> Alternative build script to be invoked character ( len = :), allocatable :: build_script contains !> Print information on this instance procedure :: info end type library_config_t","tags":"","loc":"type/library_config_t.html"},{"title":"file_scope_flag – Fortran-lang/fpm ","text":"type, public :: file_scope_flag Type storing file name - file scope compiler flags pairs Contents Variables file_name flags Source Code file_scope_flag Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: file_name Name of the file character(len=:), public, allocatable :: flags File scope flags Source Code type :: file_scope_flag !> Name of the file character ( len = :), allocatable :: file_name !> File scope flags character ( len = :), allocatable :: flags end type file_scope_flag","tags":"","loc":"type/file_scope_flag.html"},{"title":"profile_config_t – Fortran-lang/fpm ","text":"type, public :: profile_config_t Configuration meta data for a profile Contents Variables c_flags compiler cxx_flags file_scope_flags flags is_built_in link_time_flags os_type profile_name Type-Bound Procedures info Source Code profile_config_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags C compiler flags character(len=:), public, allocatable :: compiler Name of the compiler character(len=:), public, allocatable :: cxx_flags C++ compiler flags type( file_scope_flag ), public, allocatable :: file_scope_flags (:) File scope flags character(len=:), public, allocatable :: flags Fortran compiler flags logical, public :: is_built_in Is this profile one of the built-in ones? character(len=:), public, allocatable :: link_time_flags Link time compiler flags integer, public :: os_type Value repesenting OS character(len=:), public, allocatable :: profile_name Name of the profile Type-Bound Procedures procedure, public, :: info Print information on this instance public subroutine info (self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: self Instance of the profile configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: profile_config_t !> Name of the profile character ( len = :), allocatable :: profile_name !> Name of the compiler character ( len = :), allocatable :: compiler !> Value repesenting OS integer :: os_type !> Fortran compiler flags character ( len = :), allocatable :: flags !> C compiler flags character ( len = :), allocatable :: c_flags !> C++ compiler flags character ( len = :), allocatable :: cxx_flags !> Link time compiler flags character ( len = :), allocatable :: link_time_flags !> File scope flags type ( file_scope_flag ), allocatable :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical :: is_built_in contains !> Print information on this instance procedure :: info end type profile_config_t","tags":"","loc":"type/profile_config_t.html"},{"title":"preprocess_config_t – Fortran-lang/fpm ","text":"type, public :: preprocess_config_t Configuration meta data for a preprocessor Contents Variables directories macros name suffixes Type-Bound Procedures info Source Code preprocess_config_t Components Type Visibility Attributes Name Initial type( string_t ), public, allocatable :: directories (:) Directories to search for files to be preprocessed type( string_t ), public, allocatable :: macros (:) Macros to be defined for the preprocessor character(len=:), public, allocatable :: name Name of the preprocessor type( string_t ), public, allocatable :: suffixes (:) Suffixes of the files to be preprocessed Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on this instance Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: self Instance of the preprocess configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: preprocess_config_t !> Name of the preprocessor character ( len = :), allocatable :: name !> Suffixes of the files to be preprocessed type ( string_t ), allocatable :: suffixes (:) !> Directories to search for files to be preprocessed type ( string_t ), allocatable :: directories (:) !> Macros to be defined for the preprocessor type ( string_t ), allocatable :: macros (:) contains !> Print information on this instance procedure :: info end type preprocess_config_t","tags":"","loc":"type/preprocess_config_t.html"},{"title":"build_config_t – Fortran-lang/fpm ","text":"type, public :: build_config_t Configuration data for build Contents Variables auto_examples auto_executables auto_tests external_modules link module_naming module_prefix Type-Bound Procedures info Source Code build_config_t Components Type Visibility Attributes Name Initial logical, public :: auto_examples Automatic discovery of examples logical, public :: auto_executables Automatic discovery of executables logical, public :: auto_tests Automatic discovery of tests type( string_t ), public, allocatable :: external_modules (:) External modules to use type( string_t ), public, allocatable :: link (:) Libraries to link against logical, public :: module_naming = .false. Enforcing of package module names type( string_t ), public :: module_prefix Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on build configuration instance Arguments Type Intent Optional Attributes Name class( build_config_t ), intent(in) :: self Instance of the build configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: build_config_t !> Automatic discovery of executables logical :: auto_executables !> Automatic discovery of examples logical :: auto_examples !> Automatic discovery of tests logical :: auto_tests !> Enforcing of package module names logical :: module_naming = . false . type ( string_t ) :: module_prefix !> Libraries to link against type ( string_t ), allocatable :: link (:) !> External modules to use type ( string_t ), allocatable :: external_modules (:) contains !> Print information on this instance procedure :: info end type build_config_t","tags":"","loc":"type/build_config_t.html"},{"title":"get_global_settings – Fortran-lang/fpm","text":"public subroutine get_global_settings(global_settings, error) Obtain global settings from the global config file. Arguments Type Intent Optional Attributes Name type( fpm_global_settings ), intent(inout) :: global_settings Global settings to be obtained. type( error_t ), intent(out), allocatable :: error Error reading config file. Contents","tags":"","loc":"proc/get_global_settings.html"},{"title":"get_registry_settings – Fortran-lang/fpm","text":"public subroutine get_registry_settings(table, global_settings, error) Read registry settings from the global config file. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout), target :: table The [registry] subtable from the global config file. type( fpm_global_settings ), intent(inout) :: global_settings The global settings which can be filled with the registry settings. type( error_t ), intent(out), allocatable :: error Error handling. Contents","tags":"","loc":"proc/get_registry_settings.html"},{"title":"show_model – Fortran-lang/fpm","text":"public subroutine show_model(model) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model Contents Source Code show_model Source Code subroutine show_model ( model ) ! Prints a human readable representation of the Model type ( fpm_model_t ), intent ( in ) :: model print * , info_model ( model ) end subroutine show_model","tags":"","loc":"proc/show_model.html"},{"title":"check_compiler – Fortran-lang/fpm","text":"public function check_compiler(compiler, expected) result(match) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler character(len=*), intent(in) :: expected Return Value logical Contents Source Code check_compiler Source Code function check_compiler ( compiler , expected ) result ( match ) character ( len =* ), intent ( in ) :: compiler character ( len =* ), intent ( in ) :: expected logical :: match match = compiler == expected if (. not . match ) then match = index ( basename ( compiler ), expected ) > 0 end if end function check_compiler","tags":"","loc":"proc/check_compiler.html"},{"title":"compiler_name – Fortran-lang/fpm","text":"public pure function compiler_name(self) result(name) Return a compiler name string Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string Contents Source Code compiler_name Source Code pure function compiler_name ( self ) result ( name ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: name select case ( self % id ) case ( id_gcc ); name = \"gfortran\" case ( id_f95 ); name = \"f95\" case ( id_caf ); name = \"caf\" case ( id_intel_classic_nix ); name = \"ifort\" case ( id_intel_classic_mac ); name = \"ifort\" case ( id_intel_classic_windows ); name = \"ifort\" case ( id_intel_llvm_nix ); name = \"ifx\" case ( id_intel_llvm_windows ); name = \"ifx\" case ( id_intel_llvm_unknown ); name = \"ifx\" case ( id_pgi ); name = \"pgfortran\" case ( id_nvhpc ); name = \"nvfortran\" case ( id_nag ); name = \"nagfor\" case ( id_flang ); name = \"flang\" case ( id_flang_new ); name = \"flang-new\" case ( id_f18 ); name = \"f18\" case ( id_ibmxl ); name = \"xlf90\" case ( id_cray ); name = \"crayftn\" case ( id_lahey ); name = \"lfc\" case ( id_lfortran ); name = \"lFortran\" case default ; name = \"invalid/unknown\" end select end function compiler_name","tags":"","loc":"proc/compiler_name.html"},{"title":"debug_archiver – Fortran-lang/fpm","text":"public pure function debug_archiver(self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string Contents Source Code debug_archiver Source Code pure function debug_archiver ( self ) result ( repr ) !> Instance of the archiver object type ( archiver_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'ar=\"' // self % ar // '\"' end function debug_archiver","tags":"","loc":"proc/debug_archiver.html"},{"title":"debug_compiler – Fortran-lang/fpm","text":"public pure function debug_compiler(self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string Contents Source Code debug_compiler Source Code pure function debug_compiler ( self ) result ( repr ) !> Instance of the compiler object type ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'fc=\"' // self % fc // '\", cc=\"' // self % cc // '\"' end function debug_compiler","tags":"","loc":"proc/debug_compiler.html"},{"title":"enumerate_libraries – Fortran-lang/fpm","text":"public function enumerate_libraries(self, prefix, libs) result(r) Enumerate libraries, based on compiler and platform Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: prefix type( string_t ), intent(in) :: libs (:) Return Value character(len=:), allocatable Contents Source Code enumerate_libraries Source Code function enumerate_libraries ( self , prefix , libs ) result ( r ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: prefix type ( string_t ), intent ( in ) :: libs (:) character ( len = :), allocatable :: r if ( self % id == id_intel_classic_windows . or . & self % id == id_intel_llvm_windows ) then r = prefix // \" \" // string_cat ( libs , \".lib \" ) // \".lib\" else r = prefix // \" -l\" // string_cat ( libs , \" -l\" ) end if end function enumerate_libraries","tags":"","loc":"proc/enumerate_libraries.html"},{"title":"get_compiler_id – Fortran-lang/fpm","text":"public function get_compiler_id(compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) Contents Variables command full_command full_command_parts io output stat Source Code get_compiler_id Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: command character(len=:), public, allocatable :: full_command character(len=:), public, allocatable :: full_command_parts (:) integer, public :: io character(len=:), public, allocatable :: output integer, public :: stat Source Code function get_compiler_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id character ( len = :), allocatable :: full_command , full_command_parts (:), command , output integer :: stat , io ! Check whether we are dealing with an MPI compiler wrapper first if ( check_compiler ( compiler , \"mpifort\" ) & & . or . check_compiler ( compiler , \"mpif90\" ) & & . or . check_compiler ( compiler , \"mpif77\" )) then output = get_temp_filename () call run ( compiler // \" -show > \" // output // \" 2>&1\" , & & echo = . false ., exitstat = stat ) if ( stat == 0 ) then open ( file = output , newunit = io , iostat = stat ) if ( stat == 0 ) call getline ( io , full_command , stat ) close ( io , iostat = stat ) ! If we get a command from the wrapper, we will try to identify it call split ( full_command , full_command_parts , delimiters = ' ' ) if ( size ( full_command_parts ) > 0 ) then command = trim ( full_command_parts ( 1 )) endif if ( allocated ( command )) then id = get_id ( command ) if ( id /= id_unknown ) return end if end if end if id = get_id ( compiler ) end function get_compiler_id","tags":"","loc":"proc/get_compiler_id.html"},{"title":"get_default_flags – Fortran-lang/fpm","text":"public function get_default_flags(self, release) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self logical, intent(in) :: release Return Value character(len=:), allocatable Contents Source Code get_default_flags Source Code function get_default_flags ( self , release ) result ( flags ) class ( compiler_t ), intent ( in ) :: self logical , intent ( in ) :: release character ( len = :), allocatable :: flags if ( release ) then call get_release_compile_flags ( self % id , flags ) else call get_debug_compile_flags ( self % id , flags ) end if end function get_default_flags","tags":"","loc":"proc/get_default_flags.html"},{"title":"get_feature_flag – Fortran-lang/fpm","text":"public function get_feature_flag(self, feature) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: feature Return Value character(len=:), allocatable Contents Source Code get_feature_flag Source Code function get_feature_flag ( self , feature ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: feature character ( len = :), allocatable :: flags flags = \"\" select case ( feature ) case ( \"no-implicit-typing\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_typing case ( id_nag ) flags = flag_nag_no_implicit_typing case ( id_cray ) flags = flag_cray_no_implicit_typing end select case ( \"implicit-typing\" ) select case ( self % id ) case ( id_cray ) flags = flag_cray_implicit_typing case ( id_lfortran ) flags = flag_lfortran_implicit_typing end select case ( \"no-implicit-external\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_external end select case ( \"implicit-external\" ) select case ( self % id ) case ( id_lfortran ) flags = flag_lfortran_implicit_external end select case ( \"free-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_free_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_free_form case ( id_nag ) flags = flag_nag_free_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_free_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_free_form_win case ( id_cray ) flags = flag_cray_free_form end select case ( \"fixed-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_fixed_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_fixed_form case ( id_nag ) flags = flag_nag_fixed_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_fixed_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_fixed_form_win case ( id_cray ) flags = flag_cray_fixed_form case ( id_lfortran ) flags = flag_lfortran_fixed_form end select case ( \"default-form\" ) continue case default error stop \"Unknown feature '\" // feature // \"'\" end select end function get_feature_flag","tags":"","loc":"proc/get_feature_flag.html"},{"title":"get_id – Fortran-lang/fpm","text":"public function get_id(compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) Contents Source Code get_id Source Code function get_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id if ( check_compiler ( compiler , \"gfortran\" )) then id = id_gcc return end if if ( check_compiler ( compiler , \"f95\" )) then id = id_f95 return end if if ( check_compiler ( compiler , \"caf\" )) then id = id_caf return end if if ( check_compiler ( compiler , \"ifort\" )) then select case ( get_os_type ()) case default id = id_intel_classic_nix case ( OS_MACOS ) id = id_intel_classic_mac case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_classic_windows end select return end if if ( check_compiler ( compiler , \"ifx\" )) then select case ( get_os_type ()) case default id = id_intel_llvm_nix case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_llvm_windows end select return end if if ( check_compiler ( compiler , \"nvfortran\" )) then id = id_nvhpc return end if if ( check_compiler ( compiler , \"pgfortran\" ) & & . or . check_compiler ( compiler , \"pgf90\" ) & & . or . check_compiler ( compiler , \"pgf95\" )) then id = id_pgi return end if if ( check_compiler ( compiler , \"nagfor\" )) then id = id_nag return end if if ( check_compiler ( compiler , \"flang-new\" )) then id = id_flang_new return end if if ( check_compiler ( compiler , \"f18\" )) then id = id_f18 return end if if ( check_compiler ( compiler , \"flang\" )) then id = id_flang return end if if ( check_compiler ( compiler , \"xlf90\" )) then id = id_ibmxl return end if if ( check_compiler ( compiler , \"crayftn\" )) then id = id_cray return end if if ( check_compiler ( compiler , \"lfc\" )) then id = id_lahey return end if if ( check_compiler ( compiler , \"lfortran\" )) then id = id_lfortran return end if id = id_unknown end function get_id","tags":"","loc":"proc/get_id.html"},{"title":"get_include_flag – Fortran-lang/fpm","text":"public function get_include_flag(self, path) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code get_include_flag Source Code function get_include_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-I \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_nvhpc , id_pgi , & & id_flang , id_flang_new , id_f18 , & & id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix , id_lahey , id_nag , id_ibmxl , & & id_lfortran ) flags = \"-I \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/I\" // path end select end function get_include_flag","tags":"","loc":"proc/get_include_flag.html"},{"title":"get_macros – Fortran-lang/fpm","text":"public function get_macros(id, macros_list, version) result(macros) This function will parse and read the macros list and\nreturn them as defined flags.\nSet macro defintion symbol on the basis of compiler used\nCheck if macros are not allocated.\nSplit the macro name and value. Check if the value of macro starts with ‘{‘ character. Check if the value of macro ends with ‘}’ character. Check if the string contains “version” as substring. These conditions are placed in order to ensure proper spacing between the macros. Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id type( string_t ), intent(in), allocatable :: macros_list (:) character(len=:), intent(in), allocatable :: version Return Value character(len=:), allocatable Contents Variables i macro_definition_symbol valued_macros Source Code get_macros Variables Type Visibility Attributes Name Initial integer, public :: i character(len=:), public, allocatable :: macro_definition_symbol character(len=:), public, allocatable :: valued_macros (:) Source Code function get_macros ( id , macros_list , version ) result ( macros ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( in ) :: version type ( string_t ), allocatable , intent ( in ) :: macros_list (:) character ( len = :), allocatable :: macros character ( len = :), allocatable :: macro_definition_symbol character (:), allocatable :: valued_macros (:) integer :: i if (. not . allocated ( macros_list )) then macros = \"\" return end if !> Set macro defintion symbol on the basis of compiler used select case ( id ) case default macro_definition_symbol = \" -D\" case ( id_intel_classic_windows , id_intel_llvm_windows ) macro_definition_symbol = \" /D\" end select !> Check if macros are not allocated. if (. not . allocated ( macros )) then macros = \"\" end if do i = 1 , size ( macros_list ) !> Split the macro name and value. call split ( macros_list ( i )% s , valued_macros , delimiters = \"=\" ) if ( size ( valued_macros ) > 1 ) then !> Check if the value of macro starts with '{' character. if ( str_begins_with_str ( trim ( valued_macros ( size ( valued_macros ))), \"{\" )) then !> Check if the value of macro ends with '}' character. if ( str_ends_with ( trim ( valued_macros ( size ( valued_macros ))), \"}\" )) then !> Check if the string contains \"version\" as substring. if ( index ( valued_macros ( size ( valued_macros )), \"version\" ) /= 0 ) then !> These conditions are placed in order to ensure proper spacing between the macros. macros = macros // macro_definition_symbol // trim ( valued_macros ( 1 )) // '=' // version cycle end if end if end if end if macros = macros // macro_definition_symbol // macros_list ( i )% s end do end function get_macros","tags":"","loc":"proc/get_macros.html"},{"title":"get_module_flag – Fortran-lang/fpm","text":"public function get_module_flag(self, path) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code get_module_flag Source Code function get_module_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-module \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_lfortran ) flags = \"-J \" // path case ( id_nvhpc , id_pgi , id_flang ) flags = \"-module \" // path case ( id_flang_new , id_f18 ) flags = \"-module-dir \" // path case ( id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix ) flags = \"-module \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/module:\" // path case ( id_lahey ) flags = \"-M \" // path case ( id_nag ) flags = \"-mdir \" // path case ( id_ibmxl ) flags = \"-qmoddir \" // path end select end function get_module_flag","tags":"","loc":"proc/get_module_flag.html"},{"title":"is_gnu – Fortran-lang/fpm","text":"public pure function is_gnu(self) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Contents Source Code is_gnu Source Code pure logical function is_gnu ( self ) class ( compiler_t ), intent ( in ) :: self is_gnu = any ( self % id == [ id_f95 , id_gcc , id_caf ]) end function is_gnu","tags":"","loc":"proc/is_gnu.html"},{"title":"is_intel – Fortran-lang/fpm","text":"public pure function is_intel(self) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Contents Source Code is_intel Source Code pure logical function is_intel ( self ) class ( compiler_t ), intent ( in ) :: self is_intel = any ( self % id == [ id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows , & id_intel_llvm_nix , id_intel_llvm_windows , id_intel_llvm_unknown ]) end function is_intel","tags":"","loc":"proc/is_intel.html"},{"title":"is_unknown – Fortran-lang/fpm","text":"public pure function is_unknown(self) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Contents Source Code is_unknown Source Code pure function is_unknown ( self ) class ( compiler_t ), intent ( in ) :: self logical :: is_unknown is_unknown = self % id == id_unknown end function is_unknown","tags":"","loc":"proc/is_unknown.html"},{"title":"compile_c – Fortran-lang/fpm","text":"public subroutine compile_c(self, input, output, args, log_file, stat) Compile a C object Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Source Code compile_c Source Code subroutine compile_c ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % cc // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_c","tags":"","loc":"proc/compile_c.html"},{"title":"compile_cpp – Fortran-lang/fpm","text":"public subroutine compile_cpp(self, input, output, args, log_file, stat) Compile a CPP object Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Source Code compile_cpp Source Code subroutine compile_cpp ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % cxx // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_cpp","tags":"","loc":"proc/compile_cpp.html"},{"title":"compile_fortran – Fortran-lang/fpm","text":"public subroutine compile_fortran(self, input, output, args, log_file, stat) Compile a Fortran object Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Source Code compile_fortran Source Code subroutine compile_fortran ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % fc // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_fortran","tags":"","loc":"proc/compile_fortran.html"},{"title":"get_debug_compile_flags – Fortran-lang/fpm","text":"public subroutine get_debug_compile_flags(id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags Contents Source Code get_debug_compile_flags Source Code subroutine get_debug_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace case ( id_gcc ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & ' -Wno-maybe-uninitialized -Wno-uninitialized' // & flag_gnu_backtrace case ( id_nvhpc ) flags = & flag_pgi_warn // & flag_pgi_backslash // & flag_pgi_check // & flag_pgi_traceback case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_classic_mac ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_classic_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win // & flag_intel_backtrace_win case ( id_intel_llvm_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_llvm_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_nag ) flags = & flag_nag_debug // & flag_nag_check // & flag_nag_backtrace // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = \"\" end select end subroutine get_debug_compile_flags","tags":"","loc":"proc/get_debug_compile_flags.html"},{"title":"get_default_c_compiler – Fortran-lang/fpm","text":"public subroutine get_default_c_compiler(f_compiler, c_compiler) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: c_compiler Contents Variables id Source Code get_default_c_compiler Variables Type Visibility Attributes Name Initial integer(kind=compiler_enum), public :: id Source Code subroutine get_default_c_compiler ( f_compiler , c_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: c_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) c_compiler = 'icc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) c_compiler = 'icx' case ( id_flang , id_flang_new , id_f18 ) c_compiler = 'clang' case ( id_ibmxl ) c_compiler = 'xlc' case ( id_lfortran ) c_compiler = 'cc' case ( id_gcc ) c_compiler = 'gcc' case default ! Fall-back to using Fortran compiler c_compiler = f_compiler end select end subroutine get_default_c_compiler","tags":"","loc":"proc/get_default_c_compiler.html"},{"title":"get_default_cxx_compiler – Fortran-lang/fpm","text":"public subroutine get_default_cxx_compiler(f_compiler, cxx_compiler) Get C++ Compiler. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: cxx_compiler Contents Variables id Source Code get_default_cxx_compiler Variables Type Visibility Attributes Name Initial integer(kind=compiler_enum), public :: id Source Code subroutine get_default_cxx_compiler ( f_compiler , cxx_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: cxx_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) cxx_compiler = 'icpc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) cxx_compiler = 'icpx' case ( id_flang , id_flang_new , id_f18 ) cxx_compiler = 'clang++' case ( id_ibmxl ) cxx_compiler = 'xlc++' case ( id_lfortran ) cxx_compiler = 'cc' case ( id_gcc ) cxx_compiler = 'g++' case default ! Fall-back to using Fortran compiler cxx_compiler = f_compiler end select end subroutine get_default_cxx_compiler","tags":"","loc":"proc/get_default_cxx_compiler.html"},{"title":"get_main_flags – Fortran-lang/fpm","text":"public subroutine get_main_flags(self, language, flags) Get special flags for the main linker Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: language character(len=:), intent(out), allocatable :: flags Contents Source Code get_main_flags Source Code subroutine get_main_flags ( self , language , flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: language character ( len = :), allocatable , intent ( out ) :: flags flags = \"\" select case ( language ) case ( \"fortran\" ) flags = \"\" case ( \"c\" ) ! If the main program is on a C/C++ source, the Intel Fortran compiler requires option ! -nofor-main to avoid \"duplicate main\" errors. ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case ( \"c++\" , \"cpp\" , \"cxx\" ) select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case default error stop \"Unknown language '\" // language // '\", try \"fortran\", \"c\", \"c++\"' end select end subroutine get_main_flags","tags":"","loc":"proc/get_main_flags.html"},{"title":"get_release_compile_flags – Fortran-lang/fpm","text":"public subroutine get_release_compile_flags(id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags Contents Source Code get_release_compile_flags Source Code subroutine get_release_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_gcc ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_nvhpc ) flags = & flag_pgi_backslash case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_classic_mac ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_classic_windows ) flags = & & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_intel_llvm_nix ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_llvm_windows ) flags = & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_nag ) flags = & flag_nag_opt // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = & flag_lfortran_opt end select end subroutine get_release_compile_flags","tags":"","loc":"proc/get_release_compile_flags.html"},{"title":"link – Fortran-lang/fpm","text":"public subroutine link(self, output, args, log_file, stat) Link an executable Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Source Code link Source Code subroutine link ( self , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % fc // \" \" // args // \" -o \" // output , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine link","tags":"","loc":"proc/link.html"},{"title":"make_archive – Fortran-lang/fpm","text":"public subroutine make_archive(self, output, args, log_file, stat) Create an archive Todo For Windows OS, use the local delete_file_win32 in stead of delete_file .\nThis may be related to a bug in Mingw64-openmp and is expected to be resolved in the future,\nsee issue #707, #708 and #808. Type Bound archiver_t Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: self Instance of the archiver object character(len=*), intent(in) :: output Name of the archive to generate type( string_t ), intent(in) :: args (:) Object files to include into the archive character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Subroutines delete_file_win32 Source Code make_archive Subroutines subroutine delete_file_win32(file) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file Source Code subroutine make_archive ( self , output , args , log_file , stat ) !> Instance of the archiver object class ( archiver_t ), intent ( in ) :: self !> Name of the archive to generate character ( len =* ), intent ( in ) :: output !> Object files to include into the archive type ( string_t ), intent ( in ) :: args (:) !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat if ( self % use_response_file ) then call write_response_file ( output // \".resp\" , args ) call run ( self % ar // output // \" @\" // output // \".resp\" , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) call delete_file_win32 ( output // \".resp\" ) else call run ( self % ar // output // \" \" // string_cat ( args , \" \" ), & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end if contains subroutine delete_file_win32 ( file ) character ( len =* ), intent ( in ) :: file logical :: exist integer :: unit , iostat inquire ( file = file , exist = exist ) if ( exist ) then open ( file = file , newunit = unit ) close ( unit , status = 'delete' , iostat = iostat ) end if end subroutine delete_file_win32 end subroutine make_archive","tags":"","loc":"proc/make_archive.html"},{"title":"new_archiver – Fortran-lang/fpm","text":"public subroutine new_archiver(self, ar, echo, verbose) Create new archiver instance Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(out) :: self New instance of the archiver character(len=*), intent(in) :: ar User provided archiver command logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output Contents Variables arflags estat libflags os_type Source Code new_archiver Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: arflags = \" -rs \" integer, public :: estat character(len=*), public, parameter :: libflags = \" /OUT:\" integer, public :: os_type Source Code subroutine new_archiver ( self , ar , echo , verbose ) !> New instance of the archiver type ( archiver_t ), intent ( out ) :: self !> User provided archiver command character ( len =* ), intent ( in ) :: ar !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose integer :: estat , os_type character ( len =* ), parameter :: arflags = \" -rs \" , libflags = \" /OUT:\" if ( len_trim ( ar ) > 0 ) then ! Check first for ar-like commands if ( check_compiler ( ar , \"ar\" )) then self % ar = ar // arflags end if ! Check for lib-like commands if ( check_compiler ( ar , \"lib\" )) then self % ar = ar // libflags end if ! Fallback and assume ar-like behaviour self % ar = ar // arflags else os_type = get_os_type () if ( os_type /= OS_WINDOWS . and . os_type /= OS_UNKNOWN ) then self % ar = \"ar\" // arflags else call execute_command_line ( \"ar --version > \" // get_temp_filename () // \" 2>&1\" , & & exitstat = estat ) if ( estat /= 0 ) then self % ar = \"lib\" // libflags else self % ar = \"ar\" // arflags end if end if end if self % use_response_file = os_type == OS_WINDOWS self % echo = echo self % verbose = verbose end subroutine new_archiver","tags":"","loc":"proc/new_archiver.html"},{"title":"new_compiler – Fortran-lang/fpm","text":"public subroutine new_compiler(self, fc, cc, cxx, echo, verbose) Create new compiler instance Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(out) :: self New instance of the compiler character(len=*), intent(in) :: fc Fortran compiler name or path character(len=*), intent(in) :: cc C compiler name or path character(len=*), intent(in) :: cxx C++ Compiler name or path logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output Contents Source Code new_compiler Source Code subroutine new_compiler ( self , fc , cc , cxx , echo , verbose ) !> New instance of the compiler type ( compiler_t ), intent ( out ) :: self !> Fortran compiler name or path character ( len =* ), intent ( in ) :: fc !> C compiler name or path character ( len =* ), intent ( in ) :: cc !> C++ Compiler name or path character ( len =* ), intent ( in ) :: cxx !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose self % id = get_compiler_id ( fc ) self % echo = echo self % verbose = verbose self % fc = fc if ( len_trim ( cc ) > 0 ) then self % cc = cc else call get_default_c_compiler ( self % fc , self % cc ) end if if ( len_trim ( cxx ) > 0 ) then self % cxx = cxx else call get_default_cxx_compiler ( self % fc , self % cxx ) end if end subroutine new_compiler","tags":"","loc":"proc/new_compiler.html"},{"title":"set_cpp_preprocessor_flags – Fortran-lang/fpm","text":"public pure subroutine set_cpp_preprocessor_flags(id, flags) Modify the flag_cpp_preprocessor on the basis of the compiler. Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(inout), allocatable :: flags Contents Variables flag_cpp_preprocessor Source Code set_cpp_preprocessor_flags Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: flag_cpp_preprocessor Source Code pure subroutine set_cpp_preprocessor_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( inout ) :: flags character ( len = :), allocatable :: flag_cpp_preprocessor !> Modify the flag_cpp_preprocessor on the basis of the compiler. select case ( id ) case default flag_cpp_preprocessor = \"\" case ( id_caf , id_gcc , id_f95 , id_nvhpc ) flag_cpp_preprocessor = \"-cpp\" case ( id_intel_classic_windows , id_intel_llvm_windows ) flag_cpp_preprocessor = \"/fpp\" case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , id_nag ) flag_cpp_preprocessor = \"-fpp\" case ( id_lfortran ) flag_cpp_preprocessor = \"--cpp\" end select flags = flag_cpp_preprocessor // flags end subroutine set_cpp_preprocessor_flags","tags":"","loc":"proc/set_cpp_preprocessor_flags.html"},{"title":"write_response_file – Fortran-lang/fpm","text":"public subroutine write_response_file(name, argv) Response files allow to read command line options from files.\nWhitespace is used to separate the arguments, we will use newlines\nas separator to create readable response files which can be inspected\nin case of errors. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name type( string_t ), intent(in) :: argv (:) Contents Variables iarg io Source Code write_response_file Variables Type Visibility Attributes Name Initial integer, public :: iarg integer, public :: io Source Code subroutine write_response_file ( name , argv ) character ( len =* ), intent ( in ) :: name type ( string_t ), intent ( in ) :: argv (:) integer :: iarg , io open ( file = name , newunit = io , status = 'replace' ) do iarg = 1 , size ( argv ) write ( io , '(a)' ) unix_path ( argv ( iarg )% s ) end do close ( io ) end subroutine write_response_file","tags":"","loc":"proc/write_response_file.html"},{"title":"debug – Fortran-lang/fpm","text":"public interface debug Create debug printout Contents Module Procedures debug_compiler debug_archiver Module Procedures public pure function debug_compiler (self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public pure function debug_archiver (self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string","tags":"","loc":"interface/debug.html"},{"title":"get_command_arguments_quoted – Fortran-lang/fpm","text":"public function get_command_arguments_quoted() result(args) Arguments None Return Value character(len=:), allocatable Contents Source Code get_command_arguments_quoted Source Code function get_command_arguments_quoted () result ( args ) character ( len = :), allocatable :: args character ( len = :), allocatable :: arg character ( len = 1 ) :: quote integer :: ilength , istatus , i ilength = 0 args = '' quote = merge ( '\"' , \"'\" , separator () == '\\') do i=2,command_argument_count() ! look at all arguments after subcommand call get_command_argument(number=i,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit else if(allocated(arg))deallocate(arg) allocate(character(len=ilength) :: arg) call get_command_argument(number=i,value=arg,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit elseif(ilength>0)then if(index(arg//' ',' - ')/=1)then args=args//quote//arg//quote//' ' elseif(index(arg,' ')/=0)then args=args//quote//arg//quote//' ' else args=args//arg//' ' endif else args=args//repeat(quote,2)//' ' endif endif enddo end function get_command_arguments_quoted","tags":"","loc":"proc/get_command_arguments_quoted.html"},{"title":"get_env – Fortran-lang/fpm","text":"public function get_env(NAME, DEFAULT) result(VALUE) get named environment variable value. It it is blank or\n not set return the optional default value\n!print , NAME, ” is not defined in the environment. Strange…”\n!print , “This processor doesn’t support environment variables. Boooh!” Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: NAME name of environment variable to get the value of character(len=*), intent(in), optional :: DEFAULT default value to return if the requested value is undefined or blank Return Value character(len=:), allocatable the returned value Contents Source Code get_env Source Code function get_env ( NAME , DEFAULT ) result ( VALUE ) implicit none !> name of environment variable to get the value of character ( len =* ), intent ( in ) :: NAME !> default value to return if the requested value is undefined or blank character ( len =* ), intent ( in ), optional :: DEFAULT !> the returned value character ( len = :), allocatable :: VALUE integer :: howbig integer :: stat integer :: length ! get length required to hold value length = 0 if ( NAME /= '' ) then call get_environment_variable ( NAME , length = howbig , status = stat , trim_name = . true .) select case ( stat ) case ( 1 ) !*!print *, NAME, \" is not defined in the environment. Strange...\" VALUE = '' case ( 2 ) !*!print *, \"This processor doesn't support environment variables. Boooh!\" VALUE = '' case default ! make string to hold value of sufficient size allocate ( character ( len = max ( howbig , 1 )) :: VALUE ) ! get value call get_environment_variable ( NAME , VALUE , status = stat , trim_name = . true .) if ( stat /= 0 ) VALUE = '' end select else VALUE = '' endif if ( VALUE == '' . and . present ( DEFAULT )) VALUE = DEFAULT end function get_env","tags":"","loc":"proc/get_env.html"},{"title":"get_os_type – Fortran-lang/fpm","text":"public function get_os_type() result(r) Determine the OS type Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN,\nOS_SOLARIS, OS_FREEBSD, OS_OPENBSD. At first, the environment variable OS is checked, which is usually\nfound on Windows. Then, OSTYPE is read in and compared with common\nnames. If this fails too, check the existence of files that can be\nfound on specific system types only. Returns OS_UNKNOWN if the operating system cannot be determined. Arguments None Return Value integer Contents Source Code get_os_type Source Code integer function get_os_type () result ( r ) !! !! Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN, !! OS_SOLARIS, OS_FREEBSD, OS_OPENBSD. !! !! At first, the environment variable `OS` is checked, which is usually !! found on Windows. Then, `OSTYPE` is read in and compared with common !! names. If this fails too, check the existence of files that can be !! found on specific system types only. !! !! Returns OS_UNKNOWN if the operating system cannot be determined. character ( len = 32 ) :: val integer :: length , rc logical :: file_exists logical , save :: first_run = . true . integer , save :: ret = OS_UNKNOWN !$omp threadprivate(ret, first_run) if (. not . first_run ) then r = ret return end if first_run = . false . r = OS_UNKNOWN ! Check environment variable `OSTYPE`. call get_environment_variable ( 'OSTYPE' , val , length , rc ) if ( rc == 0 . and . length > 0 ) then ! Linux if ( index ( val , 'linux' ) > 0 ) then r = OS_LINUX ret = r return end if ! macOS if ( index ( val , 'darwin' ) > 0 ) then r = OS_MACOS ret = r return end if ! Windows, MSYS, MinGW, Git Bash if ( index ( val , 'win' ) > 0 . or . index ( val , 'msys' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Cygwin if ( index ( val , 'cygwin' ) > 0 ) then r = OS_CYGWIN ret = r return end if ! Solaris, OpenIndiana, ... if ( index ( val , 'SunOS' ) > 0 . or . index ( val , 'solaris' ) > 0 ) then r = OS_SOLARIS ret = r return end if ! FreeBSD if ( index ( val , 'FreeBSD' ) > 0 . or . index ( val , 'freebsd' ) > 0 ) then r = OS_FREEBSD ret = r return end if ! OpenBSD if ( index ( val , 'OpenBSD' ) > 0 . or . index ( val , 'openbsd' ) > 0 ) then r = OS_OPENBSD ret = r return end if end if ! Check environment variable `OS`. call get_environment_variable ( 'OS' , val , length , rc ) if ( rc == 0 . and . length > 0 . and . index ( val , 'Windows_NT' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Linux inquire ( file = '/etc/os-release' , exist = file_exists ) if ( file_exists ) then r = OS_LINUX ret = r return end if ! macOS inquire ( file = '/usr/bin/sw_vers' , exist = file_exists ) if ( file_exists ) then r = OS_MACOS ret = r return end if ! FreeBSD inquire ( file = '/bin/freebsd-version' , exist = file_exists ) if ( file_exists ) then r = OS_FREEBSD ret = r return end if end function get_os_type","tags":"","loc":"proc/get_os_type.html"},{"title":"os_is_unix – Fortran-lang/fpm","text":"public function os_is_unix(os) Compare the output of get_os_type or the optional\npassed INTEGER value to the value for OS_WINDOWS\nand return .TRUE. if they match and .FALSE. otherwise Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Return Value logical Contents Source Code os_is_unix Source Code logical function os_is_unix ( os ) integer , intent ( in ), optional :: os integer :: build_os if ( present ( os )) then build_os = os else build_os = get_os_type () end if os_is_unix = build_os /= OS_WINDOWS end function os_is_unix","tags":"","loc":"proc/os_is_unix.html"},{"title":"separator – Fortran-lang/fpm","text":"public function separator() result(sep) NAME separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character\n(LICENSE:PD) SYNOPSIS function separator() result ( sep ) character ( len = 1 ) :: sep DESCRIPTION First using the name the program was invoked with , then the name returned by an INQUIRE ( 3 f ) of that name , then \".\\NAME\" and \"./NAME\" try to determine the separator character used to separate directory names from file basenames . If a slash or backslash is not found in the name , the environment variable PATH is examined first for a backslash , then a slash . Can be very system dependent . If the queries fail the default returned is \"/\" . EXAMPLE sample usage program demo_separator use M_io , only : separator implicit none write ( * , * ) ' separator= ' , separator () end program demo_separator !write( , )’ unknown system directory path separator’\nifort_bug*!sep_cache=sep Arguments None Return Value character(len=1) ifort_bug*!character(len=1),save :: sep_cache=’ ‘ Contents Source Code separator Source Code function separator () result ( sep ) !> !!##NAME !! separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character !! (LICENSE:PD) !! !!##SYNOPSIS !! !! function separator() result(sep) !! !! character(len=1) :: sep !! !!##DESCRIPTION !! First using the name the program was invoked with, then the name !! returned by an INQUIRE(3f) of that name, then \".\\NAME\" and \"./NAME\" !! try to determine the separator character used to separate directory !! names from file basenames. !! !! If a slash or backslash is not found in the name, the environment !! variable PATH is examined first for a backslash, then a slash. !! !! Can be very system dependent. If the queries fail the default returned !! is \"/\". !! !!##EXAMPLE !! !! sample usage !! !! program demo_separator !! use M_io, only : separator !! implicit none !! write(*,*)'separator=',separator() !! end program demo_separator ! use the pathname returned as arg0 to determine pathname separator implicit none character ( len = :), allocatable :: arg0 integer :: arg0_length integer :: istat logical :: existing character ( len = 1 ) :: sep !*ifort_bug*!character(len=1),save :: sep_cache=' ' character ( len = 4096 ) :: name character ( len = :), allocatable :: fname !*ifort_bug*! if(sep_cache/=' ')then ! use cached value. NOTE: A parallel code might theoretically use multiple OS !*ifort_bug*! sep=sep_cache !*ifort_bug*! return !*ifort_bug*! endif arg0_length = 0 name = ' ' call get_command_argument ( 0 , length = arg0_length , status = istat ) if ( allocated ( arg0 )) deallocate ( arg0 ) allocate ( character ( len = arg0_length ) :: arg0 ) call get_command_argument ( 0 , arg0 , status = istat ) ! check argument name if ( index ( arg0 , '\\')/=0)then sep=' \\ ' elseif(index(arg0,' / ')/=0)then sep=' / ' else ! try name returned by INQUIRE(3f) existing=.false. name=' ' inquire(file=arg0,iostat=istat,exist=existing,name=name) if(index(name,' \\ ')/=0)then sep=' \\ ' elseif(index(name,' / ')/=0)then sep=' / ' else ! well, try some common syntax and assume in current directory fname=' . \\ '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' \\ ' else fname=' . / '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' / ' else ! check environment variable PATH sep=merge(' \\ ',' / ',index(get_env(' PATH '),' \\ ')/=0) !*!write(*,*)' < WARNING > unknown system directory path separator ' endif endif endif endif !*ifort_bug*!sep_cache=sep end function separator","tags":"","loc":"proc/separator.html"},{"title":"MPI_TYPE_NAME – Fortran-lang/fpm","text":"public pure function MPI_TYPE_NAME(mpilib) result(name) Return a name for the MPI library Arguments Type Intent Optional Attributes Name integer, intent(in) :: mpilib Return Value character(len=:), allocatable Contents Source Code MPI_TYPE_NAME Source Code pure function MPI_TYPE_NAME ( mpilib ) result ( name ) integer , intent ( in ) :: mpilib character ( len = :), allocatable :: name select case ( mpilib ) case ( MPI_TYPE_NONE ); name = \"none\" case ( MPI_TYPE_OPENMPI ); name = \"OpenMPI\" case ( MPI_TYPE_MPICH ); name = \"MPICH\" case ( MPI_TYPE_INTEL ); name = \"INTELMPI\" case ( MPI_TYPE_MSMPI ); name = \"MS-MPI\" case default ; name = \"UNKNOWN\" end select end function MPI_TYPE_NAME","tags":"","loc":"proc/mpi_type_name.html"},{"title":"resolve_metapackages – Fortran-lang/fpm","text":"public interface resolve_metapackages Contents Module Procedures resolve_metapackage_model Module Procedures private subroutine resolve_metapackage_model(model, package, settings, error) Resolve all metapackages into the package config Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(inout) :: model type( package_config_t ), intent(inout) :: package class( fpm_build_settings ), intent(inout) :: settings type( error_t ), intent(out), allocatable :: error","tags":"","loc":"interface/resolve_metapackages.html"},{"title":"build_model – Fortran-lang/fpm","text":"public subroutine build_model(model, settings, package, error) Constructs a valid fpm model from command line settings and the toml manifest.\nAdd this dependency’s manifest macros Add this dependency’s package-level macros Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(out) :: model class( fpm_build_settings ), intent(inout) :: settings type( package_config_t ), intent(inout) :: package type( error_t ), intent(out), allocatable :: error Contents Source Code build_model Source Code subroutine build_model ( model , settings , package , error ) type ( fpm_model_t ), intent ( out ) :: model class ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ), intent ( inout ) :: package type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( package_config_t ) :: dependency character ( len = :), allocatable :: manifest , lib_dir logical :: has_cpp logical :: duplicates_found type ( string_t ) :: include_dir model % package_name = package % name allocate ( model % include_dirs ( 0 )) allocate ( model % link_libraries ( 0 )) allocate ( model % external_modules ( 0 )) call new_compiler ( model % compiler , settings % compiler , settings % c_compiler , & & settings % cxx_compiler , echo = settings % verbose , verbose = settings % verbose ) call new_archiver ( model % archiver , settings % archiver , & & echo = settings % verbose , verbose = settings % verbose ) if ( model % compiler % is_unknown ()) then write ( * , '(*(a:,1x))' ) & \"\" , \"Unknown compiler\" , model % compiler % fc , \"requested!\" , & \"Defaults for this compiler might be incorrect\" end if call new_compiler_flags ( model , settings ) model % build_prefix = join_path ( \"build\" , basename ( model % compiler % fc )) model % include_tests = settings % build_tests model % enforce_module_names = package % build % module_naming model % module_prefix = package % build % module_prefix ! Resolve meta-dependencies into the package and the model call resolve_metapackages ( model , package , settings , error ) if ( allocated ( error )) return ! Create dependencies call new_dependency_tree ( model % deps , cache = join_path ( \"build\" , \"cache.toml\" )) ! Build and resolve model dependencies call model % deps % add ( package , error ) if ( allocated ( error )) return ! Update dependencies where needed call model % deps % update ( error ) if ( allocated ( error )) return ! build/ directory should now exist if (. not . exists ( \"build/.gitignore\" )) then call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if allocate ( model % packages ( model % deps % ndep )) has_cpp = . false . do i = 1 , model % deps % ndep associate ( dep => model % deps % dep ( i )) manifest = join_path ( dep % proj_dir , \"fpm.toml\" ) call get_package_data ( dependency , manifest , error , apply_defaults = . true .) if ( allocated ( error )) exit model % packages ( i )% name = dependency % name associate ( features => model % packages ( i )% features ) features % implicit_typing = dependency % fortran % implicit_typing features % implicit_external = dependency % fortran % implicit_external features % source_form = dependency % fortran % source_form end associate model % packages ( i )% version = package % version % s () !> Add this dependency's manifest macros allocate ( model % packages ( i )% macros ( 0 )) if ( allocated ( dependency % preprocess )) then do j = 1 , size ( dependency % preprocess ) if ( dependency % preprocess ( j )% name == \"cpp\" ) then if (. not . has_cpp ) has_cpp = . true . if ( allocated ( dependency % preprocess ( j )% macros )) then model % packages ( i )% macros = [ model % packages ( i )% macros , dependency % preprocess ( j )% macros ] end if else write ( stderr , '(a)' ) 'Warning: Preprocessor ' // package % preprocess ( i )% name // & ' is not supported; will ignore it' end if end do end if !> Add this dependency's package-level macros if ( allocated ( dep % preprocess )) then do j = 1 , size ( dep % preprocess ) if ( dep % preprocess ( j )% name == \"cpp\" ) then if (. not . has_cpp ) has_cpp = . true . if ( allocated ( dep % preprocess ( j )% macros )) then model % packages ( i )% macros = [ model % packages ( i )% macros , dep % preprocess ( j )% macros ] end if else write ( stderr , '(a)' ) 'Warning: Preprocessor ' // package % preprocess ( i )% name // & ' is not supported; will ignore it' end if end do end if if (. not . allocated ( model % packages ( i )% sources )) allocate ( model % packages ( i )% sources ( 0 )) if ( allocated ( dependency % library )) then if ( allocated ( dependency % library % source_dir )) then lib_dir = join_path ( dep % proj_dir , dependency % library % source_dir ) if ( is_dir ( lib_dir )) then call add_sources_from_dir ( model % packages ( i )% sources , lib_dir , FPM_SCOPE_LIB , & error = error ) if ( allocated ( error )) exit end if end if if ( allocated ( dependency % library % include_dir )) then do j = 1 , size ( dependency % library % include_dir ) include_dir % s = join_path ( dep % proj_dir , dependency % library % include_dir ( j )% s ) if ( is_dir ( include_dir % s )) then model % include_dirs = [ model % include_dirs , include_dir ] end if end do end if end if if ( allocated ( dependency % build % link )) then model % link_libraries = [ model % link_libraries , dependency % build % link ] end if if ( allocated ( dependency % build % external_modules )) then model % external_modules = [ model % external_modules , dependency % build % external_modules ] end if ! Copy naming conventions from this dependency's manifest model % packages ( i )% enforce_module_names = dependency % build % module_naming model % packages ( i )% module_prefix = dependency % build % module_prefix end associate end do if ( allocated ( error )) return ! Add optional flags if ( has_cpp ) call set_cpp_preprocessor_flags ( model % compiler % id , model % fortran_compile_flags ) ! Add sources from executable directories if ( is_dir ( 'app' ) . and . package % build % auto_executables ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'app' , FPM_SCOPE_APP , & with_executables = . true ., error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'example' ) . and . package % build % auto_examples ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'example' , FPM_SCOPE_EXAMPLE , & with_executables = . true ., error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'test' ) . and . package % build % auto_tests ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'test' , FPM_SCOPE_TEST , & with_executables = . true ., error = error ) if ( allocated ( error )) then return endif end if if ( allocated ( package % executable )) then call add_executable_sources ( model % packages ( 1 )% sources , package % executable , FPM_SCOPE_APP , & auto_discover = package % build % auto_executables , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % example )) then call add_executable_sources ( model % packages ( 1 )% sources , package % example , FPM_SCOPE_EXAMPLE , & auto_discover = package % build % auto_examples , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % test )) then call add_executable_sources ( model % packages ( 1 )% sources , package % test , FPM_SCOPE_TEST , & auto_discover = package % build % auto_tests , & error = error ) if ( allocated ( error )) then return endif endif if ( settings % verbose ) then write ( * , * ) ' BUILD_NAME: ' , model % build_prefix write ( * , * ) ' COMPILER: ' , model % compiler % fc write ( * , * ) ' C COMPILER: ' , model % compiler % cc write ( * , * ) ' CXX COMPILER: ' , model % compiler % cxx write ( * , * ) ' COMPILER OPTIONS: ' , model % fortran_compile_flags write ( * , * ) ' C COMPILER OPTIONS: ' , model % c_compile_flags write ( * , * ) ' CXX COMPILER OPTIONS: ' , model % cxx_compile_flags write ( * , * ) ' LINKER OPTIONS: ' , model % link_flags write ( * , * ) ' INCLUDE DIRECTORIES: [' , string_cat ( model % include_dirs , ',' ), ']' end if ! Check for invalid module names call check_module_names ( model , error ) if ( allocated ( error )) return ! Check for duplicate modules duplicates_found = . false . call check_modules_for_duplicates ( model , duplicates_found ) if ( duplicates_found ) then call fpm_stop ( 1 , '*build_model*:Error: One or more duplicate module names found.' ) end if end subroutine build_model","tags":"","loc":"proc/build_model.html"},{"title":"check_modules_for_duplicates – Fortran-lang/fpm","text":"public subroutine check_modules_for_duplicates(model, duplicates_found) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model logical :: duplicates_found Contents Source Code check_modules_for_duplicates Source Code subroutine check_modules_for_duplicates ( model , duplicates_found ) type ( fpm_model_t ), intent ( in ) :: model integer :: maxsize integer :: i , j , k , l , m , modi type ( string_t ), allocatable :: modules (:) logical :: duplicates_found ! Initialise the size of array maxsize = 0 ! Get number of modules provided by each source file of every package do i = 1 , size ( model % packages ) do j = 1 , size ( model % packages ( i )% sources ) if ( allocated ( model % packages ( i )% sources ( j )% modules_provided )) then maxsize = maxsize + size ( model % packages ( i )% sources ( j )% modules_provided ) end if end do end do ! Allocate array to contain distinct names of modules allocate ( modules ( maxsize )) ! Initialise index to point at start of the newly allocated array modi = 1 ! Loop through modules provided by each source file of every package ! Add it to the array if it is not already there ! Otherwise print out warning about duplicates do k = 1 , size ( model % packages ) do l = 1 , size ( model % packages ( k )% sources ) if ( allocated ( model % packages ( k )% sources ( l )% modules_provided )) then do m = 1 , size ( model % packages ( k )% sources ( l )% modules_provided ) if ( model % packages ( k )% sources ( l )% modules_provided ( m )% s . in . modules (: modi - 1 )) then write ( stderr , * ) \"Warning: Module \" , model % packages ( k )% sources ( l )% modules_provided ( m )% s , & \" in \" , model % packages ( k )% sources ( l )% file_name , \" is a duplicate\" duplicates_found = . true . else modules ( modi ) = model % packages ( k )% sources ( l )% modules_provided ( m ) modi = modi + 1 end if end do end if end do end do end subroutine check_modules_for_duplicates","tags":"","loc":"proc/check_modules_for_duplicates.html"},{"title":"cmd_build – Fortran-lang/fpm","text":"public subroutine cmd_build(settings) Arguments Type Intent Optional Attributes Name type( fpm_build_settings ), intent(inout) :: settings Contents Source Code cmd_build Source Code subroutine cmd_build ( settings ) type ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( error_t ), allocatable :: error integer :: i call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Target error: ' // error % message ) end if if ( settings % list ) then do i = 1 , size ( targets ) write ( stderr , * ) targets ( i )% ptr % output_file enddo else if ( settings % show_model ) then call show_model ( model ) else call build_package ( targets , model , verbose = settings % verbose ) endif end subroutine cmd_build","tags":"","loc":"proc/cmd_build.html"},{"title":"cmd_clean – Fortran-lang/fpm","text":"public subroutine cmd_clean(settings) Delete the build directory including or excluding dependencies. Arguments Type Intent Optional Attributes Name class( fpm_clean_settings ), intent(in) :: settings Settings for the clean command. Contents Source Code cmd_clean Source Code subroutine cmd_clean ( settings ) !> Settings for the clean command. class ( fpm_clean_settings ), intent ( in ) :: settings character :: user_response if ( is_dir ( 'build' )) then ! Remove the entire build directory if ( settings % clean_call ) then call os_delete_dir ( os_is_unix (), 'build' ); return end if ! Remove the build directory but skip dependencies if ( settings % clean_skip ) then call delete_skip ( os_is_unix ()); return end if ! Prompt to remove the build directory but skip dependencies write ( stdout , '(A)' , advance = 'no' ) \"Delete build, excluding dependencies (y/n)? \" read ( stdin , '(A1)' ) user_response if ( lower ( user_response ) == 'y' ) call delete_skip ( os_is_unix ()) else write ( stdout , '(A)' ) \"fpm: No build directory found.\" end if end subroutine cmd_clean","tags":"","loc":"proc/cmd_clean.html"},{"title":"cmd_run – Fortran-lang/fpm","text":"public subroutine cmd_run(settings, test) Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(inout) :: settings logical, intent(in) :: test Contents Source Code cmd_run Source Code subroutine cmd_run ( settings , test ) class ( fpm_run_settings ), intent ( inout ) :: settings logical , intent ( in ) :: test integer :: i , j , col_width logical :: found ( size ( settings % name )) type ( error_t ), allocatable :: error type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( string_t ) :: exe_cmd type ( string_t ), allocatable :: executables (:) type ( build_target_t ), pointer :: exe_target type ( srcfile_t ), pointer :: exe_source integer :: run_scope , firsterror integer , allocatable :: stat (:) character ( len = :), allocatable :: line logical :: toomany call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Targets error: ' // error % message ) end if if ( test ) then run_scope = FPM_SCOPE_TEST else run_scope = merge ( FPM_SCOPE_EXAMPLE , FPM_SCOPE_APP , settings % example ) end if ! Enumerate executable targets to run col_width = - 1 found (:) = . false . allocate ( executables ( 0 )) do i = 1 , size ( targets ) exe_target => targets ( i )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then col_width = max ( col_width , len ( basename ( exe_target % output_file )) + 2 ) if ( size ( settings % name ) == 0 ) then exe_cmd % s = exe_target % output_file executables = [ executables , exe_cmd ] else do j = 1 , size ( settings % name ) if ( glob ( trim ( exe_source % exe_name ), trim ( settings % name ( j )))) then found ( j ) = . true . exe_cmd % s = exe_target % output_file executables = [ executables , exe_cmd ] end if end do end if end if end if end do ! Check if any apps/tests were found if ( col_width < 0 ) then if ( test ) then call fpm_stop ( 0 , 'No tests to run' ) else call fpm_stop ( 0 , 'No executables to run' ) end if end if ! Check all names are valid ! or no name and found more than one file toomany = size ( settings % name ) == 0 . and . size ( executables ) > 1 if ( any (. not . found ) & & . or . & & ( ( toomany . and . . not . test ) . or . ( toomany . and . settings % runner /= '' ) ) & & . and . & & . not . settings % list ) then line = join ( settings % name ) if ( line /= '.' ) then ! do not report these special strings if ( any (. not . found )) then write ( stderr , '(A)' , advance = \"no\" ) '*cmd_run*:specified names ' do j = 1 , size ( settings % name ) if (. not . found ( j )) write ( stderr , '(A)' , advance = \"no\" ) '\"' // trim ( settings % name ( j )) // '\" ' end do write ( stderr , '(A)' ) 'not found.' write ( stderr , * ) else if ( settings % verbose ) then write ( stderr , '(A)' , advance = \"yes\" ) 'when more than one executable is available' write ( stderr , '(A)' , advance = \"yes\" ) ' program names must be specified.' endif endif call compact_list_all () if ( line == '.' . or . line == ' ' ) then ! do not report these special strings call fpm_stop ( 0 , '' ) else call fpm_stop ( 1 , '' ) endif end if call build_package ( targets , model , verbose = settings % verbose ) if ( settings % list ) then call compact_list () else allocate ( stat ( size ( executables ))) do i = 1 , size ( executables ) if ( exists ( executables ( i )% s )) then if ( settings % runner /= ' ' ) then if (. not . allocated ( settings % args )) then call run ( settings % runner_command () // ' ' // executables ( i )% s , & echo = settings % verbose , exitstat = stat ( i )) else call run ( settings % runner_command () // ' ' // executables ( i )% s // \" \" // settings % args , & echo = settings % verbose , exitstat = stat ( i )) endif else if (. not . allocated ( settings % args )) then call run ( executables ( i )% s , echo = settings % verbose , exitstat = stat ( i )) else call run ( executables ( i )% s // \" \" // settings % args , echo = settings % verbose , & exitstat = stat ( i )) endif endif else call fpm_stop ( 1 , '*cmd_run*:' // executables ( i )% s // ' not found' ) end if end do if ( any ( stat /= 0 )) then do i = 1 , size ( stat ) if ( stat ( i ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Execution for object \"' , basename ( executables ( i )% s ),& '\" returned exit code ' , stat ( i ) end if end do firsterror = findloc ( stat /= 0 , value = . true ., dim = 1 ) call fpm_stop ( stat ( firsterror ), '*cmd_run*:stopping due to failed executions' ) end if end if contains subroutine compact_list_all () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Available names:' do ii = 1 , size ( targets ) exe_target => targets ( ii )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( exe_target % output_file , suffix = . false .)] jj = jj + 1 end if end if end do write ( stderr , * ) end subroutine compact_list_all subroutine compact_list () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Matched names:' do ii = 1 , size ( executables ) write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( executables ( ii )% s , suffix = . false .)] jj = jj + 1 end do write ( stderr , * ) end subroutine compact_list end subroutine cmd_run","tags":"","loc":"proc/cmd_run.html"},{"title":"add_dependency – Fortran-lang/fpm","text":"public subroutine add_dependency(target, dependency) Add pointer to dependeny in target%dependencies Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout) :: target type( build_target_t ), intent(in), target :: dependency Contents Source Code add_dependency Source Code subroutine add_dependency ( target , dependency ) type ( build_target_t ), intent ( inout ) :: target type ( build_target_t ) , intent ( in ), target :: dependency target % dependencies = [ target % dependencies , build_target_ptr ( dependency )] end subroutine add_dependency","tags":"","loc":"proc/add_dependency.html"},{"title":"add_target – Fortran-lang/fpm","text":"public subroutine add_target(targets, package, type, output_name, source, link_libraries, features, macros, version) Allocate a new target and append to target list Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) character(len=*), intent(in) :: package integer, intent(in) :: type character(len=*), intent(in) :: output_name type( srcfile_t ), intent(in), optional :: source type( string_t ), intent(in), optional :: link_libraries (:) type( fortran_features_t ), intent(in), optional :: features type( string_t ), intent(in), optional :: macros (:) character(len=*), intent(in), optional :: version Contents Source Code add_target Source Code subroutine add_target ( targets , package , type , output_name , source , link_libraries , & & features , macros , version ) type ( build_target_ptr ), allocatable , intent ( inout ) :: targets (:) character ( * ), intent ( in ) :: package integer , intent ( in ) :: type character ( * ), intent ( in ) :: output_name type ( srcfile_t ), intent ( in ), optional :: source type ( string_t ), intent ( in ), optional :: link_libraries (:) type ( fortran_features_t ), intent ( in ), optional :: features type ( string_t ), intent ( in ), optional :: macros (:) character ( * ), intent ( in ), optional :: version integer :: i type ( build_target_t ), pointer :: new_target if (. not . allocated ( targets )) allocate ( targets ( 0 )) ! Check for duplicate outputs do i = 1 , size ( targets ) if ( targets ( i )% ptr % output_name == output_name ) then write ( * , * ) 'Error while building target list: duplicate output object \"' ,& output_name , '\"' if ( present ( source )) write ( * , * ) ' Source file: \"' , source % file_name , '\"' call fpm_stop ( 1 , ' ' ) end if end do allocate ( new_target ) new_target % target_type = type new_target % output_name = output_name new_target % package_name = package if ( present ( source )) new_target % source = source if ( present ( link_libraries )) new_target % link_libraries = link_libraries if ( present ( features )) new_target % features = features if ( present ( macros )) new_target % macros = macros if ( present ( version )) new_target % version = version allocate ( new_target % dependencies ( 0 )) targets = [ targets , build_target_ptr ( new_target )] end subroutine add_target","tags":"","loc":"proc/add_target.html"},{"title":"filter_executable_targets – Fortran-lang/fpm","text":"public subroutine filter_executable_targets(targets, scope, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) integer, intent(in) :: scope type( string_t ), intent(out), allocatable :: list (:) Contents Source Code filter_executable_targets Source Code subroutine filter_executable_targets ( targets , scope , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) integer , intent ( in ) :: scope type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( is_executable_target ( targets ( i )% ptr , scope )) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_executable_targets","tags":"","loc":"proc/filter_executable_targets.html"},{"title":"filter_library_targets – Fortran-lang/fpm","text":"public subroutine filter_library_targets(targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) Contents Source Code filter_library_targets Source Code subroutine filter_library_targets ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( targets ( i )% ptr % target_type == FPM_TARGET_ARCHIVE ) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_library_targets","tags":"","loc":"proc/filter_library_targets.html"},{"title":"filter_modules – Fortran-lang/fpm","text":"public subroutine filter_modules(targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) Contents Source Code filter_modules Source Code subroutine filter_modules ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , j , n n = 0 call resize ( list ) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if (. not . allocated ( target % source )) cycle if ( target % source % unit_type == FPM_UNIT_SUBMODULE ) cycle if ( n + size ( target % source % modules_provided ) >= size ( list )) call resize ( list ) do j = 1 , size ( target % source % modules_provided ) n = n + 1 list ( n )% s = join_path ( target % output_dir , & target % source % modules_provided ( j )% s ) end do end associate end do call resize ( list , n ) end subroutine filter_modules","tags":"","loc":"proc/filter_modules.html"},{"title":"resolve_module_dependencies – Fortran-lang/fpm","text":"public subroutine resolve_module_dependencies(targets, external_modules, error) Add dependencies to source-based targets ( FPM_TARGET_OBJECT )\n based on any modules used by the corresponding source file. Source file scoping Source files are assigned a scope of either FPM_SCOPE_LIB , FPM_SCOPE_APP or FPM_SCOPE_TEST . The scope controls which\n modules may be used by the source file: Library sources ( FPM_SCOPE_LIB ) may only use modules\n also with library scope. This includes library modules\n from dependencies. Executable sources ( FPM_SCOPE_APP , FPM_SCOPE_TEST ) may use\n library modules (including dependencies) as well as any modules\n corresponding to source files in the same directory or a\n subdirectory of the executable source file. Warning If a module used by a source file cannot be resolved to\n a source file in the package of the correct scope, then a fatal error is returned by the procedure and model construction fails. Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), target :: targets (:) type( string_t ), intent(in) :: external_modules (:) type( error_t ), intent(out), allocatable :: error Contents Source Code resolve_module_dependencies Source Code subroutine resolve_module_dependencies ( targets , external_modules , error ) type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( string_t ), intent ( in ) :: external_modules (:) type ( error_t ), allocatable , intent ( out ) :: error type ( build_target_ptr ) :: dep integer :: i , j do i = 1 , size ( targets ) if (. not . allocated ( targets ( i )% ptr % source )) cycle do j = 1 , size ( targets ( i )% ptr % source % modules_used ) if ( targets ( i )% ptr % source % modules_used ( j )% s . in . targets ( i )% ptr % source % modules_provided ) then ! Dependency satisfied in same file, skip cycle end if if ( targets ( i )% ptr % source % modules_used ( j )% s . in . external_modules ) then ! Dependency satisfied in system-installed module cycle end if if ( any ( targets ( i )% ptr % source % unit_scope == & [ FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST ])) then dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s , & include_dir = dirname ( targets ( i )% ptr % source % file_name )) else dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s ) end if if (. not . associated ( dep % ptr )) then call fatal_error ( error , & 'Unable to find source for module dependency: \"' // & targets ( i )% ptr % source % modules_used ( j )% s // & '\" used by \"' // targets ( i )% ptr % source % file_name // '\"' ) return end if call add_dependency ( targets ( i )% ptr , dep % ptr ) end do end do end subroutine resolve_module_dependencies","tags":"","loc":"proc/resolve_module_dependencies.html"},{"title":"targets_from_sources – Fortran-lang/fpm","text":"public subroutine targets_from_sources(targets, model, prune, error) High-level wrapper to generate build target information Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: targets (:) The generated list of build targets type( fpm_model_t ), intent(inout), target :: model The package model from which to construct the target list logical, intent(in) :: prune Enable tree-shaking/pruning of module dependencies type( error_t ), intent(out), allocatable :: error Error structure Contents Source Code targets_from_sources Source Code subroutine targets_from_sources ( targets , model , prune , error ) !> The generated list of build targets type ( build_target_ptr ), intent ( out ), allocatable :: targets (:) !> The package model from which to construct the target list type ( fpm_model_t ), intent ( inout ), target :: model !> Enable tree-shaking/pruning of module dependencies logical , intent ( in ) :: prune !> Error structure type ( error_t ), intent ( out ), allocatable :: error call build_target_list ( targets , model ) call collect_exe_link_dependencies ( targets ) call resolve_module_dependencies ( targets , model % external_modules , error ) if ( allocated ( error )) return if ( prune ) then call prune_build_targets ( targets , root_package = model % package_name ) end if call resolve_target_linking ( targets , model ) end subroutine targets_from_sources","tags":"","loc":"proc/targets_from_sources.html"},{"title":"change_directory – Fortran-lang/fpm","text":"public subroutine change_directory(path, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error Contents Source Code change_directory Source Code subroutine change_directory ( path , error ) character ( len =* ), intent ( in ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) integer :: stat allocate ( cpath ( len ( path ) + 1 )) call f_c_character ( path , cpath , len ( path ) + 1 ) stat = chdir_ ( cpath ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to change directory to '\" // path // \"'\" ) end if end subroutine change_directory","tags":"","loc":"proc/change_directory.html"},{"title":"convert_to_absolute_path – Fortran-lang/fpm","text":"public subroutine convert_to_absolute_path(path, error) Converts a path to an absolute, canonical path. Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: path type( error_t ), intent(out), allocatable :: error Contents","tags":"","loc":"proc/convert_to_absolute_path.html"},{"title":"get_absolute_path – Fortran-lang/fpm","text":"public subroutine get_absolute_path(path, absolute_path, error) Determine the canonical, absolute path for the given path.\nExpands home folder (~) on both Unix and Windows. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error Contents","tags":"","loc":"proc/get_absolute_path.html"},{"title":"get_absolute_path_by_cd – Fortran-lang/fpm","text":"public subroutine get_absolute_path_by_cd(path, absolute_path, error) Alternative to get_absolute_path that uses chdir / _chdir to determine the absolute path. get_absolute_path is preferred but get_absolute_path_by_cd can be used in bootstrap mode. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error Contents","tags":"","loc":"proc/get_absolute_path_by_cd.html"},{"title":"get_current_directory – Fortran-lang/fpm","text":"public subroutine get_current_directory(path, error) Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: path type( error_t ), intent(out), allocatable :: error Contents Source Code get_current_directory Source Code subroutine get_current_directory ( path , error ) character ( len = :), allocatable , intent ( out ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) type ( c_ptr ) :: tmp allocate ( cpath ( buffersize )) tmp = getcwd_ ( cpath , buffersize ) if ( c_associated ( tmp )) then call c_f_character ( cpath , path ) else call fatal_error ( error , \"Failed to retrieve current directory\" ) end if end subroutine get_current_directory","tags":"","loc":"proc/get_current_directory.html"},{"title":"build_progress_t – Fortran-lang/fpm","text":"public interface build_progress_t Constructor for build_progress_t Contents Module Procedures new_build_progress Module Procedures private function new_build_progress(target_queue, plain_mode) result(progress) Initialise a new build progress object Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in), target :: target_queue (:) The queue of scheduled targets logical, intent(in), optional :: plain_mode Enable ‘plain’ output for progress object Return Value type( build_progress_t ) Progress object to initialise","tags":"","loc":"interface/build_progress_t.html"},{"title":"get_exe_name_with_suffix – Fortran-lang/fpm","text":"public function get_exe_name_with_suffix(source) result(suffixed) Build an executable name with suffix. Safe routine that always returns an allocated string Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(in) :: source Return Value character(len=:), allocatable Contents Source Code get_exe_name_with_suffix Source Code function get_exe_name_with_suffix ( source ) result ( suffixed ) type ( srcfile_t ), intent ( in ) :: source character ( len = :), allocatable :: suffixed if ( allocated ( source % exe_name )) then if ( get_os_type () == OS_WINDOWS ) then suffixed = source % exe_name // '.exe' else suffixed = source % exe_name end if else suffixed = \"\" endif end function get_exe_name_with_suffix","tags":"","loc":"proc/get_exe_name_with_suffix.html"},{"title":"add_executable_sources – Fortran-lang/fpm","text":"public subroutine add_executable_sources(sources, executables, scope, auto_discover, error) Add to sources using the executable and test entries in the manifest and\napplies any executable-specific overrides such as executable%name .\nAdds all sources (including modules) from each executable%source_dir Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of srcfile_t objects to append to. Allocated if not allocated class( executable_config_t ), intent(in) :: executables (:) List of executable_config_t entries from manifest integer, intent(in) :: scope Scope to apply to the discovered sources: either FPM_SCOPE_APP or FPM_SCOPE_TEST , see fpm_model logical, intent(in) :: auto_discover If .false. only executables and tests specified in the manifest are added to sources type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code add_executable_sources Source Code subroutine add_executable_sources ( sources , executables , scope , auto_discover , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> List of `[[executable_config_t]]` entries from manifest class ( executable_config_t ), intent ( in ) :: executables (:) !> Scope to apply to the discovered sources: either `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`, see [[fpm_model]] integer , intent ( in ) :: scope !> If `.false.` only executables and tests specified in the manifest are added to `sources` logical , intent ( in ) :: auto_discover !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( string_t ), allocatable :: exe_dirs (:) type ( srcfile_t ) :: exe_source call get_executable_source_dirs ( exe_dirs , executables ) do i = 1 , size ( exe_dirs ) call add_sources_from_dir ( sources , exe_dirs ( i )% s , scope , & with_executables = auto_discover , recurse = . false ., error = error ) if ( allocated ( error )) then return end if end do exe_loop : do i = 1 , size ( executables ) ! Check if executable already discovered automatically ! and apply any overrides do j = 1 , size ( sources ) if ( basename ( sources ( j )% file_name , suffix = . true .) == executables ( i )% main . and .& canon_path ( dirname ( sources ( j )% file_name )) == & canon_path ( executables ( i )% source_dir ) ) then sources ( j )% exe_name = executables ( i )% name if ( allocated ( executables ( i )% link )) then sources ( j )% link_libraries = executables ( i )% link end if sources ( j )% unit_type = FPM_UNIT_PROGRAM cycle exe_loop end if end do ! Add if not already discovered (auto_discovery off) associate ( exe => executables ( i )) exe_source = parse_source ( join_path ( exe % source_dir , exe % main ), error ) exe_source % exe_name = exe % name if ( allocated ( exe % link )) then exe_source % link_libraries = exe % link end if exe_source % unit_type = FPM_UNIT_PROGRAM exe_source % unit_scope = scope end associate if ( allocated ( error )) return if (. not . allocated ( sources )) then sources = [ exe_source ] else sources = [ sources , exe_source ] end if end do exe_loop end subroutine add_executable_sources","tags":"","loc":"proc/add_executable_sources.html"},{"title":"add_sources_from_dir – Fortran-lang/fpm","text":"public subroutine add_sources_from_dir(sources, directory, scope, with_executables, recurse, error) Add to sources by looking for source files in directory Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of srcfile_t objects to append to. Allocated if not allocated character(len=*), intent(in) :: directory Directory in which to search for source files integer, intent(in) :: scope Scope to apply to the discovered sources, see fpm_model for enumeration logical, intent(in), optional :: with_executables Executable sources (fortran program s) are ignored unless with_executables=.true. logical, intent(in), optional :: recurse Whether to recursively search subdirectories, default is .true. type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code add_sources_from_dir Source Code subroutine add_sources_from_dir ( sources , directory , scope , with_executables , recurse , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> Directory in which to search for source files character ( * ), intent ( in ) :: directory !> Scope to apply to the discovered sources, see [[fpm_model]] for enumeration integer , intent ( in ) :: scope !> Executable sources (fortran `program`s) are ignored unless `with_executables=.true.` logical , intent ( in ), optional :: with_executables !> Whether to recursively search subdirectories, default is `.true.` logical , intent ( in ), optional :: recurse !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i logical , allocatable :: is_source (:), exclude_source (:) logical :: recurse_ type ( string_t ), allocatable :: file_names (:) type ( string_t ), allocatable :: src_file_names (:) type ( string_t ), allocatable :: existing_src_files (:) type ( srcfile_t ), allocatable :: dir_sources (:) recurse_ = . true . if ( present ( recurse )) recurse_ = recurse ! Scan directory for sources call list_files ( directory , file_names , recurse = recurse_ ) if ( allocated ( sources )) then allocate ( existing_src_files ( size ( sources ))) do i = 1 , size ( sources ) existing_src_files ( i )% s = canon_path ( sources ( i )% file_name ) end do else allocate ( existing_src_files ( 0 )) end if is_source = [(. not .( is_hidden_file ( basename ( file_names ( i )% s ))) . and . & . not .( canon_path ( file_names ( i )% s ) . in . existing_src_files ) . and . & ( str_ends_with ( lower ( file_names ( i )% s ), fortran_suffixes ) . or . & str_ends_with ( lower ( file_names ( i )% s ), c_suffixes ) ), i = 1 , size ( file_names ))] src_file_names = pack ( file_names , is_source ) allocate ( dir_sources ( size ( src_file_names ))) allocate ( exclude_source ( size ( src_file_names ))) do i = 1 , size ( src_file_names ) dir_sources ( i ) = parse_source ( src_file_names ( i )% s , error ) if ( allocated ( error )) return dir_sources ( i )% unit_scope = scope allocate ( dir_sources ( i )% link_libraries ( 0 )) ! Exclude executables unless specified otherwise exclude_source ( i ) = ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM ) if ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM . and . & & present ( with_executables )) then if ( with_executables ) then exclude_source ( i ) = . false . end if end if end do if (. not . allocated ( sources )) then sources = pack ( dir_sources ,. not . exclude_source ) else sources = [ sources , pack ( dir_sources ,. not . exclude_source )] end if end subroutine add_sources_from_dir","tags":"","loc":"proc/add_sources_from_dir.html"},{"title":"parse_c_source – Fortran-lang/fpm","text":"public function parse_c_source(c_filename, error) result(c_source) Parsing of c, cpp source files The following statements are recognised and parsed: #include preprocessor statement Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: c_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) Contents Source Code parse_c_source Source Code function parse_c_source ( c_filename , error ) result ( c_source ) character ( * ), intent ( in ) :: c_filename type ( srcfile_t ) :: c_source type ( error_t ), allocatable , intent ( out ) :: error integer :: fh , n_include , i , pass , stat type ( string_t ), allocatable :: file_lines (:) c_source % file_name = c_filename if ( str_ends_with ( lower ( c_filename ), \".c\" )) then c_source % unit_type = FPM_UNIT_CSOURCE else if ( str_ends_with ( lower ( c_filename ), \".h\" )) then c_source % unit_type = FPM_UNIT_CHEADER else if ( str_ends_with ( lower ( c_filename ), \".cpp\" )) then c_source % unit_type = FPM_UNIT_CPPSOURCE end if allocate ( c_source % modules_used ( 0 )) allocate ( c_source % modules_provided ( 0 )) allocate ( c_source % parent_modules ( 0 )) open ( newunit = fh , file = c_filename , status = 'old' ) file_lines = read_lines ( fh ) close ( fh ) ! Ignore empty files, returned as FPM_UNIT_UNKNOWN if ( len_trim ( file_lines ) < 1 ) then c_source % unit_type = FPM_UNIT_UNKNOWN return end if c_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_include = 0 file_loop : do i = 1 , size ( file_lines ) ! Process 'INCLUDE' statements if ( index ( adjustl ( lower ( file_lines ( i )% s )), '#include' ) == 1 . and . & index ( file_lines ( i )% s , '\"' ) > 0 ) then n_include = n_include + 1 if ( pass == 2 ) then c_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , c_filename , & 'unable to get c include file' , i , & file_lines ( i )% s , index ( file_lines ( i )% s , '\"' )) return end if end if end if end do file_loop if ( pass == 1 ) then allocate ( c_source % include_dependencies ( n_include )) end if end do end function parse_c_source","tags":"","loc":"proc/parse_c_source.html"},{"title":"parse_f_source – Fortran-lang/fpm","text":"public function parse_f_source(f_filename, error) result(f_source) Parsing of free-form fortran source files The following statements are recognised and parsed: Module / submodule / program declaration Module use statement include statement Note Intrinsic modules used by sources are not listed in\n the modules_used field of source objects. Note Submodules are treated as normal modules which use their\n corresponding parent modules. Parsing limitations Statements must not continued onto another line\n except for an only: list in the use statement. This is supported: use my_module , only : & my_var , my_function , my_subroutine This is NOT supported: use & my_module Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) Contents Source Code parse_f_source Source Code function parse_f_source ( f_filename , error ) result ( f_source ) character ( * ), intent ( in ) :: f_filename type ( srcfile_t ) :: f_source type ( error_t ), allocatable , intent ( out ) :: error logical :: inside_module , inside_interface , using , intrinsic_module integer :: stat integer :: fh , n_use , n_include , n_mod , n_parent , i , j , ic , pass type ( string_t ), allocatable :: file_lines (:), file_lines_lower (:) character (:), allocatable :: temp_string , mod_name , string_parts (:) if (. not . exists ( f_filename )) then call file_not_found_error ( error , f_filename ) return end if f_source % file_name = f_filename open ( newunit = fh , file = f_filename , status = 'old' ) file_lines = read_lines_expanded ( fh ) close ( fh ) ! for efficiency in parsing make a lowercase left-adjusted copy of the file ! Need a copy because INCLUDE (and #include) file arguments are case-sensitive file_lines_lower = file_lines do i = 1 , size ( file_lines_lower ) file_lines_lower ( i )% s = adjustl ( lower ( file_lines_lower ( i )% s )) enddo ! fnv_1a can only be applied to non-zero-length arrays if ( len_trim ( file_lines_lower ) > 0 ) f_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_use = 0 n_include = 0 n_mod = 0 n_parent = 0 inside_module = . false . inside_interface = . false . file_loop : do i = 1 , size ( file_lines_lower ) ! Skip comment lines and preprocessor directives if ( index ( file_lines_lower ( i )% s , '!' ) == 1 . or . & index ( file_lines_lower ( i )% s , '#' ) == 1 . or . & len_trim ( file_lines_lower ( i )% s ) < 1 ) then cycle end if ! Detect exported C-API via bind(C) if (. not . inside_interface . and . & parse_subsequence ( file_lines_lower ( i )% s , 'bind' , '(' , 'c' )) then do j = i , 1 , - 1 if ( index ( file_lines_lower ( j )% s , 'function' ) > 0 . or . & index ( file_lines_lower ( j )% s , 'subroutine' ) > 0 ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM exit end if if ( j > 1 ) then ic = index ( file_lines_lower ( j - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( j - 1 )% s ) end if temp_string = trim ( file_lines_lower ( j - 1 )% s ( 1 : ic )) if ( index ( temp_string , '&' ) /= len ( temp_string )) then exit end if end if end do end if ! Skip lines that are continued: not statements if ( i > 1 ) then ic = index ( file_lines_lower ( i - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( i - 1 )% s ) end if temp_string = trim ( file_lines_lower ( i - 1 )% s ( 1 : ic )) if ( len ( temp_string ) > 0 . and . index ( temp_string , '&' ) == len ( temp_string )) then cycle end if end if ! Detect beginning of interface block if ( index ( file_lines_lower ( i )% s , 'interface' ) == 1 ) then inside_interface = . true . cycle end if ! Detect end of interface block if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'interface' )) then inside_interface = . false . cycle end if ! Process 'USE' statements call parse_use_statement ( f_filename , i , file_lines_lower ( i )% s , using , intrinsic_module , mod_name , error ) if ( allocated ( error )) return if ( using ) then ! Not a valid module name? if (. not . is_fortran_name ( mod_name )) cycle ! Valid intrinsic module: not a dependency if ( intrinsic_module ) cycle n_use = n_use + 1 if ( pass == 2 ) f_source % modules_used ( n_use )% s = mod_name cycle endif ! Process 'INCLUDE' statements ic = index ( file_lines_lower ( i )% s , 'include' ) if ( ic == 1 ) then ic = index ( lower ( file_lines ( i )% s ), 'include' ) if ( index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), '\"' ) == 1 . or . & index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), \"'\" ) == 1 ) then n_include = n_include + 1 if ( pass == 2 ) then f_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = \"'\" // '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find include file name' , i , & file_lines ( i )% s ) return end if end if cycle end if end if ! Extract name of module if is module if ( index ( file_lines_lower ( i )% s , 'module ' ) == 1 ) then ! Remove any trailing comments ic = index ( file_lines_lower ( i )% s , '!' ) - 1 if ( ic < 1 ) then ic = len ( file_lines_lower ( i )% s ) end if temp_string = trim ( file_lines_lower ( i )% s ( 1 : ic )) ! R1405 module-stmt := \"MODULE\" module-name ! module-stmt has two space-delimited parts only ! (no line continuations) call split ( temp_string , string_parts , ' ' ) if ( size ( string_parts ) /= 2 ) then cycle end if mod_name = trim ( adjustl ( string_parts ( 2 ))) if ( scan ( mod_name , '=(&' ) > 0 ) then ! Ignore these cases: ! module & ! module =* ! module (i) cycle end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for module' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 if ( pass == 2 ) then f_source % modules_provided ( n_mod ) = string_t ( mod_name ) end if if ( f_source % unit_type == FPM_UNIT_UNKNOWN ) then f_source % unit_type = FPM_UNIT_MODULE end if if (. not . inside_module ) then inside_module = . true . else ! Must have missed an end module statement (can't assume a pure module) if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end if cycle end if ! Extract name of submodule if is submodule if ( index ( file_lines_lower ( i )% s , 'submodule' ) == 1 ) then mod_name = split_n ( file_lines_lower ( i )% s , n = 3 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule name' , i , & file_lines_lower ( i )% s ) return end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule ancestry' , i , & file_lines_lower ( i )% s ) return end if if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBMODULE end if n_use = n_use + 1 inside_module = . true . n_parent = n_parent + 1 if ( pass == 2 ) then if ( index ( temp_string , ':' ) > 0 ) then temp_string = temp_string ( index ( temp_string , ':' ) + 1 :) end if if (. not . is_fortran_name ( temp_string )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule parent' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , temp_string )) return end if f_source % modules_used ( n_use )% s = temp_string f_source % parent_modules ( n_parent )% s = temp_string f_source % modules_provided ( n_mod )% s = mod_name end if cycle end if ! Detect if contains a program ! (no modules allowed after program def) if ( index ( file_lines_lower ( i )% s , 'program ' ) == 1 ) then temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = ' ' , stat = stat ) if ( stat == 0 ) then if ( scan ( temp_string , '=(' ) > 0 ) then ! Ignore: ! program =* ! program (i) =* cycle end if end if f_source % unit_type = FPM_UNIT_PROGRAM cycle end if ! Parse end module statement ! (to check for code outside of modules) if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'module' ) . or . & parse_sequence ( file_lines_lower ( i )% s , 'end' , 'submodule' )) then inside_module = . false . cycle end if ! Any statements not yet parsed are assumed to be other code statements if (. not . inside_module . and . f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end do file_loop ! If unable to parse end of module statement, then can't assume pure module ! (there could be non-module subprograms present) if ( inside_module . and . f_source % unit_type == FPM_UNIT_MODULE ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if if ( pass == 1 ) then allocate ( f_source % modules_used ( n_use )) allocate ( f_source % include_dependencies ( n_include )) allocate ( f_source % modules_provided ( n_mod )) allocate ( f_source % parent_modules ( n_parent )) end if end do end function parse_f_source","tags":"","loc":"proc/parse_f_source.html"},{"title":"parse_use_statement – Fortran-lang/fpm","text":"public subroutine parse_use_statement(f_filename, i, line, use_stmt, is_intrinsic, module_name, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename Current file name and line number (for error messaging) integer, intent(in) :: i character(len=*), intent(in) :: line The line being parsed. MUST BE preprocessed with trim(adjustl() logical, intent(out) :: use_stmt Does this line contain a use statement? logical, intent(out) :: is_intrinsic Is the module in this statement intrinsic? character(len=:), intent(out), allocatable :: module_name used module name type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code parse_use_statement Source Code subroutine parse_use_statement ( f_filename , i , line , use_stmt , is_intrinsic , module_name , error ) !> Current file name and line number (for error messaging) character ( * ), intent ( in ) :: f_filename integer , intent ( in ) :: i !> The line being parsed. MUST BE preprocessed with trim(adjustl() character ( * ), intent ( in ) :: line !> Does this line contain a `use` statement? logical , intent ( out ) :: use_stmt !> Is the module in this statement intrinsic? logical , intent ( out ) :: is_intrinsic !> used module name character (:), allocatable , intent ( out ) :: module_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( 15 ), parameter :: INTRINSIC_NAMES ( * ) = & [ 'iso_c_binding ' , & 'iso_fortran_env' , & 'ieee_arithmetic' , & 'ieee_exceptions' , & 'ieee_features ' , & 'omp_lib ' ] character ( len = :), allocatable :: temp_string integer :: colons , intr , nonintr , j , stat logical :: has_intrinsic_name use_stmt = . false . is_intrinsic = . false . if ( len_trim ( line ) <= 0 ) return ! Quick check that the line is preprocessed if ( line ( 1 : 1 ) == ' ' ) then call fatal_error ( error , 'internal_error: source file line is not trim(adjustl()) on input to parse_use_statement' ) return end if ! 'use' should be the first string in the adjustl line use_stmt = index ( line , 'use ' ) == 1 . or . index ( line , 'use::' ) == 1 . or . index ( line , 'use,' ) == 1 if (. not . use_stmt ) return colons = index ( line , '::' ) nonintr = 0 intr = 0 have_colons : if ( colons > 3 ) then ! there may be an intrinsic/non-intrinsic spec nonintr = index ( line ( 1 : colons - 1 ), 'non_intrinsic' ) if ( nonintr == 0 ) intr = index ( line ( 1 : colons - 1 ), 'intrinsic' ) temp_string = split_n ( line , delims = ':' , n = 2 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line , colons ) return end if module_name = split_n ( temp_string , delims = ' ,' , n = 1 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if else module_name = split_n ( line , n = 2 , delims = ' ,' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if end if have_colons ! If declared intrinsic, check that it is true has_intrinsic_name = any ([( index ( module_name , trim ( INTRINSIC_NAMES ( j ))) > 0 , & j = 1 , size ( INTRINSIC_NAMES ))]) if ( intr > 0 . and . . not . has_intrinsic_name ) then ! An intrinsic module was not found. Its name could be in the next line, ! in which case, we just skip this check. The compiler will do the job if the name is invalid. ! Module name was not read: it's in the next line if ( index ( module_name , '&' ) <= 0 ) then call file_parse_error ( error , f_filename , & 'module ' // module_name // ' is declared intrinsic but it is not ' , i , & line ) return endif endif ! Should we treat this as an intrinsic module is_intrinsic = nonintr == 0 . and . & ! not declared non-intrinsic ( intr > 0 . or . has_intrinsic_name ) end subroutine parse_use_statement","tags":"","loc":"proc/parse_use_statement.html"},{"title":"basename – Fortran-lang/fpm","text":"public function basename(path, suffix) result(base) Extract filename from path with/without suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: suffix Return Value character(len=:), allocatable Contents Source Code basename Source Code function basename ( path , suffix ) result ( base ) character ( * ), intent ( In ) :: path logical , intent ( in ), optional :: suffix character (:), allocatable :: base character (:), allocatable :: file_parts (:) logical :: with_suffix if (. not . present ( suffix )) then with_suffix = . true . else with_suffix = suffix end if call split ( path , file_parts , delimiters = '\\/' ) if ( size ( file_parts ) > 0 ) then base = trim ( file_parts ( size ( file_parts ))) else base = '' endif if (. not . with_suffix ) then call split ( base , file_parts , delimiters = '.' ) if ( size ( file_parts ) >= 2 ) then base = trim ( file_parts ( size ( file_parts ) - 1 )) endif endif end function basename","tags":"","loc":"proc/basename.html"},{"title":"canon_path – Fortran-lang/fpm","text":"public function canon_path(path) Canonicalize path for comparison\n* Handles path string redundancies\n* Does not test existence of path To be replaced by realpath/_fullname in stdlib_os FIXME: Lot’s of ugly hacks following here Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code canon_path Source Code function canon_path ( path ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: canon_path character ( len = :), allocatable :: nixpath integer :: istart , iend , nn , last logical :: is_path , absolute nixpath = unix_path ( path ) istart = 0 nn = 0 iend = 0 absolute = nixpath ( 1 : 1 ) == \"/\" if ( absolute ) then canon_path = \"/\" else canon_path = \"\" end if do while ( iend < len ( nixpath )) call next ( nixpath , istart , iend , is_path ) if ( is_path ) then select case ( nixpath ( istart : iend )) case ( \".\" , \"\" ) ! always drop empty paths case ( \"..\" ) if ( nn > 0 ) then last = scan ( canon_path (: len ( canon_path ) - 1 ), \"/\" , back = . true .) canon_path = canon_path (: last ) nn = nn - 1 else if (. not . absolute ) then canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end if end if case default nn = nn + 1 canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end select end if end do if ( len ( canon_path ) == 0 ) canon_path = \".\" if ( len ( canon_path ) > 1 . and . canon_path ( len ( canon_path ):) == \"/\" ) then canon_path = canon_path (: len ( canon_path ) - 1 ) end if contains subroutine next ( string , istart , iend , is_path ) character ( len =* ), intent ( in ) :: string integer , intent ( inout ) :: istart integer , intent ( inout ) :: iend logical , intent ( inout ) :: is_path integer :: ii , nn character :: tok nn = len ( string ) if ( iend >= nn ) then istart = nn iend = nn return end if ii = min ( iend + 1 , nn ) tok = string ( ii : ii ) is_path = tok /= '/' if (. not . is_path ) then is_path = . false . istart = ii iend = ii return end if istart = ii do ii = min ( iend + 1 , nn ), nn tok = string ( ii : ii ) select case ( tok ) case ( '/' ) exit case default iend = ii cycle end select end do end subroutine next end function canon_path","tags":"","loc":"proc/canon_path.html"},{"title":"dirname – Fortran-lang/fpm","text":"public function dirname(path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code dirname Source Code function dirname ( path ) result ( dir ) character ( * ), intent ( in ) :: path character (:), allocatable :: dir dir = path ( 1 : scan ( path , ' / \\' , back = . true .)) end function dirname","tags":"","loc":"proc/dirname.html"},{"title":"exists – Fortran-lang/fpm","text":"public function exists(filename) result(r) test if pathname already exists Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value logical Contents","tags":"","loc":"proc/exists.html"},{"title":"get_dos_path – Fortran-lang/fpm","text":"public function get_dos_path(path, error) Ensure a windows path is converted to an 8.3 DOS path if it contains spaces\nNo need to convert if there are no spaces Read screen output Ensure there are no trailing slashes Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error Return Value character(len=:), allocatable Contents Source Code get_dos_path Source Code function get_dos_path ( path , error ) character ( len =* ), intent ( in ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: get_dos_path character (:), allocatable :: redirect , screen_output , line integer :: stat , cmdstat , iunit , last ! Non-Windows OS if ( get_os_type () /= OS_WINDOWS ) then get_dos_path = path return end if ! Trim path first get_dos_path = trim ( path ) !> No need to convert if there are no spaces has_spaces : if ( scan ( get_dos_path , ' ' ) > 0 ) then redirect = get_temp_filename () call execute_command_line ( 'cmd /c for %A in (\"' // path // '\") do @echo %~sA >' // redirect // ' 2>&1' ,& exitstat = stat , cmdstat = cmdstat ) !> Read screen output command_OK : if ( cmdstat == 0 . and . stat == 0 ) then allocate ( character ( len = 0 ) :: screen_output ) open ( newunit = iunit , file = redirect , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output = screen_output // line // ' ' end do ! Close and delete file close ( iunit , status = 'delete' ) else call fatal_error ( error , 'cannot read temporary file from successful DOS path evaluation' ) return endif else command_OK call fatal_error ( error , 'unsuccessful Windows->DOS path command' ) return end if command_OK get_dos_path = trim ( adjustl ( screen_output )) endif has_spaces !> Ensure there are no trailing slashes last = len_trim ( get_dos_path ) if ( last > 1 . and . get_dos_path ( last : last ) == '/' . or . get_dos_path ( last : last ) == '\\' ) get_dos_path = get_dos_path ( 1 : last - 1 ) end function get_dos_path","tags":"","loc":"proc/get_dos_path.html"},{"title":"get_local_prefix – Fortran-lang/fpm","text":"public function get_local_prefix(os) result(prefix) Determine the path prefix to the local folder. Used for installation, registry etc. Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Platform identifier Return Value character(len=:), allocatable Installation prefix Contents Source Code get_local_prefix Source Code function get_local_prefix ( os ) result ( prefix ) !> Installation prefix character ( len = :), allocatable :: prefix !> Platform identifier integer , intent ( in ), optional :: os !> Default installation prefix on Unix platforms character ( len =* ), parameter :: default_prefix_unix = \"/usr/local\" !> Default installation prefix on Windows platforms character ( len =* ), parameter :: default_prefix_win = \"C:\\\" character(len=:), allocatable :: home if (os_is_unix(os)) then home=get_env('HOME','') if (home /= '' ) then prefix = join_path(home, \" . local \") else prefix = default_prefix_unix end if else home=get_env('APPDATA','') if (home /= '' ) then prefix = join_path(home, \" local \" ) else prefix = default_prefix_win end if end if end function get_local_prefix","tags":"","loc":"proc/get_local_prefix.html"},{"title":"get_temp_filename – Fortran-lang/fpm","text":"public function get_temp_filename() result(tempfile) Uses iso_c_binding Get a unused temporary filename\n Calls posix ‘tempnam’ - not recommended, but\n we have no security concerns for this application\n and use here is temporary.\nWorks with MinGW Arguments None Return Value character(len=:), allocatable Contents Source Code get_temp_filename Source Code function get_temp_filename () result ( tempfile ) ! use iso_c_binding , only : c_ptr , C_NULL_PTR , c_f_pointer integer , parameter :: MAX_FILENAME_LENGTH = 32768 character (:), allocatable :: tempfile type ( c_ptr ) :: c_tempfile_ptr character ( len = 1 ), pointer :: c_tempfile (:) interface function c_tempnam ( dir , pfx ) result ( tmp ) bind ( c , name = \"tempnam\" ) import type ( c_ptr ), intent ( in ), value :: dir type ( c_ptr ), intent ( in ), value :: pfx type ( c_ptr ) :: tmp end function c_tempnam subroutine c_free ( ptr ) BIND ( C , name = \"free\" ) import type ( c_ptr ), value :: ptr end subroutine c_free end interface c_tempfile_ptr = c_tempnam ( C_NULL_PTR , C_NULL_PTR ) call c_f_pointer ( c_tempfile_ptr , c_tempfile ,[ MAX_FILENAME_LENGTH ]) tempfile = f_string ( c_tempfile ) call c_free ( c_tempfile_ptr ) end function get_temp_filename","tags":"","loc":"proc/get_temp_filename.html"},{"title":"is_absolute_path – Fortran-lang/fpm","text":"public function is_absolute_path(path, is_unix) Returns .true. if provided path is absolute. ~ not treated as absolute. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: is_unix Return Value logical Contents Source Code is_absolute_path Source Code logical function is_absolute_path ( path , is_unix ) character ( len =* ), intent ( in ) :: path logical , optional , intent ( in ) :: is_unix character ( len =* ), parameter :: letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' logical :: is_unix_os if ( present ( is_unix )) then is_unix_os = is_unix else is_unix_os = os_is_unix () end if if ( is_unix_os ) then is_absolute_path = path ( 1 : 1 ) == '/' else if ( len ( path ) < 2 ) then is_absolute_path = . false . return end if is_absolute_path = index ( letters , path ( 1 : 1 )) /= 0 . and . path ( 2 : 2 ) == ':' end if end function is_absolute_path","tags":"","loc":"proc/is_absolute_path.html"},{"title":"is_dir – Fortran-lang/fpm","text":"public function is_dir(dir) test if a name matches an existing directory path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical Contents Source Code is_dir Source Code logical function is_dir ( dir ) character ( * ), intent ( in ) :: dir integer :: stat select case ( get_os_type ()) case ( OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD ) call run ( \"test -d \" // dir , & & exitstat = stat , echo = . false ., verbose = . false .) case ( OS_WINDOWS ) call run ( 'cmd /c \"if not exist ' // windows_path ( dir ) // '\\ exit /B 1\"' , & & exitstat = stat , echo = . false ., verbose = . false .) end select is_dir = ( stat == 0 ) end function is_dir","tags":"","loc":"proc/is_dir.html"},{"title":"is_hidden_file – Fortran-lang/fpm","text":"public function is_hidden_file(file_basename) result(r) test if a file is hidden Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file_basename Return Value logical Contents Source Code is_hidden_file Source Code logical function is_hidden_file ( file_basename ) result ( r ) character ( * ), intent ( in ) :: file_basename if ( len ( file_basename ) <= 2 ) then r = . false . else r = str_begins_with_str ( file_basename , '.' ) end if end function is_hidden_file","tags":"","loc":"proc/is_hidden_file.html"},{"title":"join_path – Fortran-lang/fpm","text":"public function join_path(a1, a2, a3, a4, a5) result(path) Construct path by joining strings with os file separator Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: a1 character(len=*), intent(in) :: a2 character(len=*), intent(in), optional :: a3 character(len=*), intent(in), optional :: a4 character(len=*), intent(in), optional :: a5 Return Value character(len=:), allocatable Contents Source Code join_path Source Code function join_path ( a1 , a2 , a3 , a4 , a5 ) result ( path ) character ( len =* ), intent ( in ) :: a1 , a2 character ( len =* ), intent ( in ), optional :: a3 , a4 , a5 character ( len = :), allocatable :: path character ( len = 1 ) :: filesep logical , save :: has_cache = . false . character ( len = 1 ), save :: cache = '/' !$omp threadprivate(has_cache, cache) if ( has_cache ) then filesep = cache else select case ( get_os_type ()) case default filesep = '/' case ( OS_WINDOWS ) filesep = '\\' end select cache = filesep has_cache = . true . end if if ( a1 == \"\" ) then path = a2 else path = a1 // filesep // a2 end if if ( present ( a3 )) then path = path // filesep // a3 else return end if if ( present ( a4 )) then path = path // filesep // a4 else return end if if ( present ( a5 )) then path = path // filesep // a5 else return end if end function join_path","tags":"","loc":"proc/join_path.html"},{"title":"number_of_rows – Fortran-lang/fpm","text":"public function number_of_rows(s) result(nrows) Determine number or rows in a file given a LUN Arguments Type Intent Optional Attributes Name integer, intent(in) :: s Return Value integer Contents Source Code number_of_rows Source Code integer function number_of_rows ( s ) result ( nrows ) integer , intent ( in ) :: s integer :: ios rewind ( s ) nrows = 0 do read ( s , * , iostat = ios ) if ( ios /= 0 ) exit nrows = nrows + 1 end do rewind ( s ) end function number_of_rows","tags":"","loc":"proc/number_of_rows.html"},{"title":"parent_dir – Fortran-lang/fpm","text":"public function parent_dir(path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code parent_dir Source Code function parent_dir ( path ) result ( dir ) character ( * ), intent ( in ) :: path character (:), allocatable :: dir dir = path ( 1 : scan ( path , ' / \\' , back = . true .) - 1 ) end function parent_dir","tags":"","loc":"proc/parent_dir.html"},{"title":"read_lines – Fortran-lang/fpm","text":"public function read_lines(fh) result(lines) read lines into an array of TYPE(STRING_T) variables Arguments Type Intent Optional Attributes Name integer, intent(in) :: fh Return Value type( string_t ), allocatable, (:) Contents Source Code read_lines Source Code function read_lines ( fh ) result ( lines ) integer , intent ( in ) :: fh type ( string_t ), allocatable :: lines (:) integer :: i integer :: iostat allocate ( lines ( number_of_rows ( fh ))) do i = 1 , size ( lines ) call getline ( fh , lines ( i )% s , iostat ) end do end function read_lines","tags":"","loc":"proc/read_lines.html"},{"title":"read_lines_expanded – Fortran-lang/fpm","text":"public function read_lines_expanded(fh) result(lines) read lines into an array of TYPE(STRING_T) variables expanding tabs Arguments Type Intent Optional Attributes Name integer, intent(in) :: fh Return Value type( string_t ), allocatable, (:) Contents Source Code read_lines_expanded Source Code function read_lines_expanded ( fh ) result ( lines ) integer , intent ( in ) :: fh type ( string_t ), allocatable :: lines (:) integer :: i integer :: iostat character ( len = :), allocatable :: line_buffer_read allocate ( lines ( number_of_rows ( fh ))) do i = 1 , size ( lines ) call getline ( fh , line_buffer_read , iostat ) lines ( i )% s = dilate ( line_buffer_read ) end do end function read_lines_expanded","tags":"","loc":"proc/read_lines_expanded.html"},{"title":"unix_path – Fortran-lang/fpm","text":"public function unix_path(path) result(nixpath) Replace file system separators for 1 Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code unix_path Source Code function unix_path ( path ) result ( nixpath ) character ( * ), intent ( in ) :: path character (:), allocatable :: nixpath integer :: idx nixpath = path idx = index ( nixpath , '\\') do while(idx > 0) nixpath(idx:idx) = ' / ' idx = index(nixpath,' \\' ) end do end function unix_path","tags":"","loc":"proc/unix_path.html"},{"title":"which – Fortran-lang/fpm","text":"public function which(command) result(pathname) Name which ( 3 f ) - [ M_io : ENVIRONMENT ] given a command name find the pathname by searching the directories in the environment variable $ PATH ( LICENSE : PD ) Syntax function which(command) result(pathname) character(len=*),intent(in) :: command\ncharacter(len=:),allocatable :: pathname Description Given a command name find the first file with that name in the directories specified by the environment variable $ PATH . options COMMAND the command to search for Returns PATHNAME the first pathname found in the current user path . Returns blank if the command is not found . Example Sample program: Checking the error message and counting lines: program demo_which use M_io , only : which implicit none write ( * , * ) ' ls is ' , which ( ' ls ' ) write ( * , * ) ' dir is ' , which ( ' dir ' ) write ( * , * ) ' install is ' , which ( ' install ' ) end program demo_which Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: command Return Value character(len=:), allocatable Contents Source Code which Source Code function which ( command ) result ( pathname ) character ( len =* ), intent ( in ) :: command character ( len = :), allocatable :: pathname , checkon , paths (:), exts (:) integer :: i , j pathname = '' call split ( get_env ( 'PATH' ), paths , delimiters = merge ( ';' , ':' , separator () == '\\')) SEARCH: do i=1,size(paths) checkon=trim(join_path(trim(paths(i)),command)) select case(separator()) case(' / ') if(exists(checkon))then pathname=checkon exit SEARCH endif case(' \\ ') if(exists(checkon))then pathname=checkon exit SEARCH endif if(exists(checkon//' . bat '))then pathname=checkon//' . bat ' exit SEARCH endif if(exists(checkon//' . exe '))then pathname=checkon//' . exe ' exit SEARCH endif call split(get_env(' PATHEXT '),exts,delimiters=' ; ') do j=1,size(exts) if(exists(checkon//' . '//trim(exts(j))))then pathname=checkon//' . ' // trim ( exts ( j )) exit SEARCH endif enddo end select enddo SEARCH end function which","tags":"","loc":"proc/which.html"},{"title":"windows_path – Fortran-lang/fpm","text":"public function windows_path(path) result(winpath) Replace file system separators for windows Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code windows_path Source Code function windows_path ( path ) result ( winpath ) character ( * ), intent ( in ) :: path character (:), allocatable :: winpath integer :: idx winpath = path idx = index ( winpath , '/' ) do while ( idx > 0 ) winpath ( idx : idx ) = '\\' idx = index(winpath,' / ' ) end do end function windows_path","tags":"","loc":"proc/windows_path.html"},{"title":"delete_file – Fortran-lang/fpm","text":"public subroutine delete_file(file) delete a file by filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file Contents Source Code delete_file Source Code subroutine delete_file ( file ) character ( len =* ), intent ( in ) :: file logical :: exist integer :: unit inquire ( file = file , exist = exist ) if ( exist ) then open ( file = file , newunit = unit ) close ( unit , status = \"delete\" ) end if end subroutine delete_file","tags":"","loc":"proc/delete_file.html"},{"title":"execute_and_read_output – Fortran-lang/fpm","text":"public subroutine execute_and_read_output(cmd, output, error, verbose) Execute command line and return output as a string. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd Command to execute. character(len=:), intent(out), allocatable :: output Command line output. type( error_t ), intent(out), allocatable :: error Error to handle. logical, intent(in), optional :: verbose Print additional information if true. Contents","tags":"","loc":"proc/execute_and_read_output.html"},{"title":"fileclose – Fortran-lang/fpm","text":"public subroutine fileclose(lun, ier) simple close of a LUN. On error show message and stop (by default) Arguments Type Intent Optional Attributes Name integer, intent(in) :: lun integer, intent(out), optional :: ier Contents Source Code fileclose Source Code subroutine fileclose ( lun , ier ) integer , intent ( in ) :: lun integer , intent ( out ), optional :: ier character ( len = 256 ) :: message integer :: ios if ( lun /=- 1 ) then close ( unit = lun , iostat = ios , iomsg = message ) if ( ios /= 0 ) then if ( present ( ier )) then ier = ios else call fpm_stop ( 4 , '*fileclose*:' // trim ( message )) endif endif endif end subroutine fileclose","tags":"","loc":"proc/fileclose.html"},{"title":"fileopen – Fortran-lang/fpm","text":"public subroutine fileopen(filename, lun, ier) procedure to open filename as a sequential “text” file Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename integer, intent(out) :: lun integer, intent(out), optional :: ier Contents Source Code fileopen Source Code subroutine fileopen ( filename , lun , ier ) character ( len =* ), intent ( in ) :: filename integer , intent ( out ) :: lun integer , intent ( out ), optional :: ier integer :: ios character ( len = 256 ) :: message message = ' ' ios = 0 if ( filename /= ' ' ) then open ( file = filename , & & newunit = lun , & & form = 'formatted' , & ! FORM = FORMATTED | UNFORMATTED & access = 'sequential' , & ! ACCESS = SEQUENTIAL| DIRECT | STREAM & action = 'write' , & ! ACTION = READ|WRITE| READWRITE & position = 'rewind' , & ! POSITION= ASIS | REWIND | APPEND & status = 'new' , & ! STATUS = NEW| REPLACE| OLD| SCRATCH| UNKNOWN & iostat = ios , & & iomsg = message ) else lun = stdout ios = 0 endif if ( ios /= 0 ) then lun =- 1 if ( present ( ier )) then ier = ios else call fpm_stop ( 3 , '*fileopen*:' // filename // ':' // trim ( message )) endif endif end subroutine fileopen","tags":"","loc":"proc/fileopen.html"},{"title":"filewrite – Fortran-lang/fpm","text":"public subroutine filewrite(filename, filedata) procedure to write filedata to file filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename character(len=*), intent(in) :: filedata (:) Contents Source Code filewrite Source Code subroutine filewrite ( filename , filedata ) character ( len =* ), intent ( in ) :: filename character ( len =* ), intent ( in ) :: filedata (:) integer :: lun , i , ios character ( len = 256 ) :: message call fileopen ( filename , lun ) if ( lun /=- 1 ) then ! program currently stops on error on open, but might ! want it to continue so -1 (unallowed LUN) indicates error ! write file do i = 1 , size ( filedata ) write ( lun , '(a)' , iostat = ios , iomsg = message ) trim ( filedata ( i )) if ( ios /= 0 ) then call fpm_stop ( 5 , '*filewrite*:' // filename // ':' // trim ( message )) endif enddo endif ! close file call fileclose ( lun ) end subroutine filewrite","tags":"","loc":"proc/filewrite.html"},{"title":"get_home – Fortran-lang/fpm","text":"public subroutine get_home(home, error) Get the HOME directory on Unix and the %USERPROFILE% directory on Windows. Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: home type( error_t ), intent(out), allocatable :: error Contents Source Code get_home Source Code subroutine get_home ( home , error ) character ( len = :), allocatable , intent ( out ) :: home type ( error_t ), allocatable , intent ( out ) :: error if ( os_is_unix ()) then home = get_env ( 'HOME' , '' ) if ( home == '' ) then call fatal_error ( error , \"Couldn't retrieve 'HOME' variable\" ) return end if else home = get_env ( 'USERPROFILE' , '' ) if ( home == '' ) then call fatal_error ( error , \"Couldn't retrieve '%USERPROFILE%' variable\" ) return end if end if end subroutine get_home","tags":"","loc":"proc/get_home.html"},{"title":"getline – Fortran-lang/fpm","text":"public subroutine getline(unit, line, iostat, iomsg) NAME getline(3f) - [M_io:READ] read a line of arbintrary length from specified\n LUN into allocatable string (up to system line length limit)\n(LICENSE:PD) SYNTAX subroutine getline(unit,line,iostat,iomsg) integer,intent(in) :: unit\ncharacter(len=:),allocatable,intent(out) :: line\ninteger,intent(out) :: iostat\ncharacter(len=:), allocatable, optional :: iomsg DESCRIPTION Read a line of any length up to programming environment maximum line length . Requires Fortran 2003 +. It is primarily expected to be used when reading input which will then be parsed or echoed . The input file must have a PAD attribute of YES for the function to work properly , which is typically true . The simple use of a loop that repeatedly re - allocates a character variable in addition to reading the input file one buffer at a time could ( depending on the programming environment used ) be inefficient , as it could reallocate and allocate memory used for the output string with each buffer read . OPTIONS LINE The line read when IOSTAT returns as zero . LUN LUN ( Fortran logical I / O unit ) number of file open and ready to read . IOSTAT status returned by READ ( IOSTAT = IOS ) . If not zero , an error occurred or an end - of - file or end - of - record was encountered . IOMSG error message returned by system when IOSTAT is not zero . EXAMPLE Sample program: program demo_getline use , intrinsic :: iso_fortran_env , only : stdin => input_unit use , intrinsic :: iso_fortran_env , only : iostat_end use FPM_filesystem , only : getline implicit none integer :: iostat character ( len = : ) , allocatable :: line , iomsg open ( unit = stdin , pad = ' yes ' ) INFINITE : do call getline ( stdin , line , iostat , iomsg ) if ( iostat /= 0 ) exit INFINITE write ( * , ' (a) ' ) ' [ ' // line // ' ] ' enddo INFINITE if ( iostat /= iostat_end ) then write ( * , * ) ' error reading input: ' , iomsg endif end program demo_getline Arguments Type Intent Optional Attributes Name integer, intent(in) :: unit Formatted IO unit character(len=:), intent(out), allocatable :: line Line to read integer, intent(out) :: iostat Status of operation character(len=:), optional, allocatable :: iomsg Error message Contents Source Code getline Source Code subroutine getline ( unit , line , iostat , iomsg ) !> Formatted IO unit integer , intent ( in ) :: unit !> Line to read character ( len = :), allocatable , intent ( out ) :: line !> Status of operation integer , intent ( out ) :: iostat !> Error message character ( len = :), allocatable , optional :: iomsg integer , parameter :: BUFFER_SIZE = 32768 character ( len = BUFFER_SIZE ) :: buffer character ( len = 256 ) :: msg integer :: size integer :: stat allocate ( character ( len = 0 ) :: line ) do read ( unit , '(a)' , advance = 'no' , iostat = stat , iomsg = msg , size = size ) & & buffer if ( stat > 0 ) exit line = line // buffer (: size ) if ( stat < 0 ) then if ( is_iostat_eor ( stat )) then stat = 0 end if exit end if end do if ( stat /= 0 ) then if ( present ( iomsg )) iomsg = trim ( msg ) end if iostat = stat end subroutine getline","tags":"","loc":"proc/getline.html"},{"title":"list_files – Fortran-lang/fpm","text":"public recursive subroutine list_files(dir, files, recurse) Get file & directory names in directory dir using iso_c_binding. File/directory names return are relative to cwd, ie. preprended with dir Includes files starting with . except current directory and parent directory Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir type( string_t ), intent(out), allocatable :: files (:) logical, intent(in), optional :: recurse Contents Source Code list_files Source Code recursive subroutine list_files ( dir , files , recurse ) character ( len =* ), intent ( in ) :: dir type ( string_t ), allocatable , intent ( out ) :: files (:) logical , intent ( in ), optional :: recurse integer :: i type ( string_t ), allocatable :: dir_files (:) type ( string_t ), allocatable :: sub_dir_files (:) type ( c_ptr ) :: dir_handle type ( c_ptr ) :: dir_entry_c character ( len = :, kind = c_char ), allocatable :: fortran_name character ( len = :), allocatable :: string_fortran integer , parameter :: N_MAX = 256 type ( string_t ) :: files_tmp ( N_MAX ) integer ( kind = c_int ) :: r if ( c_is_dir ( dir ( 1 : len_trim ( dir )) // c_null_char ) == 0 ) then allocate ( files ( 0 )) return end if dir_handle = c_opendir ( dir ( 1 : len_trim ( dir )) // c_null_char ) if (. not . c_associated ( dir_handle )) then print * , 'c_opendir() failed' error stop end if i = 0 allocate ( files ( 0 )) do dir_entry_c = c_readdir ( dir_handle ) if (. not . c_associated ( dir_entry_c )) then exit else string_fortran = f_string ( c_get_d_name ( dir_entry_c )) if (( string_fortran == '.' . or . string_fortran == '..' )) then cycle end if i = i + 1 if ( i > N_MAX ) then files = [ files , files_tmp ] i = 1 end if files_tmp ( i )% s = join_path ( dir , string_fortran ) end if end do r = c_closedir ( dir_handle ) if ( r /= 0 ) then print * , 'c_closedir() failed' error stop end if if ( i > 0 ) then files = [ files , files_tmp ( 1 : i )] end if if ( present ( recurse )) then if ( recurse ) then allocate ( sub_dir_files ( 0 )) do i = 1 , size ( files ) if ( c_is_dir ( files ( i )% s // c_null_char ) /= 0 ) then call list_files ( files ( i )% s , dir_files , recurse = . true .) sub_dir_files = [ sub_dir_files , dir_files ] end if end do files = [ files , sub_dir_files ] end if end if end subroutine list_files","tags":"","loc":"proc/list_files.html"},{"title":"mkdir – Fortran-lang/fpm","text":"public subroutine mkdir(dir, echo) Create a directory. Create subdirectories as needed Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir logical, intent(in), optional :: echo Contents Source Code mkdir Source Code subroutine mkdir ( dir , echo ) character ( len =* ), intent ( in ) :: dir logical , intent ( in ), optional :: echo integer :: stat if ( is_dir ( dir )) return select case ( get_os_type ()) case ( OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD ) call run ( 'mkdir -p ' // dir , exitstat = stat , echo = echo , verbose = . false .) case ( OS_WINDOWS ) call run ( \"mkdir \" // windows_path ( dir ), & & echo = echo , exitstat = stat , verbose = . false .) end select if ( stat /= 0 ) then call fpm_stop ( 1 , '*mkdir*:directory creation failed' ) end if end subroutine mkdir","tags":"","loc":"proc/mkdir.html"},{"title":"os_delete_dir – Fortran-lang/fpm","text":"public subroutine os_delete_dir(is_unix, dir, echo) Delete directory using system OS remove directory commands Arguments Type Intent Optional Attributes Name logical, intent(in) :: is_unix character(len=*), intent(in) :: dir logical, intent(in), optional :: echo Contents Source Code os_delete_dir Source Code subroutine os_delete_dir ( is_unix , dir , echo ) logical , intent ( in ) :: is_unix character ( len =* ), intent ( in ) :: dir logical , intent ( in ), optional :: echo if ( is_unix ) then call run ( 'rm -rf ' // dir , echo = echo , verbose = . false .) else call run ( 'rmdir /s/q ' // dir , echo = echo , verbose = . false .) end if end subroutine os_delete_dir","tags":"","loc":"proc/os_delete_dir.html"},{"title":"run – Fortran-lang/fpm","text":"public subroutine run(cmd, echo, exitstat, verbose, redirect) Name run(3f) - execute specified system command and selectively echo\ncommand and output to a file and/or stdout.\n(LICENSE:MIT) Syntax subroutine run(cmd,echo,exitstat,verbose,redirect)\n\n character(len=*), intent(in) :: cmd\n logical,intent(in),optional :: echo\n integer, intent(out),optional :: exitstat\n logical, intent(in), optional :: verbose\n character(*), intent(in), optional :: redirect Description Execute the specified system command. Optionally echo the command before execution return the system exit status of the command. redirect the output of the command to a file. echo command output to stdout Calling run(3f) is preferred to direct calls to\n execute_command_line(3f) in the fpm(1) source to provide a standard\n interface where output modes can be specified. Options CMD System command to execute ECHO Whether to echo the command being executed or not Defaults to . TRUE . . VERBOSE Whether to redirect the command output to a null device or not Defaults to . TRUE . . REDIRECT Filename to redirect stdout and stderr of the command into . If generated it is closed before run ( 3 f ) returns . EXITSTAT The system exit status of the command when supported by the system . If not present and a non - zero status is generated program termination occurs . Example Sample program: Checking the error message and counting lines: program demo_run use fpm_filesystem , only : run implicit none logical , parameter :: T = . true ., F = . false . integer :: exitstat character ( len = : ) , allocatable :: cmd cmd = ' ls -ltrasd *.md ' call run ( cmd ) call run ( cmd , exitstat = exitstat ) call run ( cmd , echo = F ) call run ( cmd , verbose = F ) end program demo_run Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd logical, intent(in), optional :: echo integer, intent(out), optional :: exitstat logical, intent(in), optional :: verbose character(len=*), intent(in), optional :: redirect Contents Source Code run Source Code subroutine run ( cmd , echo , exitstat , verbose , redirect ) character ( len =* ), intent ( in ) :: cmd logical , intent ( in ), optional :: echo integer , intent ( out ), optional :: exitstat logical , intent ( in ), optional :: verbose character ( * ), intent ( in ), optional :: redirect integer :: cmdstat character ( len = 256 ) :: cmdmsg , iomsg logical :: echo_local , verbose_local character (:), allocatable :: redirect_str character (:), allocatable :: line integer :: stat , fh , iostat if ( present ( echo )) then echo_local = echo else echo_local = . true . end if if ( present ( verbose )) then verbose_local = verbose else verbose_local = . true . end if if ( present ( redirect )) then if ( redirect /= '' ) then redirect_str = \">\" // redirect // \" 2>&1\" endif else if ( verbose_local ) then ! No redirection but verbose output redirect_str = \"\" else ! No redirection and non-verbose output if ( os_is_unix ()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if end if if ( echo_local ) print * , '+ ' , cmd !//redirect_str call execute_command_line ( cmd // redirect_str , exitstat = stat , cmdstat = cmdstat , cmdmsg = cmdmsg ) if ( cmdstat /= 0 ) then write ( * , '(a)' ) ':failed command ' // cmd // redirect_str call fpm_stop ( 1 , '*run*:' // trim ( cmdmsg )) endif if ( verbose_local . and . present ( redirect )) then open ( newunit = fh , file = redirect , status = 'old' , iostat = iostat , iomsg = iomsg ) if ( iostat == 0 ) then do call getline ( fh , line , iostat ) if ( iostat /= 0 ) exit write ( * , '(A)' ) trim ( line ) end do else write ( * , '(A)' ) trim ( iomsg ) endif close ( fh ) end if if ( present ( exitstat )) then exitstat = stat elseif ( stat /= 0 ) then call fpm_stop ( stat , '*run*: Command ' // cmd // redirect_str // ' returned a non-zero status code' ) end if end subroutine run","tags":"","loc":"proc/run.html"},{"title":"warnwrite – Fortran-lang/fpm","text":"public subroutine warnwrite(fname, data) write trimmed character data to a file if it does not exist Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: fname character(len=*), intent(in) :: data (:) Contents Source Code warnwrite Source Code subroutine warnwrite ( fname , data ) character ( len =* ), intent ( in ) :: fname character ( len =* ), intent ( in ) :: data (:) if (. not . exists ( fname )) then call filewrite ( fname , data ) else write ( stderr , '(*(g0,1x))' ) ' ' , fname ,& & 'already exists. Not overwriting' endif end subroutine warnwrite","tags":"","loc":"proc/warnwrite.html"},{"title":"build_package – Fortran-lang/fpm","text":"public subroutine build_package(targets, model, verbose) Top-level routine to build package described by model Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout) :: targets (:) type( fpm_model_t ), intent(in) :: model logical, intent(in) :: verbose Contents Source Code build_package Source Code subroutine build_package ( targets , model , verbose ) type ( build_target_ptr ), intent ( inout ) :: targets (:) type ( fpm_model_t ), intent ( in ) :: model logical , intent ( in ) :: verbose integer :: i , j type ( build_target_ptr ), allocatable :: queue (:) integer , allocatable :: schedule_ptr (:), stat (:) logical :: build_failed , skip_current type ( string_t ), allocatable :: build_dirs (:) type ( string_t ) :: temp type ( build_progress_t ) :: progress logical :: plain_output ! Need to make output directory for include (mod) files allocate ( build_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % output_dir . in . build_dirs ) cycle temp % s = target % output_dir build_dirs = [ build_dirs , temp ] end associate end do do i = 1 , size ( build_dirs ) call mkdir ( build_dirs ( i )% s , verbose ) end do ! Perform depth-first topological sort of targets do i = 1 , size ( targets ) call sort_target ( targets ( i )% ptr ) end do ! Construct build schedule queue call schedule_targets ( queue , schedule_ptr , targets ) ! Check if queue is empty if (. not . verbose . and . size ( queue ) < 1 ) then write ( stderr , '(a)' ) 'Project is up to date' return end if ! Initialise build status flags allocate ( stat ( size ( queue ))) stat (:) = 0 build_failed = . false . ! Set output mode #ifndef FPM_BOOTSTRAP plain_output = (. not .( c_isatty () == 1 )) . or . verbose #else plain_output = . true . #endif progress = build_progress_t ( queue , plain_output ) ! Loop over parallel schedule regions do i = 1 , size ( schedule_ptr ) - 1 ! Build targets in schedule region i !$omp parallel do default(shared) private(skip_current) schedule(dynamic,1) do j = schedule_ptr ( i ),( schedule_ptr ( i + 1 ) - 1 ) ! Check if build already failed !$omp atomic read skip_current = build_failed if (. not . skip_current ) then call progress % compiling_status ( j ) call build_target ( model , queue ( j )% ptr , verbose , stat ( j )) call progress % completed_status ( j , stat ( j )) end if ! Set global flag if this target failed to build if ( stat ( j ) /= 0 ) then !$omp atomic write build_failed = . true . end if end do ! Check if this schedule region failed: exit with message if failed if ( build_failed ) then write ( * , * ) do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) Then call print_build_log ( queue ( j )% ptr ) end if end do do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Compilation failed for object \"' , basename ( queue ( j )% ptr % output_file ), '\"' end if end do call fpm_stop ( 1 , 'stopping due to failed compilation' ) end if end do call progress % success () end subroutine build_package","tags":"","loc":"proc/build_package.html"},{"title":"schedule_targets – Fortran-lang/fpm","text":"public subroutine schedule_targets(queue, schedule_ptr, targets) Construct a build schedule from the sorted targets. The schedule is broken into regions, described by schedule_ptr ,\n where targets in each region can be compiled in parallel. Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: queue (:) integer, allocatable :: schedule_ptr (:) type( build_target_ptr ), intent(in) :: targets (:) Contents Source Code schedule_targets Source Code subroutine schedule_targets ( queue , schedule_ptr , targets ) type ( build_target_ptr ), allocatable , intent ( out ) :: queue (:) integer , allocatable :: schedule_ptr (:) type ( build_target_ptr ), intent ( in ) :: targets (:) integer :: i , j integer :: n_schedule , n_sorted n_schedule = 0 ! Number of schedule regions n_sorted = 0 ! Total number of targets to build do i = 1 , size ( targets ) if ( targets ( i )% ptr % sorted ) then n_sorted = n_sorted + 1 end if n_schedule = max ( n_schedule , targets ( i )% ptr % schedule ) end do allocate ( queue ( n_sorted )) allocate ( schedule_ptr ( n_schedule + 1 )) ! Construct the target queue and schedule region pointer n_sorted = 1 schedule_ptr ( n_sorted ) = 1 do i = 1 , n_schedule do j = 1 , size ( targets ) if ( targets ( j )% ptr % sorted ) then if ( targets ( j )% ptr % schedule == i ) then queue ( n_sorted )% ptr => targets ( j )% ptr n_sorted = n_sorted + 1 end if end if end do schedule_ptr ( i + 1 ) = n_sorted end do end subroutine schedule_targets","tags":"","loc":"proc/schedule_targets.html"},{"title":"sort_target – Fortran-lang/fpm","text":"public recursive subroutine sort_target(target) Topologically sort a target for scheduling by\n recursing over its dependencies. Checks disk-cached source hashes to determine if objects are\n up-to-date. Up-to-date sources are tagged as skipped. On completion, target should either be marked as\nsorted ( target%sorted=.true. ) or skipped ( target%skip=.true. ) If target is marked as sorted, target%schedule should be an\ninteger greater than zero indicating the region for scheduling Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout), target :: target Contents Source Code sort_target Source Code recursive subroutine sort_target ( target ) type ( build_target_t ), intent ( inout ), target :: target integer :: i , fh , stat ! Check if target has already been processed (as a dependency) if ( target % sorted . or . target % skip ) then return end if ! Check for a circular dependency ! (If target has been touched but not processed) if ( target % touched ) then call fpm_stop ( 1 , '(!) Circular dependency found with: ' // target % output_file ) else target % touched = . true . ! Set touched flag end if ! Load cached source file digest if present if (. not . allocated ( target % digest_cached ) . and . & exists ( target % output_file ) . and . & exists ( target % output_file // '.digest' )) then allocate ( target % digest_cached ) open ( newunit = fh , file = target % output_file // '.digest' , status = 'old' ) read ( fh , * , iostat = stat ) target % digest_cached close ( fh ) if ( stat /= 0 ) then ! Cached digest is not recognized deallocate ( target % digest_cached ) end if end if if ( allocated ( target % source )) then ! Skip if target is source-based and source file is unmodified if ( allocated ( target % digest_cached )) then if ( target % digest_cached == target % source % digest ) target % skip = . true . end if elseif ( exists ( target % output_file )) then ! Skip if target is not source-based and already exists target % skip = . true . end if ! Loop over target dependencies target % schedule = 1 do i = 1 , size ( target % dependencies ) ! Sort dependency call sort_target ( target % dependencies ( i )% ptr ) if (. not . target % dependencies ( i )% ptr % skip ) then ! Can't skip target if any dependency is not skipped target % skip = . false . ! Set target schedule after all of its dependencies target % schedule = max ( target % schedule , target % dependencies ( i )% ptr % schedule + 1 ) end if end do ! Mark flag as processed: either sorted or skipped target % sorted = . not . target % skip end subroutine sort_target","tags":"","loc":"proc/sort_target.html"},{"title":"get_command_line_settings – Fortran-lang/fpm","text":"public subroutine get_command_line_settings(cmd_settings) ! canon_path is not converting “.”, etc.\n& ‘ unknown help topic “’//trim(unnamed(i)).’not found in:’,manual] Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(out), allocatable :: cmd_settings Contents Source Code get_command_line_settings Source Code subroutine get_command_line_settings ( cmd_settings ) class ( fpm_cmd_settings ), allocatable , intent ( out ) :: cmd_settings integer , parameter :: widest = 256 character ( len = 4096 ) :: cmdarg integer :: i integer :: os type ( fpm_install_settings ), allocatable :: install_settings type ( version_t ) :: version character ( len = :), allocatable :: common_args , compiler_args , run_args , working_dir , & & c_compiler , cxx_compiler , archiver , version_s , token_s character ( len =* ), parameter :: fc_env = \"FC\" , cc_env = \"CC\" , ar_env = \"AR\" , & & fflags_env = \"FFLAGS\" , cflags_env = \"CFLAGS\" , cxxflags_env = \"CXXFLAGS\" , ldflags_env = \"LDFLAGS\" , & & fc_default = \"gfortran\" , cc_default = \" \" , ar_default = \" \" , flags_default = \" \" , & & cxx_env = \"CXX\" , cxx_default = \" \" type ( error_t ), allocatable :: error call set_help () os = get_os_type () ! text for --version switch, select case ( os ) 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_OPENBSD ); os_type = \"OS Type: OpenBSD\" case ( OS_UNKNOWN ); os_type = \"OS Type: Unknown\" case default ; os_type = \"OS Type: UNKNOWN\" end select ! Get current release version version = fpm_version () version_s = version % s () version_text = [ character ( len = 80 ) :: & & 'Version: ' // trim ( version_s ) // ', 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 CLI_RESPONSE_FILE = . true . cmdarg = get_subcommand () common_args = & ' --directory:C \" \"' // & ' --verbose F' run_args = & ' --target \" \"' // & ' --list F' // & ' --runner \" \"' // & ' --runner-args \" \"' compiler_args = & ' --profile \" \"' // & ' --no-prune F' // & ' --compiler \"' // get_fpm_env ( fc_env , fc_default ) // '\"' // & ' --c-compiler \"' // get_fpm_env ( cc_env , cc_default ) // '\"' // & ' --cxx-compiler \"' // get_fpm_env ( cxx_env , cxx_default ) // '\"' // & ' --archiver \"' // get_fpm_env ( ar_env , ar_default ) // '\"' // & ' --flag:: \"' // get_fpm_env ( fflags_env , flags_default ) // '\"' // & ' --c-flag:: \"' // get_fpm_env ( cflags_env , flags_default ) // '\"' // & ' --cxx-flag:: \"' // get_fpm_env ( cxxflags_env , flags_default ) // '\"' // & ' --link-flag:: \"' // get_fpm_env ( ldflags_env , flags_default ) // '\"' ! now set subcommand-specific help text and process commandline ! arguments. Then call subcommand routine select case ( trim ( cmdarg )) case ( 'run' ) call set_args ( common_args // compiler_args // run_args // '& & --all F & & --example F& & --' , help_run , version_text ) call check_build_vals () if ( size ( unnamed ) > 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 ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_run_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_run_settings (& & args = remaining ,& & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = lget ( 'example' ), & & list = lget ( 'list' ),& & build_tests = . false .,& & name = names ,& & runner = val_runner ,& & runner_args = val_runner_args , & & verbose = lget ( 'verbose' ) ) case ( 'build' ) call set_args ( common_args // compiler_args // '& & --list F & & --show-model F & & --tests F & & --' , help_build , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_build_settings :: cmd_settings ) cmd_settings = fpm_build_settings ( & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ) ) case ( 'new' ) call set_args ( common_args // '& & --src F & & --lib F & & --app F & & --test F & & --example F & & --backfill F & & --full F & & --bare F' , & & help_new , version_text ) select case ( size ( unnamed )) case ( 1 ) if ( lget ( 'backfill' )) then name = '.' else write ( stderr , '(*(7x,g0,/))' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|[--full|--bare] [--backfill]' call fpm_stop ( 1 , 'directory name required' ) endif case ( 2 ) name = trim ( unnamed ( 2 )) case default write ( stderr , '(7x,g0)' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| [--full|--bare] [--backfill]' call fpm_stop ( 2 , 'only one directory name allowed' ) end select !*! canon_path is not converting \".\", etc. if ( name == '.' ) then call get_current_directory ( name , error ) if ( allocated ( error )) then write ( stderr , '(\"[Error]\", 1x, a)' ) error % message stop 1 endif endif name = canon_path ( name ) if ( . not . is_fortran_name ( to_fortran_name ( basename ( name ))) ) then write ( stderr , '(g0)' ) [ character ( len = 72 ) :: & & ' the fpm project name must be made of up to 63 ASCII letters,' , & & ' numbers, underscores, or hyphens, and start with a letter.' ] call fpm_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))' )& & ' --full and any of [--src|--lib,--app,--test,--example,--bare]' , & & ' are mutually exclusive.' call fpm_stop ( 5 , ' ' ) elseif ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' , 'full' ])) & & . and . lget ( 'bare' ) ) then write ( stderr , '(*(a))' )& & ' --bare and any of [--src|--lib,--app,--test,--example,--full]' , & & ' are mutually exclusive.' call fpm_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 ( common_args , help_help , version_text ) if ( size ( unnamed ) < 2 ) then if ( unnamed ( 1 ) == 'help' ) then unnamed = [ ' ' , 'fpm' ] else unnamed = manual endif elseif ( unnamed ( 2 ) == 'manual' ) then unnamed = manual endif 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 ( 'clean' ) help_text = [ character ( len = widest ) :: help_text , help_clean ] case ( 'publish' ) help_text = [ character ( len = widest ) :: help_text , help_publish ] case default help_text = [ character ( len = widest ) :: help_text , & & ' unknown help topic \"' // trim ( unnamed ( i )) // '\"' ] !!& ' unknown help topic \"'//trim(unnamed(i)).'not found in:',manual] end select enddo call printhelp ( help_text ) case ( 'install' ) call set_args ( common_args // compiler_args // '& & --no-rebuild F --prefix \" \" & & --list F & & --libdir \"lib\" --bindir \"bin\" --includedir \"include\"' , & help_install , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( install_settings , source = fpm_install_settings (& list = lget ( 'list' ), & profile = val_profile ,& prune = . not . lget ( 'no-prune' ), & compiler = val_compiler , & c_compiler = c_compiler , & cxx_compiler = cxx_compiler , & archiver = archiver , & flag = val_flag , & cflag = val_cflag , & cxxflag = val_cxxflag , & ldflag = val_ldflag , & 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 ( common_args // '& & --list F& &' , help_list , version_text ) if ( lget ( 'list' )) then help_text = [ character ( widest ) :: help_list_nodash , help_list_dash ] else help_text = help_list_nodash endif call printhelp ( help_text ) case ( 'test' ) call set_args ( common_args // compiler_args // run_args // ' --' , & help_test , version_text ) call check_build_vals () if ( size ( unnamed ) > 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 ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_test_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_test_settings (& & args = remaining , & & profile = val_profile , & & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = . false ., & & list = lget ( 'list' ), & & build_tests = . true ., & & name = names , & & runner = val_runner , & & runner_args = val_runner_args , & & verbose = lget ( 'verbose' )) case ( 'update' ) call set_args ( common_args // ' --fetch-only F --clean F' , & help_update , version_text ) if ( size ( unnamed ) > 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 ( 'clean' ) call set_args ( common_args // & & ' --skip' // & & ' --all' , & help_clean , version_text ) allocate ( fpm_clean_settings :: cmd_settings ) call get_current_directory ( working_dir , error ) cmd_settings = fpm_clean_settings ( & & clean_skip = lget ( 'skip' ), & & clean_call = lget ( 'all' )) case ( 'publish' ) call set_args ( common_args // compiler_args // '& & --show-package-version F & & --show-upload-data F & & --dry-run F & & --token \" \" & & --list F & & --show-model F & & --tests F & & --' , help_publish , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) token_s = sget ( 'token' ) allocate ( fpm_publish_settings :: cmd_settings ) cmd_settings = fpm_publish_settings ( & & show_package_version = lget ( 'show-package-version' ), & & show_upload_data = lget ( 'show-upload-data' ), & & is_dry_run = lget ( 'dry-run' ), & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ),& & token = token_s ) case default if ( cmdarg . ne . '' . and . which ( 'fpm-' // cmdarg ). ne . '' ) then call run ( 'fpm-' // trim ( cmdarg ) // ' ' // get_command_arguments_quoted (),. false .) stop else call set_args ( '& & --list F& &' , help_fpm , version_text ) ! Note: will not get here if --version or --usage or --help ! is present on commandline if ( lget ( 'list' )) then help_text = help_list_dash elseif ( len_trim ( cmdarg ) == 0 ) then write ( stdout , '(*(a))' ) 'Fortran Package Manager:' write ( stdout , '(*(a))' ) ' ' help_text = [ character ( widest ) :: help_list_nodash , help_usage ] else write ( stderr , '(*(a))' ) ' unknown subcommand [' , & & trim ( cmdarg ), ']' help_text = [ character ( widest ) :: help_list_dash , help_usage ] endif call printhelp ( help_text ) endif end select if ( allocated ( cmd_settings )) then working_dir = sget ( \"directory\" ) call move_alloc ( working_dir , cmd_settings % working_dir ) end if contains subroutine check_build_vals () val_compiler = sget ( 'compiler' ) if ( val_compiler == '' ) val_compiler = 'gfortran' val_flag = \" \" // sget ( 'flag' ) val_cflag = \" \" // sget ( 'c-flag' ) val_cxxflag = \" \" // sget ( 'cxx-flag' ) val_ldflag = \" \" // sget ( 'link-flag' ) val_profile = sget ( 'profile' ) end subroutine check_build_vals !> Print help text and stop subroutine printhelp ( lines ) character ( len = :), intent ( in ), allocatable :: lines (:) integer :: iii , ii if ( allocated ( lines )) then ii = size ( lines ) if ( ii > 0 . and . len ( lines ) > 0 ) then write ( stdout , '(g0)' )( trim ( lines ( iii )), iii = 1 , ii ) else write ( stdout , '(a)' ) ' *printhelp* output requested is empty' endif endif stop end subroutine printhelp end subroutine get_command_line_settings","tags":"","loc":"proc/get_command_line_settings.html"},{"title":"dilate – Fortran-lang/fpm","text":"public function dilate(instr) result(outstr) NAME dilate(3f) - [M_strings:NONALPHA] expand tab characters\n(LICENSE:PD) SYNOPSIS function dilate(INSTR) result ( OUTSTR ) character ( len = * ), intent =( in ) :: INSTR character ( len =:), allocatable :: OUTSTR DESCRIPTION dilate() converts tabs in INSTR to spaces in OUTSTR. It assumes a\n tab is set every 8 characters. Trailing spaces are removed.\n\n In addition, trailing carriage returns and line feeds are removed\n (they are usually a problem created by going to and from MSWindows). OPTIONS instr Input line to remove tabs from RESULTS outstr Output string with tabs expanded. EXAMPLES Sample program: program demo_dilate use M_strings , only : dilate implicit none character ( len = : ) , allocatable :: in integer :: i in = ' this is my string ' ! change spaces to tabs to make a sample input do i = 1 , len ( in ) if ( in ( i : i ) == ' ' ) in ( i : i ) = char ( 9 ) enddo write ( * , ' (a) ' ) in , dilate ( in ) end program demo_dilate Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr Return Value character(len=:), allocatable Contents Source Code dilate Source Code function dilate ( instr ) result ( outstr ) character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len = :), allocatable :: outstr ! tab-expanded version of INSTR produced integer :: i integer :: icount integer :: lgth icount = 0 do i = 1 , len ( instr ) if ( instr ( i : i ) == char ( 9 )) icount = icount + 1 end do allocate ( character ( len = ( len ( instr ) + 8 * icount )) :: outstr ) call notabs ( instr , outstr , lgth ) outstr = outstr (: lgth ) end function dilate","tags":"","loc":"proc/dilate.html"},{"title":"f_string – Fortran-lang/fpm","text":"public function f_string(c_string) Uses iso_c_binding return Fortran character variable when given a C-like array of\nsingle characters terminated with a C_NULL_CHAR character Arguments Type Intent Optional Attributes Name character(len=1), intent(in) :: c_string (:) Return Value character(len=:), allocatable Contents Source Code f_string Source Code function f_string ( c_string ) use iso_c_binding character ( len = 1 ), intent ( in ) :: c_string (:) character (:), allocatable :: f_string integer :: i , n i = 0 do while ( c_string ( i + 1 ) /= C_NULL_CHAR ) i = i + 1 end do n = i allocate ( character ( n ) :: f_string ) do i = 1 , n f_string ( i : i ) = c_string ( i ) end do end function f_string","tags":"","loc":"proc/f_string.html"},{"title":"glob – Fortran-lang/fpm","text":"public function glob(tame, wild) NAME glob ( 3 f ) - [ fpm_strings : COMPARE ] compare given string for match to pattern which may contain wildcard characters ( LICENSE : PD ) SYNOPSIS logical function glob(string, pattern )\n\n character(len=*),intent(in) :: string\n character(len=*),intent(in) :: pattern DESCRIPTION glob(3f) compares given STRING for match to PATTERN which may\n contain wildcard characters. In this version to get a match the entire string must be described\n by PATTERN. Trailing whitespace is significant, so trim the input\n string to have trailing whitespace ignored. OPTIONS string the input string to test to see if it contains the pattern . pattern the following simple globbing options are available o \" ? \" matching any one character o \" * \" matching zero or more characters . Do NOT use adjacent asterisks . o Both strings may have trailing spaces which are ignored . o There is no escape character , so matching strings with literal question mark and asterisk is problematic . EXAMPLES Example program program demo_glob implicit none ! This main () routine passes a bunch of test strings ! into the above code . In performance comparison mode , ! it does that over and over . Otherwise , it does it just ! once . Either way , it outputs a passed / failed result . ! integer :: nReps logical :: allpassed integer :: i allpassed = . true . nReps = 10000 ! Can choose as many repetitions as you ' re expecting ! in the real world . nReps = 1 do i = 1 , nReps ! Cases with repeating character sequences . allpassed = allpassed . and . test ( \" a*abab \" , \" a*b \" , . true . ) !! cycle allpassed = allpassed . and . test ( \" ab \" , \" *? \" , . true . ) allpassed = allpassed . and . test ( \" abc \" , \" *? \" , . true . ) allpassed = allpassed . and . test ( \" abcccd \" , \" *ccd \" , . true . ) allpassed = allpassed . and . test ( \" bLah \" , \" bLaH \" , . false . ) allpassed = allpassed . and . test ( \" mississippi \" , \" *sip* \" , . true . ) allpassed = allpassed . and . & & test ( \" xxxx*zzzzzzzzy*f \" , \" xxx*zzy*f \" , . true . ) allpassed = allpassed . and . & & test ( \" xxxx*zzzzzzzzy*f \" , \" xxxx*zzy*fffff \" , . false . ) allpassed = allpassed . and . & & test ( \" mississipissippi \" , \" *issip*ss* \" , . true . ) allpassed = allpassed . and . & & test ( \" xxxxzzzzzzzzyf \" , \" xxxx*zzy*fffff \" , . false . ) allpassed = allpassed . and . & & test ( \" xxxxzzzzzzzzyf \" , \" xxxx*zzy*f \" , . true . ) allpassed = allpassed . and . test ( \" xyxyxyzyxyz \" , \" xy*z*xyz \" , . true . ) allpassed = allpassed . and . test ( \" xyxyxyxyz \" , \" xy*xyz \" , . true . ) allpassed = allpassed . and . test ( \" mississippi \" , \" mi*sip* \" , . true . ) allpassed = allpassed . and . test ( \" ababac \" , \" *abac* \" , . true . ) allpassed = allpassed . and . test ( \" aaazz \" , \" a*zz* \" , . true . ) allpassed = allpassed . and . test ( \" a12b12 \" , \" *12*23 \" , . false . ) allpassed = allpassed . and . test ( \" a12b12 \" , \" a12b \" , . false . ) allpassed = allpassed . and . test ( \" a12b12 \" , \" *12*12* \" , . true . ) ! Additional cases where the ' * ' char appears in the tame string . allpassed = allpassed . and . test ( \" * \" , \" * \" , . true . ) allpassed = allpassed . and . test ( \" a*r \" , \" a* \" , . true . ) allpassed = allpassed . and . test ( \" a*ar \" , \" a*aar \" , . false . ) ! More double wildcard scenarios . allpassed = allpassed . and . test ( \" XYXYXYZYXYz \" , \" XY*Z*XYz \" , . true . ) allpassed = allpassed . and . test ( \" missisSIPpi \" , \" *SIP* \" , . true . ) allpassed = allpassed . and . test ( \" mississipPI \" , \" *issip*PI \" , . true . ) allpassed = allpassed . and . test ( \" xyxyxyxyz \" , \" xy*xyz \" , . true . ) allpassed = allpassed . and . test ( \" miSsissippi \" , \" mi*sip* \" , . true . ) allpassed = allpassed . and . test ( \" miSsissippi \" , \" mi*Sip* \" , . false . ) allpassed = allpassed . and . test ( \" abAbac \" , \" *Abac* \" , . true . ) allpassed = allpassed . and . test ( \" aAazz \" , \" a*zz* \" , . true . ) allpassed = allpassed . and . test ( \" A12b12 \" , \" *12*23 \" , . false . ) allpassed = allpassed . and . test ( \" a12B12 \" , \" *12*12* \" , . true . ) allpassed = allpassed . and . test ( \" oWn \" , \" *oWn* \" , . true . ) ! Completely tame ( no wildcards ) cases . allpassed = allpassed . and . test ( \" bLah \" , \" bLah \" , . true . ) ! Simple mixed wildcard tests suggested by IBMer Marlin Deckert . allpassed = allpassed . and . test ( \" a \" , \" *? \" , . true . ) ! More mixed wildcard tests including coverage for false positives . allpassed = allpassed . and . test ( \" a \" , \" ?? \" , . false . ) allpassed = allpassed . and . test ( \" ab \" , \" ?*? \" , . true . ) allpassed = allpassed . and . test ( \" ab \" , \" *?*?* \" , . true . ) allpassed = allpassed . and . test ( \" abc \" , \" ?**?*? \" , . true . ) allpassed = allpassed . and . test ( \" abc \" , \" ?**?*&? \" , . false . ) allpassed = allpassed . and . test ( \" abcd \" , \" ?b*?? \" , . true . ) allpassed = allpassed . and . test ( \" abcd \" , \" ?a*?? \" , . false . ) allpassed = allpassed . and . test ( \" abcd \" , \" ?**?c? \" , . true . ) allpassed = allpassed . and . test ( \" abcd \" , \" ?**?d? \" , . false . ) allpassed = allpassed . and . test ( \" abcde \" , \" ?*b*?*d*? \" , . true . ) ! Single - character - match cases . allpassed = allpassed . and . test ( \" bLah \" , \" bL?h \" , . true . ) allpassed = allpassed . and . test ( \" bLaaa \" , \" bLa? \" , . false . ) allpassed = allpassed . and . test ( \" bLah \" , \" bLa? \" , . true . ) allpassed = allpassed . and . test ( \" bLaH \" , \" ?Lah \" , . false . ) allpassed = allpassed . and . test ( \" bLaH \" , \" ?LaH \" , . true . ) ! Many - wildcard scenarios . allpassed = allpassed . and . test ( & & \" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa& & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab \" ,& & \" a*a*a*a*a*a*aa*aaa*a*a*b \" , & & . true . ) allpassed = allpassed . and . test ( & & \" abababababababababababababababababababaacacacacacacac& & adaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab \" ,& & \" *a*b*ba*ca*a*aa*aaa*fa*ga*b* \" , & & . true . ) allpassed = allpassed . and . test ( & & \" abababababababababababababababababababaacacacacacaca& & cadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab \" ,& & \" *a*b*ba*ca*a*x*aaa*fa*ga*b* \" , & & . false . ) allpassed = allpassed . and . test ( & & \" abababababababababababababababababababaacacacacacacacad& & aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab \" ,& & \" *a*b*ba*ca*aaaa*fa*ga*gggg*b* \" , & & . false . ) allpassed = allpassed . and . test ( & & \" abababababababababababababababababababaacacacacacacacad& & aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab \" ,& & \" *a*b*ba*ca*aaaa*fa*ga*ggg*b* \" , & & . true . ) allpassed = allpassed . and . test ( \" aaabbaabbaab \" , \" *aabbaa*a* \" , . true . ) allpassed = allpassed . and . & test ( \" a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a* \" , & & \" a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a* \" , . true . ) allpassed = allpassed . and . test ( \" aaaaaaaaaaaaaaaaa \" , & & \" *a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a* \" , . true . ) allpassed = allpassed . and . test ( \" aaaaaaaaaaaaaaaa \" , & & \" *a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a* \" , . false . ) allpassed = allpassed . and . test ( & & \" abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& &* abcdefghijk * abcdefghijkl * abcdefghijklm * abcdefghijklmn \" ,& & \" abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc& &* abc * abc * abc * \" ,& & . false . ) allpassed = allpassed . and . test ( & & \" abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& &* abcdefghijk * abcdefghijkl * abcdefghijklm * abcdefghijklmn \" ,& & \" abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc* \" , & & . true . ) allpassed = allpassed . and . test ( \" abc*abcd*abcd*abc*abcd \" , & & \" abc*abc*abc*abc*abc \" , . false . ) allpassed = allpassed . and . test ( \" abc*abcd*abcd*abc*abcd*abcd& &* abc * abcd * abc * abc * abcd \" , & & \" abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd \" , & & . true . ) allpassed = allpassed . and . test ( \" abc \" , & & \" ********a********b********c******** \" , . true . ) allpassed = allpassed . and . & & test ( \" ********a********b********c******** \" , \" abc \" , . false . ) allpassed = allpassed . and . & & test ( \" abc \" , \" ********a********b********b******** \" , . false . ) allpassed = allpassed . and . test ( \" *abc* \" , \" ***a*b*c*** \" , . true . ) ! A case - insensitive algorithm test . ! allpassed = allpassed . and . test ( \" mississippi \" , \" *issip*PI \" , . true . ) enddo if ( allpassed ) then write ( * , ' (a) ' ) \" Passed \" , nReps else write ( * , ' (a) ' ) \" Failed \" endif contains ! This is a test program for wildcard matching routines . ! It can be used either to test a single routine for correctness , ! or to compare the timings of two ( or more ) different wildcard ! matching routines . ! function test ( tame , wild , bExpectedResult ) result ( bpassed ) use fpm_strings , only : glob character ( len =* ) :: tame character ( len =* ) :: wild logical :: bExpectedResult logical :: bResult logical :: bPassed bResult = . true . ! We ' ll do \"&=\" cumulative checking. bPassed = . false . ! Assume the worst . write ( * , * ) repeat ( ' = ' , 79 ) bResult = glob ( tame , wild ) ! Call a wildcard matching routine . ! To assist correctness checking , output the two strings in any ! failing scenarios . if ( bExpectedResult . eqv . bResult ) then bPassed = . true . if ( nReps == 1 ) write ( * , * ) \" Passed match on \" , tame , \" vs. \" , wild else if ( nReps == 1 ) write ( * , * ) \" Failed match on \" , tame , \" vs. \" , wild endif end function test end program demo_glob Expected output REFERENCE The article “Matching Wildcards: An Empirical Way to Tame an Algorithm”\n in Dr Dobb’s Journal, By Kirk J. Krauss, October 07, 2014 Arguments Type Intent Optional Attributes Name character(len=*) :: tame A string without wildcards to compare to the globbing expression character(len=*) :: wild A (potentially) corresponding string with wildcards Return Value logical result of test Contents Source Code glob Source Code function glob ( tame , wild ) ! @(#)fpm_strings::glob(3f): function compares text strings, one of which can have wildcards ('*' or '?'). logical :: glob !! result of test character ( len =* ) :: tame !! A string without wildcards to compare to the globbing expression character ( len =* ) :: wild !! A (potentially) corresponding string with wildcards character ( len = len ( tame ) + 1 ) :: tametext character ( len = len ( wild ) + 1 ) :: wildtext character ( len = 1 ), parameter :: NULL = char ( 0 ) integer :: wlen integer :: ti , wi integer :: i character ( len = :), allocatable :: tbookmark , wbookmark ! These two values are set when we observe a wildcard character. They ! represent the locations, in the two strings, from which we start once we've observed it. tametext = tame // NULL wildtext = wild // NULL tbookmark = NULL wbookmark = NULL wlen = len ( wild ) wi = 1 ti = 1 do ! Walk the text strings one character at a time. if ( wildtext ( wi : wi ) == '*' ) then ! How do you match a unique text string? do i = wi , wlen ! Easy: unique up on it! if ( wildtext ( wi : wi ) == '*' ) then wi = wi + 1 else exit endif enddo if ( wildtext ( wi : wi ) == NULL ) then ! \"x\" matches \"*\" glob = . true . return endif if ( wildtext ( wi : wi ) /= '?' ) then ! Fast-forward to next possible match. do while ( tametext ( ti : ti ) /= wildtext ( wi : wi )) ti = ti + 1 if ( tametext ( ti : ti ) == NULL ) then glob = . false . return ! \"x\" doesn't match \"*y*\" endif enddo endif wbookmark = wildtext ( wi :) tbookmark = tametext ( ti :) elseif ( tametext ( ti : ti ) /= wildtext ( wi : wi ) . and . wildtext ( wi : wi ) /= '?' ) then ! Got a non-match. If we've set our bookmarks, back up to one or both of them and retry. if ( wbookmark /= NULL ) then if ( wildtext ( wi :) /= wbookmark ) then wildtext = wbookmark ; wlen = len_trim ( wbookmark ) wi = 1 ! Don't go this far back again. if ( tametext ( ti : ti ) /= wildtext ( wi : wi )) then tbookmark = tbookmark ( 2 :) tametext = tbookmark ti = 1 cycle ! \"xy\" matches \"*y\" else wi = wi + 1 endif endif if ( tametext ( ti : ti ) /= NULL ) then ti = ti + 1 cycle ! \"mississippi\" matches \"*sip*\" endif endif glob = . false . return ! \"xy\" doesn't match \"x\" endif ti = ti + 1 wi = wi + 1 if ( tametext ( ti : ti ) == NULL ) then ! How do you match a tame text string? if ( wildtext ( wi : wi ) /= NULL ) then do while ( wildtext ( wi : wi ) == '*' ) ! The tame way: unique up on it! wi = wi + 1 ! \"x\" matches \"x*\" if ( wildtext ( wi : wi ) == NULL ) exit enddo endif if ( wildtext ( wi : wi ) == NULL ) then glob = . true . return ! \"x\" matches \"x\" endif glob = . false . return ! \"x\" doesn't match \"xy\" endif enddo end function glob","tags":"","loc":"proc/glob.html"},{"title":"has_valid_custom_prefix – Fortran-lang/fpm","text":"public function has_valid_custom_prefix(module_name, custom_prefix) result(valid) Check that a module name is prefixed with a custom prefix:\n1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed)\n2) It must begin with the prefix\n3) If longer, package name must be followed by default separator (“_”) plus at least one char Basic check: check that both names are individually valid FPM package enforcing: check that the module name begins with the custom prefix Query string lengths\n2) It must begin with the package name.\n3) It can be equal to the package name, or, if longer, must be followed by the\n4) Package name must not end with an underscore Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: custom_prefix Return Value logical Contents Source Code has_valid_custom_prefix Source Code logical function has_valid_custom_prefix ( module_name , custom_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: custom_prefix !> custom_module separator: single underscore character ( * ), parameter :: SEP = \"_\" logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check that both names are individually valid valid = is_fortran_name ( module_name % s ) . and . & is_valid_module_prefix ( custom_prefix ) !> FPM package enforcing: check that the module name begins with the custom prefix if ( valid ) then !> Query string lengths lpkg = len_trim ( custom_prefix ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , custom_prefix % s , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator )) end if end function has_valid_custom_prefix","tags":"","loc":"proc/has_valid_custom_prefix.html"},{"title":"has_valid_standard_prefix – Fortran-lang/fpm","text":"public function has_valid_standard_prefix(module_name, package_name) result(valid) Check that a module name is prefixed with the default package prefix:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Basic check: check the name is Fortran-compliant FPM package enforcing: check that the module name begins with the package name Query string lengths\n2) It must begin with the package name.\n3) It can be equal to the package name, or, if longer, must be followed by the\n4) Package name must not end with an underscore Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name Return Value logical Contents Source Code has_valid_standard_prefix Source Code logical function has_valid_standard_prefix ( module_name , package_name ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name !> Default package__module separator: two underscores character ( * ), parameter :: SEP = \"__\" character ( len = :), allocatable :: fortranized_pkg logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ) !> FPM package enforcing: check that the module name begins with the package name if ( valid ) then fortranized_pkg = to_fortran_name ( package_name % s ) !> Query string lengths lpkg = len_trim ( fortranized_pkg ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , fortranized_pkg , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = is_fortran_name ( fortranized_pkg ) . and . & fortranized_pkg ( lpkg : lpkg ) /= '_' . and . & ( same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator ))) end if end function has_valid_standard_prefix","tags":"","loc":"proc/has_valid_standard_prefix.html"},{"title":"is_fortran_name – Fortran-lang/fpm","text":"public elemental function is_fortran_name(line) result(lout) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: line Return Value logical Contents Source Code is_fortran_name Source Code elemental 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 ) /= 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","tags":"","loc":"proc/is_fortran_name.html"},{"title":"is_valid_module_name – Fortran-lang/fpm","text":"public function is_valid_module_name(module_name, package_name, custom_prefix, enforce_module_names) result(valid) Check that a module name fits the current naming rules:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Basic check: check the name is Fortran-compliant FPM package enforcing: check that the module name begins with the package name Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name type( string_t ), intent(in) :: custom_prefix logical, intent(in) :: enforce_module_names Return Value logical Contents Source Code is_valid_module_name Source Code logical function is_valid_module_name ( module_name , package_name , custom_prefix , enforce_module_names ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name type ( string_t ), intent ( in ) :: custom_prefix logical , intent ( in ) :: enforce_module_names !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ); if (. not . valid ) return !> FPM package enforcing: check that the module name begins with the package name if ( enforce_module_names ) then ! Default prefixing is always valid valid = has_valid_standard_prefix ( module_name , package_name ) ! If a custom prefix was validated, it provides additional naming options ! Because they never overlap with the default prefix, the former is always an option if ( len_trim ( custom_prefix ) > 0 . and . . not . valid ) & valid = has_valid_custom_prefix ( module_name , custom_prefix ) end if end function is_valid_module_name","tags":"","loc":"proc/is_valid_module_name.html"},{"title":"is_valid_module_prefix – Fortran-lang/fpm","text":"public function is_valid_module_prefix(module_prefix) result(valid) Check that a custom module prefix fits the current naming rules:\n1) Only alphanumeric characters (no spaces, dashes, underscores or other characters)\n2) Does not begin with a number (Fortran-compatible syntax) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_prefix Return Value logical Contents Source Code is_valid_module_prefix Source Code logical function is_valid_module_prefix ( module_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_prefix character ( len =* ), parameter :: num = '0123456789' character ( len =* ), parameter :: lower = 'abcdefghijklmnopqrstuvwxyz' character ( len =* ), parameter :: upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' character ( len =* ), parameter :: alpha = upper // lower character ( len =* ), parameter :: allowed = alpha // num character ( len = :), allocatable :: name name = trim ( module_prefix % s ) if ( len ( name ) > 0 . and . len ( name ) <= 63 ) then valid = verify ( name ( 1 : 1 ), alpha ) == 0 . and . & verify ( name , allowed ) == 0 else valid = . false . endif end function is_valid_module_prefix","tags":"","loc":"proc/is_valid_module_prefix.html"},{"title":"join – Fortran-lang/fpm","text":"public pure function join(str, sep, trm, left, right, start, end) result(string) NAME join ( 3 f ) - [ M_strings : EDITING ] append CHARACTER variable array into a single CHARACTER variable with specified separator ( LICENSE : PD ) SYNOPSIS pure function join ( str , sep , trm , left , right , start , end ) result ( string ) character ( len =* ) , intent ( in ) :: str ( : ) character ( len =* ) , intent ( in ) , optional :: sep logical , intent ( in ) , optional :: trm character ( len =* ) , intent ( in ) , optional :: right character ( len =* ) , intent ( in ) , optional :: left character ( len =* ) , intent ( in ) , optional :: start character ( len =* ) , intent ( in ) , optional :: end character ( len = : ) , allocatable :: string DESCRIPTION JOIN(3f) appends the elements of a CHARACTER array into a single\n CHARACTER variable, with elements 1 to N joined from left to right.\n By default each element is trimmed of trailing spaces and the\n default separator is a null string. OPTIONS STR (:) array of CHARACTER variables to be joined SEP separator string to place between each variable . defaults to a null string . LEFT string to place at left of each element RIGHT string to place at right of each element START prefix string END suffix string TRM option to trim each element of STR of trailing spaces . Defaults to . TRUE . RESULT STRING CHARACTER variable composed of all of the elements of STR () appended together with the optional separator SEP placed between the elements . EXAMPLE Sample program: program demo_join\n use M_strings, only: join\n implicit none\n character(len=:),allocatable :: s(:)\n character(len=:),allocatable :: out\n integer :: i\n s=[character(len=10) :: ‘United’,’ we’,’ stand,’, &\n & ‘ divided’,’ we fall.’]\n out=join(s)\n write( ,’(a)’) out\n write( ,’(a)’) join(s,trm=.false.)\n write( ,’(a)’) (join(s,trm=.false.,sep=’|’),i=1,3)\n write( ,’(a)’) join(s,sep=’<>’)\n write( ,’(a)’) join(s,sep=’;’,left=’[‘,right=’]’)\n write( ,’(a)’) join(s,left=’[‘,right=’]’)\n write(*,’(a)’) join(s,left=’>>’)\n end program demo_join Expected output: United we stand, divided we fall.\n United we stand, divided we fall.\n United | we | stand, | divided | we fall.\n United | we | stand, | divided | we fall.\n United | we | stand, | divided | we fall.\n United<> we<> stand,<> divided<> we fall.\n [United];[ we];[ stand,];[ divided];[ we fall.]\n [United][ we][ stand,][ divided][ we fall.] United>> we>> stand,>> divided>> we fall. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str (:) character(len=*), intent(in), optional :: sep logical, intent(in), optional :: trm character(len=*), intent(in), optional :: left character(len=*), intent(in), optional :: right character(len=*), intent(in), optional :: start character(len=*), intent(in), optional :: end Return Value character(len=:), allocatable Contents Source Code join Source Code pure function join ( str , sep , trm , left , right , start , end ) result ( string ) ! @(#)M_strings::join(3f): merge string array into a single CHARACTER value adding specified separators, caps, prefix and suffix character ( len =* ), intent ( in ) :: str (:) character ( len =* ), intent ( in ), optional :: sep , right , left , start , end logical , intent ( in ), optional :: trm character ( len = :), allocatable :: sep_local , left_local , right_local character ( len = :), allocatable :: string logical :: trm_local integer :: i if ( present ( sep )) then ; sep_local = sep ; else ; sep_local = '' ; endif if ( present ( trm )) then ; trm_local = trm ; else ; trm_local = . true . ; endif if ( present ( left )) then ; left_local = left ; else ; left_local = '' ; endif if ( present ( right )) then ; right_local = right ; else ; right_local = '' ; endif string = '' if ( size ( str ) == 0 ) then string = string // left_local // right_local else do i = 1 , size ( str ) - 1 if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local // sep_local else string = string // left_local // str ( i ) // right_local // sep_local endif enddo if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local else string = string // left_local // str ( i ) // right_local endif endif if ( present ( start )) string = start // string if ( present ( end )) string = string // end end function join","tags":"","loc":"proc/join.html"},{"title":"lower – Fortran-lang/fpm","text":"public pure elemental function lower(str, begin, end) result(string) Changes a string to lowercase over optional specified column range Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str integer, intent(in), optional :: begin integer, intent(in), optional :: end Return Value character(len=len(str)) Contents Source Code lower Source Code elemental pure function lower ( str , begin , end ) result ( string ) character ( * ), intent ( In ) :: str character ( len ( str )) :: string integer , intent ( in ), optional :: begin , end integer :: i integer :: ibegin , iend string = str ibegin = 1 if ( present ( begin )) then ibegin = max ( ibegin , begin ) endif iend = len_trim ( str ) if ( present ( end )) then iend = min ( iend , end ) endif do i = ibegin , iend ! step thru each letter in the string in specified range select case ( str ( i : i )) case ( 'A' : 'Z' ) string ( i : i ) = char ( iachar ( str ( i : i )) + 32 ) ! change letter to miniscule case default end select end do end function lower","tags":"","loc":"proc/lower.html"},{"title":"module_prefix_template – Fortran-lang/fpm","text":"public function module_prefix_template(project_name, custom_prefix) result(prefix) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) Contents Source Code module_prefix_template Source Code type ( string_t ) function module_prefix_template ( project_name , custom_prefix ) result ( prefix ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then prefix = string_t ( trim ( custom_prefix % s ) // \"_\" ) else prefix = string_t ( to_fortran_name ( project_name % s ) // \"__\" ) end if end function module_prefix_template","tags":"","loc":"proc/module_prefix_template.html"},{"title":"module_prefix_type – Fortran-lang/fpm","text":"public function module_prefix_type(project_name, custom_prefix) result(ptype) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) Contents Source Code module_prefix_type Source Code type ( string_t ) function module_prefix_type ( project_name , custom_prefix ) result ( ptype ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then ptype = string_t ( \"custom\" ) else ptype = string_t ( \"default\" ) end if end function module_prefix_type","tags":"","loc":"proc/module_prefix_type.html"},{"title":"replace – Fortran-lang/fpm","text":"public pure function replace(string, charset, target_char) result(res) Returns string with characters in charset replaced with target_char. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string character(len=1), intent(in) :: charset (:) character(len=1), intent(in) :: target_char Return Value character(len=len(string)) Contents Source Code replace Source Code pure function replace ( string , charset , target_char ) result ( res ) character ( * ), intent ( in ) :: string character , intent ( in ) :: charset (:), target_char character ( len ( string )) :: res integer :: n res = string do n = 1 , len ( string ) if ( any ( string ( n : n ) == charset )) then res ( n : n ) = target_char end if end do end function replace","tags":"","loc":"proc/replace.html"},{"title":"str_begins_with_str – Fortran-lang/fpm","text":"public pure function str_begins_with_str(s, e, case_sensitive) result(r) test if a CHARACTER string begins with a specified prefix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e logical, intent(in), optional :: case_sensitive Return Value logical Contents Source Code str_begins_with_str Source Code pure logical function str_begins_with_str ( s , e , case_sensitive ) result ( r ) character ( * ), intent ( in ) :: s , e logical , optional , intent ( in ) :: case_sensitive ! Default option: case sensitive integer :: n1 , n2 logical :: lower_case ! Check if case sensitive if ( present ( case_sensitive )) then lower_case = . not . case_sensitive else lower_case = . false . end if n1 = 1 n2 = 1 + len ( e ) - 1 if ( n2 > len ( s )) then r = . false . elseif ( lower_case ) then r = lower ( s ( n1 : n2 )) == lower ( e ) else r = ( s ( n1 : n2 ) == e ) end if end function str_begins_with_str","tags":"","loc":"proc/str_begins_with_str.html"},{"title":"string_array_contains – Fortran-lang/fpm","text":"public function string_array_contains(search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical Contents Source Code string_array_contains Source Code logical function string_array_contains ( search_string , array ) character ( * ), intent ( in ) :: search_string type ( string_t ), intent ( in ) :: array (:) integer :: i string_array_contains = any ([( array ( i )% s == search_string , & i = 1 , size ( array ))]) end function string_array_contains","tags":"","loc":"proc/string_array_contains.html"},{"title":"string_cat – Fortran-lang/fpm","text":"public function string_cat(strings, delim) result(cat) Concatenate an array of type(string_t) into\n a single CHARACTER variable Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) character(len=*), intent(in), optional :: delim Return Value character(len=:), allocatable Contents Source Code string_cat Source Code function string_cat ( strings , delim ) result ( cat ) type ( string_t ), intent ( in ) :: strings (:) character ( * ), intent ( in ), optional :: delim character (:), allocatable :: cat integer :: i character (:), allocatable :: delim_str if ( size ( strings ) < 1 ) then cat = '' return end if if ( present ( delim )) then delim_str = delim else delim_str = '' end if cat = strings ( 1 )% s do i = 2 , size ( strings ) cat = cat // delim_str // strings ( i )% s end do end function string_cat","tags":"","loc":"proc/string_cat.html"},{"title":"to_fortran_name – Fortran-lang/fpm","text":"public pure function to_fortran_name(string) result(res) Returns string with special characters replaced with an underscore.\nFor now, only a hyphen is treated as a special character, but this can be\nexpanded to other characters if needed. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string Return Value character(len=len(string)) Contents Source Code to_fortran_name Source Code pure function to_fortran_name ( string ) result ( res ) character ( * ), intent ( in ) :: string character ( len ( string )) :: res character , parameter :: SPECIAL_CHARACTERS ( * ) = [ '-' ] res = replace ( string , SPECIAL_CHARACTERS , '_' ) end function to_fortran_name","tags":"","loc":"proc/to_fortran_name.html"},{"title":"notabs – Fortran-lang/fpm","text":"public impure elemental subroutine notabs(instr, outstr, ilen) NAME notabs(3f) - [fpm_strings:NONALPHA] expand tab characters\n (LICENSE:PD) SYNOPSIS subroutine notabs(INSTR,OUTSTR,ILEN)\n\n character(len=*),intent=(in) :: INSTR\n character(len=*),intent=(out) :: OUTSTR\n integer,intent=(out) :: ILEN DESCRIPTION NOTABS() converts tabs in INSTR to spaces in OUTSTR while maintaining\n columns. It assumes a tab is set every 8 characters. Trailing spaces\n are removed. In addition, trailing carriage returns and line feeds are removed\n (they are usually a problem created by going to and from MSWindows). What are some reasons for removing tab characters from an input line?\n Some Fortran compilers have problems with tabs, as tabs are not\n part of the Fortran character set. Some editors and printers will\n have problems with tabs. It is often useful to expand tabs in input\n files to simplify further processing such as tokenizing an input line. OPTIONS instr Input line to remove tabs from RESULTS outstr Output string with tabs expanded. Assumed to be of sufficient\n length\n ilen Significant length of returned string EXAMPLES Sample program: program demo_notabs ! test filter to remove tabs and trailing white space from input ! on files up to 1024 characters wide use fpm_strings , only : notabs character ( len = 1024 ) :: in , out integer :: ios , iout do read ( * , ' (A) ' , iostat = ios ) in if ( ios /= 0 ) exit call notabs ( in , out , iout ) write ( * , ' (a) ' ) out ( : iout ) enddo end program demo_notabs SEE ALSO GNU/Unix commands expand(1) and unexpand(1) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr character(len=*), intent(out) :: outstr integer, intent(out) :: ilen Contents Source Code notabs Source Code elemental impure subroutine notabs ( instr , outstr , ilen ) ! ident_31=\"@(#)fpm_strings::notabs(3f): convert tabs to spaces while maintaining columns, remove CRLF chars\" character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len =* ), intent ( out ) :: outstr ! tab-expanded version of INSTR produced integer , intent ( out ) :: ilen ! column position of last character put into output string ! that is, ILEN holds the position of the last non-blank character in OUTSTR integer , parameter :: tabsize = 8 ! assume a tab stop is set every 8th column integer :: ipos ! position in OUTSTR to put next character of INSTR integer :: lenin ! length of input string trimmed of trailing spaces integer :: lenout ! number of characters output string can hold integer :: istep ! counter that advances thru input string INSTR one character at a time character ( len = 1 ) :: c ! character in input line being processed integer :: iade ! ADE (ASCII Decimal Equivalent) of character being tested ipos = 1 ! where to put next character in output string OUTSTR lenin = len_trim ( instr ( 1 : len ( instr ) )) ! length of INSTR trimmed of trailing spaces lenout = len ( outstr ) ! number of characters output string OUTSTR can hold outstr = \" \" ! this SHOULD blank-fill string, a buggy machine required a loop to set all characters SCAN_LINE : do istep = 1 , lenin ! look through input string one character at a time c = instr ( istep : istep ) ! get next character iade = ichar ( c ) ! get ADE of the character EXPAND_TABS : select case ( iade ) ! take different actions depending on which character was found case ( 9 ) ! test if character is a tab and move pointer out to appropriate column ipos = ipos + ( tabsize - ( mod ( ipos - 1 , tabsize ))) case ( 10 , 13 ) ! convert carriage-return and new-line to space ,typically to handle DOS-format files ipos = ipos + 1 case default ! c is anything else other than a tab,newline,or return insert it in output string if ( ipos > lenout ) then write ( stderr , * ) \"*notabs* output string overflow\" exit else outstr ( ipos : ipos ) = c ipos = ipos + 1 endif end select EXPAND_TABS enddo SCAN_LINE ipos = min ( ipos , lenout ) ! tabs or newline or return characters or last character might have gone too far ilen = len_trim ( outstr (: ipos )) ! trim trailing spaces end subroutine notabs","tags":"","loc":"proc/notabs.html"},{"title":"remove_characters_in_set – Fortran-lang/fpm","text":"public subroutine remove_characters_in_set(string, set, replace_with) Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: string character(len=*), intent(in) :: set character(len=1), intent(in), optional :: replace_with Contents Source Code remove_characters_in_set Source Code subroutine remove_characters_in_set ( string , set , replace_with ) character ( len = :), allocatable , intent ( inout ) :: string character ( * ), intent ( in ) :: set character , optional , intent ( in ) :: replace_with ! Replace with this character instead of removing integer :: feed , length if (. not . allocated ( string )) return if ( len ( set ) <= 0 ) return length = len ( string ) feed = scan ( string , set ) do while ( length > 0 . and . feed > 0 ) ! Remove heading if ( length == 1 ) then string = \"\" elseif ( feed == 1 ) then string = string ( 2 : length ) ! Remove trailing elseif ( feed == length ) then string = string ( 1 : length - 1 ) ! In between: replace with given character elseif ( present ( replace_with )) then string ( feed : feed ) = replace_with ! Or just remove else string = string ( 1 : feed - 1 ) // string ( feed + 1 : length ) end if length = len ( string ) feed = scan ( string , set ) end do end subroutine remove_characters_in_set","tags":"","loc":"proc/remove_characters_in_set.html"},{"title":"remove_newline_characters – Fortran-lang/fpm","text":"public subroutine remove_newline_characters(string) Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout) :: string Contents Source Code remove_newline_characters Source Code subroutine remove_newline_characters ( string ) type ( string_t ), intent ( inout ) :: string integer :: feed , length character ( * ), parameter :: CRLF = new_line ( 'a' ) // achar ( 13 ) character ( * ), parameter :: SPACE = ' ' call remove_characters_in_set ( string % s , set = CRLF , replace_with = SPACE ) end subroutine remove_newline_characters","tags":"","loc":"proc/remove_newline_characters.html"},{"title":"split – Fortran-lang/fpm","text":"public subroutine split(input_line, array, delimiters, order, nulls) parse string on delimiter characters and store tokens into an allocatable array\n given a line of structure ” par1 par2 par3 … parn ” store each par(n) into a separate variable in array. by default adjacent delimiters in the input string do not create an empty string in the output array no quoting of delimiters is supported Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input_line input string to tokenize character(len=:), intent(out), allocatable :: array (:) output array of tokens character(len=*), intent(in), optional :: delimiters list of delimiter characters character(len=*), intent(in), optional :: order order of output array sequential|[reverse|right] character(len=*), intent(in), optional :: nulls return strings composed of delimiters or not ignore|return|ignoreend Contents Source Code split Source Code subroutine split ( input_line , array , delimiters , order , nulls ) !! given a line of structure \" par1 par2 par3 ... parn \" store each par(n) into a separate variable in array. !! !! * by default adjacent delimiters in the input string do not create an empty string in the output array !! * no quoting of delimiters is supported character ( len =* ), intent ( in ) :: input_line !! input string to tokenize character ( len =* ), optional , intent ( in ) :: delimiters !! list of delimiter characters character ( len =* ), optional , intent ( in ) :: order !! order of output array sequential|[reverse|right] character ( len =* ), optional , intent ( in ) :: nulls !! return strings composed of delimiters or not ignore|return|ignoreend character ( len = :), allocatable , intent ( out ) :: array (:) !! output array of tokens integer :: n ! max number of strings INPUT_LINE could split into if all delimiter integer , allocatable :: ibegin (:) ! positions in input string where tokens start integer , allocatable :: iterm (:) ! positions in input string where tokens end character ( len = :), allocatable :: dlim ! string containing delimiter characters character ( len = :), allocatable :: ordr ! string containing order keyword character ( len = :), allocatable :: nlls ! string containing nulls keyword integer :: ii , iiii ! loop parameters used to control print order integer :: icount ! number of tokens found integer :: ilen ! length of input string with trailing spaces trimmed integer :: i10 , i20 , i30 ! loop counters integer :: icol ! pointer into input string as it is being parsed integer :: idlim ! number of delimiter characters integer :: ifound ! where next delimiter character is found in remaining input string data integer :: inotnull ! count strings not composed of delimiters integer :: ireturn ! number of tokens returned integer :: imax ! length of longest token ! decide on value for optional DELIMITERS parameter if ( present ( delimiters )) then ! optional delimiter list was present if ( delimiters /= '' ) then ! if DELIMITERS was specified and not null use it dlim = delimiters else ! DELIMITERS was specified on call as empty string dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif else ! no delimiter value was specified dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif idlim = len ( dlim ) ! dlim a lot of blanks on some machines if dlim is a big string if ( present ( order )) then ; ordr = lower ( adjustl ( order )); else ; ordr = 'sequential' ; endif ! decide on value for optional ORDER parameter if ( present ( nulls )) then ; nlls = lower ( adjustl ( nulls )); else ; nlls = 'ignore' ; endif ! optional parameter n = len ( input_line ) + 1 ! max number of strings INPUT_LINE could split into if all delimiter allocate ( ibegin ( n )) ! allocate enough space to hold starting location of tokens if string all tokens allocate ( iterm ( n )) ! allocate enough space to hold ending location of tokens if string all tokens ibegin (:) = 1 iterm (:) = 1 ilen = len ( input_line ) ! ILEN is the column position of the last non-blank character icount = 0 ! how many tokens found inotnull = 0 ! how many tokens found not composed of delimiters imax = 0 ! length of longest token found select case ( ilen ) case ( 0 ) ! command was totally blank case default ! there is at least one non-delimiter in INPUT_LINE if get here icol = 1 ! initialize pointer into input line INFINITE : do i30 = 1 , ilen , 1 ! store into each array element ibegin ( i30 ) = icol ! assume start new token on the character if ( index ( dlim ( 1 : idlim ), input_line ( icol : icol )) == 0 ) then ! if current character is not a delimiter iterm ( i30 ) = ilen ! initially assume no more tokens do i10 = 1 , idlim ! search for next delimiter ifound = index ( input_line ( ibegin ( i30 ): ilen ), dlim ( i10 : i10 )) IF ( ifound > 0 ) then iterm ( i30 ) = min ( iterm ( i30 ), ifound + ibegin ( i30 ) - 2 ) endif enddo icol = iterm ( i30 ) + 2 ! next place to look as found end of this token inotnull = inotnull + 1 ! increment count of number of tokens not composed of delimiters else ! character is a delimiter for a null string iterm ( i30 ) = icol - 1 ! record assumed end of string. Will be less than beginning icol = icol + 1 ! advance pointer into input string endif imax = max ( imax , iterm ( i30 ) - ibegin ( i30 ) + 1 ) icount = i30 ! increment count of number of tokens found if ( icol > ilen ) then ! no text left exit INFINITE endif enddo INFINITE end select select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) ireturn = inotnull case default ireturn = icount end select allocate ( character ( len = imax ) :: array ( ireturn )) ! allocate the array to return !allocate(array(ireturn)) ! allocate the array to turn select case ( trim ( adjustl ( ordr ))) ! decide which order to store tokens case ( 'reverse' , 'right' ) ; ii = ireturn ; iiii =- 1 ! last to first case default ; ii = 1 ; iiii = 1 ! first to last end select do i20 = 1 , icount ! fill the array with the tokens that were found if ( iterm ( i20 ) < ibegin ( i20 )) then select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) case default array ( ii ) = ' ' ii = ii + iiii end select else array ( ii ) = input_line ( ibegin ( i20 ): iterm ( i20 )) ii = ii + iiii endif enddo end subroutine split","tags":"","loc":"proc/split.html"},{"title":"fnv_1a – Fortran-lang/fpm","text":"public interface fnv_1a Contents Module Procedures fnv_1a_char fnv_1a_string_t Module Procedures private pure function fnv_1a_char(input, seed) result(hash) Hash a character(*) string of default kind Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64) private pure function fnv_1a_string_t(input, seed) result(hash) Hash a string_t array of default kind Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: input (:) integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64)","tags":"","loc":"interface/fnv_1a.html"},{"title":"len_trim – Fortran-lang/fpm","text":"public interface len_trim Contents Module Procedures string_len_trim strings_len_trim Module Procedures private elemental function string_len_trim(string) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: string Return Value integer private pure function strings_len_trim(strings) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) Return Value integer","tags":"","loc":"interface/len_trim.html"},{"title":"operator(.in.) – Fortran-lang/fpm","text":"public interface operator(.in.) Contents Module Procedures string_array_contains Module Procedures public function string_array_contains (search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical","tags":"","loc":"interface/operator(.in.).html"},{"title":"resize – Fortran-lang/fpm","text":"public interface resize Contents Module Procedures resize_string Module Procedures private subroutine resize_string(list, n) increase the size of a TYPE(STRING_T) array by N elements Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout), allocatable :: list (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size","tags":"","loc":"interface/resize~2.html"},{"title":"str – Fortran-lang/fpm","text":"public interface str Contents Module Procedures str_int str_int64 str_logical Module Procedures private pure function str_int(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer, intent(in) :: i Return Value character(len=str_int_len) private pure function str_int64(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer(kind=int64), intent(in) :: i Return Value character(len=str_int64_len) private pure function str_logical(l) result(s) Converts logical “l” to string Arguments Type Intent Optional Attributes Name logical, intent(in) :: l Return Value character(len=str_logical_len)","tags":"","loc":"interface/str.html"},{"title":"str_ends_with – Fortran-lang/fpm","text":"public interface str_ends_with Contents Module Procedures str_ends_with_str str_ends_with_any Module Procedures private pure function str_ends_with_str(s, e) result(r) test if a CHARACTER string ends with a specified suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e Return Value logical private pure function str_ends_with_any(s, e) result(r) test if a CHARACTER string ends with any of an array of suffixs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e (:) Return Value logical","tags":"","loc":"interface/str_ends_with.html"},{"title":"string_t – Fortran-lang/fpm","text":"public interface string_t Contents Module Procedures new_string_t Module Procedures private function new_string_t(s) result(string) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s Return Value type( string_t )","tags":"","loc":"interface/string_t.html"},{"title":"regex_version_from_text – Fortran-lang/fpm","text":"public function regex_version_from_text(text, what, error) result(ver) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: text character(len=*), intent(in) :: what type( error_t ), intent(out), allocatable :: error Return Value type( string_t ) Contents Source Code regex_version_from_text Source Code type ( string_t ) function regex_version_from_text ( text , what , error ) result ( ver ) character ( * ), intent ( in ) :: text character ( * ), intent ( in ) :: what type ( error_t ), allocatable , intent ( out ) :: error integer :: ire , length if ( len_trim ( text ) <= 0 ) then call syntax_error ( error , 'cannot retrieve ' // what // ' version: empty input string' ) return end if ! Extract 3-sized version \"1.0.4\" ire = regex ( text , '\\d+\\.\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ! Parse version into the object (this should always work) ver = string_t ( text ( ire : ire + length - 1 )) else ! Try 2-sized version \"1.0\" ire = regex ( text , '\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ver = string_t ( text ( ire : ire + length - 1 )) else call syntax_error ( error , 'cannot retrieve ' // what // ' version.' ) end if end if end function regex_version_from_text","tags":"","loc":"proc/regex_version_from_text.html"},{"title":"new_version – Fortran-lang/fpm","text":"public interface new_version Contents Module Procedures new_version_from_string new_version_from_int Module Procedures private subroutine new_version_from_string(self, string, error) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data character(len=*), intent(in) :: string String describing the version information type( error_t ), intent(out), allocatable :: error Error handling private subroutine new_version_from_int(self, num) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data integer, intent(in) :: num (:) Subversion numbers to define version data","tags":"","loc":"interface/new_version.html"},{"title":"git_matches_manifest – Fortran-lang/fpm","text":"public function git_matches_manifest(cached, manifest, verbosity, iunit) Check that a cached dependency matches a manifest request The manifest dependency only contains partial information (what’s requested),\nwhile the cached dependency always stores a commit hash because it’s built\nafter the repo is available (saved as git_descriptor%revision==revision).\nSo, comparing against the descriptor is not reliable Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: cached Two input git targets type( git_target_t ), intent(in) :: manifest Two input git targets integer, intent(in) :: verbosity integer, intent(in) :: iunit Return Value logical Contents Source Code git_matches_manifest Source Code logical function git_matches_manifest ( cached , manifest , verbosity , iunit ) !> Two input git targets type ( git_target_t ), intent ( in ) :: cached , manifest integer , intent ( in ) :: verbosity , iunit git_matches_manifest = cached % url == manifest % url if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT URL has changed: \" , cached % url , \" vs. \" , manifest % url return endif !> The manifest dependency only contains partial information (what's requested), !> while the cached dependency always stores a commit hash because it's built !> after the repo is available (saved as git_descriptor%revision==revision). !> So, comparing against the descriptor is not reliable git_matches_manifest = allocated ( cached % object ) . eqv . allocated ( manifest % object ) if ( git_matches_manifest . and . allocated ( cached % object )) & git_matches_manifest = cached % object == manifest % object if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT OBJECT has changed: \" , cached % object , \" vs. \" , manifest % object end if end function git_matches_manifest","tags":"","loc":"proc/git_matches_manifest.html"},{"title":"git_target_branch – Fortran-lang/fpm","text":"public function git_target_branch(url, branch) result(self) Target a branch in the git repository Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: branch Name of the branch of interest Return Value type( git_target_t ) New git target Contents Source Code git_target_branch Source Code function git_target_branch ( url , branch ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Name of the branch of interest character ( len =* ), intent ( in ) :: branch !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % branch self % url = url self % object = branch end function git_target_branch","tags":"","loc":"proc/git_target_branch.html"},{"title":"git_target_default – Fortran-lang/fpm","text":"public function git_target_default(url) result(self) Default target Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository Return Value type( git_target_t ) New git target Contents Source Code git_target_default Source Code function git_target_default ( url ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % default self % url = url end function git_target_default","tags":"","loc":"proc/git_target_default.html"},{"title":"git_target_eq – Fortran-lang/fpm","text":"public function git_target_eq(this, that) result(is_equal) Check that two git targets are equal Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: this Two input git targets type( git_target_t ), intent(in) :: that Two input git targets Return Value logical Contents Source Code git_target_eq Source Code logical function git_target_eq ( this , that ) result ( is_equal ) !> Two input git targets type ( git_target_t ), intent ( in ) :: this , that is_equal = this % descriptor == that % descriptor . and . & this % url == that % url . and . & this % object == that % object end function git_target_eq","tags":"","loc":"proc/git_target_eq.html"},{"title":"git_target_revision – Fortran-lang/fpm","text":"public function git_target_revision(url, sha1) result(self) Target a specific git revision Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: sha1 Commit hash of interest Return Value type( git_target_t ) New git target Contents Source Code git_target_revision Source Code function git_target_revision ( url , sha1 ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Commit hash of interest character ( len =* ), intent ( in ) :: sha1 !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % revision self % url = url self % object = sha1 end function git_target_revision","tags":"","loc":"proc/git_target_revision.html"},{"title":"git_target_tag – Fortran-lang/fpm","text":"public function git_target_tag(url, tag) result(self) Target a git tag Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: tag Tag name of interest Return Value type( git_target_t ) New git target Contents Source Code git_target_tag Source Code function git_target_tag ( url , tag ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Tag name of interest character ( len =* ), intent ( in ) :: tag !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % tag self % url = url self % object = tag end function git_target_tag","tags":"","loc":"proc/git_target_tag.html"},{"title":"checkout – Fortran-lang/fpm","text":"public subroutine checkout(self, local_path, error) Type Bound git_target_t Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target character(len=*), intent(in) :: local_path Local path to checkout in type( error_t ), intent(out), allocatable :: error Error Contents Variables object stat workdir Source Code checkout Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: object integer, public :: stat character(len=:), public, allocatable :: workdir Source Code subroutine checkout ( self , local_path , error ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character ( len = :), allocatable :: object , workdir if ( allocated ( self % object )) then object = self % object else object = 'HEAD' end if workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) call execute_command_line ( \"git init \" // local_path , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while initiating git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" fetch --depth=1 \" // & self % url // \" \" // object , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while fetching git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" checkout -qf FETCH_HEAD\" , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while checking out git repository for remote dependency' ) return end if end subroutine checkout","tags":"","loc":"proc/checkout.html"},{"title":"git_archive – Fortran-lang/fpm","text":"public subroutine git_archive(source, destination, ref, verbose, error) Archive a folder using git archive . Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: source Directory to archive. character(len=*), intent(in) :: destination Destination of the archive. character(len=*), intent(in) :: ref (Symbolic) Reference to be archived. logical, intent(in) :: verbose Print additional information if true. type( error_t ), intent(out), allocatable :: error Error handling. Contents Variables archive_format cmd_output stat Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archive_format character(len=:), public, allocatable :: cmd_output integer, public :: stat","tags":"","loc":"proc/git_archive.html"},{"title":"git_revision – Fortran-lang/fpm","text":"public subroutine git_revision(local_path, object, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: local_path Local path to checkout in character(len=:), intent(out), allocatable :: object Git object reference type( error_t ), intent(out), allocatable :: error Error Contents Variables hexdigits iend iomsg istart line stat temp_file unit workdir Source Code git_revision Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: hexdigits = '0123456789abcdef' integer, public :: iend character(len=:), public, allocatable :: iomsg integer, public :: istart character(len=:), public, allocatable :: line integer, public :: stat character(len=:), public, allocatable :: temp_file integer, public :: unit character(len=:), public, allocatable :: workdir Source Code subroutine git_revision ( local_path , object , error ) !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Git object reference character ( len = :), allocatable , intent ( out ) :: object !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , unit , istart , iend character ( len = :), allocatable :: temp_file , line , iomsg , workdir character ( len =* ), parameter :: hexdigits = '0123456789abcdef' workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) allocate ( temp_file , source = get_temp_filename ()) line = \"git \" // workdir // \" log -n 1 > \" // temp_file call execute_command_line ( line , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error while retrieving commit information\" ) return end if open ( file = temp_file , newunit = unit ) call getline ( unit , line , stat , iomsg ) if ( stat /= 0 ) then call fatal_error ( error , iomsg ) return end if close ( unit , status = \"delete\" ) ! Tokenize: ! commit 0123456789abcdef (HEAD, ...) istart = scan ( line , ' ' ) + 1 iend = verify ( line ( istart :), hexdigits ) + istart - 1 if ( iend < istart ) iend = len ( line ) object = line ( istart : iend ) end subroutine git_revision","tags":"","loc":"proc/git_revision.html"},{"title":"info – Fortran-lang/fpm","text":"public subroutine info(self, unit, verbosity) Show information on git target Type Bound git_target_t Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Contents Variables fmt pr Source Code info Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: fmt = '(\"#\", 1x, a, t30, a)' integer, public :: pr Source Code subroutine info ( self , unit , verbosity ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Git target\" if ( allocated ( self % url )) then write ( unit , fmt ) \"- URL\" , self % url end if if ( allocated ( self % object )) then select case ( self % descriptor ) case default write ( unit , fmt ) \"- object\" , self % object case ( git_descriptor % tag ) write ( unit , fmt ) \"- tag\" , self % object case ( git_descriptor % branch ) write ( unit , fmt ) \"- branch\" , self % object case ( git_descriptor % revision ) write ( unit , fmt ) \"- sha1\" , self % object end select end if end subroutine info","tags":"","loc":"proc/info.html"},{"title":"operator(==) – Fortran-lang/fpm","text":"public interface operator(==) Contents Module Procedures git_target_eq Module Procedures public function git_target_eq (this, that) result(is_equal) Check that two git targets are equal Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: this Two input git targets type( git_target_t ), intent(in) :: that Two input git targets Return Value logical","tags":"","loc":"interface/operator(==).html"},{"title":"check_and_read_pkg_data – Fortran-lang/fpm","text":"public subroutine check_and_read_pkg_data(json, node, download_url, version, error) Arguments Type Intent Optional Attributes Name type(json_object), intent(inout) :: json class( dependency_node_t ), intent(in) :: node character(len=:), intent(out), allocatable :: download_url type( version_t ), intent(out) :: version type( error_t ), intent(out), allocatable :: error Contents","tags":"","loc":"proc/check_and_read_pkg_data.html"},{"title":"new_dependency_node – Fortran-lang/fpm","text":"public subroutine new_dependency_node(self, dependency, version, proj_dir, update) Create a new dependency node from a configuration Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(out) :: self Instance of the dependency node type( dependency_config_t ), intent(in) :: dependency Dependency configuration data type( version_t ), intent(in), optional :: version Version of the dependency character(len=*), intent(in), optional :: proj_dir Installation prefix of the dependency logical, intent(in), optional :: update Dependency should be updated Contents Source Code new_dependency_node Source Code subroutine new_dependency_node ( self , dependency , version , proj_dir , update ) !> Instance of the dependency node type ( dependency_node_t ), intent ( out ) :: self !> Dependency configuration data type ( dependency_config_t ), intent ( in ) :: dependency !> Version of the dependency type ( version_t ), intent ( in ), optional :: version !> Installation prefix of the dependency character ( len =* ), intent ( in ), optional :: proj_dir !> Dependency should be updated logical , intent ( in ), optional :: update self % dependency_config_t = dependency if ( present ( version )) then self % version = version end if if ( present ( proj_dir )) then self % proj_dir = proj_dir end if if ( present ( update )) then self % update = update end if end subroutine new_dependency_node","tags":"","loc":"proc/new_dependency_node.html"},{"title":"new_dependency_tree – Fortran-lang/fpm","text":"public subroutine new_dependency_tree(self, verbosity, cache) Create a new dependency tree Arguments Type Intent Optional Attributes Name type( dependency_tree_t ), intent(out) :: self Instance of the dependency tree integer, intent(in), optional :: verbosity Verbosity of printout character(len=*), intent(in), optional :: cache Name of the cache file Contents Source Code new_dependency_tree Source Code subroutine new_dependency_tree ( self , verbosity , cache ) !> Instance of the dependency tree type ( dependency_tree_t ), intent ( out ) :: self !> Verbosity of printout integer , intent ( in ), optional :: verbosity !> Name of the cache file character ( len =* ), intent ( in ), optional :: cache call resize ( self % dep ) self % dep_dir = join_path ( \"build\" , \"dependencies\" ) if ( present ( verbosity )) self % verbosity = verbosity if ( present ( cache )) self % cache = cache end subroutine new_dependency_tree","tags":"","loc":"proc/new_dependency_tree.html"},{"title":"resize – Fortran-lang/fpm","text":"public interface resize Overloaded reallocation interface Contents Module Procedures resize_dependency_node Module Procedures private pure subroutine resize_dependency_node(var, n) Reallocate a list of dependencies Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(inout), allocatable :: var (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size","tags":"","loc":"interface/resize.html"},{"title":"check_keys – Fortran-lang/fpm","text":"public subroutine check_keys(table, valid_keys, error) Check if table contains only keys that are part of the list. If a key is\nfound that is not part of the list, an error is allocated. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: valid_keys (:) List of keys to check. type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code check_keys Source Code subroutine check_keys ( table , valid_keys , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys to check. character ( len =* ), intent ( in ) :: valid_keys (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: keys (:) type ( toml_table ), pointer :: child character (:), allocatable :: name , value , valid_keys_string integer :: ikey , ivalid call table % get_key ( name ) call table % get_keys ( keys ) do ikey = 1 , size ( keys ) if (. not . any ( keys ( ikey )% key == valid_keys )) then ! Generate error message valid_keys_string = new_line ( 'a' ) // new_line ( 'a' ) do ivalid = 1 , size ( valid_keys ) valid_keys_string = valid_keys_string // trim ( valid_keys ( ivalid )) // new_line ( 'a' ) end do allocate ( error ) error % message = \"Key '\" // keys ( ikey )% key // \"' not allowed in the '\" // & & name // \"' table.\" // new_line ( 'a' ) // new_line ( 'a' ) // 'Valid keys: ' // valid_keys_string return end if ! Check if value can be mapped or else (wrong type) show error message with the error location. ! Right now, it can only be mapped to a string or to a child node, but this can be extended in the future. call get_value ( table , keys ( ikey )% key , value ) if (. not . allocated ( value )) then ! If value is not a string, check if it is a child node call get_value ( table , keys ( ikey )% key , child ) if (. not . associated ( child )) then allocate ( error ) error % message = \"'\" // name // \"' has an invalid '\" // keys ( ikey )% key // \"' entry.\" return endif end if end do end subroutine check_keys","tags":"","loc":"proc/check_keys.html"},{"title":"get_list – Fortran-lang/fpm","text":"public subroutine get_list(table, key, list, error) Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Key to read from type( string_t ), intent(out), allocatable :: list (:) List of strings to read type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code get_list Source Code subroutine get_list ( table , key , list , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Key to read from character ( len =* ), intent ( in ) :: key !> List of strings to read type ( string_t ), allocatable , intent ( out ) :: list (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , ilist , nlist type ( toml_array ), pointer :: children character ( len = :), allocatable :: str if (. not . table % has_key ( key )) return call get_value ( table , key , children , requested = . false .) if ( associated ( children )) then nlist = len ( children ) allocate ( list ( nlist )) do ilist = 1 , nlist call get_value ( children , ilist , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) exit end if call move_alloc ( str , list ( ilist )% s ) end do if ( allocated ( error )) return else call get_value ( table , key , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) return end if if ( allocated ( str )) then allocate ( list ( 1 )) call move_alloc ( str , list ( 1 )% s ) end if end if end subroutine get_list","tags":"","loc":"proc/get_list.html"},{"title":"read_package_file – Fortran-lang/fpm","text":"public subroutine read_package_file(table, manifest, error) Process the configuration file to a TOML data structure Arguments Type Intent Optional Attributes Name type(toml_table), intent(out), allocatable :: table TOML data structure character(len=*), intent(in) :: manifest Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation Contents Source Code read_package_file Source Code subroutine read_package_file ( table , manifest , error ) !> TOML data structure type ( toml_table ), allocatable , intent ( out ) :: table !> Name of the package configuration file character ( len =* ), intent ( in ) :: manifest !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error type ( toml_error ), allocatable :: parse_error integer :: unit logical :: exist inquire ( file = manifest , exist = exist ) if (. not . exist ) then call file_not_found_error ( error , manifest ) return end if open ( file = manifest , newunit = unit ) call toml_load ( table , unit , error = parse_error ) close ( unit ) if ( allocated ( parse_error )) then allocate ( error ) call move_alloc ( parse_error % message , error % message ) return end if end subroutine read_package_file","tags":"","loc":"proc/read_package_file.html"},{"title":"new_installer – Fortran-lang/fpm","text":"public subroutine new_installer(self, prefix, bindir, libdir, includedir, verbosity, copy, move) Create a new instance of an installer Arguments Type Intent Optional Attributes Name type( installer_t ), intent(out) :: self Instance of the installer character(len=*), intent(in), optional :: prefix Path to installation directory character(len=*), intent(in), optional :: bindir Binary dir relative to the installation prefix character(len=*), intent(in), optional :: libdir Library directory relative to the installation prefix character(len=*), intent(in), optional :: includedir Include directory relative to the installation prefix integer, intent(in), optional :: verbosity Verbosity of the installer character(len=*), intent(in), optional :: copy Copy command character(len=*), intent(in), optional :: move Move command Contents Source Code new_installer Source Code subroutine new_installer ( self , prefix , bindir , libdir , includedir , verbosity , & copy , move ) !> Instance of the installer type ( installer_t ), intent ( out ) :: self !> Path to installation directory character ( len =* ), intent ( in ), optional :: prefix !> Binary dir relative to the installation prefix character ( len =* ), intent ( in ), optional :: bindir !> Library directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: libdir !> Include directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: includedir !> Verbosity of the installer integer , intent ( in ), optional :: verbosity !> Copy command character ( len =* ), intent ( in ), optional :: copy !> Move command character ( len =* ), intent ( in ), optional :: move self % os = get_os_type () ! By default, never prompt the user for overwrites if ( present ( copy )) then self % copy = copy else if ( os_is_unix ( self % os )) then self % copy = default_force_copy_unix else self % copy = default_force_copy_win end if end if if ( present ( move )) then self % move = move else if ( os_is_unix ( self % os )) then self % move = default_move_unix else self % move = default_move_win end if end if if ( present ( includedir )) then self % includedir = includedir else self % includedir = default_includedir end if if ( present ( prefix )) then self % prefix = prefix else self % prefix = get_local_prefix ( self % os ) end if if ( present ( bindir )) then self % bindir = bindir else self % bindir = default_bindir end if if ( present ( libdir )) then self % libdir = libdir else self % libdir = default_libdir end if if ( present ( verbosity )) then self % verbosity = verbosity else self % verbosity = 1 end if end subroutine new_installer","tags":"","loc":"proc/new_installer.html"},{"title":"default_example – Fortran-lang/fpm","text":"public subroutine default_example(self, name) Populate test in case we find the default example/ directory Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package Contents Source Code default_example Source Code subroutine default_example ( self , name ) !> Instance of the executable meta data type ( example_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-demo\" self % source_dir = \"example\" self % main = \"main.f90\" end subroutine default_example","tags":"","loc":"proc/default_example.html"},{"title":"default_executable – Fortran-lang/fpm","text":"public subroutine default_executable(self, name) Populate executable in case we find the default app directory Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package Contents Source Code default_executable Source Code subroutine default_executable ( self , name ) !> Instance of the executable meta data type ( executable_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name self % source_dir = \"app\" self % main = \"main.f90\" end subroutine default_executable","tags":"","loc":"proc/default_executable.html"},{"title":"default_library – Fortran-lang/fpm","text":"public subroutine default_library(self) Populate library in case we find the default src directory Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library meta data Contents Source Code default_library Source Code subroutine default_library ( self ) !> Instance of the library meta data type ( library_config_t ), intent ( out ) :: self self % source_dir = \"src\" self % include_dir = [ string_t ( \"include\" )] end subroutine default_library","tags":"","loc":"proc/default_library.html"},{"title":"default_test – Fortran-lang/fpm","text":"public subroutine default_test(self, name) Populate test in case we find the default test/ directory Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package Contents Source Code default_test Source Code subroutine default_test ( self , name ) !> Instance of the executable meta data type ( test_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-test\" self % source_dir = \"test\" self % main = \"main.f90\" end subroutine default_test","tags":"","loc":"proc/default_test.html"},{"title":"get_package_data – Fortran-lang/fpm","text":"public subroutine get_package_data(package, file, error, apply_defaults) Obtain package meta data from a configuation file Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: package Parsed package meta data character(len=*), intent(in) :: file Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation logical, intent(in), optional :: apply_defaults Apply package defaults (uses file system operations) Contents Source Code get_package_data Source Code subroutine get_package_data ( package , file , error , apply_defaults ) !> Parsed package meta data type ( package_config_t ), intent ( out ) :: package !> Name of the package configuration file character ( len =* ), intent ( in ) :: file !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error !> Apply package defaults (uses file system operations) logical , intent ( in ), optional :: apply_defaults type ( toml_table ), allocatable :: table character ( len = :), allocatable :: root call read_package_file ( table , file , error ) if ( allocated ( error )) return if (. not . allocated ( table )) then call fatal_error ( error , \"Unclassified error while reading: '\" // file // \"'\" ) return end if call new_package ( package , table , dirname ( file ), error ) if ( allocated ( error )) return if ( present ( apply_defaults )) then if ( apply_defaults ) then root = dirname ( file ) if ( len_trim ( root ) == 0 ) root = \".\" call package_defaults ( package , root , error ) if ( allocated ( error )) return end if end if end subroutine get_package_data","tags":"","loc":"proc/get_package_data.html"},{"title":"fpm_version – Fortran-lang/fpm","text":"public function fpm_version() Return the current fpm version from fpm_version_ID as a version type Arguments None Return Value type( version_t ) Contents Source Code fpm_version Source Code type ( version_t ) function fpm_version () type ( error_t ), allocatable :: error ! Fallback to last known version in case of undefined macro #ifndef FPM_RELEASE_VERSION # define FPM_RELEASE_VERSION 0.8.0 #endif ! Accept solution from https://stackoverflow.com/questions/31649691/stringify-macro-with-gnu-gfortran ! which provides the \"easiest\" way to pass a macro to a string in Fortran complying with both ! gfortran's \"traditional\" cpp and the standard cpp syntaxes #ifdef __GFORTRAN__ /* traditional-cpp stringification */ # define STRINGIFY_START(X) \"& # define STRINGIFY_END(X) &X\" #else /* default stringification */ # define STRINGIFY_(X) #X # define STRINGIFY_START(X) & # define STRINGIFY_END(X) STRINGIFY_(X) #endif character ( len = :), allocatable :: ver_string ver_string = STRINGIFY_START ( FPM_RELEASE_VERSION ) STRINGIFY_END ( FPM_RELEASE_VERSION ) call new_version ( fpm_version , ver_string , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*fpm*:internal error: cannot get version - ' // error % message ) end function fpm_version","tags":"","loc":"proc/fpm_version.html"},{"title":"bad_name_error – Fortran-lang/fpm","text":"public function bad_name_error(error, label, name) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: label Error message label to add to message character(len=*), intent(in) :: name name value to check Return Value logical Contents Source Code bad_name_error Source Code function bad_name_error ( error , label , name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message label to add to message character ( len =* ), intent ( in ) :: label !> name value to check character ( len =* ), intent ( in ) :: name logical :: bad_name_error if (. not . is_fortran_name ( to_fortran_name ( name ))) then bad_name_error = . true . allocate ( error ) error % message = 'manifest file syntax error: ' // label // ' name must be composed only of & &alphanumerics, \"-\" and \"_\" and start with a letter ::' // name else bad_name_error = . false . endif end function bad_name_error","tags":"","loc":"proc/bad_name_error.html"},{"title":"fatal_error – Fortran-lang/fpm","text":"public subroutine fatal_error(error, message) Generic fatal runtime error Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message Contents Source Code fatal_error Source Code subroutine fatal_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine fatal_error","tags":"","loc":"proc/fatal_error.html"},{"title":"file_not_found_error – Fortran-lang/fpm","text":"public subroutine file_not_found_error(error, file_name) Error created when a file is missing or not found Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of the missing file Contents Source Code file_not_found_error Source Code subroutine file_not_found_error ( error , file_name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of the missing file character ( len =* ), intent ( in ) :: file_name allocate ( error ) error % message = \"'\" // file_name // \"' could not be found, check if the file exists\" end subroutine file_not_found_error","tags":"","loc":"proc/file_not_found_error.html"},{"title":"file_parse_error – Fortran-lang/fpm","text":"public subroutine file_parse_error(error, file_name, message, line_num, line_string, line_col) Error created when file parsing fails Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of file character(len=*), intent(in) :: message Parse error message integer, intent(in), optional :: line_num Line number of parse error character(len=*), intent(in), optional :: line_string Line context string integer, intent(in), optional :: line_col Line context column Contents Source Code file_parse_error Source Code subroutine file_parse_error ( error , file_name , message , line_num , & line_string , line_col ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of file character ( len =* ), intent ( in ) :: file_name !> Parse error message character ( len =* ), intent ( in ) :: message !> Line number of parse error integer , intent ( in ), optional :: line_num !> Line context string character ( len =* ), intent ( in ), optional :: line_string !> Line context column integer , intent ( in ), optional :: line_col character ( 50 ) :: temp_string allocate ( error ) error % message = 'Parse error: ' // message // new_line ( 'a' ) error % message = error % message // file_name if ( present ( line_num )) then write ( temp_string , '(I0)' ) line_num error % message = error % message // ':' // trim ( temp_string ) end if if ( present ( line_col )) then if ( line_col > 0 ) then write ( temp_string , '(I0)' ) line_col error % message = error % message // ':' // trim ( temp_string ) end if end if if ( present ( line_string )) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // line_string if ( present ( line_col )) then if ( line_col > 0 ) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // repeat ( ' ' , line_col - 1 ) // '^' end if end if end if end subroutine file_parse_error","tags":"","loc":"proc/file_parse_error.html"},{"title":"fpm_stop – Fortran-lang/fpm","text":"public subroutine fpm_stop(value, message) Arguments Type Intent Optional Attributes Name integer, intent(in) :: value value to use on STOP character(len=*), intent(in) :: message Error message Contents Source Code fpm_stop Source Code subroutine fpm_stop ( value , message ) ! TODO: if verbose mode, call ERROR STOP instead of STOP ! TODO: if M_escape is used, add color ! to work with older compilers might need a case statement for values !> value to use on STOP integer , intent ( in ) :: value !> Error message character ( len =* ), intent ( in ) :: message integer :: iostat if ( message /= '' ) then flush ( unit = stderr , iostat = iostat ) flush ( unit = stdout , iostat = iostat ) if ( value > 0 ) then write ( stderr , '(\" \",a)' ) trim ( message ) else write ( stderr , '(\" \",a)' ) trim ( message ) endif flush ( unit = stderr , iostat = iostat ) endif stop value end subroutine fpm_stop","tags":"","loc":"proc/fpm_stop.html"},{"title":"syntax_error – Fortran-lang/fpm","text":"public subroutine syntax_error(error, message) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message Contents Source Code syntax_error Source Code subroutine syntax_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine syntax_error","tags":"","loc":"proc/syntax_error.html"},{"title":"cmd_install – Fortran-lang/fpm","text":"public subroutine cmd_install(settings) Entry point for the fpm-install subcommand Arguments Type Intent Optional Attributes Name type( fpm_install_settings ), intent(inout) :: settings Representation of the command line settings Contents Source Code cmd_install Source Code subroutine cmd_install ( settings ) !> Representation of the command line settings type ( fpm_install_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( error_t ), allocatable :: error type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( installer_t ) :: installer type ( string_t ), allocatable :: list (:) logical :: installable call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) call build_model ( model , settings , package , error ) call handle_error ( error ) call targets_from_sources ( targets , model , settings % prune , error ) call handle_error ( error ) installable = ( allocated ( package % library ) . and . package % install % library ) & . or . allocated ( package % executable ) if (. not . installable ) then call fatal_error ( error , \"Project does not contain any installable targets\" ) call handle_error ( error ) end if if ( settings % list ) then call install_info ( output_unit , targets ) return end if if (. not . settings % no_rebuild ) then call build_package ( targets , model , verbose = settings % verbose ) end if call new_installer ( installer , prefix = settings % prefix , & bindir = settings % bindir , libdir = settings % libdir , & includedir = settings % includedir , & verbosity = merge ( 2 , 1 , settings % verbose )) if ( allocated ( package % library ) . and . package % install % library ) then call filter_library_targets ( targets , list ) if ( size ( list ) > 0 ) then call installer % install_library ( list ( 1 )% s , error ) call handle_error ( error ) call install_module_files ( installer , targets , error ) call handle_error ( error ) end if end if if ( allocated ( package % executable )) then call install_executables ( installer , targets , error ) call handle_error ( error ) end if end subroutine cmd_install","tags":"","loc":"proc/cmd_install.html"},{"title":"cmd_update – Fortran-lang/fpm","text":"public subroutine cmd_update(settings) Entry point for the update subcommand Arguments Type Intent Optional Attributes Name type( fpm_update_settings ), intent(in) :: settings Representation of the command line arguments Contents Source Code cmd_update Source Code subroutine cmd_update ( settings ) !> Representation of the command line arguments type ( fpm_update_settings ), intent ( in ) :: settings type ( package_config_t ) :: package type ( dependency_tree_t ) :: deps type ( error_t ), allocatable :: error integer :: ii character ( len = :), allocatable :: cache call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) if (. not . exists ( \"build\" )) then call mkdir ( \"build\" ) call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if cache = join_path ( \"build\" , \"cache.toml\" ) if ( settings % clean ) call delete_file ( cache ) call new_dependency_tree ( deps , cache = cache , & verbosity = merge ( 2 , 1 , settings % verbose )) call deps % add ( package , error ) call handle_error ( error ) ! Force-update all dependencies if `--clean` if ( settings % clean ) then do ii = 1 , deps % ndep deps % dep ( ii )% update = . true . end do end if if ( settings % fetch_only ) return if ( size ( settings % name ) == 0 ) then call deps % update ( error ) call handle_error ( error ) else do ii = 1 , size ( settings % name ) call deps % update ( trim ( settings % name ( ii )), error ) call handle_error ( error ) end do end if end subroutine cmd_update","tags":"","loc":"proc/cmd_update.html"},{"title":"cmd_new – Fortran-lang/fpm","text":"public subroutine cmd_new(settings) TOP DIRECTORY NAME PROCESSING\nsee if requested new directory already exists and process appropriately\ntemporarily change to new directory as a test. NB: System dependent Arguments Type Intent Optional Attributes Name type( fpm_new_settings ), intent(in) :: settings Contents Source Code cmd_new Source Code subroutine cmd_new ( settings ) type ( fpm_new_settings ), intent ( in ) :: settings integer , parameter :: tfc = selected_char_kind ( 'DEFAULT' ) character ( len = :, kind = tfc ), allocatable :: bname ! baeename of NAME character ( len = :, kind = tfc ), allocatable :: tomlfile (:) character ( len = :, kind = tfc ), allocatable :: littlefile (:) !> TOP DIRECTORY NAME PROCESSING !> see if requested new directory already exists and process appropriately if ( exists ( settings % name ) . and . . not . settings % backfill ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists.' write ( stderr , '(*(g0,1x))' )& & ' perhaps you wanted to add --backfill ?' return elseif ( is_dir ( settings % name ) . and . settings % backfill ) then write ( * , '(*(g0))' ) 'backfilling ' , settings % name elseif ( exists ( settings % name ) ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists and is not a directory.' return else ! make new directory call mkdir ( settings % name ) endif !> temporarily change to new directory as a test. NB: System dependent call run ( 'cd ' // settings % name ) ! NOTE: need some system routines to handle filenames like \".\" ! like realpath() or getcwd(). bname = basename ( settings % name ) littlefile = [ character ( len = 80 ) :: '# ' // bname , 'My cool new project!' ] ! create NAME/README.md call warnwrite ( join_path ( settings % name , 'README.md' ), littlefile ) ! start building NAME/fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: & & ' # This is your fpm(Fortran Package Manager) manifest file ' ,& & ' # (\"fpm.toml\"). It is heavily annotated to help guide you though ' ,& & ' # customizing a package build, although the defaults are sufficient ' ,& & ' # for many basic packages. ' ,& & ' # ' ,& & ' # The manifest file is not only used to provide metadata identifying ' ,& & ' # your project (so it can be used by others as a dependency). It can ' ,& & ' # specify where your library and program sources live, what the name ' ,& & ' # of the executable(s) will be, what files to build, dependencies on ' ,& & ' # other fpm packages, and what external libraries are required. ' ,& & ' # ' ,& & ' # The manifest format must conform to the TOML configuration file ' ,& & ' # standard. ' ,& & ' # ' ,& & ' # TOML files support flexible use of white-space and commenting of the ' ,& & ' # configuration data, but for clarity in this sample active directives ' ,& & ' # begin in column one. Inactive example directives are commented ' ,& & ' # out with a pound character (\"#\") but begin in column one as well. ' ,& & ' # Commentary begins with a pound character in column three. ' ,& & ' # ' ,& & ' # This file draws heavily upon the following references: ' ,& & ' # ' ,& & ' # The fpm home page at ' ,& & ' # https://github.com/fortran-lang/fpm ' ,& & ' # A complete list of keys and their attributes at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/manifest-reference.md ' ,& & ' # examples of fpm project packaging at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/PACKAGING.md ' ,& & ' # The Fortran TOML file interface and it''s references at ' ,& & ' # https://github.com/toml-f/toml-f ' ,& & ' # ' ,& & ' #----------------------- ' ,& & ' # project Identification ' ,& & ' #----------------------- ' ,& & ' # We begin with project metadata at the manifest root. This data is designed ' ,& & ' # to aid others when searching for the project in a repository and to ' ,& & ' # identify how and when to contact the package supporters. ' ,& & ' ' ,& & 'name = \"' // bname // '\"' ,& & ' # The project name (required) is how the project will be referred to. ' ,& & ' # The name is used by other packages using it as a dependency. It also ' ,& & ' # is used as the default name of any library built and the optional ' ,& & ' # default executable built from app/main.f90. It must conform to the rules ' ,& & ' # for a Fortran variable name. ' ,& & ' ' ,& & 'version = \"0.1.0\" ' ,& & ' # The project version number is a string. A recommended scheme for ' ,& & ' # specifying versions is the Semantic Versioning scheme. ' ,& & ' ' ,& & 'license = \"license\" ' ,& & ' # Licensing information specified using SPDX identifiers is preferred ' ,& & ' # (eg. \"Apache-2.0 OR MIT\" or \"LGPL-3.0-or-later\"). ' ,& & ' ' ,& & 'maintainer = \"jane.doe@example.com\" ' ,& & ' # Information on the project maintainer and means to reach out to them. ' ,& & ' ' ,& & 'author = \"Jane Doe\" ' ,& & ' # Information on the project author. ' ,& & ' ' ,& & 'copyright = \"Copyright 2020 Jane Doe\" ' ,& & ' # A statement clarifying the Copyright status of the project. ' ,& & ' ' ,& & '#description = \"A short project summary in plain text\" ' ,& & ' # The description provides a short summary on the project. It should be ' ,& & ' # plain text and not use any markup formatting. ' ,& & ' ' ,& & '#categories = [\"fortran\", \"graphics\"] ' ,& & ' # Categories associated with the project. Listing only one is preferred. ' ,& & ' ' ,& & '#keywords = [\"hdf5\", \"mpi\"] ' ,& & ' # The keywords field is an array of strings describing the project. ' ,& & ' ' ,& & '#homepage = \"https://stdlib.fortran-lang.org\" ' ,& & ' # URL to the webpage of the project. ' ,& & ' ' ,& & ' # ----------------------------------------- ' ,& & ' # We are done with identifying the project. ' ,& & ' # ----------------------------------------- ' ,& & ' # ' ,& & ' # Now lets start describing how the project should be built. ' ,& & ' # ' ,& & ' # Note tables would go here but we will not be talking about them (much)!!' ,& & ' # ' ,& & ' # Tables are a way to explicitly specify large numbers of programs in ' ,& & ' # a compact format instead of individual per-program entries in the ' ,& & ' # [[executable]], [[test]], and [[example]] sections to follow but ' ,& & ' # will not be discussed further except for the following notes: ' ,& & ' # ' ,& & ' # + Tables must appear (here) before any sections are declared. Once a ' ,& & ' # section is specified in a TOML file everything afterwards must be ' ,& & ' # values for that section or the beginning of a new section. A simple ' ,& & ' # example looks like: ' ,& & ' ' ,& & '#executable = [ ' ,& & '# { name = \"a-prog\" }, ' ,& & '# { name = \"app-tool\", source-dir = \"tool\" }, ' ,& & '# { name = \"fpm-man\", source-dir = \"tool\", main=\"fman.f90\" } ' ,& & '#] ' ,& & ' ' ,& & ' # This would be in lieue of the [[executable]] section found later in this ' ,& & ' # configuration file. ' ,& & ' # + See the reference documents (at the beginning of this document) ' ,& & ' # for more information on tables if you have long lists of programs ' ,& & ' # to build and are not simply depending on auto-detection. ' ,& & ' # ' ,& & ' # Now lets begin the TOML sections (lines beginning with \"[\") ... ' ,& & ' # ' ,& & ' ' ,& & '[install] # Options for the \"install\" subcommand ' ,& & ' ' ,& & ' # When you run the \"install\" subcommand only executables are installed by ' ,& & ' # default on the local system. Library projects that will be used outside of ' ,& & ' # \"fpm\" can set the \"library\" boolean to also allow installing the module ' ,& & ' # files and library archive. Without this being set to \"true\" an \"install\" ' ,& & ' # subcommand ignores parameters that specify library installation. ' ,& & ' ' ,& & 'library = false ' ,& & ' ' ,& & '[build] # General Build Options ' ,& & ' ' ,& & ' ### Automatic target discovery ' ,& & ' # ' ,& & ' # Normally fpm recursively searches the app/, example/, and test/ directories ' ,& & ' # for program sources and builds them. To disable this automatic discovery of ' ,& & ' # program targets set the following to \"false\": ' ,& & ' ' ,& & '#auto-executables = true ' ,& & '#auto-examples = true ' ,& & '#auto-tests = true ' ,& & ' ' ,& & ' ### Package-level External Library Links ' ,& & ' # ' ,& & ' # To declare link-time dependencies on external libraries a list of ' ,& & ' # native libraries can be specified with the \"link\" entry. You may ' ,& & ' # have one library name or a list of strings in case several ' ,& & ' # libraries should be linked. This list of library dependencies is ' ,& & ' # exported to dependent packages. You may have to alter your library ' ,& & ' # search-path to ensure the libraries can be accessed. Typically, ' ,& & ' # this is done with the LD_LIBRARY_PATH environment variable on ULS ' ,& & ' # (Unix-Like Systems). You only specify the core name of the library ' ,& & ' # (as is typical with most programming environments, where you ' ,& & ' # would specify \"-lz\" on your load command to link against the zlib ' ,& & ' # compression library even though the library file would typically be ' ,& & ' # a file called \"libz.a\" \"or libz.so\"). So to link against that library ' ,& & ' # you would specify: ' ,& & ' ' ,& & '#link = \"z\" ' ,& & ' ' ,& & ' # Note that in some cases the order of the libraries matters: ' ,& & ' ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_lib ) then call mkdir ( join_path ( settings % name , 'src' ) ) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[library] ' ,& & ' ' ,& & ' # You can change the name of the directory to search for your library ' ,& & ' # source from the default of \"src/\". Library targets are exported ' ,& & ' # and usable by other projects. ' ,& & ' ' ,& & 'source-dir=\"src\" ' ,& & ' ' ,& & ' # this can be a list: ' ,& & ' ' ,& & '#source-dir=[\"src\", \"src2\"] ' ,& & ' ' ,& & ' # More complex libraries may organize their modules in subdirectories. ' ,& & ' # For modules in a top-level directory fpm requires (but does not ' ,& & ' # enforce) that: ' ,& & ' # ' ,& & ' # + The module has the same name as the source file. This is important. ' ,& & ' # + There should be only one module per file. ' ,& & ' # ' ,& & ' # These two requirements simplify the build process for fpm. As Fortran ' ,& & ' # compilers emit module files (.mod) with the same name as the module ' ,& & ' # itself (but not the source file, .f90), naming the module the same ' ,& & ' # as the source file allows fpm to: ' ,& & ' # ' ,& & ' # + Uniquely and exactly map a source file (.f90) to its object (.o) ' ,& & ' # and module (.mod) files. ' ,& & ' # + Avoid conflicts with modules of the same name that could appear ' ,& & ' # in dependency packages. ' ,& & ' # ' ,& & ' ### Multi-level library source ' ,& & ' # You can place your module source files in any number of levels of ' ,& & ' # subdirectories inside your source directory, but there are certain naming ' ,& & ' # conventions to be followed -- module names must contain the path components ' ,& & ' # of the directory that its source file is in. ' ,& & ' # ' ,& & ' # This rule applies generally to any number of nested directories and ' ,& & ' # modules. For example, src/a/b/c/d.f90 must define a module called a_b_c_d. ' ,& & ' # Again, this is not enforced but may be required in future releases. ' ,& & '' ] endif ! create placeholder module src/bname.f90 littlefile = [ character ( len = 80 ) :: & & 'module ' // to_fortran_name ( bname ), & & ' implicit none' , & & ' private' , & & '' , & & ' public :: say_hello' , & & 'contains' , & & ' subroutine say_hello' , & & ' print *, \"Hello, ' // bname // '!\"' , & & ' end subroutine say_hello' , & & 'end module ' // to_fortran_name ( bname )] ! create NAME/src/NAME.f90 call warnwrite ( join_path ( settings % name , 'src' , bname // '.f90' ),& & littlefile ) endif if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[dependencies] ' ,& & ' ' ,& & ' # Inevitably, you will want to be able to include other packages in ' ,& & ' # a project. Fpm makes this incredibly simple, by taking care of ' ,& & ' # fetching and compiling your dependencies for you. You just tell it ' ,& & ' # what your dependencies names are, and where to find them. ' ,& & ' # ' ,& & ' # If you are going to distribute your package only place dependencies ' ,& & ' # here someone using your package as a remote dependency needs built. ' ,& & ' # You can define dependencies just for developer executables in the ' ,& & ' # next section, or even for specific executables as we will see below ' ,& & ' # (Then fpm will still fetch and compile it when building your ' ,& & ' # developer executables, but users of your library will not have to). ' ,& & ' # ' ,& & ' ## GLOBAL DEPENDENCIES (exported with your project) ' ,& & ' # ' ,& & ' # Typically, dependencies are defined by specifying the project''s ' ,& & ' # git repository. ' ,& & ' # ' ,& & ' # You can be specific about which version of a dependency you would ' ,& & ' # like. By default the latest default branch is used. You can ' ,& & ' # optionally specify a branch, a tag or a commit value. ' ,& & ' # ' ,& & ' # So here are several alternates for specifying a remote dependency (you ' ,& & ' # can have at most one of \"branch\", \"rev\" or \"tag\" present): ' ,& & ' ' ,& & '#stdlib = { git = \"https://github.com/LKedward/stdlib-fpm.git\" } ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\",branch = \"master\" },' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", tag = \"v0.1.0\" }, ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", rev = \"5a9b7a8\" }. ' ,& & ' ' ,& & ' # There may be multiple packages listed: ' ,& & ' ' ,& & '#M_strings = { git = \"https://github.com/urbanjost/M_strings.git\" } ' ,& & '#M_time = { git = \"https://github.com/urbanjost/M_time.git\" } ' ,& & ' ' ,& & ' # ' ,& & ' # You can even specify the local path to another project if it is in ' ,& & ' # a sub-folder (If for example you have got another fpm package **in ' ,& & ' # the same repository**) like this: ' ,& & ' ' ,& & '#M_strings = { path = \"M_strings\" } ' ,& & ' ' ,& & ' # This tells fpm that we depend on a crate called M_strings which is found ' ,& & ' # in the M_strings folder (relative to the fpm.toml it’s written in). ' ,& & ' # ' ,& & ' # For a more verbose layout use normal tables rather than inline tables ' ,& & ' # to specify dependencies: ' ,& & ' ' ,& & '#[dependencies.toml-f] ' ,& & '#git = \"https://github.com/toml-f/toml-f\" ' ,& & '#rev = \"2f5eaba864ff630ba0c3791126a3f811b6e437f3\" ' ,& & ' ' ,& & ' # Now you can use any modules from these libraries anywhere in your ' ,& & ' # code -- whether is in your library source or a program source. ' ,& & ' ' ,& & '[dev-dependencies] ' ,& & ' ' ,& & ' ## Dependencies Only for Development ' ,& & ' # ' ,& & ' # You can specify dependencies your library or application does not ' ,& & ' # depend on in a similar way. The difference is that these will not ' ,& & ' # be exported as part of your project to those using it as a remote ' ,& & ' # dependency. ' ,& & ' # ' ,& & ' # Currently, like a global dependency it will still be available for ' ,& & ' # all codes. It is up to the developer to ensure that nothing except ' ,& & ' # developer test programs rely upon it. ' ,& & ' ' ,& & '#M_msg = { git = \"https://github.com/urbanjost/M_msg.git\" } ' ,& & '#M_verify = { git = \"https://github.com/urbanjost/M_verify.git\" } ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_executable ) then ! create next section of fpm.toml call mkdir ( join_path ( settings % name , 'app' )) ! create NAME/app or stop if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & ' #----------------------------------- ' ,& & ' ## Application-specific declarations ' ,& & ' #----------------------------------- ' ,& & ' # Now lets begin entries for the TOML tables (lines beginning with \"[[\") ' ,& & ' # that describe the program sources -- applications, tests, and examples. ' ,& & ' # ' ,& & ' # First we will configuration individual applications run with \"fpm run\". ' ,& & ' # ' ,& & ' # + the \"name\" entry for the executable to be built must always ' ,& & ' # be specified. The name must satisfy the rules for a Fortran ' ,& & ' # variable name. This will be the name of the binary installed by ' ,& & ' # the \"install\" subcommand and used on the \"run\" subcommand. ' ,& & ' # + The source directory for each executable can be adjusted by the ' ,& & ' # \"source-dir\" entry. ' ,& & ' # + The basename of the source file containing the program body can ' ,& & ' # be specified with the \"main\" entry. ' ,& & ' # + Executables can also specify their own external package and ' ,& & ' # library link dependencies. ' ,& & ' # ' ,& & ' # Currently, like a global dependency any external package dependency ' ,& & ' # will be available for all codes. It is up to the developer to ensure ' ,& & ' # that nothing except the application programs specified rely upon it. ' ,& & ' # ' ,& & ' # Note if your application needs to use a module internally, but you do not ' ,& & ' # intend to build it as a library to be used in other projects, you can ' ,& & ' # include the module in your program source file or directory as well. ' ,& & ' ' ,& & '[[executable]] ' ,& & 'name=\"' // bname // '\"' ,& & 'source-dir=\"app\" ' ,& & 'main=\"main.f90\" ' ,& & ' ' ,& & ' # You may repeat this pattern to define additional applications. For instance,' ,& & ' # the following sample illustrates all accepted options, where \"link\" and ' ,& & ' # \"executable.dependencies\" keys are the same as the global external library ' ,& & ' # links and package dependencies described previously except they apply ' ,& & ' # only to this executable: ' ,& & ' ' ,& & '#[[ executable ]] ' ,& & '#name = \"app-name\" ' ,& & '#source-dir = \"prog\" ' ,& & '#main = \"program.f90\" ' ,& & '#link = \"z\" ' ,& & '#[executable.dependencies] ' ,& & '#M_CLI = { git = \"https://github.com/urbanjost/M_CLI.git\" } ' ,& & '#helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } ' ,& & '#M_path = { git = \"https://github.com/urbanjost/M_path.git\" } ' ,& & '' ] endif if ( exists ( bname // '/src/' )) then littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' use ' // to_fortran_name ( bname ) // ', only: say_hello' , & & ' implicit none' , & & '' , & & ' call say_hello()' , & & 'end program main' ] else littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' implicit none' , & & '' , & & ' print *, \"hello from project ' // bname // '\"' , & & 'end program main' ] endif call warnwrite ( join_path ( settings % name , 'app/main.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_test ) then ! create NAME/test or stop call mkdir ( join_path ( settings % name , 'test' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[[test]] ' ,& & ' ' ,& & ' # The same declarations can be made for test programs, which are ' ,& & ' # executed with the \"fpm test\" command and are not build when your ' ,& & ' # package is used as a dependency by other packages. These are ' ,& & ' # typically unit tests of the package only used during package ' ,& & ' # development. ' ,& & ' ' ,& & 'name=\"runTests\" ' ,& & 'source-dir=\"test\" ' ,& & 'main=\"check.f90\" ' ,& & ' ' ,& & ' # you may repeat this pattern to add additional explicit test program ' ,& & ' # parameters. The following example contains a sample of all accepted ' ,& & ' # options. ' ,& & ' ' ,& & '#[[ test ]] ' ,& & '#name = \"tester\" ' ,& & '#source-dir=\"test\" ' ,& & '#main=\"tester.f90\" ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '#[test.dependencies] ' ,& & '#M_CLI2 = { git = \"https://github.com/urbanjost/M_CLI2.git\" } ' ,& & '#M_io = { git = \"https://github.com/urbanjost/M_io.git\" } ' ,& & '#M_system= { git = \"https://github.com/urbanjost/M_system.git\" } ' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program check' , & & 'implicit none' , & & '' , & & 'print *, \"Put some tests in here!\"' , & & 'end program check' ] ! create NAME/test/check.f90 call warnwrite ( join_path ( settings % name , 'test/check.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_example ) then ! create NAME/example or stop call mkdir ( join_path ( settings % name , 'example' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[[example]] ' ,& & ' ' ,& & ' # Example applications for a project are defined here. ' ,& & ' # These are run via \"fpm run --example NAME\" and like the ' ,& & ' # test applications, are not built when this package is used as a ' ,& & ' # dependency by other packages. ' ,& & ' ' ,& & 'name=\"demo\" ' ,& & 'source-dir=\"example\" ' ,& & 'main=\"demo.f90\" ' ,& & ' ' ,& & ' # ' ,& & ' # you may add additional programs to the example table. The following ' ,& & ' # example contains a sample of all accepted options ' ,& & ' ' ,& & '#[[ example ]] ' ,& & '#name = \"example-tool\" ' ,& & '#source-dir=\"example\" ' ,& & '#main=\"tool.f90\" ' ,& & '#link = \"z\" ' ,& & '#[example.dependencies] ' ,& & '#M_kracken95 = { git = \"https://github.com/urbanjost/M_kracken95.git\" } ' ,& & '#datetime = {git = \"https://github.com/wavebitscientific/datetime-fortran.git\" }' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program demo' , & & 'implicit none' , & & '' , & & 'print *, \"Put some examples in here!\"' , & & 'end program demo' ] ! create NAME/example/demo.f90 call warnwrite ( join_path ( settings % name , 'example/demo.f90' ), littlefile ) endif ! now that built it write NAME/fpm.toml if ( allocated ( tomlfile ) ) then call validate_toml_data ( tomlfile ) call warnwrite ( join_path ( settings % name , 'fpm.toml' ), tomlfile ) else call create_verified_basic_manifest ( join_path ( settings % name , 'fpm.toml' )) endif ! assumes git(1) is installed and in path if ( which ( 'git' ) /= '' ) then call run ( 'git init ' // settings % name ) endif contains function git_metadata ( what ) result ( returned ) !> get metadata values such as email address and git name from git(1) or return appropriate default use fpm_filesystem , only : get_temp_filename , getline character ( len =* ), intent ( in ) :: what ! keyword designating what git metatdata to query character ( len = :), allocatable :: returned ! value to return for requested keyword character ( len = :), allocatable :: command character ( len = :), allocatable :: temp_filename character ( len = :), allocatable :: iomsg character ( len = :), allocatable :: temp_value integer :: stat , unit temp_filename = get_temp_filename () ! for known keywords set default value for RETURNED and associated git(1) command for query select case ( what ) case ( 'uname' ) returned = \"Jane Doe\" command = \"git config --get user.name > \" // temp_filename case ( 'email' ) returned = \"jane.doe@example.com\" command = \"git config --get user.email > \" // temp_filename case default write ( stderr , '(*(g0,1x))' )& & ' *git_metadata* unknown metadata name ' , trim ( what ) returned = '' return end select ! Execute command if git(1) is in command path if ( which ( 'git' ) /= '' ) then call run ( command , exitstat = stat ) if ( stat /= 0 ) then ! If command failed just return default return else ! Command did not return an error so try to read expected output file open ( file = temp_filename , newunit = unit , iostat = stat ) if ( stat == 0 ) then ! Read file into a scratch variable until status of doing so is checked call getline ( unit , temp_value , stat , iomsg ) if ( stat == 0 . and . temp_value /= '' ) then ! Return output from successful command returned = temp_value endif endif ! Always do the CLOSE because a failed open has unpredictable results. ! Add IOSTAT so a failed close does not cause program to stop close ( unit , status = \"delete\" , iostat = stat ) endif endif end function git_metadata subroutine create_verified_basic_manifest ( filename ) !> create a basic but verified default manifest file use fpm_toml , only : toml_table , toml_serialize , set_value use fpm_manifest_package , only : package_config_t , new_package use fpm_error , only : error_t implicit none character ( len =* ), intent ( in ) :: filename type ( toml_table ) :: table type ( package_config_t ) :: package type ( error_t ), allocatable :: error integer :: lun character ( len = 8 ) :: date character (:), allocatable :: output if ( exists ( filename )) then write ( stderr , '(*(g0,1x))' ) ' ' , filename ,& & 'already exists. Not overwriting' return endif !> get date to put into metadata in manifest file \"fpm.toml\" call date_and_time ( DATE = date ) table = toml_table () call fileopen ( filename , lun ) ! fileopen stops on error call set_value ( table , \"name\" , BNAME ) call set_value ( table , \"version\" , \"0.1.0\" ) call set_value ( table , \"license\" , \"license\" ) call set_value ( table , \"author\" , git_metadata ( 'uname' )) call set_value ( table , \"maintainer\" , git_metadata ( 'email' )) call set_value ( table , \"copyright\" , 'Copyright ' // date ( 1 : 4 ) // ', ' // git_metadata ( 'uname' )) ! continue building of manifest ! ... call new_package ( package , table , error = error ) if ( allocated ( error )) call fpm_stop ( 3 , '' ) output = toml_serialize ( table ) if ( settings % verbose ) then print '(a)' , output endif write ( lun , '(a)' ) output call fileclose ( lun ) ! fileopen stops on error end subroutine create_verified_basic_manifest subroutine validate_toml_data ( input ) !> verify a string array is a valid fpm.toml file ! use tomlf , only : toml_load use fpm_toml , only : toml_table , toml_serialize implicit none character ( kind = tfc , len = :), intent ( in ), allocatable :: input (:) character ( len = 1 ), parameter :: nl = new_line ( 'a' ) type ( toml_table ), allocatable :: table character ( kind = tfc , len = :), allocatable :: joined_string ! you have to add a newline character by using the intrinsic ! function `new_line(\"a\")` to get the lines processed correctly. joined_string = join ( input , right = nl ) if ( allocated ( table )) deallocate ( table ) call toml_load ( table , joined_string ) if ( allocated ( table )) then if ( settings % verbose ) then ! If the TOML file is successfully parsed the table will be allocated and ! can be written by `toml_serialize` to the standard output print '(a)' , toml_serialize ( table ) endif call table % destroy endif end subroutine validate_toml_data end subroutine cmd_new","tags":"","loc":"proc/cmd_new.html"},{"title":"cmd_publish – Fortran-lang/fpm","text":"public subroutine cmd_publish(settings) The publish command first builds the root package to obtain all the relevant information such as the\npackage version. It then creates a tarball of the package and uploads it to the registry.\nChecks before uploading the package. Arguments Type Intent Optional Attributes Name type( fpm_publish_settings ), intent(inout) :: settings Contents","tags":"","loc":"proc/cmd_publish.html"},{"title":"new_install_config – Fortran-lang/fpm","text":"public subroutine new_install_config(self, table, error) Create a new installation configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( install_config_t ), intent(out) :: self Instance of the install configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_install_config Source Code subroutine new_install_config ( self , table , error ) !> Instance of the install configuration type ( install_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"library\" , self % library , . false .) end subroutine new_install_config","tags":"","loc":"proc/new_install_config.html"},{"title":"new_example – Fortran-lang/fpm","text":"public subroutine new_example(self, table, error) Construct a new example configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the example configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_example Source Code subroutine new_example ( self , table , error ) !> Instance of the example configuration type ( example_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve example name\" ) return end if if ( bad_name_error ( error , 'example' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"example\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_example","tags":"","loc":"proc/new_example.html"},{"title":"new_test – Fortran-lang/fpm","text":"public subroutine new_test(self, table, error) Construct a new test configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the test configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_test Source Code subroutine new_test ( self , table , error ) !> Instance of the test configuration type ( test_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve test name\" ) return end if if ( bad_name_error ( error , 'test' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"test\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_test","tags":"","loc":"proc/new_test.html"},{"title":"new_fortran_config – Fortran-lang/fpm","text":"public subroutine new_fortran_config(self, table, error) Construct a new build configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( fortran_config_t ), intent(out) :: self Instance of the fortran configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_fortran_config Source Code subroutine new_fortran_config ( self , table , error ) !> Instance of the fortran configuration type ( fortran_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character (:), allocatable :: source_form call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"implicit-typing\" , self % implicit_typing , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-typing' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"implicit-external\" , self % implicit_external , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-external' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"source-form\" , source_form , \"free\" , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'source-form' in fpm.toml, expecting logical\" ) return end if select case ( source_form ) case default call fatal_error ( error , \"Value of source-form cannot be '\" // source_form // \"'\" ) return case ( \"free\" , \"fixed\" , \"default\" ) self % source_form = source_form end select end subroutine new_fortran_config","tags":"","loc":"proc/new_fortran_config.html"},{"title":"manifest_has_changed – Fortran-lang/fpm","text":"public function manifest_has_changed(cached, manifest, verbosity, iunit) result(has_changed) Check if two dependency configurations are different Perform all checks\nAll checks passed! The two instances are equal Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: cached Two instances of the dependency configuration class( dependency_config_t ), intent(in) :: manifest Two instances of the dependency configuration integer, intent(in) :: verbosity Log verbosity integer, intent(in) :: iunit Log verbosity Return Value logical Contents Source Code manifest_has_changed Source Code logical function manifest_has_changed ( cached , manifest , verbosity , iunit ) result ( has_changed ) !> Two instances of the dependency configuration class ( dependency_config_t ), intent ( in ) :: cached , manifest !> Log verbosity integer , intent ( in ) :: verbosity , iunit has_changed = . true . !> Perform all checks if ( allocated ( cached % git ). neqv . allocated ( manifest % git )) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT presence has changed. \" return endif if ( allocated ( cached % git )) then if (. not . git_matches_manifest ( cached % git , manifest % git , verbosity , iunit )) return end if !> All checks passed! The two instances are equal has_changed = . false . end function manifest_has_changed","tags":"","loc":"proc/manifest_has_changed.html"},{"title":"new_dependencies – Fortran-lang/fpm","text":"public subroutine new_dependencies(deps, table, root, meta, error) Construct new dependency array from a TOML data structure Flag dependencies that should be treated as metapackages\nParse all meta- and non-metapackage dependencies Neither a standard dep nor a metapackage\nValid meta dependency Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out), allocatable :: deps (:) Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( metapackage_config_t ), intent(out), optional :: meta (optional) metapackages type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_dependencies Source Code subroutine new_dependencies ( deps , table , root , meta , error ) !> Instance of the dependency configuration type ( dependency_config_t ), allocatable , intent ( out ) :: deps (:) !> (optional) metapackages type ( metapackage_config_t ), optional , intent ( out ) :: meta !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) type ( dependency_config_t ), allocatable :: all_deps (:) type ( metapackage_request_t ) :: meta_request logical , allocatable :: is_meta (:) logical :: metapackages_allowed integer :: idep , stat , ndep call table % get_keys ( list ) ! An empty table is okay if ( size ( list ) < 1 ) return !> Flag dependencies that should be treated as metapackages metapackages_allowed = present ( meta ) allocate ( is_meta ( size ( list )), source = . false .) allocate ( all_deps ( size ( list ))) !> Parse all meta- and non-metapackage dependencies do idep = 1 , size ( list ) ! Check if this is a standard dependency node call get_value ( table , list ( idep )% key , node , stat = stat ) is_standard_dependency : if ( stat /= toml_stat % success ) then ! See if it can be a valid metapackage name call new_meta_request ( meta_request , list ( idep )% key , table , error = error ) !> Neither a standard dep nor a metapackage if ( allocated ( error )) then call syntax_error ( error , \"Dependency \" // list ( idep )% key // \" is not a valid metapackage or a table entry\" ) return endif !> Valid meta dependency is_meta ( idep ) = . true . else ! Parse as a standard dependency is_meta ( idep ) = . false . call new_dependency ( all_deps ( idep ), node , root , error ) if ( allocated ( error )) return end if is_standard_dependency end do ! Non-meta dependencies ndep = count (. not . is_meta ) ! Finalize standard dependencies allocate ( deps ( ndep )) ndep = 0 do idep = 1 , size ( list ) if ( is_meta ( idep )) cycle ndep = ndep + 1 deps ( ndep ) = all_deps ( idep ) end do ! Finalize meta dependencies if ( metapackages_allowed ) call new_meta_config ( meta , table , is_meta , error ) end subroutine new_dependencies","tags":"","loc":"proc/new_dependencies.html"},{"title":"new_dependency – Fortran-lang/fpm","text":"public subroutine new_dependency(self, table, root, error) Construct a new dependency configuration from a TOML data structure Get optional preprocessor directives Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out) :: self Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_dependency Source Code subroutine new_dependency ( self , table , root , error ) !> Instance of the dependency configuration type ( dependency_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: uri , value , requested_version type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_value ( table , \"namespace\" , self % namespace ) call get_value ( table , \"v\" , requested_version ) if ( allocated ( requested_version )) then if (. not . allocated ( self % requested_version )) allocate ( self % requested_version ) call new_version ( self % requested_version , requested_version , error ) if ( allocated ( error )) return end if !> Get optional preprocessor directives call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return endif call get_value ( table , \"path\" , uri ) if ( allocated ( uri )) then if ( get_os_type () == OS_WINDOWS ) uri = windows_path ( uri ) if ( present ( root )) uri = join_path ( root , uri ) ! Relative to the fpm.toml it’s written in call move_alloc ( uri , self % path ) return end if call get_value ( table , \"git\" , uri ) if ( allocated ( uri )) then call get_value ( table , \"tag\" , value ) if ( allocated ( value )) then self % git = git_target_tag ( uri , value ) end if if (. not . allocated ( self % git )) then call get_value ( table , \"branch\" , value ) if ( allocated ( value )) then self % git = git_target_branch ( uri , value ) end if end if if (. not . allocated ( self % git )) then call get_value ( table , \"rev\" , value ) if ( allocated ( value )) then self % git = git_target_revision ( uri , value ) end if end if if (. not . allocated ( self % git )) then self % git = git_target_default ( uri ) end if return end if end subroutine new_dependency","tags":"","loc":"proc/new_dependency.html"},{"title":"new_package – Fortran-lang/fpm","text":"public subroutine new_package(self, table, root, error) Construct a new package configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: self Instance of the package configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_package Source Code subroutine new_package ( self , table , root , error ) !> Instance of the package configuration type ( package_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( len =* ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error ! Backspace (8), tabulator (9), newline (10), formfeed (12) and carriage ! return (13) are invalid in package names character ( len =* ), parameter :: invalid_chars = & achar ( 8 ) // achar ( 9 ) // achar ( 10 ) // achar ( 12 ) // achar ( 13 ) type ( toml_table ), pointer :: child , node type ( toml_array ), pointer :: children character ( len = :), allocatable :: version , version_file integer :: ii , nn , stat , io call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve package name\" ) return end if if ( bad_name_error ( error , 'package' , self % name )) then return endif call get_value ( table , \"license\" , self % license ) if ( len ( self % name ) <= 0 ) then call syntax_error ( error , \"Package name must be a non-empty string\" ) return end if ii = scan ( self % name , invalid_chars ) if ( ii > 0 ) then call syntax_error ( error , \"Package name contains invalid characters\" ) return end if call get_value ( table , \"build\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for build entry, must be a table\" ) return end if call new_build_config ( self % build , child , self % name , error ) if ( allocated ( error )) return call get_value ( table , \"install\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for install entry, must be a table\" ) return end if call new_install_config ( self % install , child , error ) if ( allocated ( error )) return call get_value ( table , \"fortran\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for fortran entry, must be a table\" ) return end if call new_fortran_config ( self % fortran , child , error ) if ( allocated ( error )) return call get_value ( table , \"version\" , version , \"0\" ) call new_version ( self % version , version , error ) if ( allocated ( error ) . and . present ( root )) then version_file = join_path ( root , version ) if ( exists ( version_file )) then deallocate ( error ) open ( file = version_file , newunit = io , iostat = stat ) if ( stat == 0 ) then call getline ( io , version , iostat = stat ) end if if ( stat == 0 ) then close ( io , iostat = stat ) end if if ( stat == 0 ) then call new_version ( self % version , version , error ) else call fatal_error ( error , \"Reading version number from file '\" & & // version_file // \"' failed\" ) end if end if end if if ( allocated ( error )) return call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , root , self % meta , error ) if ( allocated ( error )) return end if call get_value ( table , \"dev-dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dev_dependency , child , root , error = error ) if ( allocated ( error )) return end if call get_value ( table , \"library\" , child , requested = . false .) if ( associated ( child )) then allocate ( self % library ) call new_library ( self % library , child , error ) if ( allocated ( error )) return end if call get_value ( table , \"profiles\" , child , requested = . false .) if ( associated ( child )) then call new_profiles ( self % profiles , child , error ) if ( allocated ( error )) return else self % profiles = get_default_profiles ( error ) if ( allocated ( error )) return end if call get_value ( table , \"executable\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % executable ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve executable from array entry\" ) exit end if call new_executable ( self % executable ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % executable , error ) if ( allocated ( error )) return end if call get_value ( table , \"example\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % example ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve example from array entry\" ) exit end if call new_example ( self % example ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % example , error ) if ( allocated ( error )) return if ( allocated ( self % executable )) then call unique_programs ( self % executable , self % example , error ) if ( allocated ( error )) return end if end if call get_value ( table , \"test\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % test ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve test from array entry\" ) exit end if call new_test ( self % test ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % test , error ) if ( allocated ( error )) return end if call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return end if end subroutine new_package","tags":"","loc":"proc/new_package.html"},{"title":"new_executable – Fortran-lang/fpm","text":"public subroutine new_executable(self, table, error) Construct a new executable configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_executable Source Code subroutine new_executable ( self , table , error ) !> Instance of the executable configuration type ( executable_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve executable name\" ) return end if if ( bad_name_error ( error , 'executable' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"app\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_executable","tags":"","loc":"proc/new_executable.html"},{"title":"is_meta_package – Fortran-lang/fpm","text":"public function is_meta_package(key) Check local schema for allowed entries Supported metapackages Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: key Instance of the TOML data structure Return Value logical Contents Source Code is_meta_package Source Code logical function is_meta_package ( key ) !> Instance of the TOML data structure character ( * ), intent ( in ) :: key select case ( key ) !> Supported metapackages case ( \"openmp\" , \"stdlib\" , \"mpi\" , \"minpack\" ) is_meta_package = . true . case default is_meta_package = . false . end select end function is_meta_package","tags":"","loc":"proc/is_meta_package.html"},{"title":"new_meta_config – Fortran-lang/fpm","text":"public subroutine new_meta_config(self, table, meta_allowed, error) Construct a new build configuration from a TOML data structure The toml table is not checked here because it already passed\nthe “new_dependencies” check Arguments Type Intent Optional Attributes Name type( metapackage_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in) :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_meta_config Source Code subroutine new_meta_config ( self , table , meta_allowed , error ) !> Instance of the build configuration type ( metapackage_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ) :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call new_meta_request ( self % openmp , \"openmp\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % stdlib , \"stdlib\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % minpack , \"minpack\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % mpi , \"mpi\" , table , meta_allowed , error ) if ( allocated ( error )) return end subroutine new_meta_config","tags":"","loc":"proc/new_meta_config.html"},{"title":"new_meta_request – Fortran-lang/fpm","text":"public subroutine new_meta_request(self, key, table, meta_allowed, error) Construct a new metapackage request from the dependencies table Set name\nThe toml table is not checked here because it already passed\nthe “new_dependencies” check Set list of entries that are allowed to be metapackages Arguments Type Intent Optional Attributes Name type( metapackage_request_t ), intent(out) :: self character(len=*), intent(in) :: key The package name type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in), optional :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_meta_request Source Code subroutine new_meta_request ( self , key , table , meta_allowed , error ) type ( metapackage_request_t ), intent ( out ) :: self !> The package name character ( len =* ), intent ( in ) :: key !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ), optional :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: value logical , allocatable :: allow_meta (:) type ( toml_key ), allocatable :: keys (:) call request_destroy ( self ) !> Set name self % name = key if (. not . is_meta_package ( key )) then call fatal_error ( error , \"Error reading fpm.toml: <\" // key // \"> is not a valid metapackage name\" ) return end if !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call table % get_keys ( keys ) !> Set list of entries that are allowed to be metapackages if ( present ( meta_allowed )) then if ( size ( meta_allowed ) /= size ( keys )) then call fatal_error ( error , \"Internal error: list of metapackage-enable entries does not match table size\" ) return end if allow_meta = meta_allowed else allocate ( allow_meta ( size ( keys )), source = . true .) endif do i = 1 , size ( keys ) ! Skip standard dependencies if (. not . allow_meta ( i )) cycle if ( keys ( i )% key == key ) then call get_value ( table , key , value ) if (. not . allocated ( value )) then call syntax_error ( error , \"Could not retrieve version string for metapackage key <\" // key // \">. Check syntax\" ) return else call request_parse ( self , value , error ) return endif end if end do ! Key is not present, metapackage not requested return end subroutine new_meta_request","tags":"","loc":"proc/new_meta_request.html"},{"title":"new_library – Fortran-lang/fpm","text":"public subroutine new_library(self, table, error) Construct a new library configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_library Source Code subroutine new_library ( self , table , error ) !> Instance of the library configuration type ( library_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"source-dir\" , self % source_dir , \"src\" ) call get_value ( table , \"build-script\" , self % build_script ) call get_list ( table , \"include-dir\" , self % include_dir , error ) if ( allocated ( error )) return ! Set default value of include-dir if not found in manifest if (. not . allocated ( self % include_dir )) then self % include_dir = [ string_t ( \"include\" )] end if end subroutine new_library","tags":"","loc":"proc/new_library.html"},{"title":"get_default_profiles – Fortran-lang/fpm","text":"public function get_default_profiles(error) result(default_profiles) Construct an array of built-in profiles Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Error handling Return Value type( profile_config_t ), allocatable, (:) Contents Source Code get_default_profiles Source Code function get_default_profiles ( error ) result ( default_profiles ) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( profile_config_t ), allocatable :: default_profiles (:) default_profiles = [ & & new_profile ( 'release' , & & 'caf' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'gfortran' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'f95' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -ffast-math -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Mbackslash' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_ALL , & & flags = ' -fp-model precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl -standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_ALL , & & flags = ' -fp-model=precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl -standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nagfor' , & & OS_ALL , & & flags = ' -O4 -coarray=single -PIC' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'lfortran' , & & OS_ALL , & & flags = ' flag_lfortran_opt' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'caf' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'gfortran' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'f95' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -Wno-maybe-uninitialized -Wno-uninitialized -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Minform=inform -Mbackslash -g -Mbounds -Mchkptr -Mchkstk -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -standard-semantics -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1& & /Od /Z7 /assume:byterecl /standard-semantics /traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -standard-semantics -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'lfortran' , & & OS_ALL , & & flags = '' , & & is_built_in = . true .) & &] end function get_default_profiles","tags":"","loc":"proc/get_default_profiles.html"},{"title":"info_profile – Fortran-lang/fpm","text":"public function info_profile(profile) result(s) Print a representation of profile_config_t Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in) :: profile Profile to be represented Return Value character(len=:), allocatable String representation of given profile Contents Variables i Source Code info_profile Variables Type Visibility Attributes Name Initial integer, public :: i Source Code function info_profile ( profile ) result ( s ) !> Profile to be represented type ( profile_config_t ), intent ( in ) :: profile !> String representation of given profile character (:), allocatable :: s integer :: i s = \"profile_config_t(\" s = s // 'profile_name=\"' // profile % profile_name // '\"' s = s // ', compiler=\"' // profile % compiler // '\"' s = s // \", os_type=\" select case ( profile % os_type ) case ( OS_UNKNOWN ) s = s // \"OS_UNKNOWN\" case ( OS_LINUX ) s = s // \"OS_LINUX\" case ( OS_MACOS ) s = s // \"OS_MACOS\" case ( OS_WINDOWS ) s = s // \"OS_WINDOWS\" case ( OS_CYGWIN ) s = s // \"OS_CYGWIN\" case ( OS_SOLARIS ) s = s // \"OS_SOLARIS\" case ( OS_FREEBSD ) s = s // \"OS_FREEBSD\" case ( OS_OPENBSD ) s = s // \"OS_OPENBSD\" case ( OS_ALL ) s = s // \"OS_ALL\" case default s = s // \"INVALID\" end select if ( allocated ( profile % flags )) s = s // ', flags=\"' // profile % flags // '\"' if ( allocated ( profile % c_flags )) s = s // ', c_flags=\"' // profile % c_flags // '\"' if ( allocated ( profile % cxx_flags )) s = s // ', cxx_flags=\"' // profile % cxx_flags // '\"' if ( allocated ( profile % link_time_flags )) s = s // ', link_time_flags=\"' // profile % link_time_flags // '\"' if ( allocated ( profile % file_scope_flags )) then do i = 1 , size ( profile % file_scope_flags ) s = s // ', flags for ' // profile % file_scope_flags ( i )% file_name // & & ' =\"' // profile % file_scope_flags ( i )% flags // '\"' end do end if s = s // \")\" end function info_profile","tags":"","loc":"proc/info_profile.html"},{"title":"new_profile – Fortran-lang/fpm","text":"public function new_profile(profile_name, compiler, os_type, flags, c_flags, cxx_flags, link_time_flags, file_scope_flags, is_built_in) result(profile) Construct a new profile configuration from a TOML data structure Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: profile_name Name of the profile character(len=*), intent(in) :: compiler Name of the compiler integer, intent(in) :: os_type Type of the OS character(len=*), intent(in), optional :: flags Fortran compiler flags character(len=*), intent(in), optional :: c_flags C compiler flags character(len=*), intent(in), optional :: cxx_flags C++ compiler flags character(len=*), intent(in), optional :: link_time_flags Link time compiler flags type( file_scope_flag ), intent(in), optional :: file_scope_flags (:) File scope flags logical, intent(in), optional :: is_built_in Is this profile one of the built-in ones? Return Value type( profile_config_t ) Contents Source Code new_profile Source Code function new_profile ( profile_name , compiler , os_type , flags , c_flags , cxx_flags , & link_time_flags , file_scope_flags , is_built_in ) & & result ( profile ) !> Name of the profile character ( len =* ), intent ( in ) :: profile_name !> Name of the compiler character ( len =* ), intent ( in ) :: compiler !> Type of the OS integer , intent ( in ) :: os_type !> Fortran compiler flags character ( len =* ), optional , intent ( in ) :: flags !> C compiler flags character ( len =* ), optional , intent ( in ) :: c_flags !> C++ compiler flags character ( len =* ), optional , intent ( in ) :: cxx_flags !> Link time compiler flags character ( len =* ), optional , intent ( in ) :: link_time_flags !> File scope flags type ( file_scope_flag ), optional , intent ( in ) :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical , optional , intent ( in ) :: is_built_in type ( profile_config_t ) :: profile profile % profile_name = profile_name profile % compiler = compiler profile % os_type = os_type if ( present ( flags )) then profile % flags = flags else profile % flags = \"\" end if if ( present ( c_flags )) then profile % c_flags = c_flags else profile % c_flags = \"\" end if if ( present ( cxx_flags )) then profile % cxx_flags = cxx_flags else profile % cxx_flags = \"\" end if if ( present ( link_time_flags )) then profile % link_time_flags = link_time_flags else profile % link_time_flags = \"\" end if if ( present ( file_scope_flags )) then profile % file_scope_flags = file_scope_flags end if if ( present ( is_built_in )) then profile % is_built_in = is_built_in else profile % is_built_in = . false . end if end function new_profile","tags":"","loc":"proc/new_profile.html"},{"title":"find_profile – Fortran-lang/fpm","text":"public subroutine find_profile(profiles, profile_name, compiler, os_type, found_matching, chosen_profile) Look for profile with given configuration in array profiles Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in), allocatable :: profiles (:) Array of profiles character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler Name of compiler integer, intent(in) :: os_type Type of operating system (enum) logical, intent(out) :: found_matching Boolean value containing true if matching profile was found type( profile_config_t ), intent(out) :: chosen_profile Last matching profile in the profiles array Contents Variables curr_compiler curr_os curr_priority curr_profile_name i priority Source Code find_profile Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: curr_compiler integer, public :: curr_os integer, public :: curr_priority character(len=:), public, allocatable :: curr_profile_name integer, public :: i integer, public :: priority Source Code subroutine find_profile ( profiles , profile_name , compiler , os_type , found_matching , chosen_profile ) !> Array of profiles type ( profile_config_t ), allocatable , intent ( in ) :: profiles (:) !> Name of profile character (:), allocatable , intent ( in ) :: profile_name !> Name of compiler character (:), allocatable , intent ( in ) :: compiler !> Type of operating system (enum) integer , intent ( in ) :: os_type !> Boolean value containing true if matching profile was found logical , intent ( out ) :: found_matching !> Last matching profile in the profiles array type ( profile_config_t ), intent ( out ) :: chosen_profile character (:), allocatable :: curr_profile_name character (:), allocatable :: curr_compiler integer :: curr_os integer :: i , priority , curr_priority found_matching = . false . if ( size ( profiles ) < 1 ) return ! Try to find profile with matching OS type do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . os_type ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do ! Try to find profile with OS type 'all' if (. not . found_matching ) then do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . OS_ALL ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do end if end subroutine find_profile","tags":"","loc":"proc/find_profile.html"},{"title":"get_flags – Fortran-lang/fpm","text":"public subroutine get_flags(profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid) Look for flags, c-flags, link-time-flags key-val pairs\nand files table in a given table and create new profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler integer, intent(in) :: os_type OS type type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles logical, intent(in) :: os_valid Was called with valid operating system Contents Variables c_flags cxx_flags err_message file_flags file_list file_name file_scope_flags files flags ifile ikey is_valid key_name link_time_flags stat Source Code get_flags Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags character(len=:), public, allocatable :: cxx_flags character(len=:), public, allocatable :: err_message character(len=:), public, allocatable :: file_flags type(toml_key), public, allocatable :: file_list (:) character(len=:), public, allocatable :: file_name type( file_scope_flag ), public, allocatable :: file_scope_flags (:) type(toml_table), public, pointer :: files character(len=:), public, allocatable :: flags integer, public :: ifile integer, public :: ikey logical, public :: is_valid character(len=:), public, allocatable :: key_name character(len=:), public, allocatable :: link_time_flags integer, public :: stat Source Code subroutine get_flags ( profile_name , compiler_name , os_type , key_list , table , profiles , profindex , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> OS type integer , intent ( in ) :: os_type !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) type ( file_scope_flag ), allocatable :: file_scope_flags (:) integer :: ikey , ifile , stat logical :: is_valid call get_value ( table , 'flags' , flags ) call get_value ( table , 'c-flags' , c_flags ) call get_value ( table , 'cxx-flags' , cxx_flags ) call get_value ( table , 'link-time-flags' , link_time_flags ) call get_value ( table , 'files' , files ) if ( associated ( files )) then call files % get_keys ( file_list ) allocate ( file_scope_flags ( size ( file_list ))) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags ) associate ( cur_file => file_scope_flags ( ifile )) if (. not .( path . eq . \"\" )) file_name = join_path ( path , file_name ) cur_file % file_name = file_name cur_file % flags = file_flags end associate end do end if profiles ( profindex ) = new_profile ( profile_name , compiler_name , os_type , & & flags , c_flags , cxx_flags , link_time_flags , file_scope_flags ) profindex = profindex + 1 end subroutine get_flags","tags":"","loc":"proc/get_flags.html"},{"title":"info – Fortran-lang/fpm","text":"public subroutine info(self, unit, verbosity) Write information on instance Type Bound profile_config_t Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: self Instance of the profile configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Contents Variables fmt pr Source Code info Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: fmt = '(\"#\", 1x, a, t30, a)' integer, public :: pr Source Code subroutine info ( self , unit , verbosity ) !> Instance of the profile configuration class ( profile_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if write ( unit , fmt ) \"Profile\" if ( allocated ( self % profile_name )) then write ( unit , fmt ) \"- profile name\" , self % profile_name end if if ( allocated ( self % compiler )) then write ( unit , fmt ) \"- compiler\" , self % compiler end if write ( unit , fmt ) \"- os\" , self % os_type if ( allocated ( self % flags )) then write ( unit , fmt ) \"- compiler flags\" , self % flags end if end subroutine info","tags":"","loc":"proc/info~10.html"},{"title":"match_os_type – Fortran-lang/fpm","text":"public subroutine match_os_type(os_name, os_type) Match os_type enum to a lowercase string with name of OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of operating system integer, intent(out) :: os_type Enum representing type of OS Contents Source Code match_os_type Source Code subroutine match_os_type ( os_name , os_type ) !> Name of operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Enum representing type of OS integer , intent ( out ) :: os_type select case ( os_name ) case ( \"linux\" ); os_type = OS_LINUX case ( \"macos\" ); os_type = OS_WINDOWS case ( \"cygwin\" ); os_type = OS_CYGWIN case ( \"solaris\" ); os_type = OS_SOLARIS case ( \"freebsd\" ); os_type = OS_FREEBSD case ( \"openbsd\" ); os_type = OS_OPENBSD case ( \"all\" ); os_type = OS_ALL case default ; os_type = OS_UNKNOWN end select end subroutine match_os_type","tags":"","loc":"proc/match_os_type.html"},{"title":"new_profiles – Fortran-lang/fpm","text":"public subroutine new_profiles(profiles, table, error) Construct new profiles array from a TOML data structure Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(out), allocatable :: profiles (:) Instance of the dependency configuration type(toml_table), intent(inout), target :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Variables comp_list compiler_name default_profiles iprof is_valid os_list prof_list prof_node profile_name profiles_size profindex stat Source Code new_profiles Variables Type Visibility Attributes Name Initial type(toml_key), public, allocatable :: comp_list (:) character(len=:), public, allocatable :: compiler_name type( profile_config_t ), public, allocatable :: default_profiles (:) integer, public :: iprof logical, public :: is_valid type(toml_key), public, allocatable :: os_list (:) type(toml_key), public, allocatable :: prof_list (:) type(toml_table), public, pointer :: prof_node character(len=:), public, allocatable :: profile_name integer, public :: profiles_size integer, public :: profindex integer, public :: stat Source Code subroutine new_profiles ( profiles , table , error ) !> Instance of the dependency configuration type ( profile_config_t ), allocatable , intent ( out ) :: profiles (:) !> Instance of the TOML data structure type ( toml_table ), target , intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: prof_node type ( toml_key ), allocatable :: prof_list (:) type ( toml_key ), allocatable :: comp_list (:) type ( toml_key ), allocatable :: os_list (:) character ( len = :), allocatable :: profile_name , compiler_name integer :: profiles_size , iprof , stat , profindex logical :: is_valid type ( profile_config_t ), allocatable :: default_profiles (:) path = '' default_profiles = get_default_profiles ( error ) if ( allocated ( error )) return call table % get_keys ( prof_list ) if ( size ( prof_list ) < 1 ) return profiles_size = 0 do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER call traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Profile \" // prof_list ( iprof )% key // \" must be a table entry\" ) exit end if call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return end if end if end do profiles_size = profiles_size + size ( default_profiles ) allocate ( profiles ( profiles_size )) do profindex = 1 , size ( default_profiles ) profiles ( profindex ) = default_profiles ( profindex ) end do do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER prof_node => table call traverse_oss ( profile_name , compiler_name , os_list , prof_node , profiles , profindex , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return end if end if end do ! Apply profiles with profile name 'all' to matching profiles do iprof = 1 , size ( profiles ) if ( profiles ( iprof )% profile_name . eq . 'all' ) then do profindex = 1 , size ( profiles ) if (. not .( profiles ( profindex )% profile_name . eq . 'all' ) & & . and .( profiles ( profindex )% compiler . eq . profiles ( iprof )% compiler ) & & . and .( profiles ( profindex )% os_type . eq . profiles ( iprof )% os_type )) then profiles ( profindex )% flags = profiles ( profindex )% flags // & & \" \" // profiles ( iprof )% flags profiles ( profindex )% c_flags = profiles ( profindex )% c_flags // & & \" \" // profiles ( iprof )% c_flags profiles ( profindex )% cxx_flags = profiles ( profindex )% cxx_flags // & & \" \" // profiles ( iprof )% cxx_flags profiles ( profindex )% link_time_flags = profiles ( profindex )% link_time_flags // & & \" \" // profiles ( iprof )% link_time_flags end if end do end if end do end subroutine new_profiles","tags":"","loc":"proc/new_profiles.html"},{"title":"traverse_compilers – Fortran-lang/fpm","text":"public subroutine traverse_compilers(profile_name, comp_list, table, error, profiles_size, profiles, profindex) Traverse compiler tables Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile type(toml_key), intent(in), allocatable :: comp_list (:) List of OSs in table with profile name given type(toml_table), intent(in), pointer :: table Table containing compiler tables type( error_t ), intent(out), allocatable :: error Error handling integer, intent(inout), optional :: profiles_size Number of profiles in list of profiles type( profile_config_t ), intent(inout), optional, allocatable :: profiles (:) List of profiles integer, intent(inout), optional :: profindex Index in the list of profiles Contents Variables comp_node compiler_name icomp is_valid os_list stat Source Code traverse_compilers Variables Type Visibility Attributes Name Initial type(toml_table), public, pointer :: comp_node character(len=:), public, allocatable :: compiler_name integer, public :: icomp logical, public :: is_valid type(toml_key), public, allocatable :: os_list (:) integer, public :: stat Source Code subroutine traverse_compilers ( profile_name , comp_list , table , error , profiles_size , profiles , profindex ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> List of OSs in table with profile name given type ( toml_key ), allocatable , intent ( in ) :: comp_list (:) !> Table containing compiler tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ), optional :: profiles_size !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ), optional :: profiles (:) !> Index in the list of profiles integer , intent ( inout ), optional :: profindex character ( len = :), allocatable :: compiler_name type ( toml_table ), pointer :: comp_node type ( toml_key ), allocatable :: os_list (:) integer :: icomp , stat logical :: is_valid if ( size ( comp_list ) < 1 ) return do icomp = 1 , size ( comp_list ) call validate_compiler_name ( comp_list ( icomp )% key , is_valid ) if ( is_valid ) then compiler_name = comp_list ( icomp )% key call get_value ( table , compiler_name , comp_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Compiler \" // comp_list ( icomp )% key // \" must be a table entry\" ) exit end if call comp_node % get_keys ( os_list ) if ( present ( profiles_size )) then call traverse_oss_for_size ( profile_name , compiler_name , os_list , comp_node , profiles_size , error ) if ( allocated ( error )) return else if (. not .( present ( profiles ). and . present ( profindex ))) then call fatal_error ( error , \"Both profiles and profindex have to be present\" ) return end if call traverse_oss ( profile_name , compiler_name , os_list , comp_node , & & profiles , profindex , error ) if ( allocated ( error )) return end if else call fatal_error ( error , '*traverse_compilers*:Error: Compiler name not specified or invalid.' ) end if end do end subroutine traverse_compilers","tags":"","loc":"proc/traverse_compilers.html"},{"title":"traverse_oss – Fortran-lang/fpm","text":"public subroutine traverse_oss(profile_name, compiler_name, os_list, table, profiles, profindex, error) Traverse operating system tables to obtain profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles type( error_t ), intent(out), allocatable :: error Error handling Contents Variables ios is_key_val is_valid key_list l_os_name os_name os_node os_type stat Source Code traverse_oss Variables Type Visibility Attributes Name Initial integer, public :: ios logical, public :: is_key_val logical, public :: is_valid type(toml_key), public, allocatable :: key_list (:) character(len=:), public, allocatable :: l_os_name character(len=:), public, allocatable :: os_name type(toml_table), public, pointer :: os_node integer, public :: os_type integer, public :: stat Source Code subroutine traverse_oss ( profile_name , compiler_name , os_list , table , profiles , profindex , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat , os_type logical :: is_valid , is_key_val if ( size ( os_list ) < 1 ) return do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) call match_os_type ( os_name , os_type ) call get_flags ( profile_name , compiler_name , os_type , key_list , os_node , profiles , profindex , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table os_type = OS_ALL call get_flags ( profile_name , compiler_name , os_type , os_list , os_node , profiles , profindex , . false .) end if end do end subroutine traverse_oss","tags":"","loc":"proc/traverse_oss.html"},{"title":"traverse_oss_for_size – Fortran-lang/fpm","text":"public subroutine traverse_oss_for_size(profile_name, compiler_name, os_list, table, profiles_size, error) Traverse operating system tables to obtain number of profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables integer, intent(inout) :: profiles_size Number of profiles in list of profiles type( error_t ), intent(out), allocatable :: error Error handling Contents Variables ios is_key_val is_valid key_list key_val_added l_os_name os_name os_node stat Source Code traverse_oss_for_size Variables Type Visibility Attributes Name Initial integer, public :: ios logical, public :: is_key_val logical, public :: is_valid type(toml_key), public, allocatable :: key_list (:) logical, public :: key_val_added character(len=:), public, allocatable :: l_os_name character(len=:), public, allocatable :: os_name type(toml_table), public, pointer :: os_node integer, public :: stat Source Code subroutine traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ) :: profiles_size type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat logical :: is_valid , key_val_added , is_key_val if ( size ( os_list ) < 1 ) return key_val_added = . false . do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) profiles_size = profiles_size + 1 call validate_profile_table ( profile_name , compiler_name , key_list , os_node , error , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table if ( is_key_val . and .. not . key_val_added ) then key_val_added = . true . is_key_val = . false . profiles_size = profiles_size + 1 else if (. not . is_key_val ) then profiles_size = profiles_size + 1 end if call validate_profile_table ( profile_name , compiler_name , os_list , os_node , error , . false .) end if end do end subroutine traverse_oss_for_size","tags":"","loc":"proc/traverse_oss_for_size.html"},{"title":"validate_compiler_name – Fortran-lang/fpm","text":"public subroutine validate_compiler_name(compiler_name, is_valid) Check if compiler name is a valid compiler name Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: compiler_name Name of a compiler logical, intent(out) :: is_valid Boolean value of whether compiler_name is valid or not Contents Source Code validate_compiler_name Source Code subroutine validate_compiler_name ( compiler_name , is_valid ) !> Name of a compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> Boolean value of whether compiler_name is valid or not logical , intent ( out ) :: is_valid select case ( compiler_name ) case ( \"gfortran\" , \"ifort\" , \"ifx\" , \"pgfortran\" , \"nvfortran\" , \"flang\" , \"caf\" , & & \"f95\" , \"lfortran\" , \"lfc\" , \"nagfor\" , \"crayftn\" , \"xlf90\" , \"ftn95\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_compiler_name","tags":"","loc":"proc/validate_compiler_name.html"},{"title":"validate_os_name – Fortran-lang/fpm","text":"public subroutine validate_os_name(os_name, is_valid) Check if os_name is a valid name of a supported OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of an operating system logical, intent(out) :: is_valid Boolean value of whether os_name is valid or not Contents Source Code validate_os_name Source Code subroutine validate_os_name ( os_name , is_valid ) !> Name of an operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Boolean value of whether os_name is valid or not logical , intent ( out ) :: is_valid select case ( os_name ) case ( \"linux\" , \"macos\" , \"windows\" , \"cygwin\" , \"solaris\" , \"freebsd\" , & & \"openbsd\" , \"unknown\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_os_name","tags":"","loc":"proc/validate_os_name.html"},{"title":"validate_profile_table – Fortran-lang/fpm","text":"public subroutine validate_profile_table(profile_name, compiler_name, key_list, table, error, os_valid) Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in) :: os_valid Was called with valid operating system Contents Variables c_flags cxx_flags err_message file_flags file_list file_name files flags ifile ikey is_valid key_name link_time_flags stat Source Code validate_profile_table Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags character(len=:), public, allocatable :: cxx_flags character(len=:), public, allocatable :: err_message character(len=:), public, allocatable :: file_flags type(toml_key), public, allocatable :: file_list (:) character(len=:), public, allocatable :: file_name type(toml_table), public, pointer :: files character(len=:), public, allocatable :: flags integer, public :: ifile integer, public :: ikey logical, public :: is_valid character(len=:), public, allocatable :: key_name character(len=:), public, allocatable :: link_time_flags integer, public :: stat Source Code subroutine validate_profile_table ( profile_name , compiler_name , key_list , table , error , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) integer :: ikey , ifile , stat logical :: is_valid if ( size ( key_list ). ge . 1 ) then do ikey = 1 , size ( key_list ) key_name = key_list ( ikey )% key if ( key_name . eq . 'flags' ) then call get_value ( table , 'flags' , flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'c-flags' ) then call get_value ( table , 'c-flags' , c_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"c-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'cxx-flags' ) then call get_value ( table , 'cxx-flags' , cxx_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"cxx-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'link-time-flags' ) then call get_value ( table , 'link-time-flags' , link_time_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"link-time-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'files' ) then call get_value ( table , 'files' , files , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"files has to be a table\" ) return end if call files % get_keys ( file_list ) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"file scope flags has to be a key-value pair\" ) return end if end do else if (. not . os_valid ) then call validate_os_name ( key_name , is_valid ) err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" if (. not . is_valid ) call syntax_error ( error , err_message ) else err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" call syntax_error ( error , err_message ) end if end do end if if ( allocated ( error )) return end subroutine validate_profile_table","tags":"","loc":"proc/validate_profile_table.html"},{"title":"new_preprocess_config – Fortran-lang/fpm","text":"public subroutine new_preprocess_config(self, table, error) Construct a new preprocess configuration from TOML data structure Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out) :: self Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure. type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_preprocess_config Source Code subroutine new_preprocess_config ( self , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), intent ( out ) :: self !> Instance of the TOML data structure. type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_list ( table , \"suffixes\" , self % suffixes , error ) if ( allocated ( error )) return call get_list ( table , \"directories\" , self % directories , error ) if ( allocated ( error )) return call get_list ( table , \"macros\" , self % macros , error ) if ( allocated ( error )) return end subroutine new_preprocess_config","tags":"","loc":"proc/new_preprocess_config.html"},{"title":"new_preprocessors – Fortran-lang/fpm","text":"public subroutine new_preprocessors(preprocessors, table, error) Construct new preprocess array from a TOML data structure. Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out), allocatable :: preprocessors (:) Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_preprocessors Source Code subroutine new_preprocessors ( preprocessors , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), allocatable , intent ( out ) :: preprocessors (:) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) integer :: iprep , stat call table % get_keys ( list ) ! An empty table is not allowed if ( size ( list ) == 0 ) then call syntax_error ( error , \"No preprocessors defined\" ) end if allocate ( preprocessors ( size ( list ))) do iprep = 1 , size ( list ) call get_value ( table , list ( iprep )% key , node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Preprocessor \" // list ( iprep )% key // \" must be a table entry\" ) exit end if call new_preprocess_config ( preprocessors ( iprep ), node , error ) if ( allocated ( error )) exit end do end subroutine new_preprocessors","tags":"","loc":"proc/new_preprocessors.html"},{"title":"operator(==) – Fortran-lang/fpm","text":"public interface operator(==) Contents Module Procedures preprocess_is_same Module Procedures private function preprocess_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: this class( preprocess_config_t ), intent(in) :: that Return Value logical","tags":"","loc":"interface/operator(==)~2.html"},{"title":"new_build_config – Fortran-lang/fpm","text":"public subroutine new_build_config(self, table, package_name, error) Construct a new build configuration from a TOML data structure Module naming: fist, attempt boolean value first Value found, but not a boolean. Attempt to read a prefix string Arguments Type Intent Optional Attributes Name type( build_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: package_name Package name type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_build_config Source Code subroutine new_build_config ( self , table , package_name , error ) !> Instance of the build configuration type ( build_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Package name character ( len =* ), intent ( in ) :: package_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call check ( table , package_name , error ) if ( allocated ( error )) return call get_value ( table , \"auto-executables\" , self % auto_executables , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-executables' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-tests\" , self % auto_tests , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-tests' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-examples\" , self % auto_examples , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-examples' in fpm.toml, expecting logical\" ) return end if !> Module naming: fist, attempt boolean value first call get_value ( table , \"module-naming\" , self % module_naming , . false ., stat = stat ) if ( stat == toml_stat % success ) then ! Boolean value found. Set no custom prefix. This also falls back to ! key not provided self % module_prefix = string_t ( \"\" ) else !> Value found, but not a boolean. Attempt to read a prefix string call get_value ( table , \"module-naming\" , self % module_prefix % s ) if (. not . allocated ( self % module_prefix % s )) then call syntax_error ( error , \"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string\" ) return end if if (. not . is_valid_module_prefix ( self % module_prefix )) then call syntax_error ( error , \"Invalid custom module name prefix for in fpm.toml: <\" // self % module_prefix % s // & \">, expecting a valid alphanumeric string\" ) return end if ! Set module naming to ON self % module_naming = . true . end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return call get_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return end subroutine new_build_config","tags":"","loc":"proc/new_build_config.html"},{"title":"has_manifest – Fortran-lang/fpm","text":"function has_manifest(dir) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical Contents Source Code has_manifest Source Code function has_manifest ( dir ) character ( len =* ), intent ( in ) :: dir logical :: has_manifest has_manifest = exists ( join_path ( dir , \"fpm.toml\" )) end function has_manifest","tags":"","loc":"proc/has_manifest.html"},{"title":"get_working_dir – Fortran-lang/fpm","text":"subroutine get_working_dir(settings, working_dir_) Save access to working directory in settings, in case setting have not been allocated Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(in), optional :: settings character(len=:), intent(out), allocatable :: working_dir_ Contents Source Code get_working_dir Source Code subroutine get_working_dir ( settings , working_dir_ ) class ( fpm_cmd_settings ), optional , intent ( in ) :: settings character ( len = :), allocatable , intent ( out ) :: working_dir_ if ( present ( settings )) then working_dir_ = settings % working_dir end if end subroutine get_working_dir","tags":"","loc":"proc/get_working_dir.html"},{"title":"handle_error – Fortran-lang/fpm","text":"subroutine handle_error(error_) Arguments Type Intent Optional Attributes Name type( error_t ), intent(in), optional :: error_ Contents Source Code handle_error Source Code subroutine handle_error ( error_ ) type ( error_t ), optional , intent ( in ) :: error_ if ( present ( error_ )) then write ( error_unit , '(\"[Error]\", 1x, a)' ) error_ % message stop 1 end if end subroutine handle_error","tags":"","loc":"proc/handle_error~2.html"},{"title":"fpm_settings – Fortran-lang/fpm","text":"Manages global settings which are defined in the global config file. Uses fpm_error fpm_toml fpm_environment fpm_filesystem fpm_os Contents Variables official_registry_base_url Derived Types fpm_global_settings Subroutines get_global_settings get_registry_settings Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: official_registry_base_url = 'https://registry-apis.vercel.app' Derived Types type, public :: fpm_global_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: config_file_name Name of the global config file. The default is config.toml . character(len=:), public, allocatable :: path_to_config_folder Path to the global config file excluding the file name. type(fpm_registry_settings), public, allocatable :: registry_settings Registry configs. Type-Bound Procedures procedure\n , public\n, :: full_path Function procedure\n , public\n, :: has_custom_location Function procedure\n , public\n, :: path_to_config_folder_or_empty Function Subroutines public subroutine get_global_settings (global_settings, error) Obtain global settings from the global config file. Arguments Type Intent Optional Attributes Name type( fpm_global_settings ), intent(inout) :: global_settings Global settings to be obtained. type( error_t ), intent(out), allocatable :: error Error reading config file. public subroutine get_registry_settings (table, global_settings, error) Read registry settings from the global config file. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout), target :: table The [registry] subtable from the global config file. type( fpm_global_settings ), intent(inout) :: global_settings The global settings which can be filled with the registry settings. type( error_t ), intent(out), allocatable :: error Error handling.","tags":"","loc":"module/fpm_settings.html"},{"title":"fpm_model – Fortran-lang/fpm","text":"The fpm package model Defines the fpm model data types which encapsulate all information\n required to correctly build a package and its dependencies. The process (see build_model ) for generating a valid fpm_model involves\n source files discovery ( fpm_sources ) and parsing ( fpm_source_parsing ). Once a valid fpm_model has been constructed, it may be passed to targets_from_sources to\n generate a list of build targets for the backend. Enumerations Source type: FPM_UNIT_* Describes the type of source file — determines build target generation The logical order of precedence for assigning unit_type is as follows: if source - file contains program then unit_type = FPM_UNIT_PROGRAM else if source - file contains non - module subroutine / function then unit_type = FPM_UNIT_SUBPROGRAM else if source - file contains submodule then unit_type = FPM_UNIT_SUBMODULE else if source - file contains module then unit_type = FPM_UNIT_MODULE end if Note A source file is only designated FPM_UNIT_MODULE if it only contains modules - no non-module subprograms.\n (This allows tree-shaking/pruning of build targets based on unused module dependencies.) Source scope: FPM_SCOPE_* Describes the scoping rules for using modules — controls module dependency resolution Uses fpm_compiler fpm_dependency fpm_strings iso_fortran_env Contents Variables FPM_SCOPE_APP FPM_SCOPE_DEP FPM_SCOPE_EXAMPLE FPM_SCOPE_LIB FPM_SCOPE_TEST FPM_SCOPE_UNKNOWN FPM_UNIT_CHEADER FPM_UNIT_CPPSOURCE FPM_UNIT_CSOURCE FPM_UNIT_MODULE FPM_UNIT_PROGRAM FPM_UNIT_SUBMODULE FPM_UNIT_SUBPROGRAM FPM_UNIT_UNKNOWN Derived Types fortran_features_t fpm_model_t srcfile_t Subroutines show_model Variables Type Visibility Attributes Name Initial integer, public, parameter :: FPM_SCOPE_APP = 3 Module-use scope is library/dependency and app modules integer, public, parameter :: FPM_SCOPE_DEP = 2 Module-use scope is library/dependency modules only integer, public, parameter :: FPM_SCOPE_EXAMPLE = 5 integer, public, parameter :: FPM_SCOPE_LIB = 1 Module-use scope is library/dependency modules only integer, public, parameter :: FPM_SCOPE_TEST = 4 Module-use scope is library/dependency and test modules integer, public, parameter :: FPM_SCOPE_UNKNOWN = -1 Source has no module-use scope integer, public, parameter :: FPM_UNIT_CHEADER = 6 Source type is c header file integer, public, parameter :: FPM_UNIT_CPPSOURCE = 7 Souce type is c++ source file. integer, public, parameter :: FPM_UNIT_CSOURCE = 5 Source type is c source file integer, public, parameter :: FPM_UNIT_MODULE = 2 Source only contains one or more fortran modules integer, public, parameter :: FPM_UNIT_PROGRAM = 1 Source contains a fortran program integer, public, parameter :: FPM_UNIT_SUBMODULE = 3 Source contains one or more fortran submodules integer, public, parameter :: FPM_UNIT_SUBPROGRAM = 4 Source contains one or more fortran subprogram not within modules integer, public, parameter :: FPM_UNIT_UNKNOWN = -1 Source type unknown Derived Types type, public :: fortran_features_t Enabled Fortran language features Components Type Visibility Attributes Name Initial logical, public :: implicit_external = .false. Use implicit external interface logical, public :: implicit_typing = .false. Use default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources type, public :: fpm_model_t Type describing everything required to build\n the root package and its dependencies. Components Type Visibility Attributes Name Initial type( archiver_t ), public :: archiver Archiver object character(len=:), public, allocatable :: build_prefix Base directory for build character(len=:), public, allocatable :: c_compile_flags Command line flags passed to C for compilation type( compiler_t ), public :: compiler Compiler object character(len=:), public, allocatable :: cxx_compile_flags Command line flags passed to C++ for compilation type( dependency_tree_t ), public :: deps Project dependencies logical, public :: enforce_module_names = .false. Whether module names should be prefixed with the package name type( string_t ), public, allocatable :: external_modules (:) External modules used character(len=:), public, allocatable :: fortran_compile_flags Command line flags passed to fortran for compilation type( string_t ), public, allocatable :: include_dirs (:) Include directories logical, public :: include_tests = .true. Whether tests should be added to the build list character(len=:), public, allocatable :: link_flags Command line flags passed to the linker type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public :: module_prefix Prefix for all module names character(len=:), public, allocatable :: package_name Name of root package type(package_t), public, allocatable :: packages (:) Array of packages (including the root package) type, public :: srcfile_t Type for describing a source file Components Type Visibility Attributes Name Initial integer(kind=int64), public :: digest Current hash character(len=:), public, allocatable :: exe_name Name of executable for FPM_UNIT_PROGRAM character(len=:), public, allocatable :: file_name File path relative to cwd type( string_t ), public, allocatable :: include_dependencies (:) Files INCLUDEd by this source file type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: modules_provided (:) Modules provided by this source file (lowerstring) type( string_t ), public, allocatable :: modules_used (:) Modules USEd by this source file (lowerstring) type( string_t ), public, allocatable :: parent_modules (:) Parent modules (submodules only) integer, public :: unit_scope = FPM_SCOPE_UNKNOWN Target module-use scope integer, public :: unit_type = FPM_UNIT_UNKNOWN Type of source unit Subroutines public subroutine show_model (model) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model","tags":"","loc":"module/fpm_model.html"},{"title":"fpm_backend_console – Fortran-lang/fpm","text":"Build Backend Console This module provides a lightweight implementation for printing to the console\n and updating previously-printed console lines. It used by fpm_backend_output for pretty-printing build status and progress. Note The implementation for updating previous lines relies on no other output\n going to stdout / stderr except through the console_t object provided. Note All write statements to stdout are enclosed within OpenMP critical regions Uses iso_fortran_env Contents Variables COLOR_GREEN COLOR_RED COLOR_RESET COLOR_YELLOW LINE_RESET Derived Types console_t Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: COLOR_GREEN = ESC//\"[32m\" Escape code for green foreground color character(len=*), public, parameter :: COLOR_RED = ESC//\"[31m\" Escape code for red foreground color character(len=*), public, parameter :: COLOR_RESET = ESC//\"[0m\" Escape code to reset foreground color character(len=*), public, parameter :: COLOR_YELLOW = ESC//\"[93m\" Escape code for yellow foreground color character(len=*), public, parameter :: LINE_RESET = ESC//\"[2K\"//ESC//\"[1G\" Escape code for erasing current line Derived Types type, public :: console_t Console object Components Type Visibility Attributes Name Initial integer, public :: n_line = 1 Number of lines printed Type-Bound Procedures procedure\n , public\n, :: update_line =>\n console_update_line Subroutine Update a previously-written console line procedure\n , public\n, :: write_line =>\n console_write_line Subroutine Write a single line to the console","tags":"","loc":"module/fpm_backend_console.html"},{"title":"fpm_compiler – Fortran-lang/fpm","text":"Define compiler command options This module defines compiler options to use for the debug and release builds. Uses fpm_error iso_fortran_env fpm_environment fpm_filesystem fpm_strings Contents Variables compiler_enum flag_cray_fixed_form flag_cray_free_form flag_cray_implicit_typing flag_cray_no_implicit_typing flag_gnu_backtrace flag_gnu_check flag_gnu_coarray flag_gnu_debug flag_gnu_external flag_gnu_fixed_form flag_gnu_free_form flag_gnu_limit flag_gnu_no_implicit_external flag_gnu_no_implicit_typing flag_gnu_openmp flag_gnu_opt flag_gnu_pic flag_gnu_warn flag_ibmxl_backslash flag_intel_align flag_intel_align_win flag_intel_backtrace flag_intel_backtrace_win flag_intel_byterecl flag_intel_byterecl_win flag_intel_check flag_intel_check_win flag_intel_debug flag_intel_debug_win flag_intel_fixed_form flag_intel_fixed_form_win flag_intel_fp flag_intel_fp_win flag_intel_free_form flag_intel_free_form_win flag_intel_limit flag_intel_limit_win flag_intel_nogen flag_intel_nogen_win flag_intel_openmp flag_intel_openmp_win flag_intel_pthread flag_intel_pthread_win flag_intel_standard_compliance flag_intel_standard_compliance_win flag_intel_warn flag_intel_warn_win flag_lfortran_fixed_form flag_lfortran_implicit_external flag_lfortran_implicit_typing flag_lfortran_openmp flag_lfortran_opt flag_nag_backtrace flag_nag_check flag_nag_coarray flag_nag_debug flag_nag_fixed_form flag_nag_free_form flag_nag_no_implicit_typing flag_nag_openmp flag_nag_opt flag_nag_pic flag_pgi_backslash flag_pgi_check flag_pgi_debug flag_pgi_fixed_form flag_pgi_free_form flag_pgi_openmp flag_pgi_traceback flag_pgi_warn Enumerations unnamed Interfaces debug Derived Types archiver_t compiler_t Functions check_compiler compiler_name debug_archiver debug_compiler enumerate_libraries get_compiler_id get_default_flags get_feature_flag get_id get_include_flag get_macros get_module_flag is_gnu is_intel is_unknown Subroutines compile_c compile_cpp compile_fortran get_debug_compile_flags get_default_c_compiler get_default_cxx_compiler get_main_flags get_release_compile_flags link make_archive new_archiver new_compiler set_cpp_preprocessor_flags write_response_file Variables Type Visibility Attributes Name Initial integer, public, parameter :: compiler_enum = kind(id_unknown) character(len=*), public, parameter :: flag_cray_fixed_form = \" -ffixed\" character(len=*), public, parameter :: flag_cray_free_form = \" -ffree\" character(len=*), public, parameter :: flag_cray_implicit_typing = \" -el\" character(len=*), public, parameter :: flag_cray_no_implicit_typing = \" -dl\" character(len=*), public, parameter :: flag_gnu_backtrace = \" -fbacktrace\" character(len=*), public, parameter :: flag_gnu_check = \" -fcheck=bounds -fcheck=array-temps\" character(len=*), public, parameter :: flag_gnu_coarray = \" -fcoarray=single\" character(len=*), public, parameter :: flag_gnu_debug = \" -g\" character(len=*), public, parameter :: flag_gnu_external = \" -Wimplicit-interface\" character(len=*), public, parameter :: flag_gnu_fixed_form = \" -ffixed-form\" character(len=*), public, parameter :: flag_gnu_free_form = \" -ffree-form\" character(len=*), public, parameter :: flag_gnu_limit = \" -fmax-errors=1\" character(len=*), public, parameter :: flag_gnu_no_implicit_external = \" -Werror=implicit-interface\" character(len=*), public, parameter :: flag_gnu_no_implicit_typing = \" -fimplicit-none\" character(len=*), public, parameter :: flag_gnu_openmp = \" -fopenmp\" character(len=*), public, parameter :: flag_gnu_opt = \" -O3 -funroll-loops\" character(len=*), public, parameter :: flag_gnu_pic = \" -fPIC\" character(len=*), public, parameter :: flag_gnu_warn = \" -Wall -Wextra\" character(len=*), public, parameter :: flag_ibmxl_backslash = \" -qnoescape\" character(len=*), public, parameter :: flag_intel_align = \" -align all\" character(len=*), public, parameter :: flag_intel_align_win = \" /align:all\" character(len=*), public, parameter :: flag_intel_backtrace = \" -traceback\" character(len=*), public, parameter :: flag_intel_backtrace_win = \" /traceback\" character(len=*), public, parameter :: flag_intel_byterecl = \" -assume byterecl\" character(len=*), public, parameter :: flag_intel_byterecl_win = \" /assume:byterecl\" character(len=*), public, parameter :: flag_intel_check = \" -check all\" character(len=*), public, parameter :: flag_intel_check_win = \" /check:all\" character(len=*), public, parameter :: flag_intel_debug = \" -O0 -g\" character(len=*), public, parameter :: flag_intel_debug_win = \" /Od /Z7\" character(len=*), public, parameter :: flag_intel_fixed_form = \" -fixed\" character(len=*), public, parameter :: flag_intel_fixed_form_win = \" /fixed\" character(len=*), public, parameter :: flag_intel_fp = \" -fp-model precise -pc64\" character(len=*), public, parameter :: flag_intel_fp_win = \" /fp:precise\" character(len=*), public, parameter :: flag_intel_free_form = \" -free\" character(len=*), public, parameter :: flag_intel_free_form_win = \" /free\" character(len=*), public, parameter :: flag_intel_limit = \" -error-limit 1\" character(len=*), public, parameter :: flag_intel_limit_win = \" /error-limit:1\" character(len=*), public, parameter :: flag_intel_nogen = \" -nogen-interfaces\" character(len=*), public, parameter :: flag_intel_nogen_win = \" /nogen-interfaces\" character(len=*), public, parameter :: flag_intel_openmp = \" -qopenmp\" character(len=*), public, parameter :: flag_intel_openmp_win = \" /Qopenmp\" character(len=*), public, parameter :: flag_intel_pthread = \" -reentrancy threaded\" character(len=*), public, parameter :: flag_intel_pthread_win = \" /reentrancy:threaded\" character(len=*), public, parameter :: flag_intel_standard_compliance = \" -standard-semantics\" character(len=*), public, parameter :: flag_intel_standard_compliance_win = \" /standard-semantics\" character(len=*), public, parameter :: flag_intel_warn = \" -warn all\" character(len=*), public, parameter :: flag_intel_warn_win = \" /warn:all\" character(len=*), public, parameter :: flag_lfortran_fixed_form = \" --fixed-form\" character(len=*), public, parameter :: flag_lfortran_implicit_external = \" --allow-implicit-interface\" character(len=*), public, parameter :: flag_lfortran_implicit_typing = \" --implicit-typing\" character(len=*), public, parameter :: flag_lfortran_openmp = \" --openmp\" character(len=*), public, parameter :: flag_lfortran_opt = \" --fast\" character(len=*), public, parameter :: flag_nag_backtrace = \" -gline\" character(len=*), public, parameter :: flag_nag_check = \" -C\" character(len=*), public, parameter :: flag_nag_coarray = \" -coarray=single\" character(len=*), public, parameter :: flag_nag_debug = \" -g -O0\" character(len=*), public, parameter :: flag_nag_fixed_form = \" -fixed\" character(len=*), public, parameter :: flag_nag_free_form = \" -free\" character(len=*), public, parameter :: flag_nag_no_implicit_typing = \" -u\" character(len=*), public, parameter :: flag_nag_openmp = \" -openmp\" character(len=*), public, parameter :: flag_nag_opt = \" -O4\" character(len=*), public, parameter :: flag_nag_pic = \" -PIC\" character(len=*), public, parameter :: flag_pgi_backslash = \" -Mbackslash\" character(len=*), public, parameter :: flag_pgi_check = \" -Mbounds -Mchkptr -Mchkstk\" character(len=*), public, parameter :: flag_pgi_debug = \" -g\" character(len=*), public, parameter :: flag_pgi_fixed_form = \" -Mfixed\" character(len=*), public, parameter :: flag_pgi_free_form = \" -Mfree\" character(len=*), public, parameter :: flag_pgi_openmp = \" -mp\" character(len=*), public, parameter :: flag_pgi_traceback = \" -traceback\" character(len=*), public, parameter :: flag_pgi_warn = \" -Minform=inform\" Enumerations enum, bind(c) Enumerators enumerator :: id_unknown = 0 enumerator :: id_gcc = 1 enumerator :: id_f95 = 2 enumerator :: id_caf = 3 enumerator :: id_intel_classic_nix = 4 enumerator :: id_intel_classic_mac = 5 enumerator :: id_intel_classic_windows = 6 enumerator :: id_intel_llvm_nix = 7 enumerator :: id_intel_llvm_windows = 8 enumerator :: id_intel_llvm_unknown = 9 enumerator :: id_pgi = 10 enumerator :: id_nvhpc = 11 enumerator :: id_nag = 12 enumerator :: id_flang = 13 enumerator :: id_flang_new = 14 enumerator :: id_f18 = 15 enumerator :: id_ibmxl = 16 enumerator :: id_cray = 17 enumerator :: id_lahey = 18 enumerator :: id_lfortran = 19 Interfaces public interface debug Create debug printout public pure function debug_compiler (self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public pure function debug_archiver (self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string Derived Types type, public :: archiver_t Definition of archiver object Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: ar Path to archiver logical, public :: echo = .true. Print all command logical, public :: use_response_file = .false. Use response files to pass arguments logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure\n , public\n, :: make_archive Subroutine Create static archive type, public :: compiler_t Definition of compiler object Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cc Path to the C compiler character(len=:), public, allocatable :: cxx Path to the C++ compiler logical, public :: echo = .true. Print all commands character(len=:), public, allocatable :: fc Path to the Fortran compiler integer(kind=compiler_enum), public :: id = id_unknown Identifier of the compiler logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure\n , public\n, :: compile_c Subroutine Compile a C object procedure\n , public\n, :: compile_cpp Subroutine Compile a CPP object procedure\n , public\n, :: compile_fortran Subroutine Compile a Fortran object procedure\n , public\n, :: enumerate_libraries Function Enumerate libraries, based on compiler and platform procedure\n , public\n, :: get_default_flags Function Get default compiler flags procedure\n , public\n, :: get_feature_flag Function Get feature flag procedure\n , public\n, :: get_include_flag Function Get flag for include directories procedure\n , public\n, :: get_main_flags Subroutine Get flags for the main linking command procedure\n , public\n, :: get_module_flag Function Get flag for module output directories procedure\n , public\n, :: is_gnu Function Check whether this is a GNU compiler procedure\n , public\n, :: is_intel Function Check whether this is an Intel compiler procedure\n , public\n, :: is_unknown Function Check whether compiler is recognized procedure\n , public\n, :: link Subroutine Link executable procedure\n , public\n, :: name => compiler_name Function Return compiler name Functions public function check_compiler (compiler, expected) result(match) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler character(len=*), intent(in) :: expected Return Value logical public pure function compiler_name (self) result(name) Return a compiler name string Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public pure function debug_archiver (self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string public pure function debug_compiler (self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public function enumerate_libraries (self, prefix, libs) result(r) Enumerate libraries, based on compiler and platform Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: prefix type( string_t ), intent(in) :: libs (:) Return Value character(len=:), allocatable public function get_compiler_id (compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) public function get_default_flags (self, release) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self logical, intent(in) :: release Return Value character(len=:), allocatable public function get_feature_flag (self, feature) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: feature Return Value character(len=:), allocatable public function get_id (compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) public function get_include_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function get_macros (id, macros_list, version) result(macros) This function will parse and read the macros list and\nreturn them as defined flags.\nSet macro defintion symbol on the basis of compiler used\nCheck if macros are not allocated.\nSplit the macro name and value. Read more… Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id type( string_t ), intent(in), allocatable :: macros_list (:) character(len=:), intent(in), allocatable :: version Return Value character(len=:), allocatable public function get_module_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable public pure function is_gnu (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical public pure function is_intel (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical public pure function is_unknown (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Subroutines public subroutine compile_c (self, input, output, args, log_file, stat) Compile a C object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine compile_cpp (self, input, output, args, log_file, stat) Compile a CPP object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine compile_fortran (self, input, output, args, log_file, stat) Compile a Fortran object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine get_debug_compile_flags (id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags public subroutine get_default_c_compiler (f_compiler, c_compiler) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: c_compiler public subroutine get_default_cxx_compiler (f_compiler, cxx_compiler) Get C++ Compiler. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: cxx_compiler public subroutine get_main_flags (self, language, flags) Get special flags for the main linker Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: language character(len=:), intent(out), allocatable :: flags public subroutine get_release_compile_flags (id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags public subroutine link (self, output, args, log_file, stat) Link an executable Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine make_archive (self, output, args, log_file, stat) Create an archive Read more… Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: self Instance of the archiver object character(len=*), intent(in) :: output Name of the archive to generate type( string_t ), intent(in) :: args (:) Object files to include into the archive character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine new_archiver (self, ar, echo, verbose) Create new archiver instance Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(out) :: self New instance of the archiver character(len=*), intent(in) :: ar User provided archiver command logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output public subroutine new_compiler (self, fc, cc, cxx, echo, verbose) Create new compiler instance Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(out) :: self New instance of the compiler character(len=*), intent(in) :: fc Fortran compiler name or path character(len=*), intent(in) :: cc C compiler name or path character(len=*), intent(in) :: cxx C++ Compiler name or path logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output public pure subroutine set_cpp_preprocessor_flags (id, flags) Modify the flag_cpp_preprocessor on the basis of the compiler. Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(inout), allocatable :: flags public subroutine write_response_file (name, argv) Response files allow to read command line options from files.\nWhitespace is used to separate the arguments, we will use newlines\nas separator to create readable response files which can be inspected\nin case of errors. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name type( string_t ), intent(in) :: argv (:)","tags":"","loc":"module/fpm_compiler.html"},{"title":"fpm_environment – Fortran-lang/fpm","text":"This module contains procedures that interact with the programming environment. [get_os_type] – Determine the OS type [get_env] – return the value of an environment variable Uses fpm_error iso_fortran_env Contents Variables OS_CYGWIN OS_FREEBSD OS_LINUX OS_MACOS OS_OPENBSD OS_SOLARIS OS_UNKNOWN OS_WINDOWS Functions get_command_arguments_quoted get_env get_os_type os_is_unix separator Variables Type Visibility Attributes Name Initial integer, public, parameter :: OS_CYGWIN = 4 integer, public, parameter :: OS_FREEBSD = 6 integer, public, parameter :: OS_LINUX = 1 integer, public, parameter :: OS_MACOS = 2 integer, public, parameter :: OS_OPENBSD = 7 integer, public, parameter :: OS_SOLARIS = 5 integer, public, parameter :: OS_UNKNOWN = 0 integer, public, parameter :: OS_WINDOWS = 3 Functions public function get_command_arguments_quoted () result(args) Arguments None Return Value character(len=:), allocatable public function get_env (NAME, DEFAULT) result(VALUE) get named environment variable value. It it is blank or\n not set return the optional default value\n!print , NAME, ” is not defined in the environment. Strange…”\n!print , “This processor doesn’t support environment variables. Boooh!” Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: NAME name of environment variable to get the value of character(len=*), intent(in), optional :: DEFAULT default value to return if the requested value is undefined or blank Return Value character(len=:), allocatable the returned value public function get_os_type () result(r) Determine the OS type Read more… Arguments None Return Value integer public function os_is_unix (os) Compare the output of get_os_type or the optional\npassed INTEGER value to the value for OS_WINDOWS\nand return .TRUE. if they match and .FALSE. otherwise Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Return Value logical public function separator () result(sep) sample usage Read more… Arguments None Return Value character(len=1) ifort_bug*!character(len=1),save :: sep_cache=’ ‘","tags":"","loc":"module/fpm_environment.html"},{"title":"fpm_meta – Fortran-lang/fpm","text":"The fpm meta-package model This is a wrapper data type that encapsulate all pre-processing information\n (compiler flags, linker libraries, etc.) required to correctly enable a package\n to use a core library. Available core libraries OpenMP MPI fortran-lang stdlib fortran-lang minpack Note Core libraries are enabled in the [build] section of the fpm.toml manifest Uses fpm_model fpm_error fpm_command_line iso_fortran_env fpm_manifest fpm_versioning fpm_strings fpm_git fpm_os fpm_manifest_dependency fpm_environment fpm_filesystem fpm_compiler Contents Interfaces resolve_metapackages Derived Types metapackage_t Functions MPI_TYPE_NAME Interfaces public interface resolve_metapackages private subroutine resolve_metapackage_model(model, package, settings, error) Resolve all metapackages into the package config Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(inout) :: model type( package_config_t ), intent(inout) :: package class( fpm_build_settings ), intent(inout) :: settings type( error_t ), intent(out), allocatable :: error Derived Types type, public :: metapackage_t Type for describing a source file Components Type Visibility Attributes Name Initial type( string_t ), public :: cflags type( string_t ), public :: cxxflags type( dependency_config_t ), public, allocatable :: dependency (:) List of Development dependency meta data.\nMetapackage dependencies are never exported from the model type( string_t ), public, allocatable :: external_modules (:) type( string_t ), public :: fflags type( string_t ), public :: flags List of compiler flags and options to be added type( fortran_features_t ), public, allocatable :: fortran Special fortran features logical, public :: has_build_flags = .false. logical, public :: has_c_flags = .false. logical, public :: has_cxx_flags = .false. logical, public :: has_dependencies = .false. logical, public :: has_external_modules = .false. logical, public :: has_fortran_flags = .false. logical, public :: has_include_dirs = .false. logical, public :: has_link_flags = .false. logical, public :: has_link_libraries = .false. logical, public :: has_run_command = .false. type( string_t ), public, allocatable :: incl_dirs (:) type( string_t ), public :: link_flags type( string_t ), public, allocatable :: link_libs (:) type( string_t ), public :: run_command type( version_t ), public, allocatable :: version Package version (if supported) Type-Bound Procedures procedure\n , public\n, :: destroy Subroutine Clean metapackage structure procedure\n , public\n, :: new =>\n init_from_name Subroutine Initialize the metapackage structure from its given name generic,\n public\n, :: resolve =>\n resolve_cmd, resolve_model, resolve_package_config Functions public pure function MPI_TYPE_NAME (mpilib) result(name) Return a name for the MPI library Arguments Type Intent Optional Attributes Name integer, intent(in) :: mpilib Return Value character(len=:), allocatable","tags":"","loc":"module/fpm_meta.html"},{"title":"fpm – Fortran-lang/fpm","text":"Uses fpm_backend fpm_sources iso_c_binding fpm_command_line fpm_model fpm_error iso_fortran_env fpm_dependency fpm_targets fpm_manifest fpm_meta fpm_filesystem fpm_compiler fpm_environment fpm_strings Contents Subroutines build_model check_modules_for_duplicates cmd_build cmd_clean cmd_run Subroutines public subroutine build_model (model, settings, package, error) Constructs a valid fpm model from command line settings and the toml manifest.\nAdd this dependency’s manifest macros Read more… Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(out) :: model class( fpm_build_settings ), intent(inout) :: settings type( package_config_t ), intent(inout) :: package type( error_t ), intent(out), allocatable :: error public subroutine check_modules_for_duplicates (model, duplicates_found) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model logical :: duplicates_found public subroutine cmd_build (settings) Arguments Type Intent Optional Attributes Name type( fpm_build_settings ), intent(inout) :: settings public subroutine cmd_clean (settings) Delete the build directory including or excluding dependencies. Arguments Type Intent Optional Attributes Name class( fpm_clean_settings ), intent(in) :: settings Settings for the clean command. public subroutine cmd_run (settings, test) Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(inout) :: settings logical, intent(in) :: test","tags":"","loc":"module/fpm.html"},{"title":"fpm_targets – Fortran-lang/fpm","text":"Build target handling This module handles the construction of the build target list\n from the sources list ( targets_from_sources ), the\n resolution of module-dependencies between build targets\n ( resolve_module_dependencies ), and the enumeration of\n objects required for link targets ( resolve_target_linking ). A build target ( build_target_t ) is a file to be generated\n by the backend (compilation and linking). Note The current implementation is ignorant to the existence of\n module files ( .mod , .smod ). Dependencies arising from modules\n are based on the corresponding object files ( .o ) only. For more information, please read the documentation for the procedures: build_target_list resolve_module_dependencies Enumerations Target type: FPM_TARGET_* Describes the type of build target — determines backend build rules Uses fpm_sources fpm_model fpm_error iso_fortran_env fpm_strings fpm_environment fpm_filesystem fpm_compiler Contents Variables FPM_TARGET_ARCHIVE FPM_TARGET_CPP_OBJECT FPM_TARGET_C_OBJECT FPM_TARGET_EXECUTABLE FPM_TARGET_OBJECT FPM_TARGET_UNKNOWN Derived Types build_target_ptr build_target_t Subroutines add_dependency add_target filter_executable_targets filter_library_targets filter_modules resolve_module_dependencies targets_from_sources Variables Type Visibility Attributes Name Initial integer, public, parameter :: FPM_TARGET_ARCHIVE = 2 Target type is library archive integer, public, parameter :: FPM_TARGET_CPP_OBJECT = 5 Target type is cpp compiled object integer, public, parameter :: FPM_TARGET_C_OBJECT = 4 Target type is c compiled object integer, public, parameter :: FPM_TARGET_EXECUTABLE = 1 Target type is executable integer, public, parameter :: FPM_TARGET_OBJECT = 3 Target type is compiled object integer, public, parameter :: FPM_TARGET_UNKNOWN = -1 Target type is unknown (ignored) Derived Types type, public :: build_target_ptr Wrapper type for constructing arrays of build_target_t pointers Components Type Visibility Attributes Name Initial type( build_target_t ), public, pointer :: ptr => null() type, public :: build_target_t Type describing a generated build target Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: compile_flags Compile flags for this build target type( build_target_ptr ), public, allocatable :: dependencies (:) Resolved build dependencies integer(kind=int64), public, allocatable :: digest_cached Previous source file hash type( fortran_features_t ), public :: features Language features character(len=:), public, allocatable :: link_flags Link flags for this build target type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: link_objects (:) Objects needed to link this target type( string_t ), public, allocatable :: macros (:) List of macros character(len=:), public, allocatable :: output_dir File path of output directory character(len=:), public, allocatable :: output_file File path of build target object relative to cwd character(len=:), public, allocatable :: output_log_file File path of build log file relative to cwd character(len=:), public, allocatable :: output_name File path of build target object relative to output_dir character(len=:), public, allocatable :: package_name Name of parent package integer, public :: schedule = -1 Targets in the same schedule group are guaranteed to be independent logical, public :: skip = .false. Flag set if build target will be skipped (not built) logical, public :: sorted = .false. Flag set if build target is sorted for building type( srcfile_t ), public, allocatable :: source Primary source for this build target integer, public :: target_type = FPM_TARGET_UNKNOWN Target type logical, public :: touched = .false. Flag set when first visited to check for circular dependencies character(len=:), public, allocatable :: version Version number Subroutines public subroutine add_dependency (target, dependency) Add pointer to dependeny in target%dependencies Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout) :: target type( build_target_t ), intent(in), target :: dependency public subroutine add_target (targets, package, type, output_name, source, link_libraries, features, macros, version) Allocate a new target and append to target list Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) character(len=*), intent(in) :: package integer, intent(in) :: type character(len=*), intent(in) :: output_name type( srcfile_t ), intent(in), optional :: source type( string_t ), intent(in), optional :: link_libraries (:) type( fortran_features_t ), intent(in), optional :: features type( string_t ), intent(in), optional :: macros (:) character(len=*), intent(in), optional :: version public subroutine filter_executable_targets (targets, scope, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) integer, intent(in) :: scope type( string_t ), intent(out), allocatable :: list (:) public subroutine filter_library_targets (targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) public subroutine filter_modules (targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) public subroutine resolve_module_dependencies (targets, external_modules, error) Add dependencies to source-based targets ( FPM_TARGET_OBJECT )\n based on any modules used by the corresponding source file. Read more… Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), target :: targets (:) type( string_t ), intent(in) :: external_modules (:) type( error_t ), intent(out), allocatable :: error public subroutine targets_from_sources (targets, model, prune, error) High-level wrapper to generate build target information Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: targets (:) The generated list of build targets type( fpm_model_t ), intent(inout), target :: model The package model from which to construct the target list logical, intent(in) :: prune Enable tree-shaking/pruning of module dependencies type( error_t ), intent(out), allocatable :: error Error structure","tags":"","loc":"module/fpm_targets.html"},{"title":"fpm_os – Fortran-lang/fpm","text":"Uses iso_c_binding fpm_environment fpm_filesystem fpm_error Contents Subroutines change_directory convert_to_absolute_path get_absolute_path get_absolute_path_by_cd get_current_directory Subroutines public subroutine change_directory (path, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error public subroutine convert_to_absolute_path (path, error) Converts a path to an absolute, canonical path. Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: path type( error_t ), intent(out), allocatable :: error public subroutine get_absolute_path (path, absolute_path, error) Determine the canonical, absolute path for the given path.\nExpands home folder (~) on both Unix and Windows. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error public subroutine get_absolute_path_by_cd (path, absolute_path, error) Alternative to get_absolute_path that uses chdir / _chdir to determine the absolute path. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error public subroutine get_current_directory (path, error) Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: path type( error_t ), intent(out), allocatable :: error","tags":"","loc":"module/fpm_os.html"},{"title":"fpm_backend_output – Fortran-lang/fpm","text":"Build Backend Progress Output This module provides a derived type build_progress_t for printing build status\n and progress messages to the console while the backend is building the package. The build_progress_t type supports two modes: normal and plain where the former does ‘pretty’ output and the latter does not.\n The normal mode is intended for typical interactive usage whereas\n ‘plain’ mode is used with the --verbose flag or when stdout is not attached\n to a terminal (e.g. when piping or redirecting stdout ). In these cases,\n the pretty output must be suppressed to avoid control codes being output. Uses fpm_targets iso_fortran_env fpm_filesystem fpm_backend_console Contents Interfaces build_progress_t Derived Types build_progress_t Interfaces public interface build_progress_t Constructor for build_progress_t private function new_build_progress(target_queue, plain_mode) result(progress) Initialise a new build progress object Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in), target :: target_queue (:) The queue of scheduled targets logical, intent(in), optional :: plain_mode Enable ‘plain’ output for progress object Return Value type( build_progress_t ) Progress object to initialise Derived Types type, public :: build_progress_t Build progress object Components Type Visibility Attributes Name Initial type( console_t ), public :: console Console object for updating console lines integer, public :: n_complete Number of completed targets integer, public :: n_target Total number of targets scheduled integer, public, allocatable :: output_lines (:) Store needed when updating previous console lines logical, public :: plain_mode = .true. ‘Plain’ output (no colors or updating) type( build_target_ptr ), public, pointer :: target_queue (:) Queue of scheduled build targets Constructor Constructor for build_progress_t private\n\n \n function new_build_progress (target_queue, plain_mode) Initialise a new build progress object Type-Bound Procedures procedure\n , public\n, :: compiling_status =>\n output_status_compiling Subroutine Output ‘compiling’ status for build target procedure\n , public\n, :: completed_status =>\n output_status_complete Subroutine Output ‘complete’ status for build target procedure\n , public\n, :: success =>\n output_progress_success Subroutine Output finished status for whole package","tags":"","loc":"module/fpm_backend_output.html"},{"title":"fpm_sources – Fortran-lang/fpm","text":"Discovery of sources This module implements subroutines for building a list of srcfile_t objects by looking for source files in the filesystem. Uses fpm_model fpm_error fpm_manifest_executable fpm_source_parsing fpm_environment fpm_filesystem fpm_strings Contents Functions get_exe_name_with_suffix Subroutines add_executable_sources add_sources_from_dir Functions public function get_exe_name_with_suffix (source) result(suffixed) Build an executable name with suffix. Safe routine that always returns an allocated string Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(in) :: source Return Value character(len=:), allocatable Subroutines public subroutine add_executable_sources (sources, executables, scope, auto_discover, error) Add to sources using the executable and test entries in the manifest and\napplies any executable-specific overrides such as executable%name .\nAdds all sources (including modules) from each executable%source_dir Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of srcfile_t objects to append to. Allocated if not allocated class( executable_config_t ), intent(in) :: executables (:) List of executable_config_t entries from manifest integer, intent(in) :: scope Scope to apply to the discovered sources: either FPM_SCOPE_APP or FPM_SCOPE_TEST , see fpm_model logical, intent(in) :: auto_discover If .false. only executables and tests specified in the manifest are added to sources type( error_t ), intent(out), allocatable :: error Error handling public subroutine add_sources_from_dir (sources, directory, scope, with_executables, recurse, error) Add to sources by looking for source files in directory Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of srcfile_t objects to append to. Allocated if not allocated character(len=*), intent(in) :: directory Directory in which to search for source files integer, intent(in) :: scope Scope to apply to the discovered sources, see fpm_model for enumeration logical, intent(in), optional :: with_executables Executable sources (fortran program s) are ignored unless with_executables=.true. logical, intent(in), optional :: recurse Whether to recursively search subdirectories, default is .true. type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_sources.html"},{"title":"fpm_source_parsing – Fortran-lang/fpm","text":"Parsing of package source files This module exposes two functions, parse_f_source and parse_c_source ,\n which perform a rudimentary parsing of fortran and c source files\n in order to extract information required for module dependency tracking. Both functions additionally calculate and store a file digest (hash) which\n is used by the backend ( fpm_backend ) to skip compilation of unmodified sources. Both functions return an instance of the srcfile_t type. For more information, please read the documentation for each function: parse_f_source parse_c_source Uses fpm_model fpm_strings fpm_error fpm_filesystem Contents Functions parse_c_source parse_f_source Subroutines parse_use_statement Functions public function parse_c_source (c_filename, error) result(c_source) Parsing of c, cpp source files Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: c_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) public function parse_f_source (f_filename, error) result(f_source) Parsing of free-form fortran source files Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) Subroutines public subroutine parse_use_statement (f_filename, i, line, use_stmt, is_intrinsic, module_name, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename Current file name and line number (for error messaging) integer, intent(in) :: i character(len=*), intent(in) :: line The line being parsed. MUST BE preprocessed with trim(adjustl() logical, intent(out) :: use_stmt Does this line contain a use statement? logical, intent(out) :: is_intrinsic Is the module in this statement intrinsic? character(len=:), intent(out), allocatable :: module_name used module name type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_source_parsing.html"},{"title":"fpm_filesystem – Fortran-lang/fpm","text":"This module contains general routines for interacting with the file system Directories are not files for the Intel compilers. If so, also use this compiler-dependent extension Uses iso_c_binding iso_fortran_env fpm_error fpm_environment fpm_strings Contents Functions basename canon_path dirname exists get_dos_path get_local_prefix get_temp_filename is_absolute_path is_dir is_hidden_file join_path number_of_rows parent_dir read_lines read_lines_expanded unix_path which windows_path Subroutines delete_file execute_and_read_output fileclose fileopen filewrite get_home getline list_files mkdir os_delete_dir run warnwrite Functions public function basename (path, suffix) result(base) Extract filename from path with/without suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: suffix Return Value character(len=:), allocatable public function canon_path (path) Canonicalize path for comparison\n* Handles path string redundancies\n* Does not test existence of path Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function dirname (path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function exists (filename) result(r) test if pathname already exists Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value logical public function get_dos_path (path, error) Ensure a windows path is converted to an 8.3 DOS path if it contains spaces\nNo need to convert if there are no spaces Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error Return Value character(len=:), allocatable public function get_local_prefix (os) result(prefix) Determine the path prefix to the local folder. Used for installation, registry etc. Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Platform identifier Return Value character(len=:), allocatable Installation prefix public function get_temp_filename () result(tempfile) Get a unused temporary filename\n Calls posix ‘tempnam’ - not recommended, but\n we have no security concerns for this application\n and use here is temporary.\nWorks with MinGW Arguments None Return Value character(len=:), allocatable public function is_absolute_path (path, is_unix) Returns .true. if provided path is absolute. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: is_unix Return Value logical public function is_dir (dir) test if a name matches an existing directory path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical public function is_hidden_file (file_basename) result(r) test if a file is hidden Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file_basename Return Value logical public function join_path (a1, a2, a3, a4, a5) result(path) Construct path by joining strings with os file separator Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: a1 character(len=*), intent(in) :: a2 character(len=*), intent(in), optional :: a3 character(len=*), intent(in), optional :: a4 character(len=*), intent(in), optional :: a5 Return Value character(len=:), allocatable public function number_of_rows (s) result(nrows) Determine number or rows in a file given a LUN Arguments Type Intent Optional Attributes Name integer, intent(in) :: s Return Value integer public function parent_dir (path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function read_lines (fh) result(lines) read lines into an array of TYPE(STRING_T) variables Arguments Type Intent Optional Attributes Name integer, intent(in) :: fh Return Value type( string_t ), allocatable, (:) public function read_lines_expanded (fh) result(lines) read lines into an array of TYPE(STRING_T) variables expanding tabs Arguments Type Intent Optional Attributes Name integer, intent(in) :: fh Return Value type( string_t ), allocatable, (:) public function unix_path (path) result(nixpath) Replace file system separators for 1 Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function which (command) result(pathname) Author John S. Urban License Public Domain function which(command) result(pathname) Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: command Return Value character(len=:), allocatable public function windows_path (path) result(winpath) Replace file system separators for windows Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Subroutines public subroutine delete_file (file) delete a file by filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file public subroutine execute_and_read_output (cmd, output, error, verbose) Execute command line and return output as a string. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd Command to execute. character(len=:), intent(out), allocatable :: output Command line output. type( error_t ), intent(out), allocatable :: error Error to handle. logical, intent(in), optional :: verbose Print additional information if true. public subroutine fileclose (lun, ier) simple close of a LUN. On error show message and stop (by default) Arguments Type Intent Optional Attributes Name integer, intent(in) :: lun integer, intent(out), optional :: ier public subroutine fileopen (filename, lun, ier) procedure to open filename as a sequential “text” file Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename integer, intent(out) :: lun integer, intent(out), optional :: ier public subroutine filewrite (filename, filedata) procedure to write filedata to file filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename character(len=*), intent(in) :: filedata (:) public subroutine get_home (home, error) Get the HOME directory on Unix and the %USERPROFILE% directory on Windows. Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: home type( error_t ), intent(out), allocatable :: error public subroutine getline (unit, line, iostat, iomsg) Author fpm(1) contributors License MIT subroutine getline(unit,line,iostat,iomsg) Read more… Arguments Type Intent Optional Attributes Name integer, intent(in) :: unit Formatted IO unit character(len=:), intent(out), allocatable :: line Line to read integer, intent(out) :: iostat Status of operation character(len=:), optional, allocatable :: iomsg Error message public recursive subroutine list_files (dir, files, recurse) Get file & directory names in directory dir using iso_c_binding. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir type( string_t ), intent(out), allocatable :: files (:) logical, intent(in), optional :: recurse public subroutine mkdir (dir, echo) Create a directory. Create subdirectories as needed Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir logical, intent(in), optional :: echo public subroutine os_delete_dir (is_unix, dir, echo) Delete directory using system OS remove directory commands Arguments Type Intent Optional Attributes Name logical, intent(in) :: is_unix character(len=*), intent(in) :: dir logical, intent(in), optional :: echo public subroutine run (cmd, echo, exitstat, verbose, redirect) Author fpm(1) contributors License MIT Execute the specified system command. Optionally Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd logical, intent(in), optional :: echo integer, intent(out), optional :: exitstat logical, intent(in), optional :: verbose character(len=*), intent(in), optional :: redirect public subroutine warnwrite (fname, data) write trimmed character data to a file if it does not exist Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: fname character(len=*), intent(in) :: data (:)","tags":"","loc":"module/fpm_filesystem.html"},{"title":"fpm_backend – Fortran-lang/fpm","text":"Build backend Uses a list of build_target_ptr and a valid fpm_model instance\n to schedule and execute the compilation and linking of package targets. The package build process ( build_package ) comprises three steps: Target sorting: topological sort of the target dependency graph ( sort_target ) Target scheduling: group targets into schedule regions based on the sorting ( schedule_targets ) Target building: generate targets by compilation or linking Note If compiled with OpenMP, targets will be build in parallel where possible. Incremental compilation The backend process supports incremental compilation whereby targets are not\n re-compiled if their corresponding dependencies have not been modified. Source-based targets ( i.e. objects) are not re-compiled if the corresponding source\n file is unmodified AND all of the target dependencies are not marked for re-compilation Link targets ( i.e. executables and libraries) are not re-compiled if the\n target output file already exists AND all of the target dependencies are not marked for\n re-compilation Source file modification is determined by a file digest (hash) which is calculated during\n the source parsing phase ( fpm_source_parsing ) and cached to disk after a target is\n successfully generated. Uses fpm_model fpm_error iso_fortran_env fpm_targets fpm_backend_output fpm_filesystem fpm_strings Contents Subroutines build_package schedule_targets sort_target Subroutines public subroutine build_package (targets, model, verbose) Top-level routine to build package described by model Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout) :: targets (:) type( fpm_model_t ), intent(in) :: model logical, intent(in) :: verbose public subroutine schedule_targets (queue, schedule_ptr, targets) Construct a build schedule from the sorted targets. Read more… Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: queue (:) integer, allocatable :: schedule_ptr (:) type( build_target_ptr ), intent(in) :: targets (:) public recursive subroutine sort_target (target) Topologically sort a target for scheduling by\n recursing over its dependencies. Read more… Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout), target :: target","tags":"","loc":"module/fpm_backend.html"},{"title":"fpm_command_line – Fortran-lang/fpm","text":"Definition of the command line interface This module uses M_CLI2 to define\n the command line interface.\n To define a command line interface create a new command settings type\n from the fpm_cmd_settings base class or the respective parent command\n settings. The subcommand is selected by the first non-option argument in the command\n line. In the subcase block the actual command line is defined and transferred\n 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\n wanted command line and the expected default values.\n Some of the following points also apply if you add a new option or argument\n to an existing fpm subcommand.\n At this point you should create a help page for the new command in a simple\n catman-like format as well in the set_help procedure.\n Make sure to register new subcommands in the fpm-manual command by adding\n them to the manual character array and in the help/manual case as well.\n 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\n is complete and consistent as well. Uses fpm_error m_cli2 fpm_release iso_fortran_env fpm_os fpm_environment fpm_filesystem fpm_strings Contents Derived Types fpm_build_settings fpm_clean_settings fpm_cmd_settings fpm_install_settings fpm_new_settings fpm_publish_settings fpm_run_settings fpm_test_settings fpm_update_settings Subroutines get_command_line_settings Derived Types type, public, extends( fpm_cmd_settings ) :: fpm_build_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_cmd_settings ) :: fpm_clean_settings Components Type Visibility Attributes Name Initial logical, public :: clean_call = .false. logical, public :: clean_skip = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public :: fpm_cmd_settings Components Type Visibility Attributes Name Initial logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_install_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: bindir logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: includedir character(len=:), public, allocatable :: ldflag character(len=:), public, allocatable :: libdir logical, public :: list = .false. logical, public :: no_rebuild character(len=:), public, allocatable :: prefix character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_cmd_settings ) :: fpm_new_settings Components Type Visibility Attributes Name Initial logical, public :: backfill = .true. character(len=:), public, allocatable :: name logical, public :: verbose = .true. logical, public :: with_bare = .false. logical, public :: with_example = .false. logical, public :: with_executable = .false. logical, public :: with_full = .false. logical, public :: with_lib = .true. logical, public :: with_test = .false. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_publish_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag logical, public :: is_dry_run = .false. character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: show_package_version = .false. logical, public :: show_upload_data = .false. character(len=:), public, allocatable :: token logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_run_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure\n , public\n, :: runner_command Function type, public, extends( fpm_run_settings ) :: fpm_test_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure\n , public\n, :: runner_command Function type, public, extends( fpm_cmd_settings ) :: fpm_update_settings Settings for interacting and updating with project dependencies Components Type Visibility Attributes Name Initial logical, public :: clean logical, public :: fetch_only character(len=ibug), public, allocatable :: name (:) logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Subroutines public subroutine get_command_line_settings (cmd_settings) ! canon_path is not converting “.”, etc.\n& ‘ unknown help topic “’//trim(unnamed(i)).’not found in:’,manual] Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(out), allocatable :: cmd_settings","tags":"","loc":"module/fpm_command_line.html"},{"title":"fpm_strings – Fortran-lang/fpm","text":"This module defines general procedures for string operations for both CHARACTER and\n TYPE(STRING_T) variables general routines for performing string operations Types TYPE(STRING_T) define a type to contain strings of variable length Type Conversions f_string return Fortran CHARACTER variable when given a C-like array of\n single characters terminated with a C_NULL_CHAR CHARACTER str Converts INTEGER or LOGICAL to CHARACTER string Case lower Changes a string to lowercase over optional specified column range Parsing and joining split parse string on delimiter characters and store tokens into an allocatable array string_cat Concatenate an array of type(string_t) into a single CHARACTER variable join append an array of CHARACTER variables into a single CHARACTER variable Testing str_ends_with test if a CHARACTER string or array ends with a specified suffix string_array_contains Check if array of TYPE(STRING_T) matches a particular CHARACTER string OPERATOR(.IN.) Check if array of TYPE(STRING_T) matches a particular CHARACTER string glob function compares text strings, one of which can have wildcards (‘*’ or ‘?’). is_fortran_name determine whether a string is an acceptable Fortran entity name to_fortran_name replace allowed special but unusuable characters in names with underscore Whitespace notabs subroutine to expand tab characters assuming a tab space every eight characters dilate function to expand tab characters assuming a tab space every eight characters len_trim Determine total trimmed length of STRING_T array Miscellaneous fnv_1a Hash a CHARACTER(*) string of default kind or a TYPE(STRING_T) array replace Returns string with characters in charset replaced with target_char. resize increase the size of a TYPE(STRING_T) array by N elements Module naming Uses iso_c_binding iso_fortran_env Contents Interfaces fnv_1a len_trim operator(.in.) resize str str_ends_with string_t Derived Types string_t Functions dilate f_string glob has_valid_custom_prefix has_valid_standard_prefix is_fortran_name is_valid_module_name is_valid_module_prefix join lower module_prefix_template module_prefix_type replace str_begins_with_str string_array_contains string_cat to_fortran_name Subroutines notabs remove_characters_in_set remove_newline_characters split Interfaces public interface fnv_1a private pure function fnv_1a_char(input, seed) result(hash) Hash a character(*) string of default kind Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64) private pure function fnv_1a_string_t(input, seed) result(hash) Hash a string_t array of default kind Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: input (:) integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64) public interface len_trim private elemental function string_len_trim(string) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: string Return Value integer private pure function strings_len_trim(strings) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) Return Value integer public interface operator(.in.) public function string_array_contains (search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical public interface resize private subroutine resize_string(list, n) increase the size of a TYPE(STRING_T) array by N elements Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout), allocatable :: list (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size public interface str private pure function str_int(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer, intent(in) :: i Return Value character(len=str_int_len) private pure function str_int64(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer(kind=int64), intent(in) :: i Return Value character(len=str_int64_len) private pure function str_logical(l) result(s) Converts logical “l” to string Arguments Type Intent Optional Attributes Name logical, intent(in) :: l Return Value character(len=str_logical_len) public interface str_ends_with private pure function str_ends_with_str(s, e) result(r) test if a CHARACTER string ends with a specified suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e Return Value logical private pure function str_ends_with_any(s, e) result(r) test if a CHARACTER string ends with any of an array of suffixs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e (:) Return Value logical public interface string_t private function new_string_t(s) result(string) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s Return Value type( string_t ) Derived Types type, public :: string_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: s Constructor private\n\n \n function new_string_t (s) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Functions public function dilate (instr) result(outstr) Author John S. Urban License Public Domain Sample program: Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr Return Value character(len=:), allocatable public function f_string (c_string) return Fortran character variable when given a C-like array of\nsingle characters terminated with a C_NULL_CHAR character Arguments Type Intent Optional Attributes Name character(len=1), intent(in) :: c_string (:) Return Value character(len=:), allocatable public function glob (tame, wild) Author John S. Urban License Public Domain glob(3f) compares given STRING for match to PATTERN which may\n contain wildcard characters. Read more… Arguments Type Intent Optional Attributes Name character(len=*) :: tame A string without wildcards to compare to the globbing expression character(len=*) :: wild A (potentially) corresponding string with wildcards Return Value logical result of test public function has_valid_custom_prefix (module_name, custom_prefix) result(valid) Check that a module name is prefixed with a custom prefix:\n1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed)\n2) It must begin with the prefix\n3) If longer, package name must be followed by default separator (“_”) plus at least one char Read more… Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: custom_prefix Return Value logical public function has_valid_standard_prefix (module_name, package_name) result(valid) Check that a module name is prefixed with the default package prefix:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Read more… Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name Return Value logical public elemental function is_fortran_name (line) result(lout) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: line Return Value logical public function is_valid_module_name (module_name, package_name, custom_prefix, enforce_module_names) result(valid) Check that a module name fits the current naming rules:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Read more… Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name type( string_t ), intent(in) :: custom_prefix logical, intent(in) :: enforce_module_names Return Value logical public function is_valid_module_prefix (module_prefix) result(valid) Check that a custom module prefix fits the current naming rules:\n1) Only alphanumeric characters (no spaces, dashes, underscores or other characters)\n2) Does not begin with a number (Fortran-compatible syntax) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_prefix Return Value logical public pure function join (str, sep, trm, left, right, start, end) result(string) Author John S. Urban License Public Domain JOIN(3f) appends the elements of a CHARACTER array into a single\n CHARACTER variable, with elements 1 to N joined from left to right.\n By default each element is trimmed of trailing spaces and the\n default separator is a null string. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str (:) character(len=*), intent(in), optional :: sep logical, intent(in), optional :: trm character(len=*), intent(in), optional :: left character(len=*), intent(in), optional :: right character(len=*), intent(in), optional :: start character(len=*), intent(in), optional :: end Return Value character(len=:), allocatable public pure elemental function lower (str, begin, end) result(string) Author John S. Urban License Public Domain Changes a string to lowercase over optional specified column range Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str integer, intent(in), optional :: begin integer, intent(in), optional :: end Return Value character(len=len(str)) public function module_prefix_template (project_name, custom_prefix) result(prefix) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) public function module_prefix_type (project_name, custom_prefix) result(ptype) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) public pure function replace (string, charset, target_char) result(res) Returns string with characters in charset replaced with target_char. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string character(len=1), intent(in) :: charset (:) character(len=1), intent(in) :: target_char Return Value character(len=len(string)) public pure function str_begins_with_str (s, e, case_sensitive) result(r) test if a CHARACTER string begins with a specified prefix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e logical, intent(in), optional :: case_sensitive Return Value logical public function string_array_contains (search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical public function string_cat (strings, delim) result(cat) Concatenate an array of type(string_t) into\n a single CHARACTER variable Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) character(len=*), intent(in), optional :: delim Return Value character(len=:), allocatable public pure function to_fortran_name (string) result(res) Returns string with special characters replaced with an underscore.\nFor now, only a hyphen is treated as a special character, but this can be\nexpanded to other characters if needed. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string Return Value character(len=len(string)) Subroutines public impure elemental subroutine notabs (instr, outstr, ilen) Author John S. Urban License Public Domain notabs(3f) - [fpm_strings:NONALPHA] expand tab characters\n (LICENSE:PD) Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr character(len=*), intent(out) :: outstr integer, intent(out) :: ilen public subroutine remove_characters_in_set (string, set, replace_with) Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: string character(len=*), intent(in) :: set character(len=1), intent(in), optional :: replace_with public subroutine remove_newline_characters (string) Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout) :: string public subroutine split (input_line, array, delimiters, order, nulls) Author John S. Urban License Public Domain parse string on delimiter characters and store tokens into an allocatable array\n given a line of structure ” par1 par2 par3 … parn ” store each par(n) into a separate variable in array. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input_line input string to tokenize character(len=:), intent(out), allocatable :: array (:) output array of tokens character(len=*), intent(in), optional :: delimiters list of delimiter characters character(len=*), intent(in), optional :: order order of output array sequential|[reverse|right] character(len=*), intent(in), optional :: nulls return strings composed of delimiters or not ignore|return|ignoreend","tags":"","loc":"module/fpm_strings.html"},{"title":"fpm_versioning – Fortran-lang/fpm","text":"Implementation of versioning data for comparing packages Uses regex_module fpm_strings fpm_error Contents Interfaces new_version Derived Types version_t Functions regex_version_from_text Interfaces public interface new_version private subroutine new_version_from_string(self, string, error) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data character(len=*), intent(in) :: string String describing the version information type( error_t ), intent(out), allocatable :: error Error handling private subroutine new_version_from_int(self, num) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data integer, intent(in) :: num (:) Subversion numbers to define version data Derived Types type, public :: version_t Type-Bound Procedures generic,\n public\n, :: operator(.match.) =>\n match Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) generic,\n public\n, :: operator(/=) =>\n not_equals generic,\n public\n, :: operator(<) =>\n less generic,\n public\n, :: operator(<=) =>\n less_equals generic,\n public\n, :: operator(==) =>\n equals generic,\n public\n, :: operator(>) =>\n greater generic,\n public\n, :: operator(>=) =>\n greater_equals procedure\n , public\n, :: s Function Create a printable string from a version data type Functions public function regex_version_from_text (text, what, error) result(ver) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: text character(len=*), intent(in) :: what type( error_t ), intent(out), allocatable :: error Return Value type( string_t )","tags":"","loc":"module/fpm_versioning.html"},{"title":"fpm_git – Fortran-lang/fpm","text":"Implementation for interacting with git repositories. Uses fpm_error fpm_filesystem Contents Variables compressed_package_name git_descriptor out_fmt Interfaces operator(==) Derived Types enum_descriptor git_target_t Functions git_matches_manifest git_target_branch git_target_default git_target_eq git_target_revision git_target_tag Subroutines checkout git_archive git_revision info Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: compressed_package_name = 'compressed_package' Name of the compressed package that is generated temporarily. type( enum_descriptor ), public, parameter :: git_descriptor = enum_descriptor() Actual enumerator for descriptors character(len=*), public, parameter :: out_fmt = '(\"#\", *(1x, g0))' Common output format for writing to the command line Interfaces public interface operator(==) public function git_target_eq (this, that) result(is_equal) Check that two git targets are equal Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: this Two input git targets type( git_target_t ), intent(in) :: that Two input git targets Return Value logical Derived Types type, public :: enum_descriptor Possible git target Components Type Visibility Attributes Name Initial integer, public :: branch = 201 Branch in git repository integer, public :: default = 200 Default target integer, public :: revision = 203 Commit hash integer, public :: tag = 202 Tag in git repository type, public :: git_target_t Description of an git target Components Type Visibility Attributes Name Initial integer, public :: descriptor = git_descriptor%default Kind of the git target character(len=:), public, allocatable :: object Additional descriptor of the git object character(len=:), public, allocatable :: url Target URL of the git repository Type-Bound Procedures procedure\n , public\n, :: checkout Subroutine Fetch and checkout in local directory procedure\n , public\n, :: info Subroutine Show information on instance Functions public function git_matches_manifest (cached, manifest, verbosity, iunit) Check that a cached dependency matches a manifest request Read more… Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: cached Two input git targets type( git_target_t ), intent(in) :: manifest Two input git targets integer, intent(in) :: verbosity integer, intent(in) :: iunit Return Value logical public function git_target_branch (url, branch) result(self) Target a branch in the git repository Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: branch Name of the branch of interest Return Value type( git_target_t ) New git target public function git_target_default (url) result(self) Default target Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository Return Value type( git_target_t ) New git target public function git_target_eq (this, that) result(is_equal) Check that two git targets are equal Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: this Two input git targets type( git_target_t ), intent(in) :: that Two input git targets Return Value logical public function git_target_revision (url, sha1) result(self) Target a specific git revision Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: sha1 Commit hash of interest Return Value type( git_target_t ) New git target public function git_target_tag (url, tag) result(self) Target a git tag Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: tag Tag name of interest Return Value type( git_target_t ) New git target Subroutines public subroutine checkout (self, local_path, error) Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target character(len=*), intent(in) :: local_path Local path to checkout in type( error_t ), intent(out), allocatable :: error Error public subroutine git_archive (source, destination, ref, verbose, error) Archive a folder using git archive . Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: source Directory to archive. character(len=*), intent(in) :: destination Destination of the archive. character(len=*), intent(in) :: ref (Symbolic) Reference to be archived. logical, intent(in) :: verbose Print additional information if true. type( error_t ), intent(out), allocatable :: error Error handling. public subroutine git_revision (local_path, object, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: local_path Local path to checkout in character(len=:), intent(out), allocatable :: object Git object reference type( error_t ), intent(out), allocatable :: error Error public subroutine info (self, unit, verbosity) Show information on git target Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout","tags":"","loc":"module/fpm_git.html"},{"title":"fpm_dependency – Fortran-lang/fpm","text":"Dependency management Fetching dependencies and creating a dependency tree Dependencies on the top-level can be specified from: package%dependencies package%dev_dependencies package%executable(:)%dependencies package%test(:)%dependencies Each dependency is fetched in some way and provides a path to its package\nmanifest.\nThe package%dependencies of the dependencies are resolved recursively. To initialize the dependency tree all dependencies are recursively fetched\nand stored in a flat data structure to avoid retrieving a package twice.\nThe data structure used to store this information should describe the current\nstatus of the dependency tree. Important information are: name of the package version of the package path to the package root Additionally, for version controlled dependencies the following should be\nstored along with the package: the upstream url the current checked out revision Fetching a remote (version controlled) dependency turns it for our purpose\ninto a local path dependency which is handled by the same means. Updating dependencies For a given dependency tree all top-level dependencies can be updated.\nWe have two cases to consider, a remote dependency and a local dependency,\nagain, remote dependencies turn into local dependencies by fetching.\nTherefore we will update remote dependencies by simply refetching them. For remote dependencies we have to refetch if the revision in the manifest\nchanges or the upstream HEAD has changed (for branches and tags). Note For our purpose a tag is just a fancy branch name. Tags can be delete and\n modified afterwards, therefore they do not differ too much from branches\n from our perspective. For the latter case we only know if we actually fetch from the upstream URL. In case of local (and fetched remote) dependencies we have to read the package\nmanifest and compare its dependencies against our dependency tree, any change\nrequires updating the respective dependencies as well. Handling dependency compatibilties Currenly ignored. First come, first serve. Uses fpm_error iso_fortran_env fpm_toml fpm_settings fpm_manifest fpm_versioning fpm_strings jonquil fpm_downloader fpm_git fpm_environment fpm_filesystem fpm_manifest_preprocess fpm_manifest_dependency Contents Interfaces resize Derived Types dependency_node_t dependency_tree_t Subroutines check_and_read_pkg_data new_dependency_node new_dependency_tree Interfaces public interface resize Overloaded reallocation interface private pure subroutine resize_dependency_node(var, n) Reallocate a list of dependencies Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(inout), allocatable :: var (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size Derived Types type, public, extends( dependency_config_t ) :: dependency_node_t Dependency node in the projects dependency tree Components Type Visibility Attributes Name Initial logical, public :: cached = .false. Dependency was loaded from a cache logical, public :: done = .false. Dependency is handled type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency character(len=:), public, allocatable :: proj_dir Installation prefix of this dependencies type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. character(len=:), public, allocatable :: revision Checked out revision of the version control system logical, public :: update = .false. Dependency should be updated type( version_t ), public, allocatable :: version Actual version of this dependency Type-Bound Procedures procedure\n , public\n, :: get_from_registry Subroutine Get dependency from the registry. procedure\n , public\n, :: info Subroutine Print information on this instance procedure\n , public\n, :: register Subroutine Update dependency from project manifest. type, public :: dependency_tree_t Respresentation of a projects dependencies Read more… Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cache Cache file type( dependency_node_t ), public, allocatable :: dep (:) Flattend list of all dependencies character(len=:), public, allocatable :: dep_dir Installation prefix for dependencies integer, public :: ndep = 0 Number of currently registered dependencies integer, public :: unit = output_unit Unit for IO integer, public :: verbosity = 1 Verbosity of printout Type-Bound Procedures generic,\n public\n, :: add =>\n add_project, add_project_dependencies, add_dependencies, add_dependency, add_dependency_node Overload procedure to add new dependencies to the tree generic,\n public\n, :: dump =>\n dump_to_file, dump_to_unit, dump_to_toml Writing of dependency tree generic,\n public\n, :: find =>\n find_name Find a dependency in the tree procedure\n , public\n, :: finished Function Depedendncy resolution finished generic,\n public\n, :: has =>\n has_dependency True if entity can be found generic,\n public\n, :: load =>\n load_from_file, load_from_unit, load_from_toml Reading of dependency tree generic,\n public\n, :: resolve =>\n resolve_dependencies, resolve_dependency Resolve dependencies generic,\n public\n, :: update =>\n update_dependency, update_tree Update dependency tree Subroutines public subroutine check_and_read_pkg_data (json, node, download_url, version, error) Arguments Type Intent Optional Attributes Name type(json_object), intent(inout) :: json class( dependency_node_t ), intent(in) :: node character(len=:), intent(out), allocatable :: download_url type( version_t ), intent(out) :: version type( error_t ), intent(out), allocatable :: error public subroutine new_dependency_node (self, dependency, version, proj_dir, update) Create a new dependency node from a configuration Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(out) :: self Instance of the dependency node type( dependency_config_t ), intent(in) :: dependency Dependency configuration data type( version_t ), intent(in), optional :: version Version of the dependency character(len=*), intent(in), optional :: proj_dir Installation prefix of the dependency logical, intent(in), optional :: update Dependency should be updated public subroutine new_dependency_tree (self, verbosity, cache) Create a new dependency tree Arguments Type Intent Optional Attributes Name type( dependency_tree_t ), intent(out) :: self Instance of the dependency tree integer, intent(in), optional :: verbosity Verbosity of printout character(len=*), intent(in), optional :: cache Name of the cache file","tags":"","loc":"module/fpm_dependency.html"},{"title":"fpm_toml – Fortran-lang/fpm","text":"Interface to TOML processing library This module acts as a proxy to the toml-f public Fortran API and allows\n to selectively expose components from the library to fpm .\n The interaction with toml-f data types outside of this module should be\n limited to tables, arrays and key-lists, most of the necessary interactions\n are implemented in the building interface with the get_value and set_value procedures. This module allows to implement features necessary for fpm , which are\n not yet available in upstream toml-f . For more details on the library used see the TOML-Fortran developer pages. Uses tomlf fpm_strings fpm_error Contents Subroutines check_keys get_list read_package_file Subroutines public subroutine check_keys (table, valid_keys, error) Check if table contains only keys that are part of the list. If a key is\nfound that is not part of the list, an error is allocated. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: valid_keys (:) List of keys to check. type( error_t ), intent(out), allocatable :: error Error handling public subroutine get_list (table, key, list, error) Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Key to read from type( string_t ), intent(out), allocatable :: list (:) List of strings to read type( error_t ), intent(out), allocatable :: error Error handling public subroutine read_package_file (table, manifest, error) Process the configuration file to a TOML data structure Arguments Type Intent Optional Attributes Name type(toml_table), intent(out), allocatable :: table TOML data structure character(len=*), intent(in) :: manifest Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation","tags":"","loc":"module/fpm_toml.html"},{"title":"fpm_installer – Fortran-lang/fpm","text":"Implementation of an installer object. The installer provides a way to install objects to their respective directories\nin the installation prefix, a generic install command allows to install\nto any directory within the prefix. Uses fpm_error fpm_environment iso_fortran_env fpm_filesystem Contents Derived Types installer_t Subroutines new_installer Derived Types type, public :: installer_t Declaration of the installer type Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: bindir Binary dir relative to the installation prefix character(len=:), public, allocatable :: copy Command to copy objects into the installation prefix character(len=:), public, allocatable :: includedir Include directory relative to the installation prefix character(len=:), public, allocatable :: libdir Library directory relative to the installation prefix character(len=:), public, allocatable :: move Command to move objects into the installation prefix integer, public :: os Cached operating system character(len=:), public, allocatable :: prefix Path to installation directory integer, public :: unit = output_unit Output unit for informative printout integer, public :: verbosity = 1 Verbosity of the installer Type-Bound Procedures procedure\n , public\n, :: install Subroutine Install a generic file into a subdirectory in the installation prefix procedure\n , public\n, :: install_executable Subroutine Install an executable in its correct subdirectory procedure\n , public\n, :: install_header Subroutine Install a header/module in its correct subdirectory procedure\n , public\n, :: install_library Subroutine Install a library in its correct subdirectory procedure\n , public\n, :: make_dir Subroutine Create a new directory in the prefix, type-bound for unit testing purposes procedure\n , public\n, :: run Subroutine Run an installation command, type-bound for unit testing purposes Subroutines public subroutine new_installer (self, prefix, bindir, libdir, includedir, verbosity, copy, move) Create a new instance of an installer Arguments Type Intent Optional Attributes Name type( installer_t ), intent(out) :: self Instance of the installer character(len=*), intent(in), optional :: prefix Path to installation directory character(len=*), intent(in), optional :: bindir Binary dir relative to the installation prefix character(len=*), intent(in), optional :: libdir Library directory relative to the installation prefix character(len=*), intent(in), optional :: includedir Include directory relative to the installation prefix integer, intent(in), optional :: verbosity Verbosity of the installer character(len=*), intent(in), optional :: copy Copy command character(len=*), intent(in), optional :: move Move command","tags":"","loc":"module/fpm_installer.html"},{"title":"fpm_downloader – Fortran-lang/fpm","text":"Uses fpm_error fpm_versioning jonquil fpm_filesystem fpm_strings Contents Derived Types downloader_t Derived Types type, public :: downloader_t This type could be entirely avoided but it is quite practical because it can be mocked for testing. Type-Bound Procedures procedure\n , public\n, nopass :: get_file Subroutine procedure\n , public\n, nopass :: get_pkg_data Subroutine procedure\n , public\n, nopass :: unpack Subroutine procedure\n , public\n, nopass :: upload_form Subroutine","tags":"","loc":"module/fpm_downloader.html"},{"title":"fpm_manifest – Fortran-lang/fpm","text":"Package configuration data. This module provides the necessary procedure to translate a TOML document\nto the corresponding Fortran type, while verifying it with respect to\nits schema. Additionally, the required data types for users of this module are reexported\nto hide the actual implementation details. Uses fpm_manifest_example fpm_manifest_executable fpm_error fpm_toml fpm_manifest_test fpm_strings fpm_manifest_library fpm_manifest_package fpm_filesystem fpm_environment fpm_manifest_preprocess fpm_manifest_dependency Contents Subroutines default_example default_executable default_library default_test get_package_data Subroutines public subroutine default_example (self, name) Populate test in case we find the default example/ directory Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package public subroutine default_executable (self, name) Populate executable in case we find the default app directory Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package public subroutine default_library (self) Populate library in case we find the default src directory Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library meta data public subroutine default_test (self, name) Populate test in case we find the default test/ directory Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package public subroutine get_package_data (package, file, error, apply_defaults) Obtain package meta data from a configuation file Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: package Parsed package meta data character(len=*), intent(in) :: file Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation logical, intent(in), optional :: apply_defaults Apply package defaults (uses file system operations)","tags":"","loc":"module/fpm_manifest.html"},{"title":"fpm_release – Fortran-lang/fpm","text":"Release parameters Module fpm_release contains public constants storing this build’s unique version IDs Uses fpm_versioning fpm_error Contents Functions fpm_version Functions public function fpm_version () Return the current fpm version from fpm_version_ID as a version type Arguments None Return Value type( version_t )","tags":"","loc":"module/fpm_release.html"},{"title":"fpm_error – Fortran-lang/fpm","text":"Implementation of basic error handling. Uses fpm_strings iso_fortran_env Contents Derived Types error_t Functions bad_name_error Subroutines fatal_error file_not_found_error file_parse_error fpm_stop syntax_error Derived Types type, public :: error_t Data type defining an error Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: message Error message Functions public function bad_name_error (error, label, name) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: label Error message label to add to message character(len=*), intent(in) :: name name value to check Return Value logical Subroutines public subroutine fatal_error (error, message) Generic fatal runtime error Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message public subroutine file_not_found_error (error, file_name) Error created when a file is missing or not found Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of the missing file public subroutine file_parse_error (error, file_name, message, line_num, line_string, line_col) Error created when file parsing fails Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of file character(len=*), intent(in) :: message Parse error message integer, intent(in), optional :: line_num Line number of parse error character(len=*), intent(in), optional :: line_string Line context string integer, intent(in), optional :: line_col Line context column public subroutine fpm_stop (value, message) Arguments Type Intent Optional Attributes Name integer, intent(in) :: value value to use on STOP character(len=*), intent(in) :: message Error message public subroutine syntax_error (error, message) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message","tags":"","loc":"module/fpm_error.html"},{"title":"fpm_cmd_install – Fortran-lang/fpm","text":"Uses fpm_backend fpm_error iso_fortran_env fpm_command_line fpm_model fpm_manifest fpm_targets fpm_installer fpm_filesystem fpm fpm_strings Contents Subroutines cmd_install Subroutines public subroutine cmd_install (settings) Entry point for the fpm-install subcommand Arguments Type Intent Optional Attributes Name type( fpm_install_settings ), intent(inout) :: settings Representation of the command line settings","tags":"","loc":"module/fpm_cmd_install.html"},{"title":"fpm_cmd_update – Fortran-lang/fpm","text":"Uses fpm_error fpm_command_line fpm_dependency fpm_manifest fpm_filesystem Contents Subroutines cmd_update Subroutines public subroutine cmd_update (settings) Entry point for the update subcommand Arguments Type Intent Optional Attributes Name type( fpm_update_settings ), intent(in) :: settings Representation of the command line arguments","tags":"","loc":"module/fpm_cmd_update.html"},{"title":"fpm_cmd_new – Fortran-lang/fpm","text":"Definition of the “new” subcommand A type of the general command base class fpm_cmd_settings was created for the “new” subcommand ==> type fpm_new_settings .\n This procedure read the values that were set on the command line\n from this type to decide what actions to take. It is virtually self-contained and so independant of the rest of the\n application that it could function as a separate program. The “new” subcommand options currently consist of a SINGLE top\n directory name to create that must have a name that is an\n allowable Fortran variable name. That should have been ensured\n by the command line processing before this procedure is called.\n So basically this routine has already had the options vetted and\n just needs to conditionally create a few files. As described in the documentation it will selectively\n create the subdirectories app/, test/, src/, and example/\n and populate them with sample files. It also needs to create an initial manifest file “fpm.toml”. It then calls the system command “git init”. It should test for file existence and not overwrite existing\n files and inform the user if there were conflicts. Any changes should be reflected in the documentation in fpm_command_line.f90 FUTURE\n A filename like “.” would need system commands or a standard routine\n like realpath(3c) to process properly. Perhaps allow more than one name on a single command. It is an arbitrary\n restriction based on a concensus preference, not a required limitation. Initially the name of the directory is used as the module name in the\n src file so it must be an allowable Fortran variable name. If there are\n complaints about it it might be changed. Handling unicode at this point\n might be problematic as not all current compilers handle it. Other\n utilities like content trackers (ie. git) or repositories like github\n might also have issues with alternative names or names with spaces, etc.\n So for the time being it seems prudent to encourage simple ASCII top directory\n names (similiar to the primary programming language Fortran itself). Should be able to create or pull more complicated initial examples\n based on various templates. It should place or mention other relevant\n documents such as a description of the manifest file format in user hands;\n or how to access registered packages and local packages,\n although some other command might provide that (and the help command should\n be the first go-to for a CLI utility). Uses fpm_error fpm_command_line iso_fortran_env fpm_environment fpm_filesystem fpm_strings Contents Subroutines cmd_new Subroutines public subroutine cmd_new (settings) TOP DIRECTORY NAME PROCESSING\nsee if requested new directory already exists and process appropriately\ntemporarily change to new directory as a test. NB: System dependent Arguments Type Intent Optional Attributes Name type( fpm_new_settings ), intent(in) :: settings","tags":"","loc":"module/fpm_cmd_new.html"},{"title":"fpm_cmd_publish – Fortran-lang/fpm","text":"Upload a package to the registry using the publish command. To upload a package you need to provide a token that will be linked to your username and created for a namespace.\nThe token can be obtained from the registry website. It can be used as fpm publish --token . Uses fpm_model fpm_error fpm_command_line fpm_settings fpm_versioning fpm_manifest fpm fpm_git fpm_filesystem fpm_downloader fpm_strings Contents Subroutines cmd_publish Subroutines public subroutine cmd_publish (settings) The publish command first builds the root package to obtain all the relevant information such as the\npackage version. It then creates a tarball of the package and uploads it to the registry.\nChecks before uploading the package. Arguments Type Intent Optional Attributes Name type( fpm_publish_settings ), intent(inout) :: settings","tags":"","loc":"module/fpm_cmd_publish.html"},{"title":"fpm_manifest_install – Fortran-lang/fpm","text":"Implementation of the installation configuration. An install table can currently have the following fields library = bool Uses fpm_error fpm_toml Contents Derived Types install_config_t Subroutines new_install_config Derived Types type, public :: install_config_t Configuration data for installation Components Type Visibility Attributes Name Initial logical, public :: library Install library with this project Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_install_config (self, table, error) Create a new installation configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( install_config_t ), intent(out) :: self Instance of the install configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_install.html"},{"title":"fpm_manifest_example – Fortran-lang/fpm","text":"Implementation of the meta data for an example. The example data structure is effectively a decorated version of an executable\n and shares most of its properties, except for the defaults and can be\n handled under most circumstances just like any other executable. A example table can currently have the following fields [[ example ]] name = \"string\" source-dir = \"path\" main = \"file\" link = [ \"lib\" ] [example.dependencies] Uses fpm_error fpm_manifest_executable fpm_manifest_dependency fpm_toml Contents Derived Types example_config_t Subroutines new_example Derived Types type, public, extends( executable_config_t ) :: example_config_t Configuation meta data for an example Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_example (self, table, error) Construct a new example configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the example configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_example.html"},{"title":"fpm_manifest_test – Fortran-lang/fpm","text":"Implementation of the meta data for a test. The test data structure is effectively a decorated version of an executable\n and shares most of its properties, except for the defaults and can be\n handled under most circumstances just like any other executable. A test table can currently have the following fields [[ test ]] name = \"string\" source-dir = \"path\" main = \"file\" link = [ \"lib\" ] [test.dependencies] Uses fpm_error fpm_manifest_executable fpm_manifest_dependency fpm_toml Contents Derived Types test_config_t Subroutines new_test Derived Types type, public, extends( executable_config_t ) :: test_config_t Configuation meta data for an test Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_test (self, table, error) Construct a new test configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the test configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_test.html"},{"title":"fpm_manifest_fortran – Fortran-lang/fpm","text":"Uses fpm_error fpm_toml Contents Derived Types fortran_config_t Subroutines new_fortran_config Derived Types type, public :: fortran_config_t Configuration data for Fortran Components Type Visibility Attributes Name Initial logical, public :: implicit_external Enable implicit external interfaces logical, public :: implicit_typing Enable default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Subroutines public subroutine new_fortran_config (self, table, error) Construct a new build configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( fortran_config_t ), intent(out) :: self Instance of the fortran configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_fortran.html"},{"title":"fpm_manifest_dependency – Fortran-lang/fpm","text":"Implementation of the meta data for dependencies. A dependency table can currently have the following fields [dependencies] \"dep1\" = { git = \"url\" } \"dep2\" = { git = \"url\" , branch = \"name\" } \"dep3\" = { git = \"url\" , tag = \"name\" } \"dep4\" = { git = \"url\" , rev = \"sha1\" } \"dep0\" = { path = \"path\" } To reduce the amount of boilerplate code this module provides two constructors\n for dependency types, one basic for an actual dependency (inline) table\n and another to collect all dependency objects from a dependencies table,\n which is handling the allocation of the objects and is forwarding the\n individual dependency tables to their respective constructors.\n The usual entry point should be the constructor for the super table. This objects contains a target to retrieve required fpm projects to\n build the target declaring the dependency.\n Resolving a dependency will result in obtaining a new package configuration\n data for the respective project. Uses fpm_error fpm_toml fpm_versioning fpm_strings fpm_git fpm_environment fpm_filesystem fpm_manifest_preprocess fpm_manifest_metapackages Contents Derived Types dependency_config_t Functions manifest_has_changed Subroutines new_dependencies new_dependency Derived Types type, public :: dependency_config_t Configuration meta data for a dependency Components Type Visibility Attributes Name Initial type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Functions public function manifest_has_changed (cached, manifest, verbosity, iunit) result(has_changed) Check if two dependency configurations are different Read more… Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: cached Two instances of the dependency configuration class( dependency_config_t ), intent(in) :: manifest Two instances of the dependency configuration integer, intent(in) :: verbosity Log verbosity integer, intent(in) :: iunit Log verbosity Return Value logical Subroutines public subroutine new_dependencies (deps, table, root, meta, error) Construct new dependency array from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out), allocatable :: deps (:) Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( metapackage_config_t ), intent(out), optional :: meta (optional) metapackages type( error_t ), intent(out), allocatable :: error Error handling public subroutine new_dependency (self, table, root, error) Construct a new dependency configuration from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out) :: self Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_dependency.html"},{"title":"fpm_manifest_package – Fortran-lang/fpm","text":"Define the package data containing the meta data from the configuration file. The package data defines a Fortran type corresponding to the respective\n TOML document, after creating it from a package file no more interaction\n with the TOML document is required. Every configuration type provides it custom constructor (prefixed with new_ )\n and knows how to deserialize itself from a TOML document.\n To ensure we find no untracked content in the package file all keywords are\n checked and possible entries have to be explicitly allowed in the check function.\n If entries are mutally exclusive or interdependent inside the current table\n the check function is required to enforce this schema on the data structure. The package file root allows the following keywords name = \"string\" version = \"string\" license = \"string\" author = \"string\" maintainer = \"string\" copyright = \"string\" [library] [dependencies] [dev-dependencies] [profiles] [build] [install] [fortran] [[ executable ]] [[ example ]] [[ test ]] [extra] Uses fpm_manifest_example fpm_manifest_fortran fpm_manifest_install fpm_manifest_profile fpm_manifest_executable fpm_manifest_test fpm_manifest_metapackages fpm_error fpm_toml fpm_versioning fpm_manifest_library fpm_manifest_build fpm_filesystem fpm_manifest_preprocess fpm_manifest_dependency Contents Derived Types package_config_t Subroutines new_package Derived Types type, public :: package_config_t Package meta data Components Type Visibility Attributes Name Initial type( build_config_t ), public :: build Build configuration data type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data type( dependency_config_t ), public, allocatable :: dev_dependency (:) Development dependency meta data type( example_config_t ), public, allocatable :: example (:) Example meta data type( executable_config_t ), public, allocatable :: executable (:) Executable meta data type( fortran_config_t ), public :: fortran Fortran meta data type( install_config_t ), public :: install Installation configuration data type( library_config_t ), public, allocatable :: library Library meta data character(len=:), public, allocatable :: license License meta data type( metapackage_config_t ), public :: meta Metapackage data character(len=:), public, allocatable :: name Name of the package type( preprocess_config_t ), public, allocatable :: preprocess (:) Preprocess meta data type( profile_config_t ), public, allocatable :: profiles (:) Profiles meta data type( test_config_t ), public, allocatable :: test (:) Test meta data type( version_t ), public :: version Package version Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_package (self, table, root, error) Construct a new package configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: self Instance of the package configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_package.html"},{"title":"fpm_manifest_executable – Fortran-lang/fpm","text":"Implementation of the meta data for an executables. An executable table can currently have the following fields [[ executable ]] name = \"string\" source-dir = \"path\" main = \"file\" link = [ \"lib\" ] [executable.dependencies] Uses fpm_error fpm_strings fpm_manifest_dependency fpm_toml Contents Derived Types executable_config_t Subroutines new_executable Derived Types type, public :: executable_config_t Configuation meta data for an executable Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_executable (self, table, error) Construct a new executable configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_executable.html"},{"title":"fpm_manifest_metapackages – Fortran-lang/fpm","text":"Implementation of the metapackage configuration data. A metapackage table can currently have the following fields [metapackages] fpm = \"0.1.0\" openmp = bool stdlib = bool Uses fpm_environment fpm_error fpm_toml Contents Derived Types metapackage_config_t metapackage_request_t Functions is_meta_package Subroutines new_meta_config new_meta_request Derived Types type, public :: metapackage_config_t Configuration data for metapackages Components Type Visibility Attributes Name Initial type( metapackage_request_t ), public :: minpack fortran-lang minpack type( metapackage_request_t ), public :: mpi Request MPI support type( metapackage_request_t ), public :: openmp Request OpenMP support type( metapackage_request_t ), public :: stdlib Request stdlib support type, public :: metapackage_request_t Configuration data for a single metapackage request Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: name Metapackage name logical, public :: on = .false. Request flag character(len=:), public, allocatable :: version Version Specification string Functions public function is_meta_package (key) Check local schema for allowed entries Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: key Instance of the TOML data structure Return Value logical Subroutines public subroutine new_meta_config (self, table, meta_allowed, error) Construct a new build configuration from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( metapackage_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in) :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling public subroutine new_meta_request (self, key, table, meta_allowed, error) Construct a new metapackage request from the dependencies table Read more… Arguments Type Intent Optional Attributes Name type( metapackage_request_t ), intent(out) :: self character(len=*), intent(in) :: key The package name type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in), optional :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_metapackages.html"},{"title":"fpm_manifest_library – Fortran-lang/fpm","text":"Implementation of the meta data for libraries. A library table can currently have the following fields [library] source-dir = \"path\" include-dir = [ \"path1\" , \"path2\" ] build-script = \"file\" Uses fpm_strings fpm_error fpm_toml Contents Derived Types library_config_t Subroutines new_library Derived Types type, public :: library_config_t Configuration meta data for a library Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: build_script Alternative build script to be invoked type( string_t ), public, allocatable :: include_dir (:) Include path prefix character(len=:), public, allocatable :: source_dir Source path prefix Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_library (self, table, error) Construct a new library configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_library.html"},{"title":"fpm_manifest_profile – Fortran-lang/fpm","text":"Implementation of the meta data for compiler flag profiles. A profiles table can currently have the following subtables:\n Profile names - any string, if omitted, flags are appended to all matching profiles\n Compiler - any from the following list, omitting it yields an error “gfortran” “ifort” “ifx” “pgfortran” “nvfortran” “flang” “caf” “f95” “lfortran” “lfc” “nagfor” “crayftn” “xlf90” “ftn95” OS - any from the following list, if omitted, the profile is used if and only\n if there is no profile perfectly matching the current configuration “linux” “macos” “windows” “cygwin” “solaris” “freebsd” “openbsd” “unknown” Each of the subtables currently supports the following fields: [profiles.debug.gfortran.linux] flags = \"-Wall -g -Og\" c-flags = \"-g O1\" cxx-flags = \"-g O1\" link-time-flags = \"-xlinkopt\" files = { \"hello_world.f90\" = \"-Wall -O3\" } Uses fpm_error fpm_toml fpm_filesystem fpm_environment fpm_strings Contents Variables DEFAULT_COMPILER OS_ALL path Derived Types file_scope_flag profile_config_t Functions get_default_profiles info_profile new_profile Subroutines find_profile get_flags info match_os_type new_profiles traverse_compilers traverse_oss traverse_oss_for_size validate_compiler_name validate_os_name validate_profile_table Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: DEFAULT_COMPILER = 'gfortran' Name of the default compiler integer, public, parameter :: OS_ALL = -1 character(len=:), public, allocatable :: path Derived Types type, public :: file_scope_flag Type storing file name - file scope compiler flags pairs Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: file_name Name of the file character(len=:), public, allocatable :: flags File scope flags type, public :: profile_config_t Configuration meta data for a profile Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags C compiler flags character(len=:), public, allocatable :: compiler Name of the compiler character(len=:), public, allocatable :: cxx_flags C++ compiler flags type( file_scope_flag ), public, allocatable :: file_scope_flags (:) File scope flags character(len=:), public, allocatable :: flags Fortran compiler flags logical, public :: is_built_in Is this profile one of the built-in ones? character(len=:), public, allocatable :: link_time_flags Link time compiler flags integer, public :: os_type Value repesenting OS character(len=:), public, allocatable :: profile_name Name of the profile Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Functions public function get_default_profiles (error) result(default_profiles) Construct an array of built-in profiles Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Error handling Return Value type( profile_config_t ), allocatable, (:) public function info_profile (profile) result(s) Print a representation of profile_config_t Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in) :: profile Profile to be represented Return Value character(len=:), allocatable String representation of given profile public function new_profile (profile_name, compiler, os_type, flags, c_flags, cxx_flags, link_time_flags, file_scope_flags, is_built_in) result(profile) Construct a new profile configuration from a TOML data structure Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: profile_name Name of the profile character(len=*), intent(in) :: compiler Name of the compiler integer, intent(in) :: os_type Type of the OS character(len=*), intent(in), optional :: flags Fortran compiler flags character(len=*), intent(in), optional :: c_flags C compiler flags character(len=*), intent(in), optional :: cxx_flags C++ compiler flags character(len=*), intent(in), optional :: link_time_flags Link time compiler flags type( file_scope_flag ), intent(in), optional :: file_scope_flags (:) File scope flags logical, intent(in), optional :: is_built_in Is this profile one of the built-in ones? Return Value type( profile_config_t ) Subroutines public subroutine find_profile (profiles, profile_name, compiler, os_type, found_matching, chosen_profile) Look for profile with given configuration in array profiles Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in), allocatable :: profiles (:) Array of profiles character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler Name of compiler integer, intent(in) :: os_type Type of operating system (enum) logical, intent(out) :: found_matching Boolean value containing true if matching profile was found type( profile_config_t ), intent(out) :: chosen_profile Last matching profile in the profiles array public subroutine get_flags (profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid) Look for flags, c-flags, link-time-flags key-val pairs\nand files table in a given table and create new profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler integer, intent(in) :: os_type OS type type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles logical, intent(in) :: os_valid Was called with valid operating system public subroutine info (self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: self Instance of the profile configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout public subroutine match_os_type (os_name, os_type) Match os_type enum to a lowercase string with name of OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of operating system integer, intent(out) :: os_type Enum representing type of OS public subroutine new_profiles (profiles, table, error) Construct new profiles array from a TOML data structure Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(out), allocatable :: profiles (:) Instance of the dependency configuration type(toml_table), intent(inout), target :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine traverse_compilers (profile_name, comp_list, table, error, profiles_size, profiles, profindex) Traverse compiler tables Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile type(toml_key), intent(in), allocatable :: comp_list (:) List of OSs in table with profile name given type(toml_table), intent(in), pointer :: table Table containing compiler tables type( error_t ), intent(out), allocatable :: error Error handling integer, intent(inout), optional :: profiles_size Number of profiles in list of profiles type( profile_config_t ), intent(inout), optional, allocatable :: profiles (:) List of profiles integer, intent(inout), optional :: profindex Index in the list of profiles public subroutine traverse_oss (profile_name, compiler_name, os_list, table, profiles, profindex, error) Traverse operating system tables to obtain profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles type( error_t ), intent(out), allocatable :: error Error handling public subroutine traverse_oss_for_size (profile_name, compiler_name, os_list, table, profiles_size, error) Traverse operating system tables to obtain number of profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables integer, intent(inout) :: profiles_size Number of profiles in list of profiles type( error_t ), intent(out), allocatable :: error Error handling public subroutine validate_compiler_name (compiler_name, is_valid) Check if compiler name is a valid compiler name Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: compiler_name Name of a compiler logical, intent(out) :: is_valid Boolean value of whether compiler_name is valid or not public subroutine validate_os_name (os_name, is_valid) Check if os_name is a valid name of a supported OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of an operating system logical, intent(out) :: is_valid Boolean value of whether os_name is valid or not public subroutine validate_profile_table (profile_name, compiler_name, key_list, table, error, os_valid) Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in) :: os_valid Was called with valid operating system","tags":"","loc":"module/fpm_manifest_profile.html"},{"title":"fpm_manifest_preprocess – Fortran-lang/fpm","text":"Implementation of the meta data for preprocessing. A preprocess table can currently have the following fields [preprocess] [preprocess.cpp] suffixes = [ \"F90\" , \"f90\" ] directories = [ \"src/feature1\" , \"src/models\" ] macros = [] Uses fpm_strings fpm_error fpm_toml Contents Interfaces operator(==) Derived Types preprocess_config_t Subroutines new_preprocess_config new_preprocessors Interfaces public interface operator(==) private function preprocess_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: this class( preprocess_config_t ), intent(in) :: that Return Value logical Derived Types type, public :: preprocess_config_t Configuration meta data for a preprocessor Components Type Visibility Attributes Name Initial type( string_t ), public, allocatable :: directories (:) Directories to search for files to be preprocessed type( string_t ), public, allocatable :: macros (:) Macros to be defined for the preprocessor character(len=:), public, allocatable :: name Name of the preprocessor type( string_t ), public, allocatable :: suffixes (:) Suffixes of the files to be preprocessed Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_preprocess_config (self, table, error) Construct a new preprocess configuration from TOML data structure Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out) :: self Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure. type( error_t ), intent(out), allocatable :: error Error handling public subroutine new_preprocessors (preprocessors, table, error) Construct new preprocess array from a TOML data structure. Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out), allocatable :: preprocessors (:) Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_preprocess.html"},{"title":"fpm_manifest_build – Fortran-lang/fpm","text":"Implementation of the build configuration data. A build table can currently have the following fields [build] auto-executables = bool auto-examples = bool auto-tests = bool link = [ \"lib\" ] Uses fpm_strings fpm_error fpm_toml Contents Derived Types build_config_t Subroutines new_build_config Derived Types type, public :: build_config_t Configuration data for build Components Type Visibility Attributes Name Initial logical, public :: auto_examples Automatic discovery of examples logical, public :: auto_executables Automatic discovery of executables logical, public :: auto_tests Automatic discovery of tests type( string_t ), public, allocatable :: external_modules (:) External modules to use type( string_t ), public, allocatable :: link (:) Libraries to link against logical, public :: module_naming = .false. Enforcing of package module names type( string_t ), public :: module_prefix Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_build_config (self, table, package_name, error) Construct a new build configuration from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( build_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: package_name Package name type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_build.html"},{"title":"main – Fortran-lang/fpm","text":"Uses fpm_error iso_fortran_env fpm_command_line fpm_cmd_install fpm_cmd_new fpm_cmd_update fpm_os fpm_filesystem fpm fpm_cmd_publish Contents Variables cmd_settings error project_root pwd_start pwd_working working_dir Functions has_manifest Subroutines get_working_dir handle_error Source Code main Variables Type Attributes Name Initial class( fpm_cmd_settings ), allocatable :: cmd_settings type( error_t ), allocatable :: error character(len=:), allocatable :: project_root character(len=:), allocatable :: pwd_start character(len=:), allocatable :: pwd_working character(len=:), allocatable :: working_dir Functions function has_manifest (dir) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical Subroutines subroutine get_working_dir (settings, working_dir_) Save access to working directory in settings, in case setting have not been allocated Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(in), optional :: settings character(len=:), intent(out), allocatable :: working_dir_ subroutine handle_error (error_) Arguments Type Intent Optional Attributes Name type( error_t ), intent(in), optional :: error_ Source Code program main use , intrinsic :: iso_fortran_env , only : error_unit , output_unit use fpm_command_line , only : & fpm_cmd_settings , & fpm_new_settings , & fpm_build_settings , & fpm_run_settings , & fpm_test_settings , & fpm_install_settings , & fpm_update_settings , & fpm_clean_settings , & fpm_publish_settings , & get_command_line_settings use fpm_error , only : error_t use fpm_filesystem , only : exists , parent_dir , join_path use fpm , only : cmd_build , cmd_run , cmd_clean use fpm_cmd_install , only : cmd_install use fpm_cmd_new , only : cmd_new use fpm_cmd_update , only : cmd_update use fpm_cmd_publish , only : cmd_publish use fpm_os , only : change_directory , get_current_directory implicit none class ( fpm_cmd_settings ), allocatable :: cmd_settings type ( error_t ), allocatable :: error character ( len = :), allocatable :: pwd_start , pwd_working , working_dir , project_root call get_command_line_settings ( cmd_settings ) call get_current_directory ( pwd_start , error ) call handle_error ( error ) call get_working_dir ( cmd_settings , working_dir ) if ( allocated ( working_dir )) then ! Change working directory if requested if ( len_trim ( working_dir ) > 0 ) then call change_directory ( working_dir , error ) call handle_error ( error ) call get_current_directory ( pwd_working , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // pwd_working // \"'\" else pwd_working = pwd_start end if else pwd_working = pwd_start end if select type ( settings => cmd_settings ) type is ( fpm_new_settings ) class default if (. not . has_manifest ( pwd_working )) then project_root = pwd_working do while (. not . has_manifest ( project_root )) working_dir = parent_dir ( project_root ) if ( len ( working_dir ) == 0 ) exit project_root = working_dir end do if ( has_manifest ( project_root )) then call change_directory ( project_root , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // project_root // \"'\" end if end if end select select type ( settings => cmd_settings ) type is ( fpm_new_settings ) call cmd_new ( settings ) type is ( fpm_build_settings ) call cmd_build ( settings ) type is ( fpm_run_settings ) call cmd_run ( settings , test = . false .) type is ( fpm_test_settings ) call cmd_run ( settings , test = . true .) type is ( fpm_install_settings ) call cmd_install ( settings ) type is ( fpm_update_settings ) call cmd_update ( settings ) type is ( fpm_clean_settings ) call cmd_clean ( settings ) type is ( fpm_publish_settings ) call cmd_publish ( settings ) end select if ( allocated ( project_root )) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // project_root // \"'\" end if if ( pwd_start /= pwd_working ) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // pwd_working // \"'\" end if contains function has_manifest ( dir ) character ( len =* ), intent ( in ) :: dir logical :: has_manifest has_manifest = exists ( join_path ( dir , \"fpm.toml\" )) end function has_manifest subroutine handle_error ( error_ ) type ( error_t ), optional , intent ( in ) :: error_ if ( present ( error_ )) then write ( error_unit , '(\"[Error]\", 1x, a)' ) error_ % message stop 1 end if end subroutine handle_error !> Save access to working directory in settings, in case setting have not been allocated subroutine get_working_dir ( settings , working_dir_ ) class ( fpm_cmd_settings ), optional , intent ( in ) :: settings character ( len = :), allocatable , intent ( out ) :: working_dir_ if ( present ( settings )) then working_dir_ = settings % working_dir end if end subroutine get_working_dir end program main","tags":"","loc":"program/main.html"},{"title":"fpm_settings.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_settings Source Code fpm_settings.f90 Source Code !> Manages global settings which are defined in the global config file. module fpm_settings use fpm_filesystem , only : exists , join_path , get_local_prefix , is_absolute_path , mkdir use fpm_environment , only : os_is_unix use fpm_error , only : error_t , fatal_error use fpm_toml , only : toml_table , toml_error , toml_stat , get_value , toml_load , check_keys use fpm_os , only : get_current_directory , change_directory , get_absolute_path , convert_to_absolute_path implicit none private public :: fpm_global_settings , get_global_settings , get_registry_settings , official_registry_base_url character ( * ), parameter :: official_registry_base_url = 'https://registry-apis.vercel.app' character ( * ), parameter :: default_config_file_name = 'config.toml' type :: fpm_global_settings !> Path to the global config file excluding the file name. character ( len = :), allocatable :: path_to_config_folder !> Name of the global config file. The default is `config.toml`. character ( len = :), allocatable :: config_file_name !> Registry configs. type ( fpm_registry_settings ), allocatable :: registry_settings contains procedure :: has_custom_location , full_path , path_to_config_folder_or_empty end type type :: fpm_registry_settings !> The path to the local registry. If allocated, the local registry !> will be used instead of the remote registry and replaces the !> local cache. character ( len = :), allocatable :: path !> The URL to the remote registry. Can be used to get packages !> from the official or a custom registry. character ( len = :), allocatable :: url !> The path to the cache folder. If not specified, the default cache !> folders are `~/.local/share/fpm/dependencies` on Unix and !> `%APPDATA%\\local\\fpm\\dependencies` on Windows. !> Cannot be used together with `path`. character ( len = :), allocatable :: cache_path end type contains !> Obtain global settings from the global config file. subroutine get_global_settings ( global_settings , error ) !> Global settings to be obtained. type ( fpm_global_settings ), intent ( inout ) :: global_settings !> Error reading config file. type ( error_t ), allocatable , intent ( out ) :: error !> TOML table to be filled with global config settings. type ( toml_table ), allocatable :: table !> Error parsing to TOML table. type ( toml_error ), allocatable :: parse_error type ( toml_table ), pointer :: registry_table integer :: stat ! Use custom path to the config file if it was specified. if ( global_settings % has_custom_location ()) then ! Throw error if folder doesn't exist. if (. not . exists ( global_settings % path_to_config_folder )) then call fatal_error ( error , \"Folder not found: '\" // global_settings % path_to_config_folder // \"'.\" ); return end if ! Throw error if the file doesn't exist. if (. not . exists ( global_settings % full_path ())) then call fatal_error ( error , \"File not found: '\" // global_settings % full_path () // \"'.\" ); return end if ! Make sure that the path to the global config file is absolute. call convert_to_absolute_path ( global_settings % path_to_config_folder , error ) if ( allocated ( error )) return else ! Use default path if it wasn't specified. if ( os_is_unix ()) then global_settings % path_to_config_folder = join_path ( get_local_prefix (), 'share' , 'fpm' ) else global_settings % path_to_config_folder = join_path ( get_local_prefix (), 'fpm' ) end if ! Use default file name. global_settings % config_file_name = default_config_file_name ! Apply default registry settings and return if config file doesn't exist. if (. not . exists ( global_settings % full_path ())) then call use_default_registry_settings ( global_settings ); return end if end if ! Load into TOML table. call toml_load ( table , global_settings % full_path (), error = parse_error ) if ( allocated ( parse_error )) then allocate ( error ); call move_alloc ( parse_error % message , error % message ); return end if call get_value ( table , 'registry' , registry_table , requested = . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading registry from config file '\" // & & global_settings % full_path () // \"'.\" ); return end if ! A registry table was found. if ( associated ( registry_table )) then call get_registry_settings ( registry_table , global_settings , error ) else call use_default_registry_settings ( global_settings ) end if end !> Default registry settings are typically applied if the config file doesn't exist or no registry table was found in !> the global config file. subroutine use_default_registry_settings ( global_settings ) type ( fpm_global_settings ), intent ( inout ) :: global_settings allocate ( global_settings % registry_settings ) global_settings % registry_settings % url = official_registry_base_url global_settings % registry_settings % cache_path = join_path ( global_settings % path_to_config_folder_or_empty (), & & 'dependencies' ) end !> Read registry settings from the global config file. subroutine get_registry_settings ( table , global_settings , error ) !> The [registry] subtable from the global config file. type ( toml_table ), target , intent ( inout ) :: table !> The global settings which can be filled with the registry settings. type ( fpm_global_settings ), intent ( inout ) :: global_settings !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: path , url , cache_path integer :: stat !> List of valid keys for the dependency table. character ( * ), dimension ( * ), parameter :: valid_keys = [ character ( 10 ) :: & & 'path' , & & 'url' , & & 'cache_path' & & ] call check_keys ( table , valid_keys , error ) if ( allocated ( error )) return allocate ( global_settings % registry_settings ) if ( table % has_key ( 'path' )) then call get_value ( table , 'path' , path , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading registry path: '\" // path // \"'.\" ); return end if end if if ( allocated ( path )) then if ( is_absolute_path ( path )) then global_settings % registry_settings % path = path else ! Get canonical, absolute path on both Unix and Windows. call get_absolute_path ( join_path ( global_settings % path_to_config_folder_or_empty (), path ), & & global_settings % registry_settings % path , error ) if ( allocated ( error )) return ! Check if the path to the registry exists. if (. not . exists ( global_settings % registry_settings % path )) then call fatal_error ( error , \"Directory '\" // global_settings % registry_settings % path // & & \"' doesn't exist.\" ); return end if end if end if if ( table % has_key ( 'url' )) then call get_value ( table , 'url' , url , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading registry url: '\" // url // \"'.\" ); return end if end if if ( allocated ( url )) then ! Throw error when both path and url were provided. if ( allocated ( path )) then call fatal_error ( error , 'Do not provide both path and url to the registry.' ); return end if global_settings % registry_settings % url = url else if (. not . allocated ( path )) then global_settings % registry_settings % url = official_registry_base_url end if if ( table % has_key ( 'cache_path' )) then call get_value ( table , 'cache_path' , cache_path , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading path to registry cache: '\" // cache_path // \"'.\" ); return end if end if if ( allocated ( cache_path )) then ! Throw error when both path and cache_path were provided. if ( allocated ( path )) then call fatal_error ( error , \"Do not provide both 'path' and 'cache_path'.\" ); return end if if ( is_absolute_path ( cache_path )) then if (. not . exists ( cache_path )) call mkdir ( cache_path ) global_settings % registry_settings % cache_path = cache_path else cache_path = join_path ( global_settings % path_to_config_folder_or_empty (), cache_path ) if (. not . exists ( cache_path )) call mkdir ( cache_path ) ! Get canonical, absolute path on both Unix and Windows. call get_absolute_path ( cache_path , global_settings % registry_settings % cache_path , error ) if ( allocated ( error )) return end if else if (. not . allocated ( path )) then global_settings % registry_settings % cache_path = & join_path ( global_settings % path_to_config_folder_or_empty (), 'dependencies' ) end if end !> True if the global config file is not at the default location. elemental logical function has_custom_location ( self ) class ( fpm_global_settings ), intent ( in ) :: self has_custom_location = allocated ( self % path_to_config_folder ) . and . allocated ( self % config_file_name ) if (. not . has_custom_location ) return has_custom_location = len_trim ( self % path_to_config_folder ) > 0 . and . len_trim ( self % config_file_name ) > 0 end !> The full path to the global config file. function full_path ( self ) result ( result ) class ( fpm_global_settings ), intent ( in ) :: self character ( len = :), allocatable :: result result = join_path ( self % path_to_config_folder_or_empty (), self % config_file_name ) end !> The path to the global config directory. pure function path_to_config_folder_or_empty ( self ) class ( fpm_global_settings ), intent ( in ) :: self character ( len = :), allocatable :: path_to_config_folder_or_empty if ( allocated ( self % path_to_config_folder )) then path_to_config_folder_or_empty = self % path_to_config_folder else path_to_config_folder_or_empty = \"\" end if end end","tags":"","loc":"sourcefile/fpm_settings.f90.html"},{"title":"fpm_model.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_model Source Code fpm_model.f90 Source Code !># The fpm package model !> !> Defines the fpm model data types which encapsulate all information !> required to correctly build a package and its dependencies. !> !> The process (see `[[build_model(subroutine)]]`) for generating a valid `[[fpm_model]]` involves !> source files discovery ([[fpm_sources]]) and parsing ([[fpm_source_parsing]]). !> !> Once a valid `[[fpm_model]]` has been constructed, it may be passed to `[[fpm_targets:targets_from_sources]]` to !> generate a list of build targets for the backend. !> !>### Enumerations !> !> __Source type:__ `FPM_UNIT_*` !> Describes the type of source file — determines build target generation !> !> The logical order of precedence for assigning `unit_type` is as follows: !> !>``` !> if source-file contains program then !> unit_type = FPM_UNIT_PROGRAM !> else if source-file contains non-module subroutine/function then !> unit_type = FPM_UNIT_SUBPROGRAM !> else if source-file contains submodule then !> unit_type = FPM_UNIT_SUBMODULE !> else if source-file contains module then !> unit_type = FPM_UNIT_MODULE !> end if !>``` !> !> @note A source file is only designated `FPM_UNIT_MODULE` if it **only** contains modules - no non-module subprograms. !> (This allows tree-shaking/pruning of build targets based on unused module dependencies.) !> !> __Source scope:__ `FPM_SCOPE_*` !> Describes the scoping rules for using modules — controls module dependency resolution !> module fpm_model use iso_fortran_env , only : int64 use fpm_compiler , only : compiler_t , archiver_t , debug use fpm_dependency , only : dependency_tree_t use fpm_strings , only : string_t , str , len_trim implicit none private public :: fpm_model_t , srcfile_t , show_model , fortran_features_t public :: FPM_UNIT_UNKNOWN , FPM_UNIT_PROGRAM , FPM_UNIT_MODULE , & FPM_UNIT_SUBMODULE , FPM_UNIT_SUBPROGRAM , FPM_UNIT_CSOURCE , & FPM_UNIT_CHEADER , FPM_SCOPE_UNKNOWN , FPM_SCOPE_LIB , & FPM_SCOPE_DEP , FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST , & FPM_UNIT_CPPSOURCE !> Source type unknown integer , parameter :: FPM_UNIT_UNKNOWN = - 1 !> Source contains a fortran program integer , parameter :: FPM_UNIT_PROGRAM = 1 !> Source **only** contains one or more fortran modules integer , parameter :: FPM_UNIT_MODULE = 2 !> Source contains one or more fortran submodules integer , parameter :: FPM_UNIT_SUBMODULE = 3 !> Source contains one or more fortran subprogram not within modules integer , parameter :: FPM_UNIT_SUBPROGRAM = 4 !> Source type is c source file integer , parameter :: FPM_UNIT_CSOURCE = 5 !> Source type is c header file integer , parameter :: FPM_UNIT_CHEADER = 6 !> Souce type is c++ source file. integer , parameter :: FPM_UNIT_CPPSOURCE = 7 !> Source has no module-use scope integer , parameter :: FPM_SCOPE_UNKNOWN = - 1 !> Module-use scope is library/dependency modules only integer , parameter :: FPM_SCOPE_LIB = 1 !> Module-use scope is library/dependency modules only integer , parameter :: FPM_SCOPE_DEP = 2 !> Module-use scope is library/dependency and app modules integer , parameter :: FPM_SCOPE_APP = 3 !> Module-use scope is library/dependency and test modules integer , parameter :: FPM_SCOPE_TEST = 4 integer , parameter :: FPM_SCOPE_EXAMPLE = 5 !> Enabled Fortran language features type :: fortran_features_t !> Use default implicit typing logical :: implicit_typing = . false . !> Use implicit external interface logical :: implicit_external = . false . !> Form to use for all Fortran sources character (:), allocatable :: source_form end type fortran_features_t !> Type for describing a source file type srcfile_t !> File path relative to cwd character (:), allocatable :: file_name !> Name of executable for FPM_UNIT_PROGRAM character (:), allocatable :: exe_name !> Target module-use scope integer :: unit_scope = FPM_SCOPE_UNKNOWN !> Modules provided by this source file (lowerstring) type ( string_t ), allocatable :: modules_provided (:) !> Type of source unit integer :: unit_type = FPM_UNIT_UNKNOWN !> Parent modules (submodules only) type ( string_t ), allocatable :: parent_modules (:) !> Modules USEd by this source file (lowerstring) type ( string_t ), allocatable :: modules_used (:) !> Files INCLUDEd by this source file type ( string_t ), allocatable :: include_dependencies (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Current hash integer ( int64 ) :: digest end type srcfile_t !> Type for describing a single package type package_t !> Name of package character (:), allocatable :: name !> Array of sources type ( srcfile_t ), allocatable :: sources (:) !> List of macros. type ( string_t ), allocatable :: macros (:) !> Package version number. character (:), allocatable :: version !> Module naming conventions logical :: enforce_module_names !> Prefix for all module names type ( string_t ) :: module_prefix !> Language features type ( fortran_features_t ) :: features end type package_t !> Type describing everything required to build !> the root package and its dependencies. type :: fpm_model_t !> Name of root package character (:), allocatable :: package_name !> Array of packages (including the root package) type ( package_t ), allocatable :: packages (:) !> Compiler object type ( compiler_t ) :: compiler !> Archiver object type ( archiver_t ) :: archiver !> Command line flags passed to fortran for compilation character (:), allocatable :: fortran_compile_flags !> Command line flags passed to C for compilation character (:), allocatable :: c_compile_flags !> Command line flags passed to C++ for compilation character (:), allocatable :: cxx_compile_flags !> Command line flags passed to the linker character (:), allocatable :: link_flags !> Base directory for build character (:), allocatable :: build_prefix !> Include directories type ( string_t ), allocatable :: include_dirs (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> External modules used type ( string_t ), allocatable :: external_modules (:) !> Project dependencies type ( dependency_tree_t ) :: deps !> Whether tests should be added to the build list logical :: include_tests = . true . !> Whether module names should be prefixed with the package name logical :: enforce_module_names = . false . !> Prefix for all module names type ( string_t ) :: module_prefix end type fpm_model_t contains function info_package ( p ) result ( s ) ! Returns representation of package_t type ( package_t ), intent ( in ) :: p character (:), allocatable :: s integer :: i s = s // 'package_t(' s = s // 'name=\"' // p % name // '\"' s = s // ', sources=[' do i = 1 , size ( p % sources ) s = s // info_srcfile ( p % sources ( i )) if ( i < size ( p % sources )) s = s // \", \" end do s = s // \"]\" ! Print module naming convention s = s // ', enforce_module_names=\"' // merge ( 'T' , 'F' , p % enforce_module_names ) // '\"' ! Print custom prefix if ( p % enforce_module_names . and . len_trim ( p % module_prefix ) > 0 ) & s = s // ', custom_prefix=\"' // p % module_prefix % s // '\"' s = s // \")\" end function info_package function info_srcfile ( source ) result ( s ) type ( srcfile_t ), intent ( in ) :: source character (:), allocatable :: s integer :: i !type srcfile_t s = \"srcfile_t(\" ! character(:), allocatable :: file_name s = s // 'file_name=\"' // source % file_name // '\"' ! character(:), allocatable :: exe_name s = s // ', exe_name=\"' // source % exe_name // '\"' ! integer :: unit_scope = FPM_SCOPE_UNKNOWN s = s // \", unit_scope=\" select case ( source % unit_scope ) case ( FPM_SCOPE_UNKNOWN ) s = s // \"FPM_SCOPE_UNKNOWN\" case ( FPM_SCOPE_LIB ) s = s // \"FPM_SCOPE_LIB\" case ( FPM_SCOPE_DEP ) s = s // \"FPM_SCOPE_DEP\" case ( FPM_SCOPE_APP ) s = s // \"FPM_SCOPE_APP\" case ( FPM_SCOPE_TEST ) s = s // \"FPM_SCOPE_TEST\" case ( FPM_SCOPE_EXAMPLE ) s = s // \"FPM_SCOPE_EXAMPLE\" case default s = s // \"INVALID\" end select ! type(string_t), allocatable :: modules_provided(:) s = s // \", modules_provided=[\" do i = 1 , size ( source % modules_provided ) s = s // '\"' // source % modules_provided ( i )% s // '\"' if ( i < size ( source % modules_provided )) s = s // \", \" end do s = s // \"]\" s = s // \", parent_modules=[\" do i = 1 , size ( source % parent_modules ) s = s // '\"' // source % parent_modules ( i )% s // '\"' if ( i < size ( source % parent_modules )) s = s // \", \" end do s = s // \"]\" ! integer :: unit_type = FPM_UNIT_UNKNOWN s = s // \", unit_type=\" select case ( source % unit_type ) case ( FPM_UNIT_UNKNOWN ) s = s // \"FPM_UNIT_UNKNOWN\" case ( FPM_UNIT_PROGRAM ) s = s // \"FPM_UNIT_PROGRAM\" case ( FPM_UNIT_MODULE ) s = s // \"FPM_UNIT_MODULE\" case ( FPM_UNIT_SUBMODULE ) s = s // \"FPM_UNIT_SUBMODULE\" case ( FPM_UNIT_SUBPROGRAM ) s = s // \"FPM_UNIT_SUBPROGRAM\" case ( FPM_UNIT_CSOURCE ) s = s // \"FPM_UNIT_CSOURCE\" case ( FPM_UNIT_CPPSOURCE ) s = s // \"FPM_UNIT_CPPSOURCE\" case ( FPM_UNIT_CHEADER ) s = s // \"FPM_UNIT_CHEADER\" case default s = s // \"INVALID\" end select ! type(string_t), allocatable :: modules_used(:) s = s // \", modules_used=[\" do i = 1 , size ( source % modules_used ) s = s // '\"' // source % modules_used ( i )% s // '\"' if ( i < size ( source % modules_used )) s = s // \", \" end do s = s // \"]\" ! type(string_t), allocatable :: include_dependencies(:) s = s // \", include_dependencies=[\" do i = 1 , size ( source % include_dependencies ) s = s // '\"' // source % include_dependencies ( i )% s // '\"' if ( i < size ( source % include_dependencies )) s = s // \", \" end do s = s // \"]\" ! type(string_t), allocatable :: link_libraries(:) s = s // \", link_libraries=[\" do i = 1 , size ( source % link_libraries ) s = s // '\"' // source % link_libraries ( i )% s // '\"' if ( i < size ( source % link_libraries )) s = s // \", \" end do s = s // \"]\" ! integer(int64) :: digest s = s // \", digest=\" // str ( source % digest ) !end type srcfile_t s = s // \")\" end function info_srcfile function info_srcfile_short ( source ) result ( s ) ! Prints a shortened version of srcfile_t type ( srcfile_t ), intent ( in ) :: source character (:), allocatable :: s s = \"srcfile_t(\" s = s // 'file_name=\"' // source % file_name // '\"' s = s // \", ...)\" end function info_srcfile_short function info_model ( model ) result ( s ) type ( fpm_model_t ), intent ( in ) :: model character (:), allocatable :: s integer :: i !type :: fpm_model_t s = \"fpm_model_t(\" ! character(:), allocatable :: package_name s = s // 'package_name=\"' // model % package_name // '\"' ! type(srcfile_t), allocatable :: sources(:) s = s // \", packages=[\" do i = 1 , size ( model % packages ) s = s // info_package ( model % packages ( i )) if ( i < size ( model % packages )) s = s // \", \" end do s = s // \"]\" s = s // ', compiler=(' // debug ( model % compiler ) // ')' s = s // ', archiver=(' // debug ( model % archiver ) // ')' ! character(:), allocatable :: fortran_compile_flags s = s // ', fortran_compile_flags=\"' // model % fortran_compile_flags // '\"' s = s // ', c_compile_flags=\"' // model % c_compile_flags // '\"' s = s // ', cxx_compile_flags=\"' // model % cxx_compile_flags // '\"' s = s // ', link_flags=\"' // model % link_flags // '\"' s = s // ', build_prefix=\"' // model % build_prefix // '\"' ! type(string_t), allocatable :: link_libraries(:) s = s // \", link_libraries=[\" do i = 1 , size ( model % link_libraries ) s = s // '\"' // model % link_libraries ( i )% s // '\"' if ( i < size ( model % link_libraries )) s = s // \", \" end do s = s // \"]\" ! type(string_t), allocatable :: external_modules(:) s = s // \", external_modules=[\" do i = 1 , size ( model % external_modules ) s = s // '\"' // model % external_modules ( i )% s // '\"' if ( i < size ( model % external_modules )) s = s // \", \" end do s = s // \"]\" ! type(dependency_tree_t) :: deps ! TODO: print `dependency_tree_t` properly, which should become part of the ! model, not imported from another file s = s // \", deps=dependency_tree_t(...)\" ! Print module naming convention s = s // ', enforce_module_names=\"' // merge ( 'T' , 'F' , model % enforce_module_names ) // '\"' ! Print custom prefix if ( model % enforce_module_names . and . len_trim ( model % module_prefix ) > 0 ) & s = s // ', custom_prefix=\"' // model % module_prefix % s // '\"' !end type fpm_model_t s = s // \")\" end function info_model subroutine show_model ( model ) ! Prints a human readable representation of the Model type ( fpm_model_t ), intent ( in ) :: model print * , info_model ( model ) end subroutine show_model end module fpm_model","tags":"","loc":"sourcefile/fpm_model.f90.html"},{"title":"fpm_backend_console.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_backend_console Source Code fpm_backend_console.f90 Source Code !># Build Backend Console !> This module provides a lightweight implementation for printing to the console !> and updating previously-printed console lines. It used by `[[fpm_backend_output]]` !> for pretty-printing build status and progress. !> !> @note The implementation for updating previous lines relies on no other output !> going to `stdout`/`stderr` except through the `console_t` object provided. !> !> @note All write statements to `stdout` are enclosed within OpenMP `critical` regions !> module fpm_backend_console use iso_fortran_env , only : stdout => output_unit implicit none private public :: console_t public :: LINE_RESET public :: COLOR_RED , COLOR_GREEN , COLOR_YELLOW , COLOR_RESET character ( len =* ), parameter :: ESC = char ( 27 ) !> Escape code for erasing current line character ( len =* ), parameter :: LINE_RESET = ESC // \"[2K\" // ESC // \"[1G\" !> Escape code for moving up one line character ( len =* ), parameter :: LINE_UP = ESC // \"[1A\" !> Escape code for moving down one line character ( len =* ), parameter :: LINE_DOWN = ESC // \"[1B\" !> Escape code for red foreground color character ( len =* ), parameter :: COLOR_RED = ESC // \"[31m\" !> Escape code for green foreground color character ( len =* ), parameter :: COLOR_GREEN = ESC // \"[32m\" !> Escape code for yellow foreground color character ( len =* ), parameter :: COLOR_YELLOW = ESC // \"[93m\" !> Escape code to reset foreground color character ( len =* ), parameter :: COLOR_RESET = ESC // \"[0m\" !> Console object type console_t !> Number of lines printed integer :: n_line = 1 contains !> Write a single line to the console procedure :: write_line => console_write_line !> Update a previously-written console line procedure :: update_line => console_update_line end type console_t contains !> Write a single line to the standard output subroutine console_write_line ( console , str , line , advance ) !> Console object class ( console_t ), intent ( inout ) :: console !> String to write character ( * ), intent ( in ) :: str !> Integer needed to later update console line integer , intent ( out ), optional :: line !> Advancing output (print newline?) logical , intent ( in ), optional :: advance character ( 3 ) :: adv adv = \"yes\" if ( present ( advance )) then if (. not . advance ) then adv = \"no\" end if end if !$omp critical if ( present ( line )) then line = console % n_line end if write ( stdout , '(A)' , advance = trim ( adv )) LINE_RESET // str if ( adv == \"yes\" ) then console % n_line = console % n_line + 1 end if !$omp end critical end subroutine console_write_line !> Overwrite a previously-written line in standard output subroutine console_update_line ( console , line_no , str ) !> Console object class ( console_t ), intent ( in ) :: console !> Integer output from `[[console_write_line]]` integer , intent ( in ) :: line_no !> New string to overwrite line character ( * ), intent ( in ) :: str integer :: n !$omp critical n = console % n_line - line_no ! Step back to line write ( stdout , '(A)' , advance = \"no\" ) repeat ( LINE_UP , n ) // LINE_RESET write ( stdout , '(A)' , advance = \"no\" ) str ! Step forward to end write ( stdout , '(A)' , advance = \"no\" ) repeat ( LINE_DOWN , n ) // LINE_RESET !$omp end critical end subroutine console_update_line end module fpm_backend_console","tags":"","loc":"sourcefile/fpm_backend_console.f90.html"},{"title":"fpm_compiler.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_compiler Source Code fpm_compiler.F90 Source Code !># Define compiler command options !! !! This module defines compiler options to use for the debug and release builds. ! vendor Fortran C Module output Module include OpenMP Free for OSS ! compiler compiler directory directory ! Gnu gfortran gcc -J -I -fopenmp X ! Intel ifort icc -module -I -qopenmp X ! Intel(Windows) ifort icc /module:path /I /Qopenmp X ! Intel oneAPI ifx icx -module -I -qopenmp X ! PGI pgfortran pgcc -module -I -mp X ! NVIDIA nvfortran nvc -module -I -mp X ! LLVM flang flang clang -module -I -mp X ! LFortran lfortran --- -J -I --openmp X ! Lahey/Futjitsu lfc ? -M -I -openmp ? ! NAG nagfor ? -mdir -I -openmp x ! Cray crayftn craycc -J -I -homp ? ! IBM xlf90 ? -qmoddir -I -qsmp X ! Oracle/Sun ? ? -moddir= -M -xopenmp ? ! Silverfrost FTN95 ftn95 ? ? /MOD_PATH ? ? ! Elbrus ? lcc -J -I -fopenmp ? ! Hewlett Packard ? ? ? ? ? discontinued ! Watcom ? ? ? ? ? discontinued ! PathScale ? ? -module -I -mp discontinued ! G95 ? ? -fmod= -I -fopenmp discontinued ! Open64 ? ? -module -I -mp discontinued ! Unisys ? ? ? ? ? discontinued module fpm_compiler use , intrinsic :: iso_fortran_env , only : stderr => error_unit use fpm_environment , only : & get_os_type , & OS_LINUX , & OS_MACOS , & OS_WINDOWS , & OS_CYGWIN , & OS_SOLARIS , & OS_FREEBSD , & OS_OPENBSD , & OS_UNKNOWN use fpm_filesystem , only : join_path , basename , get_temp_filename , delete_file , unix_path , & & getline , run use fpm_strings , only : split , string_cat , string_t , str_ends_with , str_begins_with_str use fpm_error , only : error_t implicit none public :: compiler_t , new_compiler , archiver_t , new_archiver , get_macros public :: debug enum , bind ( C ) enumerator :: & id_unknown , & id_gcc , & id_f95 , & id_caf , & id_intel_classic_nix , & id_intel_classic_mac , & id_intel_classic_windows , & id_intel_llvm_nix , & id_intel_llvm_windows , & id_intel_llvm_unknown , & id_pgi , & id_nvhpc , & id_nag , & id_flang , & id_flang_new , & id_f18 , & id_ibmxl , & id_cray , & id_lahey , & id_lfortran end enum integer , parameter :: compiler_enum = kind ( id_unknown ) !> Definition of compiler object type :: compiler_t !> Identifier of the compiler integer ( compiler_enum ) :: id = id_unknown !> Path to the Fortran compiler character ( len = :), allocatable :: fc !> Path to the C compiler character ( len = :), allocatable :: cc !> Path to the C++ compiler character ( len = :), allocatable :: cxx !> Print all commands logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Get default compiler flags procedure :: get_default_flags !> Get flag for module output directories procedure :: get_module_flag !> Get flag for include directories procedure :: get_include_flag !> Get feature flag procedure :: get_feature_flag !> Get flags for the main linking command procedure :: get_main_flags !> Compile a Fortran object procedure :: compile_fortran !> Compile a C object procedure :: compile_c !> Compile a CPP object procedure :: compile_cpp !> Link executable procedure :: link !> Check whether compiler is recognized procedure :: is_unknown !> Check whether this is an Intel compiler procedure :: is_intel !> Check whether this is a GNU compiler procedure :: is_gnu !> Enumerate libraries, based on compiler and platform procedure :: enumerate_libraries !> Return compiler name procedure :: name => compiler_name end type compiler_t !> Definition of archiver object type :: archiver_t !> Path to archiver character ( len = :), allocatable :: ar !> Use response files to pass arguments logical :: use_response_file = . false . !> Print all command logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Create static archive procedure :: make_archive end type archiver_t !> Create debug printout interface debug module procedure :: debug_compiler module procedure :: debug_archiver end interface debug character ( * ), parameter :: & flag_gnu_coarray = \" -fcoarray=single\" , & flag_gnu_backtrace = \" -fbacktrace\" , & flag_gnu_opt = \" -O3 -funroll-loops\" , & flag_gnu_debug = \" -g\" , & flag_gnu_pic = \" -fPIC\" , & flag_gnu_warn = \" -Wall -Wextra\" , & flag_gnu_check = \" -fcheck=bounds -fcheck=array-temps\" , & flag_gnu_limit = \" -fmax-errors=1\" , & flag_gnu_external = \" -Wimplicit-interface\" , & flag_gnu_openmp = \" -fopenmp\" , & flag_gnu_no_implicit_typing = \" -fimplicit-none\" , & flag_gnu_no_implicit_external = \" -Werror=implicit-interface\" , & flag_gnu_free_form = \" -ffree-form\" , & flag_gnu_fixed_form = \" -ffixed-form\" character ( * ), parameter :: & flag_pgi_backslash = \" -Mbackslash\" , & flag_pgi_traceback = \" -traceback\" , & flag_pgi_debug = \" -g\" , & flag_pgi_check = \" -Mbounds -Mchkptr -Mchkstk\" , & flag_pgi_warn = \" -Minform=inform\" , & flag_pgi_openmp = \" -mp\" , & flag_pgi_free_form = \" -Mfree\" , & flag_pgi_fixed_form = \" -Mfixed\" character ( * ), parameter :: & flag_ibmxl_backslash = \" -qnoescape\" character ( * ), parameter :: & flag_intel_backtrace = \" -traceback\" , & flag_intel_warn = \" -warn all\" , & flag_intel_check = \" -check all\" , & flag_intel_debug = \" -O0 -g\" , & flag_intel_fp = \" -fp-model precise -pc64\" , & flag_intel_align = \" -align all\" , & flag_intel_limit = \" -error-limit 1\" , & flag_intel_pthread = \" -reentrancy threaded\" , & flag_intel_nogen = \" -nogen-interfaces\" , & flag_intel_byterecl = \" -assume byterecl\" , & flag_intel_openmp = \" -qopenmp\" , & flag_intel_free_form = \" -free\" , & flag_intel_fixed_form = \" -fixed\" , & flag_intel_standard_compliance = \" -standard-semantics\" character ( * ), parameter :: & flag_intel_backtrace_win = \" /traceback\" , & flag_intel_warn_win = \" /warn:all\" , & flag_intel_check_win = \" /check:all\" , & flag_intel_debug_win = \" /Od /Z7\" , & flag_intel_fp_win = \" /fp:precise\" , & flag_intel_align_win = \" /align:all\" , & flag_intel_limit_win = \" /error-limit:1\" , & flag_intel_pthread_win = \" /reentrancy:threaded\" , & flag_intel_nogen_win = \" /nogen-interfaces\" , & flag_intel_byterecl_win = \" /assume:byterecl\" , & flag_intel_openmp_win = \" /Qopenmp\" , & flag_intel_free_form_win = \" /free\" , & flag_intel_fixed_form_win = \" /fixed\" , & flag_intel_standard_compliance_win = \" /standard-semantics\" character ( * ), parameter :: & flag_nag_coarray = \" -coarray=single\" , & flag_nag_pic = \" -PIC\" , & flag_nag_check = \" -C\" , & flag_nag_debug = \" -g -O0\" , & flag_nag_opt = \" -O4\" , & flag_nag_backtrace = \" -gline\" , & flag_nag_openmp = \" -openmp\" , & flag_nag_free_form = \" -free\" , & flag_nag_fixed_form = \" -fixed\" , & flag_nag_no_implicit_typing = \" -u\" character ( * ), parameter :: & flag_lfortran_opt = \" --fast\" , & flag_lfortran_openmp = \" --openmp\" , & flag_lfortran_implicit_typing = \" --implicit-typing\" , & flag_lfortran_implicit_external = \" --allow-implicit-interface\" , & flag_lfortran_fixed_form = \" --fixed-form\" character ( * ), parameter :: & flag_cray_no_implicit_typing = \" -dl\" , & flag_cray_implicit_typing = \" -el\" , & flag_cray_fixed_form = \" -ffixed\" , & flag_cray_free_form = \" -ffree\" contains function get_default_flags ( self , release ) result ( flags ) class ( compiler_t ), intent ( in ) :: self logical , intent ( in ) :: release character ( len = :), allocatable :: flags if ( release ) then call get_release_compile_flags ( self % id , flags ) else call get_debug_compile_flags ( self % id , flags ) end if end function get_default_flags subroutine get_release_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_gcc ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_nvhpc ) flags = & flag_pgi_backslash case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_classic_mac ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_classic_windows ) flags = & & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_intel_llvm_nix ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_llvm_windows ) flags = & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_nag ) flags = & flag_nag_opt // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = & flag_lfortran_opt end select end subroutine get_release_compile_flags subroutine get_debug_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace case ( id_gcc ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & ' -Wno-maybe-uninitialized -Wno-uninitialized' // & flag_gnu_backtrace case ( id_nvhpc ) flags = & flag_pgi_warn // & flag_pgi_backslash // & flag_pgi_check // & flag_pgi_traceback case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_classic_mac ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_classic_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win // & flag_intel_backtrace_win case ( id_intel_llvm_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_llvm_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_nag ) flags = & flag_nag_debug // & flag_nag_check // & flag_nag_backtrace // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = \"\" end select end subroutine get_debug_compile_flags pure subroutine set_cpp_preprocessor_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( inout ) :: flags character ( len = :), allocatable :: flag_cpp_preprocessor !> Modify the flag_cpp_preprocessor on the basis of the compiler. select case ( id ) case default flag_cpp_preprocessor = \"\" case ( id_caf , id_gcc , id_f95 , id_nvhpc ) flag_cpp_preprocessor = \"-cpp\" case ( id_intel_classic_windows , id_intel_llvm_windows ) flag_cpp_preprocessor = \"/fpp\" case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , id_nag ) flag_cpp_preprocessor = \"-fpp\" case ( id_lfortran ) flag_cpp_preprocessor = \"--cpp\" end select flags = flag_cpp_preprocessor // flags end subroutine set_cpp_preprocessor_flags !> This function will parse and read the macros list and !> return them as defined flags. function get_macros ( id , macros_list , version ) result ( macros ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( in ) :: version type ( string_t ), allocatable , intent ( in ) :: macros_list (:) character ( len = :), allocatable :: macros character ( len = :), allocatable :: macro_definition_symbol character (:), allocatable :: valued_macros (:) integer :: i if (. not . allocated ( macros_list )) then macros = \"\" return end if !> Set macro defintion symbol on the basis of compiler used select case ( id ) case default macro_definition_symbol = \" -D\" case ( id_intel_classic_windows , id_intel_llvm_windows ) macro_definition_symbol = \" /D\" end select !> Check if macros are not allocated. if (. not . allocated ( macros )) then macros = \"\" end if do i = 1 , size ( macros_list ) !> Split the macro name and value. call split ( macros_list ( i )% s , valued_macros , delimiters = \"=\" ) if ( size ( valued_macros ) > 1 ) then !> Check if the value of macro starts with '{' character. if ( str_begins_with_str ( trim ( valued_macros ( size ( valued_macros ))), \"{\" )) then !> Check if the value of macro ends with '}' character. if ( str_ends_with ( trim ( valued_macros ( size ( valued_macros ))), \"}\" )) then !> Check if the string contains \"version\" as substring. if ( index ( valued_macros ( size ( valued_macros )), \"version\" ) /= 0 ) then !> These conditions are placed in order to ensure proper spacing between the macros. macros = macros // macro_definition_symbol // trim ( valued_macros ( 1 )) // '=' // version cycle end if end if end if end if macros = macros // macro_definition_symbol // macros_list ( i )% s end do end function get_macros function get_include_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-I \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_nvhpc , id_pgi , & & id_flang , id_flang_new , id_f18 , & & id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix , id_lahey , id_nag , id_ibmxl , & & id_lfortran ) flags = \"-I \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/I\" // path end select end function get_include_flag function get_module_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-module \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_lfortran ) flags = \"-J \" // path case ( id_nvhpc , id_pgi , id_flang ) flags = \"-module \" // path case ( id_flang_new , id_f18 ) flags = \"-module-dir \" // path case ( id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix ) flags = \"-module \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/module:\" // path case ( id_lahey ) flags = \"-M \" // path case ( id_nag ) flags = \"-mdir \" // path case ( id_ibmxl ) flags = \"-qmoddir \" // path end select end function get_module_flag function get_feature_flag ( self , feature ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: feature character ( len = :), allocatable :: flags flags = \"\" select case ( feature ) case ( \"no-implicit-typing\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_typing case ( id_nag ) flags = flag_nag_no_implicit_typing case ( id_cray ) flags = flag_cray_no_implicit_typing end select case ( \"implicit-typing\" ) select case ( self % id ) case ( id_cray ) flags = flag_cray_implicit_typing case ( id_lfortran ) flags = flag_lfortran_implicit_typing end select case ( \"no-implicit-external\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_external end select case ( \"implicit-external\" ) select case ( self % id ) case ( id_lfortran ) flags = flag_lfortran_implicit_external end select case ( \"free-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_free_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_free_form case ( id_nag ) flags = flag_nag_free_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_free_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_free_form_win case ( id_cray ) flags = flag_cray_free_form end select case ( \"fixed-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_fixed_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_fixed_form case ( id_nag ) flags = flag_nag_fixed_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_fixed_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_fixed_form_win case ( id_cray ) flags = flag_cray_fixed_form case ( id_lfortran ) flags = flag_lfortran_fixed_form end select case ( \"default-form\" ) continue case default error stop \"Unknown feature '\" // feature // \"'\" end select end function get_feature_flag !> Get special flags for the main linker subroutine get_main_flags ( self , language , flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: language character ( len = :), allocatable , intent ( out ) :: flags flags = \"\" select case ( language ) case ( \"fortran\" ) flags = \"\" case ( \"c\" ) ! If the main program is on a C/C++ source, the Intel Fortran compiler requires option ! -nofor-main to avoid \"duplicate main\" errors. ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case ( \"c++\" , \"cpp\" , \"cxx\" ) select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case default error stop \"Unknown language '\" // language // '\", try \"fortran\", \"c\", \"c++\"' end select end subroutine get_main_flags subroutine get_default_c_compiler ( f_compiler , c_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: c_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) c_compiler = 'icc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) c_compiler = 'icx' case ( id_flang , id_flang_new , id_f18 ) c_compiler = 'clang' case ( id_ibmxl ) c_compiler = 'xlc' case ( id_lfortran ) c_compiler = 'cc' case ( id_gcc ) c_compiler = 'gcc' case default ! Fall-back to using Fortran compiler c_compiler = f_compiler end select end subroutine get_default_c_compiler !> Get C++ Compiler. subroutine get_default_cxx_compiler ( f_compiler , cxx_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: cxx_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) cxx_compiler = 'icpc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) cxx_compiler = 'icpx' case ( id_flang , id_flang_new , id_f18 ) cxx_compiler = 'clang++' case ( id_ibmxl ) cxx_compiler = 'xlc++' case ( id_lfortran ) cxx_compiler = 'cc' case ( id_gcc ) cxx_compiler = 'g++' case default ! Fall-back to using Fortran compiler cxx_compiler = f_compiler end select end subroutine get_default_cxx_compiler function get_compiler_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id character ( len = :), allocatable :: full_command , full_command_parts (:), command , output integer :: stat , io ! Check whether we are dealing with an MPI compiler wrapper first if ( check_compiler ( compiler , \"mpifort\" ) & & . or . check_compiler ( compiler , \"mpif90\" ) & & . or . check_compiler ( compiler , \"mpif77\" )) then output = get_temp_filename () call run ( compiler // \" -show > \" // output // \" 2>&1\" , & & echo = . false ., exitstat = stat ) if ( stat == 0 ) then open ( file = output , newunit = io , iostat = stat ) if ( stat == 0 ) call getline ( io , full_command , stat ) close ( io , iostat = stat ) ! If we get a command from the wrapper, we will try to identify it call split ( full_command , full_command_parts , delimiters = ' ' ) if ( size ( full_command_parts ) > 0 ) then command = trim ( full_command_parts ( 1 )) endif if ( allocated ( command )) then id = get_id ( command ) if ( id /= id_unknown ) return end if end if end if id = get_id ( compiler ) end function get_compiler_id function get_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id if ( check_compiler ( compiler , \"gfortran\" )) then id = id_gcc return end if if ( check_compiler ( compiler , \"f95\" )) then id = id_f95 return end if if ( check_compiler ( compiler , \"caf\" )) then id = id_caf return end if if ( check_compiler ( compiler , \"ifort\" )) then select case ( get_os_type ()) case default id = id_intel_classic_nix case ( OS_MACOS ) id = id_intel_classic_mac case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_classic_windows end select return end if if ( check_compiler ( compiler , \"ifx\" )) then select case ( get_os_type ()) case default id = id_intel_llvm_nix case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_llvm_windows end select return end if if ( check_compiler ( compiler , \"nvfortran\" )) then id = id_nvhpc return end if if ( check_compiler ( compiler , \"pgfortran\" ) & & . or . check_compiler ( compiler , \"pgf90\" ) & & . or . check_compiler ( compiler , \"pgf95\" )) then id = id_pgi return end if if ( check_compiler ( compiler , \"nagfor\" )) then id = id_nag return end if if ( check_compiler ( compiler , \"flang-new\" )) then id = id_flang_new return end if if ( check_compiler ( compiler , \"f18\" )) then id = id_f18 return end if if ( check_compiler ( compiler , \"flang\" )) then id = id_flang return end if if ( check_compiler ( compiler , \"xlf90\" )) then id = id_ibmxl return end if if ( check_compiler ( compiler , \"crayftn\" )) then id = id_cray return end if if ( check_compiler ( compiler , \"lfc\" )) then id = id_lahey return end if if ( check_compiler ( compiler , \"lfortran\" )) then id = id_lfortran return end if id = id_unknown end function get_id function check_compiler ( compiler , expected ) result ( match ) character ( len =* ), intent ( in ) :: compiler character ( len =* ), intent ( in ) :: expected logical :: match match = compiler == expected if (. not . match ) then match = index ( basename ( compiler ), expected ) > 0 end if end function check_compiler pure function is_unknown ( self ) class ( compiler_t ), intent ( in ) :: self logical :: is_unknown is_unknown = self % id == id_unknown end function is_unknown pure logical function is_intel ( self ) class ( compiler_t ), intent ( in ) :: self is_intel = any ( self % id == [ id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows , & id_intel_llvm_nix , id_intel_llvm_windows , id_intel_llvm_unknown ]) end function is_intel pure logical function is_gnu ( self ) class ( compiler_t ), intent ( in ) :: self is_gnu = any ( self % id == [ id_f95 , id_gcc , id_caf ]) end function is_gnu !> !> Enumerate libraries, based on compiler and platform !> function enumerate_libraries ( self , prefix , libs ) result ( r ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: prefix type ( string_t ), intent ( in ) :: libs (:) character ( len = :), allocatable :: r if ( self % id == id_intel_classic_windows . or . & self % id == id_intel_llvm_windows ) then r = prefix // \" \" // string_cat ( libs , \".lib \" ) // \".lib\" else r = prefix // \" -l\" // string_cat ( libs , \" -l\" ) end if end function enumerate_libraries !> Create new compiler instance subroutine new_compiler ( self , fc , cc , cxx , echo , verbose ) !> New instance of the compiler type ( compiler_t ), intent ( out ) :: self !> Fortran compiler name or path character ( len =* ), intent ( in ) :: fc !> C compiler name or path character ( len =* ), intent ( in ) :: cc !> C++ Compiler name or path character ( len =* ), intent ( in ) :: cxx !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose self % id = get_compiler_id ( fc ) self % echo = echo self % verbose = verbose self % fc = fc if ( len_trim ( cc ) > 0 ) then self % cc = cc else call get_default_c_compiler ( self % fc , self % cc ) end if if ( len_trim ( cxx ) > 0 ) then self % cxx = cxx else call get_default_cxx_compiler ( self % fc , self % cxx ) end if end subroutine new_compiler !> Create new archiver instance subroutine new_archiver ( self , ar , echo , verbose ) !> New instance of the archiver type ( archiver_t ), intent ( out ) :: self !> User provided archiver command character ( len =* ), intent ( in ) :: ar !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose integer :: estat , os_type character ( len =* ), parameter :: arflags = \" -rs \" , libflags = \" /OUT:\" if ( len_trim ( ar ) > 0 ) then ! Check first for ar-like commands if ( check_compiler ( ar , \"ar\" )) then self % ar = ar // arflags end if ! Check for lib-like commands if ( check_compiler ( ar , \"lib\" )) then self % ar = ar // libflags end if ! Fallback and assume ar-like behaviour self % ar = ar // arflags else os_type = get_os_type () if ( os_type /= OS_WINDOWS . and . os_type /= OS_UNKNOWN ) then self % ar = \"ar\" // arflags else call execute_command_line ( \"ar --version > \" // get_temp_filename () // \" 2>&1\" , & & exitstat = estat ) if ( estat /= 0 ) then self % ar = \"lib\" // libflags else self % ar = \"ar\" // arflags end if end if end if self % use_response_file = os_type == OS_WINDOWS self % echo = echo self % verbose = verbose end subroutine new_archiver !> Compile a Fortran object subroutine compile_fortran ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % fc // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_fortran !> Compile a C object subroutine compile_c ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % cc // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_c !> Compile a CPP object subroutine compile_cpp ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % cxx // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_cpp !> Link an executable subroutine link ( self , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % fc // \" \" // args // \" -o \" // output , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine link !> Create an archive !> @todo For Windows OS, use the local `delete_file_win32` in stead of `delete_file`. !> This may be related to a bug in Mingw64-openmp and is expected to be resolved in the future, !> see issue #707, #708 and #808. subroutine make_archive ( self , output , args , log_file , stat ) !> Instance of the archiver object class ( archiver_t ), intent ( in ) :: self !> Name of the archive to generate character ( len =* ), intent ( in ) :: output !> Object files to include into the archive type ( string_t ), intent ( in ) :: args (:) !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat if ( self % use_response_file ) then call write_response_file ( output // \".resp\" , args ) call run ( self % ar // output // \" @\" // output // \".resp\" , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) call delete_file_win32 ( output // \".resp\" ) else call run ( self % ar // output // \" \" // string_cat ( args , \" \" ), & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end if contains subroutine delete_file_win32 ( file ) character ( len =* ), intent ( in ) :: file logical :: exist integer :: unit , iostat inquire ( file = file , exist = exist ) if ( exist ) then open ( file = file , newunit = unit ) close ( unit , status = 'delete' , iostat = iostat ) end if end subroutine delete_file_win32 end subroutine make_archive !> Response files allow to read command line options from files. !> Whitespace is used to separate the arguments, we will use newlines !> as separator to create readable response files which can be inspected !> in case of errors. subroutine write_response_file ( name , argv ) character ( len =* ), intent ( in ) :: name type ( string_t ), intent ( in ) :: argv (:) integer :: iarg , io open ( file = name , newunit = io , status = 'replace' ) do iarg = 1 , size ( argv ) write ( io , '(a)' ) unix_path ( argv ( iarg )% s ) end do close ( io ) end subroutine write_response_file !> String representation of a compiler object pure function debug_compiler ( self ) result ( repr ) !> Instance of the compiler object type ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'fc=\"' // self % fc // '\", cc=\"' // self % cc // '\"' end function debug_compiler !> String representation of an archiver object pure function debug_archiver ( self ) result ( repr ) !> Instance of the archiver object type ( archiver_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'ar=\"' // self % ar // '\"' end function debug_archiver !> Return a compiler name string pure function compiler_name ( self ) result ( name ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: name select case ( self % id ) case ( id_gcc ); name = \"gfortran\" case ( id_f95 ); name = \"f95\" case ( id_caf ); name = \"caf\" case ( id_intel_classic_nix ); name = \"ifort\" case ( id_intel_classic_mac ); name = \"ifort\" case ( id_intel_classic_windows ); name = \"ifort\" case ( id_intel_llvm_nix ); name = \"ifx\" case ( id_intel_llvm_windows ); name = \"ifx\" case ( id_intel_llvm_unknown ); name = \"ifx\" case ( id_pgi ); name = \"pgfortran\" case ( id_nvhpc ); name = \"nvfortran\" case ( id_nag ); name = \"nagfor\" case ( id_flang ); name = \"flang\" case ( id_flang_new ); name = \"flang-new\" case ( id_f18 ); name = \"f18\" case ( id_ibmxl ); name = \"xlf90\" case ( id_cray ); name = \"crayftn\" case ( id_lahey ); name = \"lfc\" case ( id_lfortran ); name = \"lFortran\" case default ; name = \"invalid/unknown\" end select end function compiler_name end module fpm_compiler","tags":"","loc":"sourcefile/fpm_compiler.f90.html"},{"title":"fpm_environment.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_environment Source Code fpm_environment.f90 Source Code !> This module contains procedures that interact with the programming environment. !! !! * [get_os_type] -- Determine the OS type !! * [get_env] -- return the value of an environment variable module fpm_environment use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit use fpm_error , only : fpm_stop implicit none private public :: get_os_type public :: os_is_unix public :: get_env public :: get_command_arguments_quoted public :: separator integer , parameter , public :: OS_UNKNOWN = 0 integer , parameter , public :: OS_LINUX = 1 integer , parameter , public :: OS_MACOS = 2 integer , parameter , public :: OS_WINDOWS = 3 integer , parameter , public :: OS_CYGWIN = 4 integer , parameter , public :: OS_SOLARIS = 5 integer , parameter , public :: OS_FREEBSD = 6 integer , parameter , public :: OS_OPENBSD = 7 contains !> Determine the OS type integer function get_os_type () result ( r ) !! !! Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN, !! OS_SOLARIS, OS_FREEBSD, OS_OPENBSD. !! !! At first, the environment variable `OS` is checked, which is usually !! found on Windows. Then, `OSTYPE` is read in and compared with common !! names. If this fails too, check the existence of files that can be !! found on specific system types only. !! !! Returns OS_UNKNOWN if the operating system cannot be determined. character ( len = 32 ) :: val integer :: length , rc logical :: file_exists logical , save :: first_run = . true . integer , save :: ret = OS_UNKNOWN !$omp threadprivate(ret, first_run) if (. not . first_run ) then r = ret return end if first_run = . false . r = OS_UNKNOWN ! Check environment variable `OSTYPE`. call get_environment_variable ( 'OSTYPE' , val , length , rc ) if ( rc == 0 . and . length > 0 ) then ! Linux if ( index ( val , 'linux' ) > 0 ) then r = OS_LINUX ret = r return end if ! macOS if ( index ( val , 'darwin' ) > 0 ) then r = OS_MACOS ret = r return end if ! Windows, MSYS, MinGW, Git Bash if ( index ( val , 'win' ) > 0 . or . index ( val , 'msys' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Cygwin if ( index ( val , 'cygwin' ) > 0 ) then r = OS_CYGWIN ret = r return end if ! Solaris, OpenIndiana, ... if ( index ( val , 'SunOS' ) > 0 . or . index ( val , 'solaris' ) > 0 ) then r = OS_SOLARIS ret = r return end if ! FreeBSD if ( index ( val , 'FreeBSD' ) > 0 . or . index ( val , 'freebsd' ) > 0 ) then r = OS_FREEBSD ret = r return end if ! OpenBSD if ( index ( val , 'OpenBSD' ) > 0 . or . index ( val , 'openbsd' ) > 0 ) then r = OS_OPENBSD ret = r return end if end if ! Check environment variable `OS`. call get_environment_variable ( 'OS' , val , length , rc ) if ( rc == 0 . and . length > 0 . and . index ( val , 'Windows_NT' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Linux inquire ( file = '/etc/os-release' , exist = file_exists ) if ( file_exists ) then r = OS_LINUX ret = r return end if ! macOS inquire ( file = '/usr/bin/sw_vers' , exist = file_exists ) if ( file_exists ) then r = OS_MACOS ret = r return end if ! FreeBSD inquire ( file = '/bin/freebsd-version' , exist = file_exists ) if ( file_exists ) then r = OS_FREEBSD ret = r return end if end function get_os_type !> Compare the output of [[get_os_type]] or the optional !! passed INTEGER value to the value for OS_WINDOWS !! and return .TRUE. if they match and .FALSE. otherwise logical function os_is_unix ( os ) integer , intent ( in ), optional :: os integer :: build_os if ( present ( os )) then build_os = os else build_os = get_os_type () end if os_is_unix = build_os /= OS_WINDOWS end function os_is_unix !> get named environment variable value. It it is blank or !! not set return the optional default value function get_env ( NAME , DEFAULT ) result ( VALUE ) implicit none !> name of environment variable to get the value of character ( len =* ), intent ( in ) :: NAME !> default value to return if the requested value is undefined or blank character ( len =* ), intent ( in ), optional :: DEFAULT !> the returned value character ( len = :), allocatable :: VALUE integer :: howbig integer :: stat integer :: length ! get length required to hold value length = 0 if ( NAME /= '' ) then call get_environment_variable ( NAME , length = howbig , status = stat , trim_name = . true .) select case ( stat ) case ( 1 ) !*!print *, NAME, \" is not defined in the environment. Strange...\" VALUE = '' case ( 2 ) !*!print *, \"This processor doesn't support environment variables. Boooh!\" VALUE = '' case default ! make string to hold value of sufficient size allocate ( character ( len = max ( howbig , 1 )) :: VALUE ) ! get value call get_environment_variable ( NAME , VALUE , status = stat , trim_name = . true .) if ( stat /= 0 ) VALUE = '' end select else VALUE = '' endif if ( VALUE == '' . and . present ( DEFAULT )) VALUE = DEFAULT end function get_env function get_command_arguments_quoted () result ( args ) character ( len = :), allocatable :: args character ( len = :), allocatable :: arg character ( len = 1 ) :: quote integer :: ilength , istatus , i ilength = 0 args = '' quote = merge ( '\"' , \"'\" , separator () == '\\') do i=2,command_argument_count() ! look at all arguments after subcommand call get_command_argument(number=i,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit else if(allocated(arg))deallocate(arg) allocate(character(len=ilength) :: arg) call get_command_argument(number=i,value=arg,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit elseif(ilength>0)then if(index(arg//' ',' - ')/=1)then args=args//quote//arg//quote//' ' elseif(index(arg,' ')/=0)then args=args//quote//arg//quote//' ' else args=args//arg//' ' endif else args=args//repeat(quote,2)//' ' endif endif enddo end function get_command_arguments_quoted function separator() result(sep) !> !!##NAME !! separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character !! (LICENSE:PD) !! !!##SYNOPSIS !! !! function separator() result(sep) !! !! character(len=1) :: sep !! !!##DESCRIPTION !! First using the name the program was invoked with, then the name !! returned by an INQUIRE(3f) of that name, then \".\\NAME\" and \"./NAME\" !! try to determine the separator character used to separate directory !! names from file basenames. !! !! If a slash or backslash is not found in the name, the environment !! variable PATH is examined first for a backslash, then a slash. !! !! Can be very system dependent. If the queries fail the default returned !! is \"/\". !! !!##EXAMPLE !! !! sample usage !! !! program demo_separator !! use M_io, only : separator !! implicit none !! write(*,*)' separator = ',separator() !! end program demo_separator ! use the pathname returned as arg0 to determine pathname separator implicit none character(len=:),allocatable :: arg0 integer :: arg0_length integer :: istat logical :: existing character(len=1) :: sep !*ifort_bug*!character(len=1),save :: sep_cache=' ' character(len=4096) :: name character(len=:),allocatable :: fname !*ifort_bug*! if(sep_cache/=' ')then ! use cached value. NOTE: A parallel code might theoretically use multiple OS !*ifort_bug*! sep=sep_cache !*ifort_bug*! return !*ifort_bug*! endif arg0_length=0 name=' ' call get_command_argument(0,length=arg0_length,status=istat) if(allocated(arg0))deallocate(arg0) allocate(character(len=arg0_length) :: arg0) call get_command_argument(0,arg0,status=istat) ! check argument name if(index(arg0,' \\ ')/=0)then sep=' \\ ' elseif(index(arg0,' / ')/=0)then sep=' / ' else ! try name returned by INQUIRE(3f) existing=.false. name=' ' inquire(file=arg0,iostat=istat,exist=existing,name=name) if(index(name,' \\ ')/=0)then sep=' \\ ' elseif(index(name,' / ')/=0)then sep=' / ' else ! well, try some common syntax and assume in current directory fname=' . \\ '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' \\ ' else fname=' . / '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' / ' else ! check environment variable PATH sep=merge(' \\ ',' / ',index(get_env(' PATH '),' \\ ')/=0) !*!write(*,*)' < WARNING > unknown system directory path separator ' endif endif endif endif !*ifort_bug*!sep_cache=sep end function separator end module fpm_environment","tags":"","loc":"sourcefile/fpm_environment.f90.html"},{"title":"fpm_meta.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_meta Source Code fpm_meta.f90 Source Code !># The fpm meta-package model !> !> This is a wrapper data type that encapsulate all pre-processing information !> (compiler flags, linker libraries, etc.) required to correctly enable a package !> to use a core library. !> !> !>### Available core libraries !> !> - OpenMP !> - MPI !> - fortran-lang stdlib !> - fortran-lang minpack !> !> !> @note Core libraries are enabled in the [build] section of the fpm.toml manifest !> !> module fpm_meta use fpm_strings , only : string_t , len_trim , remove_newline_characters use fpm_error , only : error_t , fatal_error , syntax_error , fpm_stop use fpm_compiler use fpm_model use fpm_command_line use fpm_manifest_dependency , only : dependency_config_t use fpm_git , only : git_target_branch , git_target_tag use fpm_manifest , only : package_config_t use fpm_environment , only : get_env , os_is_unix use fpm_filesystem , only : run , get_temp_filename , getline , exists , canon_path , is_dir , get_dos_path use fpm_versioning , only : version_t , new_version , regex_version_from_text use fpm_os , only : get_absolute_path use iso_fortran_env , only : stdout => output_unit implicit none private public :: resolve_metapackages !> Type for describing a source file type , public :: metapackage_t !> Package version (if supported) type ( version_t ), allocatable :: version logical :: has_link_libraries = . false . logical :: has_link_flags = . false . logical :: has_build_flags = . false . logical :: has_fortran_flags = . false . logical :: has_c_flags = . false . logical :: has_cxx_flags = . false . logical :: has_include_dirs = . false . logical :: has_dependencies = . false . logical :: has_run_command = . false . logical :: has_external_modules = . false . !> List of compiler flags and options to be added type ( string_t ) :: flags type ( string_t ) :: fflags type ( string_t ) :: cflags type ( string_t ) :: cxxflags type ( string_t ) :: link_flags type ( string_t ) :: run_command type ( string_t ), allocatable :: incl_dirs (:) type ( string_t ), allocatable :: link_libs (:) type ( string_t ), allocatable :: external_modules (:) !> Special fortran features type ( fortran_features_t ), allocatable :: fortran !> List of Development dependency meta data. !> Metapackage dependencies are never exported from the model type ( dependency_config_t ), allocatable :: dependency (:) contains !> Clean metapackage structure procedure :: destroy !> Initialize the metapackage structure from its given name procedure :: new => init_from_name !> Add metapackage dependencies to the model procedure , private :: resolve_cmd procedure , private :: resolve_model procedure , private :: resolve_package_config generic :: resolve => resolve_cmd , resolve_model , resolve_package_config end type metapackage_t interface resolve_metapackages module procedure resolve_metapackage_model end interface resolve_metapackages integer , parameter :: MPI_TYPE_NONE = 0 integer , parameter :: MPI_TYPE_OPENMPI = 1 integer , parameter :: MPI_TYPE_MPICH = 2 integer , parameter :: MPI_TYPE_INTEL = 3 integer , parameter :: MPI_TYPE_MSMPI = 4 public :: MPI_TYPE_NAME !> Debugging information logical , parameter , private :: verbose = . false . integer , parameter , private :: LANG_FORTRAN = 1 integer , parameter , private :: LANG_C = 2 integer , parameter , private :: LANG_CXX = 3 contains !> Return a name for the MPI library pure function MPI_TYPE_NAME ( mpilib ) result ( name ) integer , intent ( in ) :: mpilib character ( len = :), allocatable :: name select case ( mpilib ) case ( MPI_TYPE_NONE ); name = \"none\" case ( MPI_TYPE_OPENMPI ); name = \"OpenMPI\" case ( MPI_TYPE_MPICH ); name = \"MPICH\" case ( MPI_TYPE_INTEL ); name = \"INTELMPI\" case ( MPI_TYPE_MSMPI ); name = \"MS-MPI\" case default ; name = \"UNKNOWN\" end select end function MPI_TYPE_NAME !> Clean the metapackage structure elemental subroutine destroy ( this ) class ( metapackage_t ), intent ( inout ) :: this this % has_link_libraries = . false . this % has_link_flags = . false . this % has_build_flags = . false . this % has_fortran_flags = . false . this % has_c_flags = . false . this % has_cxx_flags = . false . this % has_include_dirs = . false . this % has_dependencies = . false . this % has_run_command = . false . this % has_external_modules = . false . if ( allocated ( this % fortran )) deallocate ( this % fortran ) if ( allocated ( this % version )) deallocate ( this % version ) if ( allocated ( this % flags % s )) deallocate ( this % flags % s ) if ( allocated ( this % fflags % s )) deallocate ( this % fflags % s ) if ( allocated ( this % cflags % s )) deallocate ( this % cflags % s ) if ( allocated ( this % cxxflags % s )) deallocate ( this % cxxflags % s ) if ( allocated ( this % link_flags % s )) deallocate ( this % link_flags % s ) if ( allocated ( this % run_command % s )) deallocate ( this % run_command % s ) if ( allocated ( this % link_libs )) deallocate ( this % link_libs ) if ( allocated ( this % dependency )) deallocate ( this % dependency ) if ( allocated ( this % incl_dirs )) deallocate ( this % incl_dirs ) if ( allocated ( this % external_modules )) deallocate ( this % external_modules ) end subroutine destroy !> Initialize a metapackage from the given name subroutine init_from_name ( this , name , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this character ( * ), intent ( in ) :: name type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error !> Initialize metapackage by name select case ( name ) case ( \"openmp\" ); call init_openmp ( this , compiler , error ) case ( \"stdlib\" ); call init_stdlib ( this , compiler , error ) case ( \"minpack\" ); call init_minpack ( this , compiler , error ) case ( \"mpi\" ); call init_mpi ( this , compiler , error ) case default call syntax_error ( error , \"Package \" // name // \" is not supported in [metapackages]\" ) return end select end subroutine init_from_name !> Initialize OpenMP metapackage for the current system subroutine init_openmp ( this , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> OpenMP has compiler flags this % has_build_flags = . true . this % has_link_flags = . true . !> OpenMP flags should be added to which_compiler : select case ( compiler % id ) case ( id_gcc , id_f95 ) this % flags = string_t ( flag_gnu_openmp ) this % link_flags = string_t ( flag_gnu_openmp ) case ( id_intel_classic_windows , id_intel_llvm_windows ) this % flags = string_t ( flag_intel_openmp_win ) this % link_flags = string_t ( flag_intel_openmp_win ) case ( id_intel_classic_nix , id_intel_classic_mac ,& id_intel_llvm_nix ) this % flags = string_t ( flag_intel_openmp ) this % link_flags = string_t ( flag_intel_openmp ) case ( id_pgi , id_nvhpc ) this % flags = string_t ( flag_pgi_openmp ) this % link_flags = string_t ( flag_pgi_openmp ) case ( id_ibmxl ) this % flags = string_t ( \" -qsmp=omp\" ) this % link_flags = string_t ( \" -qsmp=omp\" ) case ( id_nag ) this % flags = string_t ( flag_nag_openmp ) this % link_flags = string_t ( flag_nag_openmp ) case ( id_lfortran ) this % flags = string_t ( flag_lfortran_openmp ) this % link_flags = string_t ( flag_lfortran_openmp ) case default call fatal_error ( error , 'openmp not supported on compiler ' // compiler % name () // ' yet' ) end select which_compiler end subroutine init_openmp !> Initialize minpack metapackage for the current system subroutine init_minpack ( this , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> minpack is queried as a dependency from the official repository this % has_dependencies = . true . allocate ( this % dependency ( 1 )) !> 1) minpack. There are no true releases currently. Fetch HEAD this % dependency ( 1 )% name = \"minpack\" this % dependency ( 1 )% git = git_target_tag ( \"https://github.com/fortran-lang/minpack\" , \"v2.0.0-rc.1\" ) if (. not . allocated ( this % dependency ( 1 )% git )) then call fatal_error ( error , 'cannot initialize git repo dependency for minpack metapackage' ) return end if end subroutine init_minpack !> Initialize stdlib metapackage for the current system subroutine init_stdlib ( this , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> Stdlib is queried as a dependency from the official repository this % has_dependencies = . true . allocate ( this % dependency ( 2 )) !> 1) Test-drive this % dependency ( 1 )% name = \"test-drive\" this % dependency ( 1 )% git = git_target_branch ( \"https://github.com/fortran-lang/test-drive\" , \"v0.4.0\" ) if (. not . allocated ( this % dependency ( 1 )% git )) then call fatal_error ( error , 'cannot initialize test-drive git dependency for stdlib metapackage' ) return end if !> 2) stdlib this % dependency ( 2 )% name = \"stdlib\" this % dependency ( 2 )% git = git_target_branch ( \"https://github.com/fortran-lang/stdlib\" , \"stdlib-fpm\" ) if (. not . allocated ( this % dependency ( 2 )% git )) then call fatal_error ( error , 'cannot initialize git repo dependency for stdlib metapackage' ) return end if end subroutine init_stdlib ! Resolve metapackage dependencies into the command line settings subroutine resolve_cmd ( self , settings , error ) class ( metapackage_t ), intent ( in ) :: self class ( fpm_cmd_settings ), intent ( inout ) :: settings type ( error_t ), allocatable , intent ( out ) :: error ! Add customize run commands if ( self % has_run_command ) then select type ( cmd => settings ) class is ( fpm_run_settings ) ! includes fpm_test_settings ! Only override runner if user has not provided a custom one if (. not . len_trim ( cmd % runner ) > 0 ) cmd % runner = self % run_command % s end select endif end subroutine resolve_cmd ! Resolve metapackage dependencies into the model subroutine resolve_model ( self , model , error ) class ( metapackage_t ), intent ( in ) :: self type ( fpm_model_t ), intent ( inout ) :: model type ( error_t ), allocatable , intent ( out ) :: error ! Add global build flags, to apply to all sources if ( self % has_build_flags ) then model % fortran_compile_flags = model % fortran_compile_flags // self % flags % s model % c_compile_flags = model % c_compile_flags // self % flags % s model % cxx_compile_flags = model % cxx_compile_flags // self % flags % s endif ! Add language-specific flags if ( self % has_fortran_flags ) model % fortran_compile_flags = model % fortran_compile_flags // self % fflags % s if ( self % has_c_flags ) model % c_compile_flags = model % c_compile_flags // self % cflags % s if ( self % has_cxx_flags ) model % cxx_compile_flags = model % cxx_compile_flags // self % cxxflags % s if ( self % has_link_flags ) then model % link_flags = model % link_flags // self % link_flags % s end if if ( self % has_link_libraries ) then model % link_libraries = [ model % link_libraries , self % link_libs ] end if if ( self % has_include_dirs ) then model % include_dirs = [ model % include_dirs , self % incl_dirs ] end if if ( self % has_external_modules ) then model % external_modules = [ model % external_modules , self % external_modules ] end if end subroutine resolve_model subroutine resolve_package_config ( self , package , error ) class ( metapackage_t ), intent ( in ) :: self type ( package_config_t ), intent ( inout ) :: package type ( error_t ), allocatable , intent ( out ) :: error ! All metapackage dependencies are added as dev-dependencies, ! as they may change if built upstream if ( self % has_dependencies ) then if ( allocated ( package % dev_dependency )) then package % dev_dependency = [ package % dev_dependency , self % dependency ] else package % dev_dependency = self % dependency end if end if ! Check if there are any special fortran requests which the package does not comply to if ( allocated ( self % fortran )) then if ( self % fortran % implicit_external . neqv . package % fortran % implicit_external ) then call fatal_error ( error , 'metapackage fortran error: metapackage ' // & dn ( self % fortran % implicit_external ) // ' require implicit-external, main package ' // & dn ( package % fortran % implicit_external )) return end if if ( self % fortran % implicit_typing . neqv . package % fortran % implicit_typing ) then call fatal_error ( error , 'metapackage fortran error: metapackage ' // & dn ( self % fortran % implicit_external ) // ' require implicit-typing, main package ' // & dn ( package % fortran % implicit_external )) return end if end if contains pure function dn ( bool ) logical , intent ( in ) :: bool character ( len = :), allocatable :: dn if ( bool ) then dn = \"does\" else dn = \"does not\" end if end function dn end subroutine resolve_package_config ! Add named metapackage dependency to the model subroutine add_metapackage_model ( model , package , settings , name , error ) type ( fpm_model_t ), intent ( inout ) :: model type ( package_config_t ), intent ( inout ) :: package class ( fpm_cmd_settings ), intent ( inout ) :: settings character ( * ), intent ( in ) :: name type ( error_t ), allocatable , intent ( out ) :: error type ( metapackage_t ) :: meta !> Init metapackage call meta % new ( name , model % compiler , error ) if ( allocated ( error )) return !> Add it into the model call meta % resolve ( model , error ) if ( allocated ( error )) return !> Add it into the package call meta % resolve ( package , error ) if ( allocated ( error )) return !> Add it into the settings call meta % resolve ( settings , error ) if ( allocated ( error )) return ! If we need to run executables, there should be an MPI runner if ( name == \"mpi\" ) then select type ( settings ) class is ( fpm_run_settings ) ! run, test if (. not . meta % has_run_command ) & call fatal_error ( error , \"cannot find a valid mpi runner on the local host\" ) end select endif end subroutine add_metapackage_model !> Resolve all metapackages into the package config subroutine resolve_metapackage_model ( model , package , settings , error ) type ( fpm_model_t ), intent ( inout ) :: model type ( package_config_t ), intent ( inout ) :: package class ( fpm_build_settings ), intent ( inout ) :: settings type ( error_t ), allocatable , intent ( out ) :: error ! Dependencies are added to the package config, so they're properly resolved ! into the dependency tree later. ! Flags are added to the model (whose compiler needs to be already initialized) if ( model % compiler % is_unknown ()) then call fatal_error ( error , \"compiler not initialized: cannot build metapackages\" ) return end if ! OpenMP if ( package % meta % openmp % on ) then call add_metapackage_model ( model , package , settings , \"openmp\" , error ) if ( allocated ( error )) return endif ! stdlib if ( package % meta % stdlib % on ) then call add_metapackage_model ( model , package , settings , \"stdlib\" , error ) if ( allocated ( error )) return endif ! stdlib if ( package % meta % minpack % on ) then call add_metapackage_model ( model , package , settings , \"minpack\" , error ) if ( allocated ( error )) return endif ! Stdlib is not 100% thread safe. print a warning to the user if ( package % meta % stdlib % on . and . package % meta % openmp % on ) then write ( stdout , '(a)' ) ' both openmp and stdlib requested: some functions may not be thread-safe!' end if ! MPI if ( package % meta % mpi % on ) then call add_metapackage_model ( model , package , settings , \"mpi\" , error ) if ( allocated ( error )) return endif end subroutine resolve_metapackage_model !> Initialize MPI metapackage for the current system subroutine init_mpi ( this , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ), allocatable :: c_wrappers (:), cpp_wrappers (:), fort_wrappers (:) type ( string_t ) :: output , fwrap , cwrap , cxxwrap character ( 256 ) :: msg_out character ( len = :), allocatable :: tokens (:) integer :: wcfit ( 3 ), mpilib ( 3 ), ic , icpp , i logical :: found !> Cleanup call destroy ( this ) !> Get all candidate MPI wrappers call mpi_wrappers ( compiler , fort_wrappers , c_wrappers , cpp_wrappers ) if ( verbose ) print 1 , size ( fort_wrappers ), size ( c_wrappers ), size ( cpp_wrappers ) call wrapper_compiler_fit ( fort_wrappers , c_wrappers , cpp_wrappers , compiler , wcfit , mpilib , error ) if ( allocated ( error ) . or . all ( wcfit == 0 )) then !> No wrapper compiler fit. Are we on Windows? use MSMPI-specific search found = msmpi_init ( this , compiler , error ) if ( allocated ( error )) return !> All attempts failed if (. not . found ) then call fatal_error ( error , \"cannot find MPI wrappers or libraries for \" // compiler % name () // \" compiler\" ) return endif else if ( wcfit ( LANG_FORTRAN ) > 0 ) fwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) if ( wcfit ( LANG_C ) > 0 ) cwrap = c_wrappers ( wcfit ( LANG_C )) if ( wcfit ( LANG_CXX ) > 0 ) cxxwrap = cpp_wrappers ( wcfit ( LANG_CXX )) !> If there's only an available Fortran wrapper, and the compiler's different than fpm's baseline !> fortran compiler suite, we still want to enable C language flags as that is most likely being !> ABI-compatible anyways. However, issues may arise. !> see e.g. Homebrew with clabng C/C++ and GNU fortran at https://gitlab.kitware.com/cmake/cmake/-/issues/18139 if ( wcfit ( LANG_FORTRAN ) > 0 . and . all ( wcfit ([ LANG_C , LANG_CXX ]) == 0 )) then cwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) cxxwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) end if if ( verbose ) print * , '+ MPI fortran wrapper: ' , fwrap % s if ( verbose ) print * , '+ MPI c wrapper: ' , cwrap % s if ( verbose ) print * , '+ MPI c++ wrapper: ' , cxxwrap % s !> Initialize MPI package from wrapper command call init_mpi_from_wrappers ( this , compiler , mpilib ( LANG_FORTRAN ), fwrap , cwrap , cxxwrap , error ) if ( allocated ( error )) return !> Request Fortran implicit typing if ( mpilib ( LANG_FORTRAN ) /= MPI_TYPE_INTEL ) then allocate ( this % fortran ) this % fortran % implicit_typing = . true . this % fortran % implicit_external = . true . endif end if !> Not all MPI implementations offer modules mpi and mpi_f08: hence, include them !> to the list of external modules, so they won't be requested as standard source files this % has_external_modules = . true . this % external_modules = [ string_t ( \"mpi\" ), string_t ( \"mpi_f08\" )] 1 format ( 'MPI wrappers found: fortran=' , i0 , ' c=' , i0 , ' c++=' , i0 ) end subroutine init_mpi !> Check if we're on a 64-bit environment !> Accept answer from https://stackoverflow.com/questions/49141093/get-system-information-with-fortran logical function is_64bit_environment () use iso_c_binding , only : c_intptr_t integer , parameter :: nbits = bit_size ( 0_c_intptr_t ) is_64bit_environment = nbits == 64 end function is_64bit_environment !> Check if there is a wrapper-compiler fit subroutine wrapper_compiler_fit ( fort_wrappers , c_wrappers , cpp_wrappers , compiler , wrap , mpi , error ) type ( string_t ), allocatable , intent ( in ) :: fort_wrappers (:), c_wrappers (:), cpp_wrappers (:) type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error integer , intent ( out ), dimension ( 3 ) :: wrap , mpi type ( error_t ), allocatable :: wrap_error wrap = 0 mpi = MPI_TYPE_NONE if ( size ( fort_wrappers ) > 0 ) & call mpi_compiler_match ( LANG_FORTRAN , fort_wrappers , compiler , wrap ( LANG_FORTRAN ), mpi ( LANG_FORTRAN ), wrap_error ) if ( size ( c_wrappers ) > 0 ) & call mpi_compiler_match ( LANG_C , c_wrappers , compiler , wrap ( LANG_C ), mpi ( LANG_C ), wrap_error ) if ( size ( cpp_wrappers ) > 0 ) & call mpi_compiler_match ( LANG_CXX , cpp_wrappers , compiler , wrap ( LANG_CXX ), mpi ( LANG_CXX ), wrap_error ) !> Find a Fortran wrapper for the current compiler if ( all ( wrap == 0 )) then call fatal_error ( error , 'no valid wrappers match current compiler, ' // compiler_name ( compiler )) return end if end subroutine wrapper_compiler_fit !> Check if a local MS-MPI SDK build is found logical function msmpi_init ( this , compiler , error ) result ( found ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: incdir , windir , libdir , bindir , post , reall , msysdir type ( version_t ) :: ver , ver10 type ( string_t ) :: cpath , msys_path , runner_path logical :: msys2 !> Default: not found found = . false . if ( get_os_type () == OS_WINDOWS ) then ! to run MSMPI on Windows, is_minGW : if ( compiler % id == id_gcc ) then call compiler_get_version ( compiler , ver , msys2 , error ) if ( allocated ( error )) return endif is_minGW ! Check we're on a 64-bit environment if ( is_64bit_environment ()) then libdir = get_env ( 'MSMPI_LIB64' ) post = 'x64' else libdir = get_env ( 'MSMPI_LIB32' ) post = 'x86' !> Not working on 32-bit Windows yet call fatal_error ( error , 'MS-MPI error: this package requires 64-bit Windows environment' ) return end if ! Check that the runtime is installed bindir = \"\" call get_absolute_path ( get_env ( 'MSMPI_BIN' ), bindir , error ) if ( verbose ) print * , '+ %MSMPI_BIN%=' , bindir ! In some environments, variable %MSMPI_BIN% is missing (i.e. in GitHub Action images). ! Do a second attempt: search for the default location if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ %MSMPI_BIN% empty, searching C:\\Program Files\\Microsoft MPI\\Bin\\ ...' call get_absolute_path ( 'C:\\Program Files\\Microsoft MPI\\Bin\\mpiexec.exe' , bindir , error ) endif ! Do a third attempt: search for mpiexec.exe in PATH location if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ C:\\Program Files\\Microsoft MPI\\Bin\\ not found. searching %PATH%...' call get_mpi_runner ( runner_path , verbose , error ) if (. not . allocated ( error )) then if ( verbose ) print * , '+ mpiexec found: ' , runner_path % s call find_command_location ( runner_path % s , bindir , verbose = verbose , error = error ) endif endif if ( allocated ( error ) . or . . not . exists ( bindir )) then call fatal_error ( error , 'MS-MPI error: MS-MPI Runtime directory is missing. ' // & 'check environment variable %MSMPI_BIN% or that the folder is in %PATH%.' ) return end if ! Success! found = . true . ! Init ms-mpi call destroy ( this ) ! MSYS2 provides a pre-built static msmpi.dll.a library. Use that if possible use_prebuilt : if ( msys2 ) then ! MSYS executables are in %MSYS_ROOT%/bin call compiler_get_path ( compiler , cpath , error ) if ( allocated ( error )) return call get_absolute_path ( join_path ( cpath % s , '..' ), msys_path % s , error ) if ( allocated ( error )) return call get_absolute_path ( join_path ( msys_path % s , 'include' ), incdir , error ) if ( allocated ( error )) return call get_absolute_path ( join_path ( msys_path % s , 'lib' ), libdir , error ) if ( allocated ( error )) return if ( verbose ) print 1 , 'include' , incdir , exists ( incdir ) if ( verbose ) print 1 , 'library' , libdir , exists ( libdir ) ! Check that the necessary files exist call get_absolute_path ( join_path ( libdir , 'libmsmpi.dll.a' ), post , error ) if ( allocated ( error )) return if ( len_trim ( post ) <= 0 . or . . not . exists ( post )) then call fatal_error ( error , 'MS-MPI available through the MSYS2 system not found. ' // & 'Run ' // & 'or your system-specific version to install.' ) return end if ! Add dir cpath this % has_link_flags = . true . this % link_flags = string_t ( ' -L' // get_dos_path ( libdir , error )) this % has_link_libraries = . true . this % link_libs = [ string_t ( 'msmpi.dll' )] if ( allocated ( error )) return this % has_include_dirs = . true . this % incl_dirs = [ string_t ( get_dos_path ( incdir , error ))] if ( allocated ( error )) return else call fatal_error ( error , 'MS-MPI cannot work with non-MSYS2 GNU compilers yet' ) return ! Add dir path this % has_link_flags = . true . this % link_flags = string_t ( ' -L' // get_dos_path ( libdir , error )) this % has_link_libraries = . true . this % link_libs = [ string_t ( 'msmpi' ), string_t ( 'msmpifec' ), string_t ( 'msmpifmc' )] if ( allocated ( error )) return this % has_include_dirs = . true . this % incl_dirs = [ string_t ( get_dos_path ( incdir , error )), & string_t ( get_dos_path ( incdir // post , error ))] if ( allocated ( error )) return end if use_prebuilt !> Request Fortran implicit typing allocate ( this % fortran ) this % fortran % implicit_typing = . true . this % fortran % implicit_external = . true . ! gfortran>=10 is incompatible with the old-style mpif.h MS-MPI headers. ! If so, add flags to allow old-style BOZ constants in mpif.h allow_BOZ : if ( compiler % id == id_gcc ) then call new_version ( ver10 , '10.0.0' , error ) if ( allocated ( error )) return if ( ver >= ver10 ) then this % has_build_flags = . true . this % flags = string_t ( ' -fallow-invalid-boz' ) end if endif allow_BOZ !> Add default run command this % has_run_command = . true . this % run_command = string_t ( join_path ( get_dos_path ( bindir , error ), 'mpiexec.exe' ) // ' -np * ' ) else !> Not on Windows found = . false . end if 1 format ( 'MSMSPI ' , a , ' directory: PATH=' , a , ' EXISTS=' , l1 ) end function msmpi_init !> Check if we're under a WSL bash shell logical function wsl_shell () if ( get_os_type () == OS_WINDOWS ) then wsl_shell = exists ( '/proc/sys/fs/binfmt_misc/WSLInterop' ) else wsl_shell = . false . endif end function wsl_shell !> Find the location of a valid command subroutine find_command_location ( command , path , echo , verbose , error ) character ( * ), intent ( in ) :: command character ( len = :), allocatable , intent ( out ) :: path logical , optional , intent ( in ) :: echo , verbose type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: tmp_file , screen_output , line , fullpath , search_command integer :: stat , iunit , ire , length , try character ( * ), parameter :: search ( 2 ) = [ \"where \" , \"which \" ] if ( len_trim ( command ) <= 0 ) then call fatal_error ( error , 'empty command provided in find_command_location' ) return end if tmp_file = get_temp_filename () ! On Windows, we try both commands because we may be on WSL do try = merge ( 1 , 2 , get_os_type () == OS_WINDOWS ), 2 search_command = search ( try ) // command call run ( search_command , echo = echo , exitstat = stat , verbose = verbose , redirect = tmp_file ) if ( stat == 0 ) exit end do if ( stat /= 0 ) then call fatal_error ( error , 'find_command_location failed for ' // command ) return end if ! Only read first instance (first line) allocate ( character ( len = 0 ) :: screen_output ) open ( newunit = iunit , file = tmp_file , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit if ( len ( screen_output ) > 0 ) then screen_output = screen_output // new_line ( 'a' ) // line else screen_output = line endif end do ! Close and delete file close ( iunit , status = 'delete' ) else call fatal_error ( error , 'cannot read temporary file from successful find_command_location' ) return endif ! Only use the first instance length = index ( screen_output , new_line ( 'a' )) multiline : if ( length > 1 ) then fullpath = screen_output ( 1 : length - 1 ) else fullpath = screen_output endif multiline if ( len_trim ( fullpath ) < 1 ) then call fatal_error ( error , 'no paths found to command (' // command // ')' ) return end if ! Extract path only length = index ( fullpath , command , BACK = . true .) if ( length <= 0 ) then call fatal_error ( error , 'full path to command (' // command // ') does not include command name' ) return elseif ( length == 1 ) then ! Compiler is in the current folder path = '.' else path = fullpath ( 1 : length - 1 ) end if if ( allocated ( error )) return ! On Windows, be sure to return a path with no spaces if ( get_os_type () == OS_WINDOWS ) path = get_dos_path ( path , error ) if ( allocated ( error ) . or . . not . is_dir ( path )) then call fatal_error ( error , 'full path (' // path // ') to command (' // command // ') is not a directory' ) return end if end subroutine find_command_location !> Get MPI runner in $PATH subroutine get_mpi_runner ( command , verbose , error ) type ( string_t ), intent ( out ) :: command logical , intent ( in ) :: verbose type ( error_t ), allocatable , intent ( out ) :: error character ( * ), parameter :: try ( * ) = [ 'mpiexec ' , 'mpirun ' , 'mpiexec.exe' , 'mpirun.exe ' ] character (:), allocatable :: bindir integer :: itri logical :: success ! Try several commands do itri = 1 , size ( try ) call find_command_location ( trim ( try ( itri )), command % s , verbose = verbose , error = error ) if ( allocated ( error )) cycle ! Success! success = len_trim ( command % s ) > 0 if ( success ) then if ( verbose ) print * , '+ runner folder found: ' // command % s command % s = join_path ( command % s , trim ( try ( itri ))) return endif end do ! On windows, also search in %MSMPI_BIN% if ( get_os_type () == OS_WINDOWS ) then ! Check that the runtime is installed bindir = \"\" call get_absolute_path ( get_env ( 'MSMPI_BIN' ), bindir , error ) if ( verbose ) print * , '+ %MSMPI_BIN%=' , bindir ! In some environments, variable %MSMPI_BIN% is missing (i.e. in GitHub Action images). ! Do a second attempt: search for the default location if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ %MSMPI_BIN% empty, searching C:\\Program Files\\Microsoft MPI\\Bin\\ ...' call get_absolute_path ( 'C:\\Program Files\\Microsoft MPI\\Bin\\mpiexec.exe' , bindir , error ) endif if ( len_trim ( bindir ) > 0 . and . . not . allocated ( error )) then ! MSMPI_BIN directory found command % s = join_path ( bindir , 'mpiexec.exe' ) return endif endif ! No valid command found call fatal_error ( error , 'cannot find a valid mpi runner command' ) return end subroutine get_mpi_runner !> Return compiler path subroutine compiler_get_path ( self , path , error ) type ( compiler_t ), intent ( in ) :: self type ( string_t ), intent ( out ) :: path type ( error_t ), allocatable , intent ( out ) :: error call find_command_location ( self % fc , path % s , self % echo , self % verbose , error ) end subroutine compiler_get_path !> Return compiler version subroutine compiler_get_version ( self , version , is_msys2 , error ) type ( compiler_t ), intent ( in ) :: self type ( version_t ), intent ( out ) :: version logical , intent ( out ) :: is_msys2 type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: tmp_file , screen_output , line type ( string_t ) :: ver integer :: stat , iunit , ire , length is_msys2 = . false . select case ( self % id ) case ( id_gcc ) tmp_file = get_temp_filename () call run ( self % fc // \" --version \" , echo = self % echo , verbose = self % verbose , redirect = tmp_file , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'compiler_get_version failed for ' // self % fc ) return end if allocate ( character ( len = 0 ) :: screen_output ) open ( newunit = iunit , file = tmp_file , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output = screen_output // ' ' // line // ' ' end do ! Close and delete file close ( iunit , status = 'delete' ) else call fatal_error ( error , 'cannot read temporary file from successful compiler_get_version' ) return endif ! Check if this gcc is from the MSYS2 project is_msys2 = index ( screen_output , 'MSYS2' ) > 0 ver = regex_version_from_text ( screen_output , self % fc // ' compiler' , error ) if ( allocated ( error )) return ! Extract version call new_version ( version , ver % s , error ) case default call fatal_error ( error , 'compiler_get_version not yet implemented for compiler ' // self % fc ) return end select end subroutine compiler_get_version !> Initialize an MPI metapackage from a valid wrapper command ('mpif90', etc...) subroutine init_mpi_from_wrappers ( this , compiler , mpilib , fort_wrapper , c_wrapper , cxx_wrapper , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: fort_wrapper , c_wrapper , cxx_wrapper type ( error_t ), allocatable , intent ( out ) :: error type ( version_t ) :: version type ( error_t ), allocatable :: runner_error ! Cleanup structure call destroy ( this ) ! Get linking flags if ( mpilib /= MPI_TYPE_INTEL ) then this % link_flags = mpi_wrapper_query ( mpilib , fort_wrapper , 'link' , verbose , error ) ! We fix OpenMPI's Fortran wrapper bug (https://github.com/open-mpi/ompi/issues/11636) !call fix_openmpi_link_flags(this%link_flags,compiler,mpilib,fort_wrapper,c_wrapper,cxx_wrapper,error) if ( allocated ( error )) return this % has_link_flags = len_trim ( this % link_flags ) > 0 endif ! Request to use libs in arbitrary order if ( this % has_link_flags . and . compiler % is_gnu () . and . os_is_unix () . and . get_os_type () /= OS_MACOS ) then this % link_flags = string_t ( ' -Wl,--start-group ' // this % link_flags % s ) end if ! Add language-specific flags call set_language_flags ( mpilib , fort_wrapper , this % has_fortran_flags , this % fflags , verbose , error ) if ( allocated ( error )) return call set_language_flags ( mpilib , c_wrapper , this % has_c_flags , this % cflags , verbose , error ) if ( allocated ( error )) return call set_language_flags ( mpilib , cxx_wrapper , this % has_cxx_flags , this % cxxflags , verbose , error ) if ( allocated ( error )) return ! Get library version version = mpi_version_get ( mpilib , fort_wrapper , error ) if ( allocated ( error )) then return else allocate ( this % version , source = version ) end if !> Add default run command, if present this % run_command = mpi_wrapper_query ( mpilib , fort_wrapper , 'runner' , verbose , runner_error ) this % has_run_command = ( len_trim ( this % run_command ) > 0 ) . and . . not . allocated ( runner_error ) contains subroutine set_language_flags ( mpilib , wrapper , has_flags , flags , verbose , error ) integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: wrapper logical , intent ( inout ) :: has_flags type ( string_t ), intent ( inout ) :: flags logical , intent ( in ) :: verbose type ( error_t ), allocatable , intent ( out ) :: error ! Get build flags for each language if ( len_trim ( wrapper ) > 0 ) then flags = mpi_wrapper_query ( mpilib , wrapper , 'flags' , verbose , error ) if ( allocated ( error )) return has_flags = len_trim ( flags ) > 0 ! Add heading space flags = string_t ( ' ' // flags % s ) if ( verbose ) print * , '+ MPI language flags from wrapper <' , wrapper % s , '>: flags=' , flags % s endif end subroutine set_language_flags end subroutine init_mpi_from_wrappers !> Match one of the available compiler wrappers with the current compiler subroutine mpi_compiler_match ( language , wrappers , compiler , which_one , mpilib , error ) integer , intent ( in ) :: language type ( string_t ), intent ( in ) :: wrappers (:) type ( compiler_t ), intent ( in ) :: compiler integer , intent ( out ) :: which_one , mpilib type ( error_t ), allocatable , intent ( out ) :: error integer :: i type ( string_t ) :: screen character ( 128 ) :: msg_out type ( compiler_t ) :: mpi_compiler which_one = 0 mpilib = MPI_TYPE_NONE do i = 1 , size ( wrappers ) mpilib = which_mpi_library ( wrappers ( i ), compiler , verbose = . false .) screen = mpi_wrapper_query ( mpilib , wrappers ( i ), 'compiler' , verbose = . false ., error = error ) if ( allocated ( error )) return select case ( language ) case ( LANG_FORTRAN ) ! Build compiler type. The ID is created based on the Fortran name call new_compiler ( mpi_compiler , screen % s , '' , '' , echo = . true ., verbose = . false .) ! Fortran match found! if ( mpi_compiler % id == compiler % id ) then which_one = i return end if case ( LANG_C ) ! For other languages, we can only hope that the name matches the expected one if ( screen % s == compiler % cc . or . screen % s == compiler % fc ) then which_one = i return end if case ( LANG_CXX ) if ( screen % s == compiler % cxx . or . screen % s == compiler % fc ) then which_one = i return end if end select end do ! None of the available wrappers matched the current Fortran compiler write ( msg_out , 1 ) size ( wrappers ), compiler % fc call fatal_error ( error , trim ( msg_out )) 1 format ( ' None out of ' , i0 , ' valid MPI wrappers matches compiler ' , a ) end subroutine mpi_compiler_match !> Return library version from the MPI wrapper command type ( version_t ) function mpi_version_get ( mpilib , wrapper , error ) integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: wrapper type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ) :: version_line ! Get version string version_line = mpi_wrapper_query ( mpilib , wrapper , 'version' , error = error ) if ( allocated ( error )) return ! Wrap to object call new_version ( mpi_version_get , version_line % s , error ) end function mpi_version_get !> Return several mpi wrappers, and return subroutine mpi_wrappers ( compiler , fort_wrappers , c_wrappers , cpp_wrappers ) type ( compiler_t ), intent ( in ) :: compiler type ( string_t ), allocatable , intent ( out ) :: c_wrappers (:), cpp_wrappers (:), fort_wrappers (:) character ( len = :), allocatable :: mpi_root , intel_wrap type ( error_t ), allocatable :: error ! Attempt gathering MPI wrapper names from the environment variables c_wrappers = [ string_t ( get_env ( 'MPICC' , 'mpicc' ))] cpp_wrappers = [ string_t ( get_env ( 'MPICXX' , 'mpic++' ))] fort_wrappers = [ string_t ( get_env ( 'MPIFC' , 'mpifc' )),& string_t ( get_env ( 'MPIf90' , 'mpif90' )),& string_t ( get_env ( 'MPIf77' , 'mpif77' ))] if ( get_os_type () == OS_WINDOWS ) then c_wrappers = [ c_wrappers , string_t ( 'mpicc.bat' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'mpicxx.bat' )] fort_wrappers = [ fort_wrappers , string_t ( 'mpifc.bat' )] endif ! Add compiler-specific wrappers compiler_specific : select case ( compiler % id ) case ( id_gcc , id_f95 ) c_wrappers = [ c_wrappers , string_t ( 'mpigcc' ), string_t ( 'mpgcc' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'mpig++' ), string_t ( 'mpg++' )] fort_wrappers = [ fort_wrappers , string_t ( 'mpigfortran' ), string_t ( 'mpgfortran' ),& string_t ( 'mpig77' ), string_t ( 'mpg77' )] case ( id_intel_classic_windows , id_intel_llvm_windows , & id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , id_intel_llvm_unknown ) c_wrappers = [ string_t ( get_env ( 'I_MPI_CC' , 'mpiicc' ))] cpp_wrappers = [ string_t ( get_env ( 'I_MPI_CXX' , 'mpiicpc' ))] fort_wrappers = [ string_t ( get_env ( 'I_MPI_F90' , 'mpiifort' ))] ! Also search MPI wrappers via the base MPI folder mpi_root = get_env ( 'I_MPI_ROOT' ) if ( mpi_root /= \"\" ) then mpi_root = join_path ( mpi_root , 'bin' ) intel_wrap = join_path ( mpi_root , 'mpiifort' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) fort_wrappers = [ fort_wrappers , string_t ( intel_wrap )] intel_wrap = join_path ( mpi_root , 'mpiicc' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) c_wrappers = [ c_wrappers , string_t ( intel_wrap )] intel_wrap = join_path ( mpi_root , 'mpiicpc' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) cpp_wrappers = [ cpp_wrappers , string_t ( intel_wrap )] end if case ( id_pgi , id_nvhpc ) c_wrappers = [ c_wrappers , string_t ( 'mpipgicc' ), string_t ( 'mpgcc' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'mpipgic++' )] fort_wrappers = [ fort_wrappers , string_t ( 'mpipgifort' ), string_t ( 'mpipgf90' )] case ( id_cray ) c_wrappers = [ c_wrappers , string_t ( 'cc' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'CC' )] fort_wrappers = [ fort_wrappers , string_t ( 'ftn' )] end select compiler_specific call assert_mpi_wrappers ( fort_wrappers , compiler ) call assert_mpi_wrappers ( c_wrappers , compiler ) call assert_mpi_wrappers ( cpp_wrappers , compiler ) end subroutine mpi_wrappers !> Filter out invalid/unavailable mpi wrappers subroutine assert_mpi_wrappers ( wrappers , compiler , verbose ) type ( string_t ), allocatable , intent ( inout ) :: wrappers (:) type ( compiler_t ), intent ( in ) :: compiler logical , optional , intent ( in ) :: verbose integer :: i integer , allocatable :: works (:) allocate ( works ( size ( wrappers ))) do i = 1 , size ( wrappers ) if ( present ( verbose )) then if ( verbose ) print * , '+ MPI test wrapper <' , wrappers ( i )% s , '>' endif works ( i ) = which_mpi_library ( wrappers ( i ), compiler , verbose ) end do ! Filter out non-working wrappers wrappers = pack ( wrappers , works /= MPI_TYPE_NONE ) end subroutine assert_mpi_wrappers !> Simple call to execute_command_line involving one mpi* wrapper subroutine run_mpi_wrapper ( wrapper , args , verbose , exitcode , cmd_success , screen_output ) type ( string_t ), intent ( in ) :: wrapper type ( string_t ), intent ( in ), optional :: args (:) logical , intent ( in ), optional :: verbose integer , intent ( out ), optional :: exitcode logical , intent ( out ), optional :: cmd_success type ( string_t ), intent ( out ), optional :: screen_output logical :: echo_local character (:), allocatable :: redirect_str , command , redirect , line integer :: iunit , iarg , stat , cmdstat if ( present ( verbose )) then echo_local = verbose else echo_local = . false . end if ! No redirection and non-verbose output if ( present ( screen_output )) then redirect = get_temp_filename () redirect_str = \">\" // redirect // \" 2>&1\" else if ( os_is_unix ()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if ! Empty command if ( len_trim ( wrapper ) <= 0 ) then if ( echo_local ) print * , '+ ' if ( present ( exitcode )) exitcode = 0 if ( present ( cmd_success )) cmd_success = . true . if ( present ( screen_output )) screen_output = string_t ( \"\" ) return end if ! Init command command = trim ( wrapper % s ) add_arguments : if ( present ( args )) then do iarg = 1 , size ( args ) if ( len_trim ( args ( iarg )) <= 0 ) cycle command = trim ( command ) // ' ' // args ( iarg )% s end do endif add_arguments if ( echo_local ) print * , '+ ' , command ! Test command call execute_command_line ( command // redirect_str , exitstat = stat , cmdstat = cmdstat ) ! Command successful? if ( present ( cmd_success )) cmd_success = cmdstat == 0 ! Program exit code? if ( present ( exitcode )) exitcode = stat ! Want screen output? if ( present ( screen_output ) . and . cmdstat == 0 ) then allocate ( character ( len = 0 ) :: screen_output % s ) open ( newunit = iunit , file = redirect , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output % s = screen_output % s // new_line ( 'a' ) // line if ( echo_local ) write ( * , '(A)' ) trim ( line ) end do ! Close and delete file close ( iunit , status = 'delete' ) else call fpm_stop ( 1 , 'cannot read temporary file from successful MPI wrapper' ) endif end if end subroutine run_mpi_wrapper !> Get MPI library type from the wrapper command. Currently, only OpenMPI is supported integer function which_mpi_library ( wrapper , compiler , verbose ) type ( string_t ), intent ( in ) :: wrapper type ( compiler_t ), intent ( in ) :: compiler logical , intent ( in ), optional :: verbose logical :: is_mpi_wrapper integer :: stat ! Init as currently unsupported library which_mpi_library = MPI_TYPE_NONE if ( len_trim ( wrapper ) <= 0 ) return ! Run mpi wrapper first call run_mpi_wrapper ( wrapper , verbose = verbose , cmd_success = is_mpi_wrapper ) if ( is_mpi_wrapper ) then if ( compiler % is_intel ()) then which_mpi_library = MPI_TYPE_INTEL return end if ! Attempt to decipher which library this wrapper comes from. ! OpenMPI responds to '--showme' calls call run_mpi_wrapper ( wrapper ,[ string_t ( '--showme' )], verbose ,& exitcode = stat , cmd_success = is_mpi_wrapper ) if ( stat == 0 . and . is_mpi_wrapper ) then which_mpi_library = MPI_TYPE_OPENMPI return endif ! MPICH responds to '-show' calls call run_mpi_wrapper ( wrapper ,[ string_t ( '-show' )], verbose ,& exitcode = stat , cmd_success = is_mpi_wrapper ) if ( stat == 0 . and . is_mpi_wrapper ) then which_mpi_library = MPI_TYPE_MPICH return endif end if end function which_mpi_library !> Test if an MPI wrapper works type ( string_t ) function mpi_wrapper_query ( mpilib , wrapper , command , verbose , error ) result ( screen ) integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: wrapper character ( * ), intent ( in ) :: command logical , intent ( in ), optional :: verbose type ( error_t ), allocatable , intent ( out ) :: error logical :: success character (:), allocatable :: redirect_str , tokens (:), unsupported_msg type ( string_t ) :: cmdstr type ( compiler_t ) :: mpi_compiler integer :: stat , cmdstat , ire , length unsupported_msg = 'the MPI library of wrapper ' // wrapper % s // ' does not support task ' // trim ( command ) select case ( command ) ! Get MPI compiler name case ( 'compiler' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ); cmdstr = string_t ( '--showme:command' ) case ( MPI_TYPE_MPICH ); cmdstr = string_t ( '-compile-info' ) case ( MPI_TYPE_INTEL ); cmdstr = string_t ( '-show' ) case default call fatal_error ( error , unsupported_msg ) return end select call run_mpi_wrapper ( wrapper ,[ cmdstr ], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local ' // MPI_TYPE_NAME ( mpilib ) // & ' library wrapper does not support flag ' // cmdstr % s ) return end if ! Take out the first command from the whole line call split ( screen % s , tokens , delimiters = ' ' ) screen % s = trim ( adjustl ( tokens ( 1 ))) ! Get a list of additional compiler flags case ( 'flags' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ); cmdstr = string_t ( '--showme:compile' ) case ( MPI_TYPE_MPICH ); cmdstr = string_t ( '-compile-info' ) case ( MPI_TYPE_INTEL ); cmdstr = string_t ( '-show' ) case default call fatal_error ( error , unsupported_msg ) return end select call run_mpi_wrapper ( wrapper ,[ cmdstr ], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local ' // MPI_TYPE_NAME ( mpilib ) // & ' library wrapper does not support flag ' // cmdstr % s ) return end if ! Post-process output select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! This library reports the compiler name only call remove_newline_characters ( screen ) case ( MPI_TYPE_MPICH , MPI_TYPE_INTEL ) ! These libraries report the full command including the compiler name. Remove it if so call remove_newline_characters ( screen ) call split ( screen % s , tokens ) ! Remove trailing compiler name screen % s = screen % s ( len_trim ( tokens ( 1 )) + 1 :) case default call fatal_error ( error , 'invalid MPI library type' ) return end select ! Get a list of additional linker flags case ( 'link' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ); cmdstr = string_t ( '--showme:link' ) case ( MPI_TYPE_MPICH ); cmdstr = string_t ( '-link-info' ) case default call fatal_error ( error , unsupported_msg ) return end select call run_mpi_wrapper ( wrapper ,[ cmdstr ], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local ' // MPI_TYPE_NAME ( mpilib ) // & ' library wrapper does not support flag ' // cmdstr % s ) return end if select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) call remove_newline_characters ( screen ) case ( MPI_TYPE_MPICH ) ! MPICH reports the full command including the compiler name. Remove it if so call remove_newline_characters ( screen ) call split ( screen % s , tokens ) ! Remove trailing compiler name screen % s = screen % s ( len_trim ( tokens ( 1 )) + 1 :) case default call fatal_error ( error , unsupported_msg ) return end select ! Get a list of MPI library directories case ( 'link_dirs' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! --showme:command returns the build command of this wrapper call run_mpi_wrapper ( wrapper ,[ string_t ( '--showme:libdirs' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local OpenMPI library does not support --showme:libdirs' ) return end if case default call fatal_error ( error , unsupported_msg ) return end select ! Get a list of include directories for the MPI headers/modules case ( 'incl_dirs' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! --showme:command returns the build command of this wrapper call run_mpi_wrapper ( wrapper ,[ string_t ( '--showme:incdirs' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local OpenMPI library does not support --showme:incdirs' ) return end if case default call fatal_error ( error , unsupported_msg ) return end select call remove_newline_characters ( screen ) ! Retrieve library version case ( 'version' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! --showme:command returns the build command of this wrapper call run_mpi_wrapper ( wrapper ,[ string_t ( '--showme:version' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local OpenMPI library does not support --showme:version' ) return else call remove_newline_characters ( screen ) end if case ( MPI_TYPE_MPICH ) !> MPICH offers command \"mpichversion\" in the same system folder as the MPI wrappers. !> So, attempt to run that first cmdstr = string_t ( 'mpichversion' ) call run_mpi_wrapper ( cmdstr , verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) ! Second option: run mpich wrapper + \"-v\" if ( stat /= 0 . or . . not . success ) then call run_mpi_wrapper ( wrapper ,[ string_t ( '-v' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) call remove_newline_characters ( screen ) endif ! Third option: mpiexec --version if ( stat /= 0 . or . . not . success ) then cmdstr = string_t ( 'mpiexec --version' ) call run_mpi_wrapper ( cmdstr , verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) endif if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'cannot retrieve MPICH library version from ' ) return end if case ( MPI_TYPE_INTEL ) ! --showme:command returns the build command of this wrapper call run_mpi_wrapper ( wrapper ,[ string_t ( '-v' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local INTEL MPI library does not support -v' ) return else call remove_newline_characters ( screen ) end if case default call fatal_error ( error , unsupported_msg ) return end select ! Extract version screen = regex_version_from_text ( screen % s , MPI_TYPE_NAME ( mpilib ) // ' library' , error ) if ( allocated ( error )) return ! Get path to the MPI runner command case ( 'runner' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI , MPI_TYPE_MPICH , MPI_TYPE_MSMPI , MPI_TYPE_INTEL ) call get_mpi_runner ( screen , verbose , error ) case default call fatal_error ( error , unsupported_msg ) return end select case default ; call fatal_error ( error , 'an invalid MPI wrapper command (' // command // & ') was invoked for wrapper <' // wrapper % s // '>.' ) return end select end function mpi_wrapper_query end module fpm_meta","tags":"","loc":"sourcefile/fpm_meta.f90.html"},{"title":"fpm.f90 – Fortran-lang/fpm","text":"Contents Modules fpm Source Code fpm.f90 Source Code module fpm use fpm_strings , only : string_t , operator (. in .), glob , join , string_cat , & lower , str_ends_with , is_fortran_name , str_begins_with_str , & is_valid_module_name , len_trim use fpm_backend , only : build_package use fpm_command_line , only : fpm_build_settings , fpm_new_settings , & fpm_run_settings , fpm_install_settings , fpm_test_settings , & fpm_clean_settings use fpm_dependency , only : new_dependency_tree use fpm_filesystem , only : is_dir , join_path , list_files , exists , & basename , filewrite , mkdir , run , os_delete_dir use fpm_model , only : fpm_model_t , srcfile_t , show_model , fortran_features_t , & FPM_SCOPE_UNKNOWN , FPM_SCOPE_LIB , FPM_SCOPE_DEP , & FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST use fpm_compiler , only : new_compiler , new_archiver , set_cpp_preprocessor_flags use fpm_sources , only : add_executable_sources , add_sources_from_dir use fpm_targets , only : targets_from_sources , build_target_t , build_target_ptr , & FPM_TARGET_EXECUTABLE , FPM_TARGET_ARCHIVE use fpm_manifest , only : get_package_data , package_config_t use fpm_meta , only : resolve_metapackages use fpm_error , only : error_t , fatal_error , fpm_stop use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit use iso_c_binding , only : c_char , c_ptr , c_int , c_null_char , c_associated , c_f_pointer use fpm_environment , only : os_is_unix implicit none private public :: cmd_build , cmd_run , cmd_clean public :: build_model , check_modules_for_duplicates contains !> Constructs a valid fpm model from command line settings and the toml manifest. subroutine build_model ( model , settings , package , error ) type ( fpm_model_t ), intent ( out ) :: model class ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ), intent ( inout ) :: package type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( package_config_t ) :: dependency character ( len = :), allocatable :: manifest , lib_dir logical :: has_cpp logical :: duplicates_found type ( string_t ) :: include_dir model % package_name = package % name allocate ( model % include_dirs ( 0 )) allocate ( model % link_libraries ( 0 )) allocate ( model % external_modules ( 0 )) call new_compiler ( model % compiler , settings % compiler , settings % c_compiler , & & settings % cxx_compiler , echo = settings % verbose , verbose = settings % verbose ) call new_archiver ( model % archiver , settings % archiver , & & echo = settings % verbose , verbose = settings % verbose ) if ( model % compiler % is_unknown ()) then write ( * , '(*(a:,1x))' ) & \"\" , \"Unknown compiler\" , model % compiler % fc , \"requested!\" , & \"Defaults for this compiler might be incorrect\" end if call new_compiler_flags ( model , settings ) model % build_prefix = join_path ( \"build\" , basename ( model % compiler % fc )) model % include_tests = settings % build_tests model % enforce_module_names = package % build % module_naming model % module_prefix = package % build % module_prefix ! Resolve meta-dependencies into the package and the model call resolve_metapackages ( model , package , settings , error ) if ( allocated ( error )) return ! Create dependencies call new_dependency_tree ( model % deps , cache = join_path ( \"build\" , \"cache.toml\" )) ! Build and resolve model dependencies call model % deps % add ( package , error ) if ( allocated ( error )) return ! Update dependencies where needed call model % deps % update ( error ) if ( allocated ( error )) return ! build/ directory should now exist if (. not . exists ( \"build/.gitignore\" )) then call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if allocate ( model % packages ( model % deps % ndep )) has_cpp = . false . do i = 1 , model % deps % ndep associate ( dep => model % deps % dep ( i )) manifest = join_path ( dep % proj_dir , \"fpm.toml\" ) call get_package_data ( dependency , manifest , error , apply_defaults = . true .) if ( allocated ( error )) exit model % packages ( i )% name = dependency % name associate ( features => model % packages ( i )% features ) features % implicit_typing = dependency % fortran % implicit_typing features % implicit_external = dependency % fortran % implicit_external features % source_form = dependency % fortran % source_form end associate model % packages ( i )% version = package % version % s () !> Add this dependency's manifest macros allocate ( model % packages ( i )% macros ( 0 )) if ( allocated ( dependency % preprocess )) then do j = 1 , size ( dependency % preprocess ) if ( dependency % preprocess ( j )% name == \"cpp\" ) then if (. not . has_cpp ) has_cpp = . true . if ( allocated ( dependency % preprocess ( j )% macros )) then model % packages ( i )% macros = [ model % packages ( i )% macros , dependency % preprocess ( j )% macros ] end if else write ( stderr , '(a)' ) 'Warning: Preprocessor ' // package % preprocess ( i )% name // & ' is not supported; will ignore it' end if end do end if !> Add this dependency's package-level macros if ( allocated ( dep % preprocess )) then do j = 1 , size ( dep % preprocess ) if ( dep % preprocess ( j )% name == \"cpp\" ) then if (. not . has_cpp ) has_cpp = . true . if ( allocated ( dep % preprocess ( j )% macros )) then model % packages ( i )% macros = [ model % packages ( i )% macros , dep % preprocess ( j )% macros ] end if else write ( stderr , '(a)' ) 'Warning: Preprocessor ' // package % preprocess ( i )% name // & ' is not supported; will ignore it' end if end do end if if (. not . allocated ( model % packages ( i )% sources )) allocate ( model % packages ( i )% sources ( 0 )) if ( allocated ( dependency % library )) then if ( allocated ( dependency % library % source_dir )) then lib_dir = join_path ( dep % proj_dir , dependency % library % source_dir ) if ( is_dir ( lib_dir )) then call add_sources_from_dir ( model % packages ( i )% sources , lib_dir , FPM_SCOPE_LIB , & error = error ) if ( allocated ( error )) exit end if end if if ( allocated ( dependency % library % include_dir )) then do j = 1 , size ( dependency % library % include_dir ) include_dir % s = join_path ( dep % proj_dir , dependency % library % include_dir ( j )% s ) if ( is_dir ( include_dir % s )) then model % include_dirs = [ model % include_dirs , include_dir ] end if end do end if end if if ( allocated ( dependency % build % link )) then model % link_libraries = [ model % link_libraries , dependency % build % link ] end if if ( allocated ( dependency % build % external_modules )) then model % external_modules = [ model % external_modules , dependency % build % external_modules ] end if ! Copy naming conventions from this dependency's manifest model % packages ( i )% enforce_module_names = dependency % build % module_naming model % packages ( i )% module_prefix = dependency % build % module_prefix end associate end do if ( allocated ( error )) return ! Add optional flags if ( has_cpp ) call set_cpp_preprocessor_flags ( model % compiler % id , model % fortran_compile_flags ) ! Add sources from executable directories if ( is_dir ( 'app' ) . and . package % build % auto_executables ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'app' , FPM_SCOPE_APP , & with_executables = . true ., error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'example' ) . and . package % build % auto_examples ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'example' , FPM_SCOPE_EXAMPLE , & with_executables = . true ., error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'test' ) . and . package % build % auto_tests ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'test' , FPM_SCOPE_TEST , & with_executables = . true ., error = error ) if ( allocated ( error )) then return endif end if if ( allocated ( package % executable )) then call add_executable_sources ( model % packages ( 1 )% sources , package % executable , FPM_SCOPE_APP , & auto_discover = package % build % auto_executables , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % example )) then call add_executable_sources ( model % packages ( 1 )% sources , package % example , FPM_SCOPE_EXAMPLE , & auto_discover = package % build % auto_examples , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % test )) then call add_executable_sources ( model % packages ( 1 )% sources , package % test , FPM_SCOPE_TEST , & auto_discover = package % build % auto_tests , & error = error ) if ( allocated ( error )) then return endif endif if ( settings % verbose ) then write ( * , * ) ' BUILD_NAME: ' , model % build_prefix write ( * , * ) ' COMPILER: ' , model % compiler % fc write ( * , * ) ' C COMPILER: ' , model % compiler % cc write ( * , * ) ' CXX COMPILER: ' , model % compiler % cxx write ( * , * ) ' COMPILER OPTIONS: ' , model % fortran_compile_flags write ( * , * ) ' C COMPILER OPTIONS: ' , model % c_compile_flags write ( * , * ) ' CXX COMPILER OPTIONS: ' , model % cxx_compile_flags write ( * , * ) ' LINKER OPTIONS: ' , model % link_flags write ( * , * ) ' INCLUDE DIRECTORIES: [' , string_cat ( model % include_dirs , ',' ), ']' end if ! Check for invalid module names call check_module_names ( model , error ) if ( allocated ( error )) return ! Check for duplicate modules duplicates_found = . false . call check_modules_for_duplicates ( model , duplicates_found ) if ( duplicates_found ) then call fpm_stop ( 1 , '*build_model*:Error: One or more duplicate module names found.' ) end if end subroutine build_model !> Initialize model compiler flags subroutine new_compiler_flags ( model , settings ) type ( fpm_model_t ), intent ( inout ) :: model type ( fpm_build_settings ), intent ( in ) :: settings character ( len = :), allocatable :: flags , cflags , cxxflags , ldflags if ( settings % flag == '' ) then flags = model % compiler % get_default_flags ( settings % profile == \"release\" ) else flags = settings % flag select case ( settings % profile ) case ( \"release\" , \"debug\" ) flags = flags // model % compiler % get_default_flags ( settings % profile == \"release\" ) end select end if cflags = trim ( settings % cflag ) cxxflags = trim ( settings % cxxflag ) ldflags = trim ( settings % ldflag ) model % fortran_compile_flags = flags model % c_compile_flags = cflags model % cxx_compile_flags = cxxflags model % link_flags = ldflags end subroutine new_compiler_flags ! Check for duplicate modules subroutine check_modules_for_duplicates ( model , duplicates_found ) type ( fpm_model_t ), intent ( in ) :: model integer :: maxsize integer :: i , j , k , l , m , modi type ( string_t ), allocatable :: modules (:) logical :: duplicates_found ! Initialise the size of array maxsize = 0 ! Get number of modules provided by each source file of every package do i = 1 , size ( model % packages ) do j = 1 , size ( model % packages ( i )% sources ) if ( allocated ( model % packages ( i )% sources ( j )% modules_provided )) then maxsize = maxsize + size ( model % packages ( i )% sources ( j )% modules_provided ) end if end do end do ! Allocate array to contain distinct names of modules allocate ( modules ( maxsize )) ! Initialise index to point at start of the newly allocated array modi = 1 ! Loop through modules provided by each source file of every package ! Add it to the array if it is not already there ! Otherwise print out warning about duplicates do k = 1 , size ( model % packages ) do l = 1 , size ( model % packages ( k )% sources ) if ( allocated ( model % packages ( k )% sources ( l )% modules_provided )) then do m = 1 , size ( model % packages ( k )% sources ( l )% modules_provided ) if ( model % packages ( k )% sources ( l )% modules_provided ( m )% s . in . modules (: modi - 1 )) then write ( stderr , * ) \"Warning: Module \" , model % packages ( k )% sources ( l )% modules_provided ( m )% s , & \" in \" , model % packages ( k )% sources ( l )% file_name , \" is a duplicate\" duplicates_found = . true . else modules ( modi ) = model % packages ( k )% sources ( l )% modules_provided ( m ) modi = modi + 1 end if end do end if end do end do end subroutine check_modules_for_duplicates ! Check names of all modules in this package and its dependencies subroutine check_module_names ( model , error ) type ( fpm_model_t ), intent ( in ) :: model type ( error_t ), allocatable , intent ( out ) :: error integer :: k , l , m logical :: valid , errors_found , enforce_this_file type ( string_t ) :: package_name , module_name , package_prefix errors_found = . false . ! Loop through modules provided by each source file of every package ! Add it to the array if it is not already there ! Otherwise print out warning about duplicates do k = 1 , size ( model % packages ) package_name = string_t ( model % packages ( k )% name ) ! Custom prefix is taken from each dependency's manifest if ( model % packages ( k )% enforce_module_names ) then package_prefix = model % packages ( k )% module_prefix else package_prefix = string_t ( \"\" ) end if ! Warn the user if some of the dependencies have loose naming if ( model % enforce_module_names . and . . not . model % packages ( k )% enforce_module_names ) then write ( stderr , * ) \"Warning: Dependency \" , package_name % s // & \" does not enforce module naming, but project does. \" end if do l = 1 , size ( model % packages ( k )% sources ) ! Module naming is not enforced in test modules enforce_this_file = model % enforce_module_names . and . & model % packages ( k )% sources ( l )% unit_scope /= FPM_SCOPE_TEST if ( allocated ( model % packages ( k )% sources ( l )% modules_provided )) then do m = 1 , size ( model % packages ( k )% sources ( l )% modules_provided ) module_name = model % packages ( k )% sources ( l )% modules_provided ( m ) valid = is_valid_module_name ( module_name , & package_name , & package_prefix , & enforce_this_file ) if (. not . valid ) then if ( enforce_this_file ) then if ( len_trim ( package_prefix ) > 0 ) then write ( stderr , * ) \"ERROR: Module \" , module_name % s , & \" in \" , model % packages ( k )% sources ( l )% file_name , & \" does not match its package name (\" // package_name % s // & \") or custom prefix (\" // package_prefix % s // \").\" else write ( stderr , * ) \"ERROR: Module \" , module_name % s , & \" in \" , model % packages ( k )% sources ( l )% file_name , & \" does not match its package name (\" // package_name % s // \").\" endif else write ( stderr , * ) \"ERROR: Module \" , module_name % s , & \" in \" , model % packages ( k )% sources ( l )% file_name , & \" has an invalid Fortran name. \" end if errors_found = . true . end if end do end if end do end do if ( errors_found ) then if ( model % enforce_module_names ) & write ( stderr , * ) \" Hint: Try disabling module naming in the manifest: [build] module-naming=false . \" call fatal_error ( error , \"The package contains invalid module names. \" // & \"Naming conventions \" // merge ( 'are' , 'not' , model % enforce_module_names ) // & \" being requested.\" ) end if end subroutine check_module_names subroutine cmd_build ( settings ) type ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( error_t ), allocatable :: error integer :: i call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Target error: ' // error % message ) end if if ( settings % list ) then do i = 1 , size ( targets ) write ( stderr , * ) targets ( i )% ptr % output_file enddo else if ( settings % show_model ) then call show_model ( model ) else call build_package ( targets , model , verbose = settings % verbose ) endif end subroutine cmd_build subroutine cmd_run ( settings , test ) class ( fpm_run_settings ), intent ( inout ) :: settings logical , intent ( in ) :: test integer :: i , j , col_width logical :: found ( size ( settings % name )) type ( error_t ), allocatable :: error type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( string_t ) :: exe_cmd type ( string_t ), allocatable :: executables (:) type ( build_target_t ), pointer :: exe_target type ( srcfile_t ), pointer :: exe_source integer :: run_scope , firsterror integer , allocatable :: stat (:) character ( len = :), allocatable :: line logical :: toomany call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Targets error: ' // error % message ) end if if ( test ) then run_scope = FPM_SCOPE_TEST else run_scope = merge ( FPM_SCOPE_EXAMPLE , FPM_SCOPE_APP , settings % example ) end if ! Enumerate executable targets to run col_width = - 1 found (:) = . false . allocate ( executables ( 0 )) do i = 1 , size ( targets ) exe_target => targets ( i )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then col_width = max ( col_width , len ( basename ( exe_target % output_file )) + 2 ) if ( size ( settings % name ) == 0 ) then exe_cmd % s = exe_target % output_file executables = [ executables , exe_cmd ] else do j = 1 , size ( settings % name ) if ( glob ( trim ( exe_source % exe_name ), trim ( settings % name ( j )))) then found ( j ) = . true . exe_cmd % s = exe_target % output_file executables = [ executables , exe_cmd ] end if end do end if end if end if end do ! Check if any apps/tests were found if ( col_width < 0 ) then if ( test ) then call fpm_stop ( 0 , 'No tests to run' ) else call fpm_stop ( 0 , 'No executables to run' ) end if end if ! Check all names are valid ! or no name and found more than one file toomany = size ( settings % name ) == 0 . and . size ( executables ) > 1 if ( any (. not . found ) & & . or . & & ( ( toomany . and . . not . test ) . or . ( toomany . and . settings % runner /= '' ) ) & & . and . & & . not . settings % list ) then line = join ( settings % name ) if ( line /= '.' ) then ! do not report these special strings if ( any (. not . found )) then write ( stderr , '(A)' , advance = \"no\" ) '*cmd_run*:specified names ' do j = 1 , size ( settings % name ) if (. not . found ( j )) write ( stderr , '(A)' , advance = \"no\" ) '\"' // trim ( settings % name ( j )) // '\" ' end do write ( stderr , '(A)' ) 'not found.' write ( stderr , * ) else if ( settings % verbose ) then write ( stderr , '(A)' , advance = \"yes\" ) 'when more than one executable is available' write ( stderr , '(A)' , advance = \"yes\" ) ' program names must be specified.' endif endif call compact_list_all () if ( line == '.' . or . line == ' ' ) then ! do not report these special strings call fpm_stop ( 0 , '' ) else call fpm_stop ( 1 , '' ) endif end if call build_package ( targets , model , verbose = settings % verbose ) if ( settings % list ) then call compact_list () else allocate ( stat ( size ( executables ))) do i = 1 , size ( executables ) if ( exists ( executables ( i )% s )) then if ( settings % runner /= ' ' ) then if (. not . allocated ( settings % args )) then call run ( settings % runner_command () // ' ' // executables ( i )% s , & echo = settings % verbose , exitstat = stat ( i )) else call run ( settings % runner_command () // ' ' // executables ( i )% s // \" \" // settings % args , & echo = settings % verbose , exitstat = stat ( i )) endif else if (. not . allocated ( settings % args )) then call run ( executables ( i )% s , echo = settings % verbose , exitstat = stat ( i )) else call run ( executables ( i )% s // \" \" // settings % args , echo = settings % verbose , & exitstat = stat ( i )) endif endif else call fpm_stop ( 1 , '*cmd_run*:' // executables ( i )% s // ' not found' ) end if end do if ( any ( stat /= 0 )) then do i = 1 , size ( stat ) if ( stat ( i ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Execution for object \"' , basename ( executables ( i )% s ),& '\" returned exit code ' , stat ( i ) end if end do firsterror = findloc ( stat /= 0 , value = . true ., dim = 1 ) call fpm_stop ( stat ( firsterror ), '*cmd_run*:stopping due to failed executions' ) end if end if contains subroutine compact_list_all () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Available names:' do ii = 1 , size ( targets ) exe_target => targets ( ii )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( exe_target % output_file , suffix = . false .)] jj = jj + 1 end if end if end do write ( stderr , * ) end subroutine compact_list_all subroutine compact_list () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Matched names:' do ii = 1 , size ( executables ) write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( executables ( ii )% s , suffix = . false .)] jj = jj + 1 end do write ( stderr , * ) end subroutine compact_list end subroutine cmd_run subroutine delete_skip ( is_unix ) !> delete directories in the build folder, skipping dependencies logical , intent ( in ) :: is_unix character ( len = :), allocatable :: dir type ( string_t ), allocatable :: files (:) integer :: i call list_files ( 'build' , files , . false .) do i = 1 , size ( files ) if ( is_dir ( files ( i )% s )) then dir = files ( i )% s if (. not . str_ends_with ( dir , 'dependencies' )) call os_delete_dir ( is_unix , dir ) end if end do end subroutine delete_skip !> Delete the build directory including or excluding dependencies. subroutine cmd_clean ( settings ) !> Settings for the clean command. class ( fpm_clean_settings ), intent ( in ) :: settings character :: user_response if ( is_dir ( 'build' )) then ! Remove the entire build directory if ( settings % clean_call ) then call os_delete_dir ( os_is_unix (), 'build' ); return end if ! Remove the build directory but skip dependencies if ( settings % clean_skip ) then call delete_skip ( os_is_unix ()); return end if ! Prompt to remove the build directory but skip dependencies write ( stdout , '(A)' , advance = 'no' ) \"Delete build, excluding dependencies (y/n)? \" read ( stdin , '(A1)' ) user_response if ( lower ( user_response ) == 'y' ) call delete_skip ( os_is_unix ()) else write ( stdout , '(A)' ) \"fpm: No build directory found.\" end if end subroutine cmd_clean end module fpm","tags":"","loc":"sourcefile/fpm.f90.html"},{"title":"fpm_targets.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_targets Source Code fpm_targets.f90 Source Code !># Build target handling !> !> This module handles the construction of the build target list !> from the sources list (`[[targets_from_sources]]`), the !> resolution of module-dependencies between build targets !> (`[[resolve_module_dependencies]]`), and the enumeration of !> objects required for link targets (`[[resolve_target_linking]]`). !> !> A build target (`[[build_target_t]]`) is a file to be generated !> by the backend (compilation and linking). !> !> @note The current implementation is ignorant to the existence of !> module files (`.mod`,`.smod`). Dependencies arising from modules !> are based on the corresponding object files (`.o`) only. !> !> For more information, please read the documentation for the procedures: !> !> - `[[build_target_list]]` !> - `[[resolve_module_dependencies]]` !> !>### Enumerations !> !> __Target type:__ `FPM_TARGET_*` !> Describes the type of build target — determines backend build rules !> module fpm_targets use iso_fortran_env , only : int64 use fpm_error , only : error_t , fatal_error , fpm_stop use fpm_model use fpm_compiler , only : compiler_t use fpm_environment , only : get_os_type , OS_WINDOWS , OS_MACOS use fpm_filesystem , only : dirname , join_path , canon_path use fpm_strings , only : string_t , operator (. in .), string_cat , fnv_1a , resize , lower , str_ends_with use fpm_compiler , only : get_macros use fpm_sources , only : get_exe_name_with_suffix implicit none private public FPM_TARGET_UNKNOWN , FPM_TARGET_EXECUTABLE , & FPM_TARGET_ARCHIVE , FPM_TARGET_OBJECT , & FPM_TARGET_C_OBJECT , FPM_TARGET_CPP_OBJECT public build_target_t , build_target_ptr public targets_from_sources , resolve_module_dependencies public add_target , add_dependency public filter_library_targets , filter_executable_targets , filter_modules !> Target type is unknown (ignored) integer , parameter :: FPM_TARGET_UNKNOWN = - 1 !> Target type is executable integer , parameter :: FPM_TARGET_EXECUTABLE = 1 !> Target type is library archive integer , parameter :: FPM_TARGET_ARCHIVE = 2 !> Target type is compiled object integer , parameter :: FPM_TARGET_OBJECT = 3 !> Target type is c compiled object integer , parameter :: FPM_TARGET_C_OBJECT = 4 !> Target type is cpp compiled object integer , parameter :: FPM_TARGET_CPP_OBJECT = 5 !> Wrapper type for constructing arrays of `[[build_target_t]]` pointers type build_target_ptr type ( build_target_t ), pointer :: ptr => null () end type build_target_ptr !> Type describing a generated build target type build_target_t !> File path of build target object relative to cwd character (:), allocatable :: output_file !> File path of build target object relative to output_dir character (:), allocatable :: output_name !> File path of output directory character (:), allocatable :: output_dir !> File path of build log file relative to cwd character (:), allocatable :: output_log_file !> Name of parent package character (:), allocatable :: package_name !> Primary source for this build target type ( srcfile_t ), allocatable :: source !> Resolved build dependencies type ( build_target_ptr ), allocatable :: dependencies (:) !> Target type integer :: target_type = FPM_TARGET_UNKNOWN !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Objects needed to link this target type ( string_t ), allocatable :: link_objects (:) !> Link flags for this build target character (:), allocatable :: link_flags !> Compile flags for this build target character (:), allocatable :: compile_flags !> Flag set when first visited to check for circular dependencies logical :: touched = . false . !> Flag set if build target is sorted for building logical :: sorted = . false . !> Flag set if build target will be skipped (not built) logical :: skip = . false . !> Language features type ( fortran_features_t ) :: features !> Targets in the same schedule group are guaranteed to be independent integer :: schedule = - 1 !> Previous source file hash integer ( int64 ), allocatable :: digest_cached !> List of macros type ( string_t ), allocatable :: macros (:) !> Version number character (:), allocatable :: version end type build_target_t contains !> High-level wrapper to generate build target information subroutine targets_from_sources ( targets , model , prune , error ) !> The generated list of build targets type ( build_target_ptr ), intent ( out ), allocatable :: targets (:) !> The package model from which to construct the target list type ( fpm_model_t ), intent ( inout ), target :: model !> Enable tree-shaking/pruning of module dependencies logical , intent ( in ) :: prune !> Error structure type ( error_t ), intent ( out ), allocatable :: error call build_target_list ( targets , model ) call collect_exe_link_dependencies ( targets ) call resolve_module_dependencies ( targets , model % external_modules , error ) if ( allocated ( error )) return if ( prune ) then call prune_build_targets ( targets , root_package = model % package_name ) end if call resolve_target_linking ( targets , model ) end subroutine targets_from_sources !> Constructs a list of build targets from a list of source files !> !>### Source-target mapping !> !> One compiled object target (`FPM_TARGET_OBJECT`) is generated for each !> non-executable source file (`FPM_UNIT_MODULE`,`FPM_UNIT_SUBMODULE`, !> `FPM_UNIT_SUBPROGRAM`,`FPM_UNIT_CSOURCE`). !> !> If any source file has scope `FPM_SCOPE_LIB` (*i.e.* there are library sources) !> then the first target in the target list will be a library archive target !> (`FPM_TARGET_ARCHIVE`). The archive target will have a dependency on every !> compiled object target corresponding to a library source file. !> !> One compiled object target (`FPM_TARGET_OBJECT`) and one executable target (`FPM_TARGET_EXECUTABLE`) is !> generated for each exectuable source file (`FPM_UNIT_PROGRAM`). The exectuble target !> always has a dependency on the corresponding compiled object target. If there !> is a library, then the executable target has an additional dependency on the library !> archive target. !> subroutine build_target_list ( targets , model ) !> The generated list of build targets type ( build_target_ptr ), intent ( out ), allocatable :: targets (:) !> The package model from which to construct the target list type ( fpm_model_t ), intent ( inout ), target :: model integer :: i , j , n_source , exe_type character (:), allocatable :: exe_dir , compile_flags logical :: with_lib ! Initialize targets allocate ( targets ( 0 )) ! Check for empty build (e.g. header-only lib) n_source = sum ([( size ( model % packages ( j )% sources ), & j = 1 , size ( model % packages ))]) if ( n_source < 1 ) return with_lib = any ([(( model % packages ( j )% sources ( i )% unit_scope == FPM_SCOPE_LIB , & i = 1 , size ( model % packages ( j )% sources )), & j = 1 , size ( model % packages ))]) if ( with_lib ) call add_target ( targets , package = model % package_name , type = FPM_TARGET_ARCHIVE ,& output_name = join_path (& model % package_name , 'lib' // model % package_name // '.a' )) do j = 1 , size ( model % packages ) associate ( sources => model % packages ( j )% sources ) do i = 1 , size ( sources ) if (. not . model % include_tests ) then if ( sources ( i )% unit_scope == FPM_SCOPE_TEST ) cycle end if select case ( sources ( i )% unit_type ) case ( FPM_UNIT_MODULE , FPM_UNIT_SUBMODULE , FPM_UNIT_SUBPROGRAM , FPM_UNIT_CSOURCE ) call add_target ( targets , package = model % packages ( j )% name , source = sources ( i ), & type = merge ( FPM_TARGET_C_OBJECT , FPM_TARGET_OBJECT ,& sources ( i )% unit_type == FPM_UNIT_CSOURCE ), & output_name = get_object_name ( sources ( i )), & features = model % packages ( j )% features , & macros = model % packages ( j )% macros , & version = model % packages ( j )% version ) if ( with_lib . and . sources ( i )% unit_scope == FPM_SCOPE_LIB ) then ! Archive depends on object call add_dependency ( targets ( 1 )% ptr , targets ( size ( targets ))% ptr ) end if case ( FPM_UNIT_CPPSOURCE ) call add_target ( targets , package = model % packages ( j )% name , source = sources ( i ), & type = FPM_TARGET_CPP_OBJECT , & output_name = get_object_name ( sources ( i )), & macros = model % packages ( j )% macros , & version = model % packages ( j )% version ) if ( with_lib . and . sources ( i )% unit_scope == FPM_SCOPE_LIB ) then ! Archive depends on object call add_dependency ( targets ( 1 )% ptr , targets ( size ( targets ))% ptr ) end if !> Add stdc++ as a linker flag. If not already there. if (. not . ( \"stdc++\" . in . model % link_libraries )) then if ( get_os_type () == OS_MACOS ) then model % link_libraries = [ model % link_libraries , string_t ( \"c++\" )] else model % link_libraries = [ model % link_libraries , string_t ( \"stdc++\" )] end if end if case ( FPM_UNIT_PROGRAM ) if ( str_ends_with ( lower ( sources ( i )% file_name ), [ \".c\" ])) then exe_type = FPM_TARGET_C_OBJECT else if ( str_ends_with ( lower ( sources ( i )% file_name ), [ \".cpp\" , \".cc \" ])) then exe_type = FPM_TARGET_CPP_OBJECT else ! Default to a Fortran object exe_type = FPM_TARGET_OBJECT end if call add_target ( targets , package = model % packages ( j )% name , type = exe_type ,& output_name = get_object_name ( sources ( i )), & source = sources ( i ), & features = model % packages ( j )% features , & macros = model % packages ( j )% macros & ) if ( sources ( i )% unit_scope == FPM_SCOPE_APP ) then exe_dir = 'app' else if ( sources ( i )% unit_scope == FPM_SCOPE_EXAMPLE ) then exe_dir = 'example' else exe_dir = 'test' end if call add_target ( targets , package = model % packages ( j )% name , type = FPM_TARGET_EXECUTABLE ,& link_libraries = sources ( i )% link_libraries , & output_name = join_path ( exe_dir , get_exe_name_with_suffix ( sources ( i )))) associate ( target => targets ( size ( targets ))% ptr ) ! Linker-only flags are necessary on some compilers for codes with non-Fortran main select case ( exe_type ) case ( FPM_TARGET_C_OBJECT ) call model % compiler % get_main_flags ( \"c\" , compile_flags ) case ( FPM_TARGET_CPP_OBJECT ) call model % compiler % get_main_flags ( \"c++\" , compile_flags ) case default compile_flags = \"\" end select target % compile_flags = target % compile_flags // ' ' // compile_flags ! Executable depends on object call add_dependency ( target , targets ( size ( targets ) - 1 )% ptr ) if ( with_lib ) then ! Executable depends on library call add_dependency ( target , targets ( 1 )% ptr ) end if endassociate end select end do end associate end do contains function get_object_name ( source ) result ( object_file ) ! Generate object target path from source name and model params ! ! type ( srcfile_t ), intent ( in ) :: source character (:), allocatable :: object_file integer :: i character ( 1 ), parameter :: filesep = '/' object_file = canon_path ( source % file_name ) ! Convert any remaining directory separators to underscores i = index ( object_file , filesep ) do while ( i > 0 ) object_file ( i : i ) = '_' i = index ( object_file , filesep ) end do object_file = join_path ( model % package_name , object_file ) // '.o' end function get_object_name end subroutine build_target_list !> Add non-library non-module dependencies for executable targets !> !> Executable targets will link to any non-program non-module source files that !> are in the same directory or in a subdirectory. !> !> (Note: Fortran module dependencies are handled separately in !> `resolve_module_dependencies` and `resolve_target_linking`.) !> subroutine collect_exe_link_dependencies ( targets ) type ( build_target_ptr ), intent ( inout ) :: targets (:) integer :: i , j character (:), allocatable :: exe_source_dir ! Add non-module dependencies for executables do j = 1 , size ( targets ) if ( targets ( j )% ptr % target_type == FPM_TARGET_EXECUTABLE ) then do i = 1 , size ( targets ) if ( i == j ) cycle associate ( exe => targets ( j )% ptr , dep => targets ( i )% ptr ) exe_source_dir = dirname ( exe % dependencies ( 1 )% ptr % source % file_name ) if ( allocated ( dep % source )) then if ( dep % source % unit_scope /= FPM_SCOPE_LIB . and . & dep % source % unit_type /= FPM_UNIT_PROGRAM . and . & dep % source % unit_type /= FPM_UNIT_MODULE . and . & index ( dirname ( dep % source % file_name ), exe_source_dir ) == 1 ) then call add_dependency ( exe , dep ) end if end if end associate end do end if end do end subroutine collect_exe_link_dependencies !> Allocate a new target and append to target list subroutine add_target ( targets , package , type , output_name , source , link_libraries , & & features , macros , version ) type ( build_target_ptr ), allocatable , intent ( inout ) :: targets (:) character ( * ), intent ( in ) :: package integer , intent ( in ) :: type character ( * ), intent ( in ) :: output_name type ( srcfile_t ), intent ( in ), optional :: source type ( string_t ), intent ( in ), optional :: link_libraries (:) type ( fortran_features_t ), intent ( in ), optional :: features type ( string_t ), intent ( in ), optional :: macros (:) character ( * ), intent ( in ), optional :: version integer :: i type ( build_target_t ), pointer :: new_target if (. not . allocated ( targets )) allocate ( targets ( 0 )) ! Check for duplicate outputs do i = 1 , size ( targets ) if ( targets ( i )% ptr % output_name == output_name ) then write ( * , * ) 'Error while building target list: duplicate output object \"' ,& output_name , '\"' if ( present ( source )) write ( * , * ) ' Source file: \"' , source % file_name , '\"' call fpm_stop ( 1 , ' ' ) end if end do allocate ( new_target ) new_target % target_type = type new_target % output_name = output_name new_target % package_name = package if ( present ( source )) new_target % source = source if ( present ( link_libraries )) new_target % link_libraries = link_libraries if ( present ( features )) new_target % features = features if ( present ( macros )) new_target % macros = macros if ( present ( version )) new_target % version = version allocate ( new_target % dependencies ( 0 )) targets = [ targets , build_target_ptr ( new_target )] end subroutine add_target !> Add pointer to dependeny in target%dependencies subroutine add_dependency ( target , dependency ) type ( build_target_t ), intent ( inout ) :: target type ( build_target_t ) , intent ( in ), target :: dependency target % dependencies = [ target % dependencies , build_target_ptr ( dependency )] end subroutine add_dependency !> Add dependencies to source-based targets (`FPM_TARGET_OBJECT`) !> based on any modules used by the corresponding source file. !> !>### Source file scoping !> !> Source files are assigned a scope of either `FPM_SCOPE_LIB`, !> `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`. The scope controls which !> modules may be used by the source file: !> !> - Library sources (`FPM_SCOPE_LIB`) may only use modules !> also with library scope. This includes library modules !> from dependencies. !> !> - Executable sources (`FPM_SCOPE_APP`,`FPM_SCOPE_TEST`) may use !> library modules (including dependencies) as well as any modules !> corresponding to source files in the same directory or a !> subdirectory of the executable source file. !> !> @warning If a module used by a source file cannot be resolved to !> a source file in the package of the correct scope, then a __fatal error__ !> is returned by the procedure and model construction fails. !> subroutine resolve_module_dependencies ( targets , external_modules , error ) type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( string_t ), intent ( in ) :: external_modules (:) type ( error_t ), allocatable , intent ( out ) :: error type ( build_target_ptr ) :: dep integer :: i , j do i = 1 , size ( targets ) if (. not . allocated ( targets ( i )% ptr % source )) cycle do j = 1 , size ( targets ( i )% ptr % source % modules_used ) if ( targets ( i )% ptr % source % modules_used ( j )% s . in . targets ( i )% ptr % source % modules_provided ) then ! Dependency satisfied in same file, skip cycle end if if ( targets ( i )% ptr % source % modules_used ( j )% s . in . external_modules ) then ! Dependency satisfied in system-installed module cycle end if if ( any ( targets ( i )% ptr % source % unit_scope == & [ FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST ])) then dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s , & include_dir = dirname ( targets ( i )% ptr % source % file_name )) else dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s ) end if if (. not . associated ( dep % ptr )) then call fatal_error ( error , & 'Unable to find source for module dependency: \"' // & targets ( i )% ptr % source % modules_used ( j )% s // & '\" used by \"' // targets ( i )% ptr % source % file_name // '\"' ) return end if call add_dependency ( targets ( i )% ptr , dep % ptr ) end do end do end subroutine resolve_module_dependencies function find_module_dependency ( targets , module_name , include_dir ) result ( target_ptr ) ! Find a module dependency in the library or a dependency library ! ! 'include_dir' specifies an allowable non-library search directory ! (Used for executable dependencies) ! type ( build_target_ptr ), intent ( in ), target :: targets (:) character ( * ), intent ( in ) :: module_name character ( * ), intent ( in ), optional :: include_dir type ( build_target_t ), pointer :: target_ptr integer :: k , l target_ptr => NULL () do k = 1 , size ( targets ) if (. not . allocated ( targets ( k )% ptr % source )) cycle do l = 1 , size ( targets ( k )% ptr % source % modules_provided ) if ( module_name == targets ( k )% ptr % source % modules_provided ( l )% s ) then select case ( targets ( k )% ptr % source % unit_scope ) case ( FPM_SCOPE_LIB , FPM_SCOPE_DEP ) target_ptr => targets ( k )% ptr exit case default if ( present ( include_dir )) then if ( index ( dirname ( targets ( k )% ptr % source % file_name ), include_dir ) == 1 ) then ! source file is within the include_dir or a subdirectory target_ptr => targets ( k )% ptr exit end if end if end select end if end do end do end function find_module_dependency !> Perform tree-shaking to remove unused module targets subroutine prune_build_targets ( targets , root_package ) !> Build target list to prune type ( build_target_ptr ), intent ( inout ), allocatable :: targets (:) !> Name of root package character ( * ), intent ( in ) :: root_package integer :: i , j , nexec type ( string_t ), allocatable :: modules_used (:) logical :: exclude_target ( size ( targets )) logical , allocatable :: exclude_from_archive (:) if ( size ( targets ) < 1 ) then return end if nexec = 0 allocate ( modules_used ( 0 )) ! Enumerate modules used by executables, non-module subprograms and their dependencies do i = 1 , size ( targets ) if ( targets ( i )% ptr % target_type == FPM_TARGET_EXECUTABLE ) then nexec = nexec + 1 call collect_used_modules ( targets ( i )% ptr ) elseif ( allocated ( targets ( i )% ptr % source )) then if ( targets ( i )% ptr % source % unit_type == FPM_UNIT_SUBPROGRAM ) then call collect_used_modules ( targets ( i )% ptr ) end if end if end do ! If there aren't any executables, then prune ! based on modules used in root package if ( nexec < 1 ) then do i = 1 , size ( targets ) if ( targets ( i )% ptr % package_name == root_package . and . & targets ( i )% ptr % target_type /= FPM_TARGET_ARCHIVE ) then call collect_used_modules ( targets ( i )% ptr ) end if end do end if call reset_target_flags ( targets ) exclude_target (:) = . false . ! Exclude purely module targets if they are not used anywhere do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( allocated ( target % source )) then if ( target % source % unit_type == FPM_UNIT_MODULE ) then exclude_target ( i ) = . true . target % skip = . true . do j = 1 , size ( target % source % modules_provided ) if ( target % source % modules_provided ( j )% s . in . modules_used ) then exclude_target ( i ) = . false . target % skip = . false . end if end do elseif ( target % source % unit_type == FPM_UNIT_SUBMODULE ) then ! Remove submodules if their parents are not used exclude_target ( i ) = . true . target % skip = . true . do j = 1 , size ( target % source % parent_modules ) if ( target % source % parent_modules ( j )% s . in . modules_used ) then exclude_target ( i ) = . false . target % skip = . false . end if end do end if end if ! (If there aren't any executables then we only prune modules from dependencies) if ( nexec < 1 . and . target % package_name == root_package ) then exclude_target ( i ) = . false . target % skip = . false . end if end associate end do targets = pack ( targets ,. not . exclude_target ) ! Remove unused targets from archive dependency list if ( targets ( 1 )% ptr % target_type == FPM_TARGET_ARCHIVE ) then associate ( archive => targets ( 1 )% ptr ) allocate ( exclude_from_archive ( size ( archive % dependencies ))) exclude_from_archive (:) = . false . do i = 1 , size ( archive % dependencies ) if ( archive % dependencies ( i )% ptr % skip ) then exclude_from_archive ( i ) = . true . end if end do archive % dependencies = pack ( archive % dependencies ,. not . exclude_from_archive ) end associate end if contains !> Recursively collect which modules are actually used recursive subroutine collect_used_modules ( target ) type ( build_target_t ), intent ( inout ) :: target integer :: j , k if ( target % touched ) then return else target % touched = . true . end if if ( allocated ( target % source )) then ! Add modules from this target and from any of it's children submodules do j = 1 , size ( target % source % modules_provided ) if (. not .( target % source % modules_provided ( j )% s . in . modules_used )) then modules_used = [ modules_used , target % source % modules_provided ( j )] end if ! Recurse into child submodules do k = 1 , size ( targets ) if ( allocated ( targets ( k )% ptr % source )) then if ( targets ( k )% ptr % source % unit_type == FPM_UNIT_SUBMODULE ) then if ( target % source % modules_provided ( j )% s . in . targets ( k )% ptr % source % parent_modules ) then call collect_used_modules ( targets ( k )% ptr ) end if end if end if end do end do end if ! Recurse into dependencies do j = 1 , size ( target % dependencies ) if ( target % dependencies ( j )% ptr % target_type /= FPM_TARGET_ARCHIVE ) then call collect_used_modules ( target % dependencies ( j )% ptr ) end if end do end subroutine collect_used_modules !> Reset target flags after recursive search subroutine reset_target_flags ( targets ) type ( build_target_ptr ), intent ( inout ) :: targets (:) integer :: i do i = 1 , size ( targets ) targets ( i )% ptr % touched = . false . end do end subroutine reset_target_flags end subroutine prune_build_targets !> Construct the linker flags string for each target !> `target%link_flags` includes non-library objects and library flags !> subroutine resolve_target_linking ( targets , model ) type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( fpm_model_t ), intent ( in ) :: model integer :: i character (:), allocatable :: global_link_flags , local_link_flags character (:), allocatable :: global_include_flags if ( size ( targets ) == 0 ) return global_link_flags = \"\" if ( allocated ( model % link_libraries )) then if ( size ( model % link_libraries ) > 0 ) then global_link_flags = model % compiler % enumerate_libraries ( global_link_flags , model % link_libraries ) end if end if allocate ( character ( 0 ) :: global_include_flags ) if ( allocated ( model % include_dirs )) then if ( size ( model % include_dirs ) > 0 ) then global_include_flags = global_include_flags // & & \" -I\" // string_cat ( model % include_dirs , \" -I\" ) end if end if do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) ! If the main program is a C/C++ one, some compilers require additional linking flags, see ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main ! In this case, compile_flags were already allocated if (. not . allocated ( target % compile_flags )) allocate ( character ( len = 0 ) :: target % compile_flags ) target % compile_flags = target % compile_flags // ' ' select case ( target % target_type ) case ( FPM_TARGET_C_OBJECT ) target % compile_flags = target % compile_flags // model % c_compile_flags case ( FPM_TARGET_CPP_OBJECT ) target % compile_flags = target % compile_flags // model % cxx_compile_flags case default target % compile_flags = target % compile_flags // model % fortran_compile_flags & & // get_feature_flags ( model % compiler , target % features ) end select !> Get macros as flags. target % compile_flags = target % compile_flags // get_macros ( model % compiler % id , & target % macros , & target % version ) if ( len ( global_include_flags ) > 0 ) then target % compile_flags = target % compile_flags // global_include_flags end if target % output_dir = get_output_dir ( model % build_prefix , target % compile_flags ) target % output_file = join_path ( target % output_dir , target % output_name ) target % output_log_file = join_path ( target % output_dir , target % output_name ) // '.log' end associate end do call add_include_build_dirs ( model , targets ) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) allocate ( target % link_objects ( 0 )) if ( target % target_type == FPM_TARGET_ARCHIVE ) then global_link_flags = target % output_file // global_link_flags call get_link_objects ( target % link_objects , target , is_exe = . false .) allocate ( character ( 0 ) :: target % link_flags ) else if ( target % target_type == FPM_TARGET_EXECUTABLE ) then call get_link_objects ( target % link_objects , target , is_exe = . true .) local_link_flags = \"\" if ( allocated ( model % link_flags )) local_link_flags = model % link_flags target % link_flags = model % link_flags // \" \" // string_cat ( target % link_objects , \" \" ) if ( allocated ( target % link_libraries )) then if ( size ( target % link_libraries ) > 0 ) then target % link_flags = model % compiler % enumerate_libraries ( target % link_flags , target % link_libraries ) local_link_flags = model % compiler % enumerate_libraries ( local_link_flags , target % link_libraries ) end if end if target % link_flags = target % link_flags // \" \" // global_link_flags target % output_dir = get_output_dir ( model % build_prefix , & & target % compile_flags // local_link_flags ) target % output_file = join_path ( target % output_dir , target % output_name ) target % output_log_file = join_path ( target % output_dir , target % output_name ) // '.log' end if end associate end do contains !> Wrapper to build link object list !> !> For libraries: just list dependency objects of lib target !> !> For executables: need to recursively discover non-library !> dependency objects. (i.e. modules in same dir as program) !> recursive subroutine get_link_objects ( link_objects , target , is_exe ) type ( string_t ), intent ( inout ), allocatable :: link_objects (:) type ( build_target_t ), intent ( in ) :: target logical , intent ( in ) :: is_exe integer :: i type ( string_t ) :: temp_str if (. not . allocated ( target % dependencies )) return do i = 1 , size ( target % dependencies ) associate ( dep => target % dependencies ( i )% ptr ) if (. not . allocated ( dep % source )) cycle ! Skip library dependencies for executable targets ! since the library archive will always be linked if ( is_exe . and .( dep % source % unit_scope == FPM_SCOPE_LIB )) cycle ! Skip if dependency object already listed if ( dep % output_file . in . link_objects ) cycle ! Add dependency object file to link object list temp_str % s = dep % output_file link_objects = [ link_objects , temp_str ] ! For executable objects, also need to include non-library ! dependencies from dependencies (recurse) if ( is_exe ) call get_link_objects ( link_objects , dep , is_exe = . true .) end associate end do end subroutine get_link_objects end subroutine resolve_target_linking subroutine add_include_build_dirs ( model , targets ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_ptr ), intent ( inout ), target :: targets (:) integer :: i type ( string_t ), allocatable :: build_dirs (:) type ( string_t ) :: temp allocate ( build_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % target_type /= FPM_TARGET_OBJECT ) cycle if ( target % output_dir . in . build_dirs ) cycle temp % s = target % output_dir build_dirs = [ build_dirs , temp ] end associate end do do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % target_type /= FPM_TARGET_OBJECT ) cycle target % compile_flags = target % compile_flags // & \" \" // model % compiler % get_module_flag ( target % output_dir ) // & \" -I\" // string_cat ( build_dirs , \" -I\" ) end associate end do end subroutine add_include_build_dirs function get_output_dir ( build_prefix , args ) result ( path ) character ( len =* ), intent ( in ) :: build_prefix character ( len =* ), intent ( in ) :: args character ( len = :), allocatable :: path character ( len = 16 ) :: build_hash write ( build_hash , '(z16.16)' ) fnv_1a ( args ) path = build_prefix // \"_\" // build_hash end function get_output_dir subroutine filter_library_targets ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( targets ( i )% ptr % target_type == FPM_TARGET_ARCHIVE ) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_library_targets subroutine filter_executable_targets ( targets , scope , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) integer , intent ( in ) :: scope type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( is_executable_target ( targets ( i )% ptr , scope )) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_executable_targets elemental function is_executable_target ( target_ptr , scope ) result ( is_exe ) type ( build_target_t ), intent ( in ) :: target_ptr integer , intent ( in ) :: scope logical :: is_exe is_exe = target_ptr % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( target_ptr % dependencies ) if ( is_exe ) then is_exe = target_ptr % dependencies ( 1 )% ptr % source % unit_scope == scope end if end function is_executable_target subroutine filter_modules ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , j , n n = 0 call resize ( list ) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if (. not . allocated ( target % source )) cycle if ( target % source % unit_type == FPM_UNIT_SUBMODULE ) cycle if ( n + size ( target % source % modules_provided ) >= size ( list )) call resize ( list ) do j = 1 , size ( target % source % modules_provided ) n = n + 1 list ( n )% s = join_path ( target % output_dir , & target % source % modules_provided ( j )% s ) end do end associate end do call resize ( list , n ) end subroutine filter_modules function get_feature_flags ( compiler , features ) result ( flags ) type ( compiler_t ), intent ( in ) :: compiler type ( fortran_features_t ), intent ( in ) :: features character (:), allocatable :: flags flags = \"\" if ( features % implicit_typing ) then flags = flags // compiler % get_feature_flag ( \"implicit-typing\" ) else flags = flags // compiler % get_feature_flag ( \"no-implicit-typing\" ) end if if ( features % implicit_external ) then flags = flags // compiler % get_feature_flag ( \"implicit-external\" ) else flags = flags // compiler % get_feature_flag ( \"no-implicit-external\" ) end if if ( allocated ( features % source_form )) then flags = flags // compiler % get_feature_flag ( features % source_form // \"-form\" ) end if end function get_feature_flags end module fpm_targets","tags":"","loc":"sourcefile/fpm_targets.f90.html"},{"title":"fpm_os.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_os Source Code fpm_os.F90 Source Code module fpm_os use , intrinsic :: iso_c_binding , only : c_char , c_int , c_null_char , c_ptr , c_associated use fpm_filesystem , only : exists , join_path , get_home use fpm_environment , only : os_is_unix use fpm_error , only : error_t , fatal_error implicit none private public :: change_directory , get_current_directory , get_absolute_path , convert_to_absolute_path , & & get_absolute_path_by_cd integer ( c_int ), parameter :: buffersize = 1000_c_int #ifndef _WIN32 character ( len =* ), parameter :: pwd_env = \"PWD\" #else character ( len =* ), parameter :: pwd_env = \"CD\" #endif interface function chdir_ ( path ) result ( stat ) & #ifndef _WIN32 bind ( C , name = \"chdir\" ) #else bind ( C , name = \"_chdir\" ) #endif import :: c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) integer ( c_int ) :: stat end function chdir_ function getcwd_ ( buf , bufsize ) result ( path ) & #ifndef _WIN32 bind ( C , name = \"getcwd\" ) #else bind ( C , name = \"_getcwd\" ) #endif import :: c_char , c_int , c_ptr character ( kind = c_char , len = 1 ), intent ( in ) :: buf ( * ) integer ( c_int ), value , intent ( in ) :: bufsize type ( c_ptr ) :: path end function getcwd_ !> Determine the absolute, canonicalized path for a given path. Unix-only. function realpath ( path , resolved_path ) result ( ptr ) bind ( C ) import :: c_ptr , c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) character ( kind = c_char , len = 1 ), intent ( out ) :: resolved_path ( * ) type ( c_ptr ) :: ptr end function realpath !> Determine the absolute, canonicalized path for a given path. Windows-only. function fullpath ( resolved_path , path , maxLength ) result ( ptr ) bind ( C , name = \"_fullpath\" ) import :: c_ptr , c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) character ( kind = c_char , len = 1 ), intent ( out ) :: resolved_path ( * ) integer ( c_int ), value , intent ( in ) :: maxLength type ( c_ptr ) :: ptr end function fullpath !> Determine the absolute, canonicalized path for a given path. !> Calls custom C routine because the `_WIN32` macro is correctly exported !> in C using `gfortran`. function c_realpath ( path , resolved_path , maxLength ) result ( ptr ) & bind ( C , name = \"c_realpath\" ) import :: c_ptr , c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) character ( kind = c_char , len = 1 ), intent ( out ) :: resolved_path ( * ) integer ( c_int ), value , intent ( in ) :: maxLength type ( c_ptr ) :: ptr end function c_realpath end interface contains subroutine change_directory ( path , error ) character ( len =* ), intent ( in ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) integer :: stat allocate ( cpath ( len ( path ) + 1 )) call f_c_character ( path , cpath , len ( path ) + 1 ) stat = chdir_ ( cpath ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to change directory to '\" // path // \"'\" ) end if end subroutine change_directory subroutine get_current_directory ( path , error ) character ( len = :), allocatable , intent ( out ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) type ( c_ptr ) :: tmp allocate ( cpath ( buffersize )) tmp = getcwd_ ( cpath , buffersize ) if ( c_associated ( tmp )) then call c_f_character ( cpath , path ) else call fatal_error ( error , \"Failed to retrieve current directory\" ) end if end subroutine get_current_directory subroutine f_c_character ( rhs , lhs , len ) character ( kind = c_char ), intent ( out ) :: lhs ( * ) character ( len =* ), intent ( in ) :: rhs integer , intent ( in ) :: len integer :: length length = min ( len - 1 , len_trim ( rhs )) lhs ( 1 : length ) = transfer ( rhs ( 1 : length ), lhs ( 1 : length )) lhs ( length + 1 : length + 1 ) = c_null_char end subroutine f_c_character subroutine c_f_character ( rhs , lhs ) character ( kind = c_char ), intent ( in ) :: rhs ( * ) character ( len = :), allocatable , intent ( out ) :: lhs integer :: ii do ii = 1 , huge ( ii ) - 1 if ( rhs ( ii ) == c_null_char ) then exit end if end do allocate ( character ( len = ii - 1 ) :: lhs ) lhs = transfer ( rhs ( 1 : ii - 1 ), lhs ) end subroutine c_f_character !> Determine the canonical, absolute path for the given path. !> !> Calls a C routine that uses the `_WIN32` macro to determine the correct function. !> !> Cannot be used in bootstrap mode. subroutine get_realpath ( path , real_path , error ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable , intent ( out ) :: real_path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: appended_path (:) character ( kind = c_char , len = 1 ), allocatable :: cpath (:) type ( c_ptr ) :: ptr if (. not . exists ( path )) then call fatal_error ( error , \"Cannot determine absolute path. Path '\" // path // \"' does not exist.\" ) return end if allocate ( appended_path ( len ( path ) + 1 )) call f_c_character ( path , appended_path , len ( path ) + 1 ) allocate ( cpath ( buffersize )) #ifndef FPM_BOOTSTRAP ptr = c_realpath ( appended_path , cpath , buffersize ) #endif if ( c_associated ( ptr )) then call c_f_character ( cpath , real_path ) else call fatal_error ( error , \"Failed to retrieve absolute path for '\" // path // \"'.\" ) end if end subroutine !> Determine the canonical, absolute path for the given path. !> Expands home folder (~) on both Unix and Windows. subroutine get_absolute_path ( path , absolute_path , error ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable , intent ( out ) :: absolute_path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: home #ifdef FPM_BOOTSTRAP call get_absolute_path_by_cd ( path , absolute_path , error ); return #endif if ( len_trim ( path ) < 1 ) then call fatal_error ( error , 'Path cannot be empty' ); return else if ( path ( 1 : 1 ) == '~' ) then call get_home ( home , error ) if ( allocated ( error )) return if ( len_trim ( path ) == 1 ) then absolute_path = home ; return end if if ( os_is_unix ()) then if ( path ( 2 : 2 ) /= '/' ) then call fatal_error ( error , \"Wrong separator in path: '\" // path // \"'\" ); return end if else if ( path ( 2 : 2 ) /= '\\') then call fatal_error(error, \"Wrong separator in path: ' \"//path//\" '\"); return end if end if if (len_trim(path) == 2) then absolute_path = home; return end if absolute_path = join_path(home, path(3:len_trim(path))) if (.not. exists(absolute_path)) then call fatal_error(error, \"Path not found: ' \"//absolute_path//\" '\" ); return end if else ! Get canonicalized absolute path from either the absolute or the relative path. call get_realpath ( path , absolute_path , error ) end if end subroutine !> Alternative to `get_absolute_path` that uses `chdir`/`_chdir` to determine the absolute path. !> !> `get_absolute_path` is preferred but `get_absolute_path_by_cd` can be used in bootstrap mode. subroutine get_absolute_path_by_cd ( path , absolute_path , error ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable , intent ( out ) :: absolute_path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: current_path call get_current_directory ( current_path , error ) if ( allocated ( error )) return call change_directory ( path , error ) if ( allocated ( error )) return call get_current_directory ( absolute_path , error ) if ( allocated ( error )) return call change_directory ( current_path , error ) if ( allocated ( error )) return end subroutine !> Converts a path to an absolute, canonical path. subroutine convert_to_absolute_path ( path , error ) character ( len = :), allocatable , intent ( inout ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: absolute_path call get_absolute_path ( path , absolute_path , error ) path = absolute_path end subroutine end module fpm_os","tags":"","loc":"sourcefile/fpm_os.f90.html"},{"title":"fpm_backend_output.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_backend_output Source Code fpm_backend_output.f90 Source Code !># Build Backend Progress Output !> This module provides a derived type `build_progress_t` for printing build status !> and progress messages to the console while the backend is building the package. !> !> The `build_progress_t` type supports two modes: `normal` and `plain` !> where the former does 'pretty' output and the latter does not. !> The `normal` mode is intended for typical interactive usage whereas !> 'plain' mode is used with the `--verbose` flag or when `stdout` is not attached !> to a terminal (e.g. when piping or redirecting `stdout`). In these cases, !> the pretty output must be suppressed to avoid control codes being output. module fpm_backend_output use iso_fortran_env , only : stdout => output_unit use fpm_filesystem , only : basename use fpm_targets , only : build_target_ptr use fpm_backend_console , only : console_t , LINE_RESET , COLOR_RED , COLOR_GREEN , COLOR_YELLOW , COLOR_RESET implicit none private public build_progress_t !> Build progress object type build_progress_t !> Console object for updating console lines type ( console_t ) :: console !> Number of completed targets integer :: n_complete !> Total number of targets scheduled integer :: n_target !> 'Plain' output (no colors or updating) logical :: plain_mode = . true . !> Store needed when updating previous console lines integer , allocatable :: output_lines (:) !> Queue of scheduled build targets type ( build_target_ptr ), pointer :: target_queue (:) contains !> Output 'compiling' status for build target procedure :: compiling_status => output_status_compiling !> Output 'complete' status for build target procedure :: completed_status => output_status_complete !> Output finished status for whole package procedure :: success => output_progress_success end type build_progress_t !> Constructor for build_progress_t interface build_progress_t procedure :: new_build_progress end interface build_progress_t contains !> Initialise a new build progress object function new_build_progress ( target_queue , plain_mode ) result ( progress ) !> The queue of scheduled targets type ( build_target_ptr ), intent ( in ), target :: target_queue (:) !> Enable 'plain' output for progress object logical , intent ( in ), optional :: plain_mode !> Progress object to initialise type ( build_progress_t ) :: progress progress % n_target = size ( target_queue , 1 ) progress % target_queue => target_queue progress % plain_mode = plain_mode progress % n_complete = 0 allocate ( progress % output_lines ( progress % n_target )) end function new_build_progress !> Output 'compiling' status for build target and overall percentage progress subroutine output_status_compiling ( progress , queue_index ) !> Progress object class ( build_progress_t ), intent ( inout ) :: progress !> Index of build target in the target queue integer , intent ( in ) :: queue_index character (:), allocatable :: target_name character ( 100 ) :: output_string character ( 7 ) :: overall_progress associate ( target => progress % target_queue ( queue_index )% ptr ) if ( allocated ( target % source )) then target_name = basename ( target % source % file_name ) else target_name = basename ( target % output_file ) end if write ( overall_progress , '(A,I3,A)' ) '[' , 100 * progress % n_complete / progress % n_target , '%] ' if ( progress % plain_mode ) then ! Plain output !$omp critical write ( * , '(A7,A30)' ) overall_progress , target_name !$omp end critical else ! Pretty output write ( output_string , '(A,T40,A,A)' ) target_name , COLOR_YELLOW // 'compiling...' // COLOR_RESET call progress % console % write_line ( trim ( output_string ), progress % output_lines ( queue_index )) call progress % console % write_line ( overall_progress // 'Compiling...' , advance = . false .) end if end associate end subroutine output_status_compiling !> Output 'complete' status for build target and update overall percentage progress subroutine output_status_complete ( progress , queue_index , build_stat ) !> Progress object class ( build_progress_t ), intent ( inout ) :: progress !> Index of build target in the target queue integer , intent ( in ) :: queue_index !> Build status flag integer , intent ( in ) :: build_stat character (:), allocatable :: target_name character ( 100 ) :: output_string character ( 7 ) :: overall_progress !$omp critical progress % n_complete = progress % n_complete + 1 !$omp end critical associate ( target => progress % target_queue ( queue_index )% ptr ) if ( allocated ( target % source )) then target_name = basename ( target % source % file_name ) else target_name = basename ( target % output_file ) end if if ( build_stat == 0 ) then write ( output_string , '(A,T40,A,A)' ) target_name , COLOR_GREEN // 'done.' // COLOR_RESET else write ( output_string , '(A,T40,A,A)' ) target_name , COLOR_RED // 'failed.' // COLOR_RESET end if write ( overall_progress , '(A,I3,A)' ) '[' , 100 * progress % n_complete / progress % n_target , '%] ' if ( progress % plain_mode ) then ! Plain output !$omp critical write ( * , '(A7,A30,A7)' ) overall_progress , target_name , 'done.' !$omp end critical else ! Pretty output call progress % console % update_line ( progress % output_lines ( queue_index ), trim ( output_string )) call progress % console % write_line ( overall_progress // 'Compiling...' , advance = . false .) end if end associate end subroutine output_status_complete !> Output finished status for whole package subroutine output_progress_success ( progress ) class ( build_progress_t ), intent ( inout ) :: progress if ( progress % plain_mode ) then ! Plain output write ( * , '(A)' ) '[100%] Project compiled successfully.' else ! Pretty output write ( * , '(A)' ) LINE_RESET // COLOR_GREEN // '[100%] Project compiled successfully.' // COLOR_RESET end if end subroutine output_progress_success end module fpm_backend_output","tags":"","loc":"sourcefile/fpm_backend_output.f90.html"},{"title":"fpm_sources.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_sources Source Code fpm_sources.f90 Source Code !># Discovery of sources !> !> This module implements subroutines for building a list of !> `[[srcfile_t]]` objects by looking for source files in the filesystem. !> module fpm_sources use fpm_error , only : error_t use fpm_model , only : srcfile_t , FPM_UNIT_PROGRAM use fpm_filesystem , only : basename , canon_path , dirname , join_path , list_files , is_hidden_file use fpm_environment , only : get_os_type , OS_WINDOWS use fpm_strings , only : lower , str_ends_with , string_t , operator (. in .) use fpm_source_parsing , only : parse_f_source , parse_c_source use fpm_manifest_executable , only : executable_config_t implicit none private public :: add_sources_from_dir , add_executable_sources public :: get_exe_name_with_suffix character ( 4 ), parameter :: fortran_suffixes ( 2 ) = [ \".f90\" , & \".f \" ] character ( 4 ), parameter :: c_suffixes ( 4 ) = [ \".c \" , \".h \" , \".cpp\" , \".hpp\" ] contains !> Wrapper to source parsing routines. !> Selects parsing routine based on source file name extension function parse_source ( source_file_path , error ) result ( source ) character ( * ), intent ( in ) :: source_file_path type ( error_t ), allocatable , intent ( out ) :: error type ( srcfile_t ) :: source if ( str_ends_with ( lower ( source_file_path ), fortran_suffixes )) then source = parse_f_source ( source_file_path , error ) if ( source % unit_type == FPM_UNIT_PROGRAM ) then source % exe_name = basename ( source_file_path , suffix = . false .) end if else if ( str_ends_with ( lower ( source_file_path ), c_suffixes )) then source = parse_c_source ( source_file_path , error ) end if if ( allocated ( error )) then return end if end function parse_source !> Add to `sources` by looking for source files in `directory` subroutine add_sources_from_dir ( sources , directory , scope , with_executables , recurse , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> Directory in which to search for source files character ( * ), intent ( in ) :: directory !> Scope to apply to the discovered sources, see [[fpm_model]] for enumeration integer , intent ( in ) :: scope !> Executable sources (fortran `program`s) are ignored unless `with_executables=.true.` logical , intent ( in ), optional :: with_executables !> Whether to recursively search subdirectories, default is `.true.` logical , intent ( in ), optional :: recurse !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i logical , allocatable :: is_source (:), exclude_source (:) logical :: recurse_ type ( string_t ), allocatable :: file_names (:) type ( string_t ), allocatable :: src_file_names (:) type ( string_t ), allocatable :: existing_src_files (:) type ( srcfile_t ), allocatable :: dir_sources (:) recurse_ = . true . if ( present ( recurse )) recurse_ = recurse ! Scan directory for sources call list_files ( directory , file_names , recurse = recurse_ ) if ( allocated ( sources )) then allocate ( existing_src_files ( size ( sources ))) do i = 1 , size ( sources ) existing_src_files ( i )% s = canon_path ( sources ( i )% file_name ) end do else allocate ( existing_src_files ( 0 )) end if is_source = [(. not .( is_hidden_file ( basename ( file_names ( i )% s ))) . and . & . not .( canon_path ( file_names ( i )% s ) . in . existing_src_files ) . and . & ( str_ends_with ( lower ( file_names ( i )% s ), fortran_suffixes ) . or . & str_ends_with ( lower ( file_names ( i )% s ), c_suffixes ) ), i = 1 , size ( file_names ))] src_file_names = pack ( file_names , is_source ) allocate ( dir_sources ( size ( src_file_names ))) allocate ( exclude_source ( size ( src_file_names ))) do i = 1 , size ( src_file_names ) dir_sources ( i ) = parse_source ( src_file_names ( i )% s , error ) if ( allocated ( error )) return dir_sources ( i )% unit_scope = scope allocate ( dir_sources ( i )% link_libraries ( 0 )) ! Exclude executables unless specified otherwise exclude_source ( i ) = ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM ) if ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM . and . & & present ( with_executables )) then if ( with_executables ) then exclude_source ( i ) = . false . end if end if end do if (. not . allocated ( sources )) then sources = pack ( dir_sources ,. not . exclude_source ) else sources = [ sources , pack ( dir_sources ,. not . exclude_source )] end if end subroutine add_sources_from_dir !> Add to `sources` using the executable and test entries in the manifest and !> applies any executable-specific overrides such as `executable%name`. !> Adds all sources (including modules) from each `executable%source_dir` subroutine add_executable_sources ( sources , executables , scope , auto_discover , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> List of `[[executable_config_t]]` entries from manifest class ( executable_config_t ), intent ( in ) :: executables (:) !> Scope to apply to the discovered sources: either `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`, see [[fpm_model]] integer , intent ( in ) :: scope !> If `.false.` only executables and tests specified in the manifest are added to `sources` logical , intent ( in ) :: auto_discover !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( string_t ), allocatable :: exe_dirs (:) type ( srcfile_t ) :: exe_source call get_executable_source_dirs ( exe_dirs , executables ) do i = 1 , size ( exe_dirs ) call add_sources_from_dir ( sources , exe_dirs ( i )% s , scope , & with_executables = auto_discover , recurse = . false ., error = error ) if ( allocated ( error )) then return end if end do exe_loop : do i = 1 , size ( executables ) ! Check if executable already discovered automatically ! and apply any overrides do j = 1 , size ( sources ) if ( basename ( sources ( j )% file_name , suffix = . true .) == executables ( i )% main . and .& canon_path ( dirname ( sources ( j )% file_name )) == & canon_path ( executables ( i )% source_dir ) ) then sources ( j )% exe_name = executables ( i )% name if ( allocated ( executables ( i )% link )) then sources ( j )% link_libraries = executables ( i )% link end if sources ( j )% unit_type = FPM_UNIT_PROGRAM cycle exe_loop end if end do ! Add if not already discovered (auto_discovery off) associate ( exe => executables ( i )) exe_source = parse_source ( join_path ( exe % source_dir , exe % main ), error ) exe_source % exe_name = exe % name if ( allocated ( exe % link )) then exe_source % link_libraries = exe % link end if exe_source % unit_type = FPM_UNIT_PROGRAM exe_source % unit_scope = scope end associate if ( allocated ( error )) return if (. not . allocated ( sources )) then sources = [ exe_source ] else sources = [ sources , exe_source ] end if end do exe_loop end subroutine add_executable_sources !> Build a list of unique source directories !> from executables specified in manifest subroutine get_executable_source_dirs ( exe_dirs , executables ) type ( string_t ), allocatable , intent ( inout ) :: exe_dirs (:) class ( executable_config_t ), intent ( in ) :: executables (:) type ( string_t ) :: dirs_temp ( size ( executables )) integer :: i , n n = 0 do i = 1 , size ( executables ) dirs_temp ( i )% s = ' ' enddo do i = 1 , size ( executables ) if (. not .( executables ( i )% source_dir . in . dirs_temp )) then n = n + 1 dirs_temp ( n )% s = executables ( i )% source_dir end if end do if (. not . allocated ( exe_dirs )) then exe_dirs = dirs_temp ( 1 : n ) else exe_dirs = [ exe_dirs , dirs_temp ( 1 : n )] end if end subroutine get_executable_source_dirs !> Build an executable name with suffix. Safe routine that always returns an allocated string function get_exe_name_with_suffix ( source ) result ( suffixed ) type ( srcfile_t ), intent ( in ) :: source character ( len = :), allocatable :: suffixed if ( allocated ( source % exe_name )) then if ( get_os_type () == OS_WINDOWS ) then suffixed = source % exe_name // '.exe' else suffixed = source % exe_name end if else suffixed = \"\" endif end function get_exe_name_with_suffix end module fpm_sources","tags":"","loc":"sourcefile/fpm_sources.f90.html"},{"title":"fpm_source_parsing.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_source_parsing Source Code fpm_source_parsing.f90 Source Code !># Parsing of package source files !> !> This module exposes two functions, `[[parse_f_source]]` and `[[parse_c_source]]`, !> which perform a rudimentary parsing of fortran and c source files !> in order to extract information required for module dependency tracking. !> !> Both functions additionally calculate and store a file digest (hash) which !> is used by the backend ([[fpm_backend]]) to skip compilation of unmodified sources. !> !> Both functions return an instance of the [[srcfile_t]] type. !> !> For more information, please read the documentation for each function: !> !> - `[[parse_f_source]]` !> - `[[parse_c_source]]` !> module fpm_source_parsing use fpm_error , only : error_t , file_parse_error , fatal_error , file_not_found_error use fpm_strings , only : string_t , string_cat , len_trim , split , lower , str_ends_with , fnv_1a , is_fortran_name use fpm_model , only : srcfile_t , & FPM_UNIT_UNKNOWN , FPM_UNIT_PROGRAM , FPM_UNIT_MODULE , & FPM_UNIT_SUBMODULE , FPM_UNIT_SUBPROGRAM , & FPM_UNIT_CSOURCE , FPM_UNIT_CHEADER , FPM_SCOPE_UNKNOWN , & FPM_SCOPE_LIB , FPM_SCOPE_DEP , FPM_SCOPE_APP , FPM_SCOPE_TEST , & FPM_UNIT_CPPSOURCE use fpm_filesystem , only : read_lines , read_lines_expanded , exists implicit none private public :: parse_f_source , parse_c_source , parse_use_statement contains !> Parsing of free-form fortran source files !> !> The following statements are recognised and parsed: !> !> - `Module`/`submodule`/`program` declaration !> - Module `use` statement !> - `include` statement !> !> @note Intrinsic modules used by sources are not listed in !> the `modules_used` field of source objects. !> !> @note Submodules are treated as normal modules which `use` their !> corresponding parent modules. !> !>### Parsing limitations !> !> __Statements must not continued onto another line !> except for an `only:` list in the `use` statement.__ !> !> This is supported: !> !>```fortran !> use my_module, only: & !> my_var, my_function, my_subroutine !>``` !> !> This is __NOT supported:__ !> !>```fortran !> use & !> my_module !>``` !> function parse_f_source ( f_filename , error ) result ( f_source ) character ( * ), intent ( in ) :: f_filename type ( srcfile_t ) :: f_source type ( error_t ), allocatable , intent ( out ) :: error logical :: inside_module , inside_interface , using , intrinsic_module integer :: stat integer :: fh , n_use , n_include , n_mod , n_parent , i , j , ic , pass type ( string_t ), allocatable :: file_lines (:), file_lines_lower (:) character (:), allocatable :: temp_string , mod_name , string_parts (:) if (. not . exists ( f_filename )) then call file_not_found_error ( error , f_filename ) return end if f_source % file_name = f_filename open ( newunit = fh , file = f_filename , status = 'old' ) file_lines = read_lines_expanded ( fh ) close ( fh ) ! for efficiency in parsing make a lowercase left-adjusted copy of the file ! Need a copy because INCLUDE (and #include) file arguments are case-sensitive file_lines_lower = file_lines do i = 1 , size ( file_lines_lower ) file_lines_lower ( i )% s = adjustl ( lower ( file_lines_lower ( i )% s )) enddo ! fnv_1a can only be applied to non-zero-length arrays if ( len_trim ( file_lines_lower ) > 0 ) f_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_use = 0 n_include = 0 n_mod = 0 n_parent = 0 inside_module = . false . inside_interface = . false . file_loop : do i = 1 , size ( file_lines_lower ) ! Skip comment lines and preprocessor directives if ( index ( file_lines_lower ( i )% s , '!' ) == 1 . or . & index ( file_lines_lower ( i )% s , '#' ) == 1 . or . & len_trim ( file_lines_lower ( i )% s ) < 1 ) then cycle end if ! Detect exported C-API via bind(C) if (. not . inside_interface . and . & parse_subsequence ( file_lines_lower ( i )% s , 'bind' , '(' , 'c' )) then do j = i , 1 , - 1 if ( index ( file_lines_lower ( j )% s , 'function' ) > 0 . or . & index ( file_lines_lower ( j )% s , 'subroutine' ) > 0 ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM exit end if if ( j > 1 ) then ic = index ( file_lines_lower ( j - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( j - 1 )% s ) end if temp_string = trim ( file_lines_lower ( j - 1 )% s ( 1 : ic )) if ( index ( temp_string , '&' ) /= len ( temp_string )) then exit end if end if end do end if ! Skip lines that are continued: not statements if ( i > 1 ) then ic = index ( file_lines_lower ( i - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( i - 1 )% s ) end if temp_string = trim ( file_lines_lower ( i - 1 )% s ( 1 : ic )) if ( len ( temp_string ) > 0 . and . index ( temp_string , '&' ) == len ( temp_string )) then cycle end if end if ! Detect beginning of interface block if ( index ( file_lines_lower ( i )% s , 'interface' ) == 1 ) then inside_interface = . true . cycle end if ! Detect end of interface block if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'interface' )) then inside_interface = . false . cycle end if ! Process 'USE' statements call parse_use_statement ( f_filename , i , file_lines_lower ( i )% s , using , intrinsic_module , mod_name , error ) if ( allocated ( error )) return if ( using ) then ! Not a valid module name? if (. not . is_fortran_name ( mod_name )) cycle ! Valid intrinsic module: not a dependency if ( intrinsic_module ) cycle n_use = n_use + 1 if ( pass == 2 ) f_source % modules_used ( n_use )% s = mod_name cycle endif ! Process 'INCLUDE' statements ic = index ( file_lines_lower ( i )% s , 'include' ) if ( ic == 1 ) then ic = index ( lower ( file_lines ( i )% s ), 'include' ) if ( index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), '\"' ) == 1 . or . & index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), \"'\" ) == 1 ) then n_include = n_include + 1 if ( pass == 2 ) then f_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = \"'\" // '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find include file name' , i , & file_lines ( i )% s ) return end if end if cycle end if end if ! Extract name of module if is module if ( index ( file_lines_lower ( i )% s , 'module ' ) == 1 ) then ! Remove any trailing comments ic = index ( file_lines_lower ( i )% s , '!' ) - 1 if ( ic < 1 ) then ic = len ( file_lines_lower ( i )% s ) end if temp_string = trim ( file_lines_lower ( i )% s ( 1 : ic )) ! R1405 module-stmt := \"MODULE\" module-name ! module-stmt has two space-delimited parts only ! (no line continuations) call split ( temp_string , string_parts , ' ' ) if ( size ( string_parts ) /= 2 ) then cycle end if mod_name = trim ( adjustl ( string_parts ( 2 ))) if ( scan ( mod_name , '=(&' ) > 0 ) then ! Ignore these cases: ! module & ! module =* ! module (i) cycle end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for module' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 if ( pass == 2 ) then f_source % modules_provided ( n_mod ) = string_t ( mod_name ) end if if ( f_source % unit_type == FPM_UNIT_UNKNOWN ) then f_source % unit_type = FPM_UNIT_MODULE end if if (. not . inside_module ) then inside_module = . true . else ! Must have missed an end module statement (can't assume a pure module) if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end if cycle end if ! Extract name of submodule if is submodule if ( index ( file_lines_lower ( i )% s , 'submodule' ) == 1 ) then mod_name = split_n ( file_lines_lower ( i )% s , n = 3 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule name' , i , & file_lines_lower ( i )% s ) return end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule ancestry' , i , & file_lines_lower ( i )% s ) return end if if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBMODULE end if n_use = n_use + 1 inside_module = . true . n_parent = n_parent + 1 if ( pass == 2 ) then if ( index ( temp_string , ':' ) > 0 ) then temp_string = temp_string ( index ( temp_string , ':' ) + 1 :) end if if (. not . is_fortran_name ( temp_string )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule parent' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , temp_string )) return end if f_source % modules_used ( n_use )% s = temp_string f_source % parent_modules ( n_parent )% s = temp_string f_source % modules_provided ( n_mod )% s = mod_name end if cycle end if ! Detect if contains a program ! (no modules allowed after program def) if ( index ( file_lines_lower ( i )% s , 'program ' ) == 1 ) then temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = ' ' , stat = stat ) if ( stat == 0 ) then if ( scan ( temp_string , '=(' ) > 0 ) then ! Ignore: ! program =* ! program (i) =* cycle end if end if f_source % unit_type = FPM_UNIT_PROGRAM cycle end if ! Parse end module statement ! (to check for code outside of modules) if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'module' ) . or . & parse_sequence ( file_lines_lower ( i )% s , 'end' , 'submodule' )) then inside_module = . false . cycle end if ! Any statements not yet parsed are assumed to be other code statements if (. not . inside_module . and . f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end do file_loop ! If unable to parse end of module statement, then can't assume pure module ! (there could be non-module subprograms present) if ( inside_module . and . f_source % unit_type == FPM_UNIT_MODULE ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if if ( pass == 1 ) then allocate ( f_source % modules_used ( n_use )) allocate ( f_source % include_dependencies ( n_include )) allocate ( f_source % modules_provided ( n_mod )) allocate ( f_source % parent_modules ( n_parent )) end if end do end function parse_f_source !> Parsing of c, cpp source files !> !> The following statements are recognised and parsed: !> !> - `#include` preprocessor statement !> function parse_c_source ( c_filename , error ) result ( c_source ) character ( * ), intent ( in ) :: c_filename type ( srcfile_t ) :: c_source type ( error_t ), allocatable , intent ( out ) :: error integer :: fh , n_include , i , pass , stat type ( string_t ), allocatable :: file_lines (:) c_source % file_name = c_filename if ( str_ends_with ( lower ( c_filename ), \".c\" )) then c_source % unit_type = FPM_UNIT_CSOURCE else if ( str_ends_with ( lower ( c_filename ), \".h\" )) then c_source % unit_type = FPM_UNIT_CHEADER else if ( str_ends_with ( lower ( c_filename ), \".cpp\" )) then c_source % unit_type = FPM_UNIT_CPPSOURCE end if allocate ( c_source % modules_used ( 0 )) allocate ( c_source % modules_provided ( 0 )) allocate ( c_source % parent_modules ( 0 )) open ( newunit = fh , file = c_filename , status = 'old' ) file_lines = read_lines ( fh ) close ( fh ) ! Ignore empty files, returned as FPM_UNIT_UNKNOWN if ( len_trim ( file_lines ) < 1 ) then c_source % unit_type = FPM_UNIT_UNKNOWN return end if c_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_include = 0 file_loop : do i = 1 , size ( file_lines ) ! Process 'INCLUDE' statements if ( index ( adjustl ( lower ( file_lines ( i )% s )), '#include' ) == 1 . and . & index ( file_lines ( i )% s , '\"' ) > 0 ) then n_include = n_include + 1 if ( pass == 2 ) then c_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , c_filename , & 'unable to get c include file' , i , & file_lines ( i )% s , index ( file_lines ( i )% s , '\"' )) return end if end if end if end do file_loop if ( pass == 1 ) then allocate ( c_source % include_dependencies ( n_include )) end if end do end function parse_c_source !> Split a string on one or more delimeters !> and return the nth substring if it exists !> !> n=0 will return the last item !> n=-1 will return the penultimate item etc. !> !> stat = 1 on return if the index !> is not found !> function split_n ( string , delims , n , stat ) result ( substring ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: delims integer , intent ( in ) :: n integer , intent ( out ) :: stat character (:), allocatable :: substring integer :: i character (:), allocatable :: string_parts (:) call split ( string , string_parts , delims ) if ( n < 1 ) then i = size ( string_parts ) + n if ( i < 1 ) then allocate ( character ( len = 0 ) :: substring ) ! ifort bus error otherwise stat = 1 return end if else i = n end if if ( i > size ( string_parts )) then allocate ( character ( len = 0 ) :: substring ) ! ifort bus error otherwise stat = 1 return end if substring = trim ( adjustl ( string_parts ( i ))) stat = 0 end function split_n !> Parse a subsequence of blank-separated tokens within a string !> (see parse_sequence) function parse_subsequence ( string , t1 , t2 , t3 , t4 ) result ( found ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: t1 character ( * ), intent ( in ), optional :: t2 , t3 , t4 logical :: found integer :: offset , i found = . false . offset = 1 do i = index ( string ( offset :), t1 ) if ( i == 0 ) return offset = offset + i - 1 found = parse_sequence ( string ( offset :), t1 , t2 , t3 , t4 ) if ( found ) return offset = offset + len ( t1 ) if ( offset > len ( string )) return end do end function parse_subsequence !> Helper utility to parse sequences of tokens !> that may be optionally separated by zero or more spaces function parse_sequence ( string , t1 , t2 , t3 , t4 ) result ( found ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: t1 character ( * ), intent ( in ), optional :: t2 , t3 , t4 logical :: found integer :: post , n , incr , pos , token_n logical :: match n = len ( string ) found = . false . pos = 1 do token_n = 1 , 4 do while ( pos <= n ) if ( string ( pos : pos ) /= ' ' ) then exit end if pos = pos + 1 end do select case ( token_n ) case ( 1 ) incr = len ( t1 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t1 case ( 2 ) if (. not . present ( t2 )) exit incr = len ( t2 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t2 case ( 3 ) if (. not . present ( t3 )) exit incr = len ( t3 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t3 case ( 4 ) if (. not . present ( t4 )) exit incr = len ( t4 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t4 case default exit end select if (. not . match ) then return end if pos = pos + incr end do found = . true . end function parse_sequence ! USE [, intrinsic] :: module_name [, only: only_list] ! USE [, non_intrinsic] :: module_name [, only: only_list] subroutine parse_use_statement ( f_filename , i , line , use_stmt , is_intrinsic , module_name , error ) !> Current file name and line number (for error messaging) character ( * ), intent ( in ) :: f_filename integer , intent ( in ) :: i !> The line being parsed. MUST BE preprocessed with trim(adjustl() character ( * ), intent ( in ) :: line !> Does this line contain a `use` statement? logical , intent ( out ) :: use_stmt !> Is the module in this statement intrinsic? logical , intent ( out ) :: is_intrinsic !> used module name character (:), allocatable , intent ( out ) :: module_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( 15 ), parameter :: INTRINSIC_NAMES ( * ) = & [ 'iso_c_binding ' , & 'iso_fortran_env' , & 'ieee_arithmetic' , & 'ieee_exceptions' , & 'ieee_features ' , & 'omp_lib ' ] character ( len = :), allocatable :: temp_string integer :: colons , intr , nonintr , j , stat logical :: has_intrinsic_name use_stmt = . false . is_intrinsic = . false . if ( len_trim ( line ) <= 0 ) return ! Quick check that the line is preprocessed if ( line ( 1 : 1 ) == ' ' ) then call fatal_error ( error , 'internal_error: source file line is not trim(adjustl()) on input to parse_use_statement' ) return end if ! 'use' should be the first string in the adjustl line use_stmt = index ( line , 'use ' ) == 1 . or . index ( line , 'use::' ) == 1 . or . index ( line , 'use,' ) == 1 if (. not . use_stmt ) return colons = index ( line , '::' ) nonintr = 0 intr = 0 have_colons : if ( colons > 3 ) then ! there may be an intrinsic/non-intrinsic spec nonintr = index ( line ( 1 : colons - 1 ), 'non_intrinsic' ) if ( nonintr == 0 ) intr = index ( line ( 1 : colons - 1 ), 'intrinsic' ) temp_string = split_n ( line , delims = ':' , n = 2 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line , colons ) return end if module_name = split_n ( temp_string , delims = ' ,' , n = 1 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if else module_name = split_n ( line , n = 2 , delims = ' ,' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if end if have_colons ! If declared intrinsic, check that it is true has_intrinsic_name = any ([( index ( module_name , trim ( INTRINSIC_NAMES ( j ))) > 0 , & j = 1 , size ( INTRINSIC_NAMES ))]) if ( intr > 0 . and . . not . has_intrinsic_name ) then ! An intrinsic module was not found. Its name could be in the next line, ! in which case, we just skip this check. The compiler will do the job if the name is invalid. ! Module name was not read: it's in the next line if ( index ( module_name , '&' ) <= 0 ) then call file_parse_error ( error , f_filename , & 'module ' // module_name // ' is declared intrinsic but it is not ' , i , & line ) return endif endif ! Should we treat this as an intrinsic module is_intrinsic = nonintr == 0 . and . & ! not declared non-intrinsic ( intr > 0 . or . has_intrinsic_name ) end subroutine parse_use_statement end module fpm_source_parsing","tags":"","loc":"sourcefile/fpm_source_parsing.f90.html"},{"title":"fpm_filesystem.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_filesystem Source Code fpm_filesystem.F90 Source Code !> This module contains general routines for interacting with the file system !! module fpm_filesystem use , intrinsic :: iso_fortran_env , only : stdin => input_unit , stdout => output_unit , stderr => error_unit use fpm_environment , only : get_os_type , & OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_WINDOWS , & OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD use fpm_environment , only : separator , get_env , os_is_unix use fpm_strings , only : f_string , replace , string_t , split , dilate , str_begins_with_str use iso_c_binding , only : c_char , c_ptr , c_int , c_null_char , c_associated , c_f_pointer use fpm_error , only : fpm_stop , error_t , fatal_error implicit none private public :: basename , canon_path , dirname , is_dir , join_path , number_of_rows , list_files , get_local_prefix , & mkdir , exists , get_temp_filename , windows_path , unix_path , getline , delete_file , fileopen , fileclose , & filewrite , warnwrite , parent_dir , is_hidden_file , read_lines , read_lines_expanded , which , run , & os_delete_dir , is_absolute_path , get_home , execute_and_read_output , get_dos_path #ifndef FPM_BOOTSTRAP interface function c_opendir ( dir ) result ( r ) bind ( c , name = \"c_opendir\" ) import c_char , c_ptr character ( kind = c_char ), intent ( in ) :: dir ( * ) type ( c_ptr ) :: r end function c_opendir function c_readdir ( dir ) result ( r ) bind ( c , name = \"c_readdir\" ) import c_ptr type ( c_ptr ), intent ( in ), value :: dir type ( c_ptr ) :: r end function c_readdir function c_closedir ( dir ) result ( r ) bind ( c , name = \"closedir\" ) import c_ptr , c_int type ( c_ptr ), intent ( in ), value :: dir integer ( kind = c_int ) :: r end function c_closedir function c_get_d_name ( dir ) result ( r ) bind ( c , name = \"get_d_name\" ) import c_ptr type ( c_ptr ), intent ( in ), value :: dir type ( c_ptr ) :: r end function c_get_d_name function c_is_dir ( path ) result ( r ) bind ( c , name = \"c_is_dir\" ) import c_char , c_int character ( kind = c_char ), intent ( in ) :: path ( * ) integer ( kind = c_int ) :: r end function c_is_dir end interface #endif contains !> Extract filename from path with/without suffix function basename ( path , suffix ) result ( base ) character ( * ), intent ( In ) :: path logical , intent ( in ), optional :: suffix character (:), allocatable :: base character (:), allocatable :: file_parts (:) logical :: with_suffix if (. not . present ( suffix )) then with_suffix = . true . else with_suffix = suffix end if call split ( path , file_parts , delimiters = '\\/' ) if ( size ( file_parts ) > 0 ) then base = trim ( file_parts ( size ( file_parts ))) else base = '' endif if (. not . with_suffix ) then call split ( base , file_parts , delimiters = '.' ) if ( size ( file_parts ) >= 2 ) then base = trim ( file_parts ( size ( file_parts ) - 1 )) endif endif end function basename !> Canonicalize path for comparison !! * Handles path string redundancies !! * Does not test existence of path !! !! To be replaced by realpath/_fullname in stdlib_os !! !! FIXME: Lot's of ugly hacks following here function canon_path ( path ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: canon_path character ( len = :), allocatable :: nixpath integer :: istart , iend , nn , last logical :: is_path , absolute nixpath = unix_path ( path ) istart = 0 nn = 0 iend = 0 absolute = nixpath ( 1 : 1 ) == \"/\" if ( absolute ) then canon_path = \"/\" else canon_path = \"\" end if do while ( iend < len ( nixpath )) call next ( nixpath , istart , iend , is_path ) if ( is_path ) then select case ( nixpath ( istart : iend )) case ( \".\" , \"\" ) ! always drop empty paths case ( \"..\" ) if ( nn > 0 ) then last = scan ( canon_path (: len ( canon_path ) - 1 ), \"/\" , back = . true .) canon_path = canon_path (: last ) nn = nn - 1 else if (. not . absolute ) then canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end if end if case default nn = nn + 1 canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end select end if end do if ( len ( canon_path ) == 0 ) canon_path = \".\" if ( len ( canon_path ) > 1 . and . canon_path ( len ( canon_path ):) == \"/\" ) then canon_path = canon_path (: len ( canon_path ) - 1 ) end if contains subroutine next ( string , istart , iend , is_path ) character ( len =* ), intent ( in ) :: string integer , intent ( inout ) :: istart integer , intent ( inout ) :: iend logical , intent ( inout ) :: is_path integer :: ii , nn character :: tok nn = len ( string ) if ( iend >= nn ) then istart = nn iend = nn return end if ii = min ( iend + 1 , nn ) tok = string ( ii : ii ) is_path = tok /= '/' if (. not . is_path ) then is_path = . false . istart = ii iend = ii return end if istart = ii do ii = min ( iend + 1 , nn ), nn tok = string ( ii : ii ) select case ( tok ) case ( '/' ) exit case default iend = ii cycle end select end do end subroutine next end function canon_path !> Extract dirname from path function dirname ( path ) result ( dir ) character ( * ), intent ( in ) :: path character (:), allocatable :: dir dir = path ( 1 : scan ( path , '/\\',back=.true.)) end function dirname !> Extract dirname from path function parent_dir(path) result (dir) character(*), intent(in) :: path character(:), allocatable :: dir dir = path(1:scan(path,' / \\ ',back=.true.)-1) end function parent_dir !> test if a name matches an existing directory path logical function is_dir(dir) character(*), intent(in) :: dir integer :: stat select case (get_os_type()) case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) call run( \"test -d \" // dir , & & exitstat=stat,echo=.false.,verbose=.false.) case (OS_WINDOWS) call run(' cmd / c \"if not exist ' // windows_path(dir) // '\\ exit /B 1\" ', & & exitstat=stat,echo=.false.,verbose=.false.) end select is_dir = (stat == 0) end function is_dir !> test if a file is hidden logical function is_hidden_file(file_basename) result(r) character(*), intent(in) :: file_basename if (len(file_basename) <= 2) then r = .false. else r = str_begins_with_str(file_basename, ' . ') end if end function is_hidden_file !> Construct path by joining strings with os file separator function join_path(a1,a2,a3,a4,a5) result(path) character(len=*), intent(in) :: a1, a2 character(len=*), intent(in), optional :: a3, a4, a5 character(len=:), allocatable :: path character(len=1) :: filesep logical, save :: has_cache = .false. character(len=1), save :: cache = ' / ' !$omp threadprivate(has_cache, cache) if (has_cache) then filesep = cache else select case (get_os_type()) case default filesep = ' / ' case (OS_WINDOWS) filesep = ' \\ ' end select cache = filesep has_cache = .true. end if if (a1 == \"\") then path = a2 else path = a1 // filesep // a2 end if if (present(a3)) then path = path // filesep // a3 else return end if if (present(a4)) then path = path // filesep // a4 else return end if if (present(a5)) then path = path // filesep // a5 else return end if end function join_path !> Determine number or rows in a file given a LUN integer function number_of_rows(s) result(nrows) integer,intent(in)::s integer :: ios rewind(s) nrows = 0 do read(s, *, iostat=ios) if (ios /= 0) exit nrows = nrows + 1 end do rewind(s) end function number_of_rows !> read lines into an array of TYPE(STRING_T) variables expanding tabs function read_lines_expanded(fh) result(lines) integer, intent(in) :: fh type(string_t), allocatable :: lines(:) integer :: i integer :: iostat character(len=:),allocatable :: line_buffer_read allocate(lines(number_of_rows(fh))) do i = 1, size(lines) call getline(fh, line_buffer_read, iostat) lines(i)%s = dilate(line_buffer_read) end do end function read_lines_expanded !> read lines into an array of TYPE(STRING_T) variables function read_lines(fh) result(lines) integer, intent(in) :: fh type(string_t), allocatable :: lines(:) integer :: i integer :: iostat allocate(lines(number_of_rows(fh))) do i = 1, size(lines) call getline(fh, lines(i)%s, iostat) end do end function read_lines !> Create a directory. Create subdirectories as needed subroutine mkdir(dir, echo) character(len=*), intent(in) :: dir logical, intent(in), optional :: echo integer :: stat if (is_dir(dir)) return select case (get_os_type()) case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) call run(' mkdir - p ' // dir, exitstat=stat,echo=echo,verbose=.false.) case (OS_WINDOWS) call run(\"mkdir \" // windows_path(dir), & & echo=echo, exitstat=stat,verbose=.false.) end select if (stat /= 0) then call fpm_stop(1, ' * mkdir * : directory creation failed ') end if end subroutine mkdir #ifndef FPM_BOOTSTRAP !> Get file & directory names in directory `dir` using iso_c_binding. !! !! - File/directory names return are relative to cwd, ie. preprended with `dir` !! - Includes files starting with `.` except current directory and parent directory !! recursive subroutine list_files(dir, files, recurse) character(len=*), intent(in) :: dir type(string_t), allocatable, intent(out) :: files(:) logical, intent(in), optional :: recurse integer :: i type(string_t), allocatable :: dir_files(:) type(string_t), allocatable :: sub_dir_files(:) type(c_ptr) :: dir_handle type(c_ptr) :: dir_entry_c character(len=:,kind=c_char), allocatable :: fortran_name character(len=:), allocatable :: string_fortran integer, parameter :: N_MAX = 256 type(string_t) :: files_tmp(N_MAX) integer(kind=c_int) :: r if (c_is_dir(dir(1:len_trim(dir))//c_null_char) == 0) then allocate (files(0)) return end if dir_handle = c_opendir(dir(1:len_trim(dir))//c_null_char) if (.not. c_associated(dir_handle)) then print *, ' c_opendir () failed ' error stop end if i = 0 allocate(files(0)) do dir_entry_c = c_readdir(dir_handle) if (.not. c_associated(dir_entry_c)) then exit else string_fortran = f_string(c_get_d_name(dir_entry_c)) if ((string_fortran == ' . ' .or. string_fortran == ' .. ')) then cycle end if i = i + 1 if (i > N_MAX) then files = [files, files_tmp] i = 1 end if files_tmp(i)%s = join_path(dir, string_fortran) end if end do r = c_closedir(dir_handle) if (r /= 0) then print *, ' c_closedir () failed ' error stop end if if (i > 0) then files = [files, files_tmp(1:i)] end if if (present(recurse)) then if (recurse) then allocate(sub_dir_files(0)) do i=1,size(files) if (c_is_dir(files(i)%s//c_null_char) /= 0) then call list_files(files(i)%s, dir_files, recurse=.true.) sub_dir_files = [sub_dir_files, dir_files] end if end do files = [files, sub_dir_files] end if end if end subroutine list_files #else !> Get file & directory names in directory `dir`. !! !! - File/directory names return are relative to cwd, ie. preprended with `dir` !! - Includes files starting with `.` except current directory and parent directory !! recursive subroutine list_files(dir, files, recurse) character(len=*), intent(in) :: dir type(string_t), allocatable, intent(out) :: files(:) logical, intent(in), optional :: recurse integer :: stat, fh, i character(:), allocatable :: temp_file type(string_t), allocatable :: dir_files(:) type(string_t), allocatable :: sub_dir_files(:) if (.not. is_dir(dir)) then allocate (files(0)) return end if allocate (temp_file, source=get_temp_filename()) select case (get_os_type()) case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) call run(' ls - A ' // dir , & & redirect=temp_file, exitstat=stat,echo=.false.,verbose=.false.) case (OS_WINDOWS) call run(' dir / b ' // windows_path(dir), & & redirect=temp_file, exitstat=stat,echo=.false.,verbose=.false.) end select if (stat /= 0) then call fpm_stop(2,' * list_files * : directory listing failed ') end if open (newunit=fh, file=temp_file, status=' old ') files = read_lines(fh) close(fh,status=\"delete\") do i=1,size(files) files(i)%s = join_path(dir,files(i)%s) end do if (present(recurse)) then if (recurse) then allocate(sub_dir_files(0)) do i=1,size(files) if (is_dir(files(i)%s)) then call list_files(files(i)%s, dir_files, recurse=.true.) sub_dir_files = [sub_dir_files, dir_files] end if end do files = [files, sub_dir_files] end if end if end subroutine list_files #endif !> test if pathname already exists logical function exists(filename) result(r) character(len=*), intent(in) :: filename inquire(file=filename, exist=r) !> Directories are not files for the Intel compilers. If so, also use this compiler-dependent extension #if defined(__INTEL_COMPILER) if (.not.r) inquire(directory=filename, exist=r) #endif end function !> Get a unused temporary filename !! Calls posix ' tempnam ' - not recommended, but !! we have no security concerns for this application !! and use here is temporary. !! Works with MinGW function get_temp_filename() result(tempfile) ! use iso_c_binding, only: c_ptr, C_NULL_PTR, c_f_pointer integer, parameter :: MAX_FILENAME_LENGTH = 32768 character(:), allocatable :: tempfile type(c_ptr) :: c_tempfile_ptr character(len=1), pointer :: c_tempfile(:) interface function c_tempnam(dir,pfx) result(tmp) bind(c,name=\"tempnam\") import type(c_ptr), intent(in), value :: dir type(c_ptr), intent(in), value :: pfx type(c_ptr) :: tmp end function c_tempnam subroutine c_free(ptr) BIND(C,name=\"free\") import type(c_ptr), value :: ptr end subroutine c_free end interface c_tempfile_ptr = c_tempnam(C_NULL_PTR, C_NULL_PTR) call c_f_pointer(c_tempfile_ptr,c_tempfile,[MAX_FILENAME_LENGTH]) tempfile = f_string(c_tempfile) call c_free(c_tempfile_ptr) end function get_temp_filename !> Replace file system separators for windows function windows_path(path) result(winpath) character(*), intent(in) :: path character(:), allocatable :: winpath integer :: idx winpath = path idx = index(winpath,' / ') do while(idx > 0) winpath(idx:idx) = ' \\ ' idx = index(winpath,' / ') end do end function windows_path !> Replace file system separators for unix function unix_path(path) result(nixpath) character(*), intent(in) :: path character(:), allocatable :: nixpath integer :: idx nixpath = path idx = index(nixpath,' \\ ') do while(idx > 0) nixpath(idx:idx) = ' / ' idx = index(nixpath,' \\ ') end do end function unix_path !>AUTHOR: fpm(1) contributors !!LICENSE: MIT !> !!##NAME !! getline(3f) - [M_io:READ] read a line of arbintrary length from specified !! LUN into allocatable string (up to system line length limit) !! (LICENSE:PD) !! !!##SYNTAX !! subroutine getline(unit,line,iostat,iomsg) !! !! integer,intent(in) :: unit !! character(len=:),allocatable,intent(out) :: line !! integer,intent(out) :: iostat !! character(len=:), allocatable, optional :: iomsg !! !!##DESCRIPTION !! Read a line of any length up to programming environment maximum !! line length. Requires Fortran 2003+. !! !! It is primarily expected to be used when reading input which will !! then be parsed or echoed. !! !! The input file must have a PAD attribute of YES for the function !! to work properly, which is typically true. !! !! The simple use of a loop that repeatedly re-allocates a character !! variable in addition to reading the input file one buffer at a !! time could (depending on the programming environment used) be !! inefficient, as it could reallocate and allocate memory used for !! the output string with each buffer read. !! !!##OPTIONS !! LINE The line read when IOSTAT returns as zero. !! LUN LUN (Fortran logical I/O unit) number of file open and ready !! to read. !! IOSTAT status returned by READ(IOSTAT=IOS). If not zero, an error !! occurred or an end-of-file or end-of-record was encountered. !! IOMSG error message returned by system when IOSTAT is not zero. !! !!##EXAMPLE !! !! Sample program: !! !! program demo_getline !! use,intrinsic :: iso_fortran_env, only : stdin=>input_unit !! use,intrinsic :: iso_fortran_env, only : iostat_end !! use FPM_filesystem, only : getline !! implicit none !! integer :: iostat !! character(len=:),allocatable :: line, iomsg !! open(unit=stdin,pad=' yes ') !! INFINITE: do !! call getline(stdin,line,iostat,iomsg) !! if(iostat /= 0) exit INFINITE !! write(*,' ( a ) ')' [ '//line//' ] ' !! enddo INFINITE !! if(iostat /= iostat_end)then !! write(*,*)' error reading input : ',iomsg !! endif !! end program demo_getline !! subroutine getline(unit, line, iostat, iomsg) !> Formatted IO unit integer, intent(in) :: unit !> Line to read character(len=:), allocatable, intent(out) :: line !> Status of operation integer, intent(out) :: iostat !> Error message character(len=:), allocatable, optional :: iomsg integer, parameter :: BUFFER_SIZE = 32768 character(len=BUFFER_SIZE) :: buffer character(len=256) :: msg integer :: size integer :: stat allocate(character(len=0) :: line) do read(unit, ' ( a ) ', advance=' no ', iostat=stat, iomsg=msg, size=size) & & buffer if (stat > 0) exit line = line // buffer(:size) if (stat < 0) then if (is_iostat_eor(stat)) then stat = 0 end if exit end if end do if (stat /= 0) then if (present(iomsg)) iomsg = trim(msg) end if iostat = stat end subroutine getline !> delete a file by filename subroutine delete_file(file) character(len=*), intent(in) :: file logical :: exist integer :: unit inquire(file=file, exist=exist) if (exist) then open(file=file, newunit=unit) close(unit, status=\"delete\") end if end subroutine delete_file !> write trimmed character data to a file if it does not exist subroutine warnwrite(fname,data) character(len=*),intent(in) :: fname character(len=*),intent(in) :: data(:) if(.not.exists(fname))then call filewrite(fname,data) else write(stderr,' ( * ( g0 , 1 x )) ')' < INFO > ',fname,& & ' already exists . Not overwriting ' endif end subroutine warnwrite !> procedure to open filename as a sequential \"text\" file subroutine fileopen(filename,lun,ier) character(len=*),intent(in) :: filename integer,intent(out) :: lun integer,intent(out),optional :: ier integer :: ios character(len=256) :: message message=' ' ios=0 if(filename/=' ')then open(file=filename, & & newunit=lun, & & form=' formatted ', & ! FORM = FORMATTED | UNFORMATTED & access=' sequential ', & ! ACCESS = SEQUENTIAL| DIRECT | STREAM & action=' write ', & ! ACTION = READ|WRITE| READWRITE & position=' rewind ', & ! POSITION= ASIS | REWIND | APPEND & status=' new ', & ! STATUS = NEW| REPLACE| OLD| SCRATCH| UNKNOWN & iostat=ios, & & iomsg=message) else lun=stdout ios=0 endif if(ios/=0)then lun=-1 if(present(ier))then ier=ios else call fpm_stop(3,' * fileopen * : '//filename//' : '//trim(message)) endif endif end subroutine fileopen !> simple close of a LUN. On error show message and stop (by default) subroutine fileclose(lun,ier) integer,intent(in) :: lun integer,intent(out),optional :: ier character(len=256) :: message integer :: ios if(lun/=-1)then close(unit=lun,iostat=ios,iomsg=message) if(ios/=0)then if(present(ier))then ier=ios else call fpm_stop(4,' * fileclose * : '//trim(message)) endif endif endif end subroutine fileclose !> procedure to write filedata to file filename subroutine filewrite(filename,filedata) character(len=*),intent(in) :: filename character(len=*),intent(in) :: filedata(:) integer :: lun, i, ios character(len=256) :: message call fileopen(filename,lun) if(lun/=-1)then ! program currently stops on error on open, but might ! want it to continue so -1 (unallowed LUN) indicates error ! write file do i=1,size(filedata) write(lun,' ( a ) ',iostat=ios,iomsg=message)trim(filedata(i)) if(ios/=0)then call fpm_stop(5,' * filewrite * : '//filename//' : '//trim(message)) endif enddo endif ! close file call fileclose(lun) end subroutine filewrite !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!##Name !! which(3f) - [M_io:ENVIRONMENT] given a command name find the pathname by searching !! the directories in the environment variable $PATH !! (LICENSE:PD) !! !!##Syntax !! function which(command) result(pathname) !! !! character(len=*),intent(in) :: command !! character(len=:),allocatable :: pathname !! !!##Description !! Given a command name find the first file with that name in the directories !! specified by the environment variable $PATH. !! !!##options !! COMMAND the command to search for !! !!##Returns !! PATHNAME the first pathname found in the current user path. Returns blank !! if the command is not found. !! !!##Example !! !! Sample program: !! !! Checking the error message and counting lines: !! !! program demo_which !! use M_io, only : which !! implicit none !! write(*,*)' ls is ',which(' ls ') !! write(*,*)' dir is ',which(' dir ') !! write(*,*)' install is ',which(' install ') !! end program demo_which !! function which(command) result(pathname) character(len=*),intent(in) :: command character(len=:),allocatable :: pathname, checkon, paths(:), exts(:) integer :: i, j pathname='' call split(get_env(' PATH '),paths,delimiters=merge(' ; ',' : ',separator()==' \\ ')) SEARCH: do i=1,size(paths) checkon=trim(join_path(trim(paths(i)),command)) select case(separator()) case(' / ') if(exists(checkon))then pathname=checkon exit SEARCH endif case(' \\ ') if(exists(checkon))then pathname=checkon exit SEARCH endif if(exists(checkon//' . bat '))then pathname=checkon//' . bat ' exit SEARCH endif if(exists(checkon//' . exe '))then pathname=checkon//' . exe ' exit SEARCH endif call split(get_env(' PATHEXT '),exts,delimiters=' ; ') do j=1,size(exts) if(exists(checkon//' . '//trim(exts(j))))then pathname=checkon//' . '//trim(exts(j)) exit SEARCH endif enddo end select enddo SEARCH end function which !>AUTHOR: fpm(1) contributors !!LICENSE: MIT !> !!##Name !! run(3f) - execute specified system command and selectively echo !! command and output to a file and/or stdout. !! (LICENSE:MIT) !! !!##Syntax !! subroutine run(cmd,echo,exitstat,verbose,redirect) !! !! character(len=*), intent(in) :: cmd !! logical,intent(in),optional :: echo !! integer, intent(out),optional :: exitstat !! logical, intent(in), optional :: verbose !! character(*), intent(in), optional :: redirect !! !!##Description !! Execute the specified system command. Optionally !! !! + echo the command before execution !! + return the system exit status of the command. !! + redirect the output of the command to a file. !! + echo command output to stdout !! !! Calling run(3f) is preferred to direct calls to !! execute_command_line(3f) in the fpm(1) source to provide a standard !! interface where output modes can be specified. !! !!##Options !! CMD System command to execute !! ECHO Whether to echo the command being executed or not !! Defaults to .TRUE. . !! VERBOSE Whether to redirect the command output to a null device or not !! Defaults to .TRUE. . !! REDIRECT Filename to redirect stdout and stderr of the command into. !! If generated it is closed before run(3f) returns. !! EXITSTAT The system exit status of the command when supported by !! the system. If not present and a non-zero status is !! generated program termination occurs. !! !!##Example !! !! Sample program: !! !! Checking the error message and counting lines: !! !! program demo_run !! use fpm_filesystem, only : run !! implicit none !! logical,parameter :: T=.true., F=.false. !! integer :: exitstat !! character(len=:),allocatable :: cmd !! cmd=' ls - ltrasd * . md ' !! call run(cmd) !! call run(cmd,exitstat=exitstat) !! call run(cmd,echo=F) !! call run(cmd,verbose=F) !! end program demo_run !! subroutine run(cmd,echo,exitstat,verbose,redirect) character(len=*), intent(in) :: cmd logical,intent(in),optional :: echo integer, intent(out),optional :: exitstat logical, intent(in), optional :: verbose character(*), intent(in), optional :: redirect integer :: cmdstat character(len=256) :: cmdmsg, iomsg logical :: echo_local, verbose_local character(:), allocatable :: redirect_str character(:), allocatable :: line integer :: stat, fh, iostat if(present(echo))then echo_local=echo else echo_local=.true. end if if(present(verbose))then verbose_local=verbose else verbose_local=.true. end if if (present(redirect)) then if(redirect /= '')then redirect_str = \">\"//redirect//\" 2>&1\" endif else if(verbose_local)then ! No redirection but verbose output redirect_str = \"\" else ! No redirection and non-verbose output if (os_is_unix()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if end if if(echo_local) print *, ' + ', cmd !//redirect_str call execute_command_line(cmd//redirect_str, exitstat=stat,cmdstat=cmdstat,cmdmsg=cmdmsg) if(cmdstat /= 0)then write(*,' ( a ) ')' < ERROR > : failed command '//cmd//redirect_str call fpm_stop(1,' * run * : '//trim(cmdmsg)) endif if (verbose_local.and.present(redirect)) then open(newunit=fh,file=redirect,status=' old ',iostat=iostat,iomsg=iomsg) if(iostat == 0)then do call getline(fh, line, iostat) if (iostat /= 0) exit write(*,' ( A ) ') trim(line) end do else write(*,' ( A ) ') trim(iomsg) endif close(fh) end if if (present(exitstat)) then exitstat = stat elseif (stat /= 0) then call fpm_stop(stat,' * run * : Command '//cmd//redirect_str//' returned a non - zero status code ') end if end subroutine run !> Delete directory using system OS remove directory commands subroutine os_delete_dir(is_unix, dir, echo) logical, intent(in) :: is_unix character(len=*), intent(in) :: dir logical, intent(in), optional :: echo if (is_unix) then call run(' rm - rf ' // dir, echo=echo,verbose=.false.) else call run(' rmdir / s / q ' // dir, echo=echo,verbose=.false.) end if end subroutine os_delete_dir !> Determine the path prefix to the local folder. Used for installation, registry etc. function get_local_prefix(os) result(prefix) !> Installation prefix character(len=:), allocatable :: prefix !> Platform identifier integer, intent(in), optional :: os !> Default installation prefix on Unix platforms character(len=*), parameter :: default_prefix_unix = \"/usr/local\" !> Default installation prefix on Windows platforms character(len=*), parameter :: default_prefix_win = \"C:\\\" character(len=:), allocatable :: home if (os_is_unix(os)) then home=get_env(' HOME ','') if (home /= '' ) then prefix = join_path(home, \".local\") else prefix = default_prefix_unix end if else home=get_env(' APPDATA ','') if (home /= '' ) then prefix = join_path(home, \"local\") else prefix = default_prefix_win end if end if end function get_local_prefix !> Returns .true. if provided path is absolute. !> !> `~` not treated as absolute. logical function is_absolute_path(path, is_unix) character(len=*), intent(in) :: path logical, optional, intent(in):: is_unix character(len=*), parameter :: letters = ' ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ' logical :: is_unix_os if (present(is_unix)) then is_unix_os = is_unix else is_unix_os = os_is_unix() end if if (is_unix_os) then is_absolute_path = path(1:1) == ' / ' else if (len(path) < 2) then is_absolute_path = .false. return end if is_absolute_path = index(letters, path(1:1)) /= 0 .and. path(2:2) == ' : ' end if end function is_absolute_path !> Get the HOME directory on Unix and the %USERPROFILE% directory on Windows. subroutine get_home(home, error) character(len=:), allocatable, intent(out) :: home type(error_t), allocatable, intent(out) :: error if (os_is_unix()) then home=get_env(' HOME ','') if ( home == '' ) then call fatal_error(error, \"Couldn' t retrieve 'HOME' variable \") return end if else home=get_env('USERPROFILE','') if ( home == '' ) then call fatal_error(error, \" Couldn 't retrieve ' % USERPROFILE % ' variable\") return end if end if end subroutine get_home !> Execute command line and return output as a string. subroutine execute_and_read_output(cmd, output, error, verbose) !> Command to execute. character(len=*), intent(in) :: cmd !> Command line output. character(len=:), allocatable, intent(out) :: output !> Error to handle. type(error_t), allocatable, intent(out) :: error !> Print additional information if true. logical, intent(in), optional :: verbose integer :: exitstat, unit, stat character(len=:), allocatable :: cmdmsg, tmp_file, output_line logical :: is_verbose if (present(verbose)) then is_verbose = verbose else is_verbose = .false. end if tmp_file = get_temp_filename() call run(cmd//' > '//tmp_file, exitstat=exitstat, echo=is_verbose) if (exitstat /= 0) call fatal_error(error, ' * run * : '//\"Command failed: ' \"//cmd//\" '. Message: ' \"//trim(cmdmsg)//\" '.\") open(newunit=unit, file=tmp_file, action=' read ', status=' old ') output = '' do call getline(unit, output_line, stat) if (stat /= 0) exit output = output//output_line//' ' end do if (is_verbose) print *, output close(unit, status=' delete ') end !> Ensure a windows path is converted to an 8.3 DOS path if it contains spaces function get_dos_path(path,error) character(len=*), intent(in) :: path type(error_t), allocatable, intent(out) :: error character(len=:), allocatable :: get_dos_path character(:), allocatable :: redirect,screen_output,line integer :: stat,cmdstat,iunit,last ! Non-Windows OS if (get_os_type()/=OS_WINDOWS) then get_dos_path = path return end if ! Trim path first get_dos_path = trim(path) !> No need to convert if there are no spaces has_spaces: if (scan(get_dos_path,' ')>0) then redirect = get_temp_filename() call execute_command_line(' cmd / c for % A in ( \"'//path//'\" ) do @ echo % ~ sA > '//redirect//' 2 > & 1 ',& exitstat=stat,cmdstat=cmdstat) !> Read screen output command_OK: if (cmdstat==0 .and. stat==0) then allocate(character(len=0) :: screen_output) open(newunit=iunit,file=redirect,status=' old ',iostat=stat) if (stat == 0)then do call getline(iunit, line, stat) if (stat /= 0) exit screen_output = screen_output//line//' ' end do ! Close and delete file close(iunit,status=' delete ') else call fatal_error(error,' cannot read temporary file from successful DOS path evaluation ') return endif else command_OK call fatal_error(error,' unsuccessful Windows -> DOS path command ') return end if command_OK get_dos_path = trim(adjustl(screen_output)) endif has_spaces !> Ensure there are no trailing slashes last = len_trim(get_dos_path) if (last>1 .and. get_dos_path(last:last)==' / ' .or. get_dos_path(last:last)==' \\' ) get_dos_path = get_dos_path ( 1 : last - 1 ) end function get_dos_path end module fpm_filesystem","tags":"","loc":"sourcefile/fpm_filesystem.f90.html"},{"title":"fpm_backend.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_backend Source Code fpm_backend.F90 Source Code !># Build backend !> Uses a list of `[[build_target_ptr]]` and a valid `[[fpm_model]]` instance !> to schedule and execute the compilation and linking of package targets. !> !> The package build process (`[[build_package]]`) comprises three steps: !> !> 1. __Target sorting:__ topological sort of the target dependency graph (`[[sort_target]]`) !> 2. __Target scheduling:__ group targets into schedule regions based on the sorting (`[[schedule_targets]]`) !> 3. __Target building:__ generate targets by compilation or linking !> !> @note If compiled with OpenMP, targets will be build in parallel where possible. !> !>### Incremental compilation !> The backend process supports *incremental* compilation whereby targets are not !> re-compiled if their corresponding dependencies have not been modified. !> !> - Source-based targets (*i.e.* objects) are not re-compiled if the corresponding source !> file is unmodified AND all of the target dependencies are not marked for re-compilation !> !> - Link targets (*i.e.* executables and libraries) are not re-compiled if the !> target output file already exists AND all of the target dependencies are not marked for !> re-compilation !> !> Source file modification is determined by a file digest (hash) which is calculated during !> the source parsing phase ([[fpm_source_parsing]]) and cached to disk after a target is !> successfully generated. !> module fpm_backend use , intrinsic :: iso_fortran_env , only : stdin => input_unit , stdout => output_unit , stderr => error_unit use fpm_error , only : fpm_stop use fpm_filesystem , only : basename , dirname , join_path , exists , mkdir , run , getline use fpm_model , only : fpm_model_t use fpm_strings , only : string_t , operator (. in .) use fpm_targets , only : build_target_t , build_target_ptr , FPM_TARGET_OBJECT , & FPM_TARGET_C_OBJECT , FPM_TARGET_ARCHIVE , FPM_TARGET_EXECUTABLE , & FPM_TARGET_CPP_OBJECT use fpm_backend_output implicit none private public :: build_package , sort_target , schedule_targets #ifndef FPM_BOOTSTRAP interface function c_isatty () bind ( C , name = 'c_isatty' ) use , intrinsic :: iso_c_binding , only : c_int integer ( c_int ) :: c_isatty end function end interface #endif contains !> Top-level routine to build package described by `model` subroutine build_package ( targets , model , verbose ) type ( build_target_ptr ), intent ( inout ) :: targets (:) type ( fpm_model_t ), intent ( in ) :: model logical , intent ( in ) :: verbose integer :: i , j type ( build_target_ptr ), allocatable :: queue (:) integer , allocatable :: schedule_ptr (:), stat (:) logical :: build_failed , skip_current type ( string_t ), allocatable :: build_dirs (:) type ( string_t ) :: temp type ( build_progress_t ) :: progress logical :: plain_output ! Need to make output directory for include (mod) files allocate ( build_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % output_dir . in . build_dirs ) cycle temp % s = target % output_dir build_dirs = [ build_dirs , temp ] end associate end do do i = 1 , size ( build_dirs ) call mkdir ( build_dirs ( i )% s , verbose ) end do ! Perform depth-first topological sort of targets do i = 1 , size ( targets ) call sort_target ( targets ( i )% ptr ) end do ! Construct build schedule queue call schedule_targets ( queue , schedule_ptr , targets ) ! Check if queue is empty if (. not . verbose . and . size ( queue ) < 1 ) then write ( stderr , '(a)' ) 'Project is up to date' return end if ! Initialise build status flags allocate ( stat ( size ( queue ))) stat (:) = 0 build_failed = . false . ! Set output mode #ifndef FPM_BOOTSTRAP plain_output = (. not .( c_isatty () == 1 )) . or . verbose #else plain_output = . true . #endif progress = build_progress_t ( queue , plain_output ) ! Loop over parallel schedule regions do i = 1 , size ( schedule_ptr ) - 1 ! Build targets in schedule region i !$omp parallel do default(shared) private(skip_current) schedule(dynamic,1) do j = schedule_ptr ( i ),( schedule_ptr ( i + 1 ) - 1 ) ! Check if build already failed !$omp atomic read skip_current = build_failed if (. not . skip_current ) then call progress % compiling_status ( j ) call build_target ( model , queue ( j )% ptr , verbose , stat ( j )) call progress % completed_status ( j , stat ( j )) end if ! Set global flag if this target failed to build if ( stat ( j ) /= 0 ) then !$omp atomic write build_failed = . true . end if end do ! Check if this schedule region failed: exit with message if failed if ( build_failed ) then write ( * , * ) do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) Then call print_build_log ( queue ( j )% ptr ) end if end do do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Compilation failed for object \"' , basename ( queue ( j )% ptr % output_file ), '\"' end if end do call fpm_stop ( 1 , 'stopping due to failed compilation' ) end if end do call progress % success () end subroutine build_package !> Topologically sort a target for scheduling by !> recursing over its dependencies. !> !> Checks disk-cached source hashes to determine if objects are !> up-to-date. Up-to-date sources are tagged as skipped. !> !> On completion, `target` should either be marked as !> sorted (`target%sorted=.true.`) or skipped (`target%skip=.true.`) !> !> If `target` is marked as sorted, `target%schedule` should be an !> integer greater than zero indicating the region for scheduling !> recursive subroutine sort_target ( target ) type ( build_target_t ), intent ( inout ), target :: target integer :: i , fh , stat ! Check if target has already been processed (as a dependency) if ( target % sorted . or . target % skip ) then return end if ! Check for a circular dependency ! (If target has been touched but not processed) if ( target % touched ) then call fpm_stop ( 1 , '(!) Circular dependency found with: ' // target % output_file ) else target % touched = . true . ! Set touched flag end if ! Load cached source file digest if present if (. not . allocated ( target % digest_cached ) . and . & exists ( target % output_file ) . and . & exists ( target % output_file // '.digest' )) then allocate ( target % digest_cached ) open ( newunit = fh , file = target % output_file // '.digest' , status = 'old' ) read ( fh , * , iostat = stat ) target % digest_cached close ( fh ) if ( stat /= 0 ) then ! Cached digest is not recognized deallocate ( target % digest_cached ) end if end if if ( allocated ( target % source )) then ! Skip if target is source-based and source file is unmodified if ( allocated ( target % digest_cached )) then if ( target % digest_cached == target % source % digest ) target % skip = . true . end if elseif ( exists ( target % output_file )) then ! Skip if target is not source-based and already exists target % skip = . true . end if ! Loop over target dependencies target % schedule = 1 do i = 1 , size ( target % dependencies ) ! Sort dependency call sort_target ( target % dependencies ( i )% ptr ) if (. not . target % dependencies ( i )% ptr % skip ) then ! Can't skip target if any dependency is not skipped target % skip = . false . ! Set target schedule after all of its dependencies target % schedule = max ( target % schedule , target % dependencies ( i )% ptr % schedule + 1 ) end if end do ! Mark flag as processed: either sorted or skipped target % sorted = . not . target % skip end subroutine sort_target !> Construct a build schedule from the sorted targets. !> !> The schedule is broken into regions, described by `schedule_ptr`, !> where targets in each region can be compiled in parallel. !> subroutine schedule_targets ( queue , schedule_ptr , targets ) type ( build_target_ptr ), allocatable , intent ( out ) :: queue (:) integer , allocatable :: schedule_ptr (:) type ( build_target_ptr ), intent ( in ) :: targets (:) integer :: i , j integer :: n_schedule , n_sorted n_schedule = 0 ! Number of schedule regions n_sorted = 0 ! Total number of targets to build do i = 1 , size ( targets ) if ( targets ( i )% ptr % sorted ) then n_sorted = n_sorted + 1 end if n_schedule = max ( n_schedule , targets ( i )% ptr % schedule ) end do allocate ( queue ( n_sorted )) allocate ( schedule_ptr ( n_schedule + 1 )) ! Construct the target queue and schedule region pointer n_sorted = 1 schedule_ptr ( n_sorted ) = 1 do i = 1 , n_schedule do j = 1 , size ( targets ) if ( targets ( j )% ptr % sorted ) then if ( targets ( j )% ptr % schedule == i ) then queue ( n_sorted )% ptr => targets ( j )% ptr n_sorted = n_sorted + 1 end if end if end do schedule_ptr ( i + 1 ) = n_sorted end do end subroutine schedule_targets !> Call compile/link command for a single target. !> !> If successful, also caches the source file digest to disk. !> subroutine build_target ( model , target , verbose , stat ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_t ), intent ( in ), target :: target logical , intent ( in ) :: verbose integer , intent ( out ) :: stat integer :: fh !$omp critical if (. not . exists ( dirname ( target % output_file ))) then call mkdir ( dirname ( target % output_file ), verbose ) end if !$omp end critical select case ( target % target_type ) case ( FPM_TARGET_OBJECT ) call model % compiler % compile_fortran ( target % source % file_name , target % output_file , & & target % compile_flags , target % output_log_file , stat ) case ( FPM_TARGET_C_OBJECT ) call model % compiler % compile_c ( target % source % file_name , target % output_file , & & target % compile_flags , target % output_log_file , stat ) case ( FPM_TARGET_CPP_OBJECT ) call model % compiler % compile_cpp ( target % source % file_name , target % output_file , & & target % compile_flags , target % output_log_file , stat ) case ( FPM_TARGET_EXECUTABLE ) call model % compiler % link ( target % output_file , & & target % compile_flags // \" \" // target % link_flags , target % output_log_file , stat ) case ( FPM_TARGET_ARCHIVE ) call model % archiver % make_archive ( target % output_file , target % link_objects , & & target % output_log_file , stat ) end select if ( stat == 0 . and . allocated ( target % source )) then open ( newunit = fh , file = target % output_file // '.digest' , status = 'unknown' ) write ( fh , * ) target % source % digest close ( fh ) end if end subroutine build_target !> Read and print the build log for target !> subroutine print_build_log ( target ) type ( build_target_t ), intent ( in ), target :: target integer :: fh , ios character (:), allocatable :: line if ( exists ( target % output_log_file )) then open ( newunit = fh , file = target % output_log_file , status = 'old' ) do call getline ( fh , line , ios ) if ( ios /= 0 ) exit write ( * , '(A)' ) trim ( line ) end do close ( fh ) else write ( stderr , '(*(g0:,1x))' ) ' Unable to find build log \"' , basename ( target % output_log_file ), '\"' end if end subroutine print_build_log end module fpm_backend","tags":"","loc":"sourcefile/fpm_backend.f90.html"},{"title":"fpm_command_line.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_command_line Source Code fpm_command_line.f90 Source Code !># 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 , OS_OPENBSD use M_CLI2 , only : set_args , lget , sget , unnamed , remaining , specified use M_CLI2 , only : get_subcommand , CLI_RESPONSE_FILE use fpm_strings , only : lower , split , to_fortran_name , is_fortran_name , remove_characters_in_set , string_t use fpm_filesystem , only : basename , canon_path , which , run use fpm_environment , only : get_command_arguments_quoted use fpm_error , only : fpm_stop , error_t use fpm_os , only : get_current_directory use fpm_release , only : fpm_version , version_t 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 , & fpm_clean_settings , & fpm_publish_settings , & get_command_line_settings type , abstract :: fpm_cmd_settings character ( len = :), allocatable :: working_dir 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 . logical :: build_tests = . false . logical :: prune = . true . character ( len = :), allocatable :: compiler character ( len = :), allocatable :: c_compiler character ( len = :), allocatable :: cxx_compiler character ( len = :), allocatable :: archiver character ( len = :), allocatable :: profile character ( len = :), allocatable :: flag character ( len = :), allocatable :: cflag character ( len = :), allocatable :: cxxflag character ( len = :), allocatable :: ldflag end type type , extends ( fpm_build_settings ) :: fpm_run_settings character ( len = ibug ), allocatable :: name (:) character ( len = :), allocatable :: args ! passed to the app character ( len = :), allocatable :: runner character ( len = :), allocatable :: runner_args ! passed to the runner logical :: example contains procedure :: runner_command 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 type , extends ( fpm_cmd_settings ) :: fpm_clean_settings logical :: clean_skip = . false . logical :: clean_call = . false . end type type , extends ( fpm_build_settings ) :: fpm_publish_settings logical :: show_package_version = . false . logical :: show_upload_data = . false . logical :: is_dry_run = . false . character ( len = :), allocatable :: token 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 (:), & & help_clean (:), help_publish (:) character ( len = 20 ), parameter :: manual ( * ) = [ character ( len = 20 ) :: & & ' ' , 'fpm' , 'new' , 'build' , 'run' , 'clean' , & & 'test' , 'runner' , 'install' , 'update' , 'list' , 'help' , 'version' , 'publish' ] character ( len = :), allocatable :: val_runner , val_compiler , val_flag , val_cflag , val_cxxflag , val_ldflag , & val_profile , val_runner_args ! '12345678901234567890123456789012345678901234567890123456789012345678901234567890',& character ( len = 80 ), parameter :: help_text_build_common ( * ) = [ character ( len = 80 ) :: & ' --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. ' ,& ' --no-prune Disable tree-shaking/pruning of unused module dependencies ' & ] ! '12345678901234567890123456789012345678901234567890123456789012345678901234567890',& character ( len = 80 ), parameter :: help_text_compiler ( * ) = [ character ( len = 80 ) :: & ' --compiler NAME Specify a compiler name. The default is \"gfortran\" ' ,& ' unless set by the environment variable FPM_FC. ' ,& ' --c-compiler NAME Specify the C compiler name. Automatically determined by ' ,& ' default unless set by the environment variable FPM_CC. ' ,& ' --cxx-compiler NAME Specify the C++ compiler name. Automatically determined by' ,& ' default unless set by the environment variable FPM_CXX. ' ,& ' --archiver NAME Specify the archiver name. Automatically determined by ' ,& ' default unless set by the environment variable FPM_AR. ' & ] ! '12345678901234567890123456789012345678901234567890123456789012345678901234567890',& character ( len = 80 ), parameter :: help_text_flag ( * ) = [ character ( len = 80 ) :: & ' --flag FFLAGS selects compile arguments for the build, the default value is' ,& ' set by the FPM_FFLAGS environment variable. 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. ' ,& ' --c-flag CFLAGS selects compile arguments specific for C source in the build.' ,& ' The default value is set by the FPM_CFLAGS environment ' ,& ' variable. ' ,& ' --cxx-flag CFLAGS selects compile arguments specific for C++ source in the ' ,& ' build. The default value is set by the FPM_CXXFLAGS ' ,& ' environment variable. ' ,& ' --link-flag LDFLAGS select arguments passed to the linker for the build. The ' ,& ' default value is set by the FPM_LDFLAGS environment variable.' & ] character ( len = 80 ), parameter :: help_text_environment ( * ) = [ character ( len = 80 ) :: & 'ENVIRONMENT VARIABLES' ,& ' FPM_FC sets the path to the Fortran compiler used for the build,' , & ' will be overwritten by --compiler command line option' , & '' , & ' FPM_FFLAGS sets the arguments for the Fortran compiler' , & ' will be overwritten by --flag command line option' , & '' , & ' FPM_CC sets the path to the C compiler used for the build,' , & ' will be overwritten by --c-compiler command line option' , & '' , & ' FPM_CFLAGS sets the arguments for the C compiler' , & ' will be overwritten by --c-flag command line option' , & '' , & ' FPM_CXX sets the path to the C++ compiler used for the build,' , & ' will be overwritten by --cxx-compiler command line option' , & '' , & ' FPM_CXXFLAGS sets the arguments for the C++ compiler' , & ' will be overwritten by --cxx-flag command line option' , & '' , & ' FPM_AR sets the path to the archiver used for the build,' , & ' will be overwritten by --archiver command line option' , & '' , & ' FPM_LDFLAGS sets additional link arguments for creating executables' , & ' will be overwritten by --link-flag command line option' & ] contains subroutine get_command_line_settings ( cmd_settings ) class ( fpm_cmd_settings ), allocatable , intent ( out ) :: cmd_settings integer , parameter :: widest = 256 character ( len = 4096 ) :: cmdarg integer :: i integer :: os type ( fpm_install_settings ), allocatable :: install_settings type ( version_t ) :: version character ( len = :), allocatable :: common_args , compiler_args , run_args , working_dir , & & c_compiler , cxx_compiler , archiver , version_s , token_s character ( len =* ), parameter :: fc_env = \"FC\" , cc_env = \"CC\" , ar_env = \"AR\" , & & fflags_env = \"FFLAGS\" , cflags_env = \"CFLAGS\" , cxxflags_env = \"CXXFLAGS\" , ldflags_env = \"LDFLAGS\" , & & fc_default = \"gfortran\" , cc_default = \" \" , ar_default = \" \" , flags_default = \" \" , & & cxx_env = \"CXX\" , cxx_default = \" \" type ( error_t ), allocatable :: error call set_help () os = get_os_type () ! text for --version switch, select case ( os ) 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_OPENBSD ); os_type = \"OS Type: OpenBSD\" case ( OS_UNKNOWN ); os_type = \"OS Type: Unknown\" case default ; os_type = \"OS Type: UNKNOWN\" end select ! Get current release version version = fpm_version () version_s = version % s () version_text = [ character ( len = 80 ) :: & & 'Version: ' // trim ( version_s ) // ', 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 CLI_RESPONSE_FILE = . true . cmdarg = get_subcommand () common_args = & ' --directory:C \" \"' // & ' --verbose F' run_args = & ' --target \" \"' // & ' --list F' // & ' --runner \" \"' // & ' --runner-args \" \"' compiler_args = & ' --profile \" \"' // & ' --no-prune F' // & ' --compiler \"' // get_fpm_env ( fc_env , fc_default ) // '\"' // & ' --c-compiler \"' // get_fpm_env ( cc_env , cc_default ) // '\"' // & ' --cxx-compiler \"' // get_fpm_env ( cxx_env , cxx_default ) // '\"' // & ' --archiver \"' // get_fpm_env ( ar_env , ar_default ) // '\"' // & ' --flag:: \"' // get_fpm_env ( fflags_env , flags_default ) // '\"' // & ' --c-flag:: \"' // get_fpm_env ( cflags_env , flags_default ) // '\"' // & ' --cxx-flag:: \"' // get_fpm_env ( cxxflags_env , flags_default ) // '\"' // & ' --link-flag:: \"' // get_fpm_env ( ldflags_env , flags_default ) // '\"' ! now set subcommand-specific help text and process commandline ! arguments. Then call subcommand routine select case ( trim ( cmdarg )) case ( 'run' ) call set_args ( common_args // compiler_args // run_args // '& & --all F & & --example F& & --' , help_run , version_text ) call check_build_vals () if ( size ( unnamed ) > 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 ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_run_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_run_settings (& & args = remaining ,& & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = lget ( 'example' ), & & list = lget ( 'list' ),& & build_tests = . false .,& & name = names ,& & runner = val_runner ,& & runner_args = val_runner_args , & & verbose = lget ( 'verbose' ) ) case ( 'build' ) call set_args ( common_args // compiler_args // '& & --list F & & --show-model F & & --tests F & & --' , help_build , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_build_settings :: cmd_settings ) cmd_settings = fpm_build_settings ( & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ) ) case ( 'new' ) call set_args ( common_args // '& & --src F & & --lib F & & --app F & & --test F & & --example F & & --backfill F & & --full F & & --bare F' , & & help_new , version_text ) select case ( size ( unnamed )) case ( 1 ) if ( lget ( 'backfill' )) then name = '.' else write ( stderr , '(*(7x,g0,/))' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|[--full|--bare] [--backfill]' call fpm_stop ( 1 , 'directory name required' ) endif case ( 2 ) name = trim ( unnamed ( 2 )) case default write ( stderr , '(7x,g0)' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| [--full|--bare] [--backfill]' call fpm_stop ( 2 , 'only one directory name allowed' ) end select !*! canon_path is not converting \".\", etc. if ( name == '.' ) then call get_current_directory ( name , error ) if ( allocated ( error )) then write ( stderr , '(\"[Error]\", 1x, a)' ) error % message stop 1 endif endif name = canon_path ( name ) if ( . not . is_fortran_name ( to_fortran_name ( basename ( name ))) ) then write ( stderr , '(g0)' ) [ character ( len = 72 ) :: & & ' the fpm project name must be made of up to 63 ASCII letters,' , & & ' numbers, underscores, or hyphens, and start with a letter.' ] call fpm_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))' )& & ' --full and any of [--src|--lib,--app,--test,--example,--bare]' , & & ' are mutually exclusive.' call fpm_stop ( 5 , ' ' ) elseif ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' , 'full' ])) & & . and . lget ( 'bare' ) ) then write ( stderr , '(*(a))' )& & ' --bare and any of [--src|--lib,--app,--test,--example,--full]' , & & ' are mutually exclusive.' call fpm_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 ( common_args , help_help , version_text ) if ( size ( unnamed ) < 2 ) then if ( unnamed ( 1 ) == 'help' ) then unnamed = [ ' ' , 'fpm' ] else unnamed = manual endif elseif ( unnamed ( 2 ) == 'manual' ) then unnamed = manual endif 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 ( 'clean' ) help_text = [ character ( len = widest ) :: help_text , help_clean ] case ( 'publish' ) help_text = [ character ( len = widest ) :: help_text , help_publish ] case default help_text = [ character ( len = widest ) :: help_text , & & ' unknown help topic \"' // trim ( unnamed ( i )) // '\"' ] !!& ' unknown help topic \"'//trim(unnamed(i)).'not found in:',manual] end select enddo call printhelp ( help_text ) case ( 'install' ) call set_args ( common_args // compiler_args // '& & --no-rebuild F --prefix \" \" & & --list F & & --libdir \"lib\" --bindir \"bin\" --includedir \"include\"' , & help_install , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( install_settings , source = fpm_install_settings (& list = lget ( 'list' ), & profile = val_profile ,& prune = . not . lget ( 'no-prune' ), & compiler = val_compiler , & c_compiler = c_compiler , & cxx_compiler = cxx_compiler , & archiver = archiver , & flag = val_flag , & cflag = val_cflag , & cxxflag = val_cxxflag , & ldflag = val_ldflag , & 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 ( common_args // '& & --list F& &' , help_list , version_text ) if ( lget ( 'list' )) then help_text = [ character ( widest ) :: help_list_nodash , help_list_dash ] else help_text = help_list_nodash endif call printhelp ( help_text ) case ( 'test' ) call set_args ( common_args // compiler_args // run_args // ' --' , & help_test , version_text ) call check_build_vals () if ( size ( unnamed ) > 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 ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_test_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_test_settings (& & args = remaining , & & profile = val_profile , & & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = . false ., & & list = lget ( 'list' ), & & build_tests = . true ., & & name = names , & & runner = val_runner , & & runner_args = val_runner_args , & & verbose = lget ( 'verbose' )) case ( 'update' ) call set_args ( common_args // ' --fetch-only F --clean F' , & help_update , version_text ) if ( size ( unnamed ) > 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 ( 'clean' ) call set_args ( common_args // & & ' --skip' // & & ' --all' , & help_clean , version_text ) allocate ( fpm_clean_settings :: cmd_settings ) call get_current_directory ( working_dir , error ) cmd_settings = fpm_clean_settings ( & & clean_skip = lget ( 'skip' ), & & clean_call = lget ( 'all' )) case ( 'publish' ) call set_args ( common_args // compiler_args // '& & --show-package-version F & & --show-upload-data F & & --dry-run F & & --token \" \" & & --list F & & --show-model F & & --tests F & & --' , help_publish , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) token_s = sget ( 'token' ) allocate ( fpm_publish_settings :: cmd_settings ) cmd_settings = fpm_publish_settings ( & & show_package_version = lget ( 'show-package-version' ), & & show_upload_data = lget ( 'show-upload-data' ), & & is_dry_run = lget ( 'dry-run' ), & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ),& & token = token_s ) case default if ( cmdarg . ne . '' . and . which ( 'fpm-' // cmdarg ). ne . '' ) then call run ( 'fpm-' // trim ( cmdarg ) // ' ' // get_command_arguments_quoted (),. false .) stop else call set_args ( '& & --list F& &' , help_fpm , version_text ) ! Note: will not get here if --version or --usage or --help ! is present on commandline if ( lget ( 'list' )) then help_text = help_list_dash elseif ( len_trim ( cmdarg ) == 0 ) then write ( stdout , '(*(a))' ) 'Fortran Package Manager:' write ( stdout , '(*(a))' ) ' ' help_text = [ character ( widest ) :: help_list_nodash , help_usage ] else write ( stderr , '(*(a))' ) ' unknown subcommand [' , & & trim ( cmdarg ), ']' help_text = [ character ( widest ) :: help_list_dash , help_usage ] endif call printhelp ( help_text ) endif end select if ( allocated ( cmd_settings )) then working_dir = sget ( \"directory\" ) call move_alloc ( working_dir , cmd_settings % working_dir ) end if contains subroutine check_build_vals () val_compiler = sget ( 'compiler' ) if ( val_compiler == '' ) val_compiler = 'gfortran' val_flag = \" \" // sget ( 'flag' ) val_cflag = \" \" // sget ( 'c-flag' ) val_cxxflag = \" \" // sget ( 'cxx-flag' ) val_ldflag = \" \" // sget ( 'link-flag' ) val_profile = sget ( 'profile' ) end subroutine check_build_vals !> Print help text and stop subroutine printhelp ( lines ) character ( len = :), intent ( in ), allocatable :: lines (:) integer :: iii , ii if ( allocated ( lines )) then ii = size ( lines ) if ( ii > 0 . and . len ( lines ) > 0 ) then write ( stdout , '(g0)' )( trim ( lines ( iii )), iii = 1 , ii ) else write ( stdout , '(a)' ) ' *printhelp* output requested is empty' endif endif stop end subroutine printhelp end subroutine get_command_line_settings 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 ' , & ' clean Delete the build ' , & ' publish Publish package to the registry ' , & ' ' , & ' 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] ' , & ' [--tests] [--no-prune] ' , & ' 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] ' , & ' clean [--skip] [--all] ' , & ' publish [--token TOKEN] [--show-package-version] [--show-upload-data] ' , & ' [--dry-run] [--verbose] ' , & ' ' ] 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 ... --runner-args ARGS -- 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\". ' , & ' --runner-args \"args\" an additional option to pass command-line arguments ' , & ' to the runner command, instead of to the fpm app. ' , & ' -- SUFFIX_OPTIONS additional options to suffix the command CMD and executable ' , & ' file names with. These options are passed as command-line ' , & ' arguments to the app. ' , & '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 \"mpiexec\" --runner-args \"-np 12\" ' , & ' 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 to the --help switch for displaying help text. ' , & ' + list Display brief descriptions of all subcommands. ' , & ' + install Install project. ' , & ' + clean Delete directories in the \"build/\" directory, except ' , & ' dependencies. Prompts for confirmation to delete. ' , & ' + publish Publish package to the registry. ' , & ' ' , & ' Their syntax is ' , & ' ' , & ' build [--profile PROF] [--flag FFLAGS] [--list] [--compiler COMPILER_NAME] ' , & ' [--tests] [--no-prune] ' , & ' 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] [--all] ' , & ' [--example] [--runner \"CMD\"] [--compiler COMPILER_NAME] ' , & ' [--no-prune] [-- ARGS] ' , & ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] ' , & ' [--runner \"CMD\"] [--compiler COMPILER_NAME] [--no-prune] [-- ARGS] ' , & ' help [NAME(s)] ' , & ' list [--list] ' , & ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH] ' , & ' [options] ' , & ' clean [--skip] [--all] ' , & ' publish [--token TOKEN] [--show-package-version] [--show-upload-data] ' , & ' [--dry-run] [--verbose] ' , & ' ' , & 'SUBCOMMAND OPTIONS ' , & ' -C, --directory PATH' , & ' Change working directory to PATH before running any command' , & help_text_build_common , & help_text_compiler , & help_text_flag , & ' --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. ' , & ' -- ARGS Arguments to pass to executables. ' , & ' --skip Delete directories in the build/ directory without ' , & ' prompting, but skip dependencies. ' , & ' --all Delete directories in the build/ directory without ' , & ' prompting, including dependencies. ' , & ' ' , & 'VALID FOR ALL SUBCOMMANDS ' , & ' --help Show help text and exit ' , & ' --verbose Display additional information when available ' , & ' --version Show version information and exit. ' , & ' ' , & '@file ' , & ' You may replace the default options for the fpm(1) command from a ' , & ' file if your first options begin with @file. Initial options will ' , & ' then be read from the \"response file\" \"file.rsp\" in the current ' , & ' directory. ' , & ' ' , & ' If \"file\" does not exist or cannot be read, then an error occurs and' , & ' the program stops. Each line of the file is prefixed with \"options\" ' , & ' and interpreted as a separate argument. The file itself may not ' , & ' contain @file arguments. That is, it is not processed recursively. ' , & ' ' , & ' For more information on response files see ' , & ' ' , & ' https://urbanjost.github.io/M_CLI2/set_args.3m_cli2.html ' , & ' ' , & ' The basic functionality described here will remain the same, but ' , & ' other features described at the above reference may change. ' , & ' ' , & ' An example file: ' , & ' ' , & ' # my build options ' , & ' options build ' , & ' options --compiler gfortran ' , & ' options --flag \"-pg -static -pthread -Wunreachable-code -Wunused ' , & ' -Wuninitialized -g -O -fbacktrace -fdump-core -fno-underscoring ' , & ' -frecord-marker=4 -L/usr/X11R6/lib -L/usr/X11R6/lib64 -lX11\" ' , & ' ' , & ' Note --flag would have to be on one line as response files do not ' , & ' (currently) allow for continued lines or multiple specifications of ' , & ' the same option. ' , & ' ' , & help_text_environment , & ' ' , & '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 ' , & ' fpm clean --all ' , & ' ' , & '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://fpm.fortran-lang.org/en/spec/manifest.html ' , & '' ] help_list = [ character ( len = 80 ) :: & 'NAME ' , & ' list(1) - list summary of fpm(1) subcommands ' , & ' ' , & 'SYNOPSIS ' , & ' fpm 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. ' , & help_text_build_common , & help_text_compiler , & help_text_flag , & ' --runner CMD A command to prefix the program execution paths with. ' , & ' see \"fpm help runner\" for further details. ' , & ' --list list basenames 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. ' , & ' ' , & help_text_environment , & ' ' , & 'EXAMPLES ' , & ' fpm(1) - run or display project applications: ' , & ' ' , & ' fpm run # run a target when only one exists or list targets ' , & ' fpm run --list # list basename of all targets, running nothing. ' , & ' fpm run \"demo*\" --list # list target basenames starting with \"demo*\".' , & ' fpm run \"psi*\" --runner # list target pathnames starting with \"psi*\".' , & ' 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] [--tests] ' , & ' ' , & ' 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 ' , & help_text_build_common ,& help_text_compiler , & help_text_flag , & ' --list list candidates instead of building or running them ' , & ' --tests build all tests (otherwise only if needed) ' , & ' --show-model show the model and exit (do not build) ' , & ' --help print this help and exit ' , & ' --version print program version information and exit ' , & ' ' , & help_text_environment , & ' ' , & '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 ' , & ' ' , & ' The default file structure (that will be automatically scanned) is ' , & ' ' , & ' NAME/ ' , & ' fpm.toml ' , & ' 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 ' , & ' \"README.md\" file is created but no directories or ' , & ' sample Fortran are 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 --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.' , & help_text_build_common ,& help_text_compiler , & help_text_flag , & ' --runner CMD A command to prefix the program execution paths with. ' , & ' see \"fpm help runner\" for further details. ' , & ' --list list candidate basenames instead of running them. Note they' , & ' --list will still be built if not currently up to date. ' , & ' -- ARGS optional arguments to pass to the test program(s). ' , & ' The same arguments are passed to all test names ' , & ' specified. ' , & ' ' , & help_text_environment , & ' ' , & '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' , & help_text_build_common ,& help_text_flag , & ' --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' , & '' , & help_text_environment , & '' , & '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' , & '' ] help_clean = [ character ( len = 80 ) :: & 'NAME' , & ' clean(1) - delete the build' , & '' , & 'SYNOPSIS' , & ' fpm clean' , & '' , & 'DESCRIPTION' , & ' Prompts the user to confirm deletion of the build. If affirmative,' , & ' directories in the build/ directory are deleted, except dependencies.' , & '' , & 'OPTIONS' , & ' --skip delete the build without prompting but skip dependencies.' , & ' --all delete the build without prompting including dependencies.' , & '' ] help_publish = [ character ( len = 80 ) :: & 'NAME' , & ' publish(1) - publish package to the registry' , & '' , & 'SYNOPSIS' , & ' fpm publish [--token TOKEN] [--show-package-version] [--show-upload-data]' , & ' [--dry-run] [--verbose] ' , & '' , & ' fpm publish --help|--version' , & '' , & 'DESCRIPTION' , & ' Follow the steps to create a tarball and upload a package to the registry:' , & '' , & ' 1. Register on the website (https://registry-frontend.vercel.app/).' , & ' 2. Create a namespace. Uploaded packages must be assigned to a unique' , & ' namespace to avoid conflicts among packages with similar names. A' , & ' namespace can accommodate multiple packages.' , & ' 3. Create a token for that namespace. A token is linked to your username' , & ' and is used to authenticate you during the upload process. Do not share' , & ' the token with others.' , & ' 4. Run fpm publish --token TOKEN to upload the package to the registry.' , & ' But be aware that the upload is permanent. An uploaded package cannot be' , & ' deleted.' , & '' , & ' See documentation for more information regarding package upload and usage:' , & '' , & ' Package upload:' , & ' https://fpm.fortran-lang.org/en/spec/publish.html' , & '' , & ' Package usage:' , & ' https://fpm.fortran-lang.org/en/spec/manifest.html#dependencies-from-a-registry' , & '' , & 'OPTIONS' , & ' --show-package-version show package version without publishing' , & ' --show-upload-data show upload data without publishing' , & ' --dry-run perform dry run without publishing' , & ' --help print this help and exit' , & ' --version print program version information and exit' , & ' --verbose print more information' , & '' , & 'EXAMPLES' , & '' , & ' fpm publish --show-package-version # show package version without publishing' , & ' fpm publish --show-upload-data # show upload data without publishing' , & ' fpm publish --token TOKEN --dry-run # perform dry run without publishing' , & ' fpm publish --token TOKEN # upload package to the registry' , & '' ] 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 !> Get an environment variable for fpm, this routine ensures that every variable !> used by fpm is prefixed with FPM_. function get_fpm_env ( env , default ) result ( val ) character ( len =* ), intent ( in ) :: env character ( len =* ), intent ( in ) :: default character ( len = :), allocatable :: val character ( len =* ), parameter :: fpm_prefix = \"FPM_\" val = get_env ( fpm_prefix // env , default ) end function get_fpm_env !> Build a full runner command (executable + command-line arguments) function runner_command ( cmd ) result ( run_cmd ) class ( fpm_run_settings ), intent ( in ) :: cmd character ( len = :), allocatable :: run_cmd !> Get executable if ( len_trim ( cmd % runner ) > 0 ) then run_cmd = trim ( cmd % runner ) else run_cmd = '' end if !> Append command-line arguments if ( len_trim ( cmd % runner_args ) > 0 ) run_cmd = run_cmd // ' ' // trim ( cmd % runner_args ) end function runner_command end module fpm_command_line","tags":"","loc":"sourcefile/fpm_command_line.f90.html"},{"title":"fpm_strings.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_strings Source Code fpm_strings.f90 Source Code !> This module defines general procedures for **string operations** for both CHARACTER and !! TYPE(STRING_T) variables ! !>## general routines for performing __string operations__ !! !!### Types !! - **TYPE(STRING_T)** define a type to contain strings of variable length !!### Type Conversions !! - [[F_STRING]] return Fortran **CHARACTER** variable when given a C-like array of !! single characters terminated with a C_NULL_CHAR **CHARACTER** !! - [[STR]] Converts **INTEGER** or** LOGICAL** to **CHARACTER** string !!### Case !! - [[LOWER]] Changes a string to lowercase over optional specified column range !!### Parsing and joining !! - [[SPLIT]] parse string on delimiter characters and store tokens into an allocatable array !! - [[STRING_CAT]] Concatenate an array of **type(string_t)** into a single **CHARACTER** variable !! - [[JOIN]] append an array of **CHARACTER** variables into a single **CHARACTER** variable !!### Testing !! - [[STR_ENDS_WITH]] test if a **CHARACTER** string or array ends with a specified suffix !! - [[STRING_ARRAY_CONTAINS]] Check if array of **TYPE(STRING_T)** matches a particular **CHARACTER** string !! - **OPERATOR(.IN.)** Check if array of **TYPE(STRING_T)** matches a particular **CHARACTER** string !! - [[GLOB]] function compares text strings, one of which can have wildcards ('*' or '?'). !! - [[IS_FORTRAN_NAME]] determine whether a string is an acceptable Fortran entity name !! - [[TO_FORTRAN_NAME]] replace allowed special but unusuable characters in names with underscore !!### Whitespace !! - [[NOTABS]] subroutine to expand tab characters assuming a tab space every eight characters !! - [[DILATE]] function to expand tab characters assuming a tab space every eight characters !! - [[LEN_TRIM]] Determine total trimmed length of **STRING_T** array !!### Miscellaneous !! - [[FNV_1A]] Hash a **CHARACTER(*)** string of default kind or a **TYPE(STRING_T)** array !! - [[REPLACE]] Returns string with characters in charset replaced with target_char. !! - [[RESIZE]] increase the size of a **TYPE(STRING_T)** array by N elements !! module fpm_strings use iso_fortran_env , only : int64 use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit use iso_c_binding , only : c_char , c_ptr , c_int , c_null_char , c_associated , c_f_pointer , c_size_t implicit none private public :: f_string , lower , split , str_ends_with , string_t , str_begins_with_str public :: to_fortran_name , is_fortran_name public :: string_array_contains , string_cat , len_trim , operator (. in .), fnv_1a public :: replace , resize , str , join , glob public :: notabs , dilate , remove_newline_characters , remove_characters_in_set !> Module naming public :: is_valid_module_name , is_valid_module_prefix , & has_valid_custom_prefix , has_valid_standard_prefix , & module_prefix_template , module_prefix_type type string_t character ( len = :), allocatable :: s end type interface len_trim module procedure :: string_len_trim module procedure :: strings_len_trim end interface len_trim interface resize module procedure :: resize_string end interface interface operator (. in .) module procedure string_array_contains end interface interface fnv_1a procedure :: fnv_1a_char procedure :: fnv_1a_string_t end interface fnv_1a interface str_ends_with procedure :: str_ends_with_str procedure :: str_ends_with_any end interface str_ends_with interface str module procedure str_int , str_int64 , str_logical end interface interface string_t module procedure new_string_t end interface string_t interface f_string module procedure f_string , f_string_cptr , f_string_cptr_n end interface f_string contains !> test if a CHARACTER string ends with a specified suffix pure logical function str_ends_with_str ( s , e ) result ( r ) character ( * ), intent ( in ) :: s , e integer :: n1 , n2 n1 = len ( s ) - len ( e ) + 1 n2 = len ( s ) if ( n1 < 1 ) then r = . false . else r = ( s ( n1 : n2 ) == e ) end if end function str_ends_with_str !> test if a CHARACTER string ends with any of an array of suffixs pure logical function str_ends_with_any ( s , e ) result ( r ) character ( * ), intent ( in ) :: s character ( * ), intent ( in ) :: e (:) integer :: i r = . true . do i = 1 , size ( e ) if ( str_ends_with ( s , trim ( e ( i )))) return end do r = . false . end function str_ends_with_any !> test if a CHARACTER string begins with a specified prefix pure logical function str_begins_with_str ( s , e , case_sensitive ) result ( r ) character ( * ), intent ( in ) :: s , e logical , optional , intent ( in ) :: case_sensitive ! Default option: case sensitive integer :: n1 , n2 logical :: lower_case ! Check if case sensitive if ( present ( case_sensitive )) then lower_case = . not . case_sensitive else lower_case = . false . end if n1 = 1 n2 = 1 + len ( e ) - 1 if ( n2 > len ( s )) then r = . false . elseif ( lower_case ) then r = lower ( s ( n1 : n2 )) == lower ( e ) else r = ( s ( n1 : n2 ) == e ) end if end function str_begins_with_str !> return Fortran character variable when given a C-like array of !! single characters terminated with a C_NULL_CHAR character function f_string ( c_string ) use iso_c_binding character ( len = 1 ), intent ( in ) :: c_string (:) character (:), allocatable :: f_string integer :: i , n i = 0 do while ( c_string ( i + 1 ) /= C_NULL_CHAR ) i = i + 1 end do n = i allocate ( character ( n ) :: f_string ) do i = 1 , n f_string ( i : i ) = c_string ( i ) end do end function f_string !> return Fortran character variable when given a null-terminated c_ptr function f_string_cptr ( cptr ) result ( s ) type ( c_ptr ), intent ( in ), value :: cptr character ( len = :, kind = c_char ), allocatable :: s interface function c_strlen ( s ) result ( r ) bind ( c , name = \"strlen\" ) import c_size_t , c_ptr type ( c_ptr ), intent ( in ), value :: s integer ( kind = c_size_t ) :: r end function end interface s = f_string_cptr_n ( cptr , c_strlen ( cptr )) end function !> return Fortran character variable when given a null-terminated c_ptr and its length function f_string_cptr_n ( cptr , n ) result ( s ) type ( c_ptr ), intent ( in ), value :: cptr integer ( kind = c_size_t ), intent ( in ) :: n character ( len = n , kind = c_char ) :: s character ( len = n , kind = c_char ), pointer :: sptr call c_f_pointer ( cptr , sptr ) s = sptr end function !> Hash a character(*) string of default kind pure function fnv_1a_char ( input , seed ) result ( hash ) character ( * ), intent ( in ) :: input integer ( int64 ), intent ( in ), optional :: seed integer ( int64 ) :: hash integer :: i integer ( int64 ), parameter :: FNV_OFFSET_32 = 2166136261_int64 integer ( int64 ), parameter :: FNV_PRIME_32 = 16777619_int64 if ( present ( seed )) then hash = seed else hash = FNV_OFFSET_32 end if do i = 1 , len ( input ) hash = ieor ( hash , iachar ( input ( i : i ), int64 )) * FNV_PRIME_32 end do end function fnv_1a_char !> Hash a string_t array of default kind pure function fnv_1a_string_t ( input , seed ) result ( hash ) type ( string_t ), intent ( in ) :: input (:) integer ( int64 ), intent ( in ), optional :: seed integer ( int64 ) :: hash integer :: i hash = fnv_1a ( input ( 1 )% s , seed ) do i = 2 , size ( input ) hash = fnv_1a ( input ( i )% s , hash ) end do end function fnv_1a_string_t !>Author: John S. Urban !!License: Public Domain !! Changes a string to lowercase over optional specified column range elemental pure function lower ( str , begin , end ) result ( string ) character ( * ), intent ( In ) :: str character ( len ( str )) :: string integer , intent ( in ), optional :: begin , end integer :: i integer :: ibegin , iend string = str ibegin = 1 if ( present ( begin )) then ibegin = max ( ibegin , begin ) endif iend = len_trim ( str ) if ( present ( end )) then iend = min ( iend , end ) endif do i = ibegin , iend ! step thru each letter in the string in specified range select case ( str ( i : i )) case ( 'A' : 'Z' ) string ( i : i ) = char ( iachar ( str ( i : i )) + 32 ) ! change letter to miniscule case default end select end do end function lower !> Helper function to generate a new string_t instance !> (Required due to the allocatable component) function new_string_t ( s ) result ( string ) character ( * ), intent ( in ) :: s type ( string_t ) :: string string % s = s end function new_string_t !> Check if array of TYPE(STRING_T) matches a particular CHARACTER string !! logical function string_array_contains ( search_string , array ) character ( * ), intent ( in ) :: search_string type ( string_t ), intent ( in ) :: array (:) integer :: i string_array_contains = any ([( array ( i )% s == search_string , & i = 1 , size ( array ))]) end function string_array_contains !> Concatenate an array of type(string_t) into !> a single CHARACTER variable function string_cat ( strings , delim ) result ( cat ) type ( string_t ), intent ( in ) :: strings (:) character ( * ), intent ( in ), optional :: delim character (:), allocatable :: cat integer :: i character (:), allocatable :: delim_str if ( size ( strings ) < 1 ) then cat = '' return end if if ( present ( delim )) then delim_str = delim else delim_str = '' end if cat = strings ( 1 )% s do i = 2 , size ( strings ) cat = cat // delim_str // strings ( i )% s end do end function string_cat !> Determine total trimmed length of `string_t` array pure function strings_len_trim ( strings ) result ( n ) type ( string_t ), intent ( in ) :: strings (:) integer :: i , n n = 0 do i = 1 , size ( strings ) n = n + len_trim ( strings ( i )% s ) end do end function strings_len_trim !> Determine total trimmed length of `string_t` array elemental integer function string_len_trim ( string ) result ( n ) type ( string_t ), intent ( in ) :: string if ( allocated ( string % s )) then n = len_trim ( string % s ) else n = 0 end if end function string_len_trim !>Author: John S. Urban !!License: Public Domain !! parse string on delimiter characters and store tokens into an allocatable array subroutine split ( input_line , array , delimiters , order , nulls ) !! given a line of structure \" par1 par2 par3 ... parn \" store each par(n) into a separate variable in array. !! !! * by default adjacent delimiters in the input string do not create an empty string in the output array !! * no quoting of delimiters is supported character ( len =* ), intent ( in ) :: input_line !! input string to tokenize character ( len =* ), optional , intent ( in ) :: delimiters !! list of delimiter characters character ( len =* ), optional , intent ( in ) :: order !! order of output array sequential|[reverse|right] character ( len =* ), optional , intent ( in ) :: nulls !! return strings composed of delimiters or not ignore|return|ignoreend character ( len = :), allocatable , intent ( out ) :: array (:) !! output array of tokens integer :: n ! max number of strings INPUT_LINE could split into if all delimiter integer , allocatable :: ibegin (:) ! positions in input string where tokens start integer , allocatable :: iterm (:) ! positions in input string where tokens end character ( len = :), allocatable :: dlim ! string containing delimiter characters character ( len = :), allocatable :: ordr ! string containing order keyword character ( len = :), allocatable :: nlls ! string containing nulls keyword integer :: ii , iiii ! loop parameters used to control print order integer :: icount ! number of tokens found integer :: ilen ! length of input string with trailing spaces trimmed integer :: i10 , i20 , i30 ! loop counters integer :: icol ! pointer into input string as it is being parsed integer :: idlim ! number of delimiter characters integer :: ifound ! where next delimiter character is found in remaining input string data integer :: inotnull ! count strings not composed of delimiters integer :: ireturn ! number of tokens returned integer :: imax ! length of longest token ! decide on value for optional DELIMITERS parameter if ( present ( delimiters )) then ! optional delimiter list was present if ( delimiters /= '' ) then ! if DELIMITERS was specified and not null use it dlim = delimiters else ! DELIMITERS was specified on call as empty string dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif else ! no delimiter value was specified dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif idlim = len ( dlim ) ! dlim a lot of blanks on some machines if dlim is a big string if ( present ( order )) then ; ordr = lower ( adjustl ( order )); else ; ordr = 'sequential' ; endif ! decide on value for optional ORDER parameter if ( present ( nulls )) then ; nlls = lower ( adjustl ( nulls )); else ; nlls = 'ignore' ; endif ! optional parameter n = len ( input_line ) + 1 ! max number of strings INPUT_LINE could split into if all delimiter allocate ( ibegin ( n )) ! allocate enough space to hold starting location of tokens if string all tokens allocate ( iterm ( n )) ! allocate enough space to hold ending location of tokens if string all tokens ibegin (:) = 1 iterm (:) = 1 ilen = len ( input_line ) ! ILEN is the column position of the last non-blank character icount = 0 ! how many tokens found inotnull = 0 ! how many tokens found not composed of delimiters imax = 0 ! length of longest token found select case ( ilen ) case ( 0 ) ! command was totally blank case default ! there is at least one non-delimiter in INPUT_LINE if get here icol = 1 ! initialize pointer into input line INFINITE : do i30 = 1 , ilen , 1 ! store into each array element ibegin ( i30 ) = icol ! assume start new token on the character if ( index ( dlim ( 1 : idlim ), input_line ( icol : icol )) == 0 ) then ! if current character is not a delimiter iterm ( i30 ) = ilen ! initially assume no more tokens do i10 = 1 , idlim ! search for next delimiter ifound = index ( input_line ( ibegin ( i30 ): ilen ), dlim ( i10 : i10 )) IF ( ifound > 0 ) then iterm ( i30 ) = min ( iterm ( i30 ), ifound + ibegin ( i30 ) - 2 ) endif enddo icol = iterm ( i30 ) + 2 ! next place to look as found end of this token inotnull = inotnull + 1 ! increment count of number of tokens not composed of delimiters else ! character is a delimiter for a null string iterm ( i30 ) = icol - 1 ! record assumed end of string. Will be less than beginning icol = icol + 1 ! advance pointer into input string endif imax = max ( imax , iterm ( i30 ) - ibegin ( i30 ) + 1 ) icount = i30 ! increment count of number of tokens found if ( icol > ilen ) then ! no text left exit INFINITE endif enddo INFINITE end select select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) ireturn = inotnull case default ireturn = icount end select allocate ( character ( len = imax ) :: array ( ireturn )) ! allocate the array to return !allocate(array(ireturn)) ! allocate the array to turn select case ( trim ( adjustl ( ordr ))) ! decide which order to store tokens case ( 'reverse' , 'right' ) ; ii = ireturn ; iiii =- 1 ! last to first case default ; ii = 1 ; iiii = 1 ! first to last end select do i20 = 1 , icount ! fill the array with the tokens that were found if ( iterm ( i20 ) < ibegin ( i20 )) then select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) case default array ( ii ) = ' ' ii = ii + iiii end select else array ( ii ) = input_line ( ibegin ( i20 ): iterm ( i20 )) ii = ii + iiii endif enddo end subroutine split !> Returns string with characters in charset replaced with target_char. pure function replace ( string , charset , target_char ) result ( res ) character ( * ), intent ( in ) :: string character , intent ( in ) :: charset (:), target_char character ( len ( string )) :: res integer :: n res = string do n = 1 , len ( string ) if ( any ( string ( n : n ) == charset )) then res ( n : n ) = target_char end if end do end function replace !> increase the size of a TYPE(STRING_T) array by N elements subroutine resize_string ( list , n ) !> Instance of the array to be resized type ( string_t ), allocatable , intent ( inout ) :: list (:) !> Dimension of the final array size integer , intent ( in ), optional :: n type ( string_t ), allocatable :: tmp (:) integer :: this_size , new_size , i integer , parameter :: initial_size = 16 if ( allocated ( list )) then this_size = size ( list , 1 ) call move_alloc ( list , tmp ) else this_size = initial_size end if if ( present ( n )) then new_size = n else new_size = this_size + this_size / 2 + 1 end if allocate ( list ( new_size )) if ( allocated ( tmp )) then this_size = min ( size ( tmp , 1 ), size ( list , 1 )) do i = 1 , this_size call move_alloc ( tmp ( i )% s , list ( i )% s ) end do deallocate ( tmp ) end if end subroutine resize_string !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!##NAME !! join(3f) - [M_strings:EDITING] append CHARACTER variable array into !! a single CHARACTER variable with specified separator !! (LICENSE:PD) !! !!##SYNOPSIS !! !! pure function join(str,sep,trm,left,right,start,end) result (string) !! !! character(len=*),intent(in) :: str(:) !! character(len=*),intent(in),optional :: sep !! logical,intent(in),optional :: trm !! character(len=*),intent(in),optional :: right !! character(len=*),intent(in),optional :: left !! character(len=*),intent(in),optional :: start !! character(len=*),intent(in),optional :: end !! character(len=:),allocatable :: string !! !!##DESCRIPTION !! JOIN(3f) appends the elements of a CHARACTER array into a single !! CHARACTER variable, with elements 1 to N joined from left to right. !! By default each element is trimmed of trailing spaces and the !! default separator is a null string. !! !!##OPTIONS !! STR(:) array of CHARACTER variables to be joined !! SEP separator string to place between each variable. defaults !! to a null string. !! LEFT string to place at left of each element !! RIGHT string to place at right of each element !! START prefix string !! END suffix string !! TRM option to trim each element of STR of trailing !! spaces. Defaults to .TRUE. !! !!##RESULT !! STRING CHARACTER variable composed of all of the elements of STR() !! appended together with the optional separator SEP placed !! between the elements. !! !!##EXAMPLE !! !! Sample program: !! !! program demo_join !! use M_strings, only: join !! implicit none !! character(len=:),allocatable :: s(:) !! character(len=:),allocatable :: out !! integer :: i !! s=[character(len=10) :: 'United',' we',' stand,', & !! & ' divided',' we fall.'] !! out=join(s) !! write(*,'(a)') out !! write(*,'(a)') join(s,trm=.false.) !! write(*,'(a)') (join(s,trm=.false.,sep='|'),i=1,3) !! write(*,'(a)') join(s,sep='<>') !! write(*,'(a)') join(s,sep=';',left='[',right=']') !! write(*,'(a)') join(s,left='[',right=']') !! write(*,'(a)') join(s,left='>>') !! end program demo_join !! !! Expected output: !! !! United we stand, divided we fall. !! United we stand, divided we fall. !! United | we | stand, | divided | we fall. !! United | we | stand, | divided | we fall. !! United | we | stand, | divided | we fall. !! United<> we<> stand,<> divided<> we fall. !! [United];[ we];[ stand,];[ divided];[ we fall.] !! [United][ we][ stand,][ divided][ we fall.] !! >>United>> we>> stand,>> divided>> we fall. pure function join ( str , sep , trm , left , right , start , end ) result ( string ) ! @(#)M_strings::join(3f): merge string array into a single CHARACTER value adding specified separators, caps, prefix and suffix character ( len =* ), intent ( in ) :: str (:) character ( len =* ), intent ( in ), optional :: sep , right , left , start , end logical , intent ( in ), optional :: trm character ( len = :), allocatable :: sep_local , left_local , right_local character ( len = :), allocatable :: string logical :: trm_local integer :: i if ( present ( sep )) then ; sep_local = sep ; else ; sep_local = '' ; endif if ( present ( trm )) then ; trm_local = trm ; else ; trm_local = . true . ; endif if ( present ( left )) then ; left_local = left ; else ; left_local = '' ; endif if ( present ( right )) then ; right_local = right ; else ; right_local = '' ; endif string = '' if ( size ( str ) == 0 ) then string = string // left_local // right_local else do i = 1 , size ( str ) - 1 if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local // sep_local else string = string // left_local // str ( i ) // right_local // sep_local endif enddo if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local else string = string // left_local // str ( i ) // right_local endif endif if ( present ( start )) string = start // string if ( present ( end )) string = string // end end function join !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!## NAME !! glob(3f) - [fpm_strings:COMPARE] compare given string for match to !! pattern which may contain wildcard characters !! (LICENSE:PD) !! !!## SYNOPSIS !! !! logical function glob(string, pattern ) !! !! character(len=*),intent(in) :: string !! character(len=*),intent(in) :: pattern !! !!## DESCRIPTION !! glob(3f) compares given STRING for match to PATTERN which may !! contain wildcard characters. !! !! In this version to get a match the entire string must be described !! by PATTERN. Trailing whitespace is significant, so trim the input !! string to have trailing whitespace ignored. !! !!## OPTIONS !! string the input string to test to see if it contains the pattern. !! pattern the following simple globbing options are available !! !! o \"?\" matching any one character !! o \"*\" matching zero or more characters. !! Do NOT use adjacent asterisks. !! o Both strings may have trailing spaces which !! are ignored. !! o There is no escape character, so matching strings with !! literal question mark and asterisk is problematic. !! !!## EXAMPLES !! !! Example program !! !! program demo_glob !! implicit none !! ! This main() routine passes a bunch of test strings !! ! into the above code. In performance comparison mode, !! ! it does that over and over. Otherwise, it does it just !! ! once. Either way, it outputs a passed/failed result. !! ! !! integer :: nReps !! logical :: allpassed !! integer :: i !! allpassed = .true. !! !! nReps = 10000 !! ! Can choose as many repetitions as you're expecting !! ! in the real world. !! nReps = 1 !! !! do i=1,nReps !! ! Cases with repeating character sequences. !! allpassed=allpassed .and. test(\"a*abab\", \"a*b\", .true.) !! !!cycle !! allpassed=allpassed .and. test(\"ab\", \"*?\", .true.) !! allpassed=allpassed .and. test(\"abc\", \"*?\", .true.) !! allpassed=allpassed .and. test(\"abcccd\", \"*ccd\", .true.) !! allpassed=allpassed .and. test(\"bLah\", \"bLaH\", .false.) !! allpassed=allpassed .and. test(\"mississippi\", \"*sip*\", .true.) !! allpassed=allpassed .and. & !! & test(\"xxxx*zzzzzzzzy*f\", \"xxx*zzy*f\", .true.) !! allpassed=allpassed .and. & !! & test(\"xxxx*zzzzzzzzy*f\", \"xxxx*zzy*fffff\", .false.) !! allpassed=allpassed .and. & !! & test(\"mississipissippi\", \"*issip*ss*\", .true.) !! allpassed=allpassed .and. & !! & test(\"xxxxzzzzzzzzyf\", \"xxxx*zzy*fffff\", .false.) !! allpassed=allpassed .and. & !! & test(\"xxxxzzzzzzzzyf\", \"xxxx*zzy*f\", .true.) !! allpassed=allpassed .and. test(\"xyxyxyzyxyz\", \"xy*z*xyz\", .true.) !! allpassed=allpassed .and. test(\"xyxyxyxyz\", \"xy*xyz\", .true.) !! allpassed=allpassed .and. test(\"mississippi\", \"mi*sip*\", .true.) !! allpassed=allpassed .and. test(\"ababac\", \"*abac*\", .true.) !! allpassed=allpassed .and. test(\"aaazz\", \"a*zz*\", .true.) !! allpassed=allpassed .and. test(\"a12b12\", \"*12*23\", .false.) !! allpassed=allpassed .and. test(\"a12b12\", \"a12b\", .false.) !! allpassed=allpassed .and. test(\"a12b12\", \"*12*12*\", .true.) !! !! ! Additional cases where the '*' char appears in the tame string. !! allpassed=allpassed .and. test(\"*\", \"*\", .true.) !! allpassed=allpassed .and. test(\"a*r\", \"a*\", .true.) !! allpassed=allpassed .and. test(\"a*ar\", \"a*aar\", .false.) !! !! ! More double wildcard scenarios. !! allpassed=allpassed .and. test(\"XYXYXYZYXYz\", \"XY*Z*XYz\", .true.) !! allpassed=allpassed .and. test(\"missisSIPpi\", \"*SIP*\", .true.) !! allpassed=allpassed .and. test(\"mississipPI\", \"*issip*PI\", .true.) !! allpassed=allpassed .and. test(\"xyxyxyxyz\", \"xy*xyz\", .true.) !! allpassed=allpassed .and. test(\"miSsissippi\", \"mi*sip*\", .true.) !! allpassed=allpassed .and. test(\"miSsissippi\", \"mi*Sip*\", .false.) !! allpassed=allpassed .and. test(\"abAbac\", \"*Abac*\", .true.) !! allpassed=allpassed .and. test(\"aAazz\", \"a*zz*\", .true.) !! allpassed=allpassed .and. test(\"A12b12\", \"*12*23\", .false.) !! allpassed=allpassed .and. test(\"a12B12\", \"*12*12*\", .true.) !! allpassed=allpassed .and. test(\"oWn\", \"*oWn*\", .true.) !! !! ! Completely tame (no wildcards) cases. !! allpassed=allpassed .and. test(\"bLah\", \"bLah\", .true.) !! !! ! Simple mixed wildcard tests suggested by IBMer Marlin Deckert. !! allpassed=allpassed .and. test(\"a\", \"*?\", .true.) !! !! ! More mixed wildcard tests including coverage for false positives. !! allpassed=allpassed .and. test(\"a\", \"??\", .false.) !! allpassed=allpassed .and. test(\"ab\", \"?*?\", .true.) !! allpassed=allpassed .and. test(\"ab\", \"*?*?*\", .true.) !! allpassed=allpassed .and. test(\"abc\", \"?**?*?\", .true.) !! allpassed=allpassed .and. test(\"abc\", \"?**?*&?\", .false.) !! allpassed=allpassed .and. test(\"abcd\", \"?b*??\", .true.) !! allpassed=allpassed .and. test(\"abcd\", \"?a*??\", .false.) !! allpassed=allpassed .and. test(\"abcd\", \"?**?c?\", .true.) !! allpassed=allpassed .and. test(\"abcd\", \"?**?d?\", .false.) !! allpassed=allpassed .and. test(\"abcde\", \"?*b*?*d*?\", .true.) !! !! ! Single-character-match cases. !! allpassed=allpassed .and. test(\"bLah\", \"bL?h\", .true.) !! allpassed=allpassed .and. test(\"bLaaa\", \"bLa?\", .false.) !! allpassed=allpassed .and. test(\"bLah\", \"bLa?\", .true.) !! allpassed=allpassed .and. test(\"bLaH\", \"?Lah\", .false.) !! allpassed=allpassed .and. test(\"bLaH\", \"?LaH\", .true.) !! !! ! Many-wildcard scenarios. !! allpassed=allpassed .and. test(& !! &\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa& !! &aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab\",& !! &\"a*a*a*a*a*a*aa*aaa*a*a*b\",& !! &.true.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacacac& !! &adaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*a*aa*aaa*fa*ga*b*\",& !! &.true.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacaca& !! &cadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*a*x*aaa*fa*ga*b*\",& !! &.false.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacacacad& !! &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*aaaa*fa*ga*gggg*b*\",& !! &.false.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacacacad& !! &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*aaaa*fa*ga*ggg*b*\",& !! &.true.) !! allpassed=allpassed .and. test(\"aaabbaabbaab\", \"*aabbaa*a*\", .true.) !! allpassed=allpassed .and. & !! test(\"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\",& !! &\"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\", .true.) !! allpassed=allpassed .and. test(\"aaaaaaaaaaaaaaaaa\",& !! &\"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\", .true.) !! allpassed=allpassed .and. test(\"aaaaaaaaaaaaaaaa\",& !! &\"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\", .false.) !! allpassed=allpassed .and. test(& !! &\"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& !! &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn\",& !! & \"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc& !! &*abc*abc*abc*\",& !! &.false.) !! allpassed=allpassed .and. test(& !! &\"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& !! &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn\",& !! &\"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*\",& !! &.true.) !! allpassed=allpassed .and. test(\"abc*abcd*abcd*abc*abcd\",& !! &\"abc*abc*abc*abc*abc\", .false.) !! allpassed=allpassed .and. test( \"abc*abcd*abcd*abc*abcd*abcd& !! &*abc*abcd*abc*abc*abcd\", & !! &\"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd\",& !! &.true.) !! allpassed=allpassed .and. test(\"abc\",& !! &\"********a********b********c********\", .true.) !! allpassed=allpassed .and.& !! &test(\"********a********b********c********\", \"abc\", .false.) !! allpassed=allpassed .and. & !! &test(\"abc\", \"********a********b********b********\", .false.) !! allpassed=allpassed .and. test(\"*abc*\", \"***a*b*c***\", .true.) !! !! ! A case-insensitive algorithm test. !! ! allpassed=allpassed .and. test(\"mississippi\", \"*issip*PI\", .true.) !! enddo !! !! if (allpassed)then !! write(*,'(a)')\"Passed\",nReps !! else !! write(*,'(a)')\"Failed\" !! endif !! contains !! ! This is a test program for wildcard matching routines. !! ! It can be used either to test a single routine for correctness, !! ! or to compare the timings of two (or more) different wildcard !! ! matching routines. !! ! !! function test(tame, wild, bExpectedResult) result(bpassed) !! use fpm_strings, only : glob !! character(len=*) :: tame !! character(len=*) :: wild !! logical :: bExpectedResult !! logical :: bResult !! logical :: bPassed !! bResult = .true. ! We'll do \"&=\" cumulative checking. !! bPassed = .false. ! Assume the worst. !! write(*,*)repeat('=',79) !! bResult = glob(tame, wild) ! Call a wildcard matching routine. !! !! ! To assist correctness checking, output the two strings in any !! ! failing scenarios. !! if (bExpectedResult .eqv. bResult) then !! bPassed = .true. !! if(nReps == 1) write(*,*)\"Passed match on \",tame,\" vs. \", wild !! else !! if(nReps == 1) write(*,*)\"Failed match on \",tame,\" vs. \", wild !! endif !! !! end function test !! end program demo_glob !! !! Expected output !! !! !!## REFERENCE !! The article \"Matching Wildcards: An Empirical Way to Tame an Algorithm\" !! in Dr Dobb's Journal, By Kirk J. Krauss, October 07, 2014 !! function glob ( tame , wild ) ! @(#)fpm_strings::glob(3f): function compares text strings, one of which can have wildcards ('*' or '?'). logical :: glob !! result of test character ( len =* ) :: tame !! A string without wildcards to compare to the globbing expression character ( len =* ) :: wild !! A (potentially) corresponding string with wildcards character ( len = len ( tame ) + 1 ) :: tametext character ( len = len ( wild ) + 1 ) :: wildtext character ( len = 1 ), parameter :: NULL = char ( 0 ) integer :: wlen integer :: ti , wi integer :: i character ( len = :), allocatable :: tbookmark , wbookmark ! These two values are set when we observe a wildcard character. They ! represent the locations, in the two strings, from which we start once we've observed it. tametext = tame // NULL wildtext = wild // NULL tbookmark = NULL wbookmark = NULL wlen = len ( wild ) wi = 1 ti = 1 do ! Walk the text strings one character at a time. if ( wildtext ( wi : wi ) == '*' ) then ! How do you match a unique text string? do i = wi , wlen ! Easy: unique up on it! if ( wildtext ( wi : wi ) == '*' ) then wi = wi + 1 else exit endif enddo if ( wildtext ( wi : wi ) == NULL ) then ! \"x\" matches \"*\" glob = . true . return endif if ( wildtext ( wi : wi ) /= '?' ) then ! Fast-forward to next possible match. do while ( tametext ( ti : ti ) /= wildtext ( wi : wi )) ti = ti + 1 if ( tametext ( ti : ti ) == NULL ) then glob = . false . return ! \"x\" doesn't match \"*y*\" endif enddo endif wbookmark = wildtext ( wi :) tbookmark = tametext ( ti :) elseif ( tametext ( ti : ti ) /= wildtext ( wi : wi ) . and . wildtext ( wi : wi ) /= '?' ) then ! Got a non-match. If we've set our bookmarks, back up to one or both of them and retry. if ( wbookmark /= NULL ) then if ( wildtext ( wi :) /= wbookmark ) then wildtext = wbookmark ; wlen = len_trim ( wbookmark ) wi = 1 ! Don't go this far back again. if ( tametext ( ti : ti ) /= wildtext ( wi : wi )) then tbookmark = tbookmark ( 2 :) tametext = tbookmark ti = 1 cycle ! \"xy\" matches \"*y\" else wi = wi + 1 endif endif if ( tametext ( ti : ti ) /= NULL ) then ti = ti + 1 cycle ! \"mississippi\" matches \"*sip*\" endif endif glob = . false . return ! \"xy\" doesn't match \"x\" endif ti = ti + 1 wi = wi + 1 if ( tametext ( ti : ti ) == NULL ) then ! How do you match a tame text string? if ( wildtext ( wi : wi ) /= NULL ) then do while ( wildtext ( wi : wi ) == '*' ) ! The tame way: unique up on it! wi = wi + 1 ! \"x\" matches \"x*\" if ( wildtext ( wi : wi ) == NULL ) exit enddo endif if ( wildtext ( wi : wi ) == NULL ) then glob = . true . return ! \"x\" matches \"x\" endif glob = . false . return ! \"x\" doesn't match \"xy\" endif enddo end function glob !> Returns the length of the string representation of 'i' pure integer function str_int_len ( i ) result ( sz ) integer , intent ( in ) :: i integer , parameter :: MAX_STR = 100 character ( MAX_STR ) :: s ! If 's' is too short (MAX_STR too small), Fortran will abort with: ! \"Fortran runtime error: End of record\" write ( s , '(i0)' ) i sz = len_trim ( s ) end function !> Converts integer \"i\" to string pure function str_int ( i ) result ( s ) integer , intent ( in ) :: i character ( len = str_int_len ( i )) :: s write ( s , '(i0)' ) i end function !> Returns the length of the string representation of 'i' pure integer function str_int64_len ( i ) result ( sz ) integer ( int64 ), intent ( in ) :: i integer , parameter :: MAX_STR = 100 character ( MAX_STR ) :: s ! If 's' is too short (MAX_STR too small), Fortran will abort with: ! \"Fortran runtime error: End of record\" write ( s , '(i0)' ) i sz = len_trim ( s ) end function !> Converts integer \"i\" to string pure function str_int64 ( i ) result ( s ) integer ( int64 ), intent ( in ) :: i character ( len = str_int64_len ( i )) :: s write ( s , '(i0)' ) i end function !> Returns the length of the string representation of 'l' pure integer function str_logical_len ( l ) result ( sz ) logical , intent ( in ) :: l if ( l ) then sz = 6 else sz = 7 end if end function !> Converts logical \"l\" to string pure function str_logical ( l ) result ( s ) logical , intent ( in ) :: l character ( len = str_logical_len ( l )) :: s if ( l ) then s = \".true.\" else s = \".false.\" end if end function !> Returns string with special characters replaced with an underscore. !! For now, only a hyphen is treated as a special character, but this can be !! expanded to other characters if needed. pure function to_fortran_name ( string ) result ( res ) character ( * ), intent ( in ) :: string character ( len ( string )) :: res character , parameter :: SPECIAL_CHARACTERS ( * ) = [ '-' ] res = replace ( string , SPECIAL_CHARACTERS , '_' ) end function to_fortran_name elemental 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 ) /= 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 !> Check that a module name fits the current naming rules: !> 1) It must be a valid FORTRAN name (<=63 chars, begin with letter, \"_\" is only allowed non-alphanumeric) !> 2) It must begin with the package name !> 3) If longer, package name must be followed by default separator plus at least one char logical function is_valid_module_name ( module_name , package_name , custom_prefix , enforce_module_names ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name type ( string_t ), intent ( in ) :: custom_prefix logical , intent ( in ) :: enforce_module_names !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ); if (. not . valid ) return !> FPM package enforcing: check that the module name begins with the package name if ( enforce_module_names ) then ! Default prefixing is always valid valid = has_valid_standard_prefix ( module_name , package_name ) ! If a custom prefix was validated, it provides additional naming options ! Because they never overlap with the default prefix, the former is always an option if ( len_trim ( custom_prefix ) > 0 . and . . not . valid ) & valid = has_valid_custom_prefix ( module_name , custom_prefix ) end if end function is_valid_module_name !> Check that a custom module prefix fits the current naming rules: !> 1) Only alphanumeric characters (no spaces, dashes, underscores or other characters) !> 2) Does not begin with a number (Fortran-compatible syntax) logical function is_valid_module_prefix ( module_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_prefix character ( len =* ), parameter :: num = '0123456789' character ( len =* ), parameter :: lower = 'abcdefghijklmnopqrstuvwxyz' character ( len =* ), parameter :: upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' character ( len =* ), parameter :: alpha = upper // lower character ( len =* ), parameter :: allowed = alpha // num character ( len = :), allocatable :: name name = trim ( module_prefix % s ) if ( len ( name ) > 0 . and . len ( name ) <= 63 ) then valid = verify ( name ( 1 : 1 ), alpha ) == 0 . and . & verify ( name , allowed ) == 0 else valid = . false . endif end function is_valid_module_prefix type ( string_t ) function module_prefix_template ( project_name , custom_prefix ) result ( prefix ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then prefix = string_t ( trim ( custom_prefix % s ) // \"_\" ) else prefix = string_t ( to_fortran_name ( project_name % s ) // \"__\" ) end if end function module_prefix_template type ( string_t ) function module_prefix_type ( project_name , custom_prefix ) result ( ptype ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then ptype = string_t ( \"custom\" ) else ptype = string_t ( \"default\" ) end if end function module_prefix_type !> Check that a module name is prefixed with a custom prefix: !> 1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed) !> 2) It must begin with the prefix !> 3) If longer, package name must be followed by default separator (\"_\") plus at least one char logical function has_valid_custom_prefix ( module_name , custom_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: custom_prefix !> custom_module separator: single underscore character ( * ), parameter :: SEP = \"_\" logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check that both names are individually valid valid = is_fortran_name ( module_name % s ) . and . & is_valid_module_prefix ( custom_prefix ) !> FPM package enforcing: check that the module name begins with the custom prefix if ( valid ) then !> Query string lengths lpkg = len_trim ( custom_prefix ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , custom_prefix % s , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator )) end if end function has_valid_custom_prefix !> Check that a module name is prefixed with the default package prefix: !> 1) It must be a valid FORTRAN name (<=63 chars, begin with letter, \"_\" is only allowed non-alphanumeric) !> 2) It must begin with the package name !> 3) If longer, package name must be followed by default separator plus at least one char logical function has_valid_standard_prefix ( module_name , package_name ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name !> Default package__module separator: two underscores character ( * ), parameter :: SEP = \"__\" character ( len = :), allocatable :: fortranized_pkg logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ) !> FPM package enforcing: check that the module name begins with the package name if ( valid ) then fortranized_pkg = to_fortran_name ( package_name % s ) !> Query string lengths lpkg = len_trim ( fortranized_pkg ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , fortranized_pkg , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = is_fortran_name ( fortranized_pkg ) . and . & fortranized_pkg ( lpkg : lpkg ) /= '_' . and . & ( same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator ))) end if end function has_valid_standard_prefix ! Remove all characters from a set from a string subroutine remove_characters_in_set ( string , set , replace_with ) character ( len = :), allocatable , intent ( inout ) :: string character ( * ), intent ( in ) :: set character , optional , intent ( in ) :: replace_with ! Replace with this character instead of removing integer :: feed , length if (. not . allocated ( string )) return if ( len ( set ) <= 0 ) return length = len ( string ) feed = scan ( string , set ) do while ( length > 0 . and . feed > 0 ) ! Remove heading if ( length == 1 ) then string = \"\" elseif ( feed == 1 ) then string = string ( 2 : length ) ! Remove trailing elseif ( feed == length ) then string = string ( 1 : length - 1 ) ! In between: replace with given character elseif ( present ( replace_with )) then string ( feed : feed ) = replace_with ! Or just remove else string = string ( 1 : feed - 1 ) // string ( feed + 1 : length ) end if length = len ( string ) feed = scan ( string , set ) end do end subroutine remove_characters_in_set ! Remove all new line characters from the current string, replace them with spaces subroutine remove_newline_characters ( string ) type ( string_t ), intent ( inout ) :: string integer :: feed , length character ( * ), parameter :: CRLF = new_line ( 'a' ) // achar ( 13 ) character ( * ), parameter :: SPACE = ' ' call remove_characters_in_set ( string % s , set = CRLF , replace_with = SPACE ) end subroutine remove_newline_characters !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!### NAME !! notabs(3f) - [fpm_strings:NONALPHA] expand tab characters !! (LICENSE:PD) !! !!### SYNOPSIS !! !! subroutine notabs(INSTR,OUTSTR,ILEN) !! !! character(len=*),intent=(in) :: INSTR !! character(len=*),intent=(out) :: OUTSTR !! integer,intent=(out) :: ILEN !! !!### DESCRIPTION !! NOTABS() converts tabs in INSTR to spaces in OUTSTR while maintaining !! columns. It assumes a tab is set every 8 characters. Trailing spaces !! are removed. !! !! In addition, trailing carriage returns and line feeds are removed !! (they are usually a problem created by going to and from MSWindows). !! !! What are some reasons for removing tab characters from an input line? !! Some Fortran compilers have problems with tabs, as tabs are not !! part of the Fortran character set. Some editors and printers will !! have problems with tabs. It is often useful to expand tabs in input !! files to simplify further processing such as tokenizing an input line. !! !!### OPTIONS !! instr Input line to remove tabs from !! !!### RESULTS !! outstr Output string with tabs expanded. Assumed to be of sufficient !! length !! ilen Significant length of returned string !! !!### EXAMPLES !! !! Sample program: !! !! program demo_notabs !! !! ! test filter to remove tabs and trailing white space from input !! ! on files up to 1024 characters wide !! use fpm_strings, only : notabs !! character(len=1024) :: in,out !! integer :: ios,iout !! do !! read(*,'(A)',iostat=ios)in !! if(ios /= 0) exit !! call notabs(in,out,iout) !! write(*,'(a)')out(:iout) !! enddo !! end program demo_notabs !! !!### SEE ALSO !! GNU/Unix commands expand(1) and unexpand(1) !! elemental impure subroutine notabs ( instr , outstr , ilen ) ! ident_31=\"@(#)fpm_strings::notabs(3f): convert tabs to spaces while maintaining columns, remove CRLF chars\" character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len =* ), intent ( out ) :: outstr ! tab-expanded version of INSTR produced integer , intent ( out ) :: ilen ! column position of last character put into output string ! that is, ILEN holds the position of the last non-blank character in OUTSTR integer , parameter :: tabsize = 8 ! assume a tab stop is set every 8th column integer :: ipos ! position in OUTSTR to put next character of INSTR integer :: lenin ! length of input string trimmed of trailing spaces integer :: lenout ! number of characters output string can hold integer :: istep ! counter that advances thru input string INSTR one character at a time character ( len = 1 ) :: c ! character in input line being processed integer :: iade ! ADE (ASCII Decimal Equivalent) of character being tested ipos = 1 ! where to put next character in output string OUTSTR lenin = len_trim ( instr ( 1 : len ( instr ) )) ! length of INSTR trimmed of trailing spaces lenout = len ( outstr ) ! number of characters output string OUTSTR can hold outstr = \" \" ! this SHOULD blank-fill string, a buggy machine required a loop to set all characters SCAN_LINE : do istep = 1 , lenin ! look through input string one character at a time c = instr ( istep : istep ) ! get next character iade = ichar ( c ) ! get ADE of the character EXPAND_TABS : select case ( iade ) ! take different actions depending on which character was found case ( 9 ) ! test if character is a tab and move pointer out to appropriate column ipos = ipos + ( tabsize - ( mod ( ipos - 1 , tabsize ))) case ( 10 , 13 ) ! convert carriage-return and new-line to space ,typically to handle DOS-format files ipos = ipos + 1 case default ! c is anything else other than a tab,newline,or return insert it in output string if ( ipos > lenout ) then write ( stderr , * ) \"*notabs* output string overflow\" exit else outstr ( ipos : ipos ) = c ipos = ipos + 1 endif end select EXPAND_TABS enddo SCAN_LINE ipos = min ( ipos , lenout ) ! tabs or newline or return characters or last character might have gone too far ilen = len_trim ( outstr (: ipos )) ! trim trailing spaces end subroutine notabs !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!##NAME !! dilate(3f) - [M_strings:NONALPHA] expand tab characters !! (LICENSE:PD) !! !!##SYNOPSIS !! !! function dilate(INSTR) result(OUTSTR) !! !! character(len=*),intent=(in) :: INSTR !! character(len=:),allocatable :: OUTSTR !! !!##DESCRIPTION !! dilate() converts tabs in INSTR to spaces in OUTSTR. It assumes a !! tab is set every 8 characters. Trailing spaces are removed. !! !! In addition, trailing carriage returns and line feeds are removed !! (they are usually a problem created by going to and from MSWindows). !! !!##OPTIONS !! instr Input line to remove tabs from !! !!##RESULTS !! outstr Output string with tabs expanded. !! !!##EXAMPLES !! !! Sample program: !! !! program demo_dilate !! !! use M_strings, only : dilate !! implicit none !! character(len=:),allocatable :: in !! integer :: i !! in=' this is my string ' !! ! change spaces to tabs to make a sample input !! do i=1,len(in) !! if(in(i:i) == ' ')in(i:i)=char(9) !! enddo !! write(*,'(a)')in,dilate(in) !! end program demo_dilate !! function dilate ( instr ) result ( outstr ) character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len = :), allocatable :: outstr ! tab-expanded version of INSTR produced integer :: i integer :: icount integer :: lgth icount = 0 do i = 1 , len ( instr ) if ( instr ( i : i ) == char ( 9 )) icount = icount + 1 end do allocate ( character ( len = ( len ( instr ) + 8 * icount )) :: outstr ) call notabs ( instr , outstr , lgth ) outstr = outstr (: lgth ) end function dilate end module fpm_strings","tags":"","loc":"sourcefile/fpm_strings.f90.html"},{"title":"versioning.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_versioning Source Code versioning.f90 Source Code !> Implementation of versioning data for comparing packages module fpm_versioning use fpm_error , only : error_t , syntax_error use fpm_strings , only : string_t use regex_module , only : regex implicit none private public :: version_t , new_version public :: regex_version_from_text type :: version_t private !> Version numbers found integer , allocatable :: num (:) contains generic :: operator ( == ) => equals procedure , private :: equals generic :: operator ( /= ) => not_equals procedure , private :: not_equals generic :: operator ( > ) => greater procedure , private :: greater generic :: operator ( < ) => less procedure , private :: less generic :: operator ( >= ) => greater_equals procedure , private :: greater_equals generic :: operator ( <= ) => less_equals procedure , private :: less_equals !> Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) generic :: operator (. match .) => match procedure , private :: match !> Create a printable string from a version data type procedure :: s end type version_t !> Arbitrary internal limit of the version parser integer , parameter :: max_limit = 3 interface new_version module procedure :: new_version_from_string module procedure :: new_version_from_int end interface new_version contains !> Create a new version from a string subroutine new_version_from_int ( self , num ) !> Instance of the versioning data type ( version_t ), intent ( out ) :: self !> Subversion numbers to define version data integer , intent ( in ) :: num (:) self % num = num end subroutine new_version_from_int !> Create a new version from a string subroutine new_version_from_string ( self , string , error ) !> Instance of the versioning data type ( version_t ), intent ( out ) :: self !> String describing the version information character ( len =* ), intent ( in ) :: string !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: istart , iend , stat , nn integer :: num ( max_limit ) logical :: is_number nn = 0 iend = 0 istart = 0 is_number = . false . do while ( iend < len ( string )) call next ( string , istart , iend , is_number , error ) if ( allocated ( error )) exit if ( is_number ) then if ( nn >= max_limit ) then call token_error ( error , string , istart , iend , & & \"Too many subversions found\" ) exit end if nn = nn + 1 read ( string ( istart : iend ), * , iostat = stat ) num ( nn ) if ( stat /= 0 ) then call token_error ( error , string , istart , iend , & & \"Failed to parse version number\" ) exit end if end if end do if ( allocated ( error )) return if (. not . is_number ) then call token_error ( error , string , istart , iend , & & \"Expected version number, but no characters are left\" ) return end if call new_version ( self , num (: nn )) end subroutine new_version_from_string !> Tokenize a version string subroutine next ( string , istart , iend , is_number , error ) !> String describing the version information character ( len =* ), intent ( in ) :: string !> Start of last token, start of next token on exit integer , intent ( inout ) :: istart !> End of last token on entry, end of next token on exit integer , intent ( inout ) :: iend !> Token produced is a number logical , intent ( inout ) :: is_number !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii , nn logical :: was_number character :: tok was_number = is_number nn = len ( string ) if ( iend >= nn ) then istart = nn iend = nn return end if ii = min ( iend + 1 , nn ) tok = string ( ii : ii ) is_number = tok /= '.' if ( is_number . eqv . was_number ) then call token_error ( error , string , istart , ii , & & \"Unexpected token found\" ) return end if if (. not . is_number ) then is_number = . false . istart = ii iend = ii return end if istart = ii do ii = min ( iend + 1 , nn ), nn tok = string ( ii : ii ) select case ( tok ) case default call token_error ( error , string , istart , ii , & & \"Invalid character in version number\" ) exit case ( '.' ) exit case ( '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ) iend = ii cycle end select end do end subroutine next !> Create an error on an invalid token, provide some visual context as well subroutine token_error ( error , string , istart , iend , message ) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> String describing the version information character ( len =* ), intent ( in ) :: string !> Start of last token, start of next token on exit integer , intent ( in ) :: istart !> End of last token on entry, end of next token on exit integer , intent ( in ) :: iend !> Error message character ( len =* ), intent ( in ) :: message character ( len =* ), parameter :: nl = new_line ( 'a' ) allocate ( error ) error % message = message // nl // \" | \" // string // nl // & & \" |\" // repeat ( '-' , istart ) // repeat ( '^' , iend - istart + 1 ) end subroutine token_error pure function s ( self ) result ( string ) !> Version number class ( version_t ), intent ( in ) :: self !> Character representation of the version character ( len = :), allocatable :: string integer , parameter :: buffersize = 64 character ( len = buffersize ) :: buffer integer :: ii do ii = 1 , size ( self % num ) if ( allocated ( string )) then write ( buffer , '(\".\", i0)' ) self % num ( ii ) string = string // trim ( buffer ) else write ( buffer , '(i0)' ) self % num ( ii ) string = trim ( buffer ) end if end do if (. not . allocated ( string )) then string = '0' end if end function s !> Check to version numbers for equality elemental function equals ( lhs , rhs ) result ( is_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> Version match logical :: is_equal is_equal = . not .( lhs > rhs ) if ( is_equal ) then is_equal = . not .( rhs > lhs ) end if end function equals !> Check two versions for inequality elemental function not_equals ( lhs , rhs ) result ( not_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> Version mismatch logical :: not_equal not_equal = lhs > rhs if (. not . not_equal ) then not_equal = rhs > lhs end if end function not_equals !> Relative comparison of two versions elemental function greater ( lhs , rhs ) result ( is_greater ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is greater logical :: is_greater integer :: ii do ii = 1 , min ( size ( lhs % num ), size ( rhs % num )) if ( lhs % num ( ii ) /= rhs % num ( ii )) then is_greater = lhs % num ( ii ) > rhs % num ( ii ) return end if end do is_greater = size ( lhs % num ) > size ( rhs % num ) if ( is_greater ) then do ii = size ( rhs % num ) + 1 , size ( lhs % num ) is_greater = lhs % num ( ii ) > 0 if ( is_greater ) return end do end if end function greater !> Relative comparison of two versions elemental function less ( lhs , rhs ) result ( is_less ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is less logical :: is_less is_less = rhs > lhs end function less !> Relative comparison of two versions elemental function greater_equals ( lhs , rhs ) result ( is_greater_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is greater or equal logical :: is_greater_equal is_greater_equal = . not . ( rhs > lhs ) end function greater_equals !> Relative comparison of two versions elemental function less_equals ( lhs , rhs ) result ( is_less_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is less or equal logical :: is_less_equal is_less_equal = . not . ( lhs > rhs ) end function less_equals !> Try to match first version against second version elemental function match ( lhs , rhs ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> Version match following semantic versioning rules logical :: match type ( version_t ) :: tmp match = . not .( rhs > lhs ) if ( match ) then tmp % num = rhs % num tmp % num ( size ( tmp % num )) = tmp % num ( size ( tmp % num )) + 1 match = tmp > lhs end if end function match ! Extract canonical version flags \"1.0.0\" or \"1.0\" as the first instance inside a text ! (whatever long) using regex type ( string_t ) function regex_version_from_text ( text , what , error ) result ( ver ) character ( * ), intent ( in ) :: text character ( * ), intent ( in ) :: what type ( error_t ), allocatable , intent ( out ) :: error integer :: ire , length if ( len_trim ( text ) <= 0 ) then call syntax_error ( error , 'cannot retrieve ' // what // ' version: empty input string' ) return end if ! Extract 3-sized version \"1.0.4\" ire = regex ( text , '\\d+\\.\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ! Parse version into the object (this should always work) ver = string_t ( text ( ire : ire + length - 1 )) else ! Try 2-sized version \"1.0\" ire = regex ( text , '\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ver = string_t ( text ( ire : ire + length - 1 )) else call syntax_error ( error , 'cannot retrieve ' // what // ' version.' ) end if end if end function regex_version_from_text end module fpm_versioning","tags":"","loc":"sourcefile/versioning.f90.html"},{"title":"git.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_git Source Code git.f90 Source Code !> Implementation for interacting with git repositories. module fpm_git use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : get_temp_filename , getline , join_path , execute_and_read_output , run implicit none public :: git_target_t , git_target_default , git_target_branch , git_target_tag , git_target_revision , git_revision , & & git_archive , git_matches_manifest , operator ( == ), compressed_package_name !> Name of the compressed package that is generated temporarily. character ( len =* ), parameter :: compressed_package_name = 'compressed_package' !> Possible git target type :: enum_descriptor !> Default target integer :: default = 200 !> Branch in git repository integer :: branch = 201 !> Tag in git repository integer :: tag = 202 !> Commit hash integer :: revision = 203 end type enum_descriptor !> Actual enumerator for descriptors type ( enum_descriptor ), parameter :: git_descriptor = enum_descriptor () !> Description of an git target type :: git_target_t !> Kind of the git target integer :: descriptor = git_descriptor % default !> Target URL of the git repository character ( len = :), allocatable :: url !> Additional descriptor of the git object character ( len = :), allocatable :: object contains !> Fetch and checkout in local directory procedure :: checkout !> Show information on instance procedure :: info end type git_target_t interface operator ( == ) module procedure git_target_eq end interface !> Common output format for writing to the command line character ( len =* ), parameter :: out_fmt = '(\"#\", *(1x, g0))' contains !> Default target function git_target_default ( url ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % default self % url = url end function git_target_default !> Target a branch in the git repository function git_target_branch ( url , branch ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Name of the branch of interest character ( len =* ), intent ( in ) :: branch !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % branch self % url = url self % object = branch end function git_target_branch !> Target a specific git revision function git_target_revision ( url , sha1 ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Commit hash of interest character ( len =* ), intent ( in ) :: sha1 !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % revision self % url = url self % object = sha1 end function git_target_revision !> Target a git tag function git_target_tag ( url , tag ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Tag name of interest character ( len =* ), intent ( in ) :: tag !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % tag self % url = url self % object = tag end function git_target_tag !> Check that two git targets are equal logical function git_target_eq ( this , that ) result ( is_equal ) !> Two input git targets type ( git_target_t ), intent ( in ) :: this , that is_equal = this % descriptor == that % descriptor . and . & this % url == that % url . and . & this % object == that % object end function git_target_eq !> Check that a cached dependency matches a manifest request logical function git_matches_manifest ( cached , manifest , verbosity , iunit ) !> Two input git targets type ( git_target_t ), intent ( in ) :: cached , manifest integer , intent ( in ) :: verbosity , iunit git_matches_manifest = cached % url == manifest % url if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT URL has changed: \" , cached % url , \" vs. \" , manifest % url return endif !> The manifest dependency only contains partial information (what's requested), !> while the cached dependency always stores a commit hash because it's built !> after the repo is available (saved as git_descriptor%revision==revision). !> So, comparing against the descriptor is not reliable git_matches_manifest = allocated ( cached % object ) . eqv . allocated ( manifest % object ) if ( git_matches_manifest . and . allocated ( cached % object )) & git_matches_manifest = cached % object == manifest % object if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT OBJECT has changed: \" , cached % object , \" vs. \" , manifest % object end if end function git_matches_manifest subroutine checkout ( self , local_path , error ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character ( len = :), allocatable :: object , workdir if ( allocated ( self % object )) then object = self % object else object = 'HEAD' end if workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) call execute_command_line ( \"git init \" // local_path , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while initiating git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" fetch --depth=1 \" // & self % url // \" \" // object , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while fetching git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" checkout -qf FETCH_HEAD\" , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while checking out git repository for remote dependency' ) return end if end subroutine checkout subroutine git_revision ( local_path , object , error ) !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Git object reference character ( len = :), allocatable , intent ( out ) :: object !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , unit , istart , iend character ( len = :), allocatable :: temp_file , line , iomsg , workdir character ( len =* ), parameter :: hexdigits = '0123456789abcdef' workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) allocate ( temp_file , source = get_temp_filename ()) line = \"git \" // workdir // \" log -n 1 > \" // temp_file call execute_command_line ( line , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error while retrieving commit information\" ) return end if open ( file = temp_file , newunit = unit ) call getline ( unit , line , stat , iomsg ) if ( stat /= 0 ) then call fatal_error ( error , iomsg ) return end if close ( unit , status = \"delete\" ) ! Tokenize: ! commit 0123456789abcdef (HEAD, ...) istart = scan ( line , ' ' ) + 1 iend = verify ( line ( istart :), hexdigits ) + istart - 1 if ( iend < istart ) iend = len ( line ) object = line ( istart : iend ) end subroutine git_revision !> Show information on git target subroutine info ( self , unit , verbosity ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Git target\" if ( allocated ( self % url )) then write ( unit , fmt ) \"- URL\" , self % url end if if ( allocated ( self % object )) then select case ( self % descriptor ) case default write ( unit , fmt ) \"- object\" , self % object case ( git_descriptor % tag ) write ( unit , fmt ) \"- tag\" , self % object case ( git_descriptor % branch ) write ( unit , fmt ) \"- branch\" , self % object case ( git_descriptor % revision ) write ( unit , fmt ) \"- sha1\" , self % object end select end if end subroutine info !> Archive a folder using `git archive`. subroutine git_archive ( source , destination , ref , verbose , error ) !> Directory to archive. character ( * ), intent ( in ) :: source !> Destination of the archive. character ( * ), intent ( in ) :: destination !> (Symbolic) Reference to be archived. character ( * ), intent ( in ) :: ref !> Print additional information if true. logical , intent ( in ) :: verbose !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character ( len = :), allocatable :: cmd_output , archive_format call execute_and_read_output ( 'git archive -l' , cmd_output , error , verbose ) if ( allocated ( error )) return if ( index ( cmd_output , 'tar.gz' ) /= 0 ) then archive_format = 'tar.gz' else call fatal_error ( error , \"Cannot find a suitable archive format for 'git archive'.\" ); return end if call run ( 'git archive ' // ref // ' --format=' // archive_format // ' -o ' // destination , echo = verbose , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error packing '\" // source // \"'.\" ); return end if end end module fpm_git","tags":"","loc":"sourcefile/git.f90.html"},{"title":"dependency.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_dependency Source Code dependency.f90 Source Code !> # Dependency management !> !> ## Fetching dependencies and creating a dependency tree !> !> Dependencies on the top-level can be specified from: !> !> - `package%dependencies` !> - `package%dev_dependencies` !> - `package%executable(:)%dependencies` !> - `package%test(:)%dependencies` !> !> Each dependency is fetched in some way and provides a path to its package !> manifest. !> The `package%dependencies` of the dependencies are resolved recursively. !> !> To initialize the dependency tree all dependencies are recursively fetched !> and stored in a flat data structure to avoid retrieving a package twice. !> The data structure used to store this information should describe the current !> status of the dependency tree. Important information are: !> !> - name of the package !> - version of the package !> - path to the package root !> !> Additionally, for version controlled dependencies the following should be !> stored along with the package: !> !> - the upstream url !> - the current checked out revision !> !> Fetching a remote (version controlled) dependency turns it for our purpose !> into a local path dependency which is handled by the same means. !> !> ## Updating dependencies !> !> For a given dependency tree all top-level dependencies can be updated. !> We have two cases to consider, a remote dependency and a local dependency, !> again, remote dependencies turn into local dependencies by fetching. !> Therefore we will update remote dependencies by simply refetching them. !> !> For remote dependencies we have to refetch if the revision in the manifest !> changes or the upstream HEAD has changed (for branches _and_ tags). !> !> @Note For our purpose a tag is just a fancy branch name. Tags can be delete and !> modified afterwards, therefore they do not differ too much from branches !> from our perspective. !> !> For the latter case we only know if we actually fetch from the upstream URL. !> !> In case of local (and fetched remote) dependencies we have to read the package !> manifest and compare its dependencies against our dependency tree, any change !> requires updating the respective dependencies as well. !> !> ## Handling dependency compatibilties !> !> Currenly ignored. First come, first serve. module fpm_dependency use , intrinsic :: iso_fortran_env , only : output_unit use fpm_environment , only : get_os_type , OS_WINDOWS , os_is_unix use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : exists , join_path , mkdir , canon_path , windows_path , list_files , is_dir , basename , & os_delete_dir , get_temp_filename use fpm_git , only : git_target_revision , git_target_default , git_revision , operator ( == ) use fpm_manifest , only : package_config_t , dependency_config_t , get_package_data use fpm_manifest_dependency , only : manifest_has_changed use fpm_manifest_preprocess , only : operator ( == ) use fpm_strings , only : string_t , operator (. in .) use fpm_toml , only : toml_table , toml_key , toml_error , toml_serialize , & get_value , set_value , add_table , toml_load , toml_stat use fpm_versioning , only : version_t , new_version use fpm_settings , only : fpm_global_settings , get_global_settings , official_registry_base_url use fpm_downloader , only : downloader_t use jonquil , only : json_object use fpm_strings , only : str implicit none private public :: dependency_tree_t , new_dependency_tree , dependency_node_t , new_dependency_node , resize , & & check_and_read_pkg_data !> Overloaded reallocation interface interface resize module procedure :: resize_dependency_node end interface resize !> Dependency node in the projects dependency tree type , extends ( dependency_config_t ) :: dependency_node_t !> Actual version of this dependency type ( version_t ), allocatable :: version !> Installation prefix of this dependencies character ( len = :), allocatable :: proj_dir !> Checked out revision of the version control system character ( len = :), allocatable :: revision !> Dependency is handled logical :: done = . false . !> Dependency should be updated logical :: update = . false . !> Dependency was loaded from a cache logical :: cached = . false . contains !> Update dependency from project manifest. procedure :: register !> Get dependency from the registry. procedure :: get_from_registry procedure , private :: get_from_local_registry !> Print information on this instance procedure :: info end type dependency_node_t !> Respresentation of a projects dependencies !> !> The dependencies are stored in a simple array for now, this can be replaced !> with a binary-search tree or a hash table in the future. type :: dependency_tree_t !> Unit for IO integer :: unit = output_unit !> Verbosity of printout integer :: verbosity = 1 !> Installation prefix for dependencies character ( len = :), allocatable :: dep_dir !> Number of currently registered dependencies integer :: ndep = 0 !> Flattend list of all dependencies type ( dependency_node_t ), allocatable :: dep (:) !> Cache file character ( len = :), allocatable :: cache contains !> Overload procedure to add new dependencies to the tree generic :: add => add_project , add_project_dependencies , add_dependencies , & add_dependency , add_dependency_node !> Main entry point to add a project procedure , private :: add_project !> Add a project and its dependencies to the dependency tree procedure , private :: add_project_dependencies !> Add a list of dependencies to the dependency tree procedure , private :: add_dependencies !> Add a single dependency to the dependency tree procedure , private :: add_dependency !> Add a single dependency node to the dependency tree procedure , private :: add_dependency_node !> Resolve dependencies generic :: resolve => resolve_dependencies , resolve_dependency !> Resolve dependencies procedure , private :: resolve_dependencies !> Resolve dependency procedure , private :: resolve_dependency !> True if entity can be found generic :: has => has_dependency !> True if dependency is part of the tree procedure , private :: has_dependency !> Find a dependency in the tree generic :: find => find_name !> Find a dependency by its name procedure , private :: find_name !> Depedendncy resolution finished procedure :: finished !> Reading of dependency tree generic :: load => load_from_file , load_from_unit , load_from_toml !> Read dependency tree from file procedure , private :: load_from_file !> Read dependency tree from formatted unit procedure , private :: load_from_unit !> Read dependency tree from TOML data structure procedure , private :: load_from_toml !> Writing of dependency tree generic :: dump => dump_to_file , dump_to_unit , dump_to_toml !> Write dependency tree to file procedure , private :: dump_to_file !> Write dependency tree to formatted unit procedure , private :: dump_to_unit !> Write dependency tree to TOML data structure procedure , private :: dump_to_toml !> Update dependency tree generic :: update => update_dependency , update_tree !> Update a list of dependencies procedure , private :: update_dependency !> Update all dependencies in the tree procedure , private :: update_tree end type dependency_tree_t !> Common output format for writing to the command line character ( len =* ), parameter :: out_fmt = '(\"#\", *(1x, g0))' contains !> Create a new dependency tree subroutine new_dependency_tree ( self , verbosity , cache ) !> Instance of the dependency tree type ( dependency_tree_t ), intent ( out ) :: self !> Verbosity of printout integer , intent ( in ), optional :: verbosity !> Name of the cache file character ( len =* ), intent ( in ), optional :: cache call resize ( self % dep ) self % dep_dir = join_path ( \"build\" , \"dependencies\" ) if ( present ( verbosity )) self % verbosity = verbosity if ( present ( cache )) self % cache = cache end subroutine new_dependency_tree !> Create a new dependency node from a configuration subroutine new_dependency_node ( self , dependency , version , proj_dir , update ) !> Instance of the dependency node type ( dependency_node_t ), intent ( out ) :: self !> Dependency configuration data type ( dependency_config_t ), intent ( in ) :: dependency !> Version of the dependency type ( version_t ), intent ( in ), optional :: version !> Installation prefix of the dependency character ( len =* ), intent ( in ), optional :: proj_dir !> Dependency should be updated logical , intent ( in ), optional :: update self % dependency_config_t = dependency if ( present ( version )) then self % version = version end if if ( present ( proj_dir )) then self % proj_dir = proj_dir end if if ( present ( update )) then self % update = update end if end subroutine new_dependency_node !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the dependency configuration class ( dependency_node_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if !> Call base object info call self % dependency_config_t % info ( unit , pr ) if ( allocated ( self % version )) then write ( unit , fmt ) \"- version\" , self % version % s () end if if ( allocated ( self % proj_dir )) then write ( unit , fmt ) \"- dir\" , self % proj_dir end if if ( allocated ( self % revision )) then write ( unit , fmt ) \"- revision\" , self % revision end if write ( unit , fmt ) \"- done\" , merge ( 'YES' , 'NO ' , self % done ) write ( unit , fmt ) \"- update\" , merge ( 'YES' , 'NO ' , self % update ) end subroutine info !> Add project dependencies, each depth level after each other. !> !> We implement this algorithm in an interative rather than a recursive fashion !> as a choice of design. subroutine add_project ( self , package , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Project configuration to add type ( package_config_t ), intent ( in ) :: package !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( dependency_config_t ) :: dependency type ( dependency_tree_t ) :: cached character ( len =* ), parameter :: root = '.' integer :: id if (. not . exists ( self % dep_dir )) then call mkdir ( self % dep_dir ) end if ! Create this project as the first dependency node (depth 0) dependency % name = package % name dependency % path = root call self % add ( dependency , error ) if ( allocated ( error )) return ! Resolve the root project call self % resolve ( root , error ) if ( allocated ( error )) return ! Add the root project dependencies (depth 1) call self % add ( package , root , . true ., error ) if ( allocated ( error )) return ! After resolving all dependencies, check if we have cached ones to avoid updates if ( allocated ( self % cache )) then call new_dependency_tree ( cached , verbosity = self % verbosity , cache = self % cache ) call cached % load ( self % cache , error ) if ( allocated ( error )) return ! Skip root node do id = 2 , cached % ndep cached % dep ( id )% cached = . true . call self % add ( cached % dep ( id ), error ) if ( allocated ( error )) return end do end if ! Now decent into the dependency tree, level for level do while (. not . self % finished ()) call self % resolve ( root , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return if ( allocated ( self % cache )) then call self % dump ( self % cache , error ) if ( allocated ( error )) return end if end subroutine add_project !> Add a project and its dependencies to the dependency tree recursive subroutine add_project_dependencies ( self , package , root , main , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Project configuration to add type ( package_config_t ), intent ( in ) :: package !> Current project root directory character ( len =* ), intent ( in ) :: root !> Is the main project logical , intent ( in ) :: main !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii if ( allocated ( package % dependency )) then call self % add ( package % dependency , error ) if ( allocated ( error )) return end if if ( main ) then if ( allocated ( package % dev_dependency )) then call self % add ( package % dev_dependency , error ) if ( allocated ( error )) return end if if ( allocated ( package % executable )) then do ii = 1 , size ( package % executable ) if ( allocated ( package % executable ( ii )% dependency )) then call self % add ( package % executable ( ii )% dependency , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end if if ( allocated ( package % example )) then do ii = 1 , size ( package % example ) if ( allocated ( package % example ( ii )% dependency )) then call self % add ( package % example ( ii )% dependency , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end if if ( allocated ( package % test )) then do ii = 1 , size ( package % test ) if ( allocated ( package % test ( ii )% dependency )) then call self % add ( package % test ( ii )% dependency , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end if end if end subroutine add_project_dependencies !> Add a list of dependencies to the dependency tree subroutine add_dependencies ( self , dependency , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_config_t ), intent ( in ) :: dependency (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii , ndep ndep = size ( self % dep ) if ( ndep < size ( dependency ) + self % ndep ) then call resize ( self % dep , ndep + ndep / 2 + size ( dependency )) end if do ii = 1 , size ( dependency ) call self % add ( dependency ( ii ), error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end subroutine add_dependencies !> Add a single dependency node to the dependency tree !> Dependency nodes contain additional information (version, git, revision) subroutine add_dependency_node ( self , dependency , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_node_t ), intent ( in ) :: dependency !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: id if ( self % has_dependency ( dependency )) then ! A dependency with this same name is already in the dependency tree. ! Check if it needs to be updated id = self % find ( dependency % name ) ! If this dependency was in the cache, and we're now requesting a different version ! in the manifest, ensure it is marked for update. Otherwise, if we're just querying ! the same dependency from a lower branch of the dependency tree, the existing one from ! the manifest has priority if ( dependency % cached ) then if ( dependency_has_changed ( dependency , self % dep ( id ), self % verbosity , self % unit )) then if ( self % verbosity > 0 ) write ( self % unit , out_fmt ) \"Dependency change detected:\" , dependency % name self % dep ( id )% update = . true . else ! Store the cached one self % dep ( id ) = dependency self % dep ( id )% update = . false . end if end if else ! New dependency: add from scratch self % ndep = self % ndep + 1 self % dep ( self % ndep ) = dependency self % dep ( self % ndep )% update = . false . end if end subroutine add_dependency_node !> Add a single dependency to the dependency tree subroutine add_dependency ( self , dependency , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_config_t ), intent ( in ) :: dependency !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( dependency_node_t ) :: node call new_dependency_node ( node , dependency ) call add_dependency_node ( self , node , error ) end subroutine add_dependency !> Update dependency tree subroutine update_dependency ( self , name , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Name of the dependency to update character ( len =* ), intent ( in ) :: name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: id character ( len = :), allocatable :: proj_dir , root id = self % find ( name ) root = \".\" if ( id <= 0 ) then call fatal_error ( error , \"Cannot update dependency '\" // name // \"'\" ) return end if associate ( dep => self % dep ( id )) if ( allocated ( dep % git ) . and . dep % update ) then if ( self % verbosity > 0 ) write ( self % unit , out_fmt ) \"Update:\" , dep % name proj_dir = join_path ( self % dep_dir , dep % name ) call dep % git % checkout ( proj_dir , error ) if ( allocated ( error )) return ! Unset dependency and remove updatable attribute dep % done = . false . dep % update = . false . ! Now decent into the dependency tree, level for level do while (. not . self % finished ()) call self % resolve ( root , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end if end associate end subroutine update_dependency !> Update whole dependency tree subroutine update_tree ( self , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i ! Update dependencies where needed do i = 1 , self % ndep call self % update ( self % dep ( i )% name , error ) if ( allocated ( error )) return end do end subroutine update_tree !> Resolve all dependencies in the tree subroutine resolve_dependencies ( self , root , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Current installation prefix character ( len =* ), intent ( in ) :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( fpm_global_settings ) :: global_settings integer :: ii call get_global_settings ( global_settings , error ) if ( allocated ( error )) return do ii = 1 , self % ndep call self % resolve ( self % dep ( ii ), global_settings , root , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end subroutine resolve_dependencies !> Resolve a single dependency node subroutine resolve_dependency ( self , dependency , global_settings , root , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_node_t ), intent ( inout ) :: dependency !> Global configuration settings. type ( fpm_global_settings ), intent ( in ) :: global_settings !> Current installation prefix character ( len =* ), intent ( in ) :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( package_config_t ) :: package character ( len = :), allocatable :: manifest , proj_dir , revision logical :: fetch if ( dependency % done ) return fetch = . false . if ( allocated ( dependency % proj_dir )) then proj_dir = dependency % proj_dir else if ( allocated ( dependency % path )) then proj_dir = join_path ( root , dependency % path ) else if ( allocated ( dependency % git )) then proj_dir = join_path ( self % dep_dir , dependency % name ) fetch = . not . exists ( proj_dir ) if ( fetch ) then call dependency % git % checkout ( proj_dir , error ) if ( allocated ( error )) return end if else call dependency % get_from_registry ( proj_dir , global_settings , error ) if ( allocated ( error )) return end if if ( allocated ( dependency % git )) then call git_revision ( proj_dir , revision , error ) if ( allocated ( error )) return end if manifest = join_path ( proj_dir , \"fpm.toml\" ) call get_package_data ( package , manifest , error ) if ( allocated ( error )) return call dependency % register ( package , proj_dir , fetch , revision , error ) if ( allocated ( error )) return if ( self % verbosity > 1 ) then write ( self % unit , out_fmt ) & \"Dep:\" , dependency % name , \"version\" , dependency % version % s (), & \"at\" , dependency % proj_dir end if call self % add ( package , proj_dir , . false ., error ) if ( allocated ( error )) return end subroutine resolve_dependency !> Get a dependency from the registry. Whether the dependency is fetched !> from a local, a custom remote or the official registry is determined !> by the global configuration settings. subroutine get_from_registry ( self , target_dir , global_settings , error , downloader_ ) !> Instance of the dependency configuration. class ( dependency_node_t ), intent ( in ) :: self !> The target directory of the dependency. character (:), allocatable , intent ( out ) :: target_dir !> Global configuration settings. type ( fpm_global_settings ), intent ( in ) :: global_settings !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error !> Downloader instance. class ( downloader_t ), optional , intent ( in ) :: downloader_ character (:), allocatable :: cache_path , target_url , tmp_file type ( version_t ) :: version integer :: stat , unit type ( json_object ) :: json class ( downloader_t ), allocatable :: downloader if ( present ( downloader_ )) then downloader = downloader_ else allocate ( downloader ) end if ! Use local registry if it was specified in the global config file. if ( allocated ( global_settings % registry_settings % path )) then call self % get_from_local_registry ( target_dir , global_settings % registry_settings % path , error ); return end if ! Include namespace and package name in the cache path. cache_path = join_path ( global_settings % registry_settings % cache_path , self % namespace , self % name ) ! Check cache before downloading from the remote registry if a specific version was requested. When no specific ! version was requested, do network request first to check which is the newest version. if ( allocated ( self % requested_version )) then if ( exists ( join_path ( cache_path , self % requested_version % s (), 'fpm.toml' ))) then print * , \"Using cached version of '\" , join_path ( self % namespace , self % name , self % requested_version % s ()), \"'.\" target_dir = join_path ( cache_path , self % requested_version % s ()); return end if end if tmp_file = get_temp_filename () open ( newunit = unit , file = tmp_file , action = 'readwrite' , iostat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error creating temporary file for downloading package '\" // self % name // \"'.\" ); return end if ! Include namespace and package name in the target url and download package data. target_url = global_settings % registry_settings % url // '/packages/' // self % namespace // '/' // self % name call downloader % get_pkg_data ( target_url , self % requested_version , tmp_file , json , error ) close ( unit , status = 'delete' ) if ( allocated ( error )) return ! Verify package data and read relevant information. call check_and_read_pkg_data ( json , self , target_url , version , error ) if ( allocated ( error )) return ! Open new tmp file for downloading the actual package. open ( newunit = unit , file = tmp_file , action = 'readwrite' , iostat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error creating temporary file for downloading package '\" // self % name // \"'.\" ); return end if ! Include version number in the cache path. If no cached version exists, download it. cache_path = join_path ( cache_path , version % s ()) if (. not . exists ( join_path ( cache_path , 'fpm.toml' ))) then if ( is_dir ( cache_path )) call os_delete_dir ( os_is_unix (), cache_path ) call mkdir ( cache_path ) call downloader % get_file ( target_url , tmp_file , error ) if ( allocated ( error )) then close ( unit , status = 'delete' ); return end if ! Unpack the downloaded package to the final location. call downloader % unpack ( tmp_file , cache_path , error ) close ( unit , status = 'delete' ) if ( allocated ( error )) return end if target_dir = cache_path end subroutine get_from_registry subroutine check_and_read_pkg_data ( json , node , download_url , version , error ) type ( json_object ), intent ( inout ) :: json class ( dependency_node_t ), intent ( in ) :: node character (:), allocatable , intent ( out ) :: download_url type ( version_t ), intent ( out ) :: version type ( error_t ), allocatable , intent ( out ) :: error integer :: code , stat type ( json_object ), pointer :: p , q character (:), allocatable :: version_key , version_str , error_message , namespace , name namespace = \"\" name = \"UNNAMED_NODE\" if ( allocated ( node % namespace )) namespace = node % namespace if ( allocated ( node % name )) name = node % name if (. not . json % has_key ( 'code' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No status code.\" ); return end if call get_value ( json , 'code' , code , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': \" // & & \"Failed to read status code.\" ); return end if if ( code /= 200 ) then if (. not . json % has_key ( 'message' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No error message.\" ); return end if call get_value ( json , 'message' , error_message , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': \" // & & \"Failed to read error message.\" ); return end if call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"'. Status code: '\" // & & str ( code ) // \"'. Error message: '\" // error_message // \"'.\" ); return end if if (. not . json % has_key ( 'data' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No data.\" ); return end if call get_value ( json , 'data' , p , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to read package data for '\" // join_path ( namespace , name ) // \"'.\" ); return end if if ( allocated ( node % requested_version )) then version_key = 'version_data' else version_key = 'latest_version_data' end if if (. not . p % has_key ( version_key )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No version data.\" ); return end if call get_value ( p , version_key , q , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to retrieve version data for '\" // join_path ( namespace , name ) // \"'.\" ); return end if if (. not . q % has_key ( 'download_url' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No download url.\" ); return end if call get_value ( q , 'download_url' , download_url , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to read download url for '\" // join_path ( namespace , name ) // \"'.\" ); return end if download_url = official_registry_base_url // download_url if (. not . q % has_key ( 'version' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No version found.\" ); return end if call get_value ( q , 'version' , version_str , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to read version data for '\" // join_path ( namespace , name ) // \"'.\" ); return end if call new_version ( version , version_str , error ) if ( allocated ( error )) then call fatal_error ( error , \"'\" // version_str // \"' is not a valid version for '\" // & & join_path ( namespace , name ) // \"'.\" ); return end if end subroutine !> Get the dependency from a local registry. subroutine get_from_local_registry ( self , target_dir , registry_path , error ) !> Instance of the dependency configuration. class ( dependency_node_t ), intent ( in ) :: self !> The target directory to download the dependency to. character (:), allocatable , intent ( out ) :: target_dir !> The path to the local registry. character ( * ), intent ( in ) :: registry_path !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: path_to_name type ( string_t ), allocatable :: files (:) type ( version_t ), allocatable :: versions (:) type ( version_t ) :: version integer :: i path_to_name = join_path ( registry_path , self % namespace , self % name ) if (. not . exists ( path_to_name )) then call fatal_error ( error , \"Dependency resolution of '\" // self % name // & & \"': Directory '\" // path_to_name // \"' doesn't exist.\" ); return end if call list_files ( path_to_name , files ) if ( size ( files ) == 0 ) then call fatal_error ( error , \"No versions of '\" // self % name // \"' found in '\" // path_to_name // \"'.\" ); return end if ! Version requested, find it in the cache. if ( allocated ( self % requested_version )) then do i = 1 , size ( files ) ! Identify directory that matches the version number. if ( files ( i )% s == join_path ( path_to_name , self % requested_version % s ()) . and . is_dir ( files ( i )% s )) then if (. not . exists ( join_path ( files ( i )% s , 'fpm.toml' ))) then call fatal_error ( error , \"'\" // files ( i )% s // \"' is missing an 'fpm.toml' file.\" ); return end if target_dir = files ( i )% s ; return end if end do call fatal_error ( error , \"Version '\" // self % requested_version % s () // \"' not found in '\" // path_to_name // \"'\" ) return end if ! No specific version requested, therefore collect available versions. allocate ( versions ( 0 )) do i = 1 , size ( files ) if ( is_dir ( files ( i )% s )) then call new_version ( version , basename ( files ( i )% s ), error ) if ( allocated ( error )) return versions = [ versions , version ] end if end do if ( size ( versions ) == 0 ) then call fatal_error ( error , \"No versions found in '\" // path_to_name // \"'\" ); return end if ! Find the latest version. version = versions ( 1 ) do i = 1 , size ( versions ) if ( versions ( i ) > version ) version = versions ( i ) end do path_to_name = join_path ( path_to_name , version % s ()) if (. not . exists ( join_path ( path_to_name , 'fpm.toml' ))) then call fatal_error ( error , \"'\" // path_to_name // \"' is missing an 'fpm.toml' file.\" ); return end if target_dir = path_to_name end subroutine get_from_local_registry !> True if dependency is part of the tree pure logical function has_dependency ( self , dependency ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( in ) :: self !> Dependency configuration to check class ( dependency_node_t ), intent ( in ) :: dependency has_dependency = self % find ( dependency % name ) /= 0 end function has_dependency !> Find a dependency in the dependency tree pure function find_name ( self , name ) result ( pos ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( in ) :: self !> Dependency configuration to add character ( len =* ), intent ( in ) :: name !> Index of the dependency integer :: pos integer :: ii pos = 0 do ii = 1 , self % ndep if ( name == self % dep ( ii )% name ) then pos = ii exit end if end do end function find_name !> Check if we are done with the dependency resolution pure function finished ( self ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( in ) :: self !> All dependencies are updated logical :: finished finished = all ( self % dep (: self % ndep )% done ) end function finished !> Update dependency from project manifest subroutine register ( self , package , root , fetch , revision , error ) !> Instance of the dependency node class ( dependency_node_t ), intent ( inout ) :: self !> Package configuration data type ( package_config_t ), intent ( in ) :: package !> Project has been fetched logical , intent ( in ) :: fetch !> Root directory of the project character ( len =* ), intent ( in ) :: root !> Git revision of the project character ( len =* ), intent ( in ), optional :: revision !> Error handling type ( error_t ), allocatable , intent ( out ) :: error logical :: update update = . false . if ( self % name /= package % name ) then call fatal_error ( error , \"Dependency name '\" // package % name // & & \"' found, but expected '\" // self % name // \"' instead\" ) end if self % version = package % version self % proj_dir = root if ( allocated ( self % git ) . and . present ( revision )) then self % revision = revision if (. not . fetch ) then ! Change in revision ID was checked already. Only update if ALL git information is missing update = . not . allocated ( self % git % url ) end if end if if ( update ) self % update = update self % done = . true . end subroutine register !> Read dependency tree from file subroutine load_from_file ( self , file , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> File name character ( len =* ), intent ( in ) :: file !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: unit logical :: exist inquire ( file = file , exist = exist ) if (. not . exist ) return open ( file = file , newunit = unit ) call self % load ( unit , error ) close ( unit ) end subroutine load_from_file !> Read dependency tree from file subroutine load_from_unit ( self , unit , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> File name integer , intent ( in ) :: unit !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_error ), allocatable :: parse_error type ( toml_table ), allocatable :: table call toml_load ( table , unit , error = parse_error ) if ( allocated ( parse_error )) then allocate ( error ) call move_alloc ( parse_error % message , error % message ) return end if call self % load ( table , error ) if ( allocated ( error )) return end subroutine load_from_unit !> Read dependency tree from TOML data structure subroutine load_from_toml ( self , table , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ndep , ii logical :: is_unix character ( len = :), allocatable :: version , url , obj , rev , proj_dir type ( toml_key ), allocatable :: list (:) type ( toml_table ), pointer :: ptr call table % get_keys ( list ) ndep = size ( self % dep ) if ( ndep < size ( list ) + self % ndep ) then call resize ( self % dep , ndep + ndep / 2 + size ( list )) end if is_unix = get_os_type () /= OS_WINDOWS do ii = 1 , size ( list ) call get_value ( table , list ( ii )% key , ptr ) call get_value ( ptr , \"version\" , version ) call get_value ( ptr , \"proj-dir\" , proj_dir ) call get_value ( ptr , \"git\" , url ) call get_value ( ptr , \"obj\" , obj ) call get_value ( ptr , \"rev\" , rev ) if (. not . allocated ( proj_dir )) cycle self % ndep = self % ndep + 1 associate ( dep => self % dep ( self % ndep )) dep % name = list ( ii )% key if ( is_unix ) then dep % proj_dir = proj_dir else dep % proj_dir = windows_path ( proj_dir ) end if dep % done = . false . if ( allocated ( version )) then if (. not . allocated ( dep % version )) allocate ( dep % version ) call new_version ( dep % version , version , error ) if ( allocated ( error )) exit end if if ( allocated ( url )) then if ( allocated ( obj )) then dep % git = git_target_revision ( url , obj ) else dep % git = git_target_default ( url ) end if if ( allocated ( rev )) then dep % revision = rev end if else dep % path = proj_dir end if end associate end do if ( allocated ( error )) return self % ndep = size ( list ) end subroutine load_from_toml !> Write dependency tree to file subroutine dump_to_file ( self , file , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> File name character ( len =* ), intent ( in ) :: file !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: unit open ( file = file , newunit = unit ) call self % dump ( unit , error ) close ( unit ) if ( allocated ( error )) return end subroutine dump_to_file !> Write dependency tree to file subroutine dump_to_unit ( self , unit , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Formatted unit integer , intent ( in ) :: unit !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ) :: table table = toml_table () call self % dump ( table , error ) write ( unit , '(a)' ) toml_serialize ( table ) end subroutine dump_to_unit !> Write dependency tree to TOML datastructure subroutine dump_to_toml ( self , table , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii type ( toml_table ), pointer :: ptr character ( len = :), allocatable :: proj_dir do ii = 1 , self % ndep associate ( dep => self % dep ( ii )) call add_table ( table , dep % name , ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , \"Cannot create entry for \" // dep % name ) exit end if if ( allocated ( dep % version )) then call set_value ( ptr , \"version\" , dep % version % s ()) end if proj_dir = canon_path ( dep % proj_dir ) call set_value ( ptr , \"proj-dir\" , proj_dir ) if ( allocated ( dep % git )) then call set_value ( ptr , \"git\" , dep % git % url ) if ( allocated ( dep % git % object )) then call set_value ( ptr , \"obj\" , dep % git % object ) end if if ( allocated ( dep % revision )) then call set_value ( ptr , \"rev\" , dep % revision ) end if end if end associate end do if ( allocated ( error )) return end subroutine dump_to_toml !> Reallocate a list of dependencies pure subroutine resize_dependency_node ( var , n ) !> Instance of the array to be resized type ( dependency_node_t ), allocatable , intent ( inout ) :: var (:) !> Dimension of the final array size integer , intent ( in ), optional :: n type ( dependency_node_t ), allocatable :: tmp (:) integer :: this_size , new_size integer , parameter :: initial_size = 16 if ( allocated ( var )) then this_size = size ( var , 1 ) call move_alloc ( var , tmp ) else this_size = initial_size end if if ( present ( n )) then new_size = n else new_size = this_size + this_size / 2 + 1 end if allocate ( var ( new_size )) if ( allocated ( tmp )) then this_size = min ( size ( tmp , 1 ), size ( var , 1 )) var (: this_size ) = tmp (: this_size ) deallocate ( tmp ) end if end subroutine resize_dependency_node !> Check if a dependency node has changed logical function dependency_has_changed ( cached , manifest , verbosity , iunit ) result ( has_changed ) !> Two instances of the same dependency to be compared type ( dependency_node_t ), intent ( in ) :: cached , manifest !> Log verbosity integer , intent ( in ) :: verbosity , iunit integer :: ip has_changed = . true . !> All the following entities must be equal for the dependency to not have changed if ( manifest_has_changed ( cached = cached , manifest = manifest , verbosity = verbosity , iunit = iunit )) return !> For now, only perform the following checks if both are available. A dependency in cache.toml !> will always have this metadata; a dependency from fpm.toml which has not been fetched yet !> may not have it if ( allocated ( cached % version ) . and . allocated ( manifest % version )) then if ( cached % version /= manifest % version ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"VERSION has changed: \" // cached % version % s () // \" vs. \" // manifest % version % s () return end if else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"VERSION has changed presence \" end if if ( allocated ( cached % revision ) . and . allocated ( manifest % revision )) then if ( cached % revision /= manifest % revision ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"REVISION has changed: \" // cached % revision // \" vs. \" // manifest % revision return end if else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"REVISION has changed presence \" end if if ( allocated ( cached % proj_dir ) . and . allocated ( manifest % proj_dir )) then if ( cached % proj_dir /= manifest % proj_dir ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PROJECT DIR has changed: \" // cached % proj_dir // \" vs. \" // manifest % proj_dir return end if else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PROJECT DIR has changed presence \" end if if ( allocated ( cached % preprocess ) . eqv . allocated ( manifest % preprocess )) then if ( allocated ( cached % preprocess )) then if ( size ( cached % preprocess ) /= size ( manifest % preprocess )) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PREPROCESS has changed size\" return end if do ip = 1 , size ( cached % preprocess ) if (. not .( cached % preprocess ( ip ) == manifest % preprocess ( ip ))) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PREPROCESS config has changed\" return end if end do endif else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PREPROCESS has changed presence \" return end if !> All checks passed: the two dependencies have no differences has_changed = . false . end function dependency_has_changed end module fpm_dependency","tags":"","loc":"sourcefile/dependency.f90.html"},{"title":"toml.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_toml Source Code toml.f90 Source Code !># Interface to TOML processing library !> !> This module acts as a proxy to the `toml-f` public Fortran API and allows !> to selectively expose components from the library to `fpm`. !> The interaction with `toml-f` data types outside of this module should be !> limited to tables, arrays and key-lists, most of the necessary interactions !> are implemented in the building interface with the `get_value` and `set_value` !> procedures. !> !> This module allows to implement features necessary for `fpm`, which are !> not yet available in upstream `toml-f`. !> !> For more details on the library used see the !> [TOML-Fortran](https://toml-f.github.io/toml-f) developer pages. module fpm_toml use fpm_error , only : error_t , fatal_error , file_not_found_error use fpm_strings , only : string_t use tomlf , only : toml_table , toml_array , toml_key , toml_stat , get_value , & & set_value , toml_parse , toml_error , new_table , add_table , add_array , & & toml_serialize , len , toml_load implicit none private public :: read_package_file , toml_table , toml_array , toml_key , toml_stat , & get_value , set_value , get_list , new_table , add_table , add_array , len , & toml_error , toml_serialize , toml_load , check_keys contains !> Process the configuration file to a TOML data structure subroutine read_package_file ( table , manifest , error ) !> TOML data structure type ( toml_table ), allocatable , intent ( out ) :: table !> Name of the package configuration file character ( len =* ), intent ( in ) :: manifest !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error type ( toml_error ), allocatable :: parse_error integer :: unit logical :: exist inquire ( file = manifest , exist = exist ) if (. not . exist ) then call file_not_found_error ( error , manifest ) return end if open ( file = manifest , newunit = unit ) call toml_load ( table , unit , error = parse_error ) close ( unit ) if ( allocated ( parse_error )) then allocate ( error ) call move_alloc ( parse_error % message , error % message ) return end if end subroutine read_package_file subroutine get_list ( table , key , list , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Key to read from character ( len =* ), intent ( in ) :: key !> List of strings to read type ( string_t ), allocatable , intent ( out ) :: list (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , ilist , nlist type ( toml_array ), pointer :: children character ( len = :), allocatable :: str if (. not . table % has_key ( key )) return call get_value ( table , key , children , requested = . false .) if ( associated ( children )) then nlist = len ( children ) allocate ( list ( nlist )) do ilist = 1 , nlist call get_value ( children , ilist , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) exit end if call move_alloc ( str , list ( ilist )% s ) end do if ( allocated ( error )) return else call get_value ( table , key , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) return end if if ( allocated ( str )) then allocate ( list ( 1 )) call move_alloc ( str , list ( 1 )% s ) end if end if end subroutine get_list !> Check if table contains only keys that are part of the list. If a key is !> found that is not part of the list, an error is allocated. subroutine check_keys ( table , valid_keys , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys to check. character ( len =* ), intent ( in ) :: valid_keys (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: keys (:) type ( toml_table ), pointer :: child character (:), allocatable :: name , value , valid_keys_string integer :: ikey , ivalid call table % get_key ( name ) call table % get_keys ( keys ) do ikey = 1 , size ( keys ) if (. not . any ( keys ( ikey )% key == valid_keys )) then ! Generate error message valid_keys_string = new_line ( 'a' ) // new_line ( 'a' ) do ivalid = 1 , size ( valid_keys ) valid_keys_string = valid_keys_string // trim ( valid_keys ( ivalid )) // new_line ( 'a' ) end do allocate ( error ) error % message = \"Key '\" // keys ( ikey )% key // \"' not allowed in the '\" // & & name // \"' table.\" // new_line ( 'a' ) // new_line ( 'a' ) // 'Valid keys: ' // valid_keys_string return end if ! Check if value can be mapped or else (wrong type) show error message with the error location. ! Right now, it can only be mapped to a string or to a child node, but this can be extended in the future. call get_value ( table , keys ( ikey )% key , value ) if (. not . allocated ( value )) then ! If value is not a string, check if it is a child node call get_value ( table , keys ( ikey )% key , child ) if (. not . associated ( child )) then allocate ( error ) error % message = \"'\" // name // \"' has an invalid '\" // keys ( ikey )% key // \"' entry.\" return endif end if end do end subroutine check_keys end module fpm_toml","tags":"","loc":"sourcefile/toml.f90.html"},{"title":"installer.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_installer Source Code installer.f90 Source Code !> Implementation of an installer object. !> !> The installer provides a way to install objects to their respective directories !> in the installation prefix, a generic install command allows to install !> to any directory within the prefix. module fpm_installer use , intrinsic :: iso_fortran_env , only : output_unit use fpm_environment , only : get_os_type , os_is_unix use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : join_path , mkdir , exists , unix_path , windows_path , get_local_prefix implicit none private public :: installer_t , new_installer !> Declaration of the installer type type :: installer_t !> Path to installation directory character ( len = :), allocatable :: prefix !> Binary dir relative to the installation prefix character ( len = :), allocatable :: bindir !> Library directory relative to the installation prefix character ( len = :), allocatable :: libdir !> Include directory relative to the installation prefix character ( len = :), allocatable :: includedir !> Output unit for informative printout integer :: unit = output_unit !> Verbosity of the installer integer :: verbosity = 1 !> Command to copy objects into the installation prefix character ( len = :), allocatable :: copy !> Command to move objects into the installation prefix character ( len = :), allocatable :: move !> Cached operating system integer :: os contains !> Install an executable in its correct subdirectory procedure :: install_executable !> Install a library in its correct subdirectory procedure :: install_library !> Install a header/module in its correct subdirectory procedure :: install_header !> Install a generic file into a subdirectory in the installation prefix procedure :: install !> Run an installation command, type-bound for unit testing purposes procedure :: run !> Create a new directory in the prefix, type-bound for unit testing purposes procedure :: make_dir end type installer_t !> Default name of the binary subdirectory character ( len =* ), parameter :: default_bindir = \"bin\" !> Default name of the library subdirectory character ( len =* ), parameter :: default_libdir = \"lib\" !> Default name of the include subdirectory character ( len =* ), parameter :: default_includedir = \"include\" !> Copy command on Unix platforms character ( len =* ), parameter :: default_copy_unix = \"cp\" !> Copy command on Windows platforms character ( len =* ), parameter :: default_copy_win = \"copy\" !> Copy command on Unix platforms character ( len =* ), parameter :: default_force_copy_unix = \"cp -f\" !> Copy command on Windows platforms character ( len =* ), parameter :: default_force_copy_win = \"copy /Y\" !> Move command on Unix platforms character ( len =* ), parameter :: default_move_unix = \"mv\" !> Move command on Windows platforms character ( len =* ), parameter :: default_move_win = \"move\" contains !> Create a new instance of an installer subroutine new_installer ( self , prefix , bindir , libdir , includedir , verbosity , & copy , move ) !> Instance of the installer type ( installer_t ), intent ( out ) :: self !> Path to installation directory character ( len =* ), intent ( in ), optional :: prefix !> Binary dir relative to the installation prefix character ( len =* ), intent ( in ), optional :: bindir !> Library directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: libdir !> Include directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: includedir !> Verbosity of the installer integer , intent ( in ), optional :: verbosity !> Copy command character ( len =* ), intent ( in ), optional :: copy !> Move command character ( len =* ), intent ( in ), optional :: move self % os = get_os_type () ! By default, never prompt the user for overwrites if ( present ( copy )) then self % copy = copy else if ( os_is_unix ( self % os )) then self % copy = default_force_copy_unix else self % copy = default_force_copy_win end if end if if ( present ( move )) then self % move = move else if ( os_is_unix ( self % os )) then self % move = default_move_unix else self % move = default_move_win end if end if if ( present ( includedir )) then self % includedir = includedir else self % includedir = default_includedir end if if ( present ( prefix )) then self % prefix = prefix else self % prefix = get_local_prefix ( self % os ) end if if ( present ( bindir )) then self % bindir = bindir else self % bindir = default_bindir end if if ( present ( libdir )) then self % libdir = libdir else self % libdir = default_libdir end if if ( present ( verbosity )) then self % verbosity = verbosity else self % verbosity = 1 end if end subroutine new_installer !> Install an executable in its correct subdirectory subroutine install_executable ( self , executable , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the executable character ( len =* ), intent ( in ) :: executable !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ll if (. not . os_is_unix ( self % os )) then ll = len ( executable ) if ( executable ( max ( 1 , ll - 3 ): ll ) /= \".exe\" ) then call self % install ( executable // \".exe\" , self % bindir , error ) return end if end if call self % install ( executable , self % bindir , error ) end subroutine install_executable !> Install a library in its correct subdirectory subroutine install_library ( self , library , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the library character ( len =* ), intent ( in ) :: library !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call self % install ( library , self % libdir , error ) end subroutine install_library !> Install a header/module in its correct subdirectory subroutine install_header ( self , header , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the header character ( len =* ), intent ( in ) :: header !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call self % install ( header , self % includedir , error ) end subroutine install_header !> Install a generic file into a subdirectory in the installation prefix subroutine install ( self , source , destination , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the original file character ( len =* ), intent ( in ) :: source !> Path to the destination inside the prefix character ( len =* ), intent ( in ) :: destination !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: install_dest install_dest = join_path ( self % prefix , destination ) if ( os_is_unix ( self % os )) then install_dest = unix_path ( install_dest ) else install_dest = windows_path ( install_dest ) end if call self % make_dir ( install_dest , error ) if ( allocated ( error )) return if ( self % verbosity > 0 ) then if ( exists ( install_dest )) then write ( self % unit , '(\"# Update:\", 1x, a, 1x, \"->\", 1x, a)' ) & source , install_dest else write ( self % unit , '(\"# Install:\", 1x, a, 1x, \"->\", 1x, a)' ) & source , install_dest end if end if ! Use force-copy to never prompt the user for overwrite if a package was already installed call self % run ( self % copy // ' \"' // source // '\" \"' // install_dest // '\"' , error ) if ( allocated ( error )) return end subroutine install !> Create a new directory in the prefix subroutine make_dir ( self , dir , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Directory to be created character ( len =* ), intent ( in ) :: dir !> Error handling type ( error_t ), allocatable , intent ( out ) :: error if (. not . exists ( dir )) then if ( self % verbosity > 1 ) then write ( self % unit , '(\"# Dir:\", 1x, a)' ) dir end if call mkdir ( dir ) end if end subroutine make_dir !> Run an installation command subroutine run ( self , command , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Command to be launched character ( len =* ), intent ( in ) :: command !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat if ( self % verbosity > 1 ) then write ( self % unit , '(\"# Run:\", 1x, a)' ) command end if call execute_command_line ( command , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed in command: '\" // command // \"'\" ) return end if end subroutine run end module fpm_installer","tags":"","loc":"sourcefile/installer.f90.html"},{"title":"downloader.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_downloader Source Code downloader.f90 Source Code module fpm_downloader use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : which , run use fpm_versioning , only : version_t use jonquil , only : json_object , json_value , json_error , json_load , cast_to_object use fpm_strings , only : string_t implicit none private public :: downloader_t !> This type could be entirely avoided but it is quite practical because it can be mocked for testing. type downloader_t contains procedure , nopass :: get_pkg_data , get_file , upload_form , unpack end type contains !> Perform an http get request, save output to file, and parse json. subroutine get_pkg_data ( url , version , tmp_pkg_file , json , error ) character ( * ), intent ( in ) :: url type ( version_t ), allocatable , intent ( in ) :: version character ( * ), intent ( in ) :: tmp_pkg_file type ( json_object ), intent ( out ) :: json type ( error_t ), allocatable , intent ( out ) :: error class ( json_value ), allocatable :: j_value type ( json_object ), pointer :: ptr type ( json_error ), allocatable :: j_error if ( allocated ( version )) then ! Request specific version. call get_file ( url // '/' // version % s (), tmp_pkg_file , error ) else ! Request latest version. call get_file ( url , tmp_pkg_file , error ) end if if ( allocated ( error )) return call json_load ( j_value , tmp_pkg_file , error = j_error ) if ( allocated ( j_error )) then allocate ( error ); call move_alloc ( j_error % message , error % message ); call json % destroy (); return end if ptr => cast_to_object ( j_value ) if (. not . associated ( ptr )) then call fatal_error ( error , \"Error parsing JSON from '\" // url // \"'.\" ); return end if json = ptr end !> Download a file from a url using either curl or wget. subroutine get_file ( url , tmp_pkg_file , error ) character ( * ), intent ( in ) :: url character ( * ), intent ( in ) :: tmp_pkg_file type ( error_t ), allocatable , intent ( out ) :: error integer :: stat if ( which ( 'curl' ) /= '' ) then print * , \"Downloading '\" // url // \"' -> '\" // tmp_pkg_file // \"'\" call execute_command_line ( 'curl ' // url // ' -s -o ' // tmp_pkg_file , exitstat = stat ) else if ( which ( 'wget' ) /= '' ) then print * , \"Downloading '\" // url // \"' -> '\" // tmp_pkg_file // \"'\" call execute_command_line ( 'wget ' // url // ' -q -O ' // tmp_pkg_file , exitstat = stat ) else call fatal_error ( error , \"Neither 'curl' nor 'wget' installed.\" ); return end if if ( stat /= 0 ) then call fatal_error ( error , \"Error downloading package from '\" // url // \"'.\" ); return end if end !> Perform an http post request with form data. subroutine upload_form ( endpoint , form_data , verbose , error ) !> Endpoint to upload to. character ( len =* ), intent ( in ) :: endpoint !> Form data to upload. type ( string_t ), intent ( in ) :: form_data (:) !> Print additional information if true. logical , intent ( in ) :: verbose !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: form_data_str form_data_str = '' do i = 1 , size ( form_data ) form_data_str = form_data_str // \"-F '\" // form_data ( i )% s // \"' \" end do if ( which ( 'curl' ) /= '' ) then print * , 'Uploading package ...' call run ( 'curl -X POST -H \"Content-Type: multipart/form-data\" ' // & & form_data_str // endpoint , exitstat = stat , echo = verbose ) else call fatal_error ( error , \"'curl' not installed.\" ); return end if if ( stat /= 0 ) then call fatal_error ( error , \"Error uploading package to registry.\" ); return end if end !> Unpack a tarball to a destination. subroutine unpack ( tmp_pkg_file , destination , error ) !> Path to tarball. character ( * ), intent ( in ) :: tmp_pkg_file !> Destination to unpack to. character ( * ), intent ( in ) :: destination !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error integer :: stat if ( which ( 'tar' ) == '' ) then call fatal_error ( error , \"'tar' not installed.\" ); return end if print * , \"Unpacking '\" // tmp_pkg_file // \"' to '\" // destination // \"' ...\" call execute_command_line ( 'tar -zxf ' // tmp_pkg_file // ' -C ' // destination , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error unpacking '\" // tmp_pkg_file // \"'.\" ); return end if end end","tags":"","loc":"sourcefile/downloader.f90.html"},{"title":"manifest.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest Source Code manifest.f90 Source Code !> Package configuration data. !> !> This module provides the necessary procedure to translate a TOML document !> to the corresponding Fortran type, while verifying it with respect to !> its schema. !> !> Additionally, the required data types for users of this module are reexported !> to hide the actual implementation details. module fpm_manifest use fpm_manifest_example , only : example_config_t use fpm_manifest_executable , only : executable_config_t use fpm_manifest_dependency , only : dependency_config_t use fpm_manifest_library , only : library_config_t use fpm_manifest_preprocess , only : preprocess_config_t use fpm_manifest_package , only : package_config_t , new_package use fpm_error , only : error_t , fatal_error use fpm_toml , only : toml_table , read_package_file use fpm_manifest_test , only : test_config_t use fpm_filesystem , only : join_path , exists , dirname , is_dir use fpm_environment , only : os_is_unix use fpm_strings , only : string_t implicit none private public :: get_package_data , default_executable , default_library , default_test public :: default_example public :: package_config_t , dependency_config_t , preprocess_config_t contains !> Populate library in case we find the default src directory subroutine default_library ( self ) !> Instance of the library meta data type ( library_config_t ), intent ( out ) :: self self % source_dir = \"src\" self % include_dir = [ string_t ( \"include\" )] end subroutine default_library !> Populate executable in case we find the default app directory subroutine default_executable ( self , name ) !> Instance of the executable meta data type ( executable_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name self % source_dir = \"app\" self % main = \"main.f90\" end subroutine default_executable !> Populate test in case we find the default example/ directory subroutine default_example ( self , name ) !> Instance of the executable meta data type ( example_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-demo\" self % source_dir = \"example\" self % main = \"main.f90\" end subroutine default_example !> Populate test in case we find the default test/ directory subroutine default_test ( self , name ) !> Instance of the executable meta data type ( test_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-test\" self % source_dir = \"test\" self % main = \"main.f90\" end subroutine default_test !> Obtain package meta data from a configuation file subroutine get_package_data ( package , file , error , apply_defaults ) !> Parsed package meta data type ( package_config_t ), intent ( out ) :: package !> Name of the package configuration file character ( len =* ), intent ( in ) :: file !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error !> Apply package defaults (uses file system operations) logical , intent ( in ), optional :: apply_defaults type ( toml_table ), allocatable :: table character ( len = :), allocatable :: root call read_package_file ( table , file , error ) if ( allocated ( error )) return if (. not . allocated ( table )) then call fatal_error ( error , \"Unclassified error while reading: '\" // file // \"'\" ) return end if call new_package ( package , table , dirname ( file ), error ) if ( allocated ( error )) return if ( present ( apply_defaults )) then if ( apply_defaults ) then root = dirname ( file ) if ( len_trim ( root ) == 0 ) root = \".\" call package_defaults ( package , root , error ) if ( allocated ( error )) return end if end if end subroutine get_package_data !> Apply package defaults subroutine package_defaults ( package , root , error ) !> Parsed package meta data type ( package_config_t ), intent ( inout ) :: package !> Current working directory character ( len =* ), intent ( in ) :: root !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error ! Populate library in case we find the default src directory if (. not . allocated ( package % library ) . and . & & ( is_dir ( join_path ( root , \"src\" )) . or . & & is_dir ( join_path ( root , \"include\" )))) then allocate ( package % library ) call default_library ( package % library ) end if ! Populate executable in case we find the default app if (. not . allocated ( package % executable ) . and . & & exists ( join_path ( root , \"app\" , \"main.f90\" ))) then allocate ( package % executable ( 1 )) call default_executable ( package % executable ( 1 ), package % name ) end if ! Populate example in case we find the default example directory if (. not . allocated ( package % example ) . and . & & exists ( join_path ( root , \"example\" , \"main.f90\" ))) then allocate ( package % example ( 1 )) call default_example ( package % example ( 1 ), package % name ) endif ! Populate test in case we find the default test directory if (. not . allocated ( package % test ) . and . & & exists ( join_path ( root , \"test\" , \"main.f90\" ))) then allocate ( package % test ( 1 )) call default_test ( package % test ( 1 ), package % name ) endif if (. not .( allocated ( package % library ) & & . or . allocated ( package % executable ) & & . or . allocated ( package % example ) & & . or . allocated ( package % test ))) then call fatal_error ( error , \"Neither library nor executable found, there is nothing to do\" ) return end if end subroutine package_defaults end module fpm_manifest","tags":"","loc":"sourcefile/manifest.f90.html"},{"title":"fpm_release.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_release Source Code fpm_release.F90 Source Code !># Release parameters !> Module fpm_release contains public constants storing this build's unique version IDs module fpm_release use fpm_versioning , only : version_t , new_version use fpm_error , only : error_t , fpm_stop implicit none private public :: fpm_version public :: version_t contains !> Return the current fpm version from fpm_version_ID as a version type type ( version_t ) function fpm_version () type ( error_t ), allocatable :: error ! Fallback to last known version in case of undefined macro #ifndef FPM_RELEASE_VERSION # define FPM_RELEASE_VERSION 0.8.0 #endif ! Accept solution from https://stackoverflow.com/questions/31649691/stringify-macro-with-gnu-gfortran ! which provides the \"easiest\" way to pass a macro to a string in Fortran complying with both ! gfortran's \"traditional\" cpp and the standard cpp syntaxes #ifdef __GFORTRAN__ /* traditional-cpp stringification */ # define STRINGIFY_START(X) \"& # define STRINGIFY_END(X) &X\" #else /* default stringification */ # define STRINGIFY_(X) #X # define STRINGIFY_START(X) & # define STRINGIFY_END(X) STRINGIFY_(X) #endif character ( len = :), allocatable :: ver_string ver_string = STRINGIFY_START ( FPM_RELEASE_VERSION ) STRINGIFY_END ( FPM_RELEASE_VERSION ) call new_version ( fpm_version , ver_string , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*fpm*:internal error: cannot get version - ' // error % message ) end function fpm_version end module fpm_release","tags":"","loc":"sourcefile/fpm_release.f90.html"},{"title":"error.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_error Source Code error.f90 Source Code !> Implementation of basic error handling. module fpm_error use , intrinsic :: iso_fortran_env , only : stdin => input_unit , stdout => output_unit , stderr => error_unit use fpm_strings , only : is_fortran_name , to_fortran_name implicit none private public :: error_t public :: fatal_error , syntax_error , file_not_found_error public :: file_parse_error public :: bad_name_error public :: fpm_stop !> Data type defining an error type :: error_t !> Error message character ( len = :), allocatable :: message end type error_t contains !> Generic fatal runtime error subroutine fatal_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine fatal_error subroutine syntax_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine syntax_error function bad_name_error ( error , label , name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message label to add to message character ( len =* ), intent ( in ) :: label !> name value to check character ( len =* ), intent ( in ) :: name logical :: bad_name_error if (. not . is_fortran_name ( to_fortran_name ( name ))) then bad_name_error = . true . allocate ( error ) error % message = 'manifest file syntax error: ' // label // ' name must be composed only of & &alphanumerics, \"-\" and \"_\" and start with a letter ::' // name else bad_name_error = . false . endif end function bad_name_error !> Error created when a file is missing or not found subroutine file_not_found_error ( error , file_name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of the missing file character ( len =* ), intent ( in ) :: file_name allocate ( error ) error % message = \"'\" // file_name // \"' could not be found, check if the file exists\" end subroutine file_not_found_error !> Error created when file parsing fails subroutine file_parse_error ( error , file_name , message , line_num , & line_string , line_col ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of file character ( len =* ), intent ( in ) :: file_name !> Parse error message character ( len =* ), intent ( in ) :: message !> Line number of parse error integer , intent ( in ), optional :: line_num !> Line context string character ( len =* ), intent ( in ), optional :: line_string !> Line context column integer , intent ( in ), optional :: line_col character ( 50 ) :: temp_string allocate ( error ) error % message = 'Parse error: ' // message // new_line ( 'a' ) error % message = error % message // file_name if ( present ( line_num )) then write ( temp_string , '(I0)' ) line_num error % message = error % message // ':' // trim ( temp_string ) end if if ( present ( line_col )) then if ( line_col > 0 ) then write ( temp_string , '(I0)' ) line_col error % message = error % message // ':' // trim ( temp_string ) end if end if if ( present ( line_string )) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // line_string if ( present ( line_col )) then if ( line_col > 0 ) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // repeat ( ' ' , line_col - 1 ) // '^' end if end if end if end subroutine file_parse_error subroutine fpm_stop ( value , message ) ! TODO: if verbose mode, call ERROR STOP instead of STOP ! TODO: if M_escape is used, add color ! to work with older compilers might need a case statement for values !> value to use on STOP integer , intent ( in ) :: value !> Error message character ( len =* ), intent ( in ) :: message integer :: iostat if ( message /= '' ) then flush ( unit = stderr , iostat = iostat ) flush ( unit = stdout , iostat = iostat ) if ( value > 0 ) then write ( stderr , '(\" \",a)' ) trim ( message ) else write ( stderr , '(\" \",a)' ) trim ( message ) endif flush ( unit = stderr , iostat = iostat ) endif stop value end subroutine fpm_stop end module fpm_error","tags":"","loc":"sourcefile/error.f90.html"},{"title":"install.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_cmd_install Source Code install.f90 Source Code module fpm_cmd_install use , intrinsic :: iso_fortran_env , only : output_unit use fpm , only : build_model use fpm_backend , only : build_package use fpm_command_line , only : fpm_install_settings use fpm_error , only : error_t , fatal_error , fpm_stop use fpm_filesystem , only : join_path , list_files use fpm_installer , only : installer_t , new_installer use fpm_manifest , only : package_config_t , get_package_data use fpm_model , only : fpm_model_t , FPM_SCOPE_APP use fpm_targets , only : targets_from_sources , build_target_t , & build_target_ptr , FPM_TARGET_EXECUTABLE , & filter_library_targets , filter_executable_targets , filter_modules use fpm_strings , only : string_t , resize implicit none private public :: cmd_install contains !> Entry point for the fpm-install subcommand subroutine cmd_install ( settings ) !> Representation of the command line settings type ( fpm_install_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( error_t ), allocatable :: error type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( installer_t ) :: installer type ( string_t ), allocatable :: list (:) logical :: installable call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) call build_model ( model , settings , package , error ) call handle_error ( error ) call targets_from_sources ( targets , model , settings % prune , error ) call handle_error ( error ) installable = ( allocated ( package % library ) . and . package % install % library ) & . or . allocated ( package % executable ) if (. not . installable ) then call fatal_error ( error , \"Project does not contain any installable targets\" ) call handle_error ( error ) end if if ( settings % list ) then call install_info ( output_unit , targets ) return end if if (. not . settings % no_rebuild ) then call build_package ( targets , model , verbose = settings % verbose ) end if call new_installer ( installer , prefix = settings % prefix , & bindir = settings % bindir , libdir = settings % libdir , & includedir = settings % includedir , & verbosity = merge ( 2 , 1 , settings % verbose )) if ( allocated ( package % library ) . and . package % install % library ) then call filter_library_targets ( targets , list ) if ( size ( list ) > 0 ) then call installer % install_library ( list ( 1 )% s , error ) call handle_error ( error ) call install_module_files ( installer , targets , error ) call handle_error ( error ) end if end if if ( allocated ( package % executable )) then call install_executables ( installer , targets , error ) call handle_error ( error ) end if end subroutine cmd_install subroutine install_info ( unit , targets ) integer , intent ( in ) :: unit type ( build_target_ptr ), intent ( in ) :: targets (:) integer :: ii , ntargets type ( string_t ), allocatable :: install_target (:), temp (:) allocate ( install_target ( 0 )) call filter_library_targets ( targets , temp ) install_target = [ install_target , temp ] call filter_executable_targets ( targets , FPM_SCOPE_APP , temp ) install_target = [ install_target , temp ] ntargets = size ( install_target ) write ( unit , '(\"#\", *(1x, g0))' ) & \"total number of installable targets:\" , ntargets do ii = 1 , ntargets write ( unit , '(\"-\", *(1x, g0))' ) install_target ( ii )% s end do end subroutine install_info subroutine install_module_files ( installer , targets , error ) type ( installer_t ), intent ( inout ) :: installer type ( build_target_ptr ), intent ( in ) :: targets (:) type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ), allocatable :: modules (:) integer :: ii call filter_modules ( targets , modules ) do ii = 1 , size ( modules ) call installer % install_header ( modules ( ii )% s // \".mod\" , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end subroutine install_module_files subroutine install_executables ( installer , targets , error ) type ( installer_t ), intent ( inout ) :: installer type ( build_target_ptr ), intent ( in ) :: targets (:) type ( error_t ), allocatable , intent ( out ) :: error integer :: ii do ii = 1 , size ( targets ) if ( is_executable_target ( targets ( ii )% ptr )) then call installer % install_executable ( targets ( ii )% ptr % output_file , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end subroutine install_executables elemental function is_executable_target ( target_ptr ) result ( is_exe ) type ( build_target_t ), intent ( in ) :: target_ptr logical :: is_exe is_exe = target_ptr % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( target_ptr % dependencies ) if ( is_exe ) then is_exe = target_ptr % dependencies ( 1 )% ptr % source % unit_scope == FPM_SCOPE_APP end if end function is_executable_target subroutine handle_error ( error ) type ( error_t ), intent ( in ), optional :: error if ( present ( error )) then call fpm_stop ( 1 , error % message ) end if end subroutine handle_error end module fpm_cmd_install","tags":"","loc":"sourcefile/install.f90~2.html"},{"title":"update.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_cmd_update Source Code update.f90 Source Code module fpm_cmd_update use fpm_command_line , only : fpm_update_settings use fpm_dependency , only : dependency_tree_t , new_dependency_tree use fpm_error , only : error_t , fpm_stop use fpm_filesystem , only : exists , mkdir , join_path , delete_file , filewrite use fpm_manifest , only : package_config_t , get_package_data implicit none private public :: cmd_update contains !> Entry point for the update subcommand subroutine cmd_update ( settings ) !> Representation of the command line arguments type ( fpm_update_settings ), intent ( in ) :: settings type ( package_config_t ) :: package type ( dependency_tree_t ) :: deps type ( error_t ), allocatable :: error integer :: ii character ( len = :), allocatable :: cache call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) if (. not . exists ( \"build\" )) then call mkdir ( \"build\" ) call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if cache = join_path ( \"build\" , \"cache.toml\" ) if ( settings % clean ) call delete_file ( cache ) call new_dependency_tree ( deps , cache = cache , & verbosity = merge ( 2 , 1 , settings % verbose )) call deps % add ( package , error ) call handle_error ( error ) ! Force-update all dependencies if `--clean` if ( settings % clean ) then do ii = 1 , deps % ndep deps % dep ( ii )% update = . true . end do end if if ( settings % fetch_only ) return if ( size ( settings % name ) == 0 ) then call deps % update ( error ) call handle_error ( error ) else do ii = 1 , size ( settings % name ) call deps % update ( trim ( settings % name ( ii )), error ) call handle_error ( error ) end do end if end subroutine cmd_update !> Error handling for this command subroutine handle_error ( error ) !> Potential error type ( error_t ), intent ( in ), optional :: error if ( present ( error )) then call fpm_stop ( 1 , error % message ) end if end subroutine handle_error end module fpm_cmd_update","tags":"","loc":"sourcefile/update.f90.html"},{"title":"new.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_cmd_new Source Code new.f90 Source Code module fpm_cmd_new !># Definition of the \"new\" subcommand !> !> A type of the general command base class [[fpm_cmd_settings]] !> was created for the \"new\" subcommand ==> type [[fpm_new_settings]]. !> This procedure read the values that were set on the command line !> from this type to decide what actions to take. !> !> It is virtually self-contained and so independant of the rest of the !> application that it could function as a separate program. !> !> The \"new\" subcommand options currently consist of a SINGLE top !> directory name to create that must have a name that is an !> allowable Fortran variable name. That should have been ensured !> by the command line processing before this procedure is called. !> So basically this routine has already had the options vetted and !> just needs to conditionally create a few files. !> !> As described in the documentation it will selectively !> create the subdirectories app/, test/, src/, and example/ !> and populate them with sample files. !> !> It also needs to create an initial manifest file \"fpm.toml\". !> !> It then calls the system command \"git init\". !> !> It should test for file existence and not overwrite existing !> files and inform the user if there were conflicts. !> !> Any changes should be reflected in the documentation in !> [[fpm_command_line.f90]] !> !> FUTURE !> A filename like \".\" would need system commands or a standard routine !> like realpath(3c) to process properly. !> !> Perhaps allow more than one name on a single command. It is an arbitrary !> restriction based on a concensus preference, not a required limitation. !> !> Initially the name of the directory is used as the module name in the !> src file so it must be an allowable Fortran variable name. If there are !> complaints about it it might be changed. Handling unicode at this point !> might be problematic as not all current compilers handle it. Other !> utilities like content trackers (ie. git) or repositories like github !> might also have issues with alternative names or names with spaces, etc. !> So for the time being it seems prudent to encourage simple ASCII top directory !> names (similiar to the primary programming language Fortran itself). !> !> Should be able to create or pull more complicated initial examples !> based on various templates. It should place or mention other relevant !> documents such as a description of the manifest file format in user hands; !> or how to access registered packages and local packages, !> although some other command might provide that (and the help command should !> be the first go-to for a CLI utility). use fpm_command_line , only : fpm_new_settings use fpm_environment , only : OS_LINUX , OS_MACOS , OS_WINDOWS use fpm_filesystem , only : join_path , exists , basename , mkdir , is_dir use fpm_filesystem , only : fileopen , fileclose , warnwrite , which , run use fpm_strings , only : join , to_fortran_name use fpm_error , only : fpm_stop use , intrinsic :: iso_fortran_env , only : stderr => error_unit implicit none private public :: cmd_new contains subroutine cmd_new ( settings ) type ( fpm_new_settings ), intent ( in ) :: settings integer , parameter :: tfc = selected_char_kind ( 'DEFAULT' ) character ( len = :, kind = tfc ), allocatable :: bname ! baeename of NAME character ( len = :, kind = tfc ), allocatable :: tomlfile (:) character ( len = :, kind = tfc ), allocatable :: littlefile (:) !> TOP DIRECTORY NAME PROCESSING !> see if requested new directory already exists and process appropriately if ( exists ( settings % name ) . and . . not . settings % backfill ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists.' write ( stderr , '(*(g0,1x))' )& & ' perhaps you wanted to add --backfill ?' return elseif ( is_dir ( settings % name ) . and . settings % backfill ) then write ( * , '(*(g0))' ) 'backfilling ' , settings % name elseif ( exists ( settings % name ) ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists and is not a directory.' return else ! make new directory call mkdir ( settings % name ) endif !> temporarily change to new directory as a test. NB: System dependent call run ( 'cd ' // settings % name ) ! NOTE: need some system routines to handle filenames like \".\" ! like realpath() or getcwd(). bname = basename ( settings % name ) littlefile = [ character ( len = 80 ) :: '# ' // bname , 'My cool new project!' ] ! create NAME/README.md call warnwrite ( join_path ( settings % name , 'README.md' ), littlefile ) ! start building NAME/fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: & & ' # This is your fpm(Fortran Package Manager) manifest file ' ,& & ' # (\"fpm.toml\"). It is heavily annotated to help guide you though ' ,& & ' # customizing a package build, although the defaults are sufficient ' ,& & ' # for many basic packages. ' ,& & ' # ' ,& & ' # The manifest file is not only used to provide metadata identifying ' ,& & ' # your project (so it can be used by others as a dependency). It can ' ,& & ' # specify where your library and program sources live, what the name ' ,& & ' # of the executable(s) will be, what files to build, dependencies on ' ,& & ' # other fpm packages, and what external libraries are required. ' ,& & ' # ' ,& & ' # The manifest format must conform to the TOML configuration file ' ,& & ' # standard. ' ,& & ' # ' ,& & ' # TOML files support flexible use of white-space and commenting of the ' ,& & ' # configuration data, but for clarity in this sample active directives ' ,& & ' # begin in column one. Inactive example directives are commented ' ,& & ' # out with a pound character (\"#\") but begin in column one as well. ' ,& & ' # Commentary begins with a pound character in column three. ' ,& & ' # ' ,& & ' # This file draws heavily upon the following references: ' ,& & ' # ' ,& & ' # The fpm home page at ' ,& & ' # https://github.com/fortran-lang/fpm ' ,& & ' # A complete list of keys and their attributes at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/manifest-reference.md ' ,& & ' # examples of fpm project packaging at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/PACKAGING.md ' ,& & ' # The Fortran TOML file interface and it''s references at ' ,& & ' # https://github.com/toml-f/toml-f ' ,& & ' # ' ,& & ' #----------------------- ' ,& & ' # project Identification ' ,& & ' #----------------------- ' ,& & ' # We begin with project metadata at the manifest root. This data is designed ' ,& & ' # to aid others when searching for the project in a repository and to ' ,& & ' # identify how and when to contact the package supporters. ' ,& & ' ' ,& & 'name = \"' // bname // '\"' ,& & ' # The project name (required) is how the project will be referred to. ' ,& & ' # The name is used by other packages using it as a dependency. It also ' ,& & ' # is used as the default name of any library built and the optional ' ,& & ' # default executable built from app/main.f90. It must conform to the rules ' ,& & ' # for a Fortran variable name. ' ,& & ' ' ,& & 'version = \"0.1.0\" ' ,& & ' # The project version number is a string. A recommended scheme for ' ,& & ' # specifying versions is the Semantic Versioning scheme. ' ,& & ' ' ,& & 'license = \"license\" ' ,& & ' # Licensing information specified using SPDX identifiers is preferred ' ,& & ' # (eg. \"Apache-2.0 OR MIT\" or \"LGPL-3.0-or-later\"). ' ,& & ' ' ,& & 'maintainer = \"jane.doe@example.com\" ' ,& & ' # Information on the project maintainer and means to reach out to them. ' ,& & ' ' ,& & 'author = \"Jane Doe\" ' ,& & ' # Information on the project author. ' ,& & ' ' ,& & 'copyright = \"Copyright 2020 Jane Doe\" ' ,& & ' # A statement clarifying the Copyright status of the project. ' ,& & ' ' ,& & '#description = \"A short project summary in plain text\" ' ,& & ' # The description provides a short summary on the project. It should be ' ,& & ' # plain text and not use any markup formatting. ' ,& & ' ' ,& & '#categories = [\"fortran\", \"graphics\"] ' ,& & ' # Categories associated with the project. Listing only one is preferred. ' ,& & ' ' ,& & '#keywords = [\"hdf5\", \"mpi\"] ' ,& & ' # The keywords field is an array of strings describing the project. ' ,& & ' ' ,& & '#homepage = \"https://stdlib.fortran-lang.org\" ' ,& & ' # URL to the webpage of the project. ' ,& & ' ' ,& & ' # ----------------------------------------- ' ,& & ' # We are done with identifying the project. ' ,& & ' # ----------------------------------------- ' ,& & ' # ' ,& & ' # Now lets start describing how the project should be built. ' ,& & ' # ' ,& & ' # Note tables would go here but we will not be talking about them (much)!!' ,& & ' # ' ,& & ' # Tables are a way to explicitly specify large numbers of programs in ' ,& & ' # a compact format instead of individual per-program entries in the ' ,& & ' # [[executable]], [[test]], and [[example]] sections to follow but ' ,& & ' # will not be discussed further except for the following notes: ' ,& & ' # ' ,& & ' # + Tables must appear (here) before any sections are declared. Once a ' ,& & ' # section is specified in a TOML file everything afterwards must be ' ,& & ' # values for that section or the beginning of a new section. A simple ' ,& & ' # example looks like: ' ,& & ' ' ,& & '#executable = [ ' ,& & '# { name = \"a-prog\" }, ' ,& & '# { name = \"app-tool\", source-dir = \"tool\" }, ' ,& & '# { name = \"fpm-man\", source-dir = \"tool\", main=\"fman.f90\" } ' ,& & '#] ' ,& & ' ' ,& & ' # This would be in lieue of the [[executable]] section found later in this ' ,& & ' # configuration file. ' ,& & ' # + See the reference documents (at the beginning of this document) ' ,& & ' # for more information on tables if you have long lists of programs ' ,& & ' # to build and are not simply depending on auto-detection. ' ,& & ' # ' ,& & ' # Now lets begin the TOML sections (lines beginning with \"[\") ... ' ,& & ' # ' ,& & ' ' ,& & '[install] # Options for the \"install\" subcommand ' ,& & ' ' ,& & ' # When you run the \"install\" subcommand only executables are installed by ' ,& & ' # default on the local system. Library projects that will be used outside of ' ,& & ' # \"fpm\" can set the \"library\" boolean to also allow installing the module ' ,& & ' # files and library archive. Without this being set to \"true\" an \"install\" ' ,& & ' # subcommand ignores parameters that specify library installation. ' ,& & ' ' ,& & 'library = false ' ,& & ' ' ,& & '[build] # General Build Options ' ,& & ' ' ,& & ' ### Automatic target discovery ' ,& & ' # ' ,& & ' # Normally fpm recursively searches the app/, example/, and test/ directories ' ,& & ' # for program sources and builds them. To disable this automatic discovery of ' ,& & ' # program targets set the following to \"false\": ' ,& & ' ' ,& & '#auto-executables = true ' ,& & '#auto-examples = true ' ,& & '#auto-tests = true ' ,& & ' ' ,& & ' ### Package-level External Library Links ' ,& & ' # ' ,& & ' # To declare link-time dependencies on external libraries a list of ' ,& & ' # native libraries can be specified with the \"link\" entry. You may ' ,& & ' # have one library name or a list of strings in case several ' ,& & ' # libraries should be linked. This list of library dependencies is ' ,& & ' # exported to dependent packages. You may have to alter your library ' ,& & ' # search-path to ensure the libraries can be accessed. Typically, ' ,& & ' # this is done with the LD_LIBRARY_PATH environment variable on ULS ' ,& & ' # (Unix-Like Systems). You only specify the core name of the library ' ,& & ' # (as is typical with most programming environments, where you ' ,& & ' # would specify \"-lz\" on your load command to link against the zlib ' ,& & ' # compression library even though the library file would typically be ' ,& & ' # a file called \"libz.a\" \"or libz.so\"). So to link against that library ' ,& & ' # you would specify: ' ,& & ' ' ,& & '#link = \"z\" ' ,& & ' ' ,& & ' # Note that in some cases the order of the libraries matters: ' ,& & ' ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_lib ) then call mkdir ( join_path ( settings % name , 'src' ) ) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[library] ' ,& & ' ' ,& & ' # You can change the name of the directory to search for your library ' ,& & ' # source from the default of \"src/\". Library targets are exported ' ,& & ' # and usable by other projects. ' ,& & ' ' ,& & 'source-dir=\"src\" ' ,& & ' ' ,& & ' # this can be a list: ' ,& & ' ' ,& & '#source-dir=[\"src\", \"src2\"] ' ,& & ' ' ,& & ' # More complex libraries may organize their modules in subdirectories. ' ,& & ' # For modules in a top-level directory fpm requires (but does not ' ,& & ' # enforce) that: ' ,& & ' # ' ,& & ' # + The module has the same name as the source file. This is important. ' ,& & ' # + There should be only one module per file. ' ,& & ' # ' ,& & ' # These two requirements simplify the build process for fpm. As Fortran ' ,& & ' # compilers emit module files (.mod) with the same name as the module ' ,& & ' # itself (but not the source file, .f90), naming the module the same ' ,& & ' # as the source file allows fpm to: ' ,& & ' # ' ,& & ' # + Uniquely and exactly map a source file (.f90) to its object (.o) ' ,& & ' # and module (.mod) files. ' ,& & ' # + Avoid conflicts with modules of the same name that could appear ' ,& & ' # in dependency packages. ' ,& & ' # ' ,& & ' ### Multi-level library source ' ,& & ' # You can place your module source files in any number of levels of ' ,& & ' # subdirectories inside your source directory, but there are certain naming ' ,& & ' # conventions to be followed -- module names must contain the path components ' ,& & ' # of the directory that its source file is in. ' ,& & ' # ' ,& & ' # This rule applies generally to any number of nested directories and ' ,& & ' # modules. For example, src/a/b/c/d.f90 must define a module called a_b_c_d. ' ,& & ' # Again, this is not enforced but may be required in future releases. ' ,& & '' ] endif ! create placeholder module src/bname.f90 littlefile = [ character ( len = 80 ) :: & & 'module ' // to_fortran_name ( bname ), & & ' implicit none' , & & ' private' , & & '' , & & ' public :: say_hello' , & & 'contains' , & & ' subroutine say_hello' , & & ' print *, \"Hello, ' // bname // '!\"' , & & ' end subroutine say_hello' , & & 'end module ' // to_fortran_name ( bname )] ! create NAME/src/NAME.f90 call warnwrite ( join_path ( settings % name , 'src' , bname // '.f90' ),& & littlefile ) endif if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[dependencies] ' ,& & ' ' ,& & ' # Inevitably, you will want to be able to include other packages in ' ,& & ' # a project. Fpm makes this incredibly simple, by taking care of ' ,& & ' # fetching and compiling your dependencies for you. You just tell it ' ,& & ' # what your dependencies names are, and where to find them. ' ,& & ' # ' ,& & ' # If you are going to distribute your package only place dependencies ' ,& & ' # here someone using your package as a remote dependency needs built. ' ,& & ' # You can define dependencies just for developer executables in the ' ,& & ' # next section, or even for specific executables as we will see below ' ,& & ' # (Then fpm will still fetch and compile it when building your ' ,& & ' # developer executables, but users of your library will not have to). ' ,& & ' # ' ,& & ' ## GLOBAL DEPENDENCIES (exported with your project) ' ,& & ' # ' ,& & ' # Typically, dependencies are defined by specifying the project''s ' ,& & ' # git repository. ' ,& & ' # ' ,& & ' # You can be specific about which version of a dependency you would ' ,& & ' # like. By default the latest default branch is used. You can ' ,& & ' # optionally specify a branch, a tag or a commit value. ' ,& & ' # ' ,& & ' # So here are several alternates for specifying a remote dependency (you ' ,& & ' # can have at most one of \"branch\", \"rev\" or \"tag\" present): ' ,& & ' ' ,& & '#stdlib = { git = \"https://github.com/LKedward/stdlib-fpm.git\" } ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\",branch = \"master\" },' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", tag = \"v0.1.0\" }, ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", rev = \"5a9b7a8\" }. ' ,& & ' ' ,& & ' # There may be multiple packages listed: ' ,& & ' ' ,& & '#M_strings = { git = \"https://github.com/urbanjost/M_strings.git\" } ' ,& & '#M_time = { git = \"https://github.com/urbanjost/M_time.git\" } ' ,& & ' ' ,& & ' # ' ,& & ' # You can even specify the local path to another project if it is in ' ,& & ' # a sub-folder (If for example you have got another fpm package **in ' ,& & ' # the same repository**) like this: ' ,& & ' ' ,& & '#M_strings = { path = \"M_strings\" } ' ,& & ' ' ,& & ' # This tells fpm that we depend on a crate called M_strings which is found ' ,& & ' # in the M_strings folder (relative to the fpm.toml it’s written in). ' ,& & ' # ' ,& & ' # For a more verbose layout use normal tables rather than inline tables ' ,& & ' # to specify dependencies: ' ,& & ' ' ,& & '#[dependencies.toml-f] ' ,& & '#git = \"https://github.com/toml-f/toml-f\" ' ,& & '#rev = \"2f5eaba864ff630ba0c3791126a3f811b6e437f3\" ' ,& & ' ' ,& & ' # Now you can use any modules from these libraries anywhere in your ' ,& & ' # code -- whether is in your library source or a program source. ' ,& & ' ' ,& & '[dev-dependencies] ' ,& & ' ' ,& & ' ## Dependencies Only for Development ' ,& & ' # ' ,& & ' # You can specify dependencies your library or application does not ' ,& & ' # depend on in a similar way. The difference is that these will not ' ,& & ' # be exported as part of your project to those using it as a remote ' ,& & ' # dependency. ' ,& & ' # ' ,& & ' # Currently, like a global dependency it will still be available for ' ,& & ' # all codes. It is up to the developer to ensure that nothing except ' ,& & ' # developer test programs rely upon it. ' ,& & ' ' ,& & '#M_msg = { git = \"https://github.com/urbanjost/M_msg.git\" } ' ,& & '#M_verify = { git = \"https://github.com/urbanjost/M_verify.git\" } ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_executable ) then ! create next section of fpm.toml call mkdir ( join_path ( settings % name , 'app' )) ! create NAME/app or stop if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & ' #----------------------------------- ' ,& & ' ## Application-specific declarations ' ,& & ' #----------------------------------- ' ,& & ' # Now lets begin entries for the TOML tables (lines beginning with \"[[\") ' ,& & ' # that describe the program sources -- applications, tests, and examples. ' ,& & ' # ' ,& & ' # First we will configuration individual applications run with \"fpm run\". ' ,& & ' # ' ,& & ' # + the \"name\" entry for the executable to be built must always ' ,& & ' # be specified. The name must satisfy the rules for a Fortran ' ,& & ' # variable name. This will be the name of the binary installed by ' ,& & ' # the \"install\" subcommand and used on the \"run\" subcommand. ' ,& & ' # + The source directory for each executable can be adjusted by the ' ,& & ' # \"source-dir\" entry. ' ,& & ' # + The basename of the source file containing the program body can ' ,& & ' # be specified with the \"main\" entry. ' ,& & ' # + Executables can also specify their own external package and ' ,& & ' # library link dependencies. ' ,& & ' # ' ,& & ' # Currently, like a global dependency any external package dependency ' ,& & ' # will be available for all codes. It is up to the developer to ensure ' ,& & ' # that nothing except the application programs specified rely upon it. ' ,& & ' # ' ,& & ' # Note if your application needs to use a module internally, but you do not ' ,& & ' # intend to build it as a library to be used in other projects, you can ' ,& & ' # include the module in your program source file or directory as well. ' ,& & ' ' ,& & '[[executable]] ' ,& & 'name=\"' // bname // '\"' ,& & 'source-dir=\"app\" ' ,& & 'main=\"main.f90\" ' ,& & ' ' ,& & ' # You may repeat this pattern to define additional applications. For instance,' ,& & ' # the following sample illustrates all accepted options, where \"link\" and ' ,& & ' # \"executable.dependencies\" keys are the same as the global external library ' ,& & ' # links and package dependencies described previously except they apply ' ,& & ' # only to this executable: ' ,& & ' ' ,& & '#[[ executable ]] ' ,& & '#name = \"app-name\" ' ,& & '#source-dir = \"prog\" ' ,& & '#main = \"program.f90\" ' ,& & '#link = \"z\" ' ,& & '#[executable.dependencies] ' ,& & '#M_CLI = { git = \"https://github.com/urbanjost/M_CLI.git\" } ' ,& & '#helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } ' ,& & '#M_path = { git = \"https://github.com/urbanjost/M_path.git\" } ' ,& & '' ] endif if ( exists ( bname // '/src/' )) then littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' use ' // to_fortran_name ( bname ) // ', only: say_hello' , & & ' implicit none' , & & '' , & & ' call say_hello()' , & & 'end program main' ] else littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' implicit none' , & & '' , & & ' print *, \"hello from project ' // bname // '\"' , & & 'end program main' ] endif call warnwrite ( join_path ( settings % name , 'app/main.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_test ) then ! create NAME/test or stop call mkdir ( join_path ( settings % name , 'test' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[[test]] ' ,& & ' ' ,& & ' # The same declarations can be made for test programs, which are ' ,& & ' # executed with the \"fpm test\" command and are not build when your ' ,& & ' # package is used as a dependency by other packages. These are ' ,& & ' # typically unit tests of the package only used during package ' ,& & ' # development. ' ,& & ' ' ,& & 'name=\"runTests\" ' ,& & 'source-dir=\"test\" ' ,& & 'main=\"check.f90\" ' ,& & ' ' ,& & ' # you may repeat this pattern to add additional explicit test program ' ,& & ' # parameters. The following example contains a sample of all accepted ' ,& & ' # options. ' ,& & ' ' ,& & '#[[ test ]] ' ,& & '#name = \"tester\" ' ,& & '#source-dir=\"test\" ' ,& & '#main=\"tester.f90\" ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '#[test.dependencies] ' ,& & '#M_CLI2 = { git = \"https://github.com/urbanjost/M_CLI2.git\" } ' ,& & '#M_io = { git = \"https://github.com/urbanjost/M_io.git\" } ' ,& & '#M_system= { git = \"https://github.com/urbanjost/M_system.git\" } ' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program check' , & & 'implicit none' , & & '' , & & 'print *, \"Put some tests in here!\"' , & & 'end program check' ] ! create NAME/test/check.f90 call warnwrite ( join_path ( settings % name , 'test/check.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_example ) then ! create NAME/example or stop call mkdir ( join_path ( settings % name , 'example' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[[example]] ' ,& & ' ' ,& & ' # Example applications for a project are defined here. ' ,& & ' # These are run via \"fpm run --example NAME\" and like the ' ,& & ' # test applications, are not built when this package is used as a ' ,& & ' # dependency by other packages. ' ,& & ' ' ,& & 'name=\"demo\" ' ,& & 'source-dir=\"example\" ' ,& & 'main=\"demo.f90\" ' ,& & ' ' ,& & ' # ' ,& & ' # you may add additional programs to the example table. The following ' ,& & ' # example contains a sample of all accepted options ' ,& & ' ' ,& & '#[[ example ]] ' ,& & '#name = \"example-tool\" ' ,& & '#source-dir=\"example\" ' ,& & '#main=\"tool.f90\" ' ,& & '#link = \"z\" ' ,& & '#[example.dependencies] ' ,& & '#M_kracken95 = { git = \"https://github.com/urbanjost/M_kracken95.git\" } ' ,& & '#datetime = {git = \"https://github.com/wavebitscientific/datetime-fortran.git\" }' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program demo' , & & 'implicit none' , & & '' , & & 'print *, \"Put some examples in here!\"' , & & 'end program demo' ] ! create NAME/example/demo.f90 call warnwrite ( join_path ( settings % name , 'example/demo.f90' ), littlefile ) endif ! now that built it write NAME/fpm.toml if ( allocated ( tomlfile ) ) then call validate_toml_data ( tomlfile ) call warnwrite ( join_path ( settings % name , 'fpm.toml' ), tomlfile ) else call create_verified_basic_manifest ( join_path ( settings % name , 'fpm.toml' )) endif ! assumes git(1) is installed and in path if ( which ( 'git' ) /= '' ) then call run ( 'git init ' // settings % name ) endif contains function git_metadata ( what ) result ( returned ) !> get metadata values such as email address and git name from git(1) or return appropriate default use fpm_filesystem , only : get_temp_filename , getline character ( len =* ), intent ( in ) :: what ! keyword designating what git metatdata to query character ( len = :), allocatable :: returned ! value to return for requested keyword character ( len = :), allocatable :: command character ( len = :), allocatable :: temp_filename character ( len = :), allocatable :: iomsg character ( len = :), allocatable :: temp_value integer :: stat , unit temp_filename = get_temp_filename () ! for known keywords set default value for RETURNED and associated git(1) command for query select case ( what ) case ( 'uname' ) returned = \"Jane Doe\" command = \"git config --get user.name > \" // temp_filename case ( 'email' ) returned = \"jane.doe@example.com\" command = \"git config --get user.email > \" // temp_filename case default write ( stderr , '(*(g0,1x))' )& & ' *git_metadata* unknown metadata name ' , trim ( what ) returned = '' return end select ! Execute command if git(1) is in command path if ( which ( 'git' ) /= '' ) then call run ( command , exitstat = stat ) if ( stat /= 0 ) then ! If command failed just return default return else ! Command did not return an error so try to read expected output file open ( file = temp_filename , newunit = unit , iostat = stat ) if ( stat == 0 ) then ! Read file into a scratch variable until status of doing so is checked call getline ( unit , temp_value , stat , iomsg ) if ( stat == 0 . and . temp_value /= '' ) then ! Return output from successful command returned = temp_value endif endif ! Always do the CLOSE because a failed open has unpredictable results. ! Add IOSTAT so a failed close does not cause program to stop close ( unit , status = \"delete\" , iostat = stat ) endif endif end function git_metadata subroutine create_verified_basic_manifest ( filename ) !> create a basic but verified default manifest file use fpm_toml , only : toml_table , toml_serialize , set_value use fpm_manifest_package , only : package_config_t , new_package use fpm_error , only : error_t implicit none character ( len =* ), intent ( in ) :: filename type ( toml_table ) :: table type ( package_config_t ) :: package type ( error_t ), allocatable :: error integer :: lun character ( len = 8 ) :: date character (:), allocatable :: output if ( exists ( filename )) then write ( stderr , '(*(g0,1x))' ) ' ' , filename ,& & 'already exists. Not overwriting' return endif !> get date to put into metadata in manifest file \"fpm.toml\" call date_and_time ( DATE = date ) table = toml_table () call fileopen ( filename , lun ) ! fileopen stops on error call set_value ( table , \"name\" , BNAME ) call set_value ( table , \"version\" , \"0.1.0\" ) call set_value ( table , \"license\" , \"license\" ) call set_value ( table , \"author\" , git_metadata ( 'uname' )) call set_value ( table , \"maintainer\" , git_metadata ( 'email' )) call set_value ( table , \"copyright\" , 'Copyright ' // date ( 1 : 4 ) // ', ' // git_metadata ( 'uname' )) ! continue building of manifest ! ... call new_package ( package , table , error = error ) if ( allocated ( error )) call fpm_stop ( 3 , '' ) output = toml_serialize ( table ) if ( settings % verbose ) then print '(a)' , output endif write ( lun , '(a)' ) output call fileclose ( lun ) ! fileopen stops on error end subroutine create_verified_basic_manifest subroutine validate_toml_data ( input ) !> verify a string array is a valid fpm.toml file ! use tomlf , only : toml_load use fpm_toml , only : toml_table , toml_serialize implicit none character ( kind = tfc , len = :), intent ( in ), allocatable :: input (:) character ( len = 1 ), parameter :: nl = new_line ( 'a' ) type ( toml_table ), allocatable :: table character ( kind = tfc , len = :), allocatable :: joined_string ! you have to add a newline character by using the intrinsic ! function `new_line(\"a\")` to get the lines processed correctly. joined_string = join ( input , right = nl ) if ( allocated ( table )) deallocate ( table ) call toml_load ( table , joined_string ) if ( allocated ( table )) then if ( settings % verbose ) then ! If the TOML file is successfully parsed the table will be allocated and ! can be written by `toml_serialize` to the standard output print '(a)' , toml_serialize ( table ) endif call table % destroy endif end subroutine validate_toml_data end subroutine cmd_new end module fpm_cmd_new","tags":"","loc":"sourcefile/new.f90.html"},{"title":"publish.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_cmd_publish Source Code publish.f90 Source Code !> Upload a package to the registry using the `publish` command. !> !> To upload a package you need to provide a token that will be linked to your username and created for a namespace. !> The token can be obtained from the registry website. It can be used as `fpm publish --token `. module fpm_cmd_publish use fpm_command_line , only : fpm_publish_settings use fpm_manifest , only : package_config_t , get_package_data use fpm_model , only : fpm_model_t use fpm_error , only : error_t , fpm_stop use fpm_versioning , only : version_t use fpm_filesystem , only : exists , join_path , get_temp_filename , delete_file use fpm_git , only : git_archive use fpm_downloader , only : downloader_t use fpm_strings , only : string_t use fpm_settings , only : official_registry_base_url use fpm , only : build_model implicit none private public :: cmd_publish contains !> The `publish` command first builds the root package to obtain all the relevant information such as the !> package version. It then creates a tarball of the package and uploads it to the registry. subroutine cmd_publish ( settings ) type ( fpm_publish_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( error_t ), allocatable :: error type ( version_t ), allocatable :: version type ( string_t ), allocatable :: upload_data (:) character ( len = :), allocatable :: tmp_file type ( downloader_t ) :: downloader integer :: i ! Get package data to determine package version. call get_package_data ( package , 'fpm.toml' , error , apply_defaults = . true .) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_build* Package error: ' // error % message ) version = package % version if ( settings % show_package_version ) then print * , version % s (); return end if !> Checks before uploading the package. if (. not . allocated ( package % license )) call fpm_stop ( 1 , 'No license specified in fpm.toml.' ) if (. not . package % build % module_naming ) call fpm_stop ( 1 , 'The package does not meet the module naming requirements. ' // & & 'Please set \"module-naming = true\" in fpm.toml [build] or specify a custom module prefix.' ) if (. not . allocated ( version )) call fpm_stop ( 1 , 'No version specified in fpm.toml.' ) if ( version % s () == '0' ) call fpm_stop ( 1 , 'Invalid version: \"' // version % s () // '\".' ) if (. not . exists ( 'fpm.toml' )) call fpm_stop ( 1 , \"Cannot find 'fpm.toml' file. Are you in the project root?\" ) ! Build model to obtain dependency tree. call build_model ( model , settings % fpm_build_settings , package , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_build* Model error: ' // error % message ) ! Check if package contains git dependencies. Only publish packages without git dependencies. do i = 1 , model % deps % ndep if ( allocated ( model % deps % dep ( i )% git )) then call fpm_stop ( 1 , 'Do not publish packages containing git dependencies. ' // & & \"Please upload '\" // model % deps % dep ( i )% name // \"' to the registry first.\" ) end if end do tmp_file = get_temp_filename () call git_archive ( '.' , tmp_file , 'HEAD' , settings % verbose , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_publish* Archive error: ' // error % message ) upload_data = [ & & string_t ( 'package_name=\"' // package % name // '\"' ), & & string_t ( 'package_license=\"' // package % license // '\"' ), & & string_t ( 'package_version=\"' // version % s () // '\"' ), & & string_t ( 'tarball=@\"' // tmp_file // '\"' ) & & ] if ( allocated ( settings % token )) upload_data = [ upload_data , string_t ( 'upload_token=\"' // settings % token // '\"' )] if ( settings % show_upload_data ) then call print_upload_data ( upload_data ); return end if ! Make sure a token is provided for publishing. if ( allocated ( settings % token )) then if ( settings % token == '' ) then call delete_file ( tmp_file ); call fpm_stop ( 1 , 'No token provided.' ) end if else call delete_file ( tmp_file ); call fpm_stop ( 1 , 'No token provided.' ) end if if ( settings % verbose ) then call print_upload_data ( upload_data ) print * , '' end if ! Perform network request and validate package, token etc. on the backend once ! https://github.com/fortran-lang/registry/issues/41 is resolved. if ( settings % is_dry_run ) then print * , 'Dry run successful. Generated tarball: ' , tmp_file ; return end if call downloader % upload_form ( official_registry_base_url // '/packages' , upload_data , settings % verbose , error ) call delete_file ( tmp_file ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_publish* Upload error: ' // error % message ) end subroutine print_upload_data ( upload_data ) type ( string_t ), intent ( in ) :: upload_data (:) integer :: i print * , 'Upload data:' do i = 1 , size ( upload_data ) print * , upload_data ( i )% s end do end end","tags":"","loc":"sourcefile/publish.f90.html"},{"title":"install.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_install Source Code install.f90 Source Code !> Implementation of the installation configuration. !> !> An install table can currently have the following fields !> !>```toml !>library = bool !>``` module fpm_manifest_install use fpm_error , only : error_t , fatal_error , syntax_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value implicit none private public :: install_config_t , new_install_config !> Configuration data for installation type :: install_config_t !> Install library with this project logical :: library contains !> Print information on this instance procedure :: info end type install_config_t contains !> Create a new installation configuration from a TOML data structure subroutine new_install_config ( self , table , error ) !> Instance of the install configuration type ( install_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"library\" , self % library , . false .) end subroutine new_install_config !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in install table\" ) exit case ( \"library\" ) continue end select end do if ( allocated ( error )) return end subroutine check !> Write information on install configuration instance subroutine info ( self , unit , verbosity ) !> Instance of the build configuration class ( install_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Install configuration\" write ( unit , fmt ) \" - library install\" , & & trim ( merge ( \"enabled \" , \"disabled\" , self % library )) end subroutine info end module fpm_manifest_install","tags":"","loc":"sourcefile/install.f90.html"},{"title":"example.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_example Source Code example.f90 Source Code !> Implementation of the meta data for an example. !> !> The example data structure is effectively a decorated version of an executable !> and shares most of its properties, except for the defaults and can be !> handled under most circumstances just like any other executable. !> !> A example table can currently have the following fields !> !>```toml !>[[ example ]] !>name = \"string\" !>source-dir = \"path\" !>main = \"file\" !>link = [\"lib\"] !>[example.dependencies] !>``` module fpm_manifest_example use fpm_manifest_dependency , only : dependency_config_t , new_dependencies use fpm_manifest_executable , only : executable_config_t use fpm_error , only : error_t , syntax_error , bad_name_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: example_config_t , new_example !> Configuation meta data for an example type , extends ( executable_config_t ) :: example_config_t contains !> Print information on this instance procedure :: info end type example_config_t contains !> Construct a new example configuration from a TOML data structure subroutine new_example ( self , table , error ) !> Instance of the example configuration type ( example_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve example name\" ) return end if if ( bad_name_error ( error , 'example' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"example\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_example !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Example section does not provide sufficient entries\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in example entry\" ) exit case ( \"name\" ) name_present = . true . case ( \"source-dir\" , \"main\" , \"dependencies\" , \"link\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Example name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the example configuration class ( example_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Example target\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % source_dir )) then if ( self % source_dir /= \"example\" . or . pr > 2 ) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if end if if ( allocated ( self % main )) then if ( self % main /= \"main.f90\" . or . pr > 2 ) then write ( unit , fmt ) \"- example source\" , self % main end if end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info end module fpm_manifest_example","tags":"","loc":"sourcefile/example.f90.html"},{"title":"test.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_test Source Code test.f90 Source Code !> Implementation of the meta data for a test. !> !> The test data structure is effectively a decorated version of an executable !> and shares most of its properties, except for the defaults and can be !> handled under most circumstances just like any other executable. !> !> A test table can currently have the following fields !> !>```toml !>[[ test ]] !>name = \"string\" !>source-dir = \"path\" !>main = \"file\" !>link = [\"lib\"] !>[test.dependencies] !>``` module fpm_manifest_test use fpm_manifest_dependency , only : new_dependencies use fpm_manifest_executable , only : executable_config_t use fpm_error , only : error_t , syntax_error , bad_name_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: test_config_t , new_test !> Configuation meta data for an test type , extends ( executable_config_t ) :: test_config_t contains !> Print information on this instance procedure :: info end type test_config_t contains !> Construct a new test configuration from a TOML data structure subroutine new_test ( self , table , error ) !> Instance of the test configuration type ( test_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve test name\" ) return end if if ( bad_name_error ( error , 'test' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"test\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_test !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Test section does not provide sufficient entries\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in test entry\" ) exit case ( \"name\" ) name_present = . true . case ( \"source-dir\" , \"main\" , \"dependencies\" , \"link\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Test name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the test configuration class ( test_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Test target\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % source_dir )) then if ( self % source_dir /= \"test\" . or . pr > 2 ) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if end if if ( allocated ( self % main )) then if ( self % main /= \"main.f90\" . or . pr > 2 ) then write ( unit , fmt ) \"- test source\" , self % main end if end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info end module fpm_manifest_test","tags":"","loc":"sourcefile/test.f90.html"},{"title":"fortran.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_fortran Source Code fortran.f90 Source Code module fpm_manifest_fortran use fpm_error , only : error_t , syntax_error , fatal_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value implicit none private public :: fortran_config_t , new_fortran_config !> Configuration data for Fortran type :: fortran_config_t !> Enable default implicit typing logical :: implicit_typing !> Enable implicit external interfaces logical :: implicit_external !> Form to use for all Fortran sources character (:), allocatable :: source_form end type fortran_config_t contains !> Construct a new build configuration from a TOML data structure subroutine new_fortran_config ( self , table , error ) !> Instance of the fortran configuration type ( fortran_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character (:), allocatable :: source_form call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"implicit-typing\" , self % implicit_typing , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-typing' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"implicit-external\" , self % implicit_external , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-external' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"source-form\" , source_form , \"free\" , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'source-form' in fpm.toml, expecting logical\" ) return end if select case ( source_form ) case default call fatal_error ( error , \"Value of source-form cannot be '\" // source_form // \"'\" ) return case ( \"free\" , \"fixed\" , \"default\" ) self % source_form = source_form end select end subroutine new_fortran_config !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) ! table can be empty if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case ( \"implicit-typing\" , \"implicit-external\" , \"source-form\" ) continue case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in fortran\" ) exit end select end do end subroutine check end module fpm_manifest_fortran","tags":"","loc":"sourcefile/fortran.f90.html"},{"title":"dependency.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_dependency Source Code dependency.f90 Source Code !> Implementation of the meta data for dependencies. !> !> A dependency table can currently have the following fields !> !>```toml !>[dependencies] !>\"dep1\" = { git = \"url\" } !>\"dep2\" = { git = \"url\", branch = \"name\" } !>\"dep3\" = { git = \"url\", tag = \"name\" } !>\"dep4\" = { git = \"url\", rev = \"sha1\" } !>\"dep0\" = { path = \"path\" } !>``` !> !> To reduce the amount of boilerplate code this module provides two constructors !> for dependency types, one basic for an actual dependency (inline) table !> and another to collect all dependency objects from a dependencies table, !> which is handling the allocation of the objects and is forwarding the !> individual dependency tables to their respective constructors. !> The usual entry point should be the constructor for the super table. !> !> This objects contains a target to retrieve required `fpm` projects to !> build the target declaring the dependency. !> Resolving a dependency will result in obtaining a new package configuration !> data for the respective project. module fpm_manifest_dependency use fpm_error , only : error_t , syntax_error use fpm_git , only : git_target_t , git_target_tag , git_target_branch , & & git_target_revision , git_target_default , operator ( == ), git_matches_manifest use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , check_keys use fpm_filesystem , only : windows_path , join_path use fpm_environment , only : get_os_type , OS_WINDOWS use fpm_manifest_metapackages , only : metapackage_config_t , is_meta_package , new_meta_config , & metapackage_request_t , new_meta_request use fpm_versioning , only : version_t , new_version use fpm_strings , only : string_t use fpm_manifest_preprocess implicit none private public :: dependency_config_t , new_dependency , new_dependencies , manifest_has_changed !> Configuration meta data for a dependency type :: dependency_config_t !> Name of the dependency character ( len = :), allocatable :: name !> Local target character ( len = :), allocatable :: path !> Namespace which the dependency belongs to. !> Enables multiple dependencies with the same name. !> Required for dependencies that are obtained via the official registry. character ( len = :), allocatable :: namespace !> The requested version of the dependency. !> The latest version is used if not specified. type ( version_t ), allocatable :: requested_version !> Requested macros for the dependency type ( preprocess_config_t ), allocatable :: preprocess (:) !> Git descriptor type ( git_target_t ), allocatable :: git contains !> Print information on this instance procedure :: info end type dependency_config_t !> Common output format for writing to the command line character ( len =* ), parameter :: out_fmt = '(\"#\", *(1x, g0))' contains !> Construct a new dependency configuration from a TOML data structure subroutine new_dependency ( self , table , root , error ) !> Instance of the dependency configuration type ( dependency_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: uri , value , requested_version type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_value ( table , \"namespace\" , self % namespace ) call get_value ( table , \"v\" , requested_version ) if ( allocated ( requested_version )) then if (. not . allocated ( self % requested_version )) allocate ( self % requested_version ) call new_version ( self % requested_version , requested_version , error ) if ( allocated ( error )) return end if !> Get optional preprocessor directives call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return endif call get_value ( table , \"path\" , uri ) if ( allocated ( uri )) then if ( get_os_type () == OS_WINDOWS ) uri = windows_path ( uri ) if ( present ( root )) uri = join_path ( root , uri ) ! Relative to the fpm.toml it’s written in call move_alloc ( uri , self % path ) return end if call get_value ( table , \"git\" , uri ) if ( allocated ( uri )) then call get_value ( table , \"tag\" , value ) if ( allocated ( value )) then self % git = git_target_tag ( uri , value ) end if if (. not . allocated ( self % git )) then call get_value ( table , \"branch\" , value ) if ( allocated ( value )) then self % git = git_target_branch ( uri , value ) end if end if if (. not . allocated ( self % git )) then call get_value ( table , \"rev\" , value ) if ( allocated ( value )) then self % git = git_target_revision ( uri , value ) end if end if if (. not . allocated ( self % git )) then self % git = git_target_default ( uri ) end if return end if end subroutine new_dependency !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: name type ( toml_key ), allocatable :: list (:) type ( toml_table ), pointer :: child !> List of valid keys for the dependency table. character ( * ), dimension ( * ), parameter :: valid_keys = [ character ( 24 ) :: & & \"namespace\" , & \"v\" , & \"path\" , & \"git\" , & \"tag\" , & \"branch\" , & \"rev\" , & \"preprocess\" & & ] call table % get_key ( name ) call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Dependency '\" // name // \"' does not provide sufficient entries\" ) return end if call check_keys ( table , valid_keys , error ) if ( allocated ( error )) return if ( table % has_key ( \"path\" ) . and . table % has_key ( \"git\" )) then call syntax_error ( error , \"Dependency '\" // name // \"' cannot have both git and path entries\" ) return end if if (( table % has_key ( \"branch\" ) . and . table % has_key ( \"rev\" )) . or . & ( table % has_key ( \"branch\" ) . and . table % has_key ( \"tag\" )) . or . & ( table % has_key ( \"rev\" ) . and . table % has_key ( \"tag\" ))) then call syntax_error ( error , \"Dependency '\" // name // \"' can only have one of branch, rev or tag present\" ) return end if if (( table % has_key ( \"branch\" ) . or . table % has_key ( \"tag\" ) . or . table % has_key ( \"rev\" )) & . and . . not . table % has_key ( \"git\" )) then call syntax_error ( error , \"Dependency '\" // name // \"' has git identifier but no git url\" ) return end if if (. not . table % has_key ( \"path\" ) . and . . not . table % has_key ( \"git\" ) & . and . . not . table % has_key ( \"namespace\" )) then call syntax_error ( error , \"Please provide a 'namespace' for dependency '\" // name // & & \"' if it is not a local path or git repository\" ) return end if if ( table % has_key ( 'v' ) . and . ( table % has_key ( 'path' ) . or . table % has_key ( 'git' ))) then call syntax_error ( error , \"Dependency '\" // name // \"' cannot have both v and git/path entries\" ) return end if ! Check preprocess key if ( table % has_key ( 'preprocess' )) then call get_value ( table , 'preprocess' , child ) if (. not . associated ( child )) then call syntax_error ( error , \"Dependency '\" // name // \"' has invalid 'preprocess' entry\" ) return end if end if end subroutine check !> Construct new dependency array from a TOML data structure subroutine new_dependencies ( deps , table , root , meta , error ) !> Instance of the dependency configuration type ( dependency_config_t ), allocatable , intent ( out ) :: deps (:) !> (optional) metapackages type ( metapackage_config_t ), optional , intent ( out ) :: meta !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) type ( dependency_config_t ), allocatable :: all_deps (:) type ( metapackage_request_t ) :: meta_request logical , allocatable :: is_meta (:) logical :: metapackages_allowed integer :: idep , stat , ndep call table % get_keys ( list ) ! An empty table is okay if ( size ( list ) < 1 ) return !> Flag dependencies that should be treated as metapackages metapackages_allowed = present ( meta ) allocate ( is_meta ( size ( list )), source = . false .) allocate ( all_deps ( size ( list ))) !> Parse all meta- and non-metapackage dependencies do idep = 1 , size ( list ) ! Check if this is a standard dependency node call get_value ( table , list ( idep )% key , node , stat = stat ) is_standard_dependency : if ( stat /= toml_stat % success ) then ! See if it can be a valid metapackage name call new_meta_request ( meta_request , list ( idep )% key , table , error = error ) !> Neither a standard dep nor a metapackage if ( allocated ( error )) then call syntax_error ( error , \"Dependency \" // list ( idep )% key // \" is not a valid metapackage or a table entry\" ) return endif !> Valid meta dependency is_meta ( idep ) = . true . else ! Parse as a standard dependency is_meta ( idep ) = . false . call new_dependency ( all_deps ( idep ), node , root , error ) if ( allocated ( error )) return end if is_standard_dependency end do ! Non-meta dependencies ndep = count (. not . is_meta ) ! Finalize standard dependencies allocate ( deps ( ndep )) ndep = 0 do idep = 1 , size ( list ) if ( is_meta ( idep )) cycle ndep = ndep + 1 deps ( ndep ) = all_deps ( idep ) end do ! Finalize meta dependencies if ( metapackages_allowed ) call new_meta_config ( meta , table , is_meta , error ) end subroutine new_dependencies !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the dependency configuration class ( dependency_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if write ( unit , fmt ) \"Dependency\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % git )) then write ( unit , fmt ) \"- kind\" , \"git\" call self % git % info ( unit , pr - 1 ) end if if ( allocated ( self % path )) then write ( unit , fmt ) \"- kind\" , \"local\" write ( unit , fmt ) \"- path\" , self % path end if end subroutine info !> Check if two dependency configurations are different logical function manifest_has_changed ( cached , manifest , verbosity , iunit ) result ( has_changed ) !> Two instances of the dependency configuration class ( dependency_config_t ), intent ( in ) :: cached , manifest !> Log verbosity integer , intent ( in ) :: verbosity , iunit has_changed = . true . !> Perform all checks if ( allocated ( cached % git ). neqv . allocated ( manifest % git )) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT presence has changed. \" return endif if ( allocated ( cached % git )) then if (. not . git_matches_manifest ( cached % git , manifest % git , verbosity , iunit )) return end if !> All checks passed! The two instances are equal has_changed = . false . end function manifest_has_changed end module fpm_manifest_dependency","tags":"","loc":"sourcefile/dependency.f90~2.html"},{"title":"package.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_package Source Code package.f90 Source Code !> Define the package data containing the meta data from the configuration file. !> !> The package data defines a Fortran type corresponding to the respective !> TOML document, after creating it from a package file no more interaction !> with the TOML document is required. !> !> Every configuration type provides it custom constructor (prefixed with `new_`) !> and knows how to deserialize itself from a TOML document. !> To ensure we find no untracked content in the package file all keywords are !> checked and possible entries have to be explicitly allowed in the `check` !> function. !> If entries are mutally exclusive or interdependent inside the current table !> the `check` function is required to enforce this schema on the data structure. !> !> The package file root allows the following keywords !> !>```toml !>name = \"string\" !>version = \"string\" !>license = \"string\" !>author = \"string\" !>maintainer = \"string\" !>copyright = \"string\" !>[library] !>[dependencies] !>[dev-dependencies] !>[profiles] !>[build] !>[install] !>[fortran] !>[[ executable ]] !>[[ example ]] !>[[ test ]] !>[extra] !>``` module fpm_manifest_package use fpm_manifest_build , only : build_config_t , new_build_config use fpm_manifest_dependency , only : dependency_config_t , new_dependencies use fpm_manifest_profile , only : profile_config_t , new_profiles , get_default_profiles use fpm_manifest_example , only : example_config_t , new_example use fpm_manifest_executable , only : executable_config_t , new_executable use fpm_manifest_fortran , only : fortran_config_t , new_fortran_config use fpm_manifest_library , only : library_config_t , new_library use fpm_manifest_install , only : install_config_t , new_install_config use fpm_manifest_test , only : test_config_t , new_test use fpm_manifest_preprocess , only : preprocess_config_t , new_preprocessors use fpm_manifest_metapackages , only : metapackage_config_t , new_meta_config use fpm_filesystem , only : exists , getline , join_path use fpm_error , only : error_t , fatal_error , syntax_error , bad_name_error use fpm_toml , only : toml_table , toml_array , toml_key , toml_stat , get_value , len use fpm_versioning , only : version_t , new_version implicit none private public :: package_config_t , new_package interface unique_programs module procedure :: unique_programs1 module procedure :: unique_programs2 end interface unique_programs !> Package meta data type :: package_config_t !> Name of the package character ( len = :), allocatable :: name !> Package version type ( version_t ) :: version !> Build configuration data type ( build_config_t ) :: build !> Metapackage data type ( metapackage_config_t ) :: meta !> Installation configuration data type ( install_config_t ) :: install !> Fortran meta data type ( fortran_config_t ) :: fortran !> License meta data character ( len = :), allocatable :: license !> Library meta data type ( library_config_t ), allocatable :: library !> Executable meta data type ( executable_config_t ), allocatable :: executable (:) !> Dependency meta data type ( dependency_config_t ), allocatable :: dependency (:) !> Development dependency meta data type ( dependency_config_t ), allocatable :: dev_dependency (:) !> Profiles meta data type ( profile_config_t ), allocatable :: profiles (:) !> Example meta data type ( example_config_t ), allocatable :: example (:) !> Test meta data type ( test_config_t ), allocatable :: test (:) !> Preprocess meta data type ( preprocess_config_t ), allocatable :: preprocess (:) contains !> Print information on this instance procedure :: info end type package_config_t contains !> Construct a new package configuration from a TOML data structure subroutine new_package ( self , table , root , error ) !> Instance of the package configuration type ( package_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( len =* ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error ! Backspace (8), tabulator (9), newline (10), formfeed (12) and carriage ! return (13) are invalid in package names character ( len =* ), parameter :: invalid_chars = & achar ( 8 ) // achar ( 9 ) // achar ( 10 ) // achar ( 12 ) // achar ( 13 ) type ( toml_table ), pointer :: child , node type ( toml_array ), pointer :: children character ( len = :), allocatable :: version , version_file integer :: ii , nn , stat , io call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve package name\" ) return end if if ( bad_name_error ( error , 'package' , self % name )) then return endif call get_value ( table , \"license\" , self % license ) if ( len ( self % name ) <= 0 ) then call syntax_error ( error , \"Package name must be a non-empty string\" ) return end if ii = scan ( self % name , invalid_chars ) if ( ii > 0 ) then call syntax_error ( error , \"Package name contains invalid characters\" ) return end if call get_value ( table , \"build\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for build entry, must be a table\" ) return end if call new_build_config ( self % build , child , self % name , error ) if ( allocated ( error )) return call get_value ( table , \"install\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for install entry, must be a table\" ) return end if call new_install_config ( self % install , child , error ) if ( allocated ( error )) return call get_value ( table , \"fortran\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for fortran entry, must be a table\" ) return end if call new_fortran_config ( self % fortran , child , error ) if ( allocated ( error )) return call get_value ( table , \"version\" , version , \"0\" ) call new_version ( self % version , version , error ) if ( allocated ( error ) . and . present ( root )) then version_file = join_path ( root , version ) if ( exists ( version_file )) then deallocate ( error ) open ( file = version_file , newunit = io , iostat = stat ) if ( stat == 0 ) then call getline ( io , version , iostat = stat ) end if if ( stat == 0 ) then close ( io , iostat = stat ) end if if ( stat == 0 ) then call new_version ( self % version , version , error ) else call fatal_error ( error , \"Reading version number from file '\" & & // version_file // \"' failed\" ) end if end if end if if ( allocated ( error )) return call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , root , self % meta , error ) if ( allocated ( error )) return end if call get_value ( table , \"dev-dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dev_dependency , child , root , error = error ) if ( allocated ( error )) return end if call get_value ( table , \"library\" , child , requested = . false .) if ( associated ( child )) then allocate ( self % library ) call new_library ( self % library , child , error ) if ( allocated ( error )) return end if call get_value ( table , \"profiles\" , child , requested = . false .) if ( associated ( child )) then call new_profiles ( self % profiles , child , error ) if ( allocated ( error )) return else self % profiles = get_default_profiles ( error ) if ( allocated ( error )) return end if call get_value ( table , \"executable\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % executable ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve executable from array entry\" ) exit end if call new_executable ( self % executable ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % executable , error ) if ( allocated ( error )) return end if call get_value ( table , \"example\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % example ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve example from array entry\" ) exit end if call new_example ( self % example ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % example , error ) if ( allocated ( error )) return if ( allocated ( self % executable )) then call unique_programs ( self % executable , self % example , error ) if ( allocated ( error )) return end if end if call get_value ( table , \"test\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % test ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve test from array entry\" ) exit end if call new_test ( self % test ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % test , error ) if ( allocated ( error )) return end if call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return end if end subroutine new_package !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Package file is empty\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in package file\" ) exit case ( \"name\" ) name_present = . true . case ( \"version\" , \"license\" , \"author\" , \"maintainer\" , \"copyright\" , & & \"description\" , \"keywords\" , \"categories\" , \"homepage\" , \"build\" , & & \"dependencies\" , \"dev-dependencies\" , \"profiles\" , \"test\" , \"executable\" , & & \"example\" , \"library\" , \"install\" , \"extra\" , \"preprocess\" , \"fortran\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Package name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the package configuration class ( package_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Package\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if call self % build % info ( unit , pr - 1 ) call self % install % info ( unit , pr - 1 ) if ( allocated ( self % library )) then write ( unit , fmt ) \"- target\" , \"archive\" call self % library % info ( unit , pr - 1 ) end if if ( allocated ( self % executable )) then if ( size ( self % executable ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- executables\" , size ( self % executable ) end if do ii = 1 , size ( self % executable ) call self % executable ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % example )) then if ( size ( self % example ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- examples\" , size ( self % example ) end if do ii = 1 , size ( self % example ) call self % example ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % test )) then if ( size ( self % test ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- tests\" , size ( self % test ) end if do ii = 1 , size ( self % test ) call self % test ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % dev_dependency )) then if ( size ( self % dev_dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- development deps.\" , size ( self % dev_dependency ) end if do ii = 1 , size ( self % dev_dependency ) call self % dev_dependency ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % profiles )) then if ( size ( self % profiles ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- profiles\" , size ( self % profiles ) end if do ii = 1 , size ( self % profiles ) call self % profiles ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info !> Check whether or not the names in a set of executables are unique subroutine unique_programs1 ( executable , error ) !> Array of executables class ( executable_config_t ), intent ( in ) :: executable (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j do i = 1 , size ( executable ) do j = 1 , i - 1 if ( executable ( i )% name == executable ( j )% name ) then call fatal_error ( error , \"The program named '\" // & executable ( j )% name // \"' is duplicated. \" // & \"Unique program names are required.\" ) exit end if end do end do if ( allocated ( error )) return end subroutine unique_programs1 !> Check whether or not the names in a set of executables are unique subroutine unique_programs2 ( executable_i , executable_j , error ) !> Array of executables class ( executable_config_t ), intent ( in ) :: executable_i (:) !> Array of executables class ( executable_config_t ), intent ( in ) :: executable_j (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j do i = 1 , size ( executable_i ) do j = 1 , size ( executable_j ) if ( executable_i ( i )% name == executable_j ( j )% name ) then call fatal_error ( error , \"The program named '\" // & executable_j ( j )% name // \"' is duplicated. \" // & \"Unique program names are required.\" ) exit end if end do end do if ( allocated ( error )) return end subroutine unique_programs2 end module fpm_manifest_package","tags":"","loc":"sourcefile/package.f90.html"},{"title":"executable.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_executable Source Code executable.f90 Source Code !> Implementation of the meta data for an executables. !> !> An executable table can currently have the following fields !> !>```toml !>[[ executable ]] !>name = \"string\" !>source-dir = \"path\" !>main = \"file\" !>link = [\"lib\"] !>[executable.dependencies] !>``` module fpm_manifest_executable use fpm_manifest_dependency , only : dependency_config_t , new_dependencies use fpm_error , only : error_t , syntax_error , bad_name_error use fpm_strings , only : string_t use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: executable_config_t , new_executable !> Configuation meta data for an executable type :: executable_config_t !> Name of the resulting executable character ( len = :), allocatable :: name !> Source directory for collecting the executable character ( len = :), allocatable :: source_dir !> Name of the source file declaring the main program character ( len = :), allocatable :: main !> Dependency meta data for this executable type ( dependency_config_t ), allocatable :: dependency (:) !> Libraries to link against type ( string_t ), allocatable :: link (:) contains !> Print information on this instance procedure :: info end type executable_config_t contains !> Construct a new executable configuration from a TOML data structure subroutine new_executable ( self , table , error ) !> Instance of the executable configuration type ( executable_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve executable name\" ) return end if if ( bad_name_error ( error , 'executable' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"app\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_executable !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Executable section does not provide sufficient entries\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed as executable entry\" ) exit case ( \"name\" ) name_present = . true . case ( \"source-dir\" , \"main\" , \"dependencies\" , \"link\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Executable name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the executable configuration class ( executable_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Executable target\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % source_dir )) then if ( self % source_dir /= \"app\" . or . pr > 2 ) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if end if if ( allocated ( self % main )) then if ( self % main /= \"main.f90\" . or . pr > 2 ) then write ( unit , fmt ) \"- program source\" , self % main end if end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info end module fpm_manifest_executable","tags":"","loc":"sourcefile/executable.f90.html"},{"title":"meta.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_metapackages Source Code meta.f90 Source Code !> Implementation of the metapackage configuration data. !> !> A metapackage table can currently have the following fields !> !>```toml !>[metapackages] !>fpm = \"0.1.0\" !>openmp = bool !>stdlib = bool !>``` module fpm_manifest_metapackages use fpm_error , only : error_t , fatal_error , syntax_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value use fpm_environment implicit none private public :: metapackage_config_t , new_meta_config , is_meta_package public :: metapackage_request_t , new_meta_request !> Configuration data for a single metapackage request type :: metapackage_request_t !> Request flag logical :: on = . false . !> Metapackage name character ( len = :), allocatable :: name !> Version Specification string character ( len = :), allocatable :: version end type metapackage_request_t !> Configuration data for metapackages type :: metapackage_config_t !> Request MPI support type ( metapackage_request_t ) :: mpi !> Request OpenMP support type ( metapackage_request_t ) :: openmp !> Request stdlib support type ( metapackage_request_t ) :: stdlib !> fortran-lang minpack type ( metapackage_request_t ) :: minpack end type metapackage_config_t contains !> Destroy a metapackage request elemental subroutine request_destroy ( self ) !> Instance of the request class ( metapackage_request_t ), intent ( inout ) :: self self % on = . false . if ( allocated ( self % version )) deallocate ( self % version ) if ( allocated ( self % name )) deallocate ( self % name ) end subroutine request_destroy !> Parse version string of a metapackage request subroutine request_parse ( self , version_request , error ) ! Instance of this metapackage type ( metapackage_request_t ), intent ( inout ) :: self ! Parse version request character ( len =* ), intent ( in ) :: version_request ! Error message type ( error_t ), allocatable , intent ( out ) :: error ! wildcard = use any versions if ( version_request == \"*\" ) then ! Any version is OK self % on = . true . self % version = version_request else call fatal_error ( error , 'Value <' // version_request // '> for metapackage ' // self % name // & 'is not currently supported. Try \"*\" instead. ' ) return end if end subroutine request_parse !> Construct a new metapackage request from the dependencies table subroutine new_meta_request ( self , key , table , meta_allowed , error ) type ( metapackage_request_t ), intent ( out ) :: self !> The package name character ( len =* ), intent ( in ) :: key !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ), optional :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: value logical , allocatable :: allow_meta (:) type ( toml_key ), allocatable :: keys (:) call request_destroy ( self ) !> Set name self % name = key if (. not . is_meta_package ( key )) then call fatal_error ( error , \"Error reading fpm.toml: <\" // key // \"> is not a valid metapackage name\" ) return end if !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call table % get_keys ( keys ) !> Set list of entries that are allowed to be metapackages if ( present ( meta_allowed )) then if ( size ( meta_allowed ) /= size ( keys )) then call fatal_error ( error , \"Internal error: list of metapackage-enable entries does not match table size\" ) return end if allow_meta = meta_allowed else allocate ( allow_meta ( size ( keys )), source = . true .) endif do i = 1 , size ( keys ) ! Skip standard dependencies if (. not . allow_meta ( i )) cycle if ( keys ( i )% key == key ) then call get_value ( table , key , value ) if (. not . allocated ( value )) then call syntax_error ( error , \"Could not retrieve version string for metapackage key <\" // key // \">. Check syntax\" ) return else call request_parse ( self , value , error ) return endif end if end do ! Key is not present, metapackage not requested return end subroutine new_meta_request !> Construct a new build configuration from a TOML data structure subroutine new_meta_config ( self , table , meta_allowed , error ) !> Instance of the build configuration type ( metapackage_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ) :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call new_meta_request ( self % openmp , \"openmp\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % stdlib , \"stdlib\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % minpack , \"minpack\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % mpi , \"mpi\" , table , meta_allowed , error ) if ( allocated ( error )) return end subroutine new_meta_config !> Check local schema for allowed entries logical function is_meta_package ( key ) !> Instance of the TOML data structure character ( * ), intent ( in ) :: key select case ( key ) !> Supported metapackages case ( \"openmp\" , \"stdlib\" , \"mpi\" , \"minpack\" ) is_meta_package = . true . case default is_meta_package = . false . end select end function is_meta_package end module fpm_manifest_metapackages","tags":"","loc":"sourcefile/meta.f90.html"},{"title":"library.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_library Source Code library.f90 Source Code !> Implementation of the meta data for libraries. !> !> A library table can currently have the following fields !> !>```toml !>[library] !>source-dir = \"path\" !>include-dir = [\"path1\",\"path2\"] !>build-script = \"file\" !>``` module fpm_manifest_library use fpm_error , only : error_t , syntax_error use fpm_strings , only : string_t , string_cat use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: library_config_t , new_library !> Configuration meta data for a library type :: library_config_t !> Source path prefix character ( len = :), allocatable :: source_dir !> Include path prefix type ( string_t ), allocatable :: include_dir (:) !> Alternative build script to be invoked character ( len = :), allocatable :: build_script contains !> Print information on this instance procedure :: info end type library_config_t contains !> Construct a new library configuration from a TOML data structure subroutine new_library ( self , table , error ) !> Instance of the library configuration type ( library_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"source-dir\" , self % source_dir , \"src\" ) call get_value ( table , \"build-script\" , self % build_script ) call get_list ( table , \"include-dir\" , self % include_dir , error ) if ( allocated ( error )) return ! Set default value of include-dir if not found in manifest if (. not . allocated ( self % include_dir )) then self % include_dir = [ string_t ( \"include\" )] end if end subroutine new_library !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) ! table can be empty if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in library\" ) exit case ( \"source-dir\" , \"include-dir\" , \"build-script\" ) continue end select end do end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the library configuration class ( library_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Library target\" if ( allocated ( self % source_dir )) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if if ( allocated ( self % include_dir )) then write ( unit , fmt ) \"- include directory\" , string_cat ( self % include_dir , \",\" ) end if if ( allocated ( self % build_script )) then write ( unit , fmt ) \"- custom build\" , self % build_script end if end subroutine info end module fpm_manifest_library","tags":"","loc":"sourcefile/library.f90.html"},{"title":"profiles.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_profile Source Code profiles.f90 Source Code !> Implementation of the meta data for compiler flag profiles. !> !> A profiles table can currently have the following subtables: !> Profile names - any string, if omitted, flags are appended to all matching profiles !> Compiler - any from the following list, omitting it yields an error !> !> - \"gfortran\" !> - \"ifort\" !> - \"ifx\" !> - \"pgfortran\" !> - \"nvfortran\" !> - \"flang\" !> - \"caf\" !> - \"f95\" !> - \"lfortran\" !> - \"lfc\" !> - \"nagfor\" !> - \"crayftn\" !> - \"xlf90\" !> - \"ftn95\" !> !> OS - any from the following list, if omitted, the profile is used if and only !> if there is no profile perfectly matching the current configuration !> !> - \"linux\" !> - \"macos\" !> - \"windows\" !> - \"cygwin\" !> - \"solaris\" !> - \"freebsd\" !> - \"openbsd\" !> - \"unknown\" !> !> Each of the subtables currently supports the following fields: !>```toml !>[profiles.debug.gfortran.linux] !> flags=\"-Wall -g -Og\" !> c-flags=\"-g O1\" !> cxx-flags=\"-g O1\" !> link-time-flags=\"-xlinkopt\" !> files={\"hello_world.f90\"=\"-Wall -O3\"} !>``` !> module fpm_manifest_profile use fpm_error , only : error_t , syntax_error , fatal_error , fpm_stop use fpm_toml , only : toml_table , toml_key , toml_stat , get_value use fpm_strings , only : lower use fpm_environment , only : get_os_type , OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_WINDOWS , & OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD use fpm_filesystem , only : join_path implicit none public :: profile_config_t , new_profile , new_profiles , get_default_profiles , & & info_profile , find_profile , DEFAULT_COMPILER !> Name of the default compiler character ( len =* ), parameter :: DEFAULT_COMPILER = 'gfortran' integer , parameter :: OS_ALL = - 1 character ( len = :), allocatable :: path !> Type storing file name - file scope compiler flags pairs type :: file_scope_flag !> Name of the file character ( len = :), allocatable :: file_name !> File scope flags character ( len = :), allocatable :: flags end type file_scope_flag !> Configuration meta data for a profile type :: profile_config_t !> Name of the profile character ( len = :), allocatable :: profile_name !> Name of the compiler character ( len = :), allocatable :: compiler !> Value repesenting OS integer :: os_type !> Fortran compiler flags character ( len = :), allocatable :: flags !> C compiler flags character ( len = :), allocatable :: c_flags !> C++ compiler flags character ( len = :), allocatable :: cxx_flags !> Link time compiler flags character ( len = :), allocatable :: link_time_flags !> File scope flags type ( file_scope_flag ), allocatable :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical :: is_built_in contains !> Print information on this instance procedure :: info end type profile_config_t contains !> Construct a new profile configuration from a TOML data structure function new_profile ( profile_name , compiler , os_type , flags , c_flags , cxx_flags , & link_time_flags , file_scope_flags , is_built_in ) & & result ( profile ) !> Name of the profile character ( len =* ), intent ( in ) :: profile_name !> Name of the compiler character ( len =* ), intent ( in ) :: compiler !> Type of the OS integer , intent ( in ) :: os_type !> Fortran compiler flags character ( len =* ), optional , intent ( in ) :: flags !> C compiler flags character ( len =* ), optional , intent ( in ) :: c_flags !> C++ compiler flags character ( len =* ), optional , intent ( in ) :: cxx_flags !> Link time compiler flags character ( len =* ), optional , intent ( in ) :: link_time_flags !> File scope flags type ( file_scope_flag ), optional , intent ( in ) :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical , optional , intent ( in ) :: is_built_in type ( profile_config_t ) :: profile profile % profile_name = profile_name profile % compiler = compiler profile % os_type = os_type if ( present ( flags )) then profile % flags = flags else profile % flags = \"\" end if if ( present ( c_flags )) then profile % c_flags = c_flags else profile % c_flags = \"\" end if if ( present ( cxx_flags )) then profile % cxx_flags = cxx_flags else profile % cxx_flags = \"\" end if if ( present ( link_time_flags )) then profile % link_time_flags = link_time_flags else profile % link_time_flags = \"\" end if if ( present ( file_scope_flags )) then profile % file_scope_flags = file_scope_flags end if if ( present ( is_built_in )) then profile % is_built_in = is_built_in else profile % is_built_in = . false . end if end function new_profile !> Check if compiler name is a valid compiler name subroutine validate_compiler_name ( compiler_name , is_valid ) !> Name of a compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> Boolean value of whether compiler_name is valid or not logical , intent ( out ) :: is_valid select case ( compiler_name ) case ( \"gfortran\" , \"ifort\" , \"ifx\" , \"pgfortran\" , \"nvfortran\" , \"flang\" , \"caf\" , & & \"f95\" , \"lfortran\" , \"lfc\" , \"nagfor\" , \"crayftn\" , \"xlf90\" , \"ftn95\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_compiler_name !> Check if os_name is a valid name of a supported OS subroutine validate_os_name ( os_name , is_valid ) !> Name of an operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Boolean value of whether os_name is valid or not logical , intent ( out ) :: is_valid select case ( os_name ) case ( \"linux\" , \"macos\" , \"windows\" , \"cygwin\" , \"solaris\" , \"freebsd\" , & & \"openbsd\" , \"unknown\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_os_name !> Match os_type enum to a lowercase string with name of OS subroutine match_os_type ( os_name , os_type ) !> Name of operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Enum representing type of OS integer , intent ( out ) :: os_type select case ( os_name ) case ( \"linux\" ); os_type = OS_LINUX case ( \"macos\" ); os_type = OS_WINDOWS case ( \"cygwin\" ); os_type = OS_CYGWIN case ( \"solaris\" ); os_type = OS_SOLARIS case ( \"freebsd\" ); os_type = OS_FREEBSD case ( \"openbsd\" ); os_type = OS_OPENBSD case ( \"all\" ); os_type = OS_ALL case default ; os_type = OS_UNKNOWN end select end subroutine match_os_type subroutine validate_profile_table ( profile_name , compiler_name , key_list , table , error , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) integer :: ikey , ifile , stat logical :: is_valid if ( size ( key_list ). ge . 1 ) then do ikey = 1 , size ( key_list ) key_name = key_list ( ikey )% key if ( key_name . eq . 'flags' ) then call get_value ( table , 'flags' , flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'c-flags' ) then call get_value ( table , 'c-flags' , c_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"c-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'cxx-flags' ) then call get_value ( table , 'cxx-flags' , cxx_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"cxx-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'link-time-flags' ) then call get_value ( table , 'link-time-flags' , link_time_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"link-time-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'files' ) then call get_value ( table , 'files' , files , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"files has to be a table\" ) return end if call files % get_keys ( file_list ) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"file scope flags has to be a key-value pair\" ) return end if end do else if (. not . os_valid ) then call validate_os_name ( key_name , is_valid ) err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" if (. not . is_valid ) call syntax_error ( error , err_message ) else err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" call syntax_error ( error , err_message ) end if end do end if if ( allocated ( error )) return end subroutine validate_profile_table !> Look for flags, c-flags, link-time-flags key-val pairs !> and files table in a given table and create new profiles subroutine get_flags ( profile_name , compiler_name , os_type , key_list , table , profiles , profindex , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> OS type integer , intent ( in ) :: os_type !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) type ( file_scope_flag ), allocatable :: file_scope_flags (:) integer :: ikey , ifile , stat logical :: is_valid call get_value ( table , 'flags' , flags ) call get_value ( table , 'c-flags' , c_flags ) call get_value ( table , 'cxx-flags' , cxx_flags ) call get_value ( table , 'link-time-flags' , link_time_flags ) call get_value ( table , 'files' , files ) if ( associated ( files )) then call files % get_keys ( file_list ) allocate ( file_scope_flags ( size ( file_list ))) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags ) associate ( cur_file => file_scope_flags ( ifile )) if (. not .( path . eq . \"\" )) file_name = join_path ( path , file_name ) cur_file % file_name = file_name cur_file % flags = file_flags end associate end do end if profiles ( profindex ) = new_profile ( profile_name , compiler_name , os_type , & & flags , c_flags , cxx_flags , link_time_flags , file_scope_flags ) profindex = profindex + 1 end subroutine get_flags !> Traverse operating system tables to obtain number of profiles subroutine traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ) :: profiles_size type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat logical :: is_valid , key_val_added , is_key_val if ( size ( os_list ) < 1 ) return key_val_added = . false . do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) profiles_size = profiles_size + 1 call validate_profile_table ( profile_name , compiler_name , key_list , os_node , error , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table if ( is_key_val . and .. not . key_val_added ) then key_val_added = . true . is_key_val = . false . profiles_size = profiles_size + 1 else if (. not . is_key_val ) then profiles_size = profiles_size + 1 end if call validate_profile_table ( profile_name , compiler_name , os_list , os_node , error , . false .) end if end do end subroutine traverse_oss_for_size !> Traverse operating system tables to obtain profiles subroutine traverse_oss ( profile_name , compiler_name , os_list , table , profiles , profindex , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat , os_type logical :: is_valid , is_key_val if ( size ( os_list ) < 1 ) return do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) call match_os_type ( os_name , os_type ) call get_flags ( profile_name , compiler_name , os_type , key_list , os_node , profiles , profindex , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table os_type = OS_ALL call get_flags ( profile_name , compiler_name , os_type , os_list , os_node , profiles , profindex , . false .) end if end do end subroutine traverse_oss !> Traverse compiler tables subroutine traverse_compilers ( profile_name , comp_list , table , error , profiles_size , profiles , profindex ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> List of OSs in table with profile name given type ( toml_key ), allocatable , intent ( in ) :: comp_list (:) !> Table containing compiler tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ), optional :: profiles_size !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ), optional :: profiles (:) !> Index in the list of profiles integer , intent ( inout ), optional :: profindex character ( len = :), allocatable :: compiler_name type ( toml_table ), pointer :: comp_node type ( toml_key ), allocatable :: os_list (:) integer :: icomp , stat logical :: is_valid if ( size ( comp_list ) < 1 ) return do icomp = 1 , size ( comp_list ) call validate_compiler_name ( comp_list ( icomp )% key , is_valid ) if ( is_valid ) then compiler_name = comp_list ( icomp )% key call get_value ( table , compiler_name , comp_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Compiler \" // comp_list ( icomp )% key // \" must be a table entry\" ) exit end if call comp_node % get_keys ( os_list ) if ( present ( profiles_size )) then call traverse_oss_for_size ( profile_name , compiler_name , os_list , comp_node , profiles_size , error ) if ( allocated ( error )) return else if (. not .( present ( profiles ). and . present ( profindex ))) then call fatal_error ( error , \"Both profiles and profindex have to be present\" ) return end if call traverse_oss ( profile_name , compiler_name , os_list , comp_node , & & profiles , profindex , error ) if ( allocated ( error )) return end if else call fatal_error ( error , '*traverse_compilers*:Error: Compiler name not specified or invalid.' ) end if end do end subroutine traverse_compilers !> Construct new profiles array from a TOML data structure subroutine new_profiles ( profiles , table , error ) !> Instance of the dependency configuration type ( profile_config_t ), allocatable , intent ( out ) :: profiles (:) !> Instance of the TOML data structure type ( toml_table ), target , intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: prof_node type ( toml_key ), allocatable :: prof_list (:) type ( toml_key ), allocatable :: comp_list (:) type ( toml_key ), allocatable :: os_list (:) character ( len = :), allocatable :: profile_name , compiler_name integer :: profiles_size , iprof , stat , profindex logical :: is_valid type ( profile_config_t ), allocatable :: default_profiles (:) path = '' default_profiles = get_default_profiles ( error ) if ( allocated ( error )) return call table % get_keys ( prof_list ) if ( size ( prof_list ) < 1 ) return profiles_size = 0 do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER call traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Profile \" // prof_list ( iprof )% key // \" must be a table entry\" ) exit end if call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return end if end if end do profiles_size = profiles_size + size ( default_profiles ) allocate ( profiles ( profiles_size )) do profindex = 1 , size ( default_profiles ) profiles ( profindex ) = default_profiles ( profindex ) end do do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER prof_node => table call traverse_oss ( profile_name , compiler_name , os_list , prof_node , profiles , profindex , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return end if end if end do ! Apply profiles with profile name 'all' to matching profiles do iprof = 1 , size ( profiles ) if ( profiles ( iprof )% profile_name . eq . 'all' ) then do profindex = 1 , size ( profiles ) if (. not .( profiles ( profindex )% profile_name . eq . 'all' ) & & . and .( profiles ( profindex )% compiler . eq . profiles ( iprof )% compiler ) & & . and .( profiles ( profindex )% os_type . eq . profiles ( iprof )% os_type )) then profiles ( profindex )% flags = profiles ( profindex )% flags // & & \" \" // profiles ( iprof )% flags profiles ( profindex )% c_flags = profiles ( profindex )% c_flags // & & \" \" // profiles ( iprof )% c_flags profiles ( profindex )% cxx_flags = profiles ( profindex )% cxx_flags // & & \" \" // profiles ( iprof )% cxx_flags profiles ( profindex )% link_time_flags = profiles ( profindex )% link_time_flags // & & \" \" // profiles ( iprof )% link_time_flags end if end do end if end do end subroutine new_profiles !> Construct an array of built-in profiles function get_default_profiles ( error ) result ( default_profiles ) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( profile_config_t ), allocatable :: default_profiles (:) default_profiles = [ & & new_profile ( 'release' , & & 'caf' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'gfortran' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'f95' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -ffast-math -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Mbackslash' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_ALL , & & flags = ' -fp-model precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl -standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_ALL , & & flags = ' -fp-model=precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl -standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nagfor' , & & OS_ALL , & & flags = ' -O4 -coarray=single -PIC' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'lfortran' , & & OS_ALL , & & flags = ' flag_lfortran_opt' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'caf' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'gfortran' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'f95' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -Wno-maybe-uninitialized -Wno-uninitialized -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Minform=inform -Mbackslash -g -Mbounds -Mchkptr -Mchkstk -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -standard-semantics -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1& & /Od /Z7 /assume:byterecl /standard-semantics /traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -standard-semantics -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'lfortran' , & & OS_ALL , & & flags = '' , & & is_built_in = . true .) & &] end function get_default_profiles !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the profile configuration class ( profile_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if write ( unit , fmt ) \"Profile\" if ( allocated ( self % profile_name )) then write ( unit , fmt ) \"- profile name\" , self % profile_name end if if ( allocated ( self % compiler )) then write ( unit , fmt ) \"- compiler\" , self % compiler end if write ( unit , fmt ) \"- os\" , self % os_type if ( allocated ( self % flags )) then write ( unit , fmt ) \"- compiler flags\" , self % flags end if end subroutine info !> Print a representation of profile_config_t function info_profile ( profile ) result ( s ) !> Profile to be represented type ( profile_config_t ), intent ( in ) :: profile !> String representation of given profile character (:), allocatable :: s integer :: i s = \"profile_config_t(\" s = s // 'profile_name=\"' // profile % profile_name // '\"' s = s // ', compiler=\"' // profile % compiler // '\"' s = s // \", os_type=\" select case ( profile % os_type ) case ( OS_UNKNOWN ) s = s // \"OS_UNKNOWN\" case ( OS_LINUX ) s = s // \"OS_LINUX\" case ( OS_MACOS ) s = s // \"OS_MACOS\" case ( OS_WINDOWS ) s = s // \"OS_WINDOWS\" case ( OS_CYGWIN ) s = s // \"OS_CYGWIN\" case ( OS_SOLARIS ) s = s // \"OS_SOLARIS\" case ( OS_FREEBSD ) s = s // \"OS_FREEBSD\" case ( OS_OPENBSD ) s = s // \"OS_OPENBSD\" case ( OS_ALL ) s = s // \"OS_ALL\" case default s = s // \"INVALID\" end select if ( allocated ( profile % flags )) s = s // ', flags=\"' // profile % flags // '\"' if ( allocated ( profile % c_flags )) s = s // ', c_flags=\"' // profile % c_flags // '\"' if ( allocated ( profile % cxx_flags )) s = s // ', cxx_flags=\"' // profile % cxx_flags // '\"' if ( allocated ( profile % link_time_flags )) s = s // ', link_time_flags=\"' // profile % link_time_flags // '\"' if ( allocated ( profile % file_scope_flags )) then do i = 1 , size ( profile % file_scope_flags ) s = s // ', flags for ' // profile % file_scope_flags ( i )% file_name // & & ' =\"' // profile % file_scope_flags ( i )% flags // '\"' end do end if s = s // \")\" end function info_profile !> Look for profile with given configuration in array profiles subroutine find_profile ( profiles , profile_name , compiler , os_type , found_matching , chosen_profile ) !> Array of profiles type ( profile_config_t ), allocatable , intent ( in ) :: profiles (:) !> Name of profile character (:), allocatable , intent ( in ) :: profile_name !> Name of compiler character (:), allocatable , intent ( in ) :: compiler !> Type of operating system (enum) integer , intent ( in ) :: os_type !> Boolean value containing true if matching profile was found logical , intent ( out ) :: found_matching !> Last matching profile in the profiles array type ( profile_config_t ), intent ( out ) :: chosen_profile character (:), allocatable :: curr_profile_name character (:), allocatable :: curr_compiler integer :: curr_os integer :: i , priority , curr_priority found_matching = . false . if ( size ( profiles ) < 1 ) return ! Try to find profile with matching OS type do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . os_type ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do ! Try to find profile with OS type 'all' if (. not . found_matching ) then do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . OS_ALL ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do end if end subroutine find_profile end module fpm_manifest_profile","tags":"","loc":"sourcefile/profiles.f90.html"},{"title":"preprocess.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_preprocess Source Code preprocess.f90 Source Code !> Implementation of the meta data for preprocessing. !> !> A preprocess table can currently have the following fields !> !> ```toml !> [preprocess] !> [preprocess.cpp] !> suffixes = [\"F90\", \"f90\"] !> directories = [\"src/feature1\", \"src/models\"] !> macros = [] !> ``` module fpm_manifest_preprocess use fpm_error , only : error_t , syntax_error use fpm_strings , only : string_t use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: preprocess_config_t , new_preprocess_config , new_preprocessors , operator ( == ) !> Configuration meta data for a preprocessor type :: preprocess_config_t !> Name of the preprocessor character ( len = :), allocatable :: name !> Suffixes of the files to be preprocessed type ( string_t ), allocatable :: suffixes (:) !> Directories to search for files to be preprocessed type ( string_t ), allocatable :: directories (:) !> Macros to be defined for the preprocessor type ( string_t ), allocatable :: macros (:) contains !> Print information on this instance procedure :: info end type preprocess_config_t interface operator ( == ) module procedure preprocess_is_same end interface contains !> Construct a new preprocess configuration from TOML data structure subroutine new_preprocess_config ( self , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), intent ( out ) :: self !> Instance of the TOML data structure. type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_list ( table , \"suffixes\" , self % suffixes , error ) if ( allocated ( error )) return call get_list ( table , \"directories\" , self % directories , error ) if ( allocated ( error )) return call get_list ( table , \"macros\" , self % macros , error ) if ( allocated ( error )) return end subroutine new_preprocess_config !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure. type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( inout ) :: error character ( len = :), allocatable :: name type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_key ( name ) call table % get_keys ( list ) do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) !> Valid keys. case ( \"suffixes\" , \"directories\" , \"macros\" ) case default call syntax_error ( error , \"Key '\" // list ( ikey )% key // \"' not allowed in preprocessor '\" // name // \"'.\" ); exit end select end do end subroutine check !> Construct new preprocess array from a TOML data structure. subroutine new_preprocessors ( preprocessors , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), allocatable , intent ( out ) :: preprocessors (:) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) integer :: iprep , stat call table % get_keys ( list ) ! An empty table is not allowed if ( size ( list ) == 0 ) then call syntax_error ( error , \"No preprocessors defined\" ) end if allocate ( preprocessors ( size ( list ))) do iprep = 1 , size ( list ) call get_value ( table , list ( iprep )% key , node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Preprocessor \" // list ( iprep )% key // \" must be a table entry\" ) exit end if call new_preprocess_config ( preprocessors ( iprep ), node , error ) if ( allocated ( error )) exit end do end subroutine new_preprocessors !> Write information on this instance subroutine info ( self , unit , verbosity ) !> Instance of the preprocess configuration class ( preprocess_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ilink character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Preprocessor\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % suffixes )) then write ( unit , fmt ) \" - suffixes\" do ilink = 1 , size ( self % suffixes ) write ( unit , fmt ) \" - \" // self % suffixes ( ilink )% s end do end if if ( allocated ( self % directories )) then write ( unit , fmt ) \" - directories\" do ilink = 1 , size ( self % directories ) write ( unit , fmt ) \" - \" // self % directories ( ilink )% s end do end if if ( allocated ( self % macros )) then write ( unit , fmt ) \" - macros\" do ilink = 1 , size ( self % macros ) write ( unit , fmt ) \" - \" // self % macros ( ilink )% s end do end if end subroutine info logical function preprocess_is_same ( this , that ) class ( preprocess_config_t ), intent ( in ) :: this class ( preprocess_config_t ), intent ( in ) :: that integer :: istr preprocess_is_same = . false . select type ( other => that ) type is ( preprocess_config_t ) if ( allocated ( this % name ). neqv . allocated ( other % name )) return if ( allocated ( this % name )) then if (. not .( this % name == other % name )) return endif if (. not .( allocated ( this % suffixes ). eqv . allocated ( other % suffixes ))) return if ( allocated ( this % suffixes )) then do istr = 1 , size ( this % suffixes ) if (. not .( this % suffixes ( istr )% s == other % suffixes ( istr )% s )) return end do end if if (. not .( allocated ( this % directories ). eqv . allocated ( other % directories ))) return if ( allocated ( this % directories )) then do istr = 1 , size ( this % directories ) if (. not .( this % directories ( istr )% s == other % directories ( istr )% s )) return end do end if if (. not .( allocated ( this % macros ). eqv . allocated ( other % macros ))) return if ( allocated ( this % macros )) then do istr = 1 , size ( this % macros ) if (. not .( this % macros ( istr )% s == other % macros ( istr )% s )) return end do end if class default ! Not the same type return end select !> All checks passed! preprocess_is_same = . true . end function preprocess_is_same end module fpm_manifest_preprocess","tags":"","loc":"sourcefile/preprocess.f90.html"},{"title":"build.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_build Source Code build.f90 Source Code !> Implementation of the build configuration data. !> !> A build table can currently have the following fields !> !>```toml !>[build] !>auto-executables = bool !>auto-examples = bool !>auto-tests = bool !>link = [\"lib\"] !>``` module fpm_manifest_build use fpm_error , only : error_t , syntax_error , fatal_error use fpm_strings , only : string_t , len_trim , is_valid_module_prefix use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: build_config_t , new_build_config !> Configuration data for build type :: build_config_t !> Automatic discovery of executables logical :: auto_executables !> Automatic discovery of examples logical :: auto_examples !> Automatic discovery of tests logical :: auto_tests !> Enforcing of package module names logical :: module_naming = . false . type ( string_t ) :: module_prefix !> Libraries to link against type ( string_t ), allocatable :: link (:) !> External modules to use type ( string_t ), allocatable :: external_modules (:) contains !> Print information on this instance procedure :: info end type build_config_t contains !> Construct a new build configuration from a TOML data structure subroutine new_build_config ( self , table , package_name , error ) !> Instance of the build configuration type ( build_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Package name character ( len =* ), intent ( in ) :: package_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call check ( table , package_name , error ) if ( allocated ( error )) return call get_value ( table , \"auto-executables\" , self % auto_executables , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-executables' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-tests\" , self % auto_tests , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-tests' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-examples\" , self % auto_examples , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-examples' in fpm.toml, expecting logical\" ) return end if !> Module naming: fist, attempt boolean value first call get_value ( table , \"module-naming\" , self % module_naming , . false ., stat = stat ) if ( stat == toml_stat % success ) then ! Boolean value found. Set no custom prefix. This also falls back to ! key not provided self % module_prefix = string_t ( \"\" ) else !> Value found, but not a boolean. Attempt to read a prefix string call get_value ( table , \"module-naming\" , self % module_prefix % s ) if (. not . allocated ( self % module_prefix % s )) then call syntax_error ( error , \"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string\" ) return end if if (. not . is_valid_module_prefix ( self % module_prefix )) then call syntax_error ( error , \"Invalid custom module name prefix for in fpm.toml: <\" // self % module_prefix % s // & \">, expecting a valid alphanumeric string\" ) return end if ! Set module naming to ON self % module_naming = . true . end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return call get_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return end subroutine new_build_config !> Check local schema for allowed entries subroutine check ( table , package_name , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Package name character ( len =* ), intent ( in ) :: package_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) ! table can be empty if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case ( \"auto-executables\" , \"auto-examples\" , \"auto-tests\" , \"link\" , \"external-modules\" , \"module-naming\" ) continue case default call syntax_error ( error , 'Manifest file syntax error: key \"' // list ( ikey )% key // '\" found in the [build] ' // & 'section of package/dependency \"' // package_name // '\" fpm.toml is not allowed' ) exit end select end do end subroutine check !> Write information on build configuration instance subroutine info ( self , unit , verbosity ) !> Instance of the build configuration class ( build_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ilink , imod character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Build configuration\" write ( unit , fmt ) \" - auto-discovery (apps) \" , merge ( \"enabled \" , \"disabled\" , self % auto_executables ) write ( unit , fmt ) \" - auto-discovery (examples) \" , merge ( \"enabled \" , \"disabled\" , self % auto_examples ) write ( unit , fmt ) \" - auto-discovery (tests) \" , merge ( \"enabled \" , \"disabled\" , self % auto_tests ) write ( unit , fmt ) \" - enforce module naming \" , merge ( \"enabled \" , \"disabled\" , self % module_naming ) if ( allocated ( self % link )) then write ( unit , fmt ) \" - link against\" do ilink = 1 , size ( self % link ) write ( unit , fmt ) \" - \" // self % link ( ilink )% s end do end if if ( allocated ( self % external_modules )) then write ( unit , fmt ) \" - external modules\" do imod = 1 , size ( self % external_modules ) write ( unit , fmt ) \" - \" // self % external_modules ( imod )% s end do end if end subroutine info end module fpm_manifest_build","tags":"","loc":"sourcefile/build.f90.html"},{"title":"main.f90 – Fortran-lang/fpm","text":"Contents Programs main Source Code main.f90 Source Code program main use , intrinsic :: iso_fortran_env , only : error_unit , output_unit use fpm_command_line , only : & fpm_cmd_settings , & fpm_new_settings , & fpm_build_settings , & fpm_run_settings , & fpm_test_settings , & fpm_install_settings , & fpm_update_settings , & fpm_clean_settings , & fpm_publish_settings , & get_command_line_settings use fpm_error , only : error_t use fpm_filesystem , only : exists , parent_dir , join_path use fpm , only : cmd_build , cmd_run , cmd_clean use fpm_cmd_install , only : cmd_install use fpm_cmd_new , only : cmd_new use fpm_cmd_update , only : cmd_update use fpm_cmd_publish , only : cmd_publish use fpm_os , only : change_directory , get_current_directory implicit none class ( fpm_cmd_settings ), allocatable :: cmd_settings type ( error_t ), allocatable :: error character ( len = :), allocatable :: pwd_start , pwd_working , working_dir , project_root call get_command_line_settings ( cmd_settings ) call get_current_directory ( pwd_start , error ) call handle_error ( error ) call get_working_dir ( cmd_settings , working_dir ) if ( allocated ( working_dir )) then ! Change working directory if requested if ( len_trim ( working_dir ) > 0 ) then call change_directory ( working_dir , error ) call handle_error ( error ) call get_current_directory ( pwd_working , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // pwd_working // \"'\" else pwd_working = pwd_start end if else pwd_working = pwd_start end if select type ( settings => cmd_settings ) type is ( fpm_new_settings ) class default if (. not . has_manifest ( pwd_working )) then project_root = pwd_working do while (. not . has_manifest ( project_root )) working_dir = parent_dir ( project_root ) if ( len ( working_dir ) == 0 ) exit project_root = working_dir end do if ( has_manifest ( project_root )) then call change_directory ( project_root , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // project_root // \"'\" end if end if end select select type ( settings => cmd_settings ) type is ( fpm_new_settings ) call cmd_new ( settings ) type is ( fpm_build_settings ) call cmd_build ( settings ) type is ( fpm_run_settings ) call cmd_run ( settings , test = . false .) type is ( fpm_test_settings ) call cmd_run ( settings , test = . true .) type is ( fpm_install_settings ) call cmd_install ( settings ) type is ( fpm_update_settings ) call cmd_update ( settings ) type is ( fpm_clean_settings ) call cmd_clean ( settings ) type is ( fpm_publish_settings ) call cmd_publish ( settings ) end select if ( allocated ( project_root )) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // project_root // \"'\" end if if ( pwd_start /= pwd_working ) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // pwd_working // \"'\" end if contains function has_manifest ( dir ) character ( len =* ), intent ( in ) :: dir logical :: has_manifest has_manifest = exists ( join_path ( dir , \"fpm.toml\" )) end function has_manifest subroutine handle_error ( error_ ) type ( error_t ), optional , intent ( in ) :: error_ if ( present ( error_ )) then write ( error_unit , '(\"[Error]\", 1x, a)' ) error_ % message stop 1 end if end subroutine handle_error !> Save access to working directory in settings, in case setting have not been allocated subroutine get_working_dir ( settings , working_dir_ ) class ( fpm_cmd_settings ), optional , intent ( in ) :: settings character ( len = :), allocatable , intent ( out ) :: working_dir_ if ( present ( settings )) then working_dir_ = settings % working_dir end if end subroutine get_working_dir end program main","tags":"","loc":"sourcefile/main.f90.html"},{"title":"Packaging and contributing – Fortran-lang/fpm","text":"","tags":"","loc":"page/index.html"},{"title":"Contributing Guidelines – Fortran-lang/fpm","text":"Contributing to the Fortran Package Manager Thank you for considering contributing to the Fortran Package Manager ( fpm ).\nPlease review and follow these guidelines to make the contribution process\nsimple and effective for all involved. It will help communicate that you\nrespect the time of the community developers. In return, the community will\nhelp address your problem, evaluate changes, and guide you through your pull\nrequests. By contributing to fpm , you certify that you own or are allowed to share the\ncontent of your contribution under the fpm license . Style Reporting a bug Suggesting a feature Workflow General guidelines For new contributors Style Please follow the Fortran stdlib style guide for any Fortran code that you contribute.\nThis allows us to focus on substance rather than style. Reporting a bug A bug is a demonstrable problem caused by the code in this repository.\nGood bug reports are extremely valuable to us—thank you! Before opening a bug report: Check if the issue has already been reported\n ( issues ). Check if it is still an issue or it has been fixed?\n Try to reproduce it with the latest version from the default branch. Isolate the problem and create a minimal test case. A good bug report should include all information needed to reproduce the bug.\nPlease be as detailed as possible: Which version of fpm are you using? Please be specific. What are the steps to reproduce the issue? What is the expected outcome? What happens instead? This information will help the community diagnose the issue quickly and with\nminimal back-and-forth. Suggesting a feature Before suggesting a new feature, take a moment to find out if it fits the scope\nof the project, or if it has already been discussed. It is up to you to provide\na strong argument to convince the community of the benefits of this feature.\nPlease provide as much detail and context as possible. If applicable, include a\nmocked-up snippet of what the output or behavior would look like with this\nfeature implemented. “Crazy”, out-of-the-box ideas are especially welcome.\nIt’s quite possible that we are not considering an unusually creative solution. Workflow fpm is a community project. There is no one single person making final\ndecisions. This is the workflow that we follow: Open a new issue to\n describe a bug or propose a new feature.\n Refer to the earlier sections on how to write a good bug report or feature\n request. Discuss with the community and reach majority consensus about what should be\n done about the bug or feature request.\n We define “majority” loosely as 80%.\n This means that at least 4 of 5 people engaged in the discussion should be\n able to agree on the next step.\n This allows us to have the community mostly agree while not getting stuck if\n one person disagrees.\n At this stage, the scope of the fix/feature, its behavior, and API if\n applicable should be defined.\n Only when you have community consensus on these items you should proceed to\n writing code and opening a PR. When actively working on code towards a PR, please assign yourself to the\n issue on GitHub. This is good collaborative practice to avoid duplicated effort and also\n inform others what you are currently working on. Open a new Pull Request (PR) with your contribution.\n The body of the PR should at least include a bullet-point summary of the\n changes, and a detailed description is encouraged.\n If the PR completely addresses the issue you opened in step 1, include in\n the PR description the following line: Fixes # . Request reviewers to your PR.\n For small bug fixes or documentation improvements, 1 to 2 reviewers is\n sufficient.\n For implementation of bigger features, request 3 to 4 or more reviewers.\n Ideally, request reviewers that participated in step 2. If your PR implements a feature that adds or changes the behavior of fpm ,\n your PR must also include appropriate changes to the documentation. This workflow can evolve and change over time as we learn how best to work\ntogether. If you have an idea on how to improve the workflow itself, please\nopen an issue and we’ll discuss it. General guidelines A PR should implement only one feature or bug fix. Do not commit changes to files that are irrelevant to your feature or bug fix. Smaller PRs are better than large PRs, and will lead to a shorter review and\n merge cycle Add tests for your feature or bug fix to be sure that it stays functional and useful Be open to constructive criticism and requests for improving your code. Again, please follow the Fortran stdlib style guide . For new contributors If you have never created a pull request before, welcome :tada:.\nYou can learn how from this great tutorial . Don’t know where to start?\nYou can start by looking through the list of open issues .","tags":"","loc":"page/Contributing.html"},{"title":"License – Fortran-lang/fpm","text":"MIT License Copyright (c) 2020 fpm contributors Permission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the “Software”), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","tags":"","loc":"page/License.html"},{"title":"Manifest reference – Fortran-lang/fpm","text":"301 - Moved This document now lives at https://fpm.fortran-lang.org/en/spec/manifest.html.","tags":"","loc":"page/Manifest.html"},{"title":"Packaging with fpm – Fortran-lang/fpm","text":"Preparing your package for FPM This document describes how you need to organize your application or library for\nit to successfully build with the Fortran Package Manager ( fpm ). What kind of package can fpm build? Example package layouts Single program Single-module library Multi-module library Application and library Multi-level library Be more explicit Add some tests Adding dependencies Custom build scripts What kind of package can fpm build? You can use fpm to build: Applications (program only) Libraries (modules only) Combination of the two (programs and modules combined) Let’s look at some examples of different kinds of package layouts that you can\nuse with fpm . Example package layouts This section describes some example package layouts that you can build with fpm . You can use them to model the layout of your own package. Single program Let’s start with the simplest package imaginable—a single program without\ndependencies or modules. Here’s what the layout of the top-level directory\nlooks like: .\n├── app\n│ └── main.f90\n└── fpm.toml We have one source file ( main.f90 ) in one directory ( app ). Its contents\nare: program main print * , 'Hello, World!' end program main This program prints the usual greeting to the standard output, and nothing more. There’s another important file in the top-level directory, fpm.toml . This is fpm ’s configuration file specific to your package. It includes all the data\nthat fpm needs to build your app. In our simple case, it looks like this: name = \"hello\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" The preamble includes some metadata, such as license , author , and similar,\nthat you may have seen in other package manager configuration files. The one\noption that matters here right now is: name = \"hello\" This line specifies the name of your package, which determines the name of the\nexecutable file of your program. In this example, our program executable, once\nbuilt, will be called hello . Let’s now build this program using fpm : $ fpm build # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/hello) On the first line, we ran fpm build to compile and link the application.\nThe latter two lines are emitted by fpm , and indicate which command was\nexecuted at each build step ( gfortran ), and which files have been output\nby it: object file main.o , and executable hello . We can now run the app with fpm run : $ fpm run\n Hello, World! If your application needs to use a module internally, but you don’t intend\nto build it as a library to be used in other projects, you can include the\nmodule in your program source file as well.\nFor example: $ cat app / main . f90 module math_constants real , parameter :: pi = 4 * atan ( 1. ) end module math_constants program main use math_constants , only : pi print * , 'Hello, World!' print * , 'pi = ' , pi end program main Now, run this using fpm run : $ fpm run # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/hello) Hello, World! pi = 3 .14159274 Although we have named our program hello , which is the same name as the\npackage name in fpm.toml , you can name it anything you want as long as it’s\npermitted by the language. Notice that you can run fpm run , and if the package hasn’t been built yet, fpm build will run automatically for you. This is true if the source files\nhave been updated since the last build. Thus, if you want to run your\napplication, you can skip the fpm build step, and go straight to fpm run . When running your application using fpm run , the program’s exit code is\npassed by fpm back to the operating system. So, it is possible to use Fortran\nnumbered stop and error stop codes to pass termination reasons back to the terminal. Try running the following app with fpm run : program main use math_constants , only : pi real :: angle read ( * , * , iostat = ierr ) angle if ( ierr /= 0 ) then stop 2 ! Not real elseif ( angle > pi ) then stop 1 else stop 0 endif end program main and then checking that the error code matches. Note that error codes are passed to variable $? on Unix/Mac systems, and to environment variable %errorlevel% on Windows. In this last example, our source file defined a math_constants module inside\nthe same source file as the main program. Let’s see how we can define an fpm package that makes this module available as a library. Single-module library The package layout for this example looks like this: . ├── fpm . toml └── src └── math_constants . f90 In this example we’ll build a simple math constants library that exports\nthe number pi as a parameter: $ cat src / math_constants . f90 module math_constants real , parameter :: pi = 4 * atan ( 1. ) end module math_constants and our fpm.toml is the same as before. Now use fpm build to build the package: $ fpm build # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a Based on the output of fpm build , fpm first ran gfortran to emit the\nbinary object ( math_constants.o ) and module ( math_constants.mod ) files.\nThen it ran ar to create a static library archive math_constants.a . build/debug/library is thus both your include and library path, should you\nwant to compile and link an external program with this library. For modules in the top-level ( src ) directory, fpm requires that: The module has the same name as the source file. There is only one module per file. These two requirements simplify the build process for fpm . As Fortran\ncompilers emit module files ( .mod ) with the same name as the module itself\n(but not the source file, .f90 ), naming the module the same as the source file\nallows fpm to: Uniquely and exactly map a source file ( .f90 ) to its object ( .o ) and\nmodule ( .mod ) files. Avoid conflicts with modules of the same name that could appear in dependency\npackages (more on this in a bit). Since this is a library without executable programs, fpm run here does\nnothing. In this example, our library is made of only one module. However, most\nreal-world libraries are likely to use multiple modules. Let’s see how you can\npackage your multi-module library. Multi-module library In this example, we’ll use another module to define a 64-bit real kind\nparameter and make it available in math_constants to define pi with\nhigher precision. To make this exercise worthwhile, we’ll define another math\nconstant, Euler’s number. Our package layout looks like this: . ├── fpm . toml └── src ├── math_constants . f90 └── type_kinds . f90 And our source file contents are: $ cat src / math_constants . f90 module math_constants use type_kinds , only : rk real ( rk ), parameter :: pi = 4 * atan ( 1._rk ) real ( rk ), parameter :: e = exp ( 1._rk ) end module math_constants $ cat src / type_kinds . f90 module type_kinds use iso_fortran_env , only : real64 integer , parameter :: rk = real64 end module type_kinds and there are no changes to our fpm.toml relative to previous examples. Like before, notice that the module type_kinds is name exactly as the\nsource file that contains it.\nThis is important. By now you know how to build the package: $ fpm build # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a Our build path now contains: $ ls build/debug/library/\nmath_constants.a math_constants.mod math_constants.o type_kinds.mod type_kinds.o And the static library includes all the object files: $ nm build/debug/library/math_constants.a\n\nmath_constants.o:\n\ntype_kinds.o: The takeaways from this example are that: fpm automatically scanned the src directory for any source files. It also resolved the dependency order between different modules. Application and library Let’s now combine the two previous examples into one: We’ll build the math\nconstants library and an executable program that uses it. We’ll use this\nprogram as a demo, and to verify that defining higher-precision constants from\nthe previous example actually worked. Here’s the package layout for your application + library package: . ├── app │ └── main . f90 ├── fpm . toml └── src ├── math_constants . f90 └── type_kinds . f90 Our fpm.toml remains unchanged and our executable program source file is: $ cat app / main . f90 program main use math_constants , only : e , pi print * , 'math_constants library demo' print * , 'pi = ' , pi print * , 'e = ' , e end program main Let’s go straight to running the demo program: $ fpm run # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/math_constants) math_constants library demo pi = 3 .1415926535897931 e = 2 .7182818284590451 The fpm build + run process works as expected, and our program correctly\noutputs higher-precision constants. So far we covered how fpm builds: A single program A single-module library A multi-module library A program and a library However, all our modules so far have been organized in the top level source\ndirectory. More complex libraries may organize their modules in subdirectories.\nLet’s see how we can build this with fpm . Multi-level library In this example, we’ll define our library as a collection of modules, two of\nwhich are defined in a subdirectory: . ├── app │ └── main . f90 ├── fpm . toml └── src ├── math_constants │ ├── derived . f90 │ └── fundamental . f90 ├── math_constants . f90 └── type_kinds . f90 First, fpm.toml and src/type_kinds.f90 remain unchanged relative to the\nprevious example. The rest of the source files are: $ cat src / math_constants . f90 module math_constants use math_constants_fundamental , only : e , pi use math_constants_derived , only : half_pi , two_pi end module math_constants $ cat src / math_constants / fundamental . f90 module math_constants_fundamental use type_kinds , only : rk real ( rk ), parameter :: pi = 4 * atan ( 1._rk ) real ( rk ), parameter :: e = exp ( 1._rk ) end module math_constants_fundamental $ cat src / math_constants / derived . f90 module math_constants_derived use math_constants_fundamental , only : pi use type_kinds , only : rk real ( rk ), parameter :: two_pi = 2 * pi real ( rk ), parameter :: half_pi = pi / 2 end module math_constants_derived $ cat app / main . f90 program main use math_constants , only : e , pi , half_pi , two_pi print * , 'math_constants library demo' print * , 'pi = ' , pi print * , '2*pi = ' , two_pi print * , 'pi/2 = ' , half_pi print * , 'e = ' , e end program main Our top-level math_constants module now doesn’t define the constants, but\nimports them from the two modules in the subdirectory. Constants e and pi we define in the math_constants_fundamental module, and two_pi and half_pi in the math_constants_derived module. From the main program, we access all\nthe constants from the top-level module math_constants . Let’s build and run this package: $ fpm run # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod) # gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/math_constants) math_constants library demo pi = 3 .1415926535897931 2 *pi = 6 .2831853071795862\n pi/2 = 1 .5707963267948966 e = 2 .7182818284590451 Again, fpm built and run the package as expected. Recall from an earlier example that fpm required the modules in the top-level src directory to be named the same as their source file. This is why src/math_constants.f90 defines module math_constants . For modules defined in subdirectories, there’s an additional requirement: module\nname must contain the path components of the directory that its source file is\nin. In our case, src/math_constants/fundamental.f90 defines the math_constants_fundamental module. Likewise, src/math_constants/derived.f90 defines the math_constants_derived module. This rule applies generally to any number of nested directories and modules.\nFor example, src/a/b/c/d.f90 must define a module called a_b_c_d . Takeaways from this example are that: You can place your module source files in any levels of subdirectories inside src . The module name must include the path components and the source file name–for example, src/a/b/c/d.f90 must define a module called a_b_c_d . Be more explicit So far we’ve let fpm use its defaults to determine the layout of our package.\nIt determined where our library sources would live, what the name of the\nexecutable will be, and some other things. But we can be more explicit about it,\nand make some changes to those things. Let’s look at what the fpm.toml file from our last example would look like if\nwe specified everything. name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" You can see that by making these explicit in the fpm.toml we are able to\nchange many of the settings that fpm used by default. We can change the\nfolders where our sources are stored, we can change the name of our executable,\nand we can change the name of the file our program is defined in. Add some tests fpm also provides support for unit testing. By default, fpm looks for a\nprogram in test/main.f90 which it will compile and execute with the command fpm test . The tests are treated pretty much exactly like the executables.\nLet’s define one explicitly in our fpm.toml file. We’ll make sure that our\ndefinition of pi satisfies the property sin(pi) == 0.0 . Here’s the fpm.toml file: name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" where the contents of the main.f90 file are program main use math_constants , only : pi print * , \"sin(pi) = \" , sin ( pi ) end program main With this setup, we can run our tests. $ fpm test # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod) # gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/math_constants) # gfortran (for build/debug/test/main.o) # gfortran (for build/debug/test/runTests) sin ( pi ) = 1 .2246467991473532E-016 Adding dependencies Inevitably, you’ll want to be able to include other libraries in your project.\nfpm makes this incredibly simple, by taking care of fetching and compiling your\ndependencies for you. You just tell it what your dependencies are, and where to\nfind them. Let’s add a dependency to our library. Now our fpm.toml file looks\nlike this: name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [dependencies] helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" Now you can use any modules from this library anywhere in your code. Just like\nthis: program main use helloff , only : create_greeting use math_constants , only : e , pi , half_pi , two_pi print * , 'math_constants library demo' print * , 'pi = ' , pi print * , '2*pi = ' , two_pi print * , 'pi/2 = ' , half_pi print * , 'e = ' , e print * , create_greeting ( \"fpm\" ) end program main And now, fpm run will output the following: math_constants library demo pi = 3.1415926535897931 2 * pi = 6.2831853071795862 pi / 2 = 1.5707963267948966 e = 2.7182818284590451 Hello , fpm ! Additionally, any users of your library will now automatically depend on your\ndependencies too. So if you don’t need that dependency for the library, like in\nthe above example, then you can specify it for the specific executable like\nbelow. Then fpm will still fetch and compile it when building your executable,\nbut users of your library won’t have to. name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [executable.dependencies] helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" You can also specify dependencies for your tests in a similar way, with [test.dependencies] instead of [executable.dependencies] . There’s also\nanother option for test dependencies. The below example makes the dependencies\navailable for all the tests, but again your users won’t depend on these. name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [dev-dependencies] helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" You can also be specific about which version of a dependency you’d like. You can\nspecify a branch to use like helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\", branch = \"master\" } ,\nor a tag like helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\", tag = \"v1.2.3\" } ,\nor even a specific commit like helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\", rev = \"a1b2c3\" } .\nYou can even specify the path to another folder, if for example you’ve got\nanother fpm package in the same repository. Like this: helloff = { path = \"helloff\" } . Note that you should not specify paths\noutside of your repository, or things won’t work for your users. Custom build scripts If there is something special about your library that makes fpm unable to build\nit, you can provide your own build script. fpm will then simply call your build\nscript to build the library. To specify a build script to be used, put it in the library section of your fpm.toml file, like: [library] source-dir = \"src\" build-script = \"my_build_script\" fpm will set the following environment variables to specify some parameters to\nthe build script: FC – The Fortran compiler to be used. FFLAGS – The flags that should be passed to the Fortran compiler. BUILD_DIR – Where the compiled files should be placed. INCLUDE_DIRS – The folders where any dependencies can be found, space separated.\nIt is then the responsibility of the build script to generate the appropriate\ninclude flags. Additionally, script will be called with the name of the archive ( *.a file)\nthat should be produced as the command line argument. Note: If the name of the build script is Makefile or ends with .mk , then\nthe make program will be used to run it. Not the the archive file is explicitly\nspecified as the target to be built Note: All file and directory names are specified with their full canonical\npath.","tags":"","loc":"page/Packaging.html"}]}
\ No newline at end of file
+var tipuesearch = {"pages":[{"title":" Fortran-lang/fpm ","text":"Fortran-lang/fpm Fortran package manager developer documentation The package manifest Command line interface The package model The build backend Generating this documentation Fortran package manager developer documentation This is the main documentation of the Fortran package manager ( fpm ).\nThis document serves as developer documentation of fpm itself and contains general advice for developing in the fpm code base. The package manifest The central object describing an fpm project is the package manifest fpm.toml .\nThe manifest is written in TOML, you can find the TOML specification at the official TOML homepage . The fpm.toml file targets project developers and maintainers to relieve them from writing build files for their packages.\nWith the package manifest a central place to collect information about the project is provided.\nIt contains the versioning and licensing meta data, as well as the information on external dependencies and the required build-tools or compiler settings. The manifest format specific to fpm projects is documented in the manifest reference . Note For a more practical but less complete guide on creating fpm projects see the packaging guide . The details of the TOML parsing are implemented with using the tomlf module.\nGenerally, the interface to all TOML related functions for fpm is found in the proxy module fpm_toml . All the manifest types are bundled in fpm_manifest .\nWhile the specific subtables for the package configuration are found in the src/fpm/manifest directory, they should be reexported in the fpm_manifest module if they should be elsewhere in fpm . Command line interface fpm is mainly used as a command line tool.\nTo work with an fpm project as a user you can completely rely on the command line. The command line interface is build with the M_CLI2 module and can be found in fpm_command_line . The package model Once front-end inputs have been received from the package manifest and command line interface, fpm will construct an\ninternal representation of the package and its dependencies. This internal representation is known as the package model .\nThe model and its associated data types should encapsulate all the information required to correctly build a package and\nshould be independent of the intended backend build system. Information stored in the model includes: build targets and\ntheir inter-dependencies; compiler and compiler flags; library linking information. For more information on the contents of the package model and the process for constructing it, please see fpm_model . The build backend Once a complete package model has been constructed, it can be passed to a backend for either performing the compilation\nand linking of targets, or for generating configuration files for a third-party build system.\nCurrently, only a native backend is implemented in fpm . See fpm_backend for more information. Generating this documentation This documentation is generated by FORD .\nFor more details on the project file and the comment markup in the source code visit the FORD documentation . To regenerate this documentation run: ford docs.md Developer Info fortran-lang/fpm contributors","tags":"home","loc":"index.html"},{"title":"archiver_t – Fortran-lang/fpm ","text":"type, public :: archiver_t Definition of archiver object Contents Variables ar echo use_response_file verbose Type-Bound Procedures make_archive Source Code archiver_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: ar Path to archiver logical, public :: echo = .true. Print all command logical, public :: use_response_file = .false. Use response files to pass arguments logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure, public, :: make_archive Create static archive public subroutine make_archive (self, output, args, log_file, stat) Create an archive Todo For Windows OS, use the local delete_file_win32 in stead of delete_file .\nThis may be related to a bug in Mingw64-openmp and is expected to be resolved in the future,\nsee issue #707, #708 and #808. Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: self Instance of the archiver object character(len=*), intent(in) :: output Name of the archive to generate type( string_t ), intent(in) :: args (:) Object files to include into the archive character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Source Code type :: archiver_t !> Path to archiver character ( len = :), allocatable :: ar !> Use response files to pass arguments logical :: use_response_file = . false . !> Print all command logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Create static archive procedure :: make_archive end type archiver_t","tags":"","loc":"type/archiver_t.html"},{"title":"compiler_t – Fortran-lang/fpm ","text":"type, public :: compiler_t Definition of compiler object Contents Variables cc cxx echo fc id verbose Type-Bound Procedures compile_c compile_cpp compile_fortran enumerate_libraries get_default_flags get_feature_flag get_include_flag get_main_flags get_module_flag is_gnu is_intel is_unknown link name Source Code compiler_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cc Path to the C compiler character(len=:), public, allocatable :: cxx Path to the C++ compiler logical, public :: echo = .true. Print all commands character(len=:), public, allocatable :: fc Path to the Fortran compiler integer(kind=compiler_enum), public :: id = id_unknown Identifier of the compiler logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure, public, :: compile_c Compile a C object public subroutine compile_c (self, input, output, args, log_file, stat) Compile a C object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag procedure, public, :: compile_cpp Compile a CPP object public subroutine compile_cpp (self, input, output, args, log_file, stat) Compile a CPP object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag procedure, public, :: compile_fortran Compile a Fortran object public subroutine compile_fortran (self, input, output, args, log_file, stat) Compile a Fortran object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag procedure, public, :: enumerate_libraries Enumerate libraries, based on compiler and platform public function enumerate_libraries (self, prefix, libs) result(r) Enumerate libraries, based on compiler and platform Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: prefix type( string_t ), intent(in) :: libs (:) Return Value character(len=:), allocatable procedure, public, :: get_default_flags Get default compiler flags public function get_default_flags (self, release) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self logical, intent(in) :: release Return Value character(len=:), allocatable procedure, public, :: get_feature_flag Get feature flag public function get_feature_flag (self, feature) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: feature Return Value character(len=:), allocatable procedure, public, :: get_include_flag Get flag for include directories public function get_include_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable procedure, public, :: get_main_flags Get flags for the main linking command public subroutine get_main_flags (self, language, flags) Get special flags for the main linker Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: language character(len=:), intent(out), allocatable :: flags procedure, public, :: get_module_flag Get flag for module output directories public function get_module_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable procedure, public, :: is_gnu Check whether this is a GNU compiler public pure function is_gnu (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical procedure, public, :: is_intel Check whether this is an Intel compiler public pure function is_intel (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical procedure, public, :: is_unknown Check whether compiler is recognized public pure function is_unknown (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical procedure, public, :: link Link executable public subroutine link (self, output, args, log_file, stat) Link an executable Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag procedure, public, :: name => compiler_name Return compiler name public pure function compiler_name (self) result(name) Return a compiler name string Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string Source Code type :: compiler_t !> Identifier of the compiler integer ( compiler_enum ) :: id = id_unknown !> Path to the Fortran compiler character ( len = :), allocatable :: fc !> Path to the C compiler character ( len = :), allocatable :: cc !> Path to the C++ compiler character ( len = :), allocatable :: cxx !> Print all commands logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Get default compiler flags procedure :: get_default_flags !> Get flag for module output directories procedure :: get_module_flag !> Get flag for include directories procedure :: get_include_flag !> Get feature flag procedure :: get_feature_flag !> Get flags for the main linking command procedure :: get_main_flags !> Compile a Fortran object procedure :: compile_fortran !> Compile a C object procedure :: compile_c !> Compile a CPP object procedure :: compile_cpp !> Link executable procedure :: link !> Check whether compiler is recognized procedure :: is_unknown !> Check whether this is an Intel compiler procedure :: is_intel !> Check whether this is a GNU compiler procedure :: is_gnu !> Enumerate libraries, based on compiler and platform procedure :: enumerate_libraries !> Return compiler name procedure :: name => compiler_name end type compiler_t","tags":"","loc":"type/compiler_t.html"},{"title":"fpm_global_settings – Fortran-lang/fpm ","text":"type, public :: fpm_global_settings Contents Variables config_file_name path_to_config_folder registry_settings Type-Bound Procedures full_path has_custom_location path_to_config_folder_or_empty Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: config_file_name Name of the global config file. The default is config.toml . character(len=:), public, allocatable :: path_to_config_folder Path to the global config file excluding the file name. type(fpm_registry_settings), public, allocatable :: registry_settings Registry configs. Type-Bound Procedures procedure, public, :: full_path private function full_path(self) result(result) The full path to the global config file. Arguments Type Intent Optional Attributes Name class( fpm_global_settings ), intent(in) :: self Return Value character(len=:), allocatable procedure, public, :: has_custom_location private elemental function has_custom_location(self) True if the global config file is not at the default location. Arguments Type Intent Optional Attributes Name class( fpm_global_settings ), intent(in) :: self Return Value logical procedure, public, :: path_to_config_folder_or_empty private pure function path_to_config_folder_or_empty(self) The path to the global config directory. Arguments Type Intent Optional Attributes Name class( fpm_global_settings ), intent(in) :: self Return Value character(len=:), allocatable","tags":"","loc":"type/fpm_global_settings.html"},{"title":"console_t – Fortran-lang/fpm ","text":"type, public :: console_t Console object Contents Variables n_line Type-Bound Procedures update_line write_line Source Code console_t Components Type Visibility Attributes Name Initial integer, public :: n_line = 1 Number of lines printed Type-Bound Procedures procedure, public, :: update_line => console_update_line Update a previously-written console line private subroutine console_update_line(console, line_no, str) Overwrite a previously-written line in standard output Arguments Type Intent Optional Attributes Name class( console_t ), intent(in) :: console Console object integer, intent(in) :: line_no Integer output from console_write_line character(len=*), intent(in) :: str New string to overwrite line procedure, public, :: write_line => console_write_line Write a single line to the console private subroutine console_write_line(console, str, line, advance) Write a single line to the standard output Arguments Type Intent Optional Attributes Name class( console_t ), intent(inout) :: console Console object character(len=*), intent(in) :: str String to write integer, intent(out), optional :: line Integer needed to later update console line logical, intent(in), optional :: advance Advancing output (print newline?) Source Code type console_t !> Number of lines printed integer :: n_line = 1 contains !> Write a single line to the console procedure :: write_line => console_write_line !> Update a previously-written console line procedure :: update_line => console_update_line end type console_t","tags":"","loc":"type/console_t.html"},{"title":"fpm_build_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_build_settings Contents Variables archiver build_tests c_compiler cflag compiler cxx_compiler cxxflag flag ldflag list profile prune show_model verbose working_dir Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_build_settings.html"},{"title":"fpm_clean_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_clean_settings Contents Variables clean_call clean_skip verbose working_dir Components Type Visibility Attributes Name Initial logical, public :: clean_call = .false. logical, public :: clean_skip = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_clean_settings.html"},{"title":"fpm_cmd_settings – Fortran-lang/fpm ","text":"type, public, abstract :: fpm_cmd_settings Contents Variables verbose working_dir Components Type Visibility Attributes Name Initial logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_cmd_settings.html"},{"title":"fpm_install_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_install_settings Contents Variables archiver bindir build_tests c_compiler cflag compiler cxx_compiler cxxflag flag includedir ldflag libdir list no_rebuild prefix profile prune show_model verbose working_dir Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: bindir logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: includedir character(len=:), public, allocatable :: ldflag character(len=:), public, allocatable :: libdir logical, public :: list = .false. logical, public :: no_rebuild character(len=:), public, allocatable :: prefix character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_install_settings.html"},{"title":"fpm_new_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_new_settings Contents Variables backfill name verbose with_bare with_example with_executable with_full with_lib with_test working_dir Components Type Visibility Attributes Name Initial logical, public :: backfill = .true. character(len=:), public, allocatable :: name logical, public :: verbose = .true. logical, public :: with_bare = .false. logical, public :: with_example = .false. logical, public :: with_executable = .false. logical, public :: with_full = .false. logical, public :: with_lib = .true. logical, public :: with_test = .false. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_new_settings.html"},{"title":"fpm_publish_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_publish_settings Contents Variables archiver build_tests c_compiler cflag compiler cxx_compiler cxxflag flag is_dry_run ldflag list profile prune show_model show_package_version show_upload_data token verbose working_dir Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag logical, public :: is_dry_run = .false. character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: show_package_version = .false. logical, public :: show_upload_data = .false. character(len=:), public, allocatable :: token logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_publish_settings.html"},{"title":"fpm_run_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_run_settings Contents Variables archiver args build_tests c_compiler cflag compiler cxx_compiler cxxflag example flag ldflag list name profile prune runner runner_args show_model verbose working_dir Type-Bound Procedures runner_command Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure, public, :: runner_command private function runner_command(cmd) result(run_cmd) Build a full runner command (executable + command-line arguments)\nGet executable\nAppend command-line arguments Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(in) :: cmd Return Value character(len=:), allocatable","tags":"","loc":"type/fpm_run_settings.html"},{"title":"fpm_test_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_run_settings ) :: fpm_test_settings Contents Variables archiver args build_tests c_compiler cflag compiler cxx_compiler cxxflag example flag ldflag list name profile prune runner runner_args show_model verbose working_dir Type-Bound Procedures runner_command Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure, public, :: runner_command private function runner_command(cmd) result(run_cmd) Build a full runner command (executable + command-line arguments)\nGet executable\nAppend command-line arguments Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(in) :: cmd Return Value character(len=:), allocatable","tags":"","loc":"type/fpm_test_settings.html"},{"title":"fpm_update_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_update_settings Settings for interacting and updating with project dependencies Contents Variables clean fetch_only name verbose working_dir Components Type Visibility Attributes Name Initial logical, public :: clean logical, public :: fetch_only character(len=ibug), public, allocatable :: name (:) logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","loc":"type/fpm_update_settings.html"},{"title":"metapackage_t – Fortran-lang/fpm ","text":"type, public :: metapackage_t Type for describing a source file Contents Variables cflags cxxflags dependency external_modules fflags flags fortran has_build_flags has_c_flags has_cxx_flags has_dependencies has_external_modules has_fortran_flags has_include_dirs has_link_flags has_link_libraries has_run_command incl_dirs link_flags link_libs run_command version Type-Bound Procedures destroy new resolve Source Code metapackage_t Components Type Visibility Attributes Name Initial type( string_t ), public :: cflags type( string_t ), public :: cxxflags type( dependency_config_t ), public, allocatable :: dependency (:) List of Development dependency meta data.\nMetapackage dependencies are never exported from the model type( string_t ), public, allocatable :: external_modules (:) type( string_t ), public :: fflags type( string_t ), public :: flags List of compiler flags and options to be added type( fortran_features_t ), public, allocatable :: fortran Special fortran features logical, public :: has_build_flags = .false. logical, public :: has_c_flags = .false. logical, public :: has_cxx_flags = .false. logical, public :: has_dependencies = .false. logical, public :: has_external_modules = .false. logical, public :: has_fortran_flags = .false. logical, public :: has_include_dirs = .false. logical, public :: has_link_flags = .false. logical, public :: has_link_libraries = .false. logical, public :: has_run_command = .false. type( string_t ), public, allocatable :: incl_dirs (:) type( string_t ), public :: link_flags type( string_t ), public, allocatable :: link_libs (:) type( string_t ), public :: run_command type( version_t ), public, allocatable :: version Package version (if supported) Type-Bound Procedures procedure, public, :: destroy Clean metapackage structure private elemental subroutine destroy(this) Clean the metapackage structure Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this procedure, public, :: new => init_from_name Initialize the metapackage structure from its given name private subroutine init_from_name(this, name, compiler, error) Initialize a metapackage from the given name\nInitialize metapackage by name Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this character(len=*), intent(in) :: name type( compiler_t ), intent(in) :: compiler type( error_t ), intent(out), allocatable :: error generic, public, :: resolve => resolve_cmd, resolve_model, resolve_package_config private subroutine resolve_cmd(self, settings, error) Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(in) :: self class( fpm_cmd_settings ), intent(inout) :: settings type( error_t ), intent(out), allocatable :: error private subroutine resolve_model(self, model, error) Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(in) :: self type( fpm_model_t ), intent(inout) :: model type( error_t ), intent(out), allocatable :: error private subroutine resolve_package_config(self, package, error) Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(in) :: self type( package_config_t ), intent(inout) :: package type( error_t ), intent(out), allocatable :: error Source Code type , public :: metapackage_t !> Package version (if supported) type ( version_t ), allocatable :: version logical :: has_link_libraries = . false . logical :: has_link_flags = . false . logical :: has_build_flags = . false . logical :: has_fortran_flags = . false . logical :: has_c_flags = . false . logical :: has_cxx_flags = . false . logical :: has_include_dirs = . false . logical :: has_dependencies = . false . logical :: has_run_command = . false . logical :: has_external_modules = . false . !> List of compiler flags and options to be added type ( string_t ) :: flags type ( string_t ) :: fflags type ( string_t ) :: cflags type ( string_t ) :: cxxflags type ( string_t ) :: link_flags type ( string_t ) :: run_command type ( string_t ), allocatable :: incl_dirs (:) type ( string_t ), allocatable :: link_libs (:) type ( string_t ), allocatable :: external_modules (:) !> Special fortran features type ( fortran_features_t ), allocatable :: fortran !> List of Development dependency meta data. !> Metapackage dependencies are never exported from the model type ( dependency_config_t ), allocatable :: dependency (:) contains !> Clean metapackage structure procedure :: destroy !> Initialize the metapackage structure from its given name procedure :: new => init_from_name !> Add metapackage dependencies to the model procedure , private :: resolve_cmd procedure , private :: resolve_model procedure , private :: resolve_package_config generic :: resolve => resolve_cmd , resolve_model , resolve_package_config end type metapackage_t","tags":"","loc":"type/metapackage_t.html"},{"title":"build_progress_t – Fortran-lang/fpm ","text":"type, public :: build_progress_t Build progress object Contents Variables console n_complete n_target output_lines plain_mode target_queue Constructor build_progress_t Type-Bound Procedures compiling_status completed_status success Source Code build_progress_t Components Type Visibility Attributes Name Initial type( console_t ), public :: console Console object for updating console lines integer, public :: n_complete Number of completed targets integer, public :: n_target Total number of targets scheduled integer, public, allocatable :: output_lines (:) Store needed when updating previous console lines logical, public :: plain_mode = .true. ‘Plain’ output (no colors or updating) type( build_target_ptr ), public, pointer :: target_queue (:) Queue of scheduled build targets Constructor public interface build_progress_t Constructor for build_progress_t private function new_build_progress(target_queue, plain_mode) result(progress) Initialise a new build progress object Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in), target :: target_queue (:) The queue of scheduled targets logical, intent(in), optional :: plain_mode Enable ‘plain’ output for progress object Return Value type( build_progress_t ) Progress object to initialise Type-Bound Procedures procedure, public, :: compiling_status => output_status_compiling Output ‘compiling’ status for build target private subroutine output_status_compiling(progress, queue_index) Output ‘compiling’ status for build target and overall percentage progress Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress Progress object integer, intent(in) :: queue_index Index of build target in the target queue procedure, public, :: completed_status => output_status_complete Output ‘complete’ status for build target private subroutine output_status_complete(progress, queue_index, build_stat) Output ‘complete’ status for build target and update overall percentage progress Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress Progress object integer, intent(in) :: queue_index Index of build target in the target queue integer, intent(in) :: build_stat Build status flag procedure, public, :: success => output_progress_success Output finished status for whole package private subroutine output_progress_success(progress) Output finished status for whole package Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress Source Code type build_progress_t !> Console object for updating console lines type ( console_t ) :: console !> Number of completed targets integer :: n_complete !> Total number of targets scheduled integer :: n_target !> 'Plain' output (no colors or updating) logical :: plain_mode = . true . !> Store needed when updating previous console lines integer , allocatable :: output_lines (:) !> Queue of scheduled build targets type ( build_target_ptr ), pointer :: target_queue (:) contains !> Output 'compiling' status for build target procedure :: compiling_status => output_status_compiling !> Output 'complete' status for build target procedure :: completed_status => output_status_complete !> Output finished status for whole package procedure :: success => output_progress_success end type build_progress_t","tags":"","loc":"type/build_progress_t.html"},{"title":"string_t – Fortran-lang/fpm ","text":"type, public :: string_t Contents Variables s Constructor string_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: s Constructor public interface string_t private function new_string_t(s) result(string) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s Return Value type( string_t )","tags":"","loc":"type/string_t.html"},{"title":"fortran_features_t – Fortran-lang/fpm ","text":"type, public :: fortran_features_t Enabled Fortran language features Contents Variables implicit_external implicit_typing source_form Source Code fortran_features_t Components Type Visibility Attributes Name Initial logical, public :: implicit_external = .false. Use implicit external interface logical, public :: implicit_typing = .false. Use default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Source Code type :: fortran_features_t !> Use default implicit typing logical :: implicit_typing = . false . !> Use implicit external interface logical :: implicit_external = . false . !> Form to use for all Fortran sources character (:), allocatable :: source_form end type fortran_features_t","tags":"","loc":"type/fortran_features_t.html"},{"title":"fpm_model_t – Fortran-lang/fpm ","text":"type, public :: fpm_model_t Type describing everything required to build\n the root package and its dependencies. Contents Variables archiver build_prefix c_compile_flags compiler cxx_compile_flags deps enforce_module_names external_modules fortran_compile_flags include_dirs include_tests link_flags link_libraries module_prefix package_name packages Source Code fpm_model_t Components Type Visibility Attributes Name Initial type( archiver_t ), public :: archiver Archiver object character(len=:), public, allocatable :: build_prefix Base directory for build character(len=:), public, allocatable :: c_compile_flags Command line flags passed to C for compilation type( compiler_t ), public :: compiler Compiler object character(len=:), public, allocatable :: cxx_compile_flags Command line flags passed to C++ for compilation type( dependency_tree_t ), public :: deps Project dependencies logical, public :: enforce_module_names = .false. Whether module names should be prefixed with the package name type( string_t ), public, allocatable :: external_modules (:) External modules used character(len=:), public, allocatable :: fortran_compile_flags Command line flags passed to fortran for compilation type( string_t ), public, allocatable :: include_dirs (:) Include directories logical, public :: include_tests = .true. Whether tests should be added to the build list character(len=:), public, allocatable :: link_flags Command line flags passed to the linker type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public :: module_prefix Prefix for all module names character(len=:), public, allocatable :: package_name Name of root package type(package_t), public, allocatable :: packages (:) Array of packages (including the root package) Source Code type :: fpm_model_t !> Name of root package character (:), allocatable :: package_name !> Array of packages (including the root package) type ( package_t ), allocatable :: packages (:) !> Compiler object type ( compiler_t ) :: compiler !> Archiver object type ( archiver_t ) :: archiver !> Command line flags passed to fortran for compilation character (:), allocatable :: fortran_compile_flags !> Command line flags passed to C for compilation character (:), allocatable :: c_compile_flags !> Command line flags passed to C++ for compilation character (:), allocatable :: cxx_compile_flags !> Command line flags passed to the linker character (:), allocatable :: link_flags !> Base directory for build character (:), allocatable :: build_prefix !> Include directories type ( string_t ), allocatable :: include_dirs (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> External modules used type ( string_t ), allocatable :: external_modules (:) !> Project dependencies type ( dependency_tree_t ) :: deps !> Whether tests should be added to the build list logical :: include_tests = . true . !> Whether module names should be prefixed with the package name logical :: enforce_module_names = . false . !> Prefix for all module names type ( string_t ) :: module_prefix end type fpm_model_t","tags":"","loc":"type/fpm_model_t.html"},{"title":"srcfile_t – Fortran-lang/fpm ","text":"type, public :: srcfile_t Type for describing a source file Contents Variables digest exe_name file_name include_dependencies link_libraries modules_provided modules_used parent_modules unit_scope unit_type Source Code srcfile_t Components Type Visibility Attributes Name Initial integer(kind=int64), public :: digest Current hash character(len=:), public, allocatable :: exe_name Name of executable for FPM_UNIT_PROGRAM character(len=:), public, allocatable :: file_name File path relative to cwd type( string_t ), public, allocatable :: include_dependencies (:) Files INCLUDEd by this source file type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: modules_provided (:) Modules provided by this source file (lowerstring) type( string_t ), public, allocatable :: modules_used (:) Modules USEd by this source file (lowerstring) type( string_t ), public, allocatable :: parent_modules (:) Parent modules (submodules only) integer, public :: unit_scope = FPM_SCOPE_UNKNOWN Target module-use scope integer, public :: unit_type = FPM_UNIT_UNKNOWN Type of source unit Source Code type srcfile_t !> File path relative to cwd character (:), allocatable :: file_name !> Name of executable for FPM_UNIT_PROGRAM character (:), allocatable :: exe_name !> Target module-use scope integer :: unit_scope = FPM_SCOPE_UNKNOWN !> Modules provided by this source file (lowerstring) type ( string_t ), allocatable :: modules_provided (:) !> Type of source unit integer :: unit_type = FPM_UNIT_UNKNOWN !> Parent modules (submodules only) type ( string_t ), allocatable :: parent_modules (:) !> Modules USEd by this source file (lowerstring) type ( string_t ), allocatable :: modules_used (:) !> Files INCLUDEd by this source file type ( string_t ), allocatable :: include_dependencies (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Current hash integer ( int64 ) :: digest end type srcfile_t","tags":"","loc":"type/srcfile_t.html"},{"title":"build_target_ptr – Fortran-lang/fpm ","text":"type, public :: build_target_ptr Wrapper type for constructing arrays of build_target_t pointers Contents Variables ptr Source Code build_target_ptr Components Type Visibility Attributes Name Initial type( build_target_t ), public, pointer :: ptr => null() Source Code type build_target_ptr type ( build_target_t ), pointer :: ptr => null () end type build_target_ptr","tags":"","loc":"type/build_target_ptr.html"},{"title":"build_target_t – Fortran-lang/fpm ","text":"type, public :: build_target_t Type describing a generated build target Contents Variables compile_flags dependencies digest_cached features link_flags link_libraries link_objects macros output_dir output_file output_log_file output_name package_name schedule skip sorted source target_type touched version Source Code build_target_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: compile_flags Compile flags for this build target type( build_target_ptr ), public, allocatable :: dependencies (:) Resolved build dependencies integer(kind=int64), public, allocatable :: digest_cached Previous source file hash type( fortran_features_t ), public :: features Language features character(len=:), public, allocatable :: link_flags Link flags for this build target type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: link_objects (:) Objects needed to link this target type( string_t ), public, allocatable :: macros (:) List of macros character(len=:), public, allocatable :: output_dir File path of output directory character(len=:), public, allocatable :: output_file File path of build target object relative to cwd character(len=:), public, allocatable :: output_log_file File path of build log file relative to cwd character(len=:), public, allocatable :: output_name File path of build target object relative to output_dir character(len=:), public, allocatable :: package_name Name of parent package integer, public :: schedule = -1 Targets in the same schedule group are guaranteed to be independent logical, public :: skip = .false. Flag set if build target will be skipped (not built) logical, public :: sorted = .false. Flag set if build target is sorted for building type( srcfile_t ), public, allocatable :: source Primary source for this build target integer, public :: target_type = FPM_TARGET_UNKNOWN Target type logical, public :: touched = .false. Flag set when first visited to check for circular dependencies character(len=:), public, allocatable :: version Version number Source Code type build_target_t !> File path of build target object relative to cwd character (:), allocatable :: output_file !> File path of build target object relative to output_dir character (:), allocatable :: output_name !> File path of output directory character (:), allocatable :: output_dir !> File path of build log file relative to cwd character (:), allocatable :: output_log_file !> Name of parent package character (:), allocatable :: package_name !> Primary source for this build target type ( srcfile_t ), allocatable :: source !> Resolved build dependencies type ( build_target_ptr ), allocatable :: dependencies (:) !> Target type integer :: target_type = FPM_TARGET_UNKNOWN !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Objects needed to link this target type ( string_t ), allocatable :: link_objects (:) !> Link flags for this build target character (:), allocatable :: link_flags !> Compile flags for this build target character (:), allocatable :: compile_flags !> Flag set when first visited to check for circular dependencies logical :: touched = . false . !> Flag set if build target is sorted for building logical :: sorted = . false . !> Flag set if build target will be skipped (not built) logical :: skip = . false . !> Language features type ( fortran_features_t ) :: features !> Targets in the same schedule group are guaranteed to be independent integer :: schedule = - 1 !> Previous source file hash integer ( int64 ), allocatable :: digest_cached !> List of macros type ( string_t ), allocatable :: macros (:) !> Version number character (:), allocatable :: version end type build_target_t","tags":"","loc":"type/build_target_t.html"},{"title":"downloader_t – Fortran-lang/fpm ","text":"type, public :: downloader_t This type could be entirely avoided but it is quite practical because it can be mocked for testing. Contents Type-Bound Procedures get_file get_pkg_data unpack upload_form Type-Bound Procedures procedure, public, nopass :: get_file private subroutine get_file(url, tmp_pkg_file, error) Download a file from a url using either curl or wget. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url character(len=*), intent(in) :: tmp_pkg_file type( error_t ), intent(out), allocatable :: error procedure, public, nopass :: get_pkg_data private subroutine get_pkg_data(url, version, tmp_pkg_file, json, error) Perform an http get request, save output to file, and parse json. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url type( version_t ), intent(in), allocatable :: version character(len=*), intent(in) :: tmp_pkg_file type(json_object), intent(out) :: json type( error_t ), intent(out), allocatable :: error procedure, public, nopass :: unpack private subroutine unpack(tmp_pkg_file, destination, error) Unpack a tarball to a destination. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: tmp_pkg_file Path to tarball. character(len=*), intent(in) :: destination Destination to unpack to. type( error_t ), intent(out), allocatable :: error Error handling. procedure, public, nopass :: upload_form private subroutine upload_form(endpoint, form_data, verbose, error) Perform an http post request with form data. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: endpoint Endpoint to upload to. type( string_t ), intent(in) :: form_data (:) Form data to upload. logical, intent(in) :: verbose Print additional information if true. type( error_t ), intent(out), allocatable :: error Error handling.","tags":"","loc":"type/downloader_t.html"},{"title":"dependency_node_t – Fortran-lang/fpm ","text":"type, public, extends( dependency_config_t ) :: dependency_node_t Dependency node in the projects dependency tree Contents Variables cached done git name namespace path preprocess proj_dir requested_version revision update version Type-Bound Procedures get_from_registry info register Source Code dependency_node_t Components Type Visibility Attributes Name Initial logical, public :: cached = .false. Dependency was loaded from a cache logical, public :: done = .false. Dependency is handled type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency character(len=:), public, allocatable :: proj_dir Installation prefix of this dependencies type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. character(len=:), public, allocatable :: revision Checked out revision of the version control system logical, public :: update = .false. Dependency should be updated type( version_t ), public, allocatable :: version Actual version of this dependency Type-Bound Procedures procedure, public, :: get_from_registry Get dependency from the registry. private subroutine get_from_registry(self, target_dir, global_settings, error, downloader_) Get a dependency from the registry. Whether the dependency is fetched\nfrom a local, a custom remote or the official registry is determined\nby the global configuration settings. Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(in) :: self Instance of the dependency configuration. character(len=:), intent(out), allocatable :: target_dir The target directory of the dependency. type( fpm_global_settings ), intent(in) :: global_settings Global configuration settings. type( error_t ), intent(out), allocatable :: error Error handling. class( downloader_t ), intent(in), optional :: downloader_ Downloader instance. procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Call base object info Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(in) :: self Instance of the dependency configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout procedure, public, :: register Update dependency from project manifest. private subroutine register(self, package, root, fetch, revision, error) Update dependency from project manifest Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(inout) :: self Instance of the dependency node type( package_config_t ), intent(in) :: package Package configuration data character(len=*), intent(in) :: root Root directory of the project logical, intent(in) :: fetch Project has been fetched character(len=*), intent(in), optional :: revision Git revision of the project type( error_t ), intent(out), allocatable :: error Error handling Source Code type , extends ( dependency_config_t ) :: dependency_node_t !> Actual version of this dependency type ( version_t ), allocatable :: version !> Installation prefix of this dependencies character ( len = :), allocatable :: proj_dir !> Checked out revision of the version control system character ( len = :), allocatable :: revision !> Dependency is handled logical :: done = . false . !> Dependency should be updated logical :: update = . false . !> Dependency was loaded from a cache logical :: cached = . false . contains !> Update dependency from project manifest. procedure :: register !> Get dependency from the registry. procedure :: get_from_registry procedure , private :: get_from_local_registry !> Print information on this instance procedure :: info end type dependency_node_t","tags":"","loc":"type/dependency_node_t.html"},{"title":"dependency_tree_t – Fortran-lang/fpm ","text":"type, public :: dependency_tree_t Respresentation of a projects dependencies The dependencies are stored in a simple array for now, this can be replaced\nwith a binary-search tree or a hash table in the future. Contents Variables cache dep dep_dir ndep unit verbosity Type-Bound Procedures add dump find finished has load resolve update Source Code dependency_tree_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cache Cache file type( dependency_node_t ), public, allocatable :: dep (:) Flattend list of all dependencies character(len=:), public, allocatable :: dep_dir Installation prefix for dependencies integer, public :: ndep = 0 Number of currently registered dependencies integer, public :: unit = output_unit Unit for IO integer, public :: verbosity = 1 Verbosity of printout Type-Bound Procedures generic, public, :: add => add_project, add_project_dependencies, add_dependencies, add_dependency, add_dependency_node Overload procedure to add new dependencies to the tree private subroutine add_project(self, package, error) Add project dependencies, each depth level after each other. We implement this algorithm in an interative rather than a recursive fashion\nas a choice of design. Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( package_config_t ), intent(in) :: package Project configuration to add type( error_t ), intent(out), allocatable :: error Error handling private recursive subroutine add_project_dependencies(self, package, root, main, error) Add a project and its dependencies to the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( package_config_t ), intent(in) :: package Project configuration to add character(len=*), intent(in) :: root Current project root directory logical, intent(in) :: main Is the main project type( error_t ), intent(out), allocatable :: error Error handling private subroutine add_dependencies(self, dependency, error) Add a list of dependencies to the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_config_t ), intent(in) :: dependency (:) Dependency configuration to add type( error_t ), intent(out), allocatable :: error Error handling private subroutine add_dependency(self, dependency, error) Add a single dependency to the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_config_t ), intent(in) :: dependency Dependency configuration to add type( error_t ), intent(out), allocatable :: error Error handling private subroutine add_dependency_node(self, dependency, error) Add a single dependency node to the dependency tree\nDependency nodes contain additional information (version, git, revision) Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_node_t ), intent(in) :: dependency Dependency configuration to add type( error_t ), intent(out), allocatable :: error Error handling generic, public, :: dump => dump_to_file, dump_to_unit, dump_to_toml Writing of dependency tree private subroutine dump_to_file(self, file, error) Write dependency tree to file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_unit(self, unit, error) Write dependency tree to file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_toml(self, table, error) Write dependency tree to TOML datastructure Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public, :: find => find_name Find a dependency in the tree private pure function find_name(self, name) result(pos) Find a dependency in the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: self Instance of the dependency tree character(len=*), intent(in) :: name Dependency configuration to add Return Value integer Index of the dependency procedure, public, :: finished Depedendncy resolution finished private pure function finished(self) Check if we are done with the dependency resolution Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: self Instance of the dependency tree Return Value logical All dependencies are updated generic, public, :: has => has_dependency True if entity can be found private pure function has_dependency(self, dependency) True if dependency is part of the tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: self Instance of the dependency tree class( dependency_node_t ), intent(in) :: dependency Dependency configuration to check Return Value logical generic, public, :: load => load_from_file, load_from_unit, load_from_toml Reading of dependency tree private subroutine load_from_file(self, file, error) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_unit(self, unit, error) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_toml(self, table, error) Read dependency tree from TOML data structure Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public, :: resolve => resolve_dependencies, resolve_dependency Resolve dependencies private subroutine resolve_dependencies(self, root, error) Resolve all dependencies in the tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: root Current installation prefix type( error_t ), intent(out), allocatable :: error Error handling private subroutine resolve_dependency(self, dependency, global_settings, root, error) Resolve a single dependency node Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_node_t ), intent(inout) :: dependency Dependency configuration to add type( fpm_global_settings ), intent(in) :: global_settings Global configuration settings. character(len=*), intent(in) :: root Current installation prefix type( error_t ), intent(out), allocatable :: error Error handling generic, public, :: update => update_dependency, update_tree Update dependency tree private subroutine update_dependency(self, name, error) Update dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: name Name of the dependency to update type( error_t ), intent(out), allocatable :: error Error handling private subroutine update_tree(self, error) Update whole dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( error_t ), intent(out), allocatable :: error Error handling Source Code type :: dependency_tree_t !> Unit for IO integer :: unit = output_unit !> Verbosity of printout integer :: verbosity = 1 !> Installation prefix for dependencies character ( len = :), allocatable :: dep_dir !> Number of currently registered dependencies integer :: ndep = 0 !> Flattend list of all dependencies type ( dependency_node_t ), allocatable :: dep (:) !> Cache file character ( len = :), allocatable :: cache contains !> Overload procedure to add new dependencies to the tree generic :: add => add_project , add_project_dependencies , add_dependencies , & add_dependency , add_dependency_node !> Main entry point to add a project procedure , private :: add_project !> Add a project and its dependencies to the dependency tree procedure , private :: add_project_dependencies !> Add a list of dependencies to the dependency tree procedure , private :: add_dependencies !> Add a single dependency to the dependency tree procedure , private :: add_dependency !> Add a single dependency node to the dependency tree procedure , private :: add_dependency_node !> Resolve dependencies generic :: resolve => resolve_dependencies , resolve_dependency !> Resolve dependencies procedure , private :: resolve_dependencies !> Resolve dependency procedure , private :: resolve_dependency !> True if entity can be found generic :: has => has_dependency !> True if dependency is part of the tree procedure , private :: has_dependency !> Find a dependency in the tree generic :: find => find_name !> Find a dependency by its name procedure , private :: find_name !> Depedendncy resolution finished procedure :: finished !> Reading of dependency tree generic :: load => load_from_file , load_from_unit , load_from_toml !> Read dependency tree from file procedure , private :: load_from_file !> Read dependency tree from formatted unit procedure , private :: load_from_unit !> Read dependency tree from TOML data structure procedure , private :: load_from_toml !> Writing of dependency tree generic :: dump => dump_to_file , dump_to_unit , dump_to_toml !> Write dependency tree to file procedure , private :: dump_to_file !> Write dependency tree to formatted unit procedure , private :: dump_to_unit !> Write dependency tree to TOML data structure procedure , private :: dump_to_toml !> Update dependency tree generic :: update => update_dependency , update_tree !> Update a list of dependencies procedure , private :: update_dependency !> Update all dependencies in the tree procedure , private :: update_tree end type dependency_tree_t","tags":"","loc":"type/dependency_tree_t.html"},{"title":"version_t – Fortran-lang/fpm ","text":"type, public :: version_t Contents Type-Bound Procedures operator(.match.) operator(/=) operator(<) operator(<=) operator(==) operator(>) operator(>=) s Source Code version_t Type-Bound Procedures generic, public, :: operator(.match.) => match Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) private elemental function match(lhs, rhs) Try to match first version against second version Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical Version match following semantic versioning rules generic, public, :: operator(/=) => not_equals private elemental function not_equals(lhs, rhs) result(not_equal) Check two versions for inequality Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical Version mismatch generic, public, :: operator(<) => less private elemental function less(lhs, rhs) result(is_less) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is less generic, public, :: operator(<=) => less_equals private elemental function less_equals(lhs, rhs) result(is_less_equal) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is less or equal generic, public, :: operator(==) => equals private elemental function equals(lhs, rhs) result(is_equal) Check to version numbers for equality Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical Version match generic, public, :: operator(>) => greater private elemental function greater(lhs, rhs) result(is_greater) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is greater generic, public, :: operator(>=) => greater_equals private elemental function greater_equals(lhs, rhs) result(is_greater_equal) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is greater or equal procedure, public, :: s Create a printable string from a version data type private pure function s(self) result(string) Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: self Version number Return Value character(len=:), allocatable Character representation of the version Source Code type :: version_t private !> Version numbers found integer , allocatable :: num (:) contains generic :: operator ( == ) => equals procedure , private :: equals generic :: operator ( /= ) => not_equals procedure , private :: not_equals generic :: operator ( > ) => greater procedure , private :: greater generic :: operator ( < ) => less procedure , private :: less generic :: operator ( >= ) => greater_equals procedure , private :: greater_equals generic :: operator ( <= ) => less_equals procedure , private :: less_equals !> Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) generic :: operator (. match .) => match procedure , private :: match !> Create a printable string from a version data type procedure :: s end type version_t","tags":"","loc":"type/version_t.html"},{"title":"error_t – Fortran-lang/fpm ","text":"type, public :: error_t Data type defining an error Contents Variables message Source Code error_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: message Error message Source Code type :: error_t !> Error message character ( len = :), allocatable :: message end type error_t","tags":"","loc":"type/error_t.html"},{"title":"enum_descriptor – Fortran-lang/fpm ","text":"type, public :: enum_descriptor Possible git target Contents Variables branch default revision tag Source Code enum_descriptor Components Type Visibility Attributes Name Initial integer, public :: branch = 201 Branch in git repository integer, public :: default = 200 Default target integer, public :: revision = 203 Commit hash integer, public :: tag = 202 Tag in git repository Source Code type :: enum_descriptor !> Default target integer :: default = 200 !> Branch in git repository integer :: branch = 201 !> Tag in git repository integer :: tag = 202 !> Commit hash integer :: revision = 203 end type enum_descriptor","tags":"","loc":"type/enum_descriptor.html"},{"title":"git_target_t – Fortran-lang/fpm ","text":"type, public :: git_target_t Description of an git target Contents Variables descriptor object url Type-Bound Procedures checkout info Source Code git_target_t Components Type Visibility Attributes Name Initial integer, public :: descriptor = git_descriptor%default Kind of the git target character(len=:), public, allocatable :: object Additional descriptor of the git object character(len=:), public, allocatable :: url Target URL of the git repository Type-Bound Procedures procedure, public, :: checkout Fetch and checkout in local directory public subroutine checkout (self, local_path, error) Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target character(len=*), intent(in) :: local_path Local path to checkout in type( error_t ), intent(out), allocatable :: error Error procedure, public, :: info Show information on instance public subroutine info (self, unit, verbosity) Show information on git target Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: git_target_t !> Kind of the git target integer :: descriptor = git_descriptor % default !> Target URL of the git repository character ( len = :), allocatable :: url !> Additional descriptor of the git object character ( len = :), allocatable :: object contains !> Fetch and checkout in local directory procedure :: checkout !> Show information on instance procedure :: info end type git_target_t","tags":"","loc":"type/git_target_t.html"},{"title":"installer_t – Fortran-lang/fpm ","text":"type, public :: installer_t Declaration of the installer type Contents Variables bindir copy includedir libdir move os prefix unit verbosity Type-Bound Procedures install install_executable install_header install_library make_dir run Source Code installer_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: bindir Binary dir relative to the installation prefix character(len=:), public, allocatable :: copy Command to copy objects into the installation prefix character(len=:), public, allocatable :: includedir Include directory relative to the installation prefix character(len=:), public, allocatable :: libdir Library directory relative to the installation prefix character(len=:), public, allocatable :: move Command to move objects into the installation prefix integer, public :: os Cached operating system character(len=:), public, allocatable :: prefix Path to installation directory integer, public :: unit = output_unit Output unit for informative printout integer, public :: verbosity = 1 Verbosity of the installer Type-Bound Procedures procedure, public, :: install Install a generic file into a subdirectory in the installation prefix private subroutine install(self, source, destination, error) Install a generic file into a subdirectory in the installation prefix Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: source Path to the original file character(len=*), intent(in) :: destination Path to the destination inside the prefix type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: install_executable Install an executable in its correct subdirectory private subroutine install_executable(self, executable, error) Install an executable in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: executable Path to the executable type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: install_header Install a header/module in its correct subdirectory private subroutine install_header(self, header, error) Install a header/module in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: header Path to the header type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: install_library Install a library in its correct subdirectory private subroutine install_library(self, library, error) Install a library in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: library Path to the library type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: make_dir Create a new directory in the prefix, type-bound for unit testing purposes private subroutine make_dir(self, dir, error) Create a new directory in the prefix Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: dir Directory to be created type( error_t ), intent(out), allocatable :: error Error handling procedure, public, :: run Run an installation command, type-bound for unit testing purposes private subroutine run(self, command, error) Run an installation command Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: command Command to be launched type( error_t ), intent(out), allocatable :: error Error handling Source Code type :: installer_t !> Path to installation directory character ( len = :), allocatable :: prefix !> Binary dir relative to the installation prefix character ( len = :), allocatable :: bindir !> Library directory relative to the installation prefix character ( len = :), allocatable :: libdir !> Include directory relative to the installation prefix character ( len = :), allocatable :: includedir !> Output unit for informative printout integer :: unit = output_unit !> Verbosity of the installer integer :: verbosity = 1 !> Command to copy objects into the installation prefix character ( len = :), allocatable :: copy !> Command to move objects into the installation prefix character ( len = :), allocatable :: move !> Cached operating system integer :: os contains !> Install an executable in its correct subdirectory procedure :: install_executable !> Install a library in its correct subdirectory procedure :: install_library !> Install a header/module in its correct subdirectory procedure :: install_header !> Install a generic file into a subdirectory in the installation prefix procedure :: install !> Run an installation command, type-bound for unit testing purposes procedure :: run !> Create a new directory in the prefix, type-bound for unit testing purposes procedure :: make_dir end type installer_t","tags":"","loc":"type/installer_t.html"},{"title":"dependency_config_t – Fortran-lang/fpm ","text":"type, public :: dependency_config_t Configuration meta data for a dependency Contents Variables git name namespace path preprocess requested_version Type-Bound Procedures info Source Code dependency_config_t Components Type Visibility Attributes Name Initial type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: self Instance of the dependency configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: dependency_config_t !> Name of the dependency character ( len = :), allocatable :: name !> Local target character ( len = :), allocatable :: path !> Namespace which the dependency belongs to. !> Enables multiple dependencies with the same name. !> Required for dependencies that are obtained via the official registry. character ( len = :), allocatable :: namespace !> The requested version of the dependency. !> The latest version is used if not specified. type ( version_t ), allocatable :: requested_version !> Requested macros for the dependency type ( preprocess_config_t ), allocatable :: preprocess (:) !> Git descriptor type ( git_target_t ), allocatable :: git contains !> Print information on this instance procedure :: info end type dependency_config_t","tags":"","loc":"type/dependency_config_t.html"},{"title":"example_config_t – Fortran-lang/fpm ","text":"type, public, extends( executable_config_t ) :: example_config_t Configuation meta data for an example Contents Variables dependency link main name source_dir Type-Bound Procedures info Source Code example_config_t Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( example_config_t ), intent(in) :: self Instance of the example configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type , extends ( executable_config_t ) :: example_config_t contains !> Print information on this instance procedure :: info end type example_config_t","tags":"","loc":"type/example_config_t.html"},{"title":"metapackage_config_t – Fortran-lang/fpm ","text":"type, public :: metapackage_config_t Configuration data for metapackages Contents Variables minpack mpi openmp stdlib Source Code metapackage_config_t Components Type Visibility Attributes Name Initial type( metapackage_request_t ), public :: minpack fortran-lang minpack type( metapackage_request_t ), public :: mpi Request MPI support type( metapackage_request_t ), public :: openmp Request OpenMP support type( metapackage_request_t ), public :: stdlib Request stdlib support Source Code type :: metapackage_config_t !> Request MPI support type ( metapackage_request_t ) :: mpi !> Request OpenMP support type ( metapackage_request_t ) :: openmp !> Request stdlib support type ( metapackage_request_t ) :: stdlib !> fortran-lang minpack type ( metapackage_request_t ) :: minpack end type metapackage_config_t","tags":"","loc":"type/metapackage_config_t.html"},{"title":"metapackage_request_t – Fortran-lang/fpm ","text":"type, public :: metapackage_request_t Configuration data for a single metapackage request Contents Variables name on version Source Code metapackage_request_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: name Metapackage name logical, public :: on = .false. Request flag character(len=:), public, allocatable :: version Version Specification string Source Code type :: metapackage_request_t !> Request flag logical :: on = . false . !> Metapackage name character ( len = :), allocatable :: name !> Version Specification string character ( len = :), allocatable :: version end type metapackage_request_t","tags":"","loc":"type/metapackage_request_t.html"},{"title":"test_config_t – Fortran-lang/fpm ","text":"type, public, extends( executable_config_t ) :: test_config_t Configuation meta data for an test Contents Variables dependency link main name source_dir Type-Bound Procedures info Source Code test_config_t Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( test_config_t ), intent(in) :: self Instance of the test configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type , extends ( executable_config_t ) :: test_config_t contains !> Print information on this instance procedure :: info end type test_config_t","tags":"","loc":"type/test_config_t.html"},{"title":"library_config_t – Fortran-lang/fpm ","text":"type, public :: library_config_t Configuration meta data for a library Contents Variables build_script include_dir source_dir Type-Bound Procedures info Source Code library_config_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: build_script Alternative build script to be invoked type( string_t ), public, allocatable :: include_dir (:) Include path prefix character(len=:), public, allocatable :: source_dir Source path prefix Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( library_config_t ), intent(in) :: self Instance of the library configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: library_config_t !> Source path prefix character ( len = :), allocatable :: source_dir !> Include path prefix type ( string_t ), allocatable :: include_dir (:) !> Alternative build script to be invoked character ( len = :), allocatable :: build_script contains !> Print information on this instance procedure :: info end type library_config_t","tags":"","loc":"type/library_config_t.html"},{"title":"executable_config_t – Fortran-lang/fpm ","text":"type, public :: executable_config_t Configuation meta data for an executable Contents Variables dependency link main name source_dir Type-Bound Procedures info Source Code executable_config_t Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(in) :: self Instance of the executable configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: executable_config_t !> Name of the resulting executable character ( len = :), allocatable :: name !> Source directory for collecting the executable character ( len = :), allocatable :: source_dir !> Name of the source file declaring the main program character ( len = :), allocatable :: main !> Dependency meta data for this executable type ( dependency_config_t ), allocatable :: dependency (:) !> Libraries to link against type ( string_t ), allocatable :: link (:) contains !> Print information on this instance procedure :: info end type executable_config_t","tags":"","loc":"type/executable_config_t.html"},{"title":"fortran_config_t – Fortran-lang/fpm ","text":"type, public :: fortran_config_t Configuration data for Fortran Contents Variables implicit_external implicit_typing source_form Source Code fortran_config_t Components Type Visibility Attributes Name Initial logical, public :: implicit_external Enable implicit external interfaces logical, public :: implicit_typing Enable default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Source Code type :: fortran_config_t !> Enable default implicit typing logical :: implicit_typing !> Enable implicit external interfaces logical :: implicit_external !> Form to use for all Fortran sources character (:), allocatable :: source_form end type fortran_config_t","tags":"","loc":"type/fortran_config_t.html"},{"title":"build_config_t – Fortran-lang/fpm ","text":"type, public :: build_config_t Configuration data for build Contents Variables auto_examples auto_executables auto_tests external_modules link module_naming module_prefix Type-Bound Procedures info Source Code build_config_t Components Type Visibility Attributes Name Initial logical, public :: auto_examples Automatic discovery of examples logical, public :: auto_executables Automatic discovery of executables logical, public :: auto_tests Automatic discovery of tests type( string_t ), public, allocatable :: external_modules (:) External modules to use type( string_t ), public, allocatable :: link (:) Libraries to link against logical, public :: module_naming = .false. Enforcing of package module names type( string_t ), public :: module_prefix Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on build configuration instance Arguments Type Intent Optional Attributes Name class( build_config_t ), intent(in) :: self Instance of the build configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: build_config_t !> Automatic discovery of executables logical :: auto_executables !> Automatic discovery of examples logical :: auto_examples !> Automatic discovery of tests logical :: auto_tests !> Enforcing of package module names logical :: module_naming = . false . type ( string_t ) :: module_prefix !> Libraries to link against type ( string_t ), allocatable :: link (:) !> External modules to use type ( string_t ), allocatable :: external_modules (:) contains !> Print information on this instance procedure :: info end type build_config_t","tags":"","loc":"type/build_config_t.html"},{"title":"install_config_t – Fortran-lang/fpm ","text":"type, public :: install_config_t Configuration data for installation Contents Variables library Type-Bound Procedures info Source Code install_config_t Components Type Visibility Attributes Name Initial logical, public :: library Install library with this project Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on install configuration instance Arguments Type Intent Optional Attributes Name class( install_config_t ), intent(in) :: self Instance of the build configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: install_config_t !> Install library with this project logical :: library contains !> Print information on this instance procedure :: info end type install_config_t","tags":"","loc":"type/install_config_t.html"},{"title":"preprocess_config_t – Fortran-lang/fpm ","text":"type, public :: preprocess_config_t Configuration meta data for a preprocessor Contents Variables directories macros name suffixes Type-Bound Procedures info Source Code preprocess_config_t Components Type Visibility Attributes Name Initial type( string_t ), public, allocatable :: directories (:) Directories to search for files to be preprocessed type( string_t ), public, allocatable :: macros (:) Macros to be defined for the preprocessor character(len=:), public, allocatable :: name Name of the preprocessor type( string_t ), public, allocatable :: suffixes (:) Suffixes of the files to be preprocessed Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on this instance Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: self Instance of the preprocess configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: preprocess_config_t !> Name of the preprocessor character ( len = :), allocatable :: name !> Suffixes of the files to be preprocessed type ( string_t ), allocatable :: suffixes (:) !> Directories to search for files to be preprocessed type ( string_t ), allocatable :: directories (:) !> Macros to be defined for the preprocessor type ( string_t ), allocatable :: macros (:) contains !> Print information on this instance procedure :: info end type preprocess_config_t","tags":"","loc":"type/preprocess_config_t.html"},{"title":"package_config_t – Fortran-lang/fpm ","text":"type, public :: package_config_t Package meta data Contents Variables build dependency dev_dependency example executable fortran install library license meta name preprocess profiles test version Type-Bound Procedures info Source Code package_config_t Components Type Visibility Attributes Name Initial type( build_config_t ), public :: build Build configuration data type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data type( dependency_config_t ), public, allocatable :: dev_dependency (:) Development dependency meta data type( example_config_t ), public, allocatable :: example (:) Example meta data type( executable_config_t ), public, allocatable :: executable (:) Executable meta data type( fortran_config_t ), public :: fortran Fortran meta data type( install_config_t ), public :: install Installation configuration data type( library_config_t ), public, allocatable :: library Library meta data character(len=:), public, allocatable :: license License meta data type( metapackage_config_t ), public :: meta Metapackage data character(len=:), public, allocatable :: name Name of the package type( preprocess_config_t ), public, allocatable :: preprocess (:) Preprocess meta data type( profile_config_t ), public, allocatable :: profiles (:) Profiles meta data type( test_config_t ), public, allocatable :: test (:) Test meta data type( version_t ), public :: version Package version Type-Bound Procedures procedure, public, :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( package_config_t ), intent(in) :: self Instance of the package configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: package_config_t !> Name of the package character ( len = :), allocatable :: name !> Package version type ( version_t ) :: version !> Build configuration data type ( build_config_t ) :: build !> Metapackage data type ( metapackage_config_t ) :: meta !> Installation configuration data type ( install_config_t ) :: install !> Fortran meta data type ( fortran_config_t ) :: fortran !> License meta data character ( len = :), allocatable :: license !> Library meta data type ( library_config_t ), allocatable :: library !> Executable meta data type ( executable_config_t ), allocatable :: executable (:) !> Dependency meta data type ( dependency_config_t ), allocatable :: dependency (:) !> Development dependency meta data type ( dependency_config_t ), allocatable :: dev_dependency (:) !> Profiles meta data type ( profile_config_t ), allocatable :: profiles (:) !> Example meta data type ( example_config_t ), allocatable :: example (:) !> Test meta data type ( test_config_t ), allocatable :: test (:) !> Preprocess meta data type ( preprocess_config_t ), allocatable :: preprocess (:) contains !> Print information on this instance procedure :: info end type package_config_t","tags":"","loc":"type/package_config_t.html"},{"title":"file_scope_flag – Fortran-lang/fpm ","text":"type, public :: file_scope_flag Type storing file name - file scope compiler flags pairs Contents Variables file_name flags Source Code file_scope_flag Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: file_name Name of the file character(len=:), public, allocatable :: flags File scope flags Source Code type :: file_scope_flag !> Name of the file character ( len = :), allocatable :: file_name !> File scope flags character ( len = :), allocatable :: flags end type file_scope_flag","tags":"","loc":"type/file_scope_flag.html"},{"title":"profile_config_t – Fortran-lang/fpm ","text":"type, public :: profile_config_t Configuration meta data for a profile Contents Variables c_flags compiler cxx_flags file_scope_flags flags is_built_in link_time_flags os_type profile_name Type-Bound Procedures info Source Code profile_config_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags C compiler flags character(len=:), public, allocatable :: compiler Name of the compiler character(len=:), public, allocatable :: cxx_flags C++ compiler flags type( file_scope_flag ), public, allocatable :: file_scope_flags (:) File scope flags character(len=:), public, allocatable :: flags Fortran compiler flags logical, public :: is_built_in Is this profile one of the built-in ones? character(len=:), public, allocatable :: link_time_flags Link time compiler flags integer, public :: os_type Value repesenting OS character(len=:), public, allocatable :: profile_name Name of the profile Type-Bound Procedures procedure, public, :: info Print information on this instance public subroutine info (self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: self Instance of the profile configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Source Code type :: profile_config_t !> Name of the profile character ( len = :), allocatable :: profile_name !> Name of the compiler character ( len = :), allocatable :: compiler !> Value repesenting OS integer :: os_type !> Fortran compiler flags character ( len = :), allocatable :: flags !> C compiler flags character ( len = :), allocatable :: c_flags !> C++ compiler flags character ( len = :), allocatable :: cxx_flags !> Link time compiler flags character ( len = :), allocatable :: link_time_flags !> File scope flags type ( file_scope_flag ), allocatable :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical :: is_built_in contains !> Print information on this instance procedure :: info end type profile_config_t","tags":"","loc":"type/profile_config_t.html"},{"title":"build_package – Fortran-lang/fpm","text":"public subroutine build_package(targets, model, verbose) Top-level routine to build package described by model Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout) :: targets (:) type( fpm_model_t ), intent(in) :: model logical, intent(in) :: verbose Contents Source Code build_package Source Code subroutine build_package ( targets , model , verbose ) type ( build_target_ptr ), intent ( inout ) :: targets (:) type ( fpm_model_t ), intent ( in ) :: model logical , intent ( in ) :: verbose integer :: i , j type ( build_target_ptr ), allocatable :: queue (:) integer , allocatable :: schedule_ptr (:), stat (:) logical :: build_failed , skip_current type ( string_t ), allocatable :: build_dirs (:) type ( string_t ) :: temp type ( build_progress_t ) :: progress logical :: plain_output ! Need to make output directory for include (mod) files allocate ( build_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % output_dir . in . build_dirs ) cycle temp % s = target % output_dir build_dirs = [ build_dirs , temp ] end associate end do do i = 1 , size ( build_dirs ) call mkdir ( build_dirs ( i )% s , verbose ) end do ! Perform depth-first topological sort of targets do i = 1 , size ( targets ) call sort_target ( targets ( i )% ptr ) end do ! Construct build schedule queue call schedule_targets ( queue , schedule_ptr , targets ) ! Check if queue is empty if (. not . verbose . and . size ( queue ) < 1 ) then write ( stderr , '(a)' ) 'Project is up to date' return end if ! Initialise build status flags allocate ( stat ( size ( queue ))) stat (:) = 0 build_failed = . false . ! Set output mode #ifndef FPM_BOOTSTRAP plain_output = (. not .( c_isatty () == 1 )) . or . verbose #else plain_output = . true . #endif progress = build_progress_t ( queue , plain_output ) ! Loop over parallel schedule regions do i = 1 , size ( schedule_ptr ) - 1 ! Build targets in schedule region i !$omp parallel do default(shared) private(skip_current) schedule(dynamic,1) do j = schedule_ptr ( i ),( schedule_ptr ( i + 1 ) - 1 ) ! Check if build already failed !$omp atomic read skip_current = build_failed if (. not . skip_current ) then call progress % compiling_status ( j ) call build_target ( model , queue ( j )% ptr , verbose , stat ( j )) call progress % completed_status ( j , stat ( j )) end if ! Set global flag if this target failed to build if ( stat ( j ) /= 0 ) then !$omp atomic write build_failed = . true . end if end do ! Check if this schedule region failed: exit with message if failed if ( build_failed ) then write ( * , * ) do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) Then call print_build_log ( queue ( j )% ptr ) end if end do do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Compilation failed for object \"' , basename ( queue ( j )% ptr % output_file ), '\"' end if end do call fpm_stop ( 1 , 'stopping due to failed compilation' ) end if end do call progress % success () end subroutine build_package","tags":"","loc":"proc/build_package.html"},{"title":"schedule_targets – Fortran-lang/fpm","text":"public subroutine schedule_targets(queue, schedule_ptr, targets) Construct a build schedule from the sorted targets. The schedule is broken into regions, described by schedule_ptr ,\n where targets in each region can be compiled in parallel. Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: queue (:) integer, allocatable :: schedule_ptr (:) type( build_target_ptr ), intent(in) :: targets (:) Contents Source Code schedule_targets Source Code subroutine schedule_targets ( queue , schedule_ptr , targets ) type ( build_target_ptr ), allocatable , intent ( out ) :: queue (:) integer , allocatable :: schedule_ptr (:) type ( build_target_ptr ), intent ( in ) :: targets (:) integer :: i , j integer :: n_schedule , n_sorted n_schedule = 0 ! Number of schedule regions n_sorted = 0 ! Total number of targets to build do i = 1 , size ( targets ) if ( targets ( i )% ptr % sorted ) then n_sorted = n_sorted + 1 end if n_schedule = max ( n_schedule , targets ( i )% ptr % schedule ) end do allocate ( queue ( n_sorted )) allocate ( schedule_ptr ( n_schedule + 1 )) ! Construct the target queue and schedule region pointer n_sorted = 1 schedule_ptr ( n_sorted ) = 1 do i = 1 , n_schedule do j = 1 , size ( targets ) if ( targets ( j )% ptr % sorted ) then if ( targets ( j )% ptr % schedule == i ) then queue ( n_sorted )% ptr => targets ( j )% ptr n_sorted = n_sorted + 1 end if end if end do schedule_ptr ( i + 1 ) = n_sorted end do end subroutine schedule_targets","tags":"","loc":"proc/schedule_targets.html"},{"title":"sort_target – Fortran-lang/fpm","text":"public recursive subroutine sort_target(target) Topologically sort a target for scheduling by\n recursing over its dependencies. Checks disk-cached source hashes to determine if objects are\n up-to-date. Up-to-date sources are tagged as skipped. On completion, target should either be marked as\nsorted ( target%sorted=.true. ) or skipped ( target%skip=.true. ) If target is marked as sorted, target%schedule should be an\ninteger greater than zero indicating the region for scheduling Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout), target :: target Contents Source Code sort_target Source Code recursive subroutine sort_target ( target ) type ( build_target_t ), intent ( inout ), target :: target integer :: i , fh , stat ! Check if target has already been processed (as a dependency) if ( target % sorted . or . target % skip ) then return end if ! Check for a circular dependency ! (If target has been touched but not processed) if ( target % touched ) then call fpm_stop ( 1 , '(!) Circular dependency found with: ' // target % output_file ) else target % touched = . true . ! Set touched flag end if ! Load cached source file digest if present if (. not . allocated ( target % digest_cached ) . and . & exists ( target % output_file ) . and . & exists ( target % output_file // '.digest' )) then allocate ( target % digest_cached ) open ( newunit = fh , file = target % output_file // '.digest' , status = 'old' ) read ( fh , * , iostat = stat ) target % digest_cached close ( fh ) if ( stat /= 0 ) then ! Cached digest is not recognized deallocate ( target % digest_cached ) end if end if if ( allocated ( target % source )) then ! Skip if target is source-based and source file is unmodified if ( allocated ( target % digest_cached )) then if ( target % digest_cached == target % source % digest ) target % skip = . true . end if elseif ( exists ( target % output_file )) then ! Skip if target is not source-based and already exists target % skip = . true . end if ! Loop over target dependencies target % schedule = 1 do i = 1 , size ( target % dependencies ) ! Sort dependency call sort_target ( target % dependencies ( i )% ptr ) if (. not . target % dependencies ( i )% ptr % skip ) then ! Can't skip target if any dependency is not skipped target % skip = . false . ! Set target schedule after all of its dependencies target % schedule = max ( target % schedule , target % dependencies ( i )% ptr % schedule + 1 ) end if end do ! Mark flag as processed: either sorted or skipped target % sorted = . not . target % skip end subroutine sort_target","tags":"","loc":"proc/sort_target.html"},{"title":"check_compiler – Fortran-lang/fpm","text":"public function check_compiler(compiler, expected) result(match) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler character(len=*), intent(in) :: expected Return Value logical Contents Source Code check_compiler Source Code function check_compiler ( compiler , expected ) result ( match ) character ( len =* ), intent ( in ) :: compiler character ( len =* ), intent ( in ) :: expected logical :: match match = compiler == expected if (. not . match ) then match = index ( basename ( compiler ), expected ) > 0 end if end function check_compiler","tags":"","loc":"proc/check_compiler.html"},{"title":"compiler_name – Fortran-lang/fpm","text":"public pure function compiler_name(self) result(name) Return a compiler name string Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string Contents Source Code compiler_name Source Code pure function compiler_name ( self ) result ( name ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: name select case ( self % id ) case ( id_gcc ); name = \"gfortran\" case ( id_f95 ); name = \"f95\" case ( id_caf ); name = \"caf\" case ( id_intel_classic_nix ); name = \"ifort\" case ( id_intel_classic_mac ); name = \"ifort\" case ( id_intel_classic_windows ); name = \"ifort\" case ( id_intel_llvm_nix ); name = \"ifx\" case ( id_intel_llvm_windows ); name = \"ifx\" case ( id_intel_llvm_unknown ); name = \"ifx\" case ( id_pgi ); name = \"pgfortran\" case ( id_nvhpc ); name = \"nvfortran\" case ( id_nag ); name = \"nagfor\" case ( id_flang ); name = \"flang\" case ( id_flang_new ); name = \"flang-new\" case ( id_f18 ); name = \"f18\" case ( id_ibmxl ); name = \"xlf90\" case ( id_cray ); name = \"crayftn\" case ( id_lahey ); name = \"lfc\" case ( id_lfortran ); name = \"lFortran\" case default ; name = \"invalid/unknown\" end select end function compiler_name","tags":"","loc":"proc/compiler_name.html"},{"title":"debug_archiver – Fortran-lang/fpm","text":"public pure function debug_archiver(self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string Contents Source Code debug_archiver Source Code pure function debug_archiver ( self ) result ( repr ) !> Instance of the archiver object type ( archiver_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'ar=\"' // self % ar // '\"' end function debug_archiver","tags":"","loc":"proc/debug_archiver.html"},{"title":"debug_compiler – Fortran-lang/fpm","text":"public pure function debug_compiler(self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string Contents Source Code debug_compiler Source Code pure function debug_compiler ( self ) result ( repr ) !> Instance of the compiler object type ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'fc=\"' // self % fc // '\", cc=\"' // self % cc // '\"' end function debug_compiler","tags":"","loc":"proc/debug_compiler.html"},{"title":"enumerate_libraries – Fortran-lang/fpm","text":"public function enumerate_libraries(self, prefix, libs) result(r) Enumerate libraries, based on compiler and platform Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: prefix type( string_t ), intent(in) :: libs (:) Return Value character(len=:), allocatable Contents Source Code enumerate_libraries Source Code function enumerate_libraries ( self , prefix , libs ) result ( r ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: prefix type ( string_t ), intent ( in ) :: libs (:) character ( len = :), allocatable :: r if ( self % id == id_intel_classic_windows . or . & self % id == id_intel_llvm_windows ) then r = prefix // \" \" // string_cat ( libs , \".lib \" ) // \".lib\" else r = prefix // \" -l\" // string_cat ( libs , \" -l\" ) end if end function enumerate_libraries","tags":"","loc":"proc/enumerate_libraries.html"},{"title":"get_compiler_id – Fortran-lang/fpm","text":"public function get_compiler_id(compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) Contents Variables command full_command full_command_parts io output stat Source Code get_compiler_id Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: command character(len=:), public, allocatable :: full_command character(len=:), public, allocatable :: full_command_parts (:) integer, public :: io character(len=:), public, allocatable :: output integer, public :: stat Source Code function get_compiler_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id character ( len = :), allocatable :: full_command , full_command_parts (:), command , output integer :: stat , io ! Check whether we are dealing with an MPI compiler wrapper first if ( check_compiler ( compiler , \"mpifort\" ) & & . or . check_compiler ( compiler , \"mpif90\" ) & & . or . check_compiler ( compiler , \"mpif77\" )) then output = get_temp_filename () call run ( compiler // \" -show > \" // output // \" 2>&1\" , & & echo = . false ., exitstat = stat ) if ( stat == 0 ) then open ( file = output , newunit = io , iostat = stat ) if ( stat == 0 ) call getline ( io , full_command , stat ) close ( io , iostat = stat ) ! If we get a command from the wrapper, we will try to identify it call split ( full_command , full_command_parts , delimiters = ' ' ) if ( size ( full_command_parts ) > 0 ) then command = trim ( full_command_parts ( 1 )) endif if ( allocated ( command )) then id = get_id ( command ) if ( id /= id_unknown ) return end if end if end if id = get_id ( compiler ) end function get_compiler_id","tags":"","loc":"proc/get_compiler_id.html"},{"title":"get_default_flags – Fortran-lang/fpm","text":"public function get_default_flags(self, release) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self logical, intent(in) :: release Return Value character(len=:), allocatable Contents Source Code get_default_flags Source Code function get_default_flags ( self , release ) result ( flags ) class ( compiler_t ), intent ( in ) :: self logical , intent ( in ) :: release character ( len = :), allocatable :: flags if ( release ) then call get_release_compile_flags ( self % id , flags ) else call get_debug_compile_flags ( self % id , flags ) end if end function get_default_flags","tags":"","loc":"proc/get_default_flags.html"},{"title":"get_feature_flag – Fortran-lang/fpm","text":"public function get_feature_flag(self, feature) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: feature Return Value character(len=:), allocatable Contents Source Code get_feature_flag Source Code function get_feature_flag ( self , feature ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: feature character ( len = :), allocatable :: flags flags = \"\" select case ( feature ) case ( \"no-implicit-typing\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_typing case ( id_nag ) flags = flag_nag_no_implicit_typing case ( id_cray ) flags = flag_cray_no_implicit_typing end select case ( \"implicit-typing\" ) select case ( self % id ) case ( id_cray ) flags = flag_cray_implicit_typing case ( id_lfortran ) flags = flag_lfortran_implicit_typing end select case ( \"no-implicit-external\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_external end select case ( \"implicit-external\" ) select case ( self % id ) case ( id_lfortran ) flags = flag_lfortran_implicit_external end select case ( \"free-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_free_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_free_form case ( id_nag ) flags = flag_nag_free_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_free_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_free_form_win case ( id_cray ) flags = flag_cray_free_form end select case ( \"fixed-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_fixed_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_fixed_form case ( id_nag ) flags = flag_nag_fixed_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_fixed_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_fixed_form_win case ( id_cray ) flags = flag_cray_fixed_form case ( id_lfortran ) flags = flag_lfortran_fixed_form end select case ( \"default-form\" ) continue case default error stop \"Unknown feature '\" // feature // \"'\" end select end function get_feature_flag","tags":"","loc":"proc/get_feature_flag.html"},{"title":"get_id – Fortran-lang/fpm","text":"public function get_id(compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) Contents Source Code get_id Source Code function get_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id if ( check_compiler ( compiler , \"gfortran\" )) then id = id_gcc return end if if ( check_compiler ( compiler , \"f95\" )) then id = id_f95 return end if if ( check_compiler ( compiler , \"caf\" )) then id = id_caf return end if if ( check_compiler ( compiler , \"ifort\" )) then select case ( get_os_type ()) case default id = id_intel_classic_nix case ( OS_MACOS ) id = id_intel_classic_mac case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_classic_windows end select return end if if ( check_compiler ( compiler , \"ifx\" )) then select case ( get_os_type ()) case default id = id_intel_llvm_nix case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_llvm_windows end select return end if if ( check_compiler ( compiler , \"nvfortran\" )) then id = id_nvhpc return end if if ( check_compiler ( compiler , \"pgfortran\" ) & & . or . check_compiler ( compiler , \"pgf90\" ) & & . or . check_compiler ( compiler , \"pgf95\" )) then id = id_pgi return end if if ( check_compiler ( compiler , \"nagfor\" )) then id = id_nag return end if if ( check_compiler ( compiler , \"flang-new\" )) then id = id_flang_new return end if if ( check_compiler ( compiler , \"f18\" )) then id = id_f18 return end if if ( check_compiler ( compiler , \"flang\" )) then id = id_flang return end if if ( check_compiler ( compiler , \"xlf90\" )) then id = id_ibmxl return end if if ( check_compiler ( compiler , \"crayftn\" )) then id = id_cray return end if if ( check_compiler ( compiler , \"lfc\" )) then id = id_lahey return end if if ( check_compiler ( compiler , \"lfortran\" )) then id = id_lfortran return end if id = id_unknown end function get_id","tags":"","loc":"proc/get_id.html"},{"title":"get_include_flag – Fortran-lang/fpm","text":"public function get_include_flag(self, path) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code get_include_flag Source Code function get_include_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-I \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_nvhpc , id_pgi , & & id_flang , id_flang_new , id_f18 , & & id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix , id_lahey , id_nag , id_ibmxl , & & id_lfortran ) flags = \"-I \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/I\" // path end select end function get_include_flag","tags":"","loc":"proc/get_include_flag.html"},{"title":"get_macros – Fortran-lang/fpm","text":"public function get_macros(id, macros_list, version) result(macros) This function will parse and read the macros list and\nreturn them as defined flags.\nSet macro defintion symbol on the basis of compiler used\nCheck if macros are not allocated.\nSplit the macro name and value. Check if the value of macro starts with ‘{’ character. Check if the value of macro ends with ‘}’ character. Check if the string contains “version” as substring. These conditions are placed in order to ensure proper spacing between the macros. Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id type( string_t ), intent(in), allocatable :: macros_list (:) character(len=:), intent(in), allocatable :: version Return Value character(len=:), allocatable Contents Variables i macro_definition_symbol valued_macros Source Code get_macros Variables Type Visibility Attributes Name Initial integer, public :: i character(len=:), public, allocatable :: macro_definition_symbol character(len=:), public, allocatable :: valued_macros (:) Source Code function get_macros ( id , macros_list , version ) result ( macros ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( in ) :: version type ( string_t ), allocatable , intent ( in ) :: macros_list (:) character ( len = :), allocatable :: macros character ( len = :), allocatable :: macro_definition_symbol character (:), allocatable :: valued_macros (:) integer :: i if (. not . allocated ( macros_list )) then macros = \"\" return end if !> Set macro defintion symbol on the basis of compiler used select case ( id ) case default macro_definition_symbol = \" -D\" case ( id_intel_classic_windows , id_intel_llvm_windows ) macro_definition_symbol = \" /D\" end select !> Check if macros are not allocated. if (. not . allocated ( macros )) then macros = \"\" end if do i = 1 , size ( macros_list ) !> Split the macro name and value. call split ( macros_list ( i )% s , valued_macros , delimiters = \"=\" ) if ( size ( valued_macros ) > 1 ) then !> Check if the value of macro starts with '{' character. if ( str_begins_with_str ( trim ( valued_macros ( size ( valued_macros ))), \"{\" )) then !> Check if the value of macro ends with '}' character. if ( str_ends_with ( trim ( valued_macros ( size ( valued_macros ))), \"}\" )) then !> Check if the string contains \"version\" as substring. if ( index ( valued_macros ( size ( valued_macros )), \"version\" ) /= 0 ) then !> These conditions are placed in order to ensure proper spacing between the macros. macros = macros // macro_definition_symbol // trim ( valued_macros ( 1 )) // '=' // version cycle end if end if end if end if macros = macros // macro_definition_symbol // macros_list ( i )% s end do end function get_macros","tags":"","loc":"proc/get_macros.html"},{"title":"get_module_flag – Fortran-lang/fpm","text":"public function get_module_flag(self, path) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code get_module_flag Source Code function get_module_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-module \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_lfortran ) flags = \"-J \" // path case ( id_nvhpc , id_pgi , id_flang ) flags = \"-module \" // path case ( id_flang_new , id_f18 ) flags = \"-module-dir \" // path case ( id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix ) flags = \"-module \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/module:\" // path case ( id_lahey ) flags = \"-M \" // path case ( id_nag ) flags = \"-mdir \" // path case ( id_ibmxl ) flags = \"-qmoddir \" // path end select end function get_module_flag","tags":"","loc":"proc/get_module_flag.html"},{"title":"is_gnu – Fortran-lang/fpm","text":"public pure function is_gnu(self) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Contents Source Code is_gnu Source Code pure logical function is_gnu ( self ) class ( compiler_t ), intent ( in ) :: self is_gnu = any ( self % id == [ id_f95 , id_gcc , id_caf ]) end function is_gnu","tags":"","loc":"proc/is_gnu.html"},{"title":"is_intel – Fortran-lang/fpm","text":"public pure function is_intel(self) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Contents Source Code is_intel Source Code pure logical function is_intel ( self ) class ( compiler_t ), intent ( in ) :: self is_intel = any ( self % id == [ id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows , & id_intel_llvm_nix , id_intel_llvm_windows , id_intel_llvm_unknown ]) end function is_intel","tags":"","loc":"proc/is_intel.html"},{"title":"is_unknown – Fortran-lang/fpm","text":"public pure function is_unknown(self) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Contents Source Code is_unknown Source Code pure function is_unknown ( self ) class ( compiler_t ), intent ( in ) :: self logical :: is_unknown is_unknown = self % id == id_unknown end function is_unknown","tags":"","loc":"proc/is_unknown.html"},{"title":"compile_c – Fortran-lang/fpm","text":"public subroutine compile_c(self, input, output, args, log_file, stat) Compile a C object Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Source Code compile_c Source Code subroutine compile_c ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % cc // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_c","tags":"","loc":"proc/compile_c.html"},{"title":"compile_cpp – Fortran-lang/fpm","text":"public subroutine compile_cpp(self, input, output, args, log_file, stat) Compile a CPP object Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Source Code compile_cpp Source Code subroutine compile_cpp ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % cxx // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_cpp","tags":"","loc":"proc/compile_cpp.html"},{"title":"compile_fortran – Fortran-lang/fpm","text":"public subroutine compile_fortran(self, input, output, args, log_file, stat) Compile a Fortran object Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Source Code compile_fortran Source Code subroutine compile_fortran ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % fc // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_fortran","tags":"","loc":"proc/compile_fortran.html"},{"title":"get_debug_compile_flags – Fortran-lang/fpm","text":"public subroutine get_debug_compile_flags(id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags Contents Source Code get_debug_compile_flags Source Code subroutine get_debug_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace case ( id_gcc ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & ' -Wno-maybe-uninitialized -Wno-uninitialized' // & flag_gnu_backtrace case ( id_nvhpc ) flags = & flag_pgi_warn // & flag_pgi_backslash // & flag_pgi_check // & flag_pgi_traceback case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_classic_mac ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_classic_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win // & flag_intel_backtrace_win case ( id_intel_llvm_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_llvm_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_nag ) flags = & flag_nag_debug // & flag_nag_check // & flag_nag_backtrace // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = \"\" end select end subroutine get_debug_compile_flags","tags":"","loc":"proc/get_debug_compile_flags.html"},{"title":"get_default_c_compiler – Fortran-lang/fpm","text":"public subroutine get_default_c_compiler(f_compiler, c_compiler) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: c_compiler Contents Variables id Source Code get_default_c_compiler Variables Type Visibility Attributes Name Initial integer(kind=compiler_enum), public :: id Source Code subroutine get_default_c_compiler ( f_compiler , c_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: c_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) c_compiler = 'icc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) c_compiler = 'icx' case ( id_flang , id_flang_new , id_f18 ) c_compiler = 'clang' case ( id_ibmxl ) c_compiler = 'xlc' case ( id_lfortran ) c_compiler = 'cc' case ( id_gcc ) c_compiler = 'gcc' case default ! Fall-back to using Fortran compiler c_compiler = f_compiler end select end subroutine get_default_c_compiler","tags":"","loc":"proc/get_default_c_compiler.html"},{"title":"get_default_cxx_compiler – Fortran-lang/fpm","text":"public subroutine get_default_cxx_compiler(f_compiler, cxx_compiler) Get C++ Compiler. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: cxx_compiler Contents Variables id Source Code get_default_cxx_compiler Variables Type Visibility Attributes Name Initial integer(kind=compiler_enum), public :: id Source Code subroutine get_default_cxx_compiler ( f_compiler , cxx_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: cxx_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) cxx_compiler = 'icpc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) cxx_compiler = 'icpx' case ( id_flang , id_flang_new , id_f18 ) cxx_compiler = 'clang++' case ( id_ibmxl ) cxx_compiler = 'xlc++' case ( id_lfortran ) cxx_compiler = 'cc' case ( id_gcc ) cxx_compiler = 'g++' case default ! Fall-back to using Fortran compiler cxx_compiler = f_compiler end select end subroutine get_default_cxx_compiler","tags":"","loc":"proc/get_default_cxx_compiler.html"},{"title":"get_main_flags – Fortran-lang/fpm","text":"public subroutine get_main_flags(self, language, flags) Get special flags for the main linker Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: language character(len=:), intent(out), allocatable :: flags Contents Source Code get_main_flags Source Code subroutine get_main_flags ( self , language , flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: language character ( len = :), allocatable , intent ( out ) :: flags flags = \"\" select case ( language ) case ( \"fortran\" ) flags = \"\" case ( \"c\" ) ! If the main program is on a C/C++ source, the Intel Fortran compiler requires option ! -nofor-main to avoid \"duplicate main\" errors. ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case ( \"c++\" , \"cpp\" , \"cxx\" ) select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case default error stop \"Unknown language '\" // language // '\", try \"fortran\", \"c\", \"c++\"' end select end subroutine get_main_flags","tags":"","loc":"proc/get_main_flags.html"},{"title":"get_release_compile_flags – Fortran-lang/fpm","text":"public subroutine get_release_compile_flags(id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags Contents Source Code get_release_compile_flags Source Code subroutine get_release_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_gcc ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_nvhpc ) flags = & flag_pgi_backslash case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_classic_mac ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_classic_windows ) flags = & & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_intel_llvm_nix ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_llvm_windows ) flags = & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_nag ) flags = & flag_nag_opt // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = & flag_lfortran_opt end select end subroutine get_release_compile_flags","tags":"","loc":"proc/get_release_compile_flags.html"},{"title":"link – Fortran-lang/fpm","text":"public subroutine link(self, output, args, log_file, stat) Link an executable Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Source Code link Source Code subroutine link ( self , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % fc // \" \" // args // \" -o \" // output , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine link","tags":"","loc":"proc/link.html"},{"title":"make_archive – Fortran-lang/fpm","text":"public subroutine make_archive(self, output, args, log_file, stat) Create an archive Todo For Windows OS, use the local delete_file_win32 in stead of delete_file .\nThis may be related to a bug in Mingw64-openmp and is expected to be resolved in the future,\nsee issue #707, #708 and #808. Type Bound archiver_t Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: self Instance of the archiver object character(len=*), intent(in) :: output Name of the archive to generate type( string_t ), intent(in) :: args (:) Object files to include into the archive character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag Contents Subroutines delete_file_win32 Source Code make_archive Subroutines subroutine delete_file_win32(file) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file Source Code subroutine make_archive ( self , output , args , log_file , stat ) !> Instance of the archiver object class ( archiver_t ), intent ( in ) :: self !> Name of the archive to generate character ( len =* ), intent ( in ) :: output !> Object files to include into the archive type ( string_t ), intent ( in ) :: args (:) !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat if ( self % use_response_file ) then call write_response_file ( output // \".resp\" , args ) call run ( self % ar // output // \" @\" // output // \".resp\" , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) call delete_file_win32 ( output // \".resp\" ) else call run ( self % ar // output // \" \" // string_cat ( args , \" \" ), & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end if contains subroutine delete_file_win32 ( file ) character ( len =* ), intent ( in ) :: file logical :: exist integer :: unit , iostat inquire ( file = file , exist = exist ) if ( exist ) then open ( file = file , newunit = unit ) close ( unit , status = 'delete' , iostat = iostat ) end if end subroutine delete_file_win32 end subroutine make_archive","tags":"","loc":"proc/make_archive.html"},{"title":"new_archiver – Fortran-lang/fpm","text":"public subroutine new_archiver(self, ar, echo, verbose) Create new archiver instance Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(out) :: self New instance of the archiver character(len=*), intent(in) :: ar User provided archiver command logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output Contents Variables arflags estat libflags os_type Source Code new_archiver Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: arflags = \" -rs \" integer, public :: estat character(len=*), public, parameter :: libflags = \" /OUT:\" integer, public :: os_type Source Code subroutine new_archiver ( self , ar , echo , verbose ) !> New instance of the archiver type ( archiver_t ), intent ( out ) :: self !> User provided archiver command character ( len =* ), intent ( in ) :: ar !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose integer :: estat , os_type character ( len =* ), parameter :: arflags = \" -rs \" , libflags = \" /OUT:\" if ( len_trim ( ar ) > 0 ) then ! Check first for ar-like commands if ( check_compiler ( ar , \"ar\" )) then self % ar = ar // arflags end if ! Check for lib-like commands if ( check_compiler ( ar , \"lib\" )) then self % ar = ar // libflags end if ! Fallback and assume ar-like behaviour self % ar = ar // arflags else os_type = get_os_type () if ( os_type /= OS_WINDOWS . and . os_type /= OS_UNKNOWN ) then self % ar = \"ar\" // arflags else call execute_command_line ( \"ar --version > \" // get_temp_filename () // \" 2>&1\" , & & exitstat = estat ) if ( estat /= 0 ) then self % ar = \"lib\" // libflags else self % ar = \"ar\" // arflags end if end if end if self % use_response_file = os_type == OS_WINDOWS self % echo = echo self % verbose = verbose end subroutine new_archiver","tags":"","loc":"proc/new_archiver.html"},{"title":"new_compiler – Fortran-lang/fpm","text":"public subroutine new_compiler(self, fc, cc, cxx, echo, verbose) Create new compiler instance Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(out) :: self New instance of the compiler character(len=*), intent(in) :: fc Fortran compiler name or path character(len=*), intent(in) :: cc C compiler name or path character(len=*), intent(in) :: cxx C++ Compiler name or path logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output Contents Source Code new_compiler Source Code subroutine new_compiler ( self , fc , cc , cxx , echo , verbose ) !> New instance of the compiler type ( compiler_t ), intent ( out ) :: self !> Fortran compiler name or path character ( len =* ), intent ( in ) :: fc !> C compiler name or path character ( len =* ), intent ( in ) :: cc !> C++ Compiler name or path character ( len =* ), intent ( in ) :: cxx !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose self % id = get_compiler_id ( fc ) self % echo = echo self % verbose = verbose self % fc = fc if ( len_trim ( cc ) > 0 ) then self % cc = cc else call get_default_c_compiler ( self % fc , self % cc ) end if if ( len_trim ( cxx ) > 0 ) then self % cxx = cxx else call get_default_cxx_compiler ( self % fc , self % cxx ) end if end subroutine new_compiler","tags":"","loc":"proc/new_compiler.html"},{"title":"set_cpp_preprocessor_flags – Fortran-lang/fpm","text":"public pure subroutine set_cpp_preprocessor_flags(id, flags) Modify the flag_cpp_preprocessor on the basis of the compiler. Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(inout), allocatable :: flags Contents Variables flag_cpp_preprocessor Source Code set_cpp_preprocessor_flags Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: flag_cpp_preprocessor Source Code pure subroutine set_cpp_preprocessor_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( inout ) :: flags character ( len = :), allocatable :: flag_cpp_preprocessor !> Modify the flag_cpp_preprocessor on the basis of the compiler. select case ( id ) case default flag_cpp_preprocessor = \"\" case ( id_caf , id_gcc , id_f95 , id_nvhpc ) flag_cpp_preprocessor = \"-cpp\" case ( id_intel_classic_windows , id_intel_llvm_windows ) flag_cpp_preprocessor = \"/fpp\" case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , id_nag ) flag_cpp_preprocessor = \"-fpp\" case ( id_lfortran ) flag_cpp_preprocessor = \"--cpp\" end select flags = flag_cpp_preprocessor // flags end subroutine set_cpp_preprocessor_flags","tags":"","loc":"proc/set_cpp_preprocessor_flags.html"},{"title":"write_response_file – Fortran-lang/fpm","text":"public subroutine write_response_file(name, argv) Response files allow to read command line options from files.\nWhitespace is used to separate the arguments, we will use newlines\nas separator to create readable response files which can be inspected\nin case of errors. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name type( string_t ), intent(in) :: argv (:) Contents Variables iarg io Source Code write_response_file Variables Type Visibility Attributes Name Initial integer, public :: iarg integer, public :: io Source Code subroutine write_response_file ( name , argv ) character ( len =* ), intent ( in ) :: name type ( string_t ), intent ( in ) :: argv (:) integer :: iarg , io open ( file = name , newunit = io , status = 'replace' ) do iarg = 1 , size ( argv ) write ( io , '(a)' ) unix_path ( argv ( iarg )% s ) end do close ( io ) end subroutine write_response_file","tags":"","loc":"proc/write_response_file.html"},{"title":"debug – Fortran-lang/fpm","text":"public interface debug Create debug printout Contents Module Procedures debug_compiler debug_archiver Module Procedures public pure function debug_compiler (self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public pure function debug_archiver (self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string","tags":"","loc":"interface/debug.html"},{"title":"get_global_settings – Fortran-lang/fpm","text":"public subroutine get_global_settings(global_settings, error) Obtain global settings from the global config file. Arguments Type Intent Optional Attributes Name type( fpm_global_settings ), intent(inout) :: global_settings Global settings to be obtained. type( error_t ), intent(out), allocatable :: error Error reading config file. Contents","tags":"","loc":"proc/get_global_settings.html"},{"title":"get_registry_settings – Fortran-lang/fpm","text":"public subroutine get_registry_settings(table, global_settings, error) Read registry settings from the global config file. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout), target :: table The [registry] subtable from the global config file. type( fpm_global_settings ), intent(inout) :: global_settings The global settings which can be filled with the registry settings. type( error_t ), intent(out), allocatable :: error Error handling. Contents","tags":"","loc":"proc/get_registry_settings.html"},{"title":"get_command_line_settings – Fortran-lang/fpm","text":"public subroutine get_command_line_settings(cmd_settings) ! canon_path is not converting “.”, etc.\n& ‘ unknown help topic “’//trim(unnamed(i)).’not found in:’,manual] Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(out), allocatable :: cmd_settings Contents Source Code get_command_line_settings Source Code subroutine get_command_line_settings ( cmd_settings ) class ( fpm_cmd_settings ), allocatable , intent ( out ) :: cmd_settings integer , parameter :: widest = 256 character ( len = 4096 ) :: cmdarg integer :: i integer :: os type ( fpm_install_settings ), allocatable :: install_settings type ( version_t ) :: version character ( len = :), allocatable :: common_args , compiler_args , run_args , working_dir , & & c_compiler , cxx_compiler , archiver , version_s , token_s character ( len =* ), parameter :: fc_env = \"FC\" , cc_env = \"CC\" , ar_env = \"AR\" , & & fflags_env = \"FFLAGS\" , cflags_env = \"CFLAGS\" , cxxflags_env = \"CXXFLAGS\" , ldflags_env = \"LDFLAGS\" , & & fc_default = \"gfortran\" , cc_default = \" \" , ar_default = \" \" , flags_default = \" \" , & & cxx_env = \"CXX\" , cxx_default = \" \" type ( error_t ), allocatable :: error call set_help () os = get_os_type () ! text for --version switch, select case ( os ) 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_OPENBSD ); os_type = \"OS Type: OpenBSD\" case ( OS_UNKNOWN ); os_type = \"OS Type: Unknown\" case default ; os_type = \"OS Type: UNKNOWN\" end select ! Get current release version version = fpm_version () version_s = version % s () version_text = [ character ( len = 80 ) :: & & 'Version: ' // trim ( version_s ) // ', 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 CLI_RESPONSE_FILE = . true . cmdarg = get_subcommand () common_args = & ' --directory:C \" \"' // & ' --verbose F' run_args = & ' --target \" \"' // & ' --list F' // & ' --runner \" \"' // & ' --runner-args \" \"' compiler_args = & ' --profile \" \"' // & ' --no-prune F' // & ' --compiler \"' // get_fpm_env ( fc_env , fc_default ) // '\"' // & ' --c-compiler \"' // get_fpm_env ( cc_env , cc_default ) // '\"' // & ' --cxx-compiler \"' // get_fpm_env ( cxx_env , cxx_default ) // '\"' // & ' --archiver \"' // get_fpm_env ( ar_env , ar_default ) // '\"' // & ' --flag:: \"' // get_fpm_env ( fflags_env , flags_default ) // '\"' // & ' --c-flag:: \"' // get_fpm_env ( cflags_env , flags_default ) // '\"' // & ' --cxx-flag:: \"' // get_fpm_env ( cxxflags_env , flags_default ) // '\"' // & ' --link-flag:: \"' // get_fpm_env ( ldflags_env , flags_default ) // '\"' ! now set subcommand-specific help text and process commandline ! arguments. Then call subcommand routine select case ( trim ( cmdarg )) case ( 'run' ) call set_args ( common_args // compiler_args // run_args // '& & --all F & & --example F& & --' , help_run , version_text ) call check_build_vals () if ( size ( unnamed ) > 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 ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_run_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_run_settings (& & args = remaining ,& & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = lget ( 'example' ), & & list = lget ( 'list' ),& & build_tests = . false .,& & name = names ,& & runner = val_runner ,& & runner_args = val_runner_args , & & verbose = lget ( 'verbose' ) ) case ( 'build' ) call set_args ( common_args // compiler_args // '& & --list F & & --show-model F & & --tests F & & --' , help_build , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_build_settings :: cmd_settings ) cmd_settings = fpm_build_settings ( & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ) ) case ( 'new' ) call set_args ( common_args // '& & --src F & & --lib F & & --app F & & --test F & & --example F & & --backfill F & & --full F & & --bare F' , & & help_new , version_text ) select case ( size ( unnamed )) case ( 1 ) if ( lget ( 'backfill' )) then name = '.' else write ( stderr , '(*(7x,g0,/))' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|[--full|--bare] [--backfill]' call fpm_stop ( 1 , 'directory name required' ) endif case ( 2 ) name = trim ( unnamed ( 2 )) case default write ( stderr , '(7x,g0)' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| [--full|--bare] [--backfill]' call fpm_stop ( 2 , 'only one directory name allowed' ) end select !*! canon_path is not converting \".\", etc. if ( name == '.' ) then call get_current_directory ( name , error ) if ( allocated ( error )) then write ( stderr , '(\"[Error]\", 1x, a)' ) error % message stop 1 endif endif name = canon_path ( name ) if ( . not . is_fortran_name ( to_fortran_name ( basename ( name ))) ) then write ( stderr , '(g0)' ) [ character ( len = 72 ) :: & & ' the fpm project name must be made of up to 63 ASCII letters,' , & & ' numbers, underscores, or hyphens, and start with a letter.' ] call fpm_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))' )& & ' --full and any of [--src|--lib,--app,--test,--example,--bare]' , & & ' are mutually exclusive.' call fpm_stop ( 5 , ' ' ) elseif ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' , 'full' ])) & & . and . lget ( 'bare' ) ) then write ( stderr , '(*(a))' )& & ' --bare and any of [--src|--lib,--app,--test,--example,--full]' , & & ' are mutually exclusive.' call fpm_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 ( common_args , help_help , version_text ) if ( size ( unnamed ) < 2 ) then if ( unnamed ( 1 ) == 'help' ) then unnamed = [ ' ' , 'fpm' ] else unnamed = manual endif elseif ( unnamed ( 2 ) == 'manual' ) then unnamed = manual endif 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 ( 'clean' ) help_text = [ character ( len = widest ) :: help_text , help_clean ] case ( 'publish' ) help_text = [ character ( len = widest ) :: help_text , help_publish ] case default help_text = [ character ( len = widest ) :: help_text , & & ' unknown help topic \"' // trim ( unnamed ( i )) // '\"' ] !!& ' unknown help topic \"'//trim(unnamed(i)).'not found in:',manual] end select enddo call printhelp ( help_text ) case ( 'install' ) call set_args ( common_args // compiler_args // '& & --no-rebuild F --prefix \" \" & & --list F & & --libdir \"lib\" --bindir \"bin\" --includedir \"include\"' , & help_install , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( install_settings , source = fpm_install_settings (& list = lget ( 'list' ), & profile = val_profile ,& prune = . not . lget ( 'no-prune' ), & compiler = val_compiler , & c_compiler = c_compiler , & cxx_compiler = cxx_compiler , & archiver = archiver , & flag = val_flag , & cflag = val_cflag , & cxxflag = val_cxxflag , & ldflag = val_ldflag , & 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 ( common_args // '& & --list F& &' , help_list , version_text ) if ( lget ( 'list' )) then help_text = [ character ( widest ) :: help_list_nodash , help_list_dash ] else help_text = help_list_nodash endif call printhelp ( help_text ) case ( 'test' ) call set_args ( common_args // compiler_args // run_args // ' --' , & help_test , version_text ) call check_build_vals () if ( size ( unnamed ) > 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 ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_test_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_test_settings (& & args = remaining , & & profile = val_profile , & & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = . false ., & & list = lget ( 'list' ), & & build_tests = . true ., & & name = names , & & runner = val_runner , & & runner_args = val_runner_args , & & verbose = lget ( 'verbose' )) case ( 'update' ) call set_args ( common_args // ' --fetch-only F --clean F' , & help_update , version_text ) if ( size ( unnamed ) > 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 ( 'clean' ) call set_args ( common_args // & & ' --skip' // & & ' --all' , & help_clean , version_text ) allocate ( fpm_clean_settings :: cmd_settings ) call get_current_directory ( working_dir , error ) cmd_settings = fpm_clean_settings ( & & clean_skip = lget ( 'skip' ), & & clean_call = lget ( 'all' )) case ( 'publish' ) call set_args ( common_args // compiler_args // '& & --show-package-version F & & --show-upload-data F & & --dry-run F & & --token \" \" & & --list F & & --show-model F & & --tests F & & --' , help_publish , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) token_s = sget ( 'token' ) allocate ( fpm_publish_settings :: cmd_settings ) cmd_settings = fpm_publish_settings ( & & show_package_version = lget ( 'show-package-version' ), & & show_upload_data = lget ( 'show-upload-data' ), & & is_dry_run = lget ( 'dry-run' ), & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ),& & token = token_s ) case default if ( cmdarg . ne . '' . and . which ( 'fpm-' // cmdarg ). ne . '' ) then call run ( 'fpm-' // trim ( cmdarg ) // ' ' // get_command_arguments_quoted (),. false .) stop else call set_args ( '& & --list F& &' , help_fpm , version_text ) ! Note: will not get here if --version or --usage or --help ! is present on commandline if ( lget ( 'list' )) then help_text = help_list_dash elseif ( len_trim ( cmdarg ) == 0 ) then write ( stdout , '(*(a))' ) 'Fortran Package Manager:' write ( stdout , '(*(a))' ) ' ' help_text = [ character ( widest ) :: help_list_nodash , help_usage ] else write ( stderr , '(*(a))' ) ' unknown subcommand [' , & & trim ( cmdarg ), ']' help_text = [ character ( widest ) :: help_list_dash , help_usage ] endif call printhelp ( help_text ) endif end select if ( allocated ( cmd_settings )) then working_dir = sget ( \"directory\" ) call move_alloc ( working_dir , cmd_settings % working_dir ) end if contains subroutine check_build_vals () val_compiler = sget ( 'compiler' ) if ( val_compiler == '' ) val_compiler = 'gfortran' val_flag = \" \" // sget ( 'flag' ) val_cflag = \" \" // sget ( 'c-flag' ) val_cxxflag = \" \" // sget ( 'cxx-flag' ) val_ldflag = \" \" // sget ( 'link-flag' ) val_profile = sget ( 'profile' ) end subroutine check_build_vals !> Print help text and stop subroutine printhelp ( lines ) character ( len = :), intent ( in ), allocatable :: lines (:) integer :: iii , ii if ( allocated ( lines )) then ii = size ( lines ) if ( ii > 0 . and . len ( lines ) > 0 ) then write ( stdout , '(g0)' )( trim ( lines ( iii )), iii = 1 , ii ) else write ( stdout , '(a)' ) ' *printhelp* output requested is empty' endif endif stop end subroutine printhelp end subroutine get_command_line_settings","tags":"","loc":"proc/get_command_line_settings.html"},{"title":"change_directory – Fortran-lang/fpm","text":"public subroutine change_directory(path, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error Contents Source Code change_directory Source Code subroutine change_directory ( path , error ) character ( len =* ), intent ( in ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) integer :: stat allocate ( cpath ( len ( path ) + 1 )) call f_c_character ( path , cpath , len ( path ) + 1 ) stat = chdir_ ( cpath ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to change directory to '\" // path // \"'\" ) end if end subroutine change_directory","tags":"","loc":"proc/change_directory.html"},{"title":"convert_to_absolute_path – Fortran-lang/fpm","text":"public subroutine convert_to_absolute_path(path, error) Converts a path to an absolute, canonical path. Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: path type( error_t ), intent(out), allocatable :: error Contents","tags":"","loc":"proc/convert_to_absolute_path.html"},{"title":"get_absolute_path – Fortran-lang/fpm","text":"public subroutine get_absolute_path(path, absolute_path, error) Determine the canonical, absolute path for the given path.\nExpands home folder (~) on both Unix and Windows. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error Contents","tags":"","loc":"proc/get_absolute_path.html"},{"title":"get_absolute_path_by_cd – Fortran-lang/fpm","text":"public subroutine get_absolute_path_by_cd(path, absolute_path, error) Alternative to get_absolute_path that uses chdir / _chdir to determine the absolute path. get_absolute_path is preferred but get_absolute_path_by_cd can be used in bootstrap mode. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error Contents","tags":"","loc":"proc/get_absolute_path_by_cd.html"},{"title":"get_current_directory – Fortran-lang/fpm","text":"public subroutine get_current_directory(path, error) Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: path type( error_t ), intent(out), allocatable :: error Contents Source Code get_current_directory Source Code subroutine get_current_directory ( path , error ) character ( len = :), allocatable , intent ( out ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) type ( c_ptr ) :: tmp allocate ( cpath ( buffersize )) tmp = getcwd_ ( cpath , buffersize ) if ( c_associated ( tmp )) then call c_f_character ( cpath , path ) else call fatal_error ( error , \"Failed to retrieve current directory\" ) end if end subroutine get_current_directory","tags":"","loc":"proc/get_current_directory.html"},{"title":"get_exe_name_with_suffix – Fortran-lang/fpm","text":"public function get_exe_name_with_suffix(source) result(suffixed) Build an executable name with suffix. Safe routine that always returns an allocated string Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(in) :: source Return Value character(len=:), allocatable Contents Source Code get_exe_name_with_suffix Source Code function get_exe_name_with_suffix ( source ) result ( suffixed ) type ( srcfile_t ), intent ( in ) :: source character ( len = :), allocatable :: suffixed if ( allocated ( source % exe_name )) then if ( get_os_type () == OS_WINDOWS ) then suffixed = source % exe_name // '.exe' else suffixed = source % exe_name end if else suffixed = \"\" endif end function get_exe_name_with_suffix","tags":"","loc":"proc/get_exe_name_with_suffix.html"},{"title":"add_executable_sources – Fortran-lang/fpm","text":"public subroutine add_executable_sources(sources, executables, scope, auto_discover, error) Add to sources using the executable and test entries in the manifest and\napplies any executable-specific overrides such as executable%name .\nAdds all sources (including modules) from each executable%source_dir Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of srcfile_t objects to append to. Allocated if not allocated class( executable_config_t ), intent(in) :: executables (:) List of executable_config_t entries from manifest integer, intent(in) :: scope Scope to apply to the discovered sources: either FPM_SCOPE_APP or FPM_SCOPE_TEST , see fpm_model logical, intent(in) :: auto_discover If .false. only executables and tests specified in the manifest are added to sources type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code add_executable_sources Source Code subroutine add_executable_sources ( sources , executables , scope , auto_discover , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> List of `[[executable_config_t]]` entries from manifest class ( executable_config_t ), intent ( in ) :: executables (:) !> Scope to apply to the discovered sources: either `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`, see [[fpm_model]] integer , intent ( in ) :: scope !> If `.false.` only executables and tests specified in the manifest are added to `sources` logical , intent ( in ) :: auto_discover !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( string_t ), allocatable :: exe_dirs (:) type ( srcfile_t ) :: exe_source call get_executable_source_dirs ( exe_dirs , executables ) do i = 1 , size ( exe_dirs ) call add_sources_from_dir ( sources , exe_dirs ( i )% s , scope , & with_executables = auto_discover , recurse = . false ., error = error ) if ( allocated ( error )) then return end if end do exe_loop : do i = 1 , size ( executables ) ! Check if executable already discovered automatically ! and apply any overrides do j = 1 , size ( sources ) if ( basename ( sources ( j )% file_name , suffix = . true .) == executables ( i )% main . and .& canon_path ( dirname ( sources ( j )% file_name )) == & canon_path ( executables ( i )% source_dir ) ) then sources ( j )% exe_name = executables ( i )% name if ( allocated ( executables ( i )% link )) then sources ( j )% link_libraries = executables ( i )% link end if sources ( j )% unit_type = FPM_UNIT_PROGRAM cycle exe_loop end if end do ! Add if not already discovered (auto_discovery off) associate ( exe => executables ( i )) exe_source = parse_source ( join_path ( exe % source_dir , exe % main ), error ) exe_source % exe_name = exe % name if ( allocated ( exe % link )) then exe_source % link_libraries = exe % link end if exe_source % unit_type = FPM_UNIT_PROGRAM exe_source % unit_scope = scope end associate if ( allocated ( error )) return if (. not . allocated ( sources )) then sources = [ exe_source ] else sources = [ sources , exe_source ] end if end do exe_loop end subroutine add_executable_sources","tags":"","loc":"proc/add_executable_sources.html"},{"title":"add_sources_from_dir – Fortran-lang/fpm","text":"public subroutine add_sources_from_dir(sources, directory, scope, with_executables, recurse, error) Add to sources by looking for source files in directory Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of srcfile_t objects to append to. Allocated if not allocated character(len=*), intent(in) :: directory Directory in which to search for source files integer, intent(in) :: scope Scope to apply to the discovered sources, see fpm_model for enumeration logical, intent(in), optional :: with_executables Executable sources (fortran program s) are ignored unless with_executables=.true. logical, intent(in), optional :: recurse Whether to recursively search subdirectories, default is .true. type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code add_sources_from_dir Source Code subroutine add_sources_from_dir ( sources , directory , scope , with_executables , recurse , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> Directory in which to search for source files character ( * ), intent ( in ) :: directory !> Scope to apply to the discovered sources, see [[fpm_model]] for enumeration integer , intent ( in ) :: scope !> Executable sources (fortran `program`s) are ignored unless `with_executables=.true.` logical , intent ( in ), optional :: with_executables !> Whether to recursively search subdirectories, default is `.true.` logical , intent ( in ), optional :: recurse !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i logical , allocatable :: is_source (:), exclude_source (:) logical :: recurse_ type ( string_t ), allocatable :: file_names (:) type ( string_t ), allocatable :: src_file_names (:) type ( string_t ), allocatable :: existing_src_files (:) type ( srcfile_t ), allocatable :: dir_sources (:) recurse_ = . true . if ( present ( recurse )) recurse_ = recurse ! Scan directory for sources call list_files ( directory , file_names , recurse = recurse_ ) if ( allocated ( sources )) then allocate ( existing_src_files ( size ( sources ))) do i = 1 , size ( sources ) existing_src_files ( i )% s = canon_path ( sources ( i )% file_name ) end do else allocate ( existing_src_files ( 0 )) end if is_source = [(. not .( is_hidden_file ( basename ( file_names ( i )% s ))) . and . & . not .( canon_path ( file_names ( i )% s ) . in . existing_src_files ) . and . & ( str_ends_with ( lower ( file_names ( i )% s ), fortran_suffixes ) . or . & str_ends_with ( lower ( file_names ( i )% s ), c_suffixes ) ), i = 1 , size ( file_names ))] src_file_names = pack ( file_names , is_source ) allocate ( dir_sources ( size ( src_file_names ))) allocate ( exclude_source ( size ( src_file_names ))) do i = 1 , size ( src_file_names ) dir_sources ( i ) = parse_source ( src_file_names ( i )% s , error ) if ( allocated ( error )) return dir_sources ( i )% unit_scope = scope allocate ( dir_sources ( i )% link_libraries ( 0 )) ! Exclude executables unless specified otherwise exclude_source ( i ) = ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM ) if ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM . and . & & present ( with_executables )) then if ( with_executables ) then exclude_source ( i ) = . false . end if end if end do if (. not . allocated ( sources )) then sources = pack ( dir_sources ,. not . exclude_source ) else sources = [ sources , pack ( dir_sources ,. not . exclude_source )] end if end subroutine add_sources_from_dir","tags":"","loc":"proc/add_sources_from_dir.html"},{"title":"build_model – Fortran-lang/fpm","text":"public subroutine build_model(model, settings, package, error) Constructs a valid fpm model from command line settings and the toml manifest.\nAdd this dependency’s manifest macros Add this dependency’s package-level macros Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(out) :: model class( fpm_build_settings ), intent(inout) :: settings type( package_config_t ), intent(inout) :: package type( error_t ), intent(out), allocatable :: error Contents Source Code build_model Source Code subroutine build_model ( model , settings , package , error ) type ( fpm_model_t ), intent ( out ) :: model class ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ), intent ( inout ) :: package type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( package_config_t ) :: dependency character ( len = :), allocatable :: manifest , lib_dir logical :: has_cpp logical :: duplicates_found type ( string_t ) :: include_dir model % package_name = package % name allocate ( model % include_dirs ( 0 )) allocate ( model % link_libraries ( 0 )) allocate ( model % external_modules ( 0 )) call new_compiler ( model % compiler , settings % compiler , settings % c_compiler , & & settings % cxx_compiler , echo = settings % verbose , verbose = settings % verbose ) call new_archiver ( model % archiver , settings % archiver , & & echo = settings % verbose , verbose = settings % verbose ) if ( model % compiler % is_unknown ()) then write ( * , '(*(a:,1x))' ) & \"\" , \"Unknown compiler\" , model % compiler % fc , \"requested!\" , & \"Defaults for this compiler might be incorrect\" end if call new_compiler_flags ( model , settings ) model % build_prefix = join_path ( \"build\" , basename ( model % compiler % fc )) model % include_tests = settings % build_tests model % enforce_module_names = package % build % module_naming model % module_prefix = package % build % module_prefix ! Resolve meta-dependencies into the package and the model call resolve_metapackages ( model , package , settings , error ) if ( allocated ( error )) return ! Create dependencies call new_dependency_tree ( model % deps , cache = join_path ( \"build\" , \"cache.toml\" )) ! Build and resolve model dependencies call model % deps % add ( package , error ) if ( allocated ( error )) return ! Update dependencies where needed call model % deps % update ( error ) if ( allocated ( error )) return ! build/ directory should now exist if (. not . exists ( \"build/.gitignore\" )) then call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if allocate ( model % packages ( model % deps % ndep )) has_cpp = . false . do i = 1 , model % deps % ndep associate ( dep => model % deps % dep ( i )) manifest = join_path ( dep % proj_dir , \"fpm.toml\" ) call get_package_data ( dependency , manifest , error , apply_defaults = . true .) if ( allocated ( error )) exit model % packages ( i )% name = dependency % name associate ( features => model % packages ( i )% features ) features % implicit_typing = dependency % fortran % implicit_typing features % implicit_external = dependency % fortran % implicit_external features % source_form = dependency % fortran % source_form end associate model % packages ( i )% version = package % version % s () !> Add this dependency's manifest macros allocate ( model % packages ( i )% macros ( 0 )) if ( allocated ( dependency % preprocess )) then do j = 1 , size ( dependency % preprocess ) if ( dependency % preprocess ( j )% name == \"cpp\" ) then if (. not . has_cpp ) has_cpp = . true . if ( allocated ( dependency % preprocess ( j )% macros )) then model % packages ( i )% macros = [ model % packages ( i )% macros , dependency % preprocess ( j )% macros ] end if else write ( stderr , '(a)' ) 'Warning: Preprocessor ' // package % preprocess ( i )% name // & ' is not supported; will ignore it' end if end do end if !> Add this dependency's package-level macros if ( allocated ( dep % preprocess )) then do j = 1 , size ( dep % preprocess ) if ( dep % preprocess ( j )% name == \"cpp\" ) then if (. not . has_cpp ) has_cpp = . true . if ( allocated ( dep % preprocess ( j )% macros )) then model % packages ( i )% macros = [ model % packages ( i )% macros , dep % preprocess ( j )% macros ] end if else write ( stderr , '(a)' ) 'Warning: Preprocessor ' // package % preprocess ( i )% name // & ' is not supported; will ignore it' end if end do end if if (. not . allocated ( model % packages ( i )% sources )) allocate ( model % packages ( i )% sources ( 0 )) if ( allocated ( dependency % library )) then if ( allocated ( dependency % library % source_dir )) then lib_dir = join_path ( dep % proj_dir , dependency % library % source_dir ) if ( is_dir ( lib_dir )) then call add_sources_from_dir ( model % packages ( i )% sources , lib_dir , FPM_SCOPE_LIB , & error = error ) if ( allocated ( error )) exit end if end if if ( allocated ( dependency % library % include_dir )) then do j = 1 , size ( dependency % library % include_dir ) include_dir % s = join_path ( dep % proj_dir , dependency % library % include_dir ( j )% s ) if ( is_dir ( include_dir % s )) then model % include_dirs = [ model % include_dirs , include_dir ] end if end do end if end if if ( allocated ( dependency % build % link )) then model % link_libraries = [ model % link_libraries , dependency % build % link ] end if if ( allocated ( dependency % build % external_modules )) then model % external_modules = [ model % external_modules , dependency % build % external_modules ] end if ! Copy naming conventions from this dependency's manifest model % packages ( i )% enforce_module_names = dependency % build % module_naming model % packages ( i )% module_prefix = dependency % build % module_prefix end associate end do if ( allocated ( error )) return ! Add optional flags if ( has_cpp ) call set_cpp_preprocessor_flags ( model % compiler % id , model % fortran_compile_flags ) ! Add sources from executable directories if ( is_dir ( 'app' ) . and . package % build % auto_executables ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'app' , FPM_SCOPE_APP , & with_executables = . true ., error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'example' ) . and . package % build % auto_examples ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'example' , FPM_SCOPE_EXAMPLE , & with_executables = . true ., error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'test' ) . and . package % build % auto_tests ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'test' , FPM_SCOPE_TEST , & with_executables = . true ., error = error ) if ( allocated ( error )) then return endif end if if ( allocated ( package % executable )) then call add_executable_sources ( model % packages ( 1 )% sources , package % executable , FPM_SCOPE_APP , & auto_discover = package % build % auto_executables , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % example )) then call add_executable_sources ( model % packages ( 1 )% sources , package % example , FPM_SCOPE_EXAMPLE , & auto_discover = package % build % auto_examples , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % test )) then call add_executable_sources ( model % packages ( 1 )% sources , package % test , FPM_SCOPE_TEST , & auto_discover = package % build % auto_tests , & error = error ) if ( allocated ( error )) then return endif endif if ( settings % verbose ) then write ( * , * ) ' BUILD_NAME: ' , model % build_prefix write ( * , * ) ' COMPILER: ' , model % compiler % fc write ( * , * ) ' C COMPILER: ' , model % compiler % cc write ( * , * ) ' CXX COMPILER: ' , model % compiler % cxx write ( * , * ) ' COMPILER OPTIONS: ' , model % fortran_compile_flags write ( * , * ) ' C COMPILER OPTIONS: ' , model % c_compile_flags write ( * , * ) ' CXX COMPILER OPTIONS: ' , model % cxx_compile_flags write ( * , * ) ' LINKER OPTIONS: ' , model % link_flags write ( * , * ) ' INCLUDE DIRECTORIES: [' , string_cat ( model % include_dirs , ',' ), ']' end if ! Check for invalid module names call check_module_names ( model , error ) if ( allocated ( error )) return ! Check for duplicate modules duplicates_found = . false . call check_modules_for_duplicates ( model , duplicates_found ) if ( duplicates_found ) then call fpm_stop ( 1 , '*build_model*:Error: One or more duplicate module names found.' ) end if end subroutine build_model","tags":"","loc":"proc/build_model.html"},{"title":"check_modules_for_duplicates – Fortran-lang/fpm","text":"public subroutine check_modules_for_duplicates(model, duplicates_found) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model logical :: duplicates_found Contents Source Code check_modules_for_duplicates Source Code subroutine check_modules_for_duplicates ( model , duplicates_found ) type ( fpm_model_t ), intent ( in ) :: model integer :: maxsize integer :: i , j , k , l , m , modi type ( string_t ), allocatable :: modules (:) logical :: duplicates_found ! Initialise the size of array maxsize = 0 ! Get number of modules provided by each source file of every package do i = 1 , size ( model % packages ) do j = 1 , size ( model % packages ( i )% sources ) if ( allocated ( model % packages ( i )% sources ( j )% modules_provided )) then maxsize = maxsize + size ( model % packages ( i )% sources ( j )% modules_provided ) end if end do end do ! Allocate array to contain distinct names of modules allocate ( modules ( maxsize )) ! Initialise index to point at start of the newly allocated array modi = 1 ! Loop through modules provided by each source file of every package ! Add it to the array if it is not already there ! Otherwise print out warning about duplicates do k = 1 , size ( model % packages ) do l = 1 , size ( model % packages ( k )% sources ) if ( allocated ( model % packages ( k )% sources ( l )% modules_provided )) then do m = 1 , size ( model % packages ( k )% sources ( l )% modules_provided ) if ( model % packages ( k )% sources ( l )% modules_provided ( m )% s . in . modules (: modi - 1 )) then write ( stderr , * ) \"Warning: Module \" , model % packages ( k )% sources ( l )% modules_provided ( m )% s , & \" in \" , model % packages ( k )% sources ( l )% file_name , \" is a duplicate\" duplicates_found = . true . else modules ( modi ) = model % packages ( k )% sources ( l )% modules_provided ( m ) modi = modi + 1 end if end do end if end do end do end subroutine check_modules_for_duplicates","tags":"","loc":"proc/check_modules_for_duplicates.html"},{"title":"cmd_build – Fortran-lang/fpm","text":"public subroutine cmd_build(settings) Arguments Type Intent Optional Attributes Name type( fpm_build_settings ), intent(inout) :: settings Contents Source Code cmd_build Source Code subroutine cmd_build ( settings ) type ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( error_t ), allocatable :: error integer :: i call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Target error: ' // error % message ) end if if ( settings % list ) then do i = 1 , size ( targets ) write ( stderr , * ) targets ( i )% ptr % output_file enddo else if ( settings % show_model ) then call show_model ( model ) else call build_package ( targets , model , verbose = settings % verbose ) endif end subroutine cmd_build","tags":"","loc":"proc/cmd_build.html"},{"title":"cmd_clean – Fortran-lang/fpm","text":"public subroutine cmd_clean(settings) Delete the build directory including or excluding dependencies. Arguments Type Intent Optional Attributes Name class( fpm_clean_settings ), intent(in) :: settings Settings for the clean command. Contents Source Code cmd_clean Source Code subroutine cmd_clean ( settings ) !> Settings for the clean command. class ( fpm_clean_settings ), intent ( in ) :: settings character :: user_response if ( is_dir ( 'build' )) then ! Remove the entire build directory if ( settings % clean_call ) then call os_delete_dir ( os_is_unix (), 'build' ); return end if ! Remove the build directory but skip dependencies if ( settings % clean_skip ) then call delete_skip ( os_is_unix ()); return end if ! Prompt to remove the build directory but skip dependencies write ( stdout , '(A)' , advance = 'no' ) \"Delete build, excluding dependencies (y/n)? \" read ( stdin , '(A1)' ) user_response if ( lower ( user_response ) == 'y' ) call delete_skip ( os_is_unix ()) else write ( stdout , '(A)' ) \"fpm: No build directory found.\" end if end subroutine cmd_clean","tags":"","loc":"proc/cmd_clean.html"},{"title":"cmd_run – Fortran-lang/fpm","text":"public subroutine cmd_run(settings, test) Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(inout) :: settings logical, intent(in) :: test Contents Source Code cmd_run Source Code subroutine cmd_run ( settings , test ) class ( fpm_run_settings ), intent ( inout ) :: settings logical , intent ( in ) :: test integer :: i , j , col_width logical :: found ( size ( settings % name )) type ( error_t ), allocatable :: error type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( string_t ) :: exe_cmd type ( string_t ), allocatable :: executables (:) type ( build_target_t ), pointer :: exe_target type ( srcfile_t ), pointer :: exe_source integer :: run_scope , firsterror integer , allocatable :: stat (:) character ( len = :), allocatable :: line logical :: toomany call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Targets error: ' // error % message ) end if if ( test ) then run_scope = FPM_SCOPE_TEST else run_scope = merge ( FPM_SCOPE_EXAMPLE , FPM_SCOPE_APP , settings % example ) end if ! Enumerate executable targets to run col_width = - 1 found (:) = . false . allocate ( executables ( 0 )) do i = 1 , size ( targets ) exe_target => targets ( i )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then col_width = max ( col_width , len ( basename ( exe_target % output_file )) + 2 ) if ( size ( settings % name ) == 0 ) then exe_cmd % s = exe_target % output_file executables = [ executables , exe_cmd ] else do j = 1 , size ( settings % name ) if ( glob ( trim ( exe_source % exe_name ), trim ( settings % name ( j )))) then found ( j ) = . true . exe_cmd % s = exe_target % output_file executables = [ executables , exe_cmd ] end if end do end if end if end if end do ! Check if any apps/tests were found if ( col_width < 0 ) then if ( test ) then call fpm_stop ( 0 , 'No tests to run' ) else call fpm_stop ( 0 , 'No executables to run' ) end if end if ! Check all names are valid ! or no name and found more than one file toomany = size ( settings % name ) == 0 . and . size ( executables ) > 1 if ( any (. not . found ) & & . or . & & ( ( toomany . and . . not . test ) . or . ( toomany . and . settings % runner /= '' ) ) & & . and . & & . not . settings % list ) then line = join ( settings % name ) if ( line /= '.' ) then ! do not report these special strings if ( any (. not . found )) then write ( stderr , '(A)' , advance = \"no\" ) '*cmd_run*:specified names ' do j = 1 , size ( settings % name ) if (. not . found ( j )) write ( stderr , '(A)' , advance = \"no\" ) '\"' // trim ( settings % name ( j )) // '\" ' end do write ( stderr , '(A)' ) 'not found.' write ( stderr , * ) else if ( settings % verbose ) then write ( stderr , '(A)' , advance = \"yes\" ) 'when more than one executable is available' write ( stderr , '(A)' , advance = \"yes\" ) ' program names must be specified.' endif endif call compact_list_all () if ( line == '.' . or . line == ' ' ) then ! do not report these special strings call fpm_stop ( 0 , '' ) else call fpm_stop ( 1 , '' ) endif end if call build_package ( targets , model , verbose = settings % verbose ) if ( settings % list ) then call compact_list () else allocate ( stat ( size ( executables ))) do i = 1 , size ( executables ) if ( exists ( executables ( i )% s )) then if ( settings % runner /= ' ' ) then if (. not . allocated ( settings % args )) then call run ( settings % runner_command () // ' ' // executables ( i )% s , & echo = settings % verbose , exitstat = stat ( i )) else call run ( settings % runner_command () // ' ' // executables ( i )% s // \" \" // settings % args , & echo = settings % verbose , exitstat = stat ( i )) endif else if (. not . allocated ( settings % args )) then call run ( executables ( i )% s , echo = settings % verbose , exitstat = stat ( i )) else call run ( executables ( i )% s // \" \" // settings % args , echo = settings % verbose , & exitstat = stat ( i )) endif endif else call fpm_stop ( 1 , '*cmd_run*:' // executables ( i )% s // ' not found' ) end if end do if ( any ( stat /= 0 )) then do i = 1 , size ( stat ) if ( stat ( i ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Execution for object \"' , basename ( executables ( i )% s ),& '\" returned exit code ' , stat ( i ) end if end do firsterror = findloc ( stat /= 0 , value = . true ., dim = 1 ) call fpm_stop ( stat ( firsterror ), '*cmd_run*:stopping due to failed executions' ) end if end if contains subroutine compact_list_all () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Available names:' do ii = 1 , size ( targets ) exe_target => targets ( ii )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( exe_target % output_file , suffix = . false .)] jj = jj + 1 end if end if end do write ( stderr , * ) end subroutine compact_list_all subroutine compact_list () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Matched names:' do ii = 1 , size ( executables ) write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( executables ( ii )% s , suffix = . false .)] jj = jj + 1 end do write ( stderr , * ) end subroutine compact_list end subroutine cmd_run","tags":"","loc":"proc/cmd_run.html"},{"title":"MPI_TYPE_NAME – Fortran-lang/fpm","text":"public pure function MPI_TYPE_NAME(mpilib) result(name) Return a name for the MPI library Arguments Type Intent Optional Attributes Name integer, intent(in) :: mpilib Return Value character(len=:), allocatable Contents Source Code MPI_TYPE_NAME Source Code pure function MPI_TYPE_NAME ( mpilib ) result ( name ) integer , intent ( in ) :: mpilib character ( len = :), allocatable :: name select case ( mpilib ) case ( MPI_TYPE_NONE ); name = \"none\" case ( MPI_TYPE_OPENMPI ); name = \"OpenMPI\" case ( MPI_TYPE_MPICH ); name = \"MPICH\" case ( MPI_TYPE_INTEL ); name = \"INTELMPI\" case ( MPI_TYPE_MSMPI ); name = \"MS-MPI\" case default ; name = \"UNKNOWN\" end select end function MPI_TYPE_NAME","tags":"","loc":"proc/mpi_type_name.html"},{"title":"resolve_metapackages – Fortran-lang/fpm","text":"public interface resolve_metapackages Contents Module Procedures resolve_metapackage_model Module Procedures private subroutine resolve_metapackage_model(model, package, settings, error) Resolve all metapackages into the package config Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(inout) :: model type( package_config_t ), intent(inout) :: package class( fpm_build_settings ), intent(inout) :: settings type( error_t ), intent(out), allocatable :: error","tags":"","loc":"interface/resolve_metapackages.html"},{"title":"build_progress_t – Fortran-lang/fpm","text":"public interface build_progress_t Constructor for build_progress_t Contents Module Procedures new_build_progress Module Procedures private function new_build_progress(target_queue, plain_mode) result(progress) Initialise a new build progress object Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in), target :: target_queue (:) The queue of scheduled targets logical, intent(in), optional :: plain_mode Enable ‘plain’ output for progress object Return Value type( build_progress_t ) Progress object to initialise","tags":"","loc":"interface/build_progress_t.html"},{"title":"dilate – Fortran-lang/fpm","text":"public function dilate(instr) result(outstr) NAME dilate(3f) - [M_strings:NONALPHA] expand tab characters\n(LICENSE:PD) SYNOPSIS function dilate(INSTR) result ( OUTSTR ) character ( len = * ), intent =( in ) :: INSTR character ( len =:), allocatable :: OUTSTR DESCRIPTION dilate() converts tabs in INSTR to spaces in OUTSTR. It assumes a\n tab is set every 8 characters. Trailing spaces are removed.\n\n In addition, trailing carriage returns and line feeds are removed\n (they are usually a problem created by going to and from MSWindows). OPTIONS instr Input line to remove tabs from RESULTS outstr Output string with tabs expanded. EXAMPLES Sample program: program demo_dilate use M_strings , only : dilate implicit none character ( len = : ) , allocatable :: in integer :: i in = ' this is my string ' ! change spaces to tabs to make a sample input do i = 1 , len ( in ) if ( in ( i : i ) == ' ' ) in ( i : i ) = char ( 9 ) enddo write ( * , ' (a) ' ) in , dilate ( in ) end program demo_dilate Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr Return Value character(len=:), allocatable Contents Source Code dilate Source Code function dilate ( instr ) result ( outstr ) character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len = :), allocatable :: outstr ! tab-expanded version of INSTR produced integer :: i integer :: icount integer :: lgth icount = 0 do i = 1 , len ( instr ) if ( instr ( i : i ) == char ( 9 )) icount = icount + 1 end do allocate ( character ( len = ( len ( instr ) + 8 * icount )) :: outstr ) call notabs ( instr , outstr , lgth ) outstr = outstr (: lgth ) end function dilate","tags":"","loc":"proc/dilate.html"},{"title":"f_string – Fortran-lang/fpm","text":"public function f_string(c_string) Uses iso_c_binding return Fortran character variable when given a C-like array of\nsingle characters terminated with a C_NULL_CHAR character Arguments Type Intent Optional Attributes Name character(len=1), intent(in) :: c_string (:) Return Value character(len=:), allocatable Contents Source Code f_string Source Code function f_string ( c_string ) use iso_c_binding character ( len = 1 ), intent ( in ) :: c_string (:) character (:), allocatable :: f_string integer :: i , n i = 0 do while ( c_string ( i + 1 ) /= C_NULL_CHAR ) i = i + 1 end do n = i allocate ( character ( n ) :: f_string ) do i = 1 , n f_string ( i : i ) = c_string ( i ) end do end function f_string","tags":"","loc":"proc/f_string.html"},{"title":"glob – Fortran-lang/fpm","text":"public function glob(tame, wild) NAME glob ( 3 f ) - [ fpm_strings : COMPARE ] compare given string for match to pattern which may contain wildcard characters ( LICENSE : PD ) SYNOPSIS logical function glob(string, pattern )\n\n character(len=*),intent(in) :: string\n character(len=*),intent(in) :: pattern DESCRIPTION glob(3f) compares given STRING for match to PATTERN which may\n contain wildcard characters. In this version to get a match the entire string must be described\n by PATTERN. Trailing whitespace is significant, so trim the input\n string to have trailing whitespace ignored. OPTIONS string the input string to test to see if it contains the pattern . pattern the following simple globbing options are available o \" ? \" matching any one character o \" * \" matching zero or more characters . Do NOT use adjacent asterisks . o Both strings may have trailing spaces which are ignored . o There is no escape character , so matching strings with literal question mark and asterisk is problematic . EXAMPLES Example program program demo_glob implicit none ! This main () routine passes a bunch of test strings ! into the above code . In performance comparison mode , ! it does that over and over . Otherwise , it does it just ! once . Either way , it outputs a passed / failed result . ! integer :: nReps logical :: allpassed integer :: i allpassed = . true . nReps = 10000 ! Can choose as many repetitions as you ' re expecting ! in the real world . nReps = 1 do i = 1 , nReps ! Cases with repeating character sequences . allpassed = allpassed . and . test ( \" a*abab \" , \" a*b \" , . true . ) !! cycle allpassed = allpassed . and . test ( \" ab \" , \" *? \" , . true . ) allpassed = allpassed . and . test ( \" abc \" , \" *? \" , . true . ) allpassed = allpassed . and . test ( \" abcccd \" , \" *ccd \" , . true . ) allpassed = allpassed . and . test ( \" bLah \" , \" bLaH \" , . false . ) allpassed = allpassed . and . test ( \" mississippi \" , \" *sip* \" , . true . ) allpassed = allpassed . and . & & test ( \" xxxx*zzzzzzzzy*f \" , \" xxx*zzy*f \" , . true . ) allpassed = allpassed . and . & & test ( \" xxxx*zzzzzzzzy*f \" , \" xxxx*zzy*fffff \" , . false . ) allpassed = allpassed . and . & & test ( \" mississipissippi \" , \" *issip*ss* \" , . true . ) allpassed = allpassed . and . & & test ( \" xxxxzzzzzzzzyf \" , \" xxxx*zzy*fffff \" , . false . ) allpassed = allpassed . and . & & test ( \" xxxxzzzzzzzzyf \" , \" xxxx*zzy*f \" , . true . ) allpassed = allpassed . and . test ( \" xyxyxyzyxyz \" , \" xy*z*xyz \" , . true . ) allpassed = allpassed . and . test ( \" xyxyxyxyz \" , \" xy*xyz \" , . true . ) allpassed = allpassed . and . test ( \" mississippi \" , \" mi*sip* \" , . true . ) allpassed = allpassed . and . test ( \" ababac \" , \" *abac* \" , . true . ) allpassed = allpassed . and . test ( \" aaazz \" , \" a*zz* \" , . true . ) allpassed = allpassed . and . test ( \" a12b12 \" , \" *12*23 \" , . false . ) allpassed = allpassed . and . test ( \" a12b12 \" , \" a12b \" , . false . ) allpassed = allpassed . and . test ( \" a12b12 \" , \" *12*12* \" , . true . ) ! Additional cases where the ' * ' char appears in the tame string . allpassed = allpassed . and . test ( \" * \" , \" * \" , . true . ) allpassed = allpassed . and . test ( \" a*r \" , \" a* \" , . true . ) allpassed = allpassed . and . test ( \" a*ar \" , \" a*aar \" , . false . ) ! More double wildcard scenarios . allpassed = allpassed . and . test ( \" XYXYXYZYXYz \" , \" XY*Z*XYz \" , . true . ) allpassed = allpassed . and . test ( \" missisSIPpi \" , \" *SIP* \" , . true . ) allpassed = allpassed . and . test ( \" mississipPI \" , \" *issip*PI \" , . true . ) allpassed = allpassed . and . test ( \" xyxyxyxyz \" , \" xy*xyz \" , . true . ) allpassed = allpassed . and . test ( \" miSsissippi \" , \" mi*sip* \" , . true . ) allpassed = allpassed . and . test ( \" miSsissippi \" , \" mi*Sip* \" , . false . ) allpassed = allpassed . and . test ( \" abAbac \" , \" *Abac* \" , . true . ) allpassed = allpassed . and . test ( \" aAazz \" , \" a*zz* \" , . true . ) allpassed = allpassed . and . test ( \" A12b12 \" , \" *12*23 \" , . false . ) allpassed = allpassed . and . test ( \" a12B12 \" , \" *12*12* \" , . true . ) allpassed = allpassed . and . test ( \" oWn \" , \" *oWn* \" , . true . ) ! Completely tame ( no wildcards ) cases . allpassed = allpassed . and . test ( \" bLah \" , \" bLah \" , . true . ) ! Simple mixed wildcard tests suggested by IBMer Marlin Deckert . allpassed = allpassed . and . test ( \" a \" , \" *? \" , . true . ) ! More mixed wildcard tests including coverage for false positives . allpassed = allpassed . and . test ( \" a \" , \" ?? \" , . false . ) allpassed = allpassed . and . test ( \" ab \" , \" ?*? \" , . true . ) allpassed = allpassed . and . test ( \" ab \" , \" *?*?* \" , . true . ) allpassed = allpassed . and . test ( \" abc \" , \" ?**?*? \" , . true . ) allpassed = allpassed . and . test ( \" abc \" , \" ?**?*&? \" , . false . ) allpassed = allpassed . and . test ( \" abcd \" , \" ?b*?? \" , . true . ) allpassed = allpassed . and . test ( \" abcd \" , \" ?a*?? \" , . false . ) allpassed = allpassed . and . test ( \" abcd \" , \" ?**?c? \" , . true . ) allpassed = allpassed . and . test ( \" abcd \" , \" ?**?d? \" , . false . ) allpassed = allpassed . and . test ( \" abcde \" , \" ?*b*?*d*? \" , . true . ) ! Single - character - match cases . allpassed = allpassed . and . test ( \" bLah \" , \" bL?h \" , . true . ) allpassed = allpassed . and . test ( \" bLaaa \" , \" bLa? \" , . false . ) allpassed = allpassed . and . test ( \" bLah \" , \" bLa? \" , . true . ) allpassed = allpassed . and . test ( \" bLaH \" , \" ?Lah \" , . false . ) allpassed = allpassed . and . test ( \" bLaH \" , \" ?LaH \" , . true . ) ! Many - wildcard scenarios . allpassed = allpassed . and . test ( & & \" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa& & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab \" ,& & \" a*a*a*a*a*a*aa*aaa*a*a*b \" , & & . true . ) allpassed = allpassed . and . test ( & & \" abababababababababababababababababababaacacacacacacac& & adaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab \" ,& & \" *a*b*ba*ca*a*aa*aaa*fa*ga*b* \" , & & . true . ) allpassed = allpassed . and . test ( & & \" abababababababababababababababababababaacacacacacaca& & cadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab \" ,& & \" *a*b*ba*ca*a*x*aaa*fa*ga*b* \" , & & . false . ) allpassed = allpassed . and . test ( & & \" abababababababababababababababababababaacacacacacacacad& & aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab \" ,& & \" *a*b*ba*ca*aaaa*fa*ga*gggg*b* \" , & & . false . ) allpassed = allpassed . and . test ( & & \" abababababababababababababababababababaacacacacacacacad& & aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab \" ,& & \" *a*b*ba*ca*aaaa*fa*ga*ggg*b* \" , & & . true . ) allpassed = allpassed . and . test ( \" aaabbaabbaab \" , \" *aabbaa*a* \" , . true . ) allpassed = allpassed . and . & test ( \" a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a* \" , & & \" a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a* \" , . true . ) allpassed = allpassed . and . test ( \" aaaaaaaaaaaaaaaaa \" , & & \" *a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a* \" , . true . ) allpassed = allpassed . and . test ( \" aaaaaaaaaaaaaaaa \" , & & \" *a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a* \" , . false . ) allpassed = allpassed . and . test ( & & \" abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& &* abcdefghijk * abcdefghijkl * abcdefghijklm * abcdefghijklmn \" ,& & \" abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc& &* abc * abc * abc * \" ,& & . false . ) allpassed = allpassed . and . test ( & & \" abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& &* abcdefghijk * abcdefghijkl * abcdefghijklm * abcdefghijklmn \" ,& & \" abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc* \" , & & . true . ) allpassed = allpassed . and . test ( \" abc*abcd*abcd*abc*abcd \" , & & \" abc*abc*abc*abc*abc \" , . false . ) allpassed = allpassed . and . test ( \" abc*abcd*abcd*abc*abcd*abcd& &* abc * abcd * abc * abc * abcd \" , & & \" abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd \" , & & . true . ) allpassed = allpassed . and . test ( \" abc \" , & & \" ********a********b********c******** \" , . true . ) allpassed = allpassed . and . & & test ( \" ********a********b********c******** \" , \" abc \" , . false . ) allpassed = allpassed . and . & & test ( \" abc \" , \" ********a********b********b******** \" , . false . ) allpassed = allpassed . and . test ( \" *abc* \" , \" ***a*b*c*** \" , . true . ) ! A case - insensitive algorithm test . ! allpassed = allpassed . and . test ( \" mississippi \" , \" *issip*PI \" , . true . ) enddo if ( allpassed ) then write ( * , ' (a) ' ) \" Passed \" , nReps else write ( * , ' (a) ' ) \" Failed \" endif contains ! This is a test program for wildcard matching routines . ! It can be used either to test a single routine for correctness , ! or to compare the timings of two ( or more ) different wildcard ! matching routines . ! function test ( tame , wild , bExpectedResult ) result ( bpassed ) use fpm_strings , only : glob character ( len =* ) :: tame character ( len =* ) :: wild logical :: bExpectedResult logical :: bResult logical :: bPassed bResult = . true . ! We ' ll do \"&=\" cumulative checking. bPassed = . false . ! Assume the worst . write ( * , * ) repeat ( ' = ' , 79 ) bResult = glob ( tame , wild ) ! Call a wildcard matching routine . ! To assist correctness checking , output the two strings in any ! failing scenarios . if ( bExpectedResult . eqv . bResult ) then bPassed = . true . if ( nReps == 1 ) write ( * , * ) \" Passed match on \" , tame , \" vs. \" , wild else if ( nReps == 1 ) write ( * , * ) \" Failed match on \" , tame , \" vs. \" , wild endif end function test end program demo_glob Expected output REFERENCE The article “Matching Wildcards: An Empirical Way to Tame an Algorithm”\n in Dr Dobb’s Journal, By Kirk J. Krauss, October 07, 2014 Arguments Type Intent Optional Attributes Name character(len=*) :: tame A string without wildcards to compare to the globbing expression character(len=*) :: wild A (potentially) corresponding string with wildcards Return Value logical result of test Contents Source Code glob Source Code function glob ( tame , wild ) ! @(#)fpm_strings::glob(3f): function compares text strings, one of which can have wildcards ('*' or '?'). logical :: glob !! result of test character ( len =* ) :: tame !! A string without wildcards to compare to the globbing expression character ( len =* ) :: wild !! A (potentially) corresponding string with wildcards character ( len = len ( tame ) + 1 ) :: tametext character ( len = len ( wild ) + 1 ) :: wildtext character ( len = 1 ), parameter :: NULL = char ( 0 ) integer :: wlen integer :: ti , wi integer :: i character ( len = :), allocatable :: tbookmark , wbookmark ! These two values are set when we observe a wildcard character. They ! represent the locations, in the two strings, from which we start once we've observed it. tametext = tame // NULL wildtext = wild // NULL tbookmark = NULL wbookmark = NULL wlen = len ( wild ) wi = 1 ti = 1 do ! Walk the text strings one character at a time. if ( wildtext ( wi : wi ) == '*' ) then ! How do you match a unique text string? do i = wi , wlen ! Easy: unique up on it! if ( wildtext ( wi : wi ) == '*' ) then wi = wi + 1 else exit endif enddo if ( wildtext ( wi : wi ) == NULL ) then ! \"x\" matches \"*\" glob = . true . return endif if ( wildtext ( wi : wi ) /= '?' ) then ! Fast-forward to next possible match. do while ( tametext ( ti : ti ) /= wildtext ( wi : wi )) ti = ti + 1 if ( tametext ( ti : ti ) == NULL ) then glob = . false . return ! \"x\" doesn't match \"*y*\" endif enddo endif wbookmark = wildtext ( wi :) tbookmark = tametext ( ti :) elseif ( tametext ( ti : ti ) /= wildtext ( wi : wi ) . and . wildtext ( wi : wi ) /= '?' ) then ! Got a non-match. If we've set our bookmarks, back up to one or both of them and retry. if ( wbookmark /= NULL ) then if ( wildtext ( wi :) /= wbookmark ) then wildtext = wbookmark ; wlen = len_trim ( wbookmark ) wi = 1 ! Don't go this far back again. if ( tametext ( ti : ti ) /= wildtext ( wi : wi )) then tbookmark = tbookmark ( 2 :) tametext = tbookmark ti = 1 cycle ! \"xy\" matches \"*y\" else wi = wi + 1 endif endif if ( tametext ( ti : ti ) /= NULL ) then ti = ti + 1 cycle ! \"mississippi\" matches \"*sip*\" endif endif glob = . false . return ! \"xy\" doesn't match \"x\" endif ti = ti + 1 wi = wi + 1 if ( tametext ( ti : ti ) == NULL ) then ! How do you match a tame text string? if ( wildtext ( wi : wi ) /= NULL ) then do while ( wildtext ( wi : wi ) == '*' ) ! The tame way: unique up on it! wi = wi + 1 ! \"x\" matches \"x*\" if ( wildtext ( wi : wi ) == NULL ) exit enddo endif if ( wildtext ( wi : wi ) == NULL ) then glob = . true . return ! \"x\" matches \"x\" endif glob = . false . return ! \"x\" doesn't match \"xy\" endif enddo end function glob","tags":"","loc":"proc/glob.html"},{"title":"has_valid_custom_prefix – Fortran-lang/fpm","text":"public function has_valid_custom_prefix(module_name, custom_prefix) result(valid) Check that a module name is prefixed with a custom prefix:\n1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed)\n2) It must begin with the prefix\n3) If longer, package name must be followed by default separator (“_”) plus at least one char Basic check: check that both names are individually valid FPM package enforcing: check that the module name begins with the custom prefix Query string lengths\n2) It must begin with the package name.\n3) It can be equal to the package name, or, if longer, must be followed by the\n4) Package name must not end with an underscore Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: custom_prefix Return Value logical Contents Source Code has_valid_custom_prefix Source Code logical function has_valid_custom_prefix ( module_name , custom_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: custom_prefix !> custom_module separator: single underscore character ( * ), parameter :: SEP = \"_\" logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check that both names are individually valid valid = is_fortran_name ( module_name % s ) . and . & is_valid_module_prefix ( custom_prefix ) !> FPM package enforcing: check that the module name begins with the custom prefix if ( valid ) then !> Query string lengths lpkg = len_trim ( custom_prefix ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , custom_prefix % s , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator )) end if end function has_valid_custom_prefix","tags":"","loc":"proc/has_valid_custom_prefix.html"},{"title":"has_valid_standard_prefix – Fortran-lang/fpm","text":"public function has_valid_standard_prefix(module_name, package_name) result(valid) Check that a module name is prefixed with the default package prefix:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Basic check: check the name is Fortran-compliant FPM package enforcing: check that the module name begins with the package name Query string lengths\n2) It must begin with the package name.\n3) It can be equal to the package name, or, if longer, must be followed by the\n4) Package name must not end with an underscore Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name Return Value logical Contents Source Code has_valid_standard_prefix Source Code logical function has_valid_standard_prefix ( module_name , package_name ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name !> Default package__module separator: two underscores character ( * ), parameter :: SEP = \"__\" character ( len = :), allocatable :: fortranized_pkg logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ) !> FPM package enforcing: check that the module name begins with the package name if ( valid ) then fortranized_pkg = to_fortran_name ( package_name % s ) !> Query string lengths lpkg = len_trim ( fortranized_pkg ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , fortranized_pkg , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = is_fortran_name ( fortranized_pkg ) . and . & fortranized_pkg ( lpkg : lpkg ) /= '_' . and . & ( same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator ))) end if end function has_valid_standard_prefix","tags":"","loc":"proc/has_valid_standard_prefix.html"},{"title":"is_fortran_name – Fortran-lang/fpm","text":"public elemental function is_fortran_name(line) result(lout) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: line Return Value logical Contents Source Code is_fortran_name Source Code elemental 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 ) /= 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","tags":"","loc":"proc/is_fortran_name.html"},{"title":"is_valid_module_name – Fortran-lang/fpm","text":"public function is_valid_module_name(module_name, package_name, custom_prefix, enforce_module_names) result(valid) Check that a module name fits the current naming rules:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Basic check: check the name is Fortran-compliant FPM package enforcing: check that the module name begins with the package name Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name type( string_t ), intent(in) :: custom_prefix logical, intent(in) :: enforce_module_names Return Value logical Contents Source Code is_valid_module_name Source Code logical function is_valid_module_name ( module_name , package_name , custom_prefix , enforce_module_names ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name type ( string_t ), intent ( in ) :: custom_prefix logical , intent ( in ) :: enforce_module_names !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ); if (. not . valid ) return !> FPM package enforcing: check that the module name begins with the package name if ( enforce_module_names ) then ! Default prefixing is always valid valid = has_valid_standard_prefix ( module_name , package_name ) ! If a custom prefix was validated, it provides additional naming options ! Because they never overlap with the default prefix, the former is always an option if ( len_trim ( custom_prefix ) > 0 . and . . not . valid ) & valid = has_valid_custom_prefix ( module_name , custom_prefix ) end if end function is_valid_module_name","tags":"","loc":"proc/is_valid_module_name.html"},{"title":"is_valid_module_prefix – Fortran-lang/fpm","text":"public function is_valid_module_prefix(module_prefix) result(valid) Check that a custom module prefix fits the current naming rules:\n1) Only alphanumeric characters (no spaces, dashes, underscores or other characters)\n2) Does not begin with a number (Fortran-compatible syntax) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_prefix Return Value logical Contents Source Code is_valid_module_prefix Source Code logical function is_valid_module_prefix ( module_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_prefix character ( len =* ), parameter :: num = '0123456789' character ( len =* ), parameter :: lower = 'abcdefghijklmnopqrstuvwxyz' character ( len =* ), parameter :: upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' character ( len =* ), parameter :: alpha = upper // lower character ( len =* ), parameter :: allowed = alpha // num character ( len = :), allocatable :: name name = trim ( module_prefix % s ) if ( len ( name ) > 0 . and . len ( name ) <= 63 ) then valid = verify ( name ( 1 : 1 ), alpha ) == 0 . and . & verify ( name , allowed ) == 0 else valid = . false . endif end function is_valid_module_prefix","tags":"","loc":"proc/is_valid_module_prefix.html"},{"title":"join – Fortran-lang/fpm","text":"public pure function join(str, sep, trm, left, right, start, end) result(string) NAME join ( 3 f ) - [ M_strings : EDITING ] append CHARACTER variable array into a single CHARACTER variable with specified separator ( LICENSE : PD ) SYNOPSIS pure function join ( str , sep , trm , left , right , start , end ) result ( string ) character ( len =* ) , intent ( in ) :: str ( : ) character ( len =* ) , intent ( in ) , optional :: sep logical , intent ( in ) , optional :: trm character ( len =* ) , intent ( in ) , optional :: right character ( len =* ) , intent ( in ) , optional :: left character ( len =* ) , intent ( in ) , optional :: start character ( len =* ) , intent ( in ) , optional :: end character ( len = : ) , allocatable :: string DESCRIPTION JOIN(3f) appends the elements of a CHARACTER array into a single\n CHARACTER variable, with elements 1 to N joined from left to right.\n By default each element is trimmed of trailing spaces and the\n default separator is a null string. OPTIONS STR (:) array of CHARACTER variables to be joined SEP separator string to place between each variable . defaults to a null string . LEFT string to place at left of each element RIGHT string to place at right of each element START prefix string END suffix string TRM option to trim each element of STR of trailing spaces . Defaults to . TRUE . RESULT STRING CHARACTER variable composed of all of the elements of STR () appended together with the optional separator SEP placed between the elements . EXAMPLE Sample program: program demo_join\n use M_strings, only: join\n implicit none\n character(len=:),allocatable :: s(:)\n character(len=:),allocatable :: out\n integer :: i\n s=[character(len=10) :: ‘United’,’ we’,’ stand,’, &\n & ’ divided’,’ we fall.’]\n out=join(s)\n write( ,’(a)’) out\n write( ,’(a)’) join(s,trm=.false.)\n write( ,’(a)’) (join(s,trm=.false.,sep=’|’),i=1,3)\n write( ,’(a)’) join(s,sep=’<>’)\n write( ,’(a)’) join(s,sep=’;’,left=’[‘,right=’]’)\n write( ,’(a)’) join(s,left=’[‘,right=’]’)\n write(*,’(a)’) join(s,left=’>>’)\n end program demo_join Expected output: United we stand, divided we fall.\n United we stand, divided we fall.\n United | we | stand, | divided | we fall.\n United | we | stand, | divided | we fall.\n United | we | stand, | divided | we fall.\n United<> we<> stand,<> divided<> we fall.\n [United];[ we];[ stand,];[ divided];[ we fall.]\n [United][ we][ stand,][ divided][ we fall.] United>> we>> stand,>> divided>> we fall. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str (:) character(len=*), intent(in), optional :: sep logical, intent(in), optional :: trm character(len=*), intent(in), optional :: left character(len=*), intent(in), optional :: right character(len=*), intent(in), optional :: start character(len=*), intent(in), optional :: end Return Value character(len=:), allocatable Contents Source Code join Source Code pure function join ( str , sep , trm , left , right , start , end ) result ( string ) ! @(#)M_strings::join(3f): merge string array into a single CHARACTER value adding specified separators, caps, prefix and suffix character ( len =* ), intent ( in ) :: str (:) character ( len =* ), intent ( in ), optional :: sep , right , left , start , end logical , intent ( in ), optional :: trm character ( len = :), allocatable :: sep_local , left_local , right_local character ( len = :), allocatable :: string logical :: trm_local integer :: i if ( present ( sep )) then ; sep_local = sep ; else ; sep_local = '' ; endif if ( present ( trm )) then ; trm_local = trm ; else ; trm_local = . true . ; endif if ( present ( left )) then ; left_local = left ; else ; left_local = '' ; endif if ( present ( right )) then ; right_local = right ; else ; right_local = '' ; endif string = '' if ( size ( str ) == 0 ) then string = string // left_local // right_local else do i = 1 , size ( str ) - 1 if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local // sep_local else string = string // left_local // str ( i ) // right_local // sep_local endif enddo if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local else string = string // left_local // str ( i ) // right_local endif endif if ( present ( start )) string = start // string if ( present ( end )) string = string // end end function join","tags":"","loc":"proc/join.html"},{"title":"lower – Fortran-lang/fpm","text":"public pure elemental function lower(str, begin, end) result(string) Changes a string to lowercase over optional specified column range Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str integer, intent(in), optional :: begin integer, intent(in), optional :: end Return Value character(len=len(str)) Contents Source Code lower Source Code elemental pure function lower ( str , begin , end ) result ( string ) character ( * ), intent ( In ) :: str character ( len ( str )) :: string integer , intent ( in ), optional :: begin , end integer :: i integer :: ibegin , iend string = str ibegin = 1 if ( present ( begin )) then ibegin = max ( ibegin , begin ) endif iend = len_trim ( str ) if ( present ( end )) then iend = min ( iend , end ) endif do i = ibegin , iend ! step thru each letter in the string in specified range select case ( str ( i : i )) case ( 'A' : 'Z' ) string ( i : i ) = char ( iachar ( str ( i : i )) + 32 ) ! change letter to miniscule case default end select end do end function lower","tags":"","loc":"proc/lower.html"},{"title":"module_prefix_template – Fortran-lang/fpm","text":"public function module_prefix_template(project_name, custom_prefix) result(prefix) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) Contents Source Code module_prefix_template Source Code type ( string_t ) function module_prefix_template ( project_name , custom_prefix ) result ( prefix ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then prefix = string_t ( trim ( custom_prefix % s ) // \"_\" ) else prefix = string_t ( to_fortran_name ( project_name % s ) // \"__\" ) end if end function module_prefix_template","tags":"","loc":"proc/module_prefix_template.html"},{"title":"module_prefix_type – Fortran-lang/fpm","text":"public function module_prefix_type(project_name, custom_prefix) result(ptype) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) Contents Source Code module_prefix_type Source Code type ( string_t ) function module_prefix_type ( project_name , custom_prefix ) result ( ptype ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then ptype = string_t ( \"custom\" ) else ptype = string_t ( \"default\" ) end if end function module_prefix_type","tags":"","loc":"proc/module_prefix_type.html"},{"title":"replace – Fortran-lang/fpm","text":"public pure function replace(string, charset, target_char) result(res) Returns string with characters in charset replaced with target_char. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string character(len=1), intent(in) :: charset (:) character(len=1), intent(in) :: target_char Return Value character(len=len(string)) Contents Source Code replace Source Code pure function replace ( string , charset , target_char ) result ( res ) character ( * ), intent ( in ) :: string character , intent ( in ) :: charset (:), target_char character ( len ( string )) :: res integer :: n res = string do n = 1 , len ( string ) if ( any ( string ( n : n ) == charset )) then res ( n : n ) = target_char end if end do end function replace","tags":"","loc":"proc/replace.html"},{"title":"str_begins_with_str – Fortran-lang/fpm","text":"public pure function str_begins_with_str(s, e, case_sensitive) result(r) test if a CHARACTER string begins with a specified prefix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e logical, intent(in), optional :: case_sensitive Return Value logical Contents Source Code str_begins_with_str Source Code pure logical function str_begins_with_str ( s , e , case_sensitive ) result ( r ) character ( * ), intent ( in ) :: s , e logical , optional , intent ( in ) :: case_sensitive ! Default option: case sensitive integer :: n1 , n2 logical :: lower_case ! Check if case sensitive if ( present ( case_sensitive )) then lower_case = . not . case_sensitive else lower_case = . false . end if n1 = 1 n2 = 1 + len ( e ) - 1 if ( n2 > len ( s )) then r = . false . elseif ( lower_case ) then r = lower ( s ( n1 : n2 )) == lower ( e ) else r = ( s ( n1 : n2 ) == e ) end if end function str_begins_with_str","tags":"","loc":"proc/str_begins_with_str.html"},{"title":"string_array_contains – Fortran-lang/fpm","text":"public function string_array_contains(search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical Contents Source Code string_array_contains Source Code logical function string_array_contains ( search_string , array ) character ( * ), intent ( in ) :: search_string type ( string_t ), intent ( in ) :: array (:) integer :: i string_array_contains = any ([( array ( i )% s == search_string , & i = 1 , size ( array ))]) end function string_array_contains","tags":"","loc":"proc/string_array_contains.html"},{"title":"string_cat – Fortran-lang/fpm","text":"public function string_cat(strings, delim) result(cat) Concatenate an array of type(string_t) into\n a single CHARACTER variable Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) character(len=*), intent(in), optional :: delim Return Value character(len=:), allocatable Contents Source Code string_cat Source Code function string_cat ( strings , delim ) result ( cat ) type ( string_t ), intent ( in ) :: strings (:) character ( * ), intent ( in ), optional :: delim character (:), allocatable :: cat integer :: i character (:), allocatable :: delim_str if ( size ( strings ) < 1 ) then cat = '' return end if if ( present ( delim )) then delim_str = delim else delim_str = '' end if cat = strings ( 1 )% s do i = 2 , size ( strings ) cat = cat // delim_str // strings ( i )% s end do end function string_cat","tags":"","loc":"proc/string_cat.html"},{"title":"to_fortran_name – Fortran-lang/fpm","text":"public pure function to_fortran_name(string) result(res) Returns string with special characters replaced with an underscore.\nFor now, only a hyphen is treated as a special character, but this can be\nexpanded to other characters if needed. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string Return Value character(len=len(string)) Contents Source Code to_fortran_name Source Code pure function to_fortran_name ( string ) result ( res ) character ( * ), intent ( in ) :: string character ( len ( string )) :: res character , parameter :: SPECIAL_CHARACTERS ( * ) = [ '-' ] res = replace ( string , SPECIAL_CHARACTERS , '_' ) end function to_fortran_name","tags":"","loc":"proc/to_fortran_name.html"},{"title":"notabs – Fortran-lang/fpm","text":"public impure elemental subroutine notabs(instr, outstr, ilen) NAME notabs(3f) - [fpm_strings:NONALPHA] expand tab characters\n (LICENSE:PD) SYNOPSIS subroutine notabs(INSTR,OUTSTR,ILEN)\n\n character(len=*),intent=(in) :: INSTR\n character(len=*),intent=(out) :: OUTSTR\n integer,intent=(out) :: ILEN DESCRIPTION NOTABS() converts tabs in INSTR to spaces in OUTSTR while maintaining\n columns. It assumes a tab is set every 8 characters. Trailing spaces\n are removed. In addition, trailing carriage returns and line feeds are removed\n (they are usually a problem created by going to and from MSWindows). What are some reasons for removing tab characters from an input line?\n Some Fortran compilers have problems with tabs, as tabs are not\n part of the Fortran character set. Some editors and printers will\n have problems with tabs. It is often useful to expand tabs in input\n files to simplify further processing such as tokenizing an input line. OPTIONS instr Input line to remove tabs from RESULTS outstr Output string with tabs expanded. Assumed to be of sufficient\n length\n ilen Significant length of returned string EXAMPLES Sample program: program demo_notabs ! test filter to remove tabs and trailing white space from input ! on files up to 1024 characters wide use fpm_strings , only : notabs character ( len = 1024 ) :: in , out integer :: ios , iout do read ( * , ' (A) ' , iostat = ios ) in if ( ios /= 0 ) exit call notabs ( in , out , iout ) write ( * , ' (a) ' ) out ( : iout ) enddo end program demo_notabs SEE ALSO GNU/Unix commands expand(1) and unexpand(1) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr character(len=*), intent(out) :: outstr integer, intent(out) :: ilen Contents Source Code notabs Source Code elemental impure subroutine notabs ( instr , outstr , ilen ) ! ident_31=\"@(#)fpm_strings::notabs(3f): convert tabs to spaces while maintaining columns, remove CRLF chars\" character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len =* ), intent ( out ) :: outstr ! tab-expanded version of INSTR produced integer , intent ( out ) :: ilen ! column position of last character put into output string ! that is, ILEN holds the position of the last non-blank character in OUTSTR integer , parameter :: tabsize = 8 ! assume a tab stop is set every 8th column integer :: ipos ! position in OUTSTR to put next character of INSTR integer :: lenin ! length of input string trimmed of trailing spaces integer :: lenout ! number of characters output string can hold integer :: istep ! counter that advances thru input string INSTR one character at a time character ( len = 1 ) :: c ! character in input line being processed integer :: iade ! ADE (ASCII Decimal Equivalent) of character being tested ipos = 1 ! where to put next character in output string OUTSTR lenin = len_trim ( instr ( 1 : len ( instr ) )) ! length of INSTR trimmed of trailing spaces lenout = len ( outstr ) ! number of characters output string OUTSTR can hold outstr = \" \" ! this SHOULD blank-fill string, a buggy machine required a loop to set all characters SCAN_LINE : do istep = 1 , lenin ! look through input string one character at a time c = instr ( istep : istep ) ! get next character iade = ichar ( c ) ! get ADE of the character EXPAND_TABS : select case ( iade ) ! take different actions depending on which character was found case ( 9 ) ! test if character is a tab and move pointer out to appropriate column ipos = ipos + ( tabsize - ( mod ( ipos - 1 , tabsize ))) case ( 10 , 13 ) ! convert carriage-return and new-line to space ,typically to handle DOS-format files ipos = ipos + 1 case default ! c is anything else other than a tab,newline,or return insert it in output string if ( ipos > lenout ) then write ( stderr , * ) \"*notabs* output string overflow\" exit else outstr ( ipos : ipos ) = c ipos = ipos + 1 endif end select EXPAND_TABS enddo SCAN_LINE ipos = min ( ipos , lenout ) ! tabs or newline or return characters or last character might have gone too far ilen = len_trim ( outstr (: ipos )) ! trim trailing spaces end subroutine notabs","tags":"","loc":"proc/notabs.html"},{"title":"remove_characters_in_set – Fortran-lang/fpm","text":"public subroutine remove_characters_in_set(string, set, replace_with) Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: string character(len=*), intent(in) :: set character(len=1), intent(in), optional :: replace_with Contents Source Code remove_characters_in_set Source Code subroutine remove_characters_in_set ( string , set , replace_with ) character ( len = :), allocatable , intent ( inout ) :: string character ( * ), intent ( in ) :: set character , optional , intent ( in ) :: replace_with ! Replace with this character instead of removing integer :: feed , length if (. not . allocated ( string )) return if ( len ( set ) <= 0 ) return length = len ( string ) feed = scan ( string , set ) do while ( length > 0 . and . feed > 0 ) ! Remove heading if ( length == 1 ) then string = \"\" elseif ( feed == 1 ) then string = string ( 2 : length ) ! Remove trailing elseif ( feed == length ) then string = string ( 1 : length - 1 ) ! In between: replace with given character elseif ( present ( replace_with )) then string ( feed : feed ) = replace_with ! Or just remove else string = string ( 1 : feed - 1 ) // string ( feed + 1 : length ) end if length = len ( string ) feed = scan ( string , set ) end do end subroutine remove_characters_in_set","tags":"","loc":"proc/remove_characters_in_set.html"},{"title":"remove_newline_characters – Fortran-lang/fpm","text":"public subroutine remove_newline_characters(string) Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout) :: string Contents Source Code remove_newline_characters Source Code subroutine remove_newline_characters ( string ) type ( string_t ), intent ( inout ) :: string integer :: feed , length character ( * ), parameter :: CRLF = new_line ( 'a' ) // achar ( 13 ) character ( * ), parameter :: SPACE = ' ' call remove_characters_in_set ( string % s , set = CRLF , replace_with = SPACE ) end subroutine remove_newline_characters","tags":"","loc":"proc/remove_newline_characters.html"},{"title":"split – Fortran-lang/fpm","text":"public subroutine split(input_line, array, delimiters, order, nulls) parse string on delimiter characters and store tokens into an allocatable array\n given a line of structure ” par1 par2 par3 … parn ” store each par(n) into a separate variable in array. by default adjacent delimiters in the input string do not create an empty string in the output array no quoting of delimiters is supported Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input_line input string to tokenize character(len=:), intent(out), allocatable :: array (:) output array of tokens character(len=*), intent(in), optional :: delimiters list of delimiter characters character(len=*), intent(in), optional :: order order of output array sequential|[reverse|right] character(len=*), intent(in), optional :: nulls return strings composed of delimiters or not ignore|return|ignoreend Contents Source Code split Source Code subroutine split ( input_line , array , delimiters , order , nulls ) !! given a line of structure \" par1 par2 par3 ... parn \" store each par(n) into a separate variable in array. !! !! * by default adjacent delimiters in the input string do not create an empty string in the output array !! * no quoting of delimiters is supported character ( len =* ), intent ( in ) :: input_line !! input string to tokenize character ( len =* ), optional , intent ( in ) :: delimiters !! list of delimiter characters character ( len =* ), optional , intent ( in ) :: order !! order of output array sequential|[reverse|right] character ( len =* ), optional , intent ( in ) :: nulls !! return strings composed of delimiters or not ignore|return|ignoreend character ( len = :), allocatable , intent ( out ) :: array (:) !! output array of tokens integer :: n ! max number of strings INPUT_LINE could split into if all delimiter integer , allocatable :: ibegin (:) ! positions in input string where tokens start integer , allocatable :: iterm (:) ! positions in input string where tokens end character ( len = :), allocatable :: dlim ! string containing delimiter characters character ( len = :), allocatable :: ordr ! string containing order keyword character ( len = :), allocatable :: nlls ! string containing nulls keyword integer :: ii , iiii ! loop parameters used to control print order integer :: icount ! number of tokens found integer :: ilen ! length of input string with trailing spaces trimmed integer :: i10 , i20 , i30 ! loop counters integer :: icol ! pointer into input string as it is being parsed integer :: idlim ! number of delimiter characters integer :: ifound ! where next delimiter character is found in remaining input string data integer :: inotnull ! count strings not composed of delimiters integer :: ireturn ! number of tokens returned integer :: imax ! length of longest token ! decide on value for optional DELIMITERS parameter if ( present ( delimiters )) then ! optional delimiter list was present if ( delimiters /= '' ) then ! if DELIMITERS was specified and not null use it dlim = delimiters else ! DELIMITERS was specified on call as empty string dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif else ! no delimiter value was specified dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif idlim = len ( dlim ) ! dlim a lot of blanks on some machines if dlim is a big string if ( present ( order )) then ; ordr = lower ( adjustl ( order )); else ; ordr = 'sequential' ; endif ! decide on value for optional ORDER parameter if ( present ( nulls )) then ; nlls = lower ( adjustl ( nulls )); else ; nlls = 'ignore' ; endif ! optional parameter n = len ( input_line ) + 1 ! max number of strings INPUT_LINE could split into if all delimiter allocate ( ibegin ( n )) ! allocate enough space to hold starting location of tokens if string all tokens allocate ( iterm ( n )) ! allocate enough space to hold ending location of tokens if string all tokens ibegin (:) = 1 iterm (:) = 1 ilen = len ( input_line ) ! ILEN is the column position of the last non-blank character icount = 0 ! how many tokens found inotnull = 0 ! how many tokens found not composed of delimiters imax = 0 ! length of longest token found select case ( ilen ) case ( 0 ) ! command was totally blank case default ! there is at least one non-delimiter in INPUT_LINE if get here icol = 1 ! initialize pointer into input line INFINITE : do i30 = 1 , ilen , 1 ! store into each array element ibegin ( i30 ) = icol ! assume start new token on the character if ( index ( dlim ( 1 : idlim ), input_line ( icol : icol )) == 0 ) then ! if current character is not a delimiter iterm ( i30 ) = ilen ! initially assume no more tokens do i10 = 1 , idlim ! search for next delimiter ifound = index ( input_line ( ibegin ( i30 ): ilen ), dlim ( i10 : i10 )) IF ( ifound > 0 ) then iterm ( i30 ) = min ( iterm ( i30 ), ifound + ibegin ( i30 ) - 2 ) endif enddo icol = iterm ( i30 ) + 2 ! next place to look as found end of this token inotnull = inotnull + 1 ! increment count of number of tokens not composed of delimiters else ! character is a delimiter for a null string iterm ( i30 ) = icol - 1 ! record assumed end of string. Will be less than beginning icol = icol + 1 ! advance pointer into input string endif imax = max ( imax , iterm ( i30 ) - ibegin ( i30 ) + 1 ) icount = i30 ! increment count of number of tokens found if ( icol > ilen ) then ! no text left exit INFINITE endif enddo INFINITE end select select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) ireturn = inotnull case default ireturn = icount end select allocate ( character ( len = imax ) :: array ( ireturn )) ! allocate the array to return !allocate(array(ireturn)) ! allocate the array to turn select case ( trim ( adjustl ( ordr ))) ! decide which order to store tokens case ( 'reverse' , 'right' ) ; ii = ireturn ; iiii =- 1 ! last to first case default ; ii = 1 ; iiii = 1 ! first to last end select do i20 = 1 , icount ! fill the array with the tokens that were found if ( iterm ( i20 ) < ibegin ( i20 )) then select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) case default array ( ii ) = ' ' ii = ii + iiii end select else array ( ii ) = input_line ( ibegin ( i20 ): iterm ( i20 )) ii = ii + iiii endif enddo end subroutine split","tags":"","loc":"proc/split.html"},{"title":"fnv_1a – Fortran-lang/fpm","text":"public interface fnv_1a Contents Module Procedures fnv_1a_char fnv_1a_string_t Module Procedures private pure function fnv_1a_char(input, seed) result(hash) Hash a character(*) string of default kind Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64) private pure function fnv_1a_string_t(input, seed) result(hash) Hash a string_t array of default kind Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: input (:) integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64)","tags":"","loc":"interface/fnv_1a.html"},{"title":"len_trim – Fortran-lang/fpm","text":"public interface len_trim Contents Module Procedures string_len_trim strings_len_trim Module Procedures private elemental function string_len_trim(string) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: string Return Value integer private pure function strings_len_trim(strings) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) Return Value integer","tags":"","loc":"interface/len_trim.html"},{"title":"operator(.in.) – Fortran-lang/fpm","text":"public interface operator(.in.) Contents Module Procedures string_array_contains Module Procedures public function string_array_contains (search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical","tags":"","loc":"interface/operator(.in.).html"},{"title":"resize – Fortran-lang/fpm","text":"public interface resize Contents Module Procedures resize_string Module Procedures private subroutine resize_string(list, n) increase the size of a TYPE(STRING_T) array by N elements Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout), allocatable :: list (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size","tags":"","loc":"interface/resize~2.html"},{"title":"str – Fortran-lang/fpm","text":"public interface str Contents Module Procedures str_int str_int64 str_logical Module Procedures private pure function str_int(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer, intent(in) :: i Return Value character(len=str_int_len) private pure function str_int64(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer(kind=int64), intent(in) :: i Return Value character(len=str_int64_len) private pure function str_logical(l) result(s) Converts logical “l” to string Arguments Type Intent Optional Attributes Name logical, intent(in) :: l Return Value character(len=str_logical_len)","tags":"","loc":"interface/str.html"},{"title":"str_ends_with – Fortran-lang/fpm","text":"public interface str_ends_with Contents Module Procedures str_ends_with_str str_ends_with_any Module Procedures private pure function str_ends_with_str(s, e) result(r) test if a CHARACTER string ends with a specified suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e Return Value logical private pure function str_ends_with_any(s, e) result(r) test if a CHARACTER string ends with any of an array of suffixs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e (:) Return Value logical","tags":"","loc":"interface/str_ends_with.html"},{"title":"string_t – Fortran-lang/fpm","text":"public interface string_t Contents Module Procedures new_string_t Module Procedures private function new_string_t(s) result(string) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s Return Value type( string_t )","tags":"","loc":"interface/string_t.html"},{"title":"basename – Fortran-lang/fpm","text":"public function basename(path, suffix) result(base) Extract filename from path with/without suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: suffix Return Value character(len=:), allocatable Contents Source Code basename Source Code function basename ( path , suffix ) result ( base ) character ( * ), intent ( In ) :: path logical , intent ( in ), optional :: suffix character (:), allocatable :: base character (:), allocatable :: file_parts (:) logical :: with_suffix if (. not . present ( suffix )) then with_suffix = . true . else with_suffix = suffix end if call split ( path , file_parts , delimiters = '\\/' ) if ( size ( file_parts ) > 0 ) then base = trim ( file_parts ( size ( file_parts ))) else base = '' endif if (. not . with_suffix ) then call split ( base , file_parts , delimiters = '.' ) if ( size ( file_parts ) >= 2 ) then base = trim ( file_parts ( size ( file_parts ) - 1 )) endif endif end function basename","tags":"","loc":"proc/basename.html"},{"title":"canon_path – Fortran-lang/fpm","text":"public function canon_path(path) Canonicalize path for comparison\n* Handles path string redundancies\n* Does not test existence of path To be replaced by realpath/_fullname in stdlib_os FIXME: Lot’s of ugly hacks following here Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code canon_path Source Code function canon_path ( path ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: canon_path character ( len = :), allocatable :: nixpath integer :: istart , iend , nn , last logical :: is_path , absolute nixpath = unix_path ( path ) istart = 0 nn = 0 iend = 0 absolute = nixpath ( 1 : 1 ) == \"/\" if ( absolute ) then canon_path = \"/\" else canon_path = \"\" end if do while ( iend < len ( nixpath )) call next ( nixpath , istart , iend , is_path ) if ( is_path ) then select case ( nixpath ( istart : iend )) case ( \".\" , \"\" ) ! always drop empty paths case ( \"..\" ) if ( nn > 0 ) then last = scan ( canon_path (: len ( canon_path ) - 1 ), \"/\" , back = . true .) canon_path = canon_path (: last ) nn = nn - 1 else if (. not . absolute ) then canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end if end if case default nn = nn + 1 canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end select end if end do if ( len ( canon_path ) == 0 ) canon_path = \".\" if ( len ( canon_path ) > 1 . and . canon_path ( len ( canon_path ):) == \"/\" ) then canon_path = canon_path (: len ( canon_path ) - 1 ) end if contains subroutine next ( string , istart , iend , is_path ) character ( len =* ), intent ( in ) :: string integer , intent ( inout ) :: istart integer , intent ( inout ) :: iend logical , intent ( inout ) :: is_path integer :: ii , nn character :: tok nn = len ( string ) if ( iend >= nn ) then istart = nn iend = nn return end if ii = min ( iend + 1 , nn ) tok = string ( ii : ii ) is_path = tok /= '/' if (. not . is_path ) then is_path = . false . istart = ii iend = ii return end if istart = ii do ii = min ( iend + 1 , nn ), nn tok = string ( ii : ii ) select case ( tok ) case ( '/' ) exit case default iend = ii cycle end select end do end subroutine next end function canon_path","tags":"","loc":"proc/canon_path.html"},{"title":"dirname – Fortran-lang/fpm","text":"public function dirname(path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code dirname Source Code function dirname ( path ) result ( dir ) character ( * ), intent ( in ) :: path character (:), allocatable :: dir dir = path ( 1 : scan ( path , ' / \\' , back = . true .)) end function dirname","tags":"","loc":"proc/dirname.html"},{"title":"exists – Fortran-lang/fpm","text":"public function exists(filename) result(r) test if pathname already exists Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value logical Contents","tags":"","loc":"proc/exists.html"},{"title":"get_dos_path – Fortran-lang/fpm","text":"public function get_dos_path(path, error) Ensure a windows path is converted to an 8.3 DOS path if it contains spaces\nNo need to convert if there are no spaces Read screen output Ensure there are no trailing slashes Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error Return Value character(len=:), allocatable Contents Source Code get_dos_path Source Code function get_dos_path ( path , error ) character ( len =* ), intent ( in ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: get_dos_path character (:), allocatable :: redirect , screen_output , line integer :: stat , cmdstat , iunit , last ! Non-Windows OS if ( get_os_type () /= OS_WINDOWS ) then get_dos_path = path return end if ! Trim path first get_dos_path = trim ( path ) !> No need to convert if there are no spaces has_spaces : if ( scan ( get_dos_path , ' ' ) > 0 ) then redirect = get_temp_filename () call execute_command_line ( 'cmd /c for %A in (\"' // path // '\") do @echo %~sA >' // redirect // ' 2>&1' ,& exitstat = stat , cmdstat = cmdstat ) !> Read screen output command_OK : if ( cmdstat == 0 . and . stat == 0 ) then allocate ( character ( len = 0 ) :: screen_output ) open ( newunit = iunit , file = redirect , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output = screen_output // line // ' ' end do ! Close and delete file close ( iunit , status = 'delete' ) else call fatal_error ( error , 'cannot read temporary file from successful DOS path evaluation' ) return endif else command_OK call fatal_error ( error , 'unsuccessful Windows->DOS path command' ) return end if command_OK get_dos_path = trim ( adjustl ( screen_output )) endif has_spaces !> Ensure there are no trailing slashes last = len_trim ( get_dos_path ) if ( last > 1 . and . get_dos_path ( last : last ) == '/' . or . get_dos_path ( last : last ) == '\\' ) get_dos_path = get_dos_path ( 1 : last - 1 ) end function get_dos_path","tags":"","loc":"proc/get_dos_path.html"},{"title":"get_local_prefix – Fortran-lang/fpm","text":"public function get_local_prefix(os) result(prefix) Determine the path prefix to the local folder. Used for installation, registry etc. Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Platform identifier Return Value character(len=:), allocatable Installation prefix Contents Source Code get_local_prefix Source Code function get_local_prefix ( os ) result ( prefix ) !> Installation prefix character ( len = :), allocatable :: prefix !> Platform identifier integer , intent ( in ), optional :: os !> Default installation prefix on Unix platforms character ( len =* ), parameter :: default_prefix_unix = \"/usr/local\" !> Default installation prefix on Windows platforms character ( len =* ), parameter :: default_prefix_win = \"C:\\\" character(len=:), allocatable :: home if (os_is_unix(os)) then home=get_env('HOME','') if (home /= '' ) then prefix = join_path(home, \" . local \") else prefix = default_prefix_unix end if else home=get_env('APPDATA','') if (home /= '' ) then prefix = join_path(home, \" local \" ) else prefix = default_prefix_win end if end if end function get_local_prefix","tags":"","loc":"proc/get_local_prefix.html"},{"title":"get_temp_filename – Fortran-lang/fpm","text":"public function get_temp_filename() result(tempfile) Uses iso_c_binding Get a unused temporary filename\n Calls posix ‘tempnam’ - not recommended, but\n we have no security concerns for this application\n and use here is temporary.\nWorks with MinGW Arguments None Return Value character(len=:), allocatable Contents Source Code get_temp_filename Source Code function get_temp_filename () result ( tempfile ) ! use iso_c_binding , only : c_ptr , C_NULL_PTR , c_f_pointer integer , parameter :: MAX_FILENAME_LENGTH = 32768 character (:), allocatable :: tempfile type ( c_ptr ) :: c_tempfile_ptr character ( len = 1 ), pointer :: c_tempfile (:) interface function c_tempnam ( dir , pfx ) result ( tmp ) bind ( c , name = \"tempnam\" ) import type ( c_ptr ), intent ( in ), value :: dir type ( c_ptr ), intent ( in ), value :: pfx type ( c_ptr ) :: tmp end function c_tempnam subroutine c_free ( ptr ) BIND ( C , name = \"free\" ) import type ( c_ptr ), value :: ptr end subroutine c_free end interface c_tempfile_ptr = c_tempnam ( C_NULL_PTR , C_NULL_PTR ) call c_f_pointer ( c_tempfile_ptr , c_tempfile ,[ MAX_FILENAME_LENGTH ]) tempfile = f_string ( c_tempfile ) call c_free ( c_tempfile_ptr ) end function get_temp_filename","tags":"","loc":"proc/get_temp_filename.html"},{"title":"is_absolute_path – Fortran-lang/fpm","text":"public function is_absolute_path(path, is_unix) Returns .true. if provided path is absolute. ~ not treated as absolute. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: is_unix Return Value logical Contents Source Code is_absolute_path Source Code logical function is_absolute_path ( path , is_unix ) character ( len =* ), intent ( in ) :: path logical , optional , intent ( in ) :: is_unix character ( len =* ), parameter :: letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' logical :: is_unix_os if ( present ( is_unix )) then is_unix_os = is_unix else is_unix_os = os_is_unix () end if if ( is_unix_os ) then is_absolute_path = path ( 1 : 1 ) == '/' else if ( len ( path ) < 2 ) then is_absolute_path = . false . return end if is_absolute_path = index ( letters , path ( 1 : 1 )) /= 0 . and . path ( 2 : 2 ) == ':' end if end function is_absolute_path","tags":"","loc":"proc/is_absolute_path.html"},{"title":"is_dir – Fortran-lang/fpm","text":"public function is_dir(dir) test if a name matches an existing directory path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical Contents Source Code is_dir Source Code logical function is_dir ( dir ) character ( * ), intent ( in ) :: dir integer :: stat select case ( get_os_type ()) case ( OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD ) call run ( \"test -d \" // dir , & & exitstat = stat , echo = . false ., verbose = . false .) case ( OS_WINDOWS ) call run ( 'cmd /c \"if not exist ' // windows_path ( dir ) // '\\ exit /B 1\"' , & & exitstat = stat , echo = . false ., verbose = . false .) end select is_dir = ( stat == 0 ) end function is_dir","tags":"","loc":"proc/is_dir.html"},{"title":"is_hidden_file – Fortran-lang/fpm","text":"public function is_hidden_file(file_basename) result(r) test if a file is hidden Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file_basename Return Value logical Contents Source Code is_hidden_file Source Code logical function is_hidden_file ( file_basename ) result ( r ) character ( * ), intent ( in ) :: file_basename if ( len ( file_basename ) <= 2 ) then r = . false . else r = str_begins_with_str ( file_basename , '.' ) end if end function is_hidden_file","tags":"","loc":"proc/is_hidden_file.html"},{"title":"join_path – Fortran-lang/fpm","text":"public function join_path(a1, a2, a3, a4, a5) result(path) Construct path by joining strings with os file separator Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: a1 character(len=*), intent(in) :: a2 character(len=*), intent(in), optional :: a3 character(len=*), intent(in), optional :: a4 character(len=*), intent(in), optional :: a5 Return Value character(len=:), allocatable Contents Source Code join_path Source Code function join_path ( a1 , a2 , a3 , a4 , a5 ) result ( path ) character ( len =* ), intent ( in ) :: a1 , a2 character ( len =* ), intent ( in ), optional :: a3 , a4 , a5 character ( len = :), allocatable :: path character ( len = 1 ) :: filesep logical , save :: has_cache = . false . character ( len = 1 ), save :: cache = '/' !$omp threadprivate(has_cache, cache) if ( has_cache ) then filesep = cache else select case ( get_os_type ()) case default filesep = '/' case ( OS_WINDOWS ) filesep = '\\' end select cache = filesep has_cache = . true . end if if ( a1 == \"\" ) then path = a2 else path = a1 // filesep // a2 end if if ( present ( a3 )) then path = path // filesep // a3 else return end if if ( present ( a4 )) then path = path // filesep // a4 else return end if if ( present ( a5 )) then path = path // filesep // a5 else return end if end function join_path","tags":"","loc":"proc/join_path.html"},{"title":"number_of_rows – Fortran-lang/fpm","text":"public function number_of_rows(s) result(nrows) Determine number or rows in a file given a LUN Arguments Type Intent Optional Attributes Name integer, intent(in) :: s Return Value integer Contents Source Code number_of_rows Source Code integer function number_of_rows ( s ) result ( nrows ) integer , intent ( in ) :: s integer :: ios rewind ( s ) nrows = 0 do read ( s , * , iostat = ios ) if ( ios /= 0 ) exit nrows = nrows + 1 end do rewind ( s ) end function number_of_rows","tags":"","loc":"proc/number_of_rows.html"},{"title":"parent_dir – Fortran-lang/fpm","text":"public function parent_dir(path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code parent_dir Source Code function parent_dir ( path ) result ( dir ) character ( * ), intent ( in ) :: path character (:), allocatable :: dir dir = path ( 1 : scan ( path , ' / \\' , back = . true .) - 1 ) end function parent_dir","tags":"","loc":"proc/parent_dir.html"},{"title":"read_lines – Fortran-lang/fpm","text":"public function read_lines(fh) result(lines) read lines into an array of TYPE(STRING_T) variables Arguments Type Intent Optional Attributes Name integer, intent(in) :: fh Return Value type( string_t ), allocatable, (:) Contents Source Code read_lines Source Code function read_lines ( fh ) result ( lines ) integer , intent ( in ) :: fh type ( string_t ), allocatable :: lines (:) integer :: i integer :: iostat allocate ( lines ( number_of_rows ( fh ))) do i = 1 , size ( lines ) call getline ( fh , lines ( i )% s , iostat ) end do end function read_lines","tags":"","loc":"proc/read_lines.html"},{"title":"read_lines_expanded – Fortran-lang/fpm","text":"public function read_lines_expanded(fh) result(lines) read lines into an array of TYPE(STRING_T) variables expanding tabs Arguments Type Intent Optional Attributes Name integer, intent(in) :: fh Return Value type( string_t ), allocatable, (:) Contents Source Code read_lines_expanded Source Code function read_lines_expanded ( fh ) result ( lines ) integer , intent ( in ) :: fh type ( string_t ), allocatable :: lines (:) integer :: i integer :: iostat character ( len = :), allocatable :: line_buffer_read allocate ( lines ( number_of_rows ( fh ))) do i = 1 , size ( lines ) call getline ( fh , line_buffer_read , iostat ) lines ( i )% s = dilate ( line_buffer_read ) end do end function read_lines_expanded","tags":"","loc":"proc/read_lines_expanded.html"},{"title":"unix_path – Fortran-lang/fpm","text":"public function unix_path(path) result(nixpath) Replace file system separators for 1 Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code unix_path Source Code function unix_path ( path ) result ( nixpath ) character ( * ), intent ( in ) :: path character (:), allocatable :: nixpath integer :: idx nixpath = path idx = index ( nixpath , '\\') do while(idx > 0) nixpath(idx:idx) = ' / ' idx = index(nixpath,' \\' ) end do end function unix_path","tags":"","loc":"proc/unix_path.html"},{"title":"which – Fortran-lang/fpm","text":"public function which(command) result(pathname) Name which ( 3 f ) - [ M_io : ENVIRONMENT ] given a command name find the pathname by searching the directories in the environment variable $ PATH ( LICENSE : PD ) Syntax function which(command) result(pathname) character(len=*),intent(in) :: command\ncharacter(len=:),allocatable :: pathname Description Given a command name find the first file with that name in the directories specified by the environment variable $ PATH . options COMMAND the command to search for Returns PATHNAME the first pathname found in the current user path . Returns blank if the command is not found . Example Sample program: Checking the error message and counting lines: program demo_which use M_io , only : which implicit none write ( * , * ) ' ls is ' , which ( ' ls ' ) write ( * , * ) ' dir is ' , which ( ' dir ' ) write ( * , * ) ' install is ' , which ( ' install ' ) end program demo_which Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: command Return Value character(len=:), allocatable Contents Source Code which Source Code function which ( command ) result ( pathname ) character ( len =* ), intent ( in ) :: command character ( len = :), allocatable :: pathname , checkon , paths (:), exts (:) integer :: i , j pathname = '' call split ( get_env ( 'PATH' ), paths , delimiters = merge ( ';' , ':' , separator () == '\\')) SEARCH: do i=1,size(paths) checkon=trim(join_path(trim(paths(i)),command)) select case(separator()) case(' / ') if(exists(checkon))then pathname=checkon exit SEARCH endif case(' \\ ') if(exists(checkon))then pathname=checkon exit SEARCH endif if(exists(checkon//' . bat '))then pathname=checkon//' . bat ' exit SEARCH endif if(exists(checkon//' . exe '))then pathname=checkon//' . exe ' exit SEARCH endif call split(get_env(' PATHEXT '),exts,delimiters=' ; ') do j=1,size(exts) if(exists(checkon//' . '//trim(exts(j))))then pathname=checkon//' . ' // trim ( exts ( j )) exit SEARCH endif enddo end select enddo SEARCH end function which","tags":"","loc":"proc/which.html"},{"title":"windows_path – Fortran-lang/fpm","text":"public function windows_path(path) result(winpath) Replace file system separators for windows Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Contents Source Code windows_path Source Code function windows_path ( path ) result ( winpath ) character ( * ), intent ( in ) :: path character (:), allocatable :: winpath integer :: idx winpath = path idx = index ( winpath , '/' ) do while ( idx > 0 ) winpath ( idx : idx ) = '\\' idx = index(winpath,' / ' ) end do end function windows_path","tags":"","loc":"proc/windows_path.html"},{"title":"delete_file – Fortran-lang/fpm","text":"public subroutine delete_file(file) delete a file by filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file Contents Source Code delete_file Source Code subroutine delete_file ( file ) character ( len =* ), intent ( in ) :: file logical :: exist integer :: unit inquire ( file = file , exist = exist ) if ( exist ) then open ( file = file , newunit = unit ) close ( unit , status = \"delete\" ) end if end subroutine delete_file","tags":"","loc":"proc/delete_file.html"},{"title":"execute_and_read_output – Fortran-lang/fpm","text":"public subroutine execute_and_read_output(cmd, output, error, verbose) Execute command line and return output as a string. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd Command to execute. character(len=:), intent(out), allocatable :: output Command line output. type( error_t ), intent(out), allocatable :: error Error to handle. logical, intent(in), optional :: verbose Print additional information if true. Contents","tags":"","loc":"proc/execute_and_read_output.html"},{"title":"fileclose – Fortran-lang/fpm","text":"public subroutine fileclose(lun, ier) simple close of a LUN. On error show message and stop (by default) Arguments Type Intent Optional Attributes Name integer, intent(in) :: lun integer, intent(out), optional :: ier Contents Source Code fileclose Source Code subroutine fileclose ( lun , ier ) integer , intent ( in ) :: lun integer , intent ( out ), optional :: ier character ( len = 256 ) :: message integer :: ios if ( lun /=- 1 ) then close ( unit = lun , iostat = ios , iomsg = message ) if ( ios /= 0 ) then if ( present ( ier )) then ier = ios else call fpm_stop ( 4 , '*fileclose*:' // trim ( message )) endif endif endif end subroutine fileclose","tags":"","loc":"proc/fileclose.html"},{"title":"fileopen – Fortran-lang/fpm","text":"public subroutine fileopen(filename, lun, ier) procedure to open filename as a sequential “text” file Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename integer, intent(out) :: lun integer, intent(out), optional :: ier Contents Source Code fileopen Source Code subroutine fileopen ( filename , lun , ier ) character ( len =* ), intent ( in ) :: filename integer , intent ( out ) :: lun integer , intent ( out ), optional :: ier integer :: ios character ( len = 256 ) :: message message = ' ' ios = 0 if ( filename /= ' ' ) then open ( file = filename , & & newunit = lun , & & form = 'formatted' , & ! FORM = FORMATTED | UNFORMATTED & access = 'sequential' , & ! ACCESS = SEQUENTIAL| DIRECT | STREAM & action = 'write' , & ! ACTION = READ|WRITE| READWRITE & position = 'rewind' , & ! POSITION= ASIS | REWIND | APPEND & status = 'new' , & ! STATUS = NEW| REPLACE| OLD| SCRATCH| UNKNOWN & iostat = ios , & & iomsg = message ) else lun = stdout ios = 0 endif if ( ios /= 0 ) then lun =- 1 if ( present ( ier )) then ier = ios else call fpm_stop ( 3 , '*fileopen*:' // filename // ':' // trim ( message )) endif endif end subroutine fileopen","tags":"","loc":"proc/fileopen.html"},{"title":"filewrite – Fortran-lang/fpm","text":"public subroutine filewrite(filename, filedata) procedure to write filedata to file filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename character(len=*), intent(in) :: filedata (:) Contents Source Code filewrite Source Code subroutine filewrite ( filename , filedata ) character ( len =* ), intent ( in ) :: filename character ( len =* ), intent ( in ) :: filedata (:) integer :: lun , i , ios character ( len = 256 ) :: message call fileopen ( filename , lun ) if ( lun /=- 1 ) then ! program currently stops on error on open, but might ! want it to continue so -1 (unallowed LUN) indicates error ! write file do i = 1 , size ( filedata ) write ( lun , '(a)' , iostat = ios , iomsg = message ) trim ( filedata ( i )) if ( ios /= 0 ) then call fpm_stop ( 5 , '*filewrite*:' // filename // ':' // trim ( message )) endif enddo endif ! close file call fileclose ( lun ) end subroutine filewrite","tags":"","loc":"proc/filewrite.html"},{"title":"get_home – Fortran-lang/fpm","text":"public subroutine get_home(home, error) Get the HOME directory on Unix and the %USERPROFILE% directory on Windows. Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: home type( error_t ), intent(out), allocatable :: error Contents Source Code get_home Source Code subroutine get_home ( home , error ) character ( len = :), allocatable , intent ( out ) :: home type ( error_t ), allocatable , intent ( out ) :: error if ( os_is_unix ()) then home = get_env ( 'HOME' , '' ) if ( home == '' ) then call fatal_error ( error , \"Couldn't retrieve 'HOME' variable\" ) return end if else home = get_env ( 'USERPROFILE' , '' ) if ( home == '' ) then call fatal_error ( error , \"Couldn't retrieve '%USERPROFILE%' variable\" ) return end if end if end subroutine get_home","tags":"","loc":"proc/get_home.html"},{"title":"getline – Fortran-lang/fpm","text":"public subroutine getline(unit, line, iostat, iomsg) NAME getline(3f) - [M_io:READ] read a line of arbintrary length from specified\n LUN into allocatable string (up to system line length limit)\n(LICENSE:PD) SYNTAX subroutine getline(unit,line,iostat,iomsg) integer,intent(in) :: unit\ncharacter(len=:),allocatable,intent(out) :: line\ninteger,intent(out) :: iostat\ncharacter(len=:), allocatable, optional :: iomsg DESCRIPTION Read a line of any length up to programming environment maximum line length . Requires Fortran 2003 +. It is primarily expected to be used when reading input which will then be parsed or echoed . The input file must have a PAD attribute of YES for the function to work properly , which is typically true . The simple use of a loop that repeatedly re - allocates a character variable in addition to reading the input file one buffer at a time could ( depending on the programming environment used ) be inefficient , as it could reallocate and allocate memory used for the output string with each buffer read . OPTIONS LINE The line read when IOSTAT returns as zero . LUN LUN ( Fortran logical I / O unit ) number of file open and ready to read . IOSTAT status returned by READ ( IOSTAT = IOS ) . If not zero , an error occurred or an end - of - file or end - of - record was encountered . IOMSG error message returned by system when IOSTAT is not zero . EXAMPLE Sample program: program demo_getline use , intrinsic :: iso_fortran_env , only : stdin => input_unit use , intrinsic :: iso_fortran_env , only : iostat_end use FPM_filesystem , only : getline implicit none integer :: iostat character ( len = : ) , allocatable :: line , iomsg open ( unit = stdin , pad = ' yes ' ) INFINITE : do call getline ( stdin , line , iostat , iomsg ) if ( iostat /= 0 ) exit INFINITE write ( * , ' (a) ' ) ' [ ' // line // ' ] ' enddo INFINITE if ( iostat /= iostat_end ) then write ( * , * ) ' error reading input: ' , iomsg endif end program demo_getline Arguments Type Intent Optional Attributes Name integer, intent(in) :: unit Formatted IO unit character(len=:), intent(out), allocatable :: line Line to read integer, intent(out) :: iostat Status of operation character(len=:), optional, allocatable :: iomsg Error message Contents Source Code getline Source Code subroutine getline ( unit , line , iostat , iomsg ) !> Formatted IO unit integer , intent ( in ) :: unit !> Line to read character ( len = :), allocatable , intent ( out ) :: line !> Status of operation integer , intent ( out ) :: iostat !> Error message character ( len = :), allocatable , optional :: iomsg integer , parameter :: BUFFER_SIZE = 32768 character ( len = BUFFER_SIZE ) :: buffer character ( len = 256 ) :: msg integer :: size integer :: stat allocate ( character ( len = 0 ) :: line ) do read ( unit , '(a)' , advance = 'no' , iostat = stat , iomsg = msg , size = size ) & & buffer if ( stat > 0 ) exit line = line // buffer (: size ) if ( stat < 0 ) then if ( is_iostat_eor ( stat )) then stat = 0 end if exit end if end do if ( stat /= 0 ) then if ( present ( iomsg )) iomsg = trim ( msg ) end if iostat = stat end subroutine getline","tags":"","loc":"proc/getline.html"},{"title":"list_files – Fortran-lang/fpm","text":"public recursive subroutine list_files(dir, files, recurse) Get file & directory names in directory dir using iso_c_binding. File/directory names return are relative to cwd, ie. preprended with dir Includes files starting with . except current directory and parent directory Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir type( string_t ), intent(out), allocatable :: files (:) logical, intent(in), optional :: recurse Contents Source Code list_files Source Code recursive subroutine list_files ( dir , files , recurse ) character ( len =* ), intent ( in ) :: dir type ( string_t ), allocatable , intent ( out ) :: files (:) logical , intent ( in ), optional :: recurse integer :: i type ( string_t ), allocatable :: dir_files (:) type ( string_t ), allocatable :: sub_dir_files (:) type ( c_ptr ) :: dir_handle type ( c_ptr ) :: dir_entry_c character ( len = :, kind = c_char ), allocatable :: fortran_name character ( len = :), allocatable :: string_fortran integer , parameter :: N_MAX = 256 type ( string_t ) :: files_tmp ( N_MAX ) integer ( kind = c_int ) :: r if ( c_is_dir ( dir ( 1 : len_trim ( dir )) // c_null_char ) == 0 ) then allocate ( files ( 0 )) return end if dir_handle = c_opendir ( dir ( 1 : len_trim ( dir )) // c_null_char ) if (. not . c_associated ( dir_handle )) then print * , 'c_opendir() failed' error stop end if i = 0 allocate ( files ( 0 )) do dir_entry_c = c_readdir ( dir_handle ) if (. not . c_associated ( dir_entry_c )) then exit else string_fortran = f_string ( c_get_d_name ( dir_entry_c )) if (( string_fortran == '.' . or . string_fortran == '..' )) then cycle end if i = i + 1 if ( i > N_MAX ) then files = [ files , files_tmp ] i = 1 end if files_tmp ( i )% s = join_path ( dir , string_fortran ) end if end do r = c_closedir ( dir_handle ) if ( r /= 0 ) then print * , 'c_closedir() failed' error stop end if if ( i > 0 ) then files = [ files , files_tmp ( 1 : i )] end if if ( present ( recurse )) then if ( recurse ) then allocate ( sub_dir_files ( 0 )) do i = 1 , size ( files ) if ( c_is_dir ( files ( i )% s // c_null_char ) /= 0 ) then call list_files ( files ( i )% s , dir_files , recurse = . true .) sub_dir_files = [ sub_dir_files , dir_files ] end if end do files = [ files , sub_dir_files ] end if end if end subroutine list_files","tags":"","loc":"proc/list_files.html"},{"title":"mkdir – Fortran-lang/fpm","text":"public subroutine mkdir(dir, echo) Create a directory. Create subdirectories as needed Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir logical, intent(in), optional :: echo Contents Source Code mkdir Source Code subroutine mkdir ( dir , echo ) character ( len =* ), intent ( in ) :: dir logical , intent ( in ), optional :: echo integer :: stat if ( is_dir ( dir )) return select case ( get_os_type ()) case ( OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD ) call run ( 'mkdir -p ' // dir , exitstat = stat , echo = echo , verbose = . false .) case ( OS_WINDOWS ) call run ( \"mkdir \" // windows_path ( dir ), & & echo = echo , exitstat = stat , verbose = . false .) end select if ( stat /= 0 ) then call fpm_stop ( 1 , '*mkdir*:directory creation failed' ) end if end subroutine mkdir","tags":"","loc":"proc/mkdir.html"},{"title":"os_delete_dir – Fortran-lang/fpm","text":"public subroutine os_delete_dir(is_unix, dir, echo) Delete directory using system OS remove directory commands Arguments Type Intent Optional Attributes Name logical, intent(in) :: is_unix character(len=*), intent(in) :: dir logical, intent(in), optional :: echo Contents Source Code os_delete_dir Source Code subroutine os_delete_dir ( is_unix , dir , echo ) logical , intent ( in ) :: is_unix character ( len =* ), intent ( in ) :: dir logical , intent ( in ), optional :: echo if ( is_unix ) then call run ( 'rm -rf ' // dir , echo = echo , verbose = . false .) else call run ( 'rmdir /s/q ' // dir , echo = echo , verbose = . false .) end if end subroutine os_delete_dir","tags":"","loc":"proc/os_delete_dir.html"},{"title":"run – Fortran-lang/fpm","text":"public subroutine run(cmd, echo, exitstat, verbose, redirect) Name run(3f) - execute specified system command and selectively echo\ncommand and output to a file and/or stdout.\n(LICENSE:MIT) Syntax subroutine run(cmd,echo,exitstat,verbose,redirect)\n\n character(len=*), intent(in) :: cmd\n logical,intent(in),optional :: echo\n integer, intent(out),optional :: exitstat\n logical, intent(in), optional :: verbose\n character(*), intent(in), optional :: redirect Description Execute the specified system command. Optionally echo the command before execution return the system exit status of the command. redirect the output of the command to a file. echo command output to stdout Calling run(3f) is preferred to direct calls to\n execute_command_line(3f) in the fpm(1) source to provide a standard\n interface where output modes can be specified. Options CMD System command to execute ECHO Whether to echo the command being executed or not Defaults to . TRUE . . VERBOSE Whether to redirect the command output to a null device or not Defaults to . TRUE . . REDIRECT Filename to redirect stdout and stderr of the command into . If generated it is closed before run ( 3 f ) returns . EXITSTAT The system exit status of the command when supported by the system . If not present and a non - zero status is generated program termination occurs . Example Sample program: Checking the error message and counting lines: program demo_run use fpm_filesystem , only : run implicit none logical , parameter :: T = . true ., F = . false . integer :: exitstat character ( len = : ) , allocatable :: cmd cmd = ' ls -ltrasd *.md ' call run ( cmd ) call run ( cmd , exitstat = exitstat ) call run ( cmd , echo = F ) call run ( cmd , verbose = F ) end program demo_run Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd logical, intent(in), optional :: echo integer, intent(out), optional :: exitstat logical, intent(in), optional :: verbose character(len=*), intent(in), optional :: redirect Contents Source Code run Source Code subroutine run ( cmd , echo , exitstat , verbose , redirect ) character ( len =* ), intent ( in ) :: cmd logical , intent ( in ), optional :: echo integer , intent ( out ), optional :: exitstat logical , intent ( in ), optional :: verbose character ( * ), intent ( in ), optional :: redirect integer :: cmdstat character ( len = 256 ) :: cmdmsg , iomsg logical :: echo_local , verbose_local character (:), allocatable :: redirect_str character (:), allocatable :: line integer :: stat , fh , iostat if ( present ( echo )) then echo_local = echo else echo_local = . true . end if if ( present ( verbose )) then verbose_local = verbose else verbose_local = . true . end if if ( present ( redirect )) then if ( redirect /= '' ) then redirect_str = \">\" // redirect // \" 2>&1\" endif else if ( verbose_local ) then ! No redirection but verbose output redirect_str = \"\" else ! No redirection and non-verbose output if ( os_is_unix ()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if end if if ( echo_local ) print * , '+ ' , cmd !//redirect_str call execute_command_line ( cmd // redirect_str , exitstat = stat , cmdstat = cmdstat , cmdmsg = cmdmsg ) if ( cmdstat /= 0 ) then write ( * , '(a)' ) ':failed command ' // cmd // redirect_str call fpm_stop ( 1 , '*run*:' // trim ( cmdmsg )) endif if ( verbose_local . and . present ( redirect )) then open ( newunit = fh , file = redirect , status = 'old' , iostat = iostat , iomsg = iomsg ) if ( iostat == 0 ) then do call getline ( fh , line , iostat ) if ( iostat /= 0 ) exit write ( * , '(A)' ) trim ( line ) end do else write ( * , '(A)' ) trim ( iomsg ) endif close ( fh ) end if if ( present ( exitstat )) then exitstat = stat elseif ( stat /= 0 ) then call fpm_stop ( stat , '*run*: Command ' // cmd // redirect_str // ' returned a non-zero status code' ) end if end subroutine run","tags":"","loc":"proc/run.html"},{"title":"warnwrite – Fortran-lang/fpm","text":"public subroutine warnwrite(fname, data) write trimmed character data to a file if it does not exist Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: fname character(len=*), intent(in) :: data (:) Contents Source Code warnwrite Source Code subroutine warnwrite ( fname , data ) character ( len =* ), intent ( in ) :: fname character ( len =* ), intent ( in ) :: data (:) if (. not . exists ( fname )) then call filewrite ( fname , data ) else write ( stderr , '(*(g0,1x))' ) ' ' , fname ,& & 'already exists. Not overwriting' endif end subroutine warnwrite","tags":"","loc":"proc/warnwrite.html"},{"title":"get_command_arguments_quoted – Fortran-lang/fpm","text":"public function get_command_arguments_quoted() result(args) Arguments None Return Value character(len=:), allocatable Contents Source Code get_command_arguments_quoted Source Code function get_command_arguments_quoted () result ( args ) character ( len = :), allocatable :: args character ( len = :), allocatable :: arg character ( len = 1 ) :: quote integer :: ilength , istatus , i ilength = 0 args = '' quote = merge ( '\"' , \"'\" , separator () == '\\') do i=2,command_argument_count() ! look at all arguments after subcommand call get_command_argument(number=i,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit else if(allocated(arg))deallocate(arg) allocate(character(len=ilength) :: arg) call get_command_argument(number=i,value=arg,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit elseif(ilength>0)then if(index(arg//' ',' - ')/=1)then args=args//quote//arg//quote//' ' elseif(index(arg,' ')/=0)then args=args//quote//arg//quote//' ' else args=args//arg//' ' endif else args=args//repeat(quote,2)//' ' endif endif enddo end function get_command_arguments_quoted","tags":"","loc":"proc/get_command_arguments_quoted.html"},{"title":"get_env – Fortran-lang/fpm","text":"public function get_env(NAME, DEFAULT) result(VALUE) get named environment variable value. It it is blank or\n not set return the optional default value\n!print , NAME, ” is not defined in the environment. Strange…”\n!print , “This processor doesn’t support environment variables. Boooh!” Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: NAME name of environment variable to get the value of character(len=*), intent(in), optional :: DEFAULT default value to return if the requested value is undefined or blank Return Value character(len=:), allocatable the returned value Contents Source Code get_env Source Code function get_env ( NAME , DEFAULT ) result ( VALUE ) implicit none !> name of environment variable to get the value of character ( len =* ), intent ( in ) :: NAME !> default value to return if the requested value is undefined or blank character ( len =* ), intent ( in ), optional :: DEFAULT !> the returned value character ( len = :), allocatable :: VALUE integer :: howbig integer :: stat integer :: length ! get length required to hold value length = 0 if ( NAME /= '' ) then call get_environment_variable ( NAME , length = howbig , status = stat , trim_name = . true .) select case ( stat ) case ( 1 ) !*!print *, NAME, \" is not defined in the environment. Strange...\" VALUE = '' case ( 2 ) !*!print *, \"This processor doesn't support environment variables. Boooh!\" VALUE = '' case default ! make string to hold value of sufficient size allocate ( character ( len = max ( howbig , 1 )) :: VALUE ) ! get value call get_environment_variable ( NAME , VALUE , status = stat , trim_name = . true .) if ( stat /= 0 ) VALUE = '' end select else VALUE = '' endif if ( VALUE == '' . and . present ( DEFAULT )) VALUE = DEFAULT end function get_env","tags":"","loc":"proc/get_env.html"},{"title":"get_os_type – Fortran-lang/fpm","text":"public function get_os_type() result(r) Determine the OS type Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN,\nOS_SOLARIS, OS_FREEBSD, OS_OPENBSD. At first, the environment variable OS is checked, which is usually\nfound on Windows. Then, OSTYPE is read in and compared with common\nnames. If this fails too, check the existence of files that can be\nfound on specific system types only. Returns OS_UNKNOWN if the operating system cannot be determined. Arguments None Return Value integer Contents Source Code get_os_type Source Code integer function get_os_type () result ( r ) !! !! Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN, !! OS_SOLARIS, OS_FREEBSD, OS_OPENBSD. !! !! At first, the environment variable `OS` is checked, which is usually !! found on Windows. Then, `OSTYPE` is read in and compared with common !! names. If this fails too, check the existence of files that can be !! found on specific system types only. !! !! Returns OS_UNKNOWN if the operating system cannot be determined. character ( len = 32 ) :: val integer :: length , rc logical :: file_exists logical , save :: first_run = . true . integer , save :: ret = OS_UNKNOWN !$omp threadprivate(ret, first_run) if (. not . first_run ) then r = ret return end if first_run = . false . r = OS_UNKNOWN ! Check environment variable `OSTYPE`. call get_environment_variable ( 'OSTYPE' , val , length , rc ) if ( rc == 0 . and . length > 0 ) then ! Linux if ( index ( val , 'linux' ) > 0 ) then r = OS_LINUX ret = r return end if ! macOS if ( index ( val , 'darwin' ) > 0 ) then r = OS_MACOS ret = r return end if ! Windows, MSYS, MinGW, Git Bash if ( index ( val , 'win' ) > 0 . or . index ( val , 'msys' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Cygwin if ( index ( val , 'cygwin' ) > 0 ) then r = OS_CYGWIN ret = r return end if ! Solaris, OpenIndiana, ... if ( index ( val , 'SunOS' ) > 0 . or . index ( val , 'solaris' ) > 0 ) then r = OS_SOLARIS ret = r return end if ! FreeBSD if ( index ( val , 'FreeBSD' ) > 0 . or . index ( val , 'freebsd' ) > 0 ) then r = OS_FREEBSD ret = r return end if ! OpenBSD if ( index ( val , 'OpenBSD' ) > 0 . or . index ( val , 'openbsd' ) > 0 ) then r = OS_OPENBSD ret = r return end if end if ! Check environment variable `OS`. call get_environment_variable ( 'OS' , val , length , rc ) if ( rc == 0 . and . length > 0 . and . index ( val , 'Windows_NT' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Linux inquire ( file = '/etc/os-release' , exist = file_exists ) if ( file_exists ) then r = OS_LINUX ret = r return end if ! macOS inquire ( file = '/usr/bin/sw_vers' , exist = file_exists ) if ( file_exists ) then r = OS_MACOS ret = r return end if ! FreeBSD inquire ( file = '/bin/freebsd-version' , exist = file_exists ) if ( file_exists ) then r = OS_FREEBSD ret = r return end if end function get_os_type","tags":"","loc":"proc/get_os_type.html"},{"title":"os_is_unix – Fortran-lang/fpm","text":"public function os_is_unix(os) Compare the output of get_os_type or the optional\npassed INTEGER value to the value for OS_WINDOWS\nand return .TRUE. if they match and .FALSE. otherwise Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Return Value logical Contents Source Code os_is_unix Source Code logical function os_is_unix ( os ) integer , intent ( in ), optional :: os integer :: build_os if ( present ( os )) then build_os = os else build_os = get_os_type () end if os_is_unix = build_os /= OS_WINDOWS end function os_is_unix","tags":"","loc":"proc/os_is_unix.html"},{"title":"separator – Fortran-lang/fpm","text":"public function separator() result(sep) NAME separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character\n(LICENSE:PD) SYNOPSIS function separator() result ( sep ) character ( len = 1 ) :: sep DESCRIPTION First using the name the program was invoked with , then the name returned by an INQUIRE ( 3 f ) of that name , then \".\\NAME\" and \"./NAME\" try to determine the separator character used to separate directory names from file basenames . If a slash or backslash is not found in the name , the environment variable PATH is examined first for a backslash , then a slash . Can be very system dependent . If the queries fail the default returned is \"/\" . EXAMPLE sample usage program demo_separator use M_io , only : separator implicit none write ( * , * ) ' separator= ' , separator () end program demo_separator !write( , )’ unknown system directory path separator’\nifort_bug*!sep_cache=sep Arguments None Return Value character(len=1) ifort_bug*!character(len=1),save :: sep_cache=’ ‘ Contents Source Code separator Source Code function separator () result ( sep ) !> !!##NAME !! separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character !! (LICENSE:PD) !! !!##SYNOPSIS !! !! function separator() result(sep) !! !! character(len=1) :: sep !! !!##DESCRIPTION !! First using the name the program was invoked with, then the name !! returned by an INQUIRE(3f) of that name, then \".\\NAME\" and \"./NAME\" !! try to determine the separator character used to separate directory !! names from file basenames. !! !! If a slash or backslash is not found in the name, the environment !! variable PATH is examined first for a backslash, then a slash. !! !! Can be very system dependent. If the queries fail the default returned !! is \"/\". !! !!##EXAMPLE !! !! sample usage !! !! program demo_separator !! use M_io, only : separator !! implicit none !! write(*,*)'separator=',separator() !! end program demo_separator ! use the pathname returned as arg0 to determine pathname separator implicit none character ( len = :), allocatable :: arg0 integer :: arg0_length integer :: istat logical :: existing character ( len = 1 ) :: sep !*ifort_bug*!character(len=1),save :: sep_cache=' ' character ( len = 4096 ) :: name character ( len = :), allocatable :: fname !*ifort_bug*! if(sep_cache/=' ')then ! use cached value. NOTE: A parallel code might theoretically use multiple OS !*ifort_bug*! sep=sep_cache !*ifort_bug*! return !*ifort_bug*! endif arg0_length = 0 name = ' ' call get_command_argument ( 0 , length = arg0_length , status = istat ) if ( allocated ( arg0 )) deallocate ( arg0 ) allocate ( character ( len = arg0_length ) :: arg0 ) call get_command_argument ( 0 , arg0 , status = istat ) ! check argument name if ( index ( arg0 , '\\')/=0)then sep=' \\ ' elseif(index(arg0,' / ')/=0)then sep=' / ' else ! try name returned by INQUIRE(3f) existing=.false. name=' ' inquire(file=arg0,iostat=istat,exist=existing,name=name) if(index(name,' \\ ')/=0)then sep=' \\ ' elseif(index(name,' / ')/=0)then sep=' / ' else ! well, try some common syntax and assume in current directory fname=' . \\ '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' \\ ' else fname=' . / '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' / ' else ! check environment variable PATH sep=merge(' \\ ',' / ',index(get_env(' PATH '),' \\ ')/=0) !*!write(*,*)' < WARNING > unknown system directory path separator ' endif endif endif endif !*ifort_bug*!sep_cache=sep end function separator","tags":"","loc":"proc/separator.html"},{"title":"parse_c_source – Fortran-lang/fpm","text":"public function parse_c_source(c_filename, error) result(c_source) Parsing of c, cpp source files The following statements are recognised and parsed: #include preprocessor statement Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: c_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) Contents Source Code parse_c_source Source Code function parse_c_source ( c_filename , error ) result ( c_source ) character ( * ), intent ( in ) :: c_filename type ( srcfile_t ) :: c_source type ( error_t ), allocatable , intent ( out ) :: error integer :: fh , n_include , i , pass , stat type ( string_t ), allocatable :: file_lines (:) c_source % file_name = c_filename if ( str_ends_with ( lower ( c_filename ), \".c\" )) then c_source % unit_type = FPM_UNIT_CSOURCE else if ( str_ends_with ( lower ( c_filename ), \".h\" )) then c_source % unit_type = FPM_UNIT_CHEADER else if ( str_ends_with ( lower ( c_filename ), \".cpp\" )) then c_source % unit_type = FPM_UNIT_CPPSOURCE end if allocate ( c_source % modules_used ( 0 )) allocate ( c_source % modules_provided ( 0 )) allocate ( c_source % parent_modules ( 0 )) open ( newunit = fh , file = c_filename , status = 'old' ) file_lines = read_lines ( fh ) close ( fh ) ! Ignore empty files, returned as FPM_UNIT_UNKNOWN if ( len_trim ( file_lines ) < 1 ) then c_source % unit_type = FPM_UNIT_UNKNOWN return end if c_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_include = 0 file_loop : do i = 1 , size ( file_lines ) ! Process 'INCLUDE' statements if ( index ( adjustl ( lower ( file_lines ( i )% s )), '#include' ) == 1 . and . & index ( file_lines ( i )% s , '\"' ) > 0 ) then n_include = n_include + 1 if ( pass == 2 ) then c_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , c_filename , & 'unable to get c include file' , i , & file_lines ( i )% s , index ( file_lines ( i )% s , '\"' )) return end if end if end if end do file_loop if ( pass == 1 ) then allocate ( c_source % include_dependencies ( n_include )) end if end do end function parse_c_source","tags":"","loc":"proc/parse_c_source.html"},{"title":"parse_f_source – Fortran-lang/fpm","text":"public function parse_f_source(f_filename, error) result(f_source) Parsing of free-form fortran source files The following statements are recognised and parsed: Module / submodule / program declaration Module use statement include statement Note Intrinsic modules used by sources are not listed in\n the modules_used field of source objects. Note Submodules are treated as normal modules which use their\n corresponding parent modules. Parsing limitations Statements must not continued onto another line\n except for an only: list in the use statement. This is supported: use my_module , only : & my_var , my_function , my_subroutine This is NOT supported: use & my_module Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) Contents Source Code parse_f_source Source Code function parse_f_source ( f_filename , error ) result ( f_source ) character ( * ), intent ( in ) :: f_filename type ( srcfile_t ) :: f_source type ( error_t ), allocatable , intent ( out ) :: error logical :: inside_module , inside_interface , using , intrinsic_module integer :: stat integer :: fh , n_use , n_include , n_mod , n_parent , i , j , ic , pass type ( string_t ), allocatable :: file_lines (:), file_lines_lower (:) character (:), allocatable :: temp_string , mod_name , string_parts (:) if (. not . exists ( f_filename )) then call file_not_found_error ( error , f_filename ) return end if f_source % file_name = f_filename open ( newunit = fh , file = f_filename , status = 'old' ) file_lines = read_lines_expanded ( fh ) close ( fh ) ! for efficiency in parsing make a lowercase left-adjusted copy of the file ! Need a copy because INCLUDE (and #include) file arguments are case-sensitive file_lines_lower = file_lines do i = 1 , size ( file_lines_lower ) file_lines_lower ( i )% s = adjustl ( lower ( file_lines_lower ( i )% s )) enddo ! fnv_1a can only be applied to non-zero-length arrays if ( len_trim ( file_lines_lower ) > 0 ) f_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_use = 0 n_include = 0 n_mod = 0 n_parent = 0 inside_module = . false . inside_interface = . false . file_loop : do i = 1 , size ( file_lines_lower ) ! Skip comment lines and preprocessor directives if ( index ( file_lines_lower ( i )% s , '!' ) == 1 . or . & index ( file_lines_lower ( i )% s , '#' ) == 1 . or . & len_trim ( file_lines_lower ( i )% s ) < 1 ) then cycle end if ! Detect exported C-API via bind(C) if (. not . inside_interface . and . & parse_subsequence ( file_lines_lower ( i )% s , 'bind' , '(' , 'c' )) then do j = i , 1 , - 1 if ( index ( file_lines_lower ( j )% s , 'function' ) > 0 . or . & index ( file_lines_lower ( j )% s , 'subroutine' ) > 0 ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM exit end if if ( j > 1 ) then ic = index ( file_lines_lower ( j - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( j - 1 )% s ) end if temp_string = trim ( file_lines_lower ( j - 1 )% s ( 1 : ic )) if ( index ( temp_string , '&' ) /= len ( temp_string )) then exit end if end if end do end if ! Skip lines that are continued: not statements if ( i > 1 ) then ic = index ( file_lines_lower ( i - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( i - 1 )% s ) end if temp_string = trim ( file_lines_lower ( i - 1 )% s ( 1 : ic )) if ( len ( temp_string ) > 0 . and . index ( temp_string , '&' ) == len ( temp_string )) then cycle end if end if ! Detect beginning of interface block if ( index ( file_lines_lower ( i )% s , 'interface' ) == 1 ) then inside_interface = . true . cycle end if ! Detect end of interface block if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'interface' )) then inside_interface = . false . cycle end if ! Process 'USE' statements call parse_use_statement ( f_filename , i , file_lines_lower ( i )% s , using , intrinsic_module , mod_name , error ) if ( allocated ( error )) return if ( using ) then ! Not a valid module name? if (. not . is_fortran_name ( mod_name )) cycle ! Valid intrinsic module: not a dependency if ( intrinsic_module ) cycle n_use = n_use + 1 if ( pass == 2 ) f_source % modules_used ( n_use )% s = mod_name cycle endif ! Process 'INCLUDE' statements ic = index ( file_lines_lower ( i )% s , 'include' ) if ( ic == 1 ) then ic = index ( lower ( file_lines ( i )% s ), 'include' ) if ( index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), '\"' ) == 1 . or . & index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), \"'\" ) == 1 ) then n_include = n_include + 1 if ( pass == 2 ) then f_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = \"'\" // '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find include file name' , i , & file_lines ( i )% s ) return end if end if cycle end if end if ! Extract name of module if is module if ( index ( file_lines_lower ( i )% s , 'module ' ) == 1 ) then ! Remove any trailing comments ic = index ( file_lines_lower ( i )% s , '!' ) - 1 if ( ic < 1 ) then ic = len ( file_lines_lower ( i )% s ) end if temp_string = trim ( file_lines_lower ( i )% s ( 1 : ic )) ! R1405 module-stmt := \"MODULE\" module-name ! module-stmt has two space-delimited parts only ! (no line continuations) call split ( temp_string , string_parts , ' ' ) if ( size ( string_parts ) /= 2 ) then cycle end if mod_name = trim ( adjustl ( string_parts ( 2 ))) if ( scan ( mod_name , '=(&' ) > 0 ) then ! Ignore these cases: ! module & ! module =* ! module (i) cycle end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for module' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 if ( pass == 2 ) then f_source % modules_provided ( n_mod ) = string_t ( mod_name ) end if if ( f_source % unit_type == FPM_UNIT_UNKNOWN ) then f_source % unit_type = FPM_UNIT_MODULE end if if (. not . inside_module ) then inside_module = . true . else ! Must have missed an end module statement (can't assume a pure module) if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end if cycle end if ! Extract name of submodule if is submodule if ( index ( file_lines_lower ( i )% s , 'submodule' ) == 1 ) then mod_name = split_n ( file_lines_lower ( i )% s , n = 3 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule name' , i , & file_lines_lower ( i )% s ) return end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule ancestry' , i , & file_lines_lower ( i )% s ) return end if if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBMODULE end if n_use = n_use + 1 inside_module = . true . n_parent = n_parent + 1 if ( pass == 2 ) then if ( index ( temp_string , ':' ) > 0 ) then temp_string = temp_string ( index ( temp_string , ':' ) + 1 :) end if if (. not . is_fortran_name ( temp_string )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule parent' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , temp_string )) return end if f_source % modules_used ( n_use )% s = temp_string f_source % parent_modules ( n_parent )% s = temp_string f_source % modules_provided ( n_mod )% s = mod_name end if cycle end if ! Detect if contains a program ! (no modules allowed after program def) if ( index ( file_lines_lower ( i )% s , 'program ' ) == 1 ) then temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = ' ' , stat = stat ) if ( stat == 0 ) then if ( scan ( temp_string , '=(' ) > 0 ) then ! Ignore: ! program =* ! program (i) =* cycle end if end if f_source % unit_type = FPM_UNIT_PROGRAM cycle end if ! Parse end module statement ! (to check for code outside of modules) if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'module' ) . or . & parse_sequence ( file_lines_lower ( i )% s , 'end' , 'submodule' )) then inside_module = . false . cycle end if ! Any statements not yet parsed are assumed to be other code statements if (. not . inside_module . and . f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end do file_loop ! If unable to parse end of module statement, then can't assume pure module ! (there could be non-module subprograms present) if ( inside_module . and . f_source % unit_type == FPM_UNIT_MODULE ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if if ( pass == 1 ) then allocate ( f_source % modules_used ( n_use )) allocate ( f_source % include_dependencies ( n_include )) allocate ( f_source % modules_provided ( n_mod )) allocate ( f_source % parent_modules ( n_parent )) end if end do end function parse_f_source","tags":"","loc":"proc/parse_f_source.html"},{"title":"parse_use_statement – Fortran-lang/fpm","text":"public subroutine parse_use_statement(f_filename, i, line, use_stmt, is_intrinsic, module_name, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename Current file name and line number (for error messaging) integer, intent(in) :: i character(len=*), intent(in) :: line The line being parsed. MUST BE preprocessed with trim(adjustl() logical, intent(out) :: use_stmt Does this line contain a use statement? logical, intent(out) :: is_intrinsic Is the module in this statement intrinsic? character(len=:), intent(out), allocatable :: module_name used module name type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code parse_use_statement Source Code subroutine parse_use_statement ( f_filename , i , line , use_stmt , is_intrinsic , module_name , error ) !> Current file name and line number (for error messaging) character ( * ), intent ( in ) :: f_filename integer , intent ( in ) :: i !> The line being parsed. MUST BE preprocessed with trim(adjustl() character ( * ), intent ( in ) :: line !> Does this line contain a `use` statement? logical , intent ( out ) :: use_stmt !> Is the module in this statement intrinsic? logical , intent ( out ) :: is_intrinsic !> used module name character (:), allocatable , intent ( out ) :: module_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( 15 ), parameter :: INTRINSIC_NAMES ( * ) = & [ 'iso_c_binding ' , & 'iso_fortran_env' , & 'ieee_arithmetic' , & 'ieee_exceptions' , & 'ieee_features ' , & 'omp_lib ' ] character ( len = :), allocatable :: temp_string integer :: colons , intr , nonintr , j , stat logical :: has_intrinsic_name use_stmt = . false . is_intrinsic = . false . if ( len_trim ( line ) <= 0 ) return ! Quick check that the line is preprocessed if ( line ( 1 : 1 ) == ' ' ) then call fatal_error ( error , 'internal_error: source file line is not trim(adjustl()) on input to parse_use_statement' ) return end if ! 'use' should be the first string in the adjustl line use_stmt = index ( line , 'use ' ) == 1 . or . index ( line , 'use::' ) == 1 . or . index ( line , 'use,' ) == 1 if (. not . use_stmt ) return colons = index ( line , '::' ) nonintr = 0 intr = 0 have_colons : if ( colons > 3 ) then ! there may be an intrinsic/non-intrinsic spec nonintr = index ( line ( 1 : colons - 1 ), 'non_intrinsic' ) if ( nonintr == 0 ) intr = index ( line ( 1 : colons - 1 ), 'intrinsic' ) temp_string = split_n ( line , delims = ':' , n = 2 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line , colons ) return end if module_name = split_n ( temp_string , delims = ' ,' , n = 1 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if else module_name = split_n ( line , n = 2 , delims = ' ,' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if end if have_colons ! If declared intrinsic, check that it is true has_intrinsic_name = any ([( index ( module_name , trim ( INTRINSIC_NAMES ( j ))) > 0 , & j = 1 , size ( INTRINSIC_NAMES ))]) if ( intr > 0 . and . . not . has_intrinsic_name ) then ! An intrinsic module was not found. Its name could be in the next line, ! in which case, we just skip this check. The compiler will do the job if the name is invalid. ! Module name was not read: it's in the next line if ( index ( module_name , '&' ) <= 0 ) then call file_parse_error ( error , f_filename , & 'module ' // module_name // ' is declared intrinsic but it is not ' , i , & line ) return endif endif ! Should we treat this as an intrinsic module is_intrinsic = nonintr == 0 . and . & ! not declared non-intrinsic ( intr > 0 . or . has_intrinsic_name ) end subroutine parse_use_statement","tags":"","loc":"proc/parse_use_statement.html"},{"title":"show_model – Fortran-lang/fpm","text":"public subroutine show_model(model) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model Contents Source Code show_model Source Code subroutine show_model ( model ) ! Prints a human readable representation of the Model type ( fpm_model_t ), intent ( in ) :: model print * , info_model ( model ) end subroutine show_model","tags":"","loc":"proc/show_model.html"},{"title":"add_dependency – Fortran-lang/fpm","text":"public subroutine add_dependency(target, dependency) Add pointer to dependeny in target%dependencies Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout) :: target type( build_target_t ), intent(in), target :: dependency Contents Source Code add_dependency Source Code subroutine add_dependency ( target , dependency ) type ( build_target_t ), intent ( inout ) :: target type ( build_target_t ) , intent ( in ), target :: dependency target % dependencies = [ target % dependencies , build_target_ptr ( dependency )] end subroutine add_dependency","tags":"","loc":"proc/add_dependency.html"},{"title":"add_target – Fortran-lang/fpm","text":"public subroutine add_target(targets, package, type, output_name, source, link_libraries, features, macros, version) Allocate a new target and append to target list Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) character(len=*), intent(in) :: package integer, intent(in) :: type character(len=*), intent(in) :: output_name type( srcfile_t ), intent(in), optional :: source type( string_t ), intent(in), optional :: link_libraries (:) type( fortran_features_t ), intent(in), optional :: features type( string_t ), intent(in), optional :: macros (:) character(len=*), intent(in), optional :: version Contents Source Code add_target Source Code subroutine add_target ( targets , package , type , output_name , source , link_libraries , & & features , macros , version ) type ( build_target_ptr ), allocatable , intent ( inout ) :: targets (:) character ( * ), intent ( in ) :: package integer , intent ( in ) :: type character ( * ), intent ( in ) :: output_name type ( srcfile_t ), intent ( in ), optional :: source type ( string_t ), intent ( in ), optional :: link_libraries (:) type ( fortran_features_t ), intent ( in ), optional :: features type ( string_t ), intent ( in ), optional :: macros (:) character ( * ), intent ( in ), optional :: version integer :: i type ( build_target_t ), pointer :: new_target if (. not . allocated ( targets )) allocate ( targets ( 0 )) ! Check for duplicate outputs do i = 1 , size ( targets ) if ( targets ( i )% ptr % output_name == output_name ) then write ( * , * ) 'Error while building target list: duplicate output object \"' ,& output_name , '\"' if ( present ( source )) write ( * , * ) ' Source file: \"' , source % file_name , '\"' call fpm_stop ( 1 , ' ' ) end if end do allocate ( new_target ) new_target % target_type = type new_target % output_name = output_name new_target % package_name = package if ( present ( source )) new_target % source = source if ( present ( link_libraries )) new_target % link_libraries = link_libraries if ( present ( features )) new_target % features = features if ( present ( macros )) new_target % macros = macros if ( present ( version )) new_target % version = version allocate ( new_target % dependencies ( 0 )) targets = [ targets , build_target_ptr ( new_target )] end subroutine add_target","tags":"","loc":"proc/add_target.html"},{"title":"filter_executable_targets – Fortran-lang/fpm","text":"public subroutine filter_executable_targets(targets, scope, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) integer, intent(in) :: scope type( string_t ), intent(out), allocatable :: list (:) Contents Source Code filter_executable_targets Source Code subroutine filter_executable_targets ( targets , scope , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) integer , intent ( in ) :: scope type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( is_executable_target ( targets ( i )% ptr , scope )) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_executable_targets","tags":"","loc":"proc/filter_executable_targets.html"},{"title":"filter_library_targets – Fortran-lang/fpm","text":"public subroutine filter_library_targets(targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) Contents Source Code filter_library_targets Source Code subroutine filter_library_targets ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( targets ( i )% ptr % target_type == FPM_TARGET_ARCHIVE ) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_library_targets","tags":"","loc":"proc/filter_library_targets.html"},{"title":"filter_modules – Fortran-lang/fpm","text":"public subroutine filter_modules(targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) Contents Source Code filter_modules Source Code subroutine filter_modules ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , j , n n = 0 call resize ( list ) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if (. not . allocated ( target % source )) cycle if ( target % source % unit_type == FPM_UNIT_SUBMODULE ) cycle if ( n + size ( target % source % modules_provided ) >= size ( list )) call resize ( list ) do j = 1 , size ( target % source % modules_provided ) n = n + 1 list ( n )% s = join_path ( target % output_dir , & target % source % modules_provided ( j )% s ) end do end associate end do call resize ( list , n ) end subroutine filter_modules","tags":"","loc":"proc/filter_modules.html"},{"title":"resolve_module_dependencies – Fortran-lang/fpm","text":"public subroutine resolve_module_dependencies(targets, external_modules, error) Add dependencies to source-based targets ( FPM_TARGET_OBJECT )\n based on any modules used by the corresponding source file. Source file scoping Source files are assigned a scope of either FPM_SCOPE_LIB , FPM_SCOPE_APP or FPM_SCOPE_TEST . The scope controls which\n modules may be used by the source file: Library sources ( FPM_SCOPE_LIB ) may only use modules\n also with library scope. This includes library modules\n from dependencies. Executable sources ( FPM_SCOPE_APP , FPM_SCOPE_TEST ) may use\n library modules (including dependencies) as well as any modules\n corresponding to source files in the same directory or a\n subdirectory of the executable source file. Warning If a module used by a source file cannot be resolved to\n a source file in the package of the correct scope, then a fatal error is returned by the procedure and model construction fails. Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), target :: targets (:) type( string_t ), intent(in) :: external_modules (:) type( error_t ), intent(out), allocatable :: error Contents Source Code resolve_module_dependencies Source Code subroutine resolve_module_dependencies ( targets , external_modules , error ) type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( string_t ), intent ( in ) :: external_modules (:) type ( error_t ), allocatable , intent ( out ) :: error type ( build_target_ptr ) :: dep integer :: i , j do i = 1 , size ( targets ) if (. not . allocated ( targets ( i )% ptr % source )) cycle do j = 1 , size ( targets ( i )% ptr % source % modules_used ) if ( targets ( i )% ptr % source % modules_used ( j )% s . in . targets ( i )% ptr % source % modules_provided ) then ! Dependency satisfied in same file, skip cycle end if if ( targets ( i )% ptr % source % modules_used ( j )% s . in . external_modules ) then ! Dependency satisfied in system-installed module cycle end if if ( any ( targets ( i )% ptr % source % unit_scope == & [ FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST ])) then dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s , & include_dir = dirname ( targets ( i )% ptr % source % file_name )) else dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s ) end if if (. not . associated ( dep % ptr )) then call fatal_error ( error , & 'Unable to find source for module dependency: \"' // & targets ( i )% ptr % source % modules_used ( j )% s // & '\" used by \"' // targets ( i )% ptr % source % file_name // '\"' ) return end if call add_dependency ( targets ( i )% ptr , dep % ptr ) end do end do end subroutine resolve_module_dependencies","tags":"","loc":"proc/resolve_module_dependencies.html"},{"title":"targets_from_sources – Fortran-lang/fpm","text":"public subroutine targets_from_sources(targets, model, prune, error) High-level wrapper to generate build target information Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: targets (:) The generated list of build targets type( fpm_model_t ), intent(inout), target :: model The package model from which to construct the target list logical, intent(in) :: prune Enable tree-shaking/pruning of module dependencies type( error_t ), intent(out), allocatable :: error Error structure Contents Source Code targets_from_sources Source Code subroutine targets_from_sources ( targets , model , prune , error ) !> The generated list of build targets type ( build_target_ptr ), intent ( out ), allocatable :: targets (:) !> The package model from which to construct the target list type ( fpm_model_t ), intent ( inout ), target :: model !> Enable tree-shaking/pruning of module dependencies logical , intent ( in ) :: prune !> Error structure type ( error_t ), intent ( out ), allocatable :: error call build_target_list ( targets , model ) call collect_exe_link_dependencies ( targets ) call resolve_module_dependencies ( targets , model % external_modules , error ) if ( allocated ( error )) return if ( prune ) then call prune_build_targets ( targets , root_package = model % package_name ) end if call resolve_target_linking ( targets , model ) end subroutine targets_from_sources","tags":"","loc":"proc/targets_from_sources.html"},{"title":"check_and_read_pkg_data – Fortran-lang/fpm","text":"public subroutine check_and_read_pkg_data(json, node, download_url, version, error) Arguments Type Intent Optional Attributes Name type(json_object), intent(inout) :: json class( dependency_node_t ), intent(in) :: node character(len=:), intent(out), allocatable :: download_url type( version_t ), intent(out) :: version type( error_t ), intent(out), allocatable :: error Contents","tags":"","loc":"proc/check_and_read_pkg_data.html"},{"title":"new_dependency_node – Fortran-lang/fpm","text":"public subroutine new_dependency_node(self, dependency, version, proj_dir, update) Create a new dependency node from a configuration Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(out) :: self Instance of the dependency node type( dependency_config_t ), intent(in) :: dependency Dependency configuration data type( version_t ), intent(in), optional :: version Version of the dependency character(len=*), intent(in), optional :: proj_dir Installation prefix of the dependency logical, intent(in), optional :: update Dependency should be updated Contents Source Code new_dependency_node Source Code subroutine new_dependency_node ( self , dependency , version , proj_dir , update ) !> Instance of the dependency node type ( dependency_node_t ), intent ( out ) :: self !> Dependency configuration data type ( dependency_config_t ), intent ( in ) :: dependency !> Version of the dependency type ( version_t ), intent ( in ), optional :: version !> Installation prefix of the dependency character ( len =* ), intent ( in ), optional :: proj_dir !> Dependency should be updated logical , intent ( in ), optional :: update self % dependency_config_t = dependency if ( present ( version )) then self % version = version end if if ( present ( proj_dir )) then self % proj_dir = proj_dir end if if ( present ( update )) then self % update = update end if end subroutine new_dependency_node","tags":"","loc":"proc/new_dependency_node.html"},{"title":"new_dependency_tree – Fortran-lang/fpm","text":"public subroutine new_dependency_tree(self, verbosity, cache) Create a new dependency tree Arguments Type Intent Optional Attributes Name type( dependency_tree_t ), intent(out) :: self Instance of the dependency tree integer, intent(in), optional :: verbosity Verbosity of printout character(len=*), intent(in), optional :: cache Name of the cache file Contents Source Code new_dependency_tree Source Code subroutine new_dependency_tree ( self , verbosity , cache ) !> Instance of the dependency tree type ( dependency_tree_t ), intent ( out ) :: self !> Verbosity of printout integer , intent ( in ), optional :: verbosity !> Name of the cache file character ( len =* ), intent ( in ), optional :: cache call resize ( self % dep ) self % dep_dir = join_path ( \"build\" , \"dependencies\" ) if ( present ( verbosity )) self % verbosity = verbosity if ( present ( cache )) self % cache = cache end subroutine new_dependency_tree","tags":"","loc":"proc/new_dependency_tree.html"},{"title":"resize – Fortran-lang/fpm","text":"public interface resize Overloaded reallocation interface Contents Module Procedures resize_dependency_node Module Procedures private pure subroutine resize_dependency_node(var, n) Reallocate a list of dependencies Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(inout), allocatable :: var (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size","tags":"","loc":"interface/resize.html"},{"title":"regex_version_from_text – Fortran-lang/fpm","text":"public function regex_version_from_text(text, what, error) result(ver) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: text character(len=*), intent(in) :: what type( error_t ), intent(out), allocatable :: error Return Value type( string_t ) Contents Source Code regex_version_from_text Source Code type ( string_t ) function regex_version_from_text ( text , what , error ) result ( ver ) character ( * ), intent ( in ) :: text character ( * ), intent ( in ) :: what type ( error_t ), allocatable , intent ( out ) :: error integer :: ire , length if ( len_trim ( text ) <= 0 ) then call syntax_error ( error , 'cannot retrieve ' // what // ' version: empty input string' ) return end if ! Extract 3-sized version \"1.0.4\" ire = regex ( text , '\\d+\\.\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ! Parse version into the object (this should always work) ver = string_t ( text ( ire : ire + length - 1 )) else ! Try 2-sized version \"1.0\" ire = regex ( text , '\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ver = string_t ( text ( ire : ire + length - 1 )) else call syntax_error ( error , 'cannot retrieve ' // what // ' version.' ) end if end if end function regex_version_from_text","tags":"","loc":"proc/regex_version_from_text.html"},{"title":"new_version – Fortran-lang/fpm","text":"public interface new_version Contents Module Procedures new_version_from_string new_version_from_int Module Procedures private subroutine new_version_from_string(self, string, error) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data character(len=*), intent(in) :: string String describing the version information type( error_t ), intent(out), allocatable :: error Error handling private subroutine new_version_from_int(self, num) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data integer, intent(in) :: num (:) Subversion numbers to define version data","tags":"","loc":"interface/new_version.html"},{"title":"fpm_version – Fortran-lang/fpm","text":"public function fpm_version() Return the current fpm version from fpm_version_ID as a version type Arguments None Return Value type( version_t ) Contents Source Code fpm_version Source Code type ( version_t ) function fpm_version () type ( error_t ), allocatable :: error ! Fallback to last known version in case of undefined macro #ifndef FPM_RELEASE_VERSION # define FPM_RELEASE_VERSION 0.8.0 #endif ! Accept solution from https://stackoverflow.com/questions/31649691/stringify-macro-with-gnu-gfortran ! which provides the \"easiest\" way to pass a macro to a string in Fortran complying with both ! gfortran's \"traditional\" cpp and the standard cpp syntaxes #ifdef __GFORTRAN__ /* traditional-cpp stringification */ # define STRINGIFY_START(X) \"& # define STRINGIFY_END(X) &X\" #else /* default stringification */ # define STRINGIFY_(X) #X # define STRINGIFY_START(X) & # define STRINGIFY_END(X) STRINGIFY_(X) #endif character ( len = :), allocatable :: ver_string ver_string = STRINGIFY_START ( FPM_RELEASE_VERSION ) STRINGIFY_END ( FPM_RELEASE_VERSION ) call new_version ( fpm_version , ver_string , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*fpm*:internal error: cannot get version - ' // error % message ) end function fpm_version","tags":"","loc":"proc/fpm_version.html"},{"title":"bad_name_error – Fortran-lang/fpm","text":"public function bad_name_error(error, label, name) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: label Error message label to add to message character(len=*), intent(in) :: name name value to check Return Value logical Contents Source Code bad_name_error Source Code function bad_name_error ( error , label , name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message label to add to message character ( len =* ), intent ( in ) :: label !> name value to check character ( len =* ), intent ( in ) :: name logical :: bad_name_error if (. not . is_fortran_name ( to_fortran_name ( name ))) then bad_name_error = . true . allocate ( error ) error % message = 'manifest file syntax error: ' // label // ' name must be composed only of & &alphanumerics, \"-\" and \"_\" and start with a letter ::' // name else bad_name_error = . false . endif end function bad_name_error","tags":"","loc":"proc/bad_name_error.html"},{"title":"fatal_error – Fortran-lang/fpm","text":"public subroutine fatal_error(error, message) Generic fatal runtime error Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message Contents Source Code fatal_error Source Code subroutine fatal_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine fatal_error","tags":"","loc":"proc/fatal_error.html"},{"title":"file_not_found_error – Fortran-lang/fpm","text":"public subroutine file_not_found_error(error, file_name) Error created when a file is missing or not found Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of the missing file Contents Source Code file_not_found_error Source Code subroutine file_not_found_error ( error , file_name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of the missing file character ( len =* ), intent ( in ) :: file_name allocate ( error ) error % message = \"'\" // file_name // \"' could not be found, check if the file exists\" end subroutine file_not_found_error","tags":"","loc":"proc/file_not_found_error.html"},{"title":"file_parse_error – Fortran-lang/fpm","text":"public subroutine file_parse_error(error, file_name, message, line_num, line_string, line_col) Error created when file parsing fails Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of file character(len=*), intent(in) :: message Parse error message integer, intent(in), optional :: line_num Line number of parse error character(len=*), intent(in), optional :: line_string Line context string integer, intent(in), optional :: line_col Line context column Contents Source Code file_parse_error Source Code subroutine file_parse_error ( error , file_name , message , line_num , & line_string , line_col ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of file character ( len =* ), intent ( in ) :: file_name !> Parse error message character ( len =* ), intent ( in ) :: message !> Line number of parse error integer , intent ( in ), optional :: line_num !> Line context string character ( len =* ), intent ( in ), optional :: line_string !> Line context column integer , intent ( in ), optional :: line_col character ( 50 ) :: temp_string allocate ( error ) error % message = 'Parse error: ' // message // new_line ( 'a' ) error % message = error % message // file_name if ( present ( line_num )) then write ( temp_string , '(I0)' ) line_num error % message = error % message // ':' // trim ( temp_string ) end if if ( present ( line_col )) then if ( line_col > 0 ) then write ( temp_string , '(I0)' ) line_col error % message = error % message // ':' // trim ( temp_string ) end if end if if ( present ( line_string )) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // line_string if ( present ( line_col )) then if ( line_col > 0 ) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // repeat ( ' ' , line_col - 1 ) // '^' end if end if end if end subroutine file_parse_error","tags":"","loc":"proc/file_parse_error.html"},{"title":"fpm_stop – Fortran-lang/fpm","text":"public subroutine fpm_stop(value, message) Arguments Type Intent Optional Attributes Name integer, intent(in) :: value value to use on STOP character(len=*), intent(in) :: message Error message Contents Source Code fpm_stop Source Code subroutine fpm_stop ( value , message ) ! TODO: if verbose mode, call ERROR STOP instead of STOP ! TODO: if M_escape is used, add color ! to work with older compilers might need a case statement for values !> value to use on STOP integer , intent ( in ) :: value !> Error message character ( len =* ), intent ( in ) :: message integer :: iostat if ( message /= '' ) then flush ( unit = stderr , iostat = iostat ) flush ( unit = stdout , iostat = iostat ) if ( value > 0 ) then write ( stderr , '(\" \",a)' ) trim ( message ) else write ( stderr , '(\" \",a)' ) trim ( message ) endif flush ( unit = stderr , iostat = iostat ) endif stop value end subroutine fpm_stop","tags":"","loc":"proc/fpm_stop.html"},{"title":"syntax_error – Fortran-lang/fpm","text":"public subroutine syntax_error(error, message) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message Contents Source Code syntax_error Source Code subroutine syntax_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine syntax_error","tags":"","loc":"proc/syntax_error.html"},{"title":"git_matches_manifest – Fortran-lang/fpm","text":"public function git_matches_manifest(cached, manifest, verbosity, iunit) Check that a cached dependency matches a manifest request The manifest dependency only contains partial information (what’s requested),\nwhile the cached dependency always stores a commit hash because it’s built\nafter the repo is available (saved as git_descriptor%revision==revision).\nSo, comparing against the descriptor is not reliable Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: cached Two input git targets type( git_target_t ), intent(in) :: manifest Two input git targets integer, intent(in) :: verbosity integer, intent(in) :: iunit Return Value logical Contents Source Code git_matches_manifest Source Code logical function git_matches_manifest ( cached , manifest , verbosity , iunit ) !> Two input git targets type ( git_target_t ), intent ( in ) :: cached , manifest integer , intent ( in ) :: verbosity , iunit git_matches_manifest = cached % url == manifest % url if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT URL has changed: \" , cached % url , \" vs. \" , manifest % url return endif !> The manifest dependency only contains partial information (what's requested), !> while the cached dependency always stores a commit hash because it's built !> after the repo is available (saved as git_descriptor%revision==revision). !> So, comparing against the descriptor is not reliable git_matches_manifest = allocated ( cached % object ) . eqv . allocated ( manifest % object ) if ( git_matches_manifest . and . allocated ( cached % object )) & git_matches_manifest = cached % object == manifest % object if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT OBJECT has changed: \" , cached % object , \" vs. \" , manifest % object end if end function git_matches_manifest","tags":"","loc":"proc/git_matches_manifest.html"},{"title":"git_target_branch – Fortran-lang/fpm","text":"public function git_target_branch(url, branch) result(self) Target a branch in the git repository Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: branch Name of the branch of interest Return Value type( git_target_t ) New git target Contents Source Code git_target_branch Source Code function git_target_branch ( url , branch ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Name of the branch of interest character ( len =* ), intent ( in ) :: branch !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % branch self % url = url self % object = branch end function git_target_branch","tags":"","loc":"proc/git_target_branch.html"},{"title":"git_target_default – Fortran-lang/fpm","text":"public function git_target_default(url) result(self) Default target Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository Return Value type( git_target_t ) New git target Contents Source Code git_target_default Source Code function git_target_default ( url ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % default self % url = url end function git_target_default","tags":"","loc":"proc/git_target_default.html"},{"title":"git_target_eq – Fortran-lang/fpm","text":"public function git_target_eq(this, that) result(is_equal) Check that two git targets are equal Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: this Two input git targets type( git_target_t ), intent(in) :: that Two input git targets Return Value logical Contents Source Code git_target_eq Source Code logical function git_target_eq ( this , that ) result ( is_equal ) !> Two input git targets type ( git_target_t ), intent ( in ) :: this , that is_equal = this % descriptor == that % descriptor . and . & this % url == that % url . and . & this % object == that % object end function git_target_eq","tags":"","loc":"proc/git_target_eq.html"},{"title":"git_target_revision – Fortran-lang/fpm","text":"public function git_target_revision(url, sha1) result(self) Target a specific git revision Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: sha1 Commit hash of interest Return Value type( git_target_t ) New git target Contents Source Code git_target_revision Source Code function git_target_revision ( url , sha1 ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Commit hash of interest character ( len =* ), intent ( in ) :: sha1 !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % revision self % url = url self % object = sha1 end function git_target_revision","tags":"","loc":"proc/git_target_revision.html"},{"title":"git_target_tag – Fortran-lang/fpm","text":"public function git_target_tag(url, tag) result(self) Target a git tag Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: tag Tag name of interest Return Value type( git_target_t ) New git target Contents Source Code git_target_tag Source Code function git_target_tag ( url , tag ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Tag name of interest character ( len =* ), intent ( in ) :: tag !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % tag self % url = url self % object = tag end function git_target_tag","tags":"","loc":"proc/git_target_tag.html"},{"title":"checkout – Fortran-lang/fpm","text":"public subroutine checkout(self, local_path, error) Type Bound git_target_t Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target character(len=*), intent(in) :: local_path Local path to checkout in type( error_t ), intent(out), allocatable :: error Error Contents Variables object stat workdir Source Code checkout Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: object integer, public :: stat character(len=:), public, allocatable :: workdir Source Code subroutine checkout ( self , local_path , error ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character ( len = :), allocatable :: object , workdir if ( allocated ( self % object )) then object = self % object else object = 'HEAD' end if workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) call execute_command_line ( \"git init \" // local_path , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while initiating git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" fetch --depth=1 \" // & self % url // \" \" // object , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while fetching git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" checkout -qf FETCH_HEAD\" , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while checking out git repository for remote dependency' ) return end if end subroutine checkout","tags":"","loc":"proc/checkout.html"},{"title":"git_archive – Fortran-lang/fpm","text":"public subroutine git_archive(source, destination, ref, verbose, error) Archive a folder using git archive . Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: source Directory to archive. character(len=*), intent(in) :: destination Destination of the archive. character(len=*), intent(in) :: ref (Symbolic) Reference to be archived. logical, intent(in) :: verbose Print additional information if true. type( error_t ), intent(out), allocatable :: error Error handling. Contents Variables archive_format cmd_output stat Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archive_format character(len=:), public, allocatable :: cmd_output integer, public :: stat","tags":"","loc":"proc/git_archive.html"},{"title":"git_revision – Fortran-lang/fpm","text":"public subroutine git_revision(local_path, object, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: local_path Local path to checkout in character(len=:), intent(out), allocatable :: object Git object reference type( error_t ), intent(out), allocatable :: error Error Contents Variables hexdigits iend iomsg istart line stat temp_file unit workdir Source Code git_revision Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: hexdigits = '0123456789abcdef' integer, public :: iend character(len=:), public, allocatable :: iomsg integer, public :: istart character(len=:), public, allocatable :: line integer, public :: stat character(len=:), public, allocatable :: temp_file integer, public :: unit character(len=:), public, allocatable :: workdir Source Code subroutine git_revision ( local_path , object , error ) !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Git object reference character ( len = :), allocatable , intent ( out ) :: object !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , unit , istart , iend character ( len = :), allocatable :: temp_file , line , iomsg , workdir character ( len =* ), parameter :: hexdigits = '0123456789abcdef' workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) allocate ( temp_file , source = get_temp_filename ()) line = \"git \" // workdir // \" log -n 1 > \" // temp_file call execute_command_line ( line , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error while retrieving commit information\" ) return end if open ( file = temp_file , newunit = unit ) call getline ( unit , line , stat , iomsg ) if ( stat /= 0 ) then call fatal_error ( error , iomsg ) return end if close ( unit , status = \"delete\" ) ! Tokenize: ! commit 0123456789abcdef (HEAD, ...) istart = scan ( line , ' ' ) + 1 iend = verify ( line ( istart :), hexdigits ) + istart - 1 if ( iend < istart ) iend = len ( line ) object = line ( istart : iend ) end subroutine git_revision","tags":"","loc":"proc/git_revision.html"},{"title":"info – Fortran-lang/fpm","text":"public subroutine info(self, unit, verbosity) Show information on git target Type Bound git_target_t Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Contents Variables fmt pr Source Code info Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: fmt = '(\"#\", 1x, a, t30, a)' integer, public :: pr Source Code subroutine info ( self , unit , verbosity ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Git target\" if ( allocated ( self % url )) then write ( unit , fmt ) \"- URL\" , self % url end if if ( allocated ( self % object )) then select case ( self % descriptor ) case default write ( unit , fmt ) \"- object\" , self % object case ( git_descriptor % tag ) write ( unit , fmt ) \"- tag\" , self % object case ( git_descriptor % branch ) write ( unit , fmt ) \"- branch\" , self % object case ( git_descriptor % revision ) write ( unit , fmt ) \"- sha1\" , self % object end select end if end subroutine info","tags":"","loc":"proc/info~2.html"},{"title":"operator(==) – Fortran-lang/fpm","text":"public interface operator(==) Contents Module Procedures git_target_eq Module Procedures public function git_target_eq (this, that) result(is_equal) Check that two git targets are equal Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: this Two input git targets type( git_target_t ), intent(in) :: that Two input git targets Return Value logical","tags":"","loc":"interface/operator(==).html"},{"title":"default_example – Fortran-lang/fpm","text":"public subroutine default_example(self, name) Populate test in case we find the default example/ directory Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package Contents Source Code default_example Source Code subroutine default_example ( self , name ) !> Instance of the executable meta data type ( example_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-demo\" self % source_dir = \"example\" self % main = \"main.f90\" end subroutine default_example","tags":"","loc":"proc/default_example.html"},{"title":"default_executable – Fortran-lang/fpm","text":"public subroutine default_executable(self, name) Populate executable in case we find the default app directory Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package Contents Source Code default_executable Source Code subroutine default_executable ( self , name ) !> Instance of the executable meta data type ( executable_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name self % source_dir = \"app\" self % main = \"main.f90\" end subroutine default_executable","tags":"","loc":"proc/default_executable.html"},{"title":"default_library – Fortran-lang/fpm","text":"public subroutine default_library(self) Populate library in case we find the default src directory Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library meta data Contents Source Code default_library Source Code subroutine default_library ( self ) !> Instance of the library meta data type ( library_config_t ), intent ( out ) :: self self % source_dir = \"src\" self % include_dir = [ string_t ( \"include\" )] end subroutine default_library","tags":"","loc":"proc/default_library.html"},{"title":"default_test – Fortran-lang/fpm","text":"public subroutine default_test(self, name) Populate test in case we find the default test/ directory Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package Contents Source Code default_test Source Code subroutine default_test ( self , name ) !> Instance of the executable meta data type ( test_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-test\" self % source_dir = \"test\" self % main = \"main.f90\" end subroutine default_test","tags":"","loc":"proc/default_test.html"},{"title":"get_package_data – Fortran-lang/fpm","text":"public subroutine get_package_data(package, file, error, apply_defaults) Obtain package meta data from a configuation file Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: package Parsed package meta data character(len=*), intent(in) :: file Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation logical, intent(in), optional :: apply_defaults Apply package defaults (uses file system operations) Contents Source Code get_package_data Source Code subroutine get_package_data ( package , file , error , apply_defaults ) !> Parsed package meta data type ( package_config_t ), intent ( out ) :: package !> Name of the package configuration file character ( len =* ), intent ( in ) :: file !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error !> Apply package defaults (uses file system operations) logical , intent ( in ), optional :: apply_defaults type ( toml_table ), allocatable :: table character ( len = :), allocatable :: root call read_package_file ( table , file , error ) if ( allocated ( error )) return if (. not . allocated ( table )) then call fatal_error ( error , \"Unclassified error while reading: '\" // file // \"'\" ) return end if call new_package ( package , table , dirname ( file ), error ) if ( allocated ( error )) return if ( present ( apply_defaults )) then if ( apply_defaults ) then root = dirname ( file ) if ( len_trim ( root ) == 0 ) root = \".\" call package_defaults ( package , root , error ) if ( allocated ( error )) return end if end if end subroutine get_package_data","tags":"","loc":"proc/get_package_data.html"},{"title":"check_keys – Fortran-lang/fpm","text":"public subroutine check_keys(table, valid_keys, error) Check if table contains only keys that are part of the list. If a key is\nfound that is not part of the list, an error is allocated. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: valid_keys (:) List of keys to check. type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code check_keys Source Code subroutine check_keys ( table , valid_keys , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys to check. character ( len =* ), intent ( in ) :: valid_keys (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: keys (:) type ( toml_table ), pointer :: child character (:), allocatable :: name , value , valid_keys_string integer :: ikey , ivalid call table % get_key ( name ) call table % get_keys ( keys ) do ikey = 1 , size ( keys ) if (. not . any ( keys ( ikey )% key == valid_keys )) then ! Generate error message valid_keys_string = new_line ( 'a' ) // new_line ( 'a' ) do ivalid = 1 , size ( valid_keys ) valid_keys_string = valid_keys_string // trim ( valid_keys ( ivalid )) // new_line ( 'a' ) end do allocate ( error ) error % message = \"Key '\" // keys ( ikey )% key // \"' not allowed in the '\" // & & name // \"' table.\" // new_line ( 'a' ) // new_line ( 'a' ) // 'Valid keys: ' // valid_keys_string return end if ! Check if value can be mapped or else (wrong type) show error message with the error location. ! Right now, it can only be mapped to a string or to a child node, but this can be extended in the future. call get_value ( table , keys ( ikey )% key , value ) if (. not . allocated ( value )) then ! If value is not a string, check if it is a child node call get_value ( table , keys ( ikey )% key , child ) if (. not . associated ( child )) then allocate ( error ) error % message = \"'\" // name // \"' has an invalid '\" // keys ( ikey )% key // \"' entry.\" return endif end if end do end subroutine check_keys","tags":"","loc":"proc/check_keys.html"},{"title":"get_list – Fortran-lang/fpm","text":"public subroutine get_list(table, key, list, error) Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Key to read from type( string_t ), intent(out), allocatable :: list (:) List of strings to read type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code get_list Source Code subroutine get_list ( table , key , list , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Key to read from character ( len =* ), intent ( in ) :: key !> List of strings to read type ( string_t ), allocatable , intent ( out ) :: list (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , ilist , nlist type ( toml_array ), pointer :: children character ( len = :), allocatable :: str if (. not . table % has_key ( key )) return call get_value ( table , key , children , requested = . false .) if ( associated ( children )) then nlist = len ( children ) allocate ( list ( nlist )) do ilist = 1 , nlist call get_value ( children , ilist , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) exit end if call move_alloc ( str , list ( ilist )% s ) end do if ( allocated ( error )) return else call get_value ( table , key , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) return end if if ( allocated ( str )) then allocate ( list ( 1 )) call move_alloc ( str , list ( 1 )% s ) end if end if end subroutine get_list","tags":"","loc":"proc/get_list.html"},{"title":"read_package_file – Fortran-lang/fpm","text":"public subroutine read_package_file(table, manifest, error) Process the configuration file to a TOML data structure Arguments Type Intent Optional Attributes Name type(toml_table), intent(out), allocatable :: table TOML data structure character(len=*), intent(in) :: manifest Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation Contents Source Code read_package_file Source Code subroutine read_package_file ( table , manifest , error ) !> TOML data structure type ( toml_table ), allocatable , intent ( out ) :: table !> Name of the package configuration file character ( len =* ), intent ( in ) :: manifest !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error type ( toml_error ), allocatable :: parse_error integer :: unit logical :: exist inquire ( file = manifest , exist = exist ) if (. not . exist ) then call file_not_found_error ( error , manifest ) return end if open ( file = manifest , newunit = unit ) call toml_load ( table , unit , error = parse_error ) close ( unit ) if ( allocated ( parse_error )) then allocate ( error ) call move_alloc ( parse_error % message , error % message ) return end if end subroutine read_package_file","tags":"","loc":"proc/read_package_file.html"},{"title":"new_installer – Fortran-lang/fpm","text":"public subroutine new_installer(self, prefix, bindir, libdir, includedir, verbosity, copy, move) Create a new instance of an installer Arguments Type Intent Optional Attributes Name type( installer_t ), intent(out) :: self Instance of the installer character(len=*), intent(in), optional :: prefix Path to installation directory character(len=*), intent(in), optional :: bindir Binary dir relative to the installation prefix character(len=*), intent(in), optional :: libdir Library directory relative to the installation prefix character(len=*), intent(in), optional :: includedir Include directory relative to the installation prefix integer, intent(in), optional :: verbosity Verbosity of the installer character(len=*), intent(in), optional :: copy Copy command character(len=*), intent(in), optional :: move Move command Contents Source Code new_installer Source Code subroutine new_installer ( self , prefix , bindir , libdir , includedir , verbosity , & copy , move ) !> Instance of the installer type ( installer_t ), intent ( out ) :: self !> Path to installation directory character ( len =* ), intent ( in ), optional :: prefix !> Binary dir relative to the installation prefix character ( len =* ), intent ( in ), optional :: bindir !> Library directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: libdir !> Include directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: includedir !> Verbosity of the installer integer , intent ( in ), optional :: verbosity !> Copy command character ( len =* ), intent ( in ), optional :: copy !> Move command character ( len =* ), intent ( in ), optional :: move self % os = get_os_type () ! By default, never prompt the user for overwrites if ( present ( copy )) then self % copy = copy else if ( os_is_unix ( self % os )) then self % copy = default_force_copy_unix else self % copy = default_force_copy_win end if end if if ( present ( move )) then self % move = move else if ( os_is_unix ( self % os )) then self % move = default_move_unix else self % move = default_move_win end if end if if ( present ( includedir )) then self % includedir = includedir else self % includedir = default_includedir end if if ( present ( prefix )) then self % prefix = prefix else self % prefix = get_local_prefix ( self % os ) end if if ( present ( bindir )) then self % bindir = bindir else self % bindir = default_bindir end if if ( present ( libdir )) then self % libdir = libdir else self % libdir = default_libdir end if if ( present ( verbosity )) then self % verbosity = verbosity else self % verbosity = 1 end if end subroutine new_installer","tags":"","loc":"proc/new_installer.html"},{"title":"manifest_has_changed – Fortran-lang/fpm","text":"public function manifest_has_changed(cached, manifest, verbosity, iunit) result(has_changed) Check if two dependency configurations are different Perform all checks\nAll checks passed! The two instances are equal Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: cached Two instances of the dependency configuration class( dependency_config_t ), intent(in) :: manifest Two instances of the dependency configuration integer, intent(in) :: verbosity Log verbosity integer, intent(in) :: iunit Log verbosity Return Value logical Contents Source Code manifest_has_changed Source Code logical function manifest_has_changed ( cached , manifest , verbosity , iunit ) result ( has_changed ) !> Two instances of the dependency configuration class ( dependency_config_t ), intent ( in ) :: cached , manifest !> Log verbosity integer , intent ( in ) :: verbosity , iunit has_changed = . true . !> Perform all checks if ( allocated ( cached % git ). neqv . allocated ( manifest % git )) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT presence has changed. \" return endif if ( allocated ( cached % git )) then if (. not . git_matches_manifest ( cached % git , manifest % git , verbosity , iunit )) return end if !> All checks passed! The two instances are equal has_changed = . false . end function manifest_has_changed","tags":"","loc":"proc/manifest_has_changed.html"},{"title":"new_dependencies – Fortran-lang/fpm","text":"public subroutine new_dependencies(deps, table, root, meta, error) Construct new dependency array from a TOML data structure Flag dependencies that should be treated as metapackages\nParse all meta- and non-metapackage dependencies Neither a standard dep nor a metapackage\nValid meta dependency Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out), allocatable :: deps (:) Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( metapackage_config_t ), intent(out), optional :: meta (optional) metapackages type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_dependencies Source Code subroutine new_dependencies ( deps , table , root , meta , error ) !> Instance of the dependency configuration type ( dependency_config_t ), allocatable , intent ( out ) :: deps (:) !> (optional) metapackages type ( metapackage_config_t ), optional , intent ( out ) :: meta !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) type ( dependency_config_t ), allocatable :: all_deps (:) type ( metapackage_request_t ) :: meta_request logical , allocatable :: is_meta (:) logical :: metapackages_allowed integer :: idep , stat , ndep call table % get_keys ( list ) ! An empty table is okay if ( size ( list ) < 1 ) return !> Flag dependencies that should be treated as metapackages metapackages_allowed = present ( meta ) allocate ( is_meta ( size ( list )), source = . false .) allocate ( all_deps ( size ( list ))) !> Parse all meta- and non-metapackage dependencies do idep = 1 , size ( list ) ! Check if this is a standard dependency node call get_value ( table , list ( idep )% key , node , stat = stat ) is_standard_dependency : if ( stat /= toml_stat % success ) then ! See if it can be a valid metapackage name call new_meta_request ( meta_request , list ( idep )% key , table , error = error ) !> Neither a standard dep nor a metapackage if ( allocated ( error )) then call syntax_error ( error , \"Dependency \" // list ( idep )% key // \" is not a valid metapackage or a table entry\" ) return endif !> Valid meta dependency is_meta ( idep ) = . true . else ! Parse as a standard dependency is_meta ( idep ) = . false . call new_dependency ( all_deps ( idep ), node , root , error ) if ( allocated ( error )) return end if is_standard_dependency end do ! Non-meta dependencies ndep = count (. not . is_meta ) ! Finalize standard dependencies allocate ( deps ( ndep )) ndep = 0 do idep = 1 , size ( list ) if ( is_meta ( idep )) cycle ndep = ndep + 1 deps ( ndep ) = all_deps ( idep ) end do ! Finalize meta dependencies if ( metapackages_allowed ) call new_meta_config ( meta , table , is_meta , error ) end subroutine new_dependencies","tags":"","loc":"proc/new_dependencies.html"},{"title":"new_dependency – Fortran-lang/fpm","text":"public subroutine new_dependency(self, table, root, error) Construct a new dependency configuration from a TOML data structure Get optional preprocessor directives Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out) :: self Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_dependency Source Code subroutine new_dependency ( self , table , root , error ) !> Instance of the dependency configuration type ( dependency_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: uri , value , requested_version type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_value ( table , \"namespace\" , self % namespace ) call get_value ( table , \"v\" , requested_version ) if ( allocated ( requested_version )) then if (. not . allocated ( self % requested_version )) allocate ( self % requested_version ) call new_version ( self % requested_version , requested_version , error ) if ( allocated ( error )) return end if !> Get optional preprocessor directives call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return endif call get_value ( table , \"path\" , uri ) if ( allocated ( uri )) then if ( get_os_type () == OS_WINDOWS ) uri = windows_path ( uri ) if ( present ( root )) uri = join_path ( root , uri ) ! Relative to the fpm.toml it’s written in call move_alloc ( uri , self % path ) return end if call get_value ( table , \"git\" , uri ) if ( allocated ( uri )) then call get_value ( table , \"tag\" , value ) if ( allocated ( value )) then self % git = git_target_tag ( uri , value ) end if if (. not . allocated ( self % git )) then call get_value ( table , \"branch\" , value ) if ( allocated ( value )) then self % git = git_target_branch ( uri , value ) end if end if if (. not . allocated ( self % git )) then call get_value ( table , \"rev\" , value ) if ( allocated ( value )) then self % git = git_target_revision ( uri , value ) end if end if if (. not . allocated ( self % git )) then self % git = git_target_default ( uri ) end if return end if end subroutine new_dependency","tags":"","loc":"proc/new_dependency.html"},{"title":"new_example – Fortran-lang/fpm","text":"public subroutine new_example(self, table, error) Construct a new example configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the example configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_example Source Code subroutine new_example ( self , table , error ) !> Instance of the example configuration type ( example_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve example name\" ) return end if if ( bad_name_error ( error , 'example' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"example\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_example","tags":"","loc":"proc/new_example.html"},{"title":"is_meta_package – Fortran-lang/fpm","text":"public function is_meta_package(key) Check local schema for allowed entries Supported metapackages Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: key Instance of the TOML data structure Return Value logical Contents Source Code is_meta_package Source Code logical function is_meta_package ( key ) !> Instance of the TOML data structure character ( * ), intent ( in ) :: key select case ( key ) !> Supported metapackages case ( \"openmp\" , \"stdlib\" , \"mpi\" , \"minpack\" ) is_meta_package = . true . case default is_meta_package = . false . end select end function is_meta_package","tags":"","loc":"proc/is_meta_package.html"},{"title":"new_meta_config – Fortran-lang/fpm","text":"public subroutine new_meta_config(self, table, meta_allowed, error) Construct a new build configuration from a TOML data structure The toml table is not checked here because it already passed\nthe “new_dependencies” check Arguments Type Intent Optional Attributes Name type( metapackage_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in) :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_meta_config Source Code subroutine new_meta_config ( self , table , meta_allowed , error ) !> Instance of the build configuration type ( metapackage_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ) :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call new_meta_request ( self % openmp , \"openmp\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % stdlib , \"stdlib\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % minpack , \"minpack\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % mpi , \"mpi\" , table , meta_allowed , error ) if ( allocated ( error )) return end subroutine new_meta_config","tags":"","loc":"proc/new_meta_config.html"},{"title":"new_meta_request – Fortran-lang/fpm","text":"public subroutine new_meta_request(self, key, table, meta_allowed, error) Construct a new metapackage request from the dependencies table Set name\nThe toml table is not checked here because it already passed\nthe “new_dependencies” check Set list of entries that are allowed to be metapackages Arguments Type Intent Optional Attributes Name type( metapackage_request_t ), intent(out) :: self character(len=*), intent(in) :: key The package name type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in), optional :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_meta_request Source Code subroutine new_meta_request ( self , key , table , meta_allowed , error ) type ( metapackage_request_t ), intent ( out ) :: self !> The package name character ( len =* ), intent ( in ) :: key !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ), optional :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: value logical , allocatable :: allow_meta (:) type ( toml_key ), allocatable :: keys (:) call request_destroy ( self ) !> Set name self % name = key if (. not . is_meta_package ( key )) then call fatal_error ( error , \"Error reading fpm.toml: <\" // key // \"> is not a valid metapackage name\" ) return end if !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call table % get_keys ( keys ) !> Set list of entries that are allowed to be metapackages if ( present ( meta_allowed )) then if ( size ( meta_allowed ) /= size ( keys )) then call fatal_error ( error , \"Internal error: list of metapackage-enable entries does not match table size\" ) return end if allow_meta = meta_allowed else allocate ( allow_meta ( size ( keys )), source = . true .) endif do i = 1 , size ( keys ) ! Skip standard dependencies if (. not . allow_meta ( i )) cycle if ( keys ( i )% key == key ) then call get_value ( table , key , value ) if (. not . allocated ( value )) then call syntax_error ( error , \"Could not retrieve version string for metapackage key <\" // key // \">. Check syntax\" ) return else call request_parse ( self , value , error ) return endif end if end do ! Key is not present, metapackage not requested return end subroutine new_meta_request","tags":"","loc":"proc/new_meta_request.html"},{"title":"new_test – Fortran-lang/fpm","text":"public subroutine new_test(self, table, error) Construct a new test configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the test configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_test Source Code subroutine new_test ( self , table , error ) !> Instance of the test configuration type ( test_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve test name\" ) return end if if ( bad_name_error ( error , 'test' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"test\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_test","tags":"","loc":"proc/new_test.html"},{"title":"new_library – Fortran-lang/fpm","text":"public subroutine new_library(self, table, error) Construct a new library configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_library Source Code subroutine new_library ( self , table , error ) !> Instance of the library configuration type ( library_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"source-dir\" , self % source_dir , \"src\" ) call get_value ( table , \"build-script\" , self % build_script ) call get_list ( table , \"include-dir\" , self % include_dir , error ) if ( allocated ( error )) return ! Set default value of include-dir if not found in manifest if (. not . allocated ( self % include_dir )) then self % include_dir = [ string_t ( \"include\" )] end if end subroutine new_library","tags":"","loc":"proc/new_library.html"},{"title":"new_executable – Fortran-lang/fpm","text":"public subroutine new_executable(self, table, error) Construct a new executable configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_executable Source Code subroutine new_executable ( self , table , error ) !> Instance of the executable configuration type ( executable_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve executable name\" ) return end if if ( bad_name_error ( error , 'executable' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"app\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_executable","tags":"","loc":"proc/new_executable.html"},{"title":"new_fortran_config – Fortran-lang/fpm","text":"public subroutine new_fortran_config(self, table, error) Construct a new build configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( fortran_config_t ), intent(out) :: self Instance of the fortran configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_fortran_config Source Code subroutine new_fortran_config ( self , table , error ) !> Instance of the fortran configuration type ( fortran_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character (:), allocatable :: source_form call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"implicit-typing\" , self % implicit_typing , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-typing' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"implicit-external\" , self % implicit_external , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-external' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"source-form\" , source_form , \"free\" , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'source-form' in fpm.toml, expecting logical\" ) return end if select case ( source_form ) case default call fatal_error ( error , \"Value of source-form cannot be '\" // source_form // \"'\" ) return case ( \"free\" , \"fixed\" , \"default\" ) self % source_form = source_form end select end subroutine new_fortran_config","tags":"","loc":"proc/new_fortran_config.html"},{"title":"new_build_config – Fortran-lang/fpm","text":"public subroutine new_build_config(self, table, package_name, error) Construct a new build configuration from a TOML data structure Module naming: fist, attempt boolean value first Value found, but not a boolean. Attempt to read a prefix string Arguments Type Intent Optional Attributes Name type( build_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: package_name Package name type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_build_config Source Code subroutine new_build_config ( self , table , package_name , error ) !> Instance of the build configuration type ( build_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Package name character ( len =* ), intent ( in ) :: package_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call check ( table , package_name , error ) if ( allocated ( error )) return call get_value ( table , \"auto-executables\" , self % auto_executables , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-executables' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-tests\" , self % auto_tests , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-tests' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-examples\" , self % auto_examples , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-examples' in fpm.toml, expecting logical\" ) return end if !> Module naming: fist, attempt boolean value first call get_value ( table , \"module-naming\" , self % module_naming , . false ., stat = stat ) if ( stat == toml_stat % success ) then ! Boolean value found. Set no custom prefix. This also falls back to ! key not provided self % module_prefix = string_t ( \"\" ) else !> Value found, but not a boolean. Attempt to read a prefix string call get_value ( table , \"module-naming\" , self % module_prefix % s ) if (. not . allocated ( self % module_prefix % s )) then call syntax_error ( error , \"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string\" ) return end if if (. not . is_valid_module_prefix ( self % module_prefix )) then call syntax_error ( error , \"Invalid custom module name prefix for in fpm.toml: <\" // self % module_prefix % s // & \">, expecting a valid alphanumeric string\" ) return end if ! Set module naming to ON self % module_naming = . true . end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return call get_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return end subroutine new_build_config","tags":"","loc":"proc/new_build_config.html"},{"title":"new_install_config – Fortran-lang/fpm","text":"public subroutine new_install_config(self, table, error) Create a new installation configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( install_config_t ), intent(out) :: self Instance of the install configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_install_config Source Code subroutine new_install_config ( self , table , error ) !> Instance of the install configuration type ( install_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"library\" , self % library , . false .) end subroutine new_install_config","tags":"","loc":"proc/new_install_config.html"},{"title":"new_preprocess_config – Fortran-lang/fpm","text":"public subroutine new_preprocess_config(self, table, error) Construct a new preprocess configuration from TOML data structure Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out) :: self Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure. type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_preprocess_config Source Code subroutine new_preprocess_config ( self , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), intent ( out ) :: self !> Instance of the TOML data structure. type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_list ( table , \"suffixes\" , self % suffixes , error ) if ( allocated ( error )) return call get_list ( table , \"directories\" , self % directories , error ) if ( allocated ( error )) return call get_list ( table , \"macros\" , self % macros , error ) if ( allocated ( error )) return end subroutine new_preprocess_config","tags":"","loc":"proc/new_preprocess_config.html"},{"title":"new_preprocessors – Fortran-lang/fpm","text":"public subroutine new_preprocessors(preprocessors, table, error) Construct new preprocess array from a TOML data structure. Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out), allocatable :: preprocessors (:) Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_preprocessors Source Code subroutine new_preprocessors ( preprocessors , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), allocatable , intent ( out ) :: preprocessors (:) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) integer :: iprep , stat call table % get_keys ( list ) ! An empty table is not allowed if ( size ( list ) == 0 ) then call syntax_error ( error , \"No preprocessors defined\" ) end if allocate ( preprocessors ( size ( list ))) do iprep = 1 , size ( list ) call get_value ( table , list ( iprep )% key , node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Preprocessor \" // list ( iprep )% key // \" must be a table entry\" ) exit end if call new_preprocess_config ( preprocessors ( iprep ), node , error ) if ( allocated ( error )) exit end do end subroutine new_preprocessors","tags":"","loc":"proc/new_preprocessors.html"},{"title":"operator(==) – Fortran-lang/fpm","text":"public interface operator(==) Contents Module Procedures preprocess_is_same Module Procedures private function preprocess_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: this class( preprocess_config_t ), intent(in) :: that Return Value logical","tags":"","loc":"interface/operator(==)~2.html"},{"title":"new_package – Fortran-lang/fpm","text":"public subroutine new_package(self, table, root, error) Construct a new package configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: self Instance of the package configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling Contents Source Code new_package Source Code subroutine new_package ( self , table , root , error ) !> Instance of the package configuration type ( package_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( len =* ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error ! Backspace (8), tabulator (9), newline (10), formfeed (12) and carriage ! return (13) are invalid in package names character ( len =* ), parameter :: invalid_chars = & achar ( 8 ) // achar ( 9 ) // achar ( 10 ) // achar ( 12 ) // achar ( 13 ) type ( toml_table ), pointer :: child , node type ( toml_array ), pointer :: children character ( len = :), allocatable :: version , version_file integer :: ii , nn , stat , io call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve package name\" ) return end if if ( bad_name_error ( error , 'package' , self % name )) then return endif call get_value ( table , \"license\" , self % license ) if ( len ( self % name ) <= 0 ) then call syntax_error ( error , \"Package name must be a non-empty string\" ) return end if ii = scan ( self % name , invalid_chars ) if ( ii > 0 ) then call syntax_error ( error , \"Package name contains invalid characters\" ) return end if call get_value ( table , \"build\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for build entry, must be a table\" ) return end if call new_build_config ( self % build , child , self % name , error ) if ( allocated ( error )) return call get_value ( table , \"install\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for install entry, must be a table\" ) return end if call new_install_config ( self % install , child , error ) if ( allocated ( error )) return call get_value ( table , \"fortran\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for fortran entry, must be a table\" ) return end if call new_fortran_config ( self % fortran , child , error ) if ( allocated ( error )) return call get_value ( table , \"version\" , version , \"0\" ) call new_version ( self % version , version , error ) if ( allocated ( error ) . and . present ( root )) then version_file = join_path ( root , version ) if ( exists ( version_file )) then deallocate ( error ) open ( file = version_file , newunit = io , iostat = stat ) if ( stat == 0 ) then call getline ( io , version , iostat = stat ) end if if ( stat == 0 ) then close ( io , iostat = stat ) end if if ( stat == 0 ) then call new_version ( self % version , version , error ) else call fatal_error ( error , \"Reading version number from file '\" & & // version_file // \"' failed\" ) end if end if end if if ( allocated ( error )) return call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , root , self % meta , error ) if ( allocated ( error )) return end if call get_value ( table , \"dev-dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dev_dependency , child , root , error = error ) if ( allocated ( error )) return end if call get_value ( table , \"library\" , child , requested = . false .) if ( associated ( child )) then allocate ( self % library ) call new_library ( self % library , child , error ) if ( allocated ( error )) return end if call get_value ( table , \"profiles\" , child , requested = . false .) if ( associated ( child )) then call new_profiles ( self % profiles , child , error ) if ( allocated ( error )) return else self % profiles = get_default_profiles ( error ) if ( allocated ( error )) return end if call get_value ( table , \"executable\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % executable ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve executable from array entry\" ) exit end if call new_executable ( self % executable ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % executable , error ) if ( allocated ( error )) return end if call get_value ( table , \"example\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % example ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve example from array entry\" ) exit end if call new_example ( self % example ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % example , error ) if ( allocated ( error )) return if ( allocated ( self % executable )) then call unique_programs ( self % executable , self % example , error ) if ( allocated ( error )) return end if end if call get_value ( table , \"test\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % test ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve test from array entry\" ) exit end if call new_test ( self % test ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % test , error ) if ( allocated ( error )) return end if call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return end if end subroutine new_package","tags":"","loc":"proc/new_package.html"},{"title":"get_default_profiles – Fortran-lang/fpm","text":"public function get_default_profiles(error) result(default_profiles) Construct an array of built-in profiles Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Error handling Return Value type( profile_config_t ), allocatable, (:) Contents Source Code get_default_profiles Source Code function get_default_profiles ( error ) result ( default_profiles ) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( profile_config_t ), allocatable :: default_profiles (:) default_profiles = [ & & new_profile ( 'release' , & & 'caf' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'gfortran' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'f95' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -ffast-math -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Mbackslash' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_ALL , & & flags = ' -fp-model precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl -standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_ALL , & & flags = ' -fp-model=precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl -standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nagfor' , & & OS_ALL , & & flags = ' -O4 -coarray=single -PIC' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'lfortran' , & & OS_ALL , & & flags = ' flag_lfortran_opt' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'caf' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'gfortran' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'f95' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -Wno-maybe-uninitialized -Wno-uninitialized -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Minform=inform -Mbackslash -g -Mbounds -Mchkptr -Mchkstk -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -standard-semantics -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1& & /Od /Z7 /assume:byterecl /standard-semantics /traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -standard-semantics -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'lfortran' , & & OS_ALL , & & flags = '' , & & is_built_in = . true .) & &] end function get_default_profiles","tags":"","loc":"proc/get_default_profiles.html"},{"title":"info_profile – Fortran-lang/fpm","text":"public function info_profile(profile) result(s) Print a representation of profile_config_t Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in) :: profile Profile to be represented Return Value character(len=:), allocatable String representation of given profile Contents Variables i Source Code info_profile Variables Type Visibility Attributes Name Initial integer, public :: i Source Code function info_profile ( profile ) result ( s ) !> Profile to be represented type ( profile_config_t ), intent ( in ) :: profile !> String representation of given profile character (:), allocatable :: s integer :: i s = \"profile_config_t(\" s = s // 'profile_name=\"' // profile % profile_name // '\"' s = s // ', compiler=\"' // profile % compiler // '\"' s = s // \", os_type=\" select case ( profile % os_type ) case ( OS_UNKNOWN ) s = s // \"OS_UNKNOWN\" case ( OS_LINUX ) s = s // \"OS_LINUX\" case ( OS_MACOS ) s = s // \"OS_MACOS\" case ( OS_WINDOWS ) s = s // \"OS_WINDOWS\" case ( OS_CYGWIN ) s = s // \"OS_CYGWIN\" case ( OS_SOLARIS ) s = s // \"OS_SOLARIS\" case ( OS_FREEBSD ) s = s // \"OS_FREEBSD\" case ( OS_OPENBSD ) s = s // \"OS_OPENBSD\" case ( OS_ALL ) s = s // \"OS_ALL\" case default s = s // \"INVALID\" end select if ( allocated ( profile % flags )) s = s // ', flags=\"' // profile % flags // '\"' if ( allocated ( profile % c_flags )) s = s // ', c_flags=\"' // profile % c_flags // '\"' if ( allocated ( profile % cxx_flags )) s = s // ', cxx_flags=\"' // profile % cxx_flags // '\"' if ( allocated ( profile % link_time_flags )) s = s // ', link_time_flags=\"' // profile % link_time_flags // '\"' if ( allocated ( profile % file_scope_flags )) then do i = 1 , size ( profile % file_scope_flags ) s = s // ', flags for ' // profile % file_scope_flags ( i )% file_name // & & ' =\"' // profile % file_scope_flags ( i )% flags // '\"' end do end if s = s // \")\" end function info_profile","tags":"","loc":"proc/info_profile.html"},{"title":"new_profile – Fortran-lang/fpm","text":"public function new_profile(profile_name, compiler, os_type, flags, c_flags, cxx_flags, link_time_flags, file_scope_flags, is_built_in) result(profile) Construct a new profile configuration from a TOML data structure Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: profile_name Name of the profile character(len=*), intent(in) :: compiler Name of the compiler integer, intent(in) :: os_type Type of the OS character(len=*), intent(in), optional :: flags Fortran compiler flags character(len=*), intent(in), optional :: c_flags C compiler flags character(len=*), intent(in), optional :: cxx_flags C++ compiler flags character(len=*), intent(in), optional :: link_time_flags Link time compiler flags type( file_scope_flag ), intent(in), optional :: file_scope_flags (:) File scope flags logical, intent(in), optional :: is_built_in Is this profile one of the built-in ones? Return Value type( profile_config_t ) Contents Source Code new_profile Source Code function new_profile ( profile_name , compiler , os_type , flags , c_flags , cxx_flags , & link_time_flags , file_scope_flags , is_built_in ) & & result ( profile ) !> Name of the profile character ( len =* ), intent ( in ) :: profile_name !> Name of the compiler character ( len =* ), intent ( in ) :: compiler !> Type of the OS integer , intent ( in ) :: os_type !> Fortran compiler flags character ( len =* ), optional , intent ( in ) :: flags !> C compiler flags character ( len =* ), optional , intent ( in ) :: c_flags !> C++ compiler flags character ( len =* ), optional , intent ( in ) :: cxx_flags !> Link time compiler flags character ( len =* ), optional , intent ( in ) :: link_time_flags !> File scope flags type ( file_scope_flag ), optional , intent ( in ) :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical , optional , intent ( in ) :: is_built_in type ( profile_config_t ) :: profile profile % profile_name = profile_name profile % compiler = compiler profile % os_type = os_type if ( present ( flags )) then profile % flags = flags else profile % flags = \"\" end if if ( present ( c_flags )) then profile % c_flags = c_flags else profile % c_flags = \"\" end if if ( present ( cxx_flags )) then profile % cxx_flags = cxx_flags else profile % cxx_flags = \"\" end if if ( present ( link_time_flags )) then profile % link_time_flags = link_time_flags else profile % link_time_flags = \"\" end if if ( present ( file_scope_flags )) then profile % file_scope_flags = file_scope_flags end if if ( present ( is_built_in )) then profile % is_built_in = is_built_in else profile % is_built_in = . false . end if end function new_profile","tags":"","loc":"proc/new_profile.html"},{"title":"find_profile – Fortran-lang/fpm","text":"public subroutine find_profile(profiles, profile_name, compiler, os_type, found_matching, chosen_profile) Look for profile with given configuration in array profiles Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in), allocatable :: profiles (:) Array of profiles character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler Name of compiler integer, intent(in) :: os_type Type of operating system (enum) logical, intent(out) :: found_matching Boolean value containing true if matching profile was found type( profile_config_t ), intent(out) :: chosen_profile Last matching profile in the profiles array Contents Variables curr_compiler curr_os curr_priority curr_profile_name i priority Source Code find_profile Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: curr_compiler integer, public :: curr_os integer, public :: curr_priority character(len=:), public, allocatable :: curr_profile_name integer, public :: i integer, public :: priority Source Code subroutine find_profile ( profiles , profile_name , compiler , os_type , found_matching , chosen_profile ) !> Array of profiles type ( profile_config_t ), allocatable , intent ( in ) :: profiles (:) !> Name of profile character (:), allocatable , intent ( in ) :: profile_name !> Name of compiler character (:), allocatable , intent ( in ) :: compiler !> Type of operating system (enum) integer , intent ( in ) :: os_type !> Boolean value containing true if matching profile was found logical , intent ( out ) :: found_matching !> Last matching profile in the profiles array type ( profile_config_t ), intent ( out ) :: chosen_profile character (:), allocatable :: curr_profile_name character (:), allocatable :: curr_compiler integer :: curr_os integer :: i , priority , curr_priority found_matching = . false . if ( size ( profiles ) < 1 ) return ! Try to find profile with matching OS type do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . os_type ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do ! Try to find profile with OS type 'all' if (. not . found_matching ) then do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . OS_ALL ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do end if end subroutine find_profile","tags":"","loc":"proc/find_profile.html"},{"title":"get_flags – Fortran-lang/fpm","text":"public subroutine get_flags(profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid) Look for flags, c-flags, link-time-flags key-val pairs\nand files table in a given table and create new profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler integer, intent(in) :: os_type OS type type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles logical, intent(in) :: os_valid Was called with valid operating system Contents Variables c_flags cxx_flags err_message file_flags file_list file_name file_scope_flags files flags ifile ikey is_valid key_name link_time_flags stat Source Code get_flags Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags character(len=:), public, allocatable :: cxx_flags character(len=:), public, allocatable :: err_message character(len=:), public, allocatable :: file_flags type(toml_key), public, allocatable :: file_list (:) character(len=:), public, allocatable :: file_name type( file_scope_flag ), public, allocatable :: file_scope_flags (:) type(toml_table), public, pointer :: files character(len=:), public, allocatable :: flags integer, public :: ifile integer, public :: ikey logical, public :: is_valid character(len=:), public, allocatable :: key_name character(len=:), public, allocatable :: link_time_flags integer, public :: stat Source Code subroutine get_flags ( profile_name , compiler_name , os_type , key_list , table , profiles , profindex , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> OS type integer , intent ( in ) :: os_type !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) type ( file_scope_flag ), allocatable :: file_scope_flags (:) integer :: ikey , ifile , stat logical :: is_valid call get_value ( table , 'flags' , flags ) call get_value ( table , 'c-flags' , c_flags ) call get_value ( table , 'cxx-flags' , cxx_flags ) call get_value ( table , 'link-time-flags' , link_time_flags ) call get_value ( table , 'files' , files ) if ( associated ( files )) then call files % get_keys ( file_list ) allocate ( file_scope_flags ( size ( file_list ))) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags ) associate ( cur_file => file_scope_flags ( ifile )) if (. not .( path . eq . \"\" )) file_name = join_path ( path , file_name ) cur_file % file_name = file_name cur_file % flags = file_flags end associate end do end if profiles ( profindex ) = new_profile ( profile_name , compiler_name , os_type , & & flags , c_flags , cxx_flags , link_time_flags , file_scope_flags ) profindex = profindex + 1 end subroutine get_flags","tags":"","loc":"proc/get_flags.html"},{"title":"info – Fortran-lang/fpm","text":"public subroutine info(self, unit, verbosity) Write information on instance Type Bound profile_config_t Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: self Instance of the profile configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Contents Variables fmt pr Source Code info Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: fmt = '(\"#\", 1x, a, t30, a)' integer, public :: pr Source Code subroutine info ( self , unit , verbosity ) !> Instance of the profile configuration class ( profile_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if write ( unit , fmt ) \"Profile\" if ( allocated ( self % profile_name )) then write ( unit , fmt ) \"- profile name\" , self % profile_name end if if ( allocated ( self % compiler )) then write ( unit , fmt ) \"- compiler\" , self % compiler end if write ( unit , fmt ) \"- os\" , self % os_type if ( allocated ( self % flags )) then write ( unit , fmt ) \"- compiler flags\" , self % flags end if end subroutine info","tags":"","loc":"proc/info~12.html"},{"title":"match_os_type – Fortran-lang/fpm","text":"public subroutine match_os_type(os_name, os_type) Match os_type enum to a lowercase string with name of OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of operating system integer, intent(out) :: os_type Enum representing type of OS Contents Source Code match_os_type Source Code subroutine match_os_type ( os_name , os_type ) !> Name of operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Enum representing type of OS integer , intent ( out ) :: os_type select case ( os_name ) case ( \"linux\" ); os_type = OS_LINUX case ( \"macos\" ); os_type = OS_WINDOWS case ( \"cygwin\" ); os_type = OS_CYGWIN case ( \"solaris\" ); os_type = OS_SOLARIS case ( \"freebsd\" ); os_type = OS_FREEBSD case ( \"openbsd\" ); os_type = OS_OPENBSD case ( \"all\" ); os_type = OS_ALL case default ; os_type = OS_UNKNOWN end select end subroutine match_os_type","tags":"","loc":"proc/match_os_type.html"},{"title":"new_profiles – Fortran-lang/fpm","text":"public subroutine new_profiles(profiles, table, error) Construct new profiles array from a TOML data structure Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(out), allocatable :: profiles (:) Instance of the dependency configuration type(toml_table), intent(inout), target :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Contents Variables comp_list compiler_name default_profiles iprof is_valid os_list prof_list prof_node profile_name profiles_size profindex stat Source Code new_profiles Variables Type Visibility Attributes Name Initial type(toml_key), public, allocatable :: comp_list (:) character(len=:), public, allocatable :: compiler_name type( profile_config_t ), public, allocatable :: default_profiles (:) integer, public :: iprof logical, public :: is_valid type(toml_key), public, allocatable :: os_list (:) type(toml_key), public, allocatable :: prof_list (:) type(toml_table), public, pointer :: prof_node character(len=:), public, allocatable :: profile_name integer, public :: profiles_size integer, public :: profindex integer, public :: stat Source Code subroutine new_profiles ( profiles , table , error ) !> Instance of the dependency configuration type ( profile_config_t ), allocatable , intent ( out ) :: profiles (:) !> Instance of the TOML data structure type ( toml_table ), target , intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: prof_node type ( toml_key ), allocatable :: prof_list (:) type ( toml_key ), allocatable :: comp_list (:) type ( toml_key ), allocatable :: os_list (:) character ( len = :), allocatable :: profile_name , compiler_name integer :: profiles_size , iprof , stat , profindex logical :: is_valid type ( profile_config_t ), allocatable :: default_profiles (:) path = '' default_profiles = get_default_profiles ( error ) if ( allocated ( error )) return call table % get_keys ( prof_list ) if ( size ( prof_list ) < 1 ) return profiles_size = 0 do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER call traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Profile \" // prof_list ( iprof )% key // \" must be a table entry\" ) exit end if call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return end if end if end do profiles_size = profiles_size + size ( default_profiles ) allocate ( profiles ( profiles_size )) do profindex = 1 , size ( default_profiles ) profiles ( profindex ) = default_profiles ( profindex ) end do do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER prof_node => table call traverse_oss ( profile_name , compiler_name , os_list , prof_node , profiles , profindex , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return end if end if end do ! Apply profiles with profile name 'all' to matching profiles do iprof = 1 , size ( profiles ) if ( profiles ( iprof )% profile_name . eq . 'all' ) then do profindex = 1 , size ( profiles ) if (. not .( profiles ( profindex )% profile_name . eq . 'all' ) & & . and .( profiles ( profindex )% compiler . eq . profiles ( iprof )% compiler ) & & . and .( profiles ( profindex )% os_type . eq . profiles ( iprof )% os_type )) then profiles ( profindex )% flags = profiles ( profindex )% flags // & & \" \" // profiles ( iprof )% flags profiles ( profindex )% c_flags = profiles ( profindex )% c_flags // & & \" \" // profiles ( iprof )% c_flags profiles ( profindex )% cxx_flags = profiles ( profindex )% cxx_flags // & & \" \" // profiles ( iprof )% cxx_flags profiles ( profindex )% link_time_flags = profiles ( profindex )% link_time_flags // & & \" \" // profiles ( iprof )% link_time_flags end if end do end if end do end subroutine new_profiles","tags":"","loc":"proc/new_profiles.html"},{"title":"traverse_compilers – Fortran-lang/fpm","text":"public subroutine traverse_compilers(profile_name, comp_list, table, error, profiles_size, profiles, profindex) Traverse compiler tables Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile type(toml_key), intent(in), allocatable :: comp_list (:) List of OSs in table with profile name given type(toml_table), intent(in), pointer :: table Table containing compiler tables type( error_t ), intent(out), allocatable :: error Error handling integer, intent(inout), optional :: profiles_size Number of profiles in list of profiles type( profile_config_t ), intent(inout), optional, allocatable :: profiles (:) List of profiles integer, intent(inout), optional :: profindex Index in the list of profiles Contents Variables comp_node compiler_name icomp is_valid os_list stat Source Code traverse_compilers Variables Type Visibility Attributes Name Initial type(toml_table), public, pointer :: comp_node character(len=:), public, allocatable :: compiler_name integer, public :: icomp logical, public :: is_valid type(toml_key), public, allocatable :: os_list (:) integer, public :: stat Source Code subroutine traverse_compilers ( profile_name , comp_list , table , error , profiles_size , profiles , profindex ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> List of OSs in table with profile name given type ( toml_key ), allocatable , intent ( in ) :: comp_list (:) !> Table containing compiler tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ), optional :: profiles_size !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ), optional :: profiles (:) !> Index in the list of profiles integer , intent ( inout ), optional :: profindex character ( len = :), allocatable :: compiler_name type ( toml_table ), pointer :: comp_node type ( toml_key ), allocatable :: os_list (:) integer :: icomp , stat logical :: is_valid if ( size ( comp_list ) < 1 ) return do icomp = 1 , size ( comp_list ) call validate_compiler_name ( comp_list ( icomp )% key , is_valid ) if ( is_valid ) then compiler_name = comp_list ( icomp )% key call get_value ( table , compiler_name , comp_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Compiler \" // comp_list ( icomp )% key // \" must be a table entry\" ) exit end if call comp_node % get_keys ( os_list ) if ( present ( profiles_size )) then call traverse_oss_for_size ( profile_name , compiler_name , os_list , comp_node , profiles_size , error ) if ( allocated ( error )) return else if (. not .( present ( profiles ). and . present ( profindex ))) then call fatal_error ( error , \"Both profiles and profindex have to be present\" ) return end if call traverse_oss ( profile_name , compiler_name , os_list , comp_node , & & profiles , profindex , error ) if ( allocated ( error )) return end if else call fatal_error ( error , '*traverse_compilers*:Error: Compiler name not specified or invalid.' ) end if end do end subroutine traverse_compilers","tags":"","loc":"proc/traverse_compilers.html"},{"title":"traverse_oss – Fortran-lang/fpm","text":"public subroutine traverse_oss(profile_name, compiler_name, os_list, table, profiles, profindex, error) Traverse operating system tables to obtain profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles type( error_t ), intent(out), allocatable :: error Error handling Contents Variables ios is_key_val is_valid key_list l_os_name os_name os_node os_type stat Source Code traverse_oss Variables Type Visibility Attributes Name Initial integer, public :: ios logical, public :: is_key_val logical, public :: is_valid type(toml_key), public, allocatable :: key_list (:) character(len=:), public, allocatable :: l_os_name character(len=:), public, allocatable :: os_name type(toml_table), public, pointer :: os_node integer, public :: os_type integer, public :: stat Source Code subroutine traverse_oss ( profile_name , compiler_name , os_list , table , profiles , profindex , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat , os_type logical :: is_valid , is_key_val if ( size ( os_list ) < 1 ) return do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) call match_os_type ( os_name , os_type ) call get_flags ( profile_name , compiler_name , os_type , key_list , os_node , profiles , profindex , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table os_type = OS_ALL call get_flags ( profile_name , compiler_name , os_type , os_list , os_node , profiles , profindex , . false .) end if end do end subroutine traverse_oss","tags":"","loc":"proc/traverse_oss.html"},{"title":"traverse_oss_for_size – Fortran-lang/fpm","text":"public subroutine traverse_oss_for_size(profile_name, compiler_name, os_list, table, profiles_size, error) Traverse operating system tables to obtain number of profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables integer, intent(inout) :: profiles_size Number of profiles in list of profiles type( error_t ), intent(out), allocatable :: error Error handling Contents Variables ios is_key_val is_valid key_list key_val_added l_os_name os_name os_node stat Source Code traverse_oss_for_size Variables Type Visibility Attributes Name Initial integer, public :: ios logical, public :: is_key_val logical, public :: is_valid type(toml_key), public, allocatable :: key_list (:) logical, public :: key_val_added character(len=:), public, allocatable :: l_os_name character(len=:), public, allocatable :: os_name type(toml_table), public, pointer :: os_node integer, public :: stat Source Code subroutine traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ) :: profiles_size type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat logical :: is_valid , key_val_added , is_key_val if ( size ( os_list ) < 1 ) return key_val_added = . false . do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) profiles_size = profiles_size + 1 call validate_profile_table ( profile_name , compiler_name , key_list , os_node , error , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table if ( is_key_val . and .. not . key_val_added ) then key_val_added = . true . is_key_val = . false . profiles_size = profiles_size + 1 else if (. not . is_key_val ) then profiles_size = profiles_size + 1 end if call validate_profile_table ( profile_name , compiler_name , os_list , os_node , error , . false .) end if end do end subroutine traverse_oss_for_size","tags":"","loc":"proc/traverse_oss_for_size.html"},{"title":"validate_compiler_name – Fortran-lang/fpm","text":"public subroutine validate_compiler_name(compiler_name, is_valid) Check if compiler name is a valid compiler name Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: compiler_name Name of a compiler logical, intent(out) :: is_valid Boolean value of whether compiler_name is valid or not Contents Source Code validate_compiler_name Source Code subroutine validate_compiler_name ( compiler_name , is_valid ) !> Name of a compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> Boolean value of whether compiler_name is valid or not logical , intent ( out ) :: is_valid select case ( compiler_name ) case ( \"gfortran\" , \"ifort\" , \"ifx\" , \"pgfortran\" , \"nvfortran\" , \"flang\" , \"caf\" , & & \"f95\" , \"lfortran\" , \"lfc\" , \"nagfor\" , \"crayftn\" , \"xlf90\" , \"ftn95\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_compiler_name","tags":"","loc":"proc/validate_compiler_name.html"},{"title":"validate_os_name – Fortran-lang/fpm","text":"public subroutine validate_os_name(os_name, is_valid) Check if os_name is a valid name of a supported OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of an operating system logical, intent(out) :: is_valid Boolean value of whether os_name is valid or not Contents Source Code validate_os_name Source Code subroutine validate_os_name ( os_name , is_valid ) !> Name of an operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Boolean value of whether os_name is valid or not logical , intent ( out ) :: is_valid select case ( os_name ) case ( \"linux\" , \"macos\" , \"windows\" , \"cygwin\" , \"solaris\" , \"freebsd\" , & & \"openbsd\" , \"unknown\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_os_name","tags":"","loc":"proc/validate_os_name.html"},{"title":"validate_profile_table – Fortran-lang/fpm","text":"public subroutine validate_profile_table(profile_name, compiler_name, key_list, table, error, os_valid) Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in) :: os_valid Was called with valid operating system Contents Variables c_flags cxx_flags err_message file_flags file_list file_name files flags ifile ikey is_valid key_name link_time_flags stat Source Code validate_profile_table Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags character(len=:), public, allocatable :: cxx_flags character(len=:), public, allocatable :: err_message character(len=:), public, allocatable :: file_flags type(toml_key), public, allocatable :: file_list (:) character(len=:), public, allocatable :: file_name type(toml_table), public, pointer :: files character(len=:), public, allocatable :: flags integer, public :: ifile integer, public :: ikey logical, public :: is_valid character(len=:), public, allocatable :: key_name character(len=:), public, allocatable :: link_time_flags integer, public :: stat Source Code subroutine validate_profile_table ( profile_name , compiler_name , key_list , table , error , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) integer :: ikey , ifile , stat logical :: is_valid if ( size ( key_list ). ge . 1 ) then do ikey = 1 , size ( key_list ) key_name = key_list ( ikey )% key if ( key_name . eq . 'flags' ) then call get_value ( table , 'flags' , flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'c-flags' ) then call get_value ( table , 'c-flags' , c_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"c-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'cxx-flags' ) then call get_value ( table , 'cxx-flags' , cxx_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"cxx-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'link-time-flags' ) then call get_value ( table , 'link-time-flags' , link_time_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"link-time-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'files' ) then call get_value ( table , 'files' , files , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"files has to be a table\" ) return end if call files % get_keys ( file_list ) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"file scope flags has to be a key-value pair\" ) return end if end do else if (. not . os_valid ) then call validate_os_name ( key_name , is_valid ) err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" if (. not . is_valid ) call syntax_error ( error , err_message ) else err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" call syntax_error ( error , err_message ) end if end do end if if ( allocated ( error )) return end subroutine validate_profile_table","tags":"","loc":"proc/validate_profile_table.html"},{"title":"cmd_publish – Fortran-lang/fpm","text":"public subroutine cmd_publish(settings) The publish command first builds the root package to obtain all the relevant information such as the\npackage version. It then creates a tarball of the package and uploads it to the registry.\nChecks before uploading the package. Arguments Type Intent Optional Attributes Name type( fpm_publish_settings ), intent(inout) :: settings Contents","tags":"","loc":"proc/cmd_publish.html"},{"title":"cmd_new – Fortran-lang/fpm","text":"public subroutine cmd_new(settings) TOP DIRECTORY NAME PROCESSING\nsee if requested new directory already exists and process appropriately\ntemporarily change to new directory as a test. NB: System dependent Arguments Type Intent Optional Attributes Name type( fpm_new_settings ), intent(in) :: settings Contents Source Code cmd_new Source Code subroutine cmd_new ( settings ) type ( fpm_new_settings ), intent ( in ) :: settings integer , parameter :: tfc = selected_char_kind ( 'DEFAULT' ) character ( len = :, kind = tfc ), allocatable :: bname ! baeename of NAME character ( len = :, kind = tfc ), allocatable :: tomlfile (:) character ( len = :, kind = tfc ), allocatable :: littlefile (:) !> TOP DIRECTORY NAME PROCESSING !> see if requested new directory already exists and process appropriately if ( exists ( settings % name ) . and . . not . settings % backfill ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists.' write ( stderr , '(*(g0,1x))' )& & ' perhaps you wanted to add --backfill ?' return elseif ( is_dir ( settings % name ) . and . settings % backfill ) then write ( * , '(*(g0))' ) 'backfilling ' , settings % name elseif ( exists ( settings % name ) ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists and is not a directory.' return else ! make new directory call mkdir ( settings % name ) endif !> temporarily change to new directory as a test. NB: System dependent call run ( 'cd ' // settings % name ) ! NOTE: need some system routines to handle filenames like \".\" ! like realpath() or getcwd(). bname = basename ( settings % name ) littlefile = [ character ( len = 80 ) :: '# ' // bname , 'My cool new project!' ] ! create NAME/README.md call warnwrite ( join_path ( settings % name , 'README.md' ), littlefile ) ! start building NAME/fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: & & ' # This is your fpm(Fortran Package Manager) manifest file ' ,& & ' # (\"fpm.toml\"). It is heavily annotated to help guide you though ' ,& & ' # customizing a package build, although the defaults are sufficient ' ,& & ' # for many basic packages. ' ,& & ' # ' ,& & ' # The manifest file is not only used to provide metadata identifying ' ,& & ' # your project (so it can be used by others as a dependency). It can ' ,& & ' # specify where your library and program sources live, what the name ' ,& & ' # of the executable(s) will be, what files to build, dependencies on ' ,& & ' # other fpm packages, and what external libraries are required. ' ,& & ' # ' ,& & ' # The manifest format must conform to the TOML configuration file ' ,& & ' # standard. ' ,& & ' # ' ,& & ' # TOML files support flexible use of white-space and commenting of the ' ,& & ' # configuration data, but for clarity in this sample active directives ' ,& & ' # begin in column one. Inactive example directives are commented ' ,& & ' # out with a pound character (\"#\") but begin in column one as well. ' ,& & ' # Commentary begins with a pound character in column three. ' ,& & ' # ' ,& & ' # This file draws heavily upon the following references: ' ,& & ' # ' ,& & ' # The fpm home page at ' ,& & ' # https://github.com/fortran-lang/fpm ' ,& & ' # A complete list of keys and their attributes at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/manifest-reference.md ' ,& & ' # examples of fpm project packaging at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/PACKAGING.md ' ,& & ' # The Fortran TOML file interface and it''s references at ' ,& & ' # https://github.com/toml-f/toml-f ' ,& & ' # ' ,& & ' #----------------------- ' ,& & ' # project Identification ' ,& & ' #----------------------- ' ,& & ' # We begin with project metadata at the manifest root. This data is designed ' ,& & ' # to aid others when searching for the project in a repository and to ' ,& & ' # identify how and when to contact the package supporters. ' ,& & ' ' ,& & 'name = \"' // bname // '\"' ,& & ' # The project name (required) is how the project will be referred to. ' ,& & ' # The name is used by other packages using it as a dependency. It also ' ,& & ' # is used as the default name of any library built and the optional ' ,& & ' # default executable built from app/main.f90. It must conform to the rules ' ,& & ' # for a Fortran variable name. ' ,& & ' ' ,& & 'version = \"0.1.0\" ' ,& & ' # The project version number is a string. A recommended scheme for ' ,& & ' # specifying versions is the Semantic Versioning scheme. ' ,& & ' ' ,& & 'license = \"license\" ' ,& & ' # Licensing information specified using SPDX identifiers is preferred ' ,& & ' # (eg. \"Apache-2.0 OR MIT\" or \"LGPL-3.0-or-later\"). ' ,& & ' ' ,& & 'maintainer = \"jane.doe@example.com\" ' ,& & ' # Information on the project maintainer and means to reach out to them. ' ,& & ' ' ,& & 'author = \"Jane Doe\" ' ,& & ' # Information on the project author. ' ,& & ' ' ,& & 'copyright = \"Copyright 2020 Jane Doe\" ' ,& & ' # A statement clarifying the Copyright status of the project. ' ,& & ' ' ,& & '#description = \"A short project summary in plain text\" ' ,& & ' # The description provides a short summary on the project. It should be ' ,& & ' # plain text and not use any markup formatting. ' ,& & ' ' ,& & '#categories = [\"fortran\", \"graphics\"] ' ,& & ' # Categories associated with the project. Listing only one is preferred. ' ,& & ' ' ,& & '#keywords = [\"hdf5\", \"mpi\"] ' ,& & ' # The keywords field is an array of strings describing the project. ' ,& & ' ' ,& & '#homepage = \"https://stdlib.fortran-lang.org\" ' ,& & ' # URL to the webpage of the project. ' ,& & ' ' ,& & ' # ----------------------------------------- ' ,& & ' # We are done with identifying the project. ' ,& & ' # ----------------------------------------- ' ,& & ' # ' ,& & ' # Now lets start describing how the project should be built. ' ,& & ' # ' ,& & ' # Note tables would go here but we will not be talking about them (much)!!' ,& & ' # ' ,& & ' # Tables are a way to explicitly specify large numbers of programs in ' ,& & ' # a compact format instead of individual per-program entries in the ' ,& & ' # [[executable]], [[test]], and [[example]] sections to follow but ' ,& & ' # will not be discussed further except for the following notes: ' ,& & ' # ' ,& & ' # + Tables must appear (here) before any sections are declared. Once a ' ,& & ' # section is specified in a TOML file everything afterwards must be ' ,& & ' # values for that section or the beginning of a new section. A simple ' ,& & ' # example looks like: ' ,& & ' ' ,& & '#executable = [ ' ,& & '# { name = \"a-prog\" }, ' ,& & '# { name = \"app-tool\", source-dir = \"tool\" }, ' ,& & '# { name = \"fpm-man\", source-dir = \"tool\", main=\"fman.f90\" } ' ,& & '#] ' ,& & ' ' ,& & ' # This would be in lieue of the [[executable]] section found later in this ' ,& & ' # configuration file. ' ,& & ' # + See the reference documents (at the beginning of this document) ' ,& & ' # for more information on tables if you have long lists of programs ' ,& & ' # to build and are not simply depending on auto-detection. ' ,& & ' # ' ,& & ' # Now lets begin the TOML sections (lines beginning with \"[\") ... ' ,& & ' # ' ,& & ' ' ,& & '[install] # Options for the \"install\" subcommand ' ,& & ' ' ,& & ' # When you run the \"install\" subcommand only executables are installed by ' ,& & ' # default on the local system. Library projects that will be used outside of ' ,& & ' # \"fpm\" can set the \"library\" boolean to also allow installing the module ' ,& & ' # files and library archive. Without this being set to \"true\" an \"install\" ' ,& & ' # subcommand ignores parameters that specify library installation. ' ,& & ' ' ,& & 'library = false ' ,& & ' ' ,& & '[build] # General Build Options ' ,& & ' ' ,& & ' ### Automatic target discovery ' ,& & ' # ' ,& & ' # Normally fpm recursively searches the app/, example/, and test/ directories ' ,& & ' # for program sources and builds them. To disable this automatic discovery of ' ,& & ' # program targets set the following to \"false\": ' ,& & ' ' ,& & '#auto-executables = true ' ,& & '#auto-examples = true ' ,& & '#auto-tests = true ' ,& & ' ' ,& & ' ### Package-level External Library Links ' ,& & ' # ' ,& & ' # To declare link-time dependencies on external libraries a list of ' ,& & ' # native libraries can be specified with the \"link\" entry. You may ' ,& & ' # have one library name or a list of strings in case several ' ,& & ' # libraries should be linked. This list of library dependencies is ' ,& & ' # exported to dependent packages. You may have to alter your library ' ,& & ' # search-path to ensure the libraries can be accessed. Typically, ' ,& & ' # this is done with the LD_LIBRARY_PATH environment variable on ULS ' ,& & ' # (Unix-Like Systems). You only specify the core name of the library ' ,& & ' # (as is typical with most programming environments, where you ' ,& & ' # would specify \"-lz\" on your load command to link against the zlib ' ,& & ' # compression library even though the library file would typically be ' ,& & ' # a file called \"libz.a\" \"or libz.so\"). So to link against that library ' ,& & ' # you would specify: ' ,& & ' ' ,& & '#link = \"z\" ' ,& & ' ' ,& & ' # Note that in some cases the order of the libraries matters: ' ,& & ' ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_lib ) then call mkdir ( join_path ( settings % name , 'src' ) ) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[library] ' ,& & ' ' ,& & ' # You can change the name of the directory to search for your library ' ,& & ' # source from the default of \"src/\". Library targets are exported ' ,& & ' # and usable by other projects. ' ,& & ' ' ,& & 'source-dir=\"src\" ' ,& & ' ' ,& & ' # this can be a list: ' ,& & ' ' ,& & '#source-dir=[\"src\", \"src2\"] ' ,& & ' ' ,& & ' # More complex libraries may organize their modules in subdirectories. ' ,& & ' # For modules in a top-level directory fpm requires (but does not ' ,& & ' # enforce) that: ' ,& & ' # ' ,& & ' # + The module has the same name as the source file. This is important. ' ,& & ' # + There should be only one module per file. ' ,& & ' # ' ,& & ' # These two requirements simplify the build process for fpm. As Fortran ' ,& & ' # compilers emit module files (.mod) with the same name as the module ' ,& & ' # itself (but not the source file, .f90), naming the module the same ' ,& & ' # as the source file allows fpm to: ' ,& & ' # ' ,& & ' # + Uniquely and exactly map a source file (.f90) to its object (.o) ' ,& & ' # and module (.mod) files. ' ,& & ' # + Avoid conflicts with modules of the same name that could appear ' ,& & ' # in dependency packages. ' ,& & ' # ' ,& & ' ### Multi-level library source ' ,& & ' # You can place your module source files in any number of levels of ' ,& & ' # subdirectories inside your source directory, but there are certain naming ' ,& & ' # conventions to be followed -- module names must contain the path components ' ,& & ' # of the directory that its source file is in. ' ,& & ' # ' ,& & ' # This rule applies generally to any number of nested directories and ' ,& & ' # modules. For example, src/a/b/c/d.f90 must define a module called a_b_c_d. ' ,& & ' # Again, this is not enforced but may be required in future releases. ' ,& & '' ] endif ! create placeholder module src/bname.f90 littlefile = [ character ( len = 80 ) :: & & 'module ' // to_fortran_name ( bname ), & & ' implicit none' , & & ' private' , & & '' , & & ' public :: say_hello' , & & 'contains' , & & ' subroutine say_hello' , & & ' print *, \"Hello, ' // bname // '!\"' , & & ' end subroutine say_hello' , & & 'end module ' // to_fortran_name ( bname )] ! create NAME/src/NAME.f90 call warnwrite ( join_path ( settings % name , 'src' , bname // '.f90' ),& & littlefile ) endif if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[dependencies] ' ,& & ' ' ,& & ' # Inevitably, you will want to be able to include other packages in ' ,& & ' # a project. Fpm makes this incredibly simple, by taking care of ' ,& & ' # fetching and compiling your dependencies for you. You just tell it ' ,& & ' # what your dependencies names are, and where to find them. ' ,& & ' # ' ,& & ' # If you are going to distribute your package only place dependencies ' ,& & ' # here someone using your package as a remote dependency needs built. ' ,& & ' # You can define dependencies just for developer executables in the ' ,& & ' # next section, or even for specific executables as we will see below ' ,& & ' # (Then fpm will still fetch and compile it when building your ' ,& & ' # developer executables, but users of your library will not have to). ' ,& & ' # ' ,& & ' ## GLOBAL DEPENDENCIES (exported with your project) ' ,& & ' # ' ,& & ' # Typically, dependencies are defined by specifying the project''s ' ,& & ' # git repository. ' ,& & ' # ' ,& & ' # You can be specific about which version of a dependency you would ' ,& & ' # like. By default the latest default branch is used. You can ' ,& & ' # optionally specify a branch, a tag or a commit value. ' ,& & ' # ' ,& & ' # So here are several alternates for specifying a remote dependency (you ' ,& & ' # can have at most one of \"branch\", \"rev\" or \"tag\" present): ' ,& & ' ' ,& & '#stdlib = { git = \"https://github.com/LKedward/stdlib-fpm.git\" } ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\",branch = \"master\" },' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", tag = \"v0.1.0\" }, ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", rev = \"5a9b7a8\" }. ' ,& & ' ' ,& & ' # There may be multiple packages listed: ' ,& & ' ' ,& & '#M_strings = { git = \"https://github.com/urbanjost/M_strings.git\" } ' ,& & '#M_time = { git = \"https://github.com/urbanjost/M_time.git\" } ' ,& & ' ' ,& & ' # ' ,& & ' # You can even specify the local path to another project if it is in ' ,& & ' # a sub-folder (If for example you have got another fpm package **in ' ,& & ' # the same repository**) like this: ' ,& & ' ' ,& & '#M_strings = { path = \"M_strings\" } ' ,& & ' ' ,& & ' # This tells fpm that we depend on a crate called M_strings which is found ' ,& & ' # in the M_strings folder (relative to the fpm.toml it’s written in). ' ,& & ' # ' ,& & ' # For a more verbose layout use normal tables rather than inline tables ' ,& & ' # to specify dependencies: ' ,& & ' ' ,& & '#[dependencies.toml-f] ' ,& & '#git = \"https://github.com/toml-f/toml-f\" ' ,& & '#rev = \"2f5eaba864ff630ba0c3791126a3f811b6e437f3\" ' ,& & ' ' ,& & ' # Now you can use any modules from these libraries anywhere in your ' ,& & ' # code -- whether is in your library source or a program source. ' ,& & ' ' ,& & '[dev-dependencies] ' ,& & ' ' ,& & ' ## Dependencies Only for Development ' ,& & ' # ' ,& & ' # You can specify dependencies your library or application does not ' ,& & ' # depend on in a similar way. The difference is that these will not ' ,& & ' # be exported as part of your project to those using it as a remote ' ,& & ' # dependency. ' ,& & ' # ' ,& & ' # Currently, like a global dependency it will still be available for ' ,& & ' # all codes. It is up to the developer to ensure that nothing except ' ,& & ' # developer test programs rely upon it. ' ,& & ' ' ,& & '#M_msg = { git = \"https://github.com/urbanjost/M_msg.git\" } ' ,& & '#M_verify = { git = \"https://github.com/urbanjost/M_verify.git\" } ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_executable ) then ! create next section of fpm.toml call mkdir ( join_path ( settings % name , 'app' )) ! create NAME/app or stop if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & ' #----------------------------------- ' ,& & ' ## Application-specific declarations ' ,& & ' #----------------------------------- ' ,& & ' # Now lets begin entries for the TOML tables (lines beginning with \"[[\") ' ,& & ' # that describe the program sources -- applications, tests, and examples. ' ,& & ' # ' ,& & ' # First we will configuration individual applications run with \"fpm run\". ' ,& & ' # ' ,& & ' # + the \"name\" entry for the executable to be built must always ' ,& & ' # be specified. The name must satisfy the rules for a Fortran ' ,& & ' # variable name. This will be the name of the binary installed by ' ,& & ' # the \"install\" subcommand and used on the \"run\" subcommand. ' ,& & ' # + The source directory for each executable can be adjusted by the ' ,& & ' # \"source-dir\" entry. ' ,& & ' # + The basename of the source file containing the program body can ' ,& & ' # be specified with the \"main\" entry. ' ,& & ' # + Executables can also specify their own external package and ' ,& & ' # library link dependencies. ' ,& & ' # ' ,& & ' # Currently, like a global dependency any external package dependency ' ,& & ' # will be available for all codes. It is up to the developer to ensure ' ,& & ' # that nothing except the application programs specified rely upon it. ' ,& & ' # ' ,& & ' # Note if your application needs to use a module internally, but you do not ' ,& & ' # intend to build it as a library to be used in other projects, you can ' ,& & ' # include the module in your program source file or directory as well. ' ,& & ' ' ,& & '[[executable]] ' ,& & 'name=\"' // bname // '\"' ,& & 'source-dir=\"app\" ' ,& & 'main=\"main.f90\" ' ,& & ' ' ,& & ' # You may repeat this pattern to define additional applications. For instance,' ,& & ' # the following sample illustrates all accepted options, where \"link\" and ' ,& & ' # \"executable.dependencies\" keys are the same as the global external library ' ,& & ' # links and package dependencies described previously except they apply ' ,& & ' # only to this executable: ' ,& & ' ' ,& & '#[[ executable ]] ' ,& & '#name = \"app-name\" ' ,& & '#source-dir = \"prog\" ' ,& & '#main = \"program.f90\" ' ,& & '#link = \"z\" ' ,& & '#[executable.dependencies] ' ,& & '#M_CLI = { git = \"https://github.com/urbanjost/M_CLI.git\" } ' ,& & '#helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } ' ,& & '#M_path = { git = \"https://github.com/urbanjost/M_path.git\" } ' ,& & '' ] endif if ( exists ( bname // '/src/' )) then littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' use ' // to_fortran_name ( bname ) // ', only: say_hello' , & & ' implicit none' , & & '' , & & ' call say_hello()' , & & 'end program main' ] else littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' implicit none' , & & '' , & & ' print *, \"hello from project ' // bname // '\"' , & & 'end program main' ] endif call warnwrite ( join_path ( settings % name , 'app/main.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_test ) then ! create NAME/test or stop call mkdir ( join_path ( settings % name , 'test' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[[test]] ' ,& & ' ' ,& & ' # The same declarations can be made for test programs, which are ' ,& & ' # executed with the \"fpm test\" command and are not build when your ' ,& & ' # package is used as a dependency by other packages. These are ' ,& & ' # typically unit tests of the package only used during package ' ,& & ' # development. ' ,& & ' ' ,& & 'name=\"runTests\" ' ,& & 'source-dir=\"test\" ' ,& & 'main=\"check.f90\" ' ,& & ' ' ,& & ' # you may repeat this pattern to add additional explicit test program ' ,& & ' # parameters. The following example contains a sample of all accepted ' ,& & ' # options. ' ,& & ' ' ,& & '#[[ test ]] ' ,& & '#name = \"tester\" ' ,& & '#source-dir=\"test\" ' ,& & '#main=\"tester.f90\" ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '#[test.dependencies] ' ,& & '#M_CLI2 = { git = \"https://github.com/urbanjost/M_CLI2.git\" } ' ,& & '#M_io = { git = \"https://github.com/urbanjost/M_io.git\" } ' ,& & '#M_system= { git = \"https://github.com/urbanjost/M_system.git\" } ' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program check' , & & 'implicit none' , & & '' , & & 'print *, \"Put some tests in here!\"' , & & 'end program check' ] ! create NAME/test/check.f90 call warnwrite ( join_path ( settings % name , 'test/check.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_example ) then ! create NAME/example or stop call mkdir ( join_path ( settings % name , 'example' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[[example]] ' ,& & ' ' ,& & ' # Example applications for a project are defined here. ' ,& & ' # These are run via \"fpm run --example NAME\" and like the ' ,& & ' # test applications, are not built when this package is used as a ' ,& & ' # dependency by other packages. ' ,& & ' ' ,& & 'name=\"demo\" ' ,& & 'source-dir=\"example\" ' ,& & 'main=\"demo.f90\" ' ,& & ' ' ,& & ' # ' ,& & ' # you may add additional programs to the example table. The following ' ,& & ' # example contains a sample of all accepted options ' ,& & ' ' ,& & '#[[ example ]] ' ,& & '#name = \"example-tool\" ' ,& & '#source-dir=\"example\" ' ,& & '#main=\"tool.f90\" ' ,& & '#link = \"z\" ' ,& & '#[example.dependencies] ' ,& & '#M_kracken95 = { git = \"https://github.com/urbanjost/M_kracken95.git\" } ' ,& & '#datetime = {git = \"https://github.com/wavebitscientific/datetime-fortran.git\" }' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program demo' , & & 'implicit none' , & & '' , & & 'print *, \"Put some examples in here!\"' , & & 'end program demo' ] ! create NAME/example/demo.f90 call warnwrite ( join_path ( settings % name , 'example/demo.f90' ), littlefile ) endif ! now that built it write NAME/fpm.toml if ( allocated ( tomlfile ) ) then call validate_toml_data ( tomlfile ) call warnwrite ( join_path ( settings % name , 'fpm.toml' ), tomlfile ) else call create_verified_basic_manifest ( join_path ( settings % name , 'fpm.toml' )) endif ! assumes git(1) is installed and in path if ( which ( 'git' ) /= '' ) then call run ( 'git init ' // settings % name ) endif contains function git_metadata ( what ) result ( returned ) !> get metadata values such as email address and git name from git(1) or return appropriate default use fpm_filesystem , only : get_temp_filename , getline character ( len =* ), intent ( in ) :: what ! keyword designating what git metatdata to query character ( len = :), allocatable :: returned ! value to return for requested keyword character ( len = :), allocatable :: command character ( len = :), allocatable :: temp_filename character ( len = :), allocatable :: iomsg character ( len = :), allocatable :: temp_value integer :: stat , unit temp_filename = get_temp_filename () ! for known keywords set default value for RETURNED and associated git(1) command for query select case ( what ) case ( 'uname' ) returned = \"Jane Doe\" command = \"git config --get user.name > \" // temp_filename case ( 'email' ) returned = \"jane.doe@example.com\" command = \"git config --get user.email > \" // temp_filename case default write ( stderr , '(*(g0,1x))' )& & ' *git_metadata* unknown metadata name ' , trim ( what ) returned = '' return end select ! Execute command if git(1) is in command path if ( which ( 'git' ) /= '' ) then call run ( command , exitstat = stat ) if ( stat /= 0 ) then ! If command failed just return default return else ! Command did not return an error so try to read expected output file open ( file = temp_filename , newunit = unit , iostat = stat ) if ( stat == 0 ) then ! Read file into a scratch variable until status of doing so is checked call getline ( unit , temp_value , stat , iomsg ) if ( stat == 0 . and . temp_value /= '' ) then ! Return output from successful command returned = temp_value endif endif ! Always do the CLOSE because a failed open has unpredictable results. ! Add IOSTAT so a failed close does not cause program to stop close ( unit , status = \"delete\" , iostat = stat ) endif endif end function git_metadata subroutine create_verified_basic_manifest ( filename ) !> create a basic but verified default manifest file use fpm_toml , only : toml_table , toml_serialize , set_value use fpm_manifest_package , only : package_config_t , new_package use fpm_error , only : error_t implicit none character ( len =* ), intent ( in ) :: filename type ( toml_table ) :: table type ( package_config_t ) :: package type ( error_t ), allocatable :: error integer :: lun character ( len = 8 ) :: date character (:), allocatable :: output if ( exists ( filename )) then write ( stderr , '(*(g0,1x))' ) ' ' , filename ,& & 'already exists. Not overwriting' return endif !> get date to put into metadata in manifest file \"fpm.toml\" call date_and_time ( DATE = date ) table = toml_table () call fileopen ( filename , lun ) ! fileopen stops on error call set_value ( table , \"name\" , BNAME ) call set_value ( table , \"version\" , \"0.1.0\" ) call set_value ( table , \"license\" , \"license\" ) call set_value ( table , \"author\" , git_metadata ( 'uname' )) call set_value ( table , \"maintainer\" , git_metadata ( 'email' )) call set_value ( table , \"copyright\" , 'Copyright ' // date ( 1 : 4 ) // ', ' // git_metadata ( 'uname' )) ! continue building of manifest ! ... call new_package ( package , table , error = error ) if ( allocated ( error )) call fpm_stop ( 3 , '' ) output = toml_serialize ( table ) if ( settings % verbose ) then print '(a)' , output endif write ( lun , '(a)' ) output call fileclose ( lun ) ! fileopen stops on error end subroutine create_verified_basic_manifest subroutine validate_toml_data ( input ) !> verify a string array is a valid fpm.toml file ! use tomlf , only : toml_load use fpm_toml , only : toml_table , toml_serialize implicit none character ( kind = tfc , len = :), intent ( in ), allocatable :: input (:) character ( len = 1 ), parameter :: nl = new_line ( 'a' ) type ( toml_table ), allocatable :: table character ( kind = tfc , len = :), allocatable :: joined_string ! you have to add a newline character by using the intrinsic ! function `new_line(\"a\")` to get the lines processed correctly. joined_string = join ( input , right = nl ) if ( allocated ( table )) deallocate ( table ) call toml_load ( table , joined_string ) if ( allocated ( table )) then if ( settings % verbose ) then ! If the TOML file is successfully parsed the table will be allocated and ! can be written by `toml_serialize` to the standard output print '(a)' , toml_serialize ( table ) endif call table % destroy endif end subroutine validate_toml_data end subroutine cmd_new","tags":"","loc":"proc/cmd_new.html"},{"title":"cmd_install – Fortran-lang/fpm","text":"public subroutine cmd_install(settings) Entry point for the fpm-install subcommand Arguments Type Intent Optional Attributes Name type( fpm_install_settings ), intent(inout) :: settings Representation of the command line settings Contents Source Code cmd_install Source Code subroutine cmd_install ( settings ) !> Representation of the command line settings type ( fpm_install_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( error_t ), allocatable :: error type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( installer_t ) :: installer type ( string_t ), allocatable :: list (:) logical :: installable call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) call build_model ( model , settings , package , error ) call handle_error ( error ) call targets_from_sources ( targets , model , settings % prune , error ) call handle_error ( error ) installable = ( allocated ( package % library ) . and . package % install % library ) & . or . allocated ( package % executable ) if (. not . installable ) then call fatal_error ( error , \"Project does not contain any installable targets\" ) call handle_error ( error ) end if if ( settings % list ) then call install_info ( output_unit , targets ) return end if if (. not . settings % no_rebuild ) then call build_package ( targets , model , verbose = settings % verbose ) end if call new_installer ( installer , prefix = settings % prefix , & bindir = settings % bindir , libdir = settings % libdir , & includedir = settings % includedir , & verbosity = merge ( 2 , 1 , settings % verbose )) if ( allocated ( package % library ) . and . package % install % library ) then call filter_library_targets ( targets , list ) if ( size ( list ) > 0 ) then call installer % install_library ( list ( 1 )% s , error ) call handle_error ( error ) call install_module_files ( installer , targets , error ) call handle_error ( error ) end if end if if ( allocated ( package % executable )) then call install_executables ( installer , targets , error ) call handle_error ( error ) end if end subroutine cmd_install","tags":"","loc":"proc/cmd_install.html"},{"title":"cmd_update – Fortran-lang/fpm","text":"public subroutine cmd_update(settings) Entry point for the update subcommand Arguments Type Intent Optional Attributes Name type( fpm_update_settings ), intent(in) :: settings Representation of the command line arguments Contents Source Code cmd_update Source Code subroutine cmd_update ( settings ) !> Representation of the command line arguments type ( fpm_update_settings ), intent ( in ) :: settings type ( package_config_t ) :: package type ( dependency_tree_t ) :: deps type ( error_t ), allocatable :: error integer :: ii character ( len = :), allocatable :: cache call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) if (. not . exists ( \"build\" )) then call mkdir ( \"build\" ) call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if cache = join_path ( \"build\" , \"cache.toml\" ) if ( settings % clean ) call delete_file ( cache ) call new_dependency_tree ( deps , cache = cache , & verbosity = merge ( 2 , 1 , settings % verbose )) call deps % add ( package , error ) call handle_error ( error ) ! Force-update all dependencies if `--clean` if ( settings % clean ) then do ii = 1 , deps % ndep deps % dep ( ii )% update = . true . end do end if if ( settings % fetch_only ) return if ( size ( settings % name ) == 0 ) then call deps % update ( error ) call handle_error ( error ) else do ii = 1 , size ( settings % name ) call deps % update ( trim ( settings % name ( ii )), error ) call handle_error ( error ) end do end if end subroutine cmd_update","tags":"","loc":"proc/cmd_update.html"},{"title":"has_manifest – Fortran-lang/fpm","text":"function has_manifest(dir) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical Contents Source Code has_manifest Source Code function has_manifest ( dir ) character ( len =* ), intent ( in ) :: dir logical :: has_manifest has_manifest = exists ( join_path ( dir , \"fpm.toml\" )) end function has_manifest","tags":"","loc":"proc/has_manifest.html"},{"title":"get_working_dir – Fortran-lang/fpm","text":"subroutine get_working_dir(settings, working_dir_) Save access to working directory in settings, in case setting have not been allocated Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(in), optional :: settings character(len=:), intent(out), allocatable :: working_dir_ Contents Source Code get_working_dir Source Code subroutine get_working_dir ( settings , working_dir_ ) class ( fpm_cmd_settings ), optional , intent ( in ) :: settings character ( len = :), allocatable , intent ( out ) :: working_dir_ if ( present ( settings )) then working_dir_ = settings % working_dir end if end subroutine get_working_dir","tags":"","loc":"proc/get_working_dir.html"},{"title":"handle_error – Fortran-lang/fpm","text":"subroutine handle_error(error_) Arguments Type Intent Optional Attributes Name type( error_t ), intent(in), optional :: error_ Contents Source Code handle_error Source Code subroutine handle_error ( error_ ) type ( error_t ), optional , intent ( in ) :: error_ if ( present ( error_ )) then write ( error_unit , '(\"[Error]\", 1x, a)' ) error_ % message stop 1 end if end subroutine handle_error","tags":"","loc":"proc/handle_error~2.html"},{"title":"fpm_backend – Fortran-lang/fpm","text":"Build backend Uses a list of build_target_ptr and a valid fpm_model instance\n to schedule and execute the compilation and linking of package targets. The package build process ( build_package ) comprises three steps: Target sorting: topological sort of the target dependency graph ( sort_target ) Target scheduling: group targets into schedule regions based on the sorting ( schedule_targets ) Target building: generate targets by compilation or linking Note If compiled with OpenMP, targets will be build in parallel where possible. Incremental compilation The backend process supports incremental compilation whereby targets are not\n re-compiled if their corresponding dependencies have not been modified. Source-based targets ( i.e. objects) are not re-compiled if the corresponding source\n file is unmodified AND all of the target dependencies are not marked for re-compilation Link targets ( i.e. executables and libraries) are not re-compiled if the\n target output file already exists AND all of the target dependencies are not marked for\n re-compilation Source file modification is determined by a file digest (hash) which is calculated during\n the source parsing phase ( fpm_source_parsing ) and cached to disk after a target is\n successfully generated. Uses fpm_backend_output fpm_strings fpm_targets iso_fortran_env fpm_filesystem fpm_error fpm_model Contents Subroutines build_package schedule_targets sort_target Subroutines public subroutine build_package (targets, model, verbose) Top-level routine to build package described by model Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout) :: targets (:) type( fpm_model_t ), intent(in) :: model logical, intent(in) :: verbose public subroutine schedule_targets (queue, schedule_ptr, targets) Construct a build schedule from the sorted targets. Read more… Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: queue (:) integer, allocatable :: schedule_ptr (:) type( build_target_ptr ), intent(in) :: targets (:) public recursive subroutine sort_target (target) Topologically sort a target for scheduling by\n recursing over its dependencies. Read more… Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout), target :: target","tags":"","loc":"module/fpm_backend.html"},{"title":"fpm_compiler – Fortran-lang/fpm","text":"Define compiler command options This module defines compiler options to use for the debug and release builds. Uses fpm_environment fpm_strings iso_fortran_env fpm_filesystem fpm_error Contents Variables compiler_enum flag_cray_fixed_form flag_cray_free_form flag_cray_implicit_typing flag_cray_no_implicit_typing flag_gnu_backtrace flag_gnu_check flag_gnu_coarray flag_gnu_debug flag_gnu_external flag_gnu_fixed_form flag_gnu_free_form flag_gnu_limit flag_gnu_no_implicit_external flag_gnu_no_implicit_typing flag_gnu_openmp flag_gnu_opt flag_gnu_pic flag_gnu_warn flag_ibmxl_backslash flag_intel_align flag_intel_align_win flag_intel_backtrace flag_intel_backtrace_win flag_intel_byterecl flag_intel_byterecl_win flag_intel_check flag_intel_check_win flag_intel_debug flag_intel_debug_win flag_intel_fixed_form flag_intel_fixed_form_win flag_intel_fp flag_intel_fp_win flag_intel_free_form flag_intel_free_form_win flag_intel_limit flag_intel_limit_win flag_intel_nogen flag_intel_nogen_win flag_intel_openmp flag_intel_openmp_win flag_intel_pthread flag_intel_pthread_win flag_intel_standard_compliance flag_intel_standard_compliance_win flag_intel_warn flag_intel_warn_win flag_lfortran_fixed_form flag_lfortran_implicit_external flag_lfortran_implicit_typing flag_lfortran_openmp flag_lfortran_opt flag_nag_backtrace flag_nag_check flag_nag_coarray flag_nag_debug flag_nag_fixed_form flag_nag_free_form flag_nag_no_implicit_typing flag_nag_openmp flag_nag_opt flag_nag_pic flag_pgi_backslash flag_pgi_check flag_pgi_debug flag_pgi_fixed_form flag_pgi_free_form flag_pgi_openmp flag_pgi_traceback flag_pgi_warn Enumerations unnamed Interfaces debug Derived Types archiver_t compiler_t Functions check_compiler compiler_name debug_archiver debug_compiler enumerate_libraries get_compiler_id get_default_flags get_feature_flag get_id get_include_flag get_macros get_module_flag is_gnu is_intel is_unknown Subroutines compile_c compile_cpp compile_fortran get_debug_compile_flags get_default_c_compiler get_default_cxx_compiler get_main_flags get_release_compile_flags link make_archive new_archiver new_compiler set_cpp_preprocessor_flags write_response_file Variables Type Visibility Attributes Name Initial integer, public, parameter :: compiler_enum = kind(id_unknown) character(len=*), public, parameter :: flag_cray_fixed_form = \" -ffixed\" character(len=*), public, parameter :: flag_cray_free_form = \" -ffree\" character(len=*), public, parameter :: flag_cray_implicit_typing = \" -el\" character(len=*), public, parameter :: flag_cray_no_implicit_typing = \" -dl\" character(len=*), public, parameter :: flag_gnu_backtrace = \" -fbacktrace\" character(len=*), public, parameter :: flag_gnu_check = \" -fcheck=bounds -fcheck=array-temps\" character(len=*), public, parameter :: flag_gnu_coarray = \" -fcoarray=single\" character(len=*), public, parameter :: flag_gnu_debug = \" -g\" character(len=*), public, parameter :: flag_gnu_external = \" -Wimplicit-interface\" character(len=*), public, parameter :: flag_gnu_fixed_form = \" -ffixed-form\" character(len=*), public, parameter :: flag_gnu_free_form = \" -ffree-form\" character(len=*), public, parameter :: flag_gnu_limit = \" -fmax-errors=1\" character(len=*), public, parameter :: flag_gnu_no_implicit_external = \" -Werror=implicit-interface\" character(len=*), public, parameter :: flag_gnu_no_implicit_typing = \" -fimplicit-none\" character(len=*), public, parameter :: flag_gnu_openmp = \" -fopenmp\" character(len=*), public, parameter :: flag_gnu_opt = \" -O3 -funroll-loops\" character(len=*), public, parameter :: flag_gnu_pic = \" -fPIC\" character(len=*), public, parameter :: flag_gnu_warn = \" -Wall -Wextra\" character(len=*), public, parameter :: flag_ibmxl_backslash = \" -qnoescape\" character(len=*), public, parameter :: flag_intel_align = \" -align all\" character(len=*), public, parameter :: flag_intel_align_win = \" /align:all\" character(len=*), public, parameter :: flag_intel_backtrace = \" -traceback\" character(len=*), public, parameter :: flag_intel_backtrace_win = \" /traceback\" character(len=*), public, parameter :: flag_intel_byterecl = \" -assume byterecl\" character(len=*), public, parameter :: flag_intel_byterecl_win = \" /assume:byterecl\" character(len=*), public, parameter :: flag_intel_check = \" -check all\" character(len=*), public, parameter :: flag_intel_check_win = \" /check:all\" character(len=*), public, parameter :: flag_intel_debug = \" -O0 -g\" character(len=*), public, parameter :: flag_intel_debug_win = \" /Od /Z7\" character(len=*), public, parameter :: flag_intel_fixed_form = \" -fixed\" character(len=*), public, parameter :: flag_intel_fixed_form_win = \" /fixed\" character(len=*), public, parameter :: flag_intel_fp = \" -fp-model precise -pc64\" character(len=*), public, parameter :: flag_intel_fp_win = \" /fp:precise\" character(len=*), public, parameter :: flag_intel_free_form = \" -free\" character(len=*), public, parameter :: flag_intel_free_form_win = \" /free\" character(len=*), public, parameter :: flag_intel_limit = \" -error-limit 1\" character(len=*), public, parameter :: flag_intel_limit_win = \" /error-limit:1\" character(len=*), public, parameter :: flag_intel_nogen = \" -nogen-interfaces\" character(len=*), public, parameter :: flag_intel_nogen_win = \" /nogen-interfaces\" character(len=*), public, parameter :: flag_intel_openmp = \" -qopenmp\" character(len=*), public, parameter :: flag_intel_openmp_win = \" /Qopenmp\" character(len=*), public, parameter :: flag_intel_pthread = \" -reentrancy threaded\" character(len=*), public, parameter :: flag_intel_pthread_win = \" /reentrancy:threaded\" character(len=*), public, parameter :: flag_intel_standard_compliance = \" -standard-semantics\" character(len=*), public, parameter :: flag_intel_standard_compliance_win = \" /standard-semantics\" character(len=*), public, parameter :: flag_intel_warn = \" -warn all\" character(len=*), public, parameter :: flag_intel_warn_win = \" /warn:all\" character(len=*), public, parameter :: flag_lfortran_fixed_form = \" --fixed-form\" character(len=*), public, parameter :: flag_lfortran_implicit_external = \" --allow-implicit-interface\" character(len=*), public, parameter :: flag_lfortran_implicit_typing = \" --implicit-typing\" character(len=*), public, parameter :: flag_lfortran_openmp = \" --openmp\" character(len=*), public, parameter :: flag_lfortran_opt = \" --fast\" character(len=*), public, parameter :: flag_nag_backtrace = \" -gline\" character(len=*), public, parameter :: flag_nag_check = \" -C\" character(len=*), public, parameter :: flag_nag_coarray = \" -coarray=single\" character(len=*), public, parameter :: flag_nag_debug = \" -g -O0\" character(len=*), public, parameter :: flag_nag_fixed_form = \" -fixed\" character(len=*), public, parameter :: flag_nag_free_form = \" -free\" character(len=*), public, parameter :: flag_nag_no_implicit_typing = \" -u\" character(len=*), public, parameter :: flag_nag_openmp = \" -openmp\" character(len=*), public, parameter :: flag_nag_opt = \" -O4\" character(len=*), public, parameter :: flag_nag_pic = \" -PIC\" character(len=*), public, parameter :: flag_pgi_backslash = \" -Mbackslash\" character(len=*), public, parameter :: flag_pgi_check = \" -Mbounds -Mchkptr -Mchkstk\" character(len=*), public, parameter :: flag_pgi_debug = \" -g\" character(len=*), public, parameter :: flag_pgi_fixed_form = \" -Mfixed\" character(len=*), public, parameter :: flag_pgi_free_form = \" -Mfree\" character(len=*), public, parameter :: flag_pgi_openmp = \" -mp\" character(len=*), public, parameter :: flag_pgi_traceback = \" -traceback\" character(len=*), public, parameter :: flag_pgi_warn = \" -Minform=inform\" Enumerations enum, bind(c) Enumerators enumerator :: id_unknown = 0 enumerator :: id_gcc = 1 enumerator :: id_f95 = 2 enumerator :: id_caf = 3 enumerator :: id_intel_classic_nix = 4 enumerator :: id_intel_classic_mac = 5 enumerator :: id_intel_classic_windows = 6 enumerator :: id_intel_llvm_nix = 7 enumerator :: id_intel_llvm_windows = 8 enumerator :: id_intel_llvm_unknown = 9 enumerator :: id_pgi = 10 enumerator :: id_nvhpc = 11 enumerator :: id_nag = 12 enumerator :: id_flang = 13 enumerator :: id_flang_new = 14 enumerator :: id_f18 = 15 enumerator :: id_ibmxl = 16 enumerator :: id_cray = 17 enumerator :: id_lahey = 18 enumerator :: id_lfortran = 19 Interfaces public interface debug Create debug printout public pure function debug_compiler (self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public pure function debug_archiver (self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string Derived Types type, public :: archiver_t Definition of archiver object Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: ar Path to archiver logical, public :: echo = .true. Print all command logical, public :: use_response_file = .false. Use response files to pass arguments logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure\n , public\n, :: make_archive Subroutine Create static archive type, public :: compiler_t Definition of compiler object Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cc Path to the C compiler character(len=:), public, allocatable :: cxx Path to the C++ compiler logical, public :: echo = .true. Print all commands character(len=:), public, allocatable :: fc Path to the Fortran compiler integer(kind=compiler_enum), public :: id = id_unknown Identifier of the compiler logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure\n , public\n, :: compile_c Subroutine Compile a C object procedure\n , public\n, :: compile_cpp Subroutine Compile a CPP object procedure\n , public\n, :: compile_fortran Subroutine Compile a Fortran object procedure\n , public\n, :: enumerate_libraries Function Enumerate libraries, based on compiler and platform procedure\n , public\n, :: get_default_flags Function Get default compiler flags procedure\n , public\n, :: get_feature_flag Function Get feature flag procedure\n , public\n, :: get_include_flag Function Get flag for include directories procedure\n , public\n, :: get_main_flags Subroutine Get flags for the main linking command procedure\n , public\n, :: get_module_flag Function Get flag for module output directories procedure\n , public\n, :: is_gnu Function Check whether this is a GNU compiler procedure\n , public\n, :: is_intel Function Check whether this is an Intel compiler procedure\n , public\n, :: is_unknown Function Check whether compiler is recognized procedure\n , public\n, :: link Subroutine Link executable procedure\n , public\n, :: name => compiler_name Function Return compiler name Functions public function check_compiler (compiler, expected) result(match) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler character(len=*), intent(in) :: expected Return Value logical public pure function compiler_name (self) result(name) Return a compiler name string Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public pure function debug_archiver (self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string public pure function debug_compiler (self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public function enumerate_libraries (self, prefix, libs) result(r) Enumerate libraries, based on compiler and platform Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: prefix type( string_t ), intent(in) :: libs (:) Return Value character(len=:), allocatable public function get_compiler_id (compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) public function get_default_flags (self, release) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self logical, intent(in) :: release Return Value character(len=:), allocatable public function get_feature_flag (self, feature) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: feature Return Value character(len=:), allocatable public function get_id (compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) public function get_include_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function get_macros (id, macros_list, version) result(macros) This function will parse and read the macros list and\nreturn them as defined flags.\nSet macro defintion symbol on the basis of compiler used\nCheck if macros are not allocated.\nSplit the macro name and value. Read more… Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id type( string_t ), intent(in), allocatable :: macros_list (:) character(len=:), intent(in), allocatable :: version Return Value character(len=:), allocatable public function get_module_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable public pure function is_gnu (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical public pure function is_intel (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical public pure function is_unknown (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Subroutines public subroutine compile_c (self, input, output, args, log_file, stat) Compile a C object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine compile_cpp (self, input, output, args, log_file, stat) Compile a CPP object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine compile_fortran (self, input, output, args, log_file, stat) Compile a Fortran object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine get_debug_compile_flags (id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags public subroutine get_default_c_compiler (f_compiler, c_compiler) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: c_compiler public subroutine get_default_cxx_compiler (f_compiler, cxx_compiler) Get C++ Compiler. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: cxx_compiler public subroutine get_main_flags (self, language, flags) Get special flags for the main linker Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: language character(len=:), intent(out), allocatable :: flags public subroutine get_release_compile_flags (id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags public subroutine link (self, output, args, log_file, stat) Link an executable Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine make_archive (self, output, args, log_file, stat) Create an archive Read more… Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: self Instance of the archiver object character(len=*), intent(in) :: output Name of the archive to generate type( string_t ), intent(in) :: args (:) Object files to include into the archive character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag public subroutine new_archiver (self, ar, echo, verbose) Create new archiver instance Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(out) :: self New instance of the archiver character(len=*), intent(in) :: ar User provided archiver command logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output public subroutine new_compiler (self, fc, cc, cxx, echo, verbose) Create new compiler instance Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(out) :: self New instance of the compiler character(len=*), intent(in) :: fc Fortran compiler name or path character(len=*), intent(in) :: cc C compiler name or path character(len=*), intent(in) :: cxx C++ Compiler name or path logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output public pure subroutine set_cpp_preprocessor_flags (id, flags) Modify the flag_cpp_preprocessor on the basis of the compiler. Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(inout), allocatable :: flags public subroutine write_response_file (name, argv) Response files allow to read command line options from files.\nWhitespace is used to separate the arguments, we will use newlines\nas separator to create readable response files which can be inspected\nin case of errors. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name type( string_t ), intent(in) :: argv (:)","tags":"","loc":"module/fpm_compiler.html"},{"title":"fpm_settings – Fortran-lang/fpm","text":"Manages global settings which are defined in the global config file. Uses fpm_toml fpm_os fpm_environment fpm_filesystem fpm_error Contents Variables official_registry_base_url Derived Types fpm_global_settings Subroutines get_global_settings get_registry_settings Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: official_registry_base_url = 'https://registry-apis.vercel.app' Derived Types type, public :: fpm_global_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: config_file_name Name of the global config file. The default is config.toml . character(len=:), public, allocatable :: path_to_config_folder Path to the global config file excluding the file name. type(fpm_registry_settings), public, allocatable :: registry_settings Registry configs. Type-Bound Procedures procedure\n , public\n, :: full_path Function procedure\n , public\n, :: has_custom_location Function procedure\n , public\n, :: path_to_config_folder_or_empty Function Subroutines public subroutine get_global_settings (global_settings, error) Obtain global settings from the global config file. Arguments Type Intent Optional Attributes Name type( fpm_global_settings ), intent(inout) :: global_settings Global settings to be obtained. type( error_t ), intent(out), allocatable :: error Error reading config file. public subroutine get_registry_settings (table, global_settings, error) Read registry settings from the global config file. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout), target :: table The [registry] subtable from the global config file. type( fpm_global_settings ), intent(inout) :: global_settings The global settings which can be filled with the registry settings. type( error_t ), intent(out), allocatable :: error Error handling.","tags":"","loc":"module/fpm_settings.html"},{"title":"fpm_backend_console – Fortran-lang/fpm","text":"Build Backend Console This module provides a lightweight implementation for printing to the console\n and updating previously-printed console lines. It used by fpm_backend_output for pretty-printing build status and progress. Note The implementation for updating previous lines relies on no other output\n going to stdout / stderr except through the console_t object provided. Note All write statements to stdout are enclosed within OpenMP critical regions Uses iso_fortran_env Contents Variables COLOR_GREEN COLOR_RED COLOR_RESET COLOR_YELLOW LINE_RESET Derived Types console_t Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: COLOR_GREEN = ESC//\"[32m\" Escape code for green foreground color character(len=*), public, parameter :: COLOR_RED = ESC//\"[31m\" Escape code for red foreground color character(len=*), public, parameter :: COLOR_RESET = ESC//\"[0m\" Escape code to reset foreground color character(len=*), public, parameter :: COLOR_YELLOW = ESC//\"[93m\" Escape code for yellow foreground color character(len=*), public, parameter :: LINE_RESET = ESC//\"[2K\"//ESC//\"[1G\" Escape code for erasing current line Derived Types type, public :: console_t Console object Components Type Visibility Attributes Name Initial integer, public :: n_line = 1 Number of lines printed Type-Bound Procedures procedure\n , public\n, :: update_line =>\n console_update_line Subroutine Update a previously-written console line procedure\n , public\n, :: write_line =>\n console_write_line Subroutine Write a single line to the console","tags":"","loc":"module/fpm_backend_console.html"},{"title":"fpm_command_line – Fortran-lang/fpm","text":"Definition of the command line interface This module uses M_CLI2 to define\n the command line interface.\n To define a command line interface create a new command settings type\n from the fpm_cmd_settings base class or the respective parent command\n settings. The subcommand is selected by the first non-option argument in the command\n line. In the subcase block the actual command line is defined and transferred\n 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\n wanted command line and the expected default values.\n Some of the following points also apply if you add a new option or argument\n to an existing fpm subcommand.\n At this point you should create a help page for the new command in a simple\n catman-like format as well in the set_help procedure.\n Make sure to register new subcommands in the fpm-manual command by adding\n them to the manual character array and in the help/manual case as well.\n 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\n is complete and consistent as well. Uses fpm_environment fpm_os fpm_strings fpm_release m_cli2 iso_fortran_env fpm_filesystem fpm_error Contents Derived Types fpm_build_settings fpm_clean_settings fpm_cmd_settings fpm_install_settings fpm_new_settings fpm_publish_settings fpm_run_settings fpm_test_settings fpm_update_settings Subroutines get_command_line_settings Derived Types type, public, extends( fpm_cmd_settings ) :: fpm_build_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_cmd_settings ) :: fpm_clean_settings Components Type Visibility Attributes Name Initial logical, public :: clean_call = .false. logical, public :: clean_skip = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public :: fpm_cmd_settings Components Type Visibility Attributes Name Initial logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_install_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: bindir logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: includedir character(len=:), public, allocatable :: ldflag character(len=:), public, allocatable :: libdir logical, public :: list = .false. logical, public :: no_rebuild character(len=:), public, allocatable :: prefix character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_cmd_settings ) :: fpm_new_settings Components Type Visibility Attributes Name Initial logical, public :: backfill = .true. character(len=:), public, allocatable :: name logical, public :: verbose = .true. logical, public :: with_bare = .false. logical, public :: with_example = .false. logical, public :: with_executable = .false. logical, public :: with_full = .false. logical, public :: with_lib = .true. logical, public :: with_test = .false. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_publish_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: flag logical, public :: is_dry_run = .false. character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: show_package_version = .false. logical, public :: show_upload_data = .false. character(len=:), public, allocatable :: token logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_run_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure\n , public\n, :: runner_command Function type, public, extends( fpm_run_settings ) :: fpm_test_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure\n , public\n, :: runner_command Function type, public, extends( fpm_cmd_settings ) :: fpm_update_settings Settings for interacting and updating with project dependencies Components Type Visibility Attributes Name Initial logical, public :: clean logical, public :: fetch_only character(len=ibug), public, allocatable :: name (:) logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Subroutines public subroutine get_command_line_settings (cmd_settings) ! canon_path is not converting “.”, etc.\n& ‘ unknown help topic “’//trim(unnamed(i)).’not found in:’,manual] Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(out), allocatable :: cmd_settings","tags":"","loc":"module/fpm_command_line.html"},{"title":"fpm_os – Fortran-lang/fpm","text":"Uses iso_c_binding fpm_environment fpm_error fpm_filesystem Contents Subroutines change_directory convert_to_absolute_path get_absolute_path get_absolute_path_by_cd get_current_directory Subroutines public subroutine change_directory (path, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error public subroutine convert_to_absolute_path (path, error) Converts a path to an absolute, canonical path. Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: path type( error_t ), intent(out), allocatable :: error public subroutine get_absolute_path (path, absolute_path, error) Determine the canonical, absolute path for the given path.\nExpands home folder (~) on both Unix and Windows. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error public subroutine get_absolute_path_by_cd (path, absolute_path, error) Alternative to get_absolute_path that uses chdir / _chdir to determine the absolute path. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error public subroutine get_current_directory (path, error) Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: path type( error_t ), intent(out), allocatable :: error","tags":"","loc":"module/fpm_os.html"},{"title":"fpm_sources – Fortran-lang/fpm","text":"Discovery of sources This module implements subroutines for building a list of srcfile_t objects by looking for source files in the filesystem. Uses fpm_environment fpm_strings fpm_source_parsing fpm_manifest_executable fpm_filesystem fpm_error fpm_model Contents Functions get_exe_name_with_suffix Subroutines add_executable_sources add_sources_from_dir Functions public function get_exe_name_with_suffix (source) result(suffixed) Build an executable name with suffix. Safe routine that always returns an allocated string Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(in) :: source Return Value character(len=:), allocatable Subroutines public subroutine add_executable_sources (sources, executables, scope, auto_discover, error) Add to sources using the executable and test entries in the manifest and\napplies any executable-specific overrides such as executable%name .\nAdds all sources (including modules) from each executable%source_dir Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of srcfile_t objects to append to. Allocated if not allocated class( executable_config_t ), intent(in) :: executables (:) List of executable_config_t entries from manifest integer, intent(in) :: scope Scope to apply to the discovered sources: either FPM_SCOPE_APP or FPM_SCOPE_TEST , see fpm_model logical, intent(in) :: auto_discover If .false. only executables and tests specified in the manifest are added to sources type( error_t ), intent(out), allocatable :: error Error handling public subroutine add_sources_from_dir (sources, directory, scope, with_executables, recurse, error) Add to sources by looking for source files in directory Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of srcfile_t objects to append to. Allocated if not allocated character(len=*), intent(in) :: directory Directory in which to search for source files integer, intent(in) :: scope Scope to apply to the discovered sources, see fpm_model for enumeration logical, intent(in), optional :: with_executables Executable sources (fortran program s) are ignored unless with_executables=.true. logical, intent(in), optional :: recurse Whether to recursively search subdirectories, default is .true. type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_sources.html"},{"title":"fpm – Fortran-lang/fpm","text":"Uses fpm_compiler iso_c_binding fpm_environment fpm_strings fpm_sources fpm_manifest fpm_meta fpm_dependency fpm_targets iso_fortran_env fpm_error fpm_command_line fpm_backend fpm_model fpm_filesystem Contents Subroutines build_model check_modules_for_duplicates cmd_build cmd_clean cmd_run Subroutines public subroutine build_model (model, settings, package, error) Constructs a valid fpm model from command line settings and the toml manifest.\nAdd this dependency’s manifest macros Read more… Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(out) :: model class( fpm_build_settings ), intent(inout) :: settings type( package_config_t ), intent(inout) :: package type( error_t ), intent(out), allocatable :: error public subroutine check_modules_for_duplicates (model, duplicates_found) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model logical :: duplicates_found public subroutine cmd_build (settings) Arguments Type Intent Optional Attributes Name type( fpm_build_settings ), intent(inout) :: settings public subroutine cmd_clean (settings) Delete the build directory including or excluding dependencies. Arguments Type Intent Optional Attributes Name class( fpm_clean_settings ), intent(in) :: settings Settings for the clean command. public subroutine cmd_run (settings, test) Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(inout) :: settings logical, intent(in) :: test","tags":"","loc":"module/fpm.html"},{"title":"fpm_meta – Fortran-lang/fpm","text":"The fpm meta-package model This is a wrapper data type that encapsulate all pre-processing information\n (compiler flags, linker libraries, etc.) required to correctly enable a package\n to use a core library. Available core libraries OpenMP MPI fortran-lang stdlib fortran-lang minpack Note Core libraries are enabled in the [build] section of the fpm.toml manifest Uses fpm_environment fpm_filesystem fpm_os fpm_strings fpm_manifest fpm_versioning fpm_git fpm_manifest_dependency iso_fortran_env fpm_error fpm_command_line fpm_compiler fpm_model Contents Interfaces resolve_metapackages Derived Types metapackage_t Functions MPI_TYPE_NAME Interfaces public interface resolve_metapackages private subroutine resolve_metapackage_model(model, package, settings, error) Resolve all metapackages into the package config Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(inout) :: model type( package_config_t ), intent(inout) :: package class( fpm_build_settings ), intent(inout) :: settings type( error_t ), intent(out), allocatable :: error Derived Types type, public :: metapackage_t Type for describing a source file Components Type Visibility Attributes Name Initial type( string_t ), public :: cflags type( string_t ), public :: cxxflags type( dependency_config_t ), public, allocatable :: dependency (:) List of Development dependency meta data.\nMetapackage dependencies are never exported from the model type( string_t ), public, allocatable :: external_modules (:) type( string_t ), public :: fflags type( string_t ), public :: flags List of compiler flags and options to be added type( fortran_features_t ), public, allocatable :: fortran Special fortran features logical, public :: has_build_flags = .false. logical, public :: has_c_flags = .false. logical, public :: has_cxx_flags = .false. logical, public :: has_dependencies = .false. logical, public :: has_external_modules = .false. logical, public :: has_fortran_flags = .false. logical, public :: has_include_dirs = .false. logical, public :: has_link_flags = .false. logical, public :: has_link_libraries = .false. logical, public :: has_run_command = .false. type( string_t ), public, allocatable :: incl_dirs (:) type( string_t ), public :: link_flags type( string_t ), public, allocatable :: link_libs (:) type( string_t ), public :: run_command type( version_t ), public, allocatable :: version Package version (if supported) Type-Bound Procedures procedure\n , public\n, :: destroy Subroutine Clean metapackage structure procedure\n , public\n, :: new =>\n init_from_name Subroutine Initialize the metapackage structure from its given name generic,\n public\n, :: resolve =>\n resolve_cmd, resolve_model, resolve_package_config Functions public pure function MPI_TYPE_NAME (mpilib) result(name) Return a name for the MPI library Arguments Type Intent Optional Attributes Name integer, intent(in) :: mpilib Return Value character(len=:), allocatable","tags":"","loc":"module/fpm_meta.html"},{"title":"fpm_backend_output – Fortran-lang/fpm","text":"Build Backend Progress Output This module provides a derived type build_progress_t for printing build status\n and progress messages to the console while the backend is building the package. The build_progress_t type supports two modes: normal and plain where the former does ‘pretty’ output and the latter does not.\n The normal mode is intended for typical interactive usage whereas\n ‘plain’ mode is used with the --verbose flag or when stdout is not attached\n to a terminal (e.g. when piping or redirecting stdout ). In these cases,\n the pretty output must be suppressed to avoid control codes being output. Uses fpm_backend_console fpm_filesystem iso_fortran_env fpm_targets Contents Interfaces build_progress_t Derived Types build_progress_t Interfaces public interface build_progress_t Constructor for build_progress_t private function new_build_progress(target_queue, plain_mode) result(progress) Initialise a new build progress object Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in), target :: target_queue (:) The queue of scheduled targets logical, intent(in), optional :: plain_mode Enable ‘plain’ output for progress object Return Value type( build_progress_t ) Progress object to initialise Derived Types type, public :: build_progress_t Build progress object Components Type Visibility Attributes Name Initial type( console_t ), public :: console Console object for updating console lines integer, public :: n_complete Number of completed targets integer, public :: n_target Total number of targets scheduled integer, public, allocatable :: output_lines (:) Store needed when updating previous console lines logical, public :: plain_mode = .true. ‘Plain’ output (no colors or updating) type( build_target_ptr ), public, pointer :: target_queue (:) Queue of scheduled build targets Constructor Constructor for build_progress_t private\n\n \n function new_build_progress (target_queue, plain_mode) Initialise a new build progress object Type-Bound Procedures procedure\n , public\n, :: compiling_status =>\n output_status_compiling Subroutine Output ‘compiling’ status for build target procedure\n , public\n, :: completed_status =>\n output_status_complete Subroutine Output ‘complete’ status for build target procedure\n , public\n, :: success =>\n output_progress_success Subroutine Output finished status for whole package","tags":"","loc":"module/fpm_backend_output.html"},{"title":"fpm_strings – Fortran-lang/fpm","text":"This module defines general procedures for string operations for both CHARACTER and\n TYPE(STRING_T) variables general routines for performing string operations Types TYPE(STRING_T) define a type to contain strings of variable length Type Conversions f_string return Fortran CHARACTER variable when given a C-like array of\n single characters terminated with a C_NULL_CHAR CHARACTER str Converts INTEGER or LOGICAL to CHARACTER string Case lower Changes a string to lowercase over optional specified column range Parsing and joining split parse string on delimiter characters and store tokens into an allocatable array string_cat Concatenate an array of type(string_t) into a single CHARACTER variable join append an array of CHARACTER variables into a single CHARACTER variable Testing str_ends_with test if a CHARACTER string or array ends with a specified suffix string_array_contains Check if array of TYPE(STRING_T) matches a particular CHARACTER string OPERATOR(.IN.) Check if array of TYPE(STRING_T) matches a particular CHARACTER string glob function compares text strings, one of which can have wildcards (‘*’ or ‘?’). is_fortran_name determine whether a string is an acceptable Fortran entity name to_fortran_name replace allowed special but unusuable characters in names with underscore Whitespace notabs subroutine to expand tab characters assuming a tab space every eight characters dilate function to expand tab characters assuming a tab space every eight characters len_trim Determine total trimmed length of STRING_T array Miscellaneous fnv_1a Hash a CHARACTER(*) string of default kind or a TYPE(STRING_T) array replace Returns string with characters in charset replaced with target_char. resize increase the size of a TYPE(STRING_T) array by N elements Module naming Uses iso_c_binding iso_fortran_env Contents Interfaces fnv_1a len_trim operator(.in.) resize str str_ends_with string_t Derived Types string_t Functions dilate f_string glob has_valid_custom_prefix has_valid_standard_prefix is_fortran_name is_valid_module_name is_valid_module_prefix join lower module_prefix_template module_prefix_type replace str_begins_with_str string_array_contains string_cat to_fortran_name Subroutines notabs remove_characters_in_set remove_newline_characters split Interfaces public interface fnv_1a private pure function fnv_1a_char(input, seed) result(hash) Hash a character(*) string of default kind Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64) private pure function fnv_1a_string_t(input, seed) result(hash) Hash a string_t array of default kind Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: input (:) integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64) public interface len_trim private elemental function string_len_trim(string) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: string Return Value integer private pure function strings_len_trim(strings) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) Return Value integer public interface operator(.in.) public function string_array_contains (search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical public interface resize private subroutine resize_string(list, n) increase the size of a TYPE(STRING_T) array by N elements Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout), allocatable :: list (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size public interface str private pure function str_int(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer, intent(in) :: i Return Value character(len=str_int_len) private pure function str_int64(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer(kind=int64), intent(in) :: i Return Value character(len=str_int64_len) private pure function str_logical(l) result(s) Converts logical “l” to string Arguments Type Intent Optional Attributes Name logical, intent(in) :: l Return Value character(len=str_logical_len) public interface str_ends_with private pure function str_ends_with_str(s, e) result(r) test if a CHARACTER string ends with a specified suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e Return Value logical private pure function str_ends_with_any(s, e) result(r) test if a CHARACTER string ends with any of an array of suffixs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e (:) Return Value logical public interface string_t private function new_string_t(s) result(string) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s Return Value type( string_t ) Derived Types type, public :: string_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: s Constructor private\n\n \n function new_string_t (s) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Functions public function dilate (instr) result(outstr) Author John S. Urban License Public Domain Sample program: Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr Return Value character(len=:), allocatable public function f_string (c_string) return Fortran character variable when given a C-like array of\nsingle characters terminated with a C_NULL_CHAR character Arguments Type Intent Optional Attributes Name character(len=1), intent(in) :: c_string (:) Return Value character(len=:), allocatable public function glob (tame, wild) Author John S. Urban License Public Domain glob(3f) compares given STRING for match to PATTERN which may\n contain wildcard characters. Read more… Arguments Type Intent Optional Attributes Name character(len=*) :: tame A string without wildcards to compare to the globbing expression character(len=*) :: wild A (potentially) corresponding string with wildcards Return Value logical result of test public function has_valid_custom_prefix (module_name, custom_prefix) result(valid) Check that a module name is prefixed with a custom prefix:\n1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed)\n2) It must begin with the prefix\n3) If longer, package name must be followed by default separator (“_”) plus at least one char Read more… Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: custom_prefix Return Value logical public function has_valid_standard_prefix (module_name, package_name) result(valid) Check that a module name is prefixed with the default package prefix:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Read more… Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name Return Value logical public elemental function is_fortran_name (line) result(lout) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: line Return Value logical public function is_valid_module_name (module_name, package_name, custom_prefix, enforce_module_names) result(valid) Check that a module name fits the current naming rules:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Read more… Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name type( string_t ), intent(in) :: custom_prefix logical, intent(in) :: enforce_module_names Return Value logical public function is_valid_module_prefix (module_prefix) result(valid) Check that a custom module prefix fits the current naming rules:\n1) Only alphanumeric characters (no spaces, dashes, underscores or other characters)\n2) Does not begin with a number (Fortran-compatible syntax) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_prefix Return Value logical public pure function join (str, sep, trm, left, right, start, end) result(string) Author John S. Urban License Public Domain JOIN(3f) appends the elements of a CHARACTER array into a single\n CHARACTER variable, with elements 1 to N joined from left to right.\n By default each element is trimmed of trailing spaces and the\n default separator is a null string. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str (:) character(len=*), intent(in), optional :: sep logical, intent(in), optional :: trm character(len=*), intent(in), optional :: left character(len=*), intent(in), optional :: right character(len=*), intent(in), optional :: start character(len=*), intent(in), optional :: end Return Value character(len=:), allocatable public pure elemental function lower (str, begin, end) result(string) Author John S. Urban License Public Domain Changes a string to lowercase over optional specified column range Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str integer, intent(in), optional :: begin integer, intent(in), optional :: end Return Value character(len=len(str)) public function module_prefix_template (project_name, custom_prefix) result(prefix) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) public function module_prefix_type (project_name, custom_prefix) result(ptype) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) public pure function replace (string, charset, target_char) result(res) Returns string with characters in charset replaced with target_char. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string character(len=1), intent(in) :: charset (:) character(len=1), intent(in) :: target_char Return Value character(len=len(string)) public pure function str_begins_with_str (s, e, case_sensitive) result(r) test if a CHARACTER string begins with a specified prefix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e logical, intent(in), optional :: case_sensitive Return Value logical public function string_array_contains (search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical public function string_cat (strings, delim) result(cat) Concatenate an array of type(string_t) into\n a single CHARACTER variable Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) character(len=*), intent(in), optional :: delim Return Value character(len=:), allocatable public pure function to_fortran_name (string) result(res) Returns string with special characters replaced with an underscore.\nFor now, only a hyphen is treated as a special character, but this can be\nexpanded to other characters if needed. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string Return Value character(len=len(string)) Subroutines public impure elemental subroutine notabs (instr, outstr, ilen) Author John S. Urban License Public Domain notabs(3f) - [fpm_strings:NONALPHA] expand tab characters\n (LICENSE:PD) Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr character(len=*), intent(out) :: outstr integer, intent(out) :: ilen public subroutine remove_characters_in_set (string, set, replace_with) Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: string character(len=*), intent(in) :: set character(len=1), intent(in), optional :: replace_with public subroutine remove_newline_characters (string) Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout) :: string public subroutine split (input_line, array, delimiters, order, nulls) Author John S. Urban License Public Domain parse string on delimiter characters and store tokens into an allocatable array\n given a line of structure ” par1 par2 par3 … parn ” store each par(n) into a separate variable in array. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input_line input string to tokenize character(len=:), intent(out), allocatable :: array (:) output array of tokens character(len=*), intent(in), optional :: delimiters list of delimiter characters character(len=*), intent(in), optional :: order order of output array sequential|[reverse|right] character(len=*), intent(in), optional :: nulls return strings composed of delimiters or not ignore|return|ignoreend","tags":"","loc":"module/fpm_strings.html"},{"title":"fpm_filesystem – Fortran-lang/fpm","text":"This module contains general routines for interacting with the file system Directories are not files for the Intel compilers. If so, also use this compiler-dependent extension Uses fpm_environment iso_c_binding fpm_strings iso_fortran_env fpm_error Contents Functions basename canon_path dirname exists get_dos_path get_local_prefix get_temp_filename is_absolute_path is_dir is_hidden_file join_path number_of_rows parent_dir read_lines read_lines_expanded unix_path which windows_path Subroutines delete_file execute_and_read_output fileclose fileopen filewrite get_home getline list_files mkdir os_delete_dir run warnwrite Functions public function basename (path, suffix) result(base) Extract filename from path with/without suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: suffix Return Value character(len=:), allocatable public function canon_path (path) Canonicalize path for comparison\n* Handles path string redundancies\n* Does not test existence of path Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function dirname (path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function exists (filename) result(r) test if pathname already exists Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value logical public function get_dos_path (path, error) Ensure a windows path is converted to an 8.3 DOS path if it contains spaces\nNo need to convert if there are no spaces Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error Return Value character(len=:), allocatable public function get_local_prefix (os) result(prefix) Determine the path prefix to the local folder. Used for installation, registry etc. Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Platform identifier Return Value character(len=:), allocatable Installation prefix public function get_temp_filename () result(tempfile) Get a unused temporary filename\n Calls posix ‘tempnam’ - not recommended, but\n we have no security concerns for this application\n and use here is temporary.\nWorks with MinGW Arguments None Return Value character(len=:), allocatable public function is_absolute_path (path, is_unix) Returns .true. if provided path is absolute. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: is_unix Return Value logical public function is_dir (dir) test if a name matches an existing directory path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical public function is_hidden_file (file_basename) result(r) test if a file is hidden Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file_basename Return Value logical public function join_path (a1, a2, a3, a4, a5) result(path) Construct path by joining strings with os file separator Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: a1 character(len=*), intent(in) :: a2 character(len=*), intent(in), optional :: a3 character(len=*), intent(in), optional :: a4 character(len=*), intent(in), optional :: a5 Return Value character(len=:), allocatable public function number_of_rows (s) result(nrows) Determine number or rows in a file given a LUN Arguments Type Intent Optional Attributes Name integer, intent(in) :: s Return Value integer public function parent_dir (path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function read_lines (fh) result(lines) read lines into an array of TYPE(STRING_T) variables Arguments Type Intent Optional Attributes Name integer, intent(in) :: fh Return Value type( string_t ), allocatable, (:) public function read_lines_expanded (fh) result(lines) read lines into an array of TYPE(STRING_T) variables expanding tabs Arguments Type Intent Optional Attributes Name integer, intent(in) :: fh Return Value type( string_t ), allocatable, (:) public function unix_path (path) result(nixpath) Replace file system separators for 1 Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function which (command) result(pathname) Author John S. Urban License Public Domain function which(command) result(pathname) Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: command Return Value character(len=:), allocatable public function windows_path (path) result(winpath) Replace file system separators for windows Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Subroutines public subroutine delete_file (file) delete a file by filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file public subroutine execute_and_read_output (cmd, output, error, verbose) Execute command line and return output as a string. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd Command to execute. character(len=:), intent(out), allocatable :: output Command line output. type( error_t ), intent(out), allocatable :: error Error to handle. logical, intent(in), optional :: verbose Print additional information if true. public subroutine fileclose (lun, ier) simple close of a LUN. On error show message and stop (by default) Arguments Type Intent Optional Attributes Name integer, intent(in) :: lun integer, intent(out), optional :: ier public subroutine fileopen (filename, lun, ier) procedure to open filename as a sequential “text” file Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename integer, intent(out) :: lun integer, intent(out), optional :: ier public subroutine filewrite (filename, filedata) procedure to write filedata to file filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename character(len=*), intent(in) :: filedata (:) public subroutine get_home (home, error) Get the HOME directory on Unix and the %USERPROFILE% directory on Windows. Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: home type( error_t ), intent(out), allocatable :: error public subroutine getline (unit, line, iostat, iomsg) Author fpm(1) contributors License MIT subroutine getline(unit,line,iostat,iomsg) Read more… Arguments Type Intent Optional Attributes Name integer, intent(in) :: unit Formatted IO unit character(len=:), intent(out), allocatable :: line Line to read integer, intent(out) :: iostat Status of operation character(len=:), optional, allocatable :: iomsg Error message public recursive subroutine list_files (dir, files, recurse) Get file & directory names in directory dir using iso_c_binding. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir type( string_t ), intent(out), allocatable :: files (:) logical, intent(in), optional :: recurse public subroutine mkdir (dir, echo) Create a directory. Create subdirectories as needed Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir logical, intent(in), optional :: echo public subroutine os_delete_dir (is_unix, dir, echo) Delete directory using system OS remove directory commands Arguments Type Intent Optional Attributes Name logical, intent(in) :: is_unix character(len=*), intent(in) :: dir logical, intent(in), optional :: echo public subroutine run (cmd, echo, exitstat, verbose, redirect) Author fpm(1) contributors License MIT Execute the specified system command. Optionally Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd logical, intent(in), optional :: echo integer, intent(out), optional :: exitstat logical, intent(in), optional :: verbose character(len=*), intent(in), optional :: redirect public subroutine warnwrite (fname, data) write trimmed character data to a file if it does not exist Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: fname character(len=*), intent(in) :: data (:)","tags":"","loc":"module/fpm_filesystem.html"},{"title":"fpm_environment – Fortran-lang/fpm","text":"This module contains procedures that interact with the programming environment. [get_os_type] – Determine the OS type [get_env] – return the value of an environment variable Uses fpm_error iso_fortran_env Contents Variables OS_CYGWIN OS_FREEBSD OS_LINUX OS_MACOS OS_OPENBSD OS_SOLARIS OS_UNKNOWN OS_WINDOWS Functions get_command_arguments_quoted get_env get_os_type os_is_unix separator Variables Type Visibility Attributes Name Initial integer, public, parameter :: OS_CYGWIN = 4 integer, public, parameter :: OS_FREEBSD = 6 integer, public, parameter :: OS_LINUX = 1 integer, public, parameter :: OS_MACOS = 2 integer, public, parameter :: OS_OPENBSD = 7 integer, public, parameter :: OS_SOLARIS = 5 integer, public, parameter :: OS_UNKNOWN = 0 integer, public, parameter :: OS_WINDOWS = 3 Functions public function get_command_arguments_quoted () result(args) Arguments None Return Value character(len=:), allocatable public function get_env (NAME, DEFAULT) result(VALUE) get named environment variable value. It it is blank or\n not set return the optional default value\n!print , NAME, ” is not defined in the environment. Strange…”\n!print , “This processor doesn’t support environment variables. Boooh!” Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: NAME name of environment variable to get the value of character(len=*), intent(in), optional :: DEFAULT default value to return if the requested value is undefined or blank Return Value character(len=:), allocatable the returned value public function get_os_type () result(r) Determine the OS type Read more… Arguments None Return Value integer public function os_is_unix (os) Compare the output of get_os_type or the optional\npassed INTEGER value to the value for OS_WINDOWS\nand return .TRUE. if they match and .FALSE. otherwise Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Return Value logical public function separator () result(sep) sample usage Read more… Arguments None Return Value character(len=1) ifort_bug*!character(len=1),save :: sep_cache=’ ‘","tags":"","loc":"module/fpm_environment.html"},{"title":"fpm_source_parsing – Fortran-lang/fpm","text":"Parsing of package source files This module exposes two functions, parse_f_source and parse_c_source ,\n which perform a rudimentary parsing of fortran and c source files\n in order to extract information required for module dependency tracking. Both functions additionally calculate and store a file digest (hash) which\n is used by the backend ( fpm_backend ) to skip compilation of unmodified sources. Both functions return an instance of the srcfile_t type. For more information, please read the documentation for each function: parse_f_source parse_c_source Uses fpm_strings fpm_filesystem fpm_error fpm_model Contents Functions parse_c_source parse_f_source Subroutines parse_use_statement Functions public function parse_c_source (c_filename, error) result(c_source) Parsing of c, cpp source files Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: c_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) public function parse_f_source (f_filename, error) result(f_source) Parsing of free-form fortran source files Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) Subroutines public subroutine parse_use_statement (f_filename, i, line, use_stmt, is_intrinsic, module_name, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename Current file name and line number (for error messaging) integer, intent(in) :: i character(len=*), intent(in) :: line The line being parsed. MUST BE preprocessed with trim(adjustl() logical, intent(out) :: use_stmt Does this line contain a use statement? logical, intent(out) :: is_intrinsic Is the module in this statement intrinsic? character(len=:), intent(out), allocatable :: module_name used module name type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_source_parsing.html"},{"title":"fpm_model – Fortran-lang/fpm","text":"The fpm package model Defines the fpm model data types which encapsulate all information\n required to correctly build a package and its dependencies. The process (see build_model ) for generating a valid fpm_model involves\n source files discovery ( fpm_sources ) and parsing ( fpm_source_parsing ). Once a valid fpm_model has been constructed, it may be passed to targets_from_sources to\n generate a list of build targets for the backend. Enumerations Source type: FPM_UNIT_* Describes the type of source file — determines build target generation The logical order of precedence for assigning unit_type is as follows: if source - file contains program then unit_type = FPM_UNIT_PROGRAM else if source - file contains non - module subroutine / function then unit_type = FPM_UNIT_SUBPROGRAM else if source - file contains submodule then unit_type = FPM_UNIT_SUBMODULE else if source - file contains module then unit_type = FPM_UNIT_MODULE end if Note A source file is only designated FPM_UNIT_MODULE if it only contains modules - no non-module subprograms.\n (This allows tree-shaking/pruning of build targets based on unused module dependencies.) Source scope: FPM_SCOPE_* Describes the scoping rules for using modules — controls module dependency resolution Uses fpm_compiler fpm_dependency fpm_strings iso_fortran_env Contents Variables FPM_SCOPE_APP FPM_SCOPE_DEP FPM_SCOPE_EXAMPLE FPM_SCOPE_LIB FPM_SCOPE_TEST FPM_SCOPE_UNKNOWN FPM_UNIT_CHEADER FPM_UNIT_CPPSOURCE FPM_UNIT_CSOURCE FPM_UNIT_MODULE FPM_UNIT_PROGRAM FPM_UNIT_SUBMODULE FPM_UNIT_SUBPROGRAM FPM_UNIT_UNKNOWN Derived Types fortran_features_t fpm_model_t srcfile_t Subroutines show_model Variables Type Visibility Attributes Name Initial integer, public, parameter :: FPM_SCOPE_APP = 3 Module-use scope is library/dependency and app modules integer, public, parameter :: FPM_SCOPE_DEP = 2 Module-use scope is library/dependency modules only integer, public, parameter :: FPM_SCOPE_EXAMPLE = 5 integer, public, parameter :: FPM_SCOPE_LIB = 1 Module-use scope is library/dependency modules only integer, public, parameter :: FPM_SCOPE_TEST = 4 Module-use scope is library/dependency and test modules integer, public, parameter :: FPM_SCOPE_UNKNOWN = -1 Source has no module-use scope integer, public, parameter :: FPM_UNIT_CHEADER = 6 Source type is c header file integer, public, parameter :: FPM_UNIT_CPPSOURCE = 7 Souce type is c++ source file. integer, public, parameter :: FPM_UNIT_CSOURCE = 5 Source type is c source file integer, public, parameter :: FPM_UNIT_MODULE = 2 Source only contains one or more fortran modules integer, public, parameter :: FPM_UNIT_PROGRAM = 1 Source contains a fortran program integer, public, parameter :: FPM_UNIT_SUBMODULE = 3 Source contains one or more fortran submodules integer, public, parameter :: FPM_UNIT_SUBPROGRAM = 4 Source contains one or more fortran subprogram not within modules integer, public, parameter :: FPM_UNIT_UNKNOWN = -1 Source type unknown Derived Types type, public :: fortran_features_t Enabled Fortran language features Components Type Visibility Attributes Name Initial logical, public :: implicit_external = .false. Use implicit external interface logical, public :: implicit_typing = .false. Use default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources type, public :: fpm_model_t Type describing everything required to build\n the root package and its dependencies. Components Type Visibility Attributes Name Initial type( archiver_t ), public :: archiver Archiver object character(len=:), public, allocatable :: build_prefix Base directory for build character(len=:), public, allocatable :: c_compile_flags Command line flags passed to C for compilation type( compiler_t ), public :: compiler Compiler object character(len=:), public, allocatable :: cxx_compile_flags Command line flags passed to C++ for compilation type( dependency_tree_t ), public :: deps Project dependencies logical, public :: enforce_module_names = .false. Whether module names should be prefixed with the package name type( string_t ), public, allocatable :: external_modules (:) External modules used character(len=:), public, allocatable :: fortran_compile_flags Command line flags passed to fortran for compilation type( string_t ), public, allocatable :: include_dirs (:) Include directories logical, public :: include_tests = .true. Whether tests should be added to the build list character(len=:), public, allocatable :: link_flags Command line flags passed to the linker type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public :: module_prefix Prefix for all module names character(len=:), public, allocatable :: package_name Name of root package type(package_t), public, allocatable :: packages (:) Array of packages (including the root package) type, public :: srcfile_t Type for describing a source file Components Type Visibility Attributes Name Initial integer(kind=int64), public :: digest Current hash character(len=:), public, allocatable :: exe_name Name of executable for FPM_UNIT_PROGRAM character(len=:), public, allocatable :: file_name File path relative to cwd type( string_t ), public, allocatable :: include_dependencies (:) Files INCLUDEd by this source file type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: modules_provided (:) Modules provided by this source file (lowerstring) type( string_t ), public, allocatable :: modules_used (:) Modules USEd by this source file (lowerstring) type( string_t ), public, allocatable :: parent_modules (:) Parent modules (submodules only) integer, public :: unit_scope = FPM_SCOPE_UNKNOWN Target module-use scope integer, public :: unit_type = FPM_UNIT_UNKNOWN Type of source unit Subroutines public subroutine show_model (model) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model","tags":"","loc":"module/fpm_model.html"},{"title":"fpm_targets – Fortran-lang/fpm","text":"Build target handling This module handles the construction of the build target list\n from the sources list ( targets_from_sources ), the\n resolution of module-dependencies between build targets\n ( resolve_module_dependencies ), and the enumeration of\n objects required for link targets ( resolve_target_linking ). A build target ( build_target_t ) is a file to be generated\n by the backend (compilation and linking). Note The current implementation is ignorant to the existence of\n module files ( .mod , .smod ). Dependencies arising from modules\n are based on the corresponding object files ( .o ) only. For more information, please read the documentation for the procedures: build_target_list resolve_module_dependencies Enumerations Target type: FPM_TARGET_* Describes the type of build target — determines backend build rules Uses fpm_compiler fpm_environment fpm_strings fpm_sources iso_fortran_env fpm_filesystem fpm_error fpm_model Contents Variables FPM_TARGET_ARCHIVE FPM_TARGET_CPP_OBJECT FPM_TARGET_C_OBJECT FPM_TARGET_EXECUTABLE FPM_TARGET_OBJECT FPM_TARGET_UNKNOWN Derived Types build_target_ptr build_target_t Subroutines add_dependency add_target filter_executable_targets filter_library_targets filter_modules resolve_module_dependencies targets_from_sources Variables Type Visibility Attributes Name Initial integer, public, parameter :: FPM_TARGET_ARCHIVE = 2 Target type is library archive integer, public, parameter :: FPM_TARGET_CPP_OBJECT = 5 Target type is cpp compiled object integer, public, parameter :: FPM_TARGET_C_OBJECT = 4 Target type is c compiled object integer, public, parameter :: FPM_TARGET_EXECUTABLE = 1 Target type is executable integer, public, parameter :: FPM_TARGET_OBJECT = 3 Target type is compiled object integer, public, parameter :: FPM_TARGET_UNKNOWN = -1 Target type is unknown (ignored) Derived Types type, public :: build_target_ptr Wrapper type for constructing arrays of build_target_t pointers Components Type Visibility Attributes Name Initial type( build_target_t ), public, pointer :: ptr => null() type, public :: build_target_t Type describing a generated build target Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: compile_flags Compile flags for this build target type( build_target_ptr ), public, allocatable :: dependencies (:) Resolved build dependencies integer(kind=int64), public, allocatable :: digest_cached Previous source file hash type( fortran_features_t ), public :: features Language features character(len=:), public, allocatable :: link_flags Link flags for this build target type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: link_objects (:) Objects needed to link this target type( string_t ), public, allocatable :: macros (:) List of macros character(len=:), public, allocatable :: output_dir File path of output directory character(len=:), public, allocatable :: output_file File path of build target object relative to cwd character(len=:), public, allocatable :: output_log_file File path of build log file relative to cwd character(len=:), public, allocatable :: output_name File path of build target object relative to output_dir character(len=:), public, allocatable :: package_name Name of parent package integer, public :: schedule = -1 Targets in the same schedule group are guaranteed to be independent logical, public :: skip = .false. Flag set if build target will be skipped (not built) logical, public :: sorted = .false. Flag set if build target is sorted for building type( srcfile_t ), public, allocatable :: source Primary source for this build target integer, public :: target_type = FPM_TARGET_UNKNOWN Target type logical, public :: touched = .false. Flag set when first visited to check for circular dependencies character(len=:), public, allocatable :: version Version number Subroutines public subroutine add_dependency (target, dependency) Add pointer to dependeny in target%dependencies Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout) :: target type( build_target_t ), intent(in), target :: dependency public subroutine add_target (targets, package, type, output_name, source, link_libraries, features, macros, version) Allocate a new target and append to target list Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) character(len=*), intent(in) :: package integer, intent(in) :: type character(len=*), intent(in) :: output_name type( srcfile_t ), intent(in), optional :: source type( string_t ), intent(in), optional :: link_libraries (:) type( fortran_features_t ), intent(in), optional :: features type( string_t ), intent(in), optional :: macros (:) character(len=*), intent(in), optional :: version public subroutine filter_executable_targets (targets, scope, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) integer, intent(in) :: scope type( string_t ), intent(out), allocatable :: list (:) public subroutine filter_library_targets (targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) public subroutine filter_modules (targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) public subroutine resolve_module_dependencies (targets, external_modules, error) Add dependencies to source-based targets ( FPM_TARGET_OBJECT )\n based on any modules used by the corresponding source file. Read more… Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), target :: targets (:) type( string_t ), intent(in) :: external_modules (:) type( error_t ), intent(out), allocatable :: error public subroutine targets_from_sources (targets, model, prune, error) High-level wrapper to generate build target information Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: targets (:) The generated list of build targets type( fpm_model_t ), intent(inout), target :: model The package model from which to construct the target list logical, intent(in) :: prune Enable tree-shaking/pruning of module dependencies type( error_t ), intent(out), allocatable :: error Error structure","tags":"","loc":"module/fpm_targets.html"},{"title":"fpm_downloader – Fortran-lang/fpm","text":"Uses fpm_strings fpm_versioning jonquil fpm_filesystem fpm_error Contents Derived Types downloader_t Derived Types type, public :: downloader_t This type could be entirely avoided but it is quite practical because it can be mocked for testing. Type-Bound Procedures procedure\n , public\n, nopass :: get_file Subroutine procedure\n , public\n, nopass :: get_pkg_data Subroutine procedure\n , public\n, nopass :: unpack Subroutine procedure\n , public\n, nopass :: upload_form Subroutine","tags":"","loc":"module/fpm_downloader.html"},{"title":"fpm_dependency – Fortran-lang/fpm","text":"Dependency management Fetching dependencies and creating a dependency tree Dependencies on the top-level can be specified from: package%dependencies package%dev_dependencies package%executable(:)%dependencies package%test(:)%dependencies Each dependency is fetched in some way and provides a path to its package\nmanifest.\nThe package%dependencies of the dependencies are resolved recursively. To initialize the dependency tree all dependencies are recursively fetched\nand stored in a flat data structure to avoid retrieving a package twice.\nThe data structure used to store this information should describe the current\nstatus of the dependency tree. Important information are: name of the package version of the package path to the package root Additionally, for version controlled dependencies the following should be\nstored along with the package: the upstream url the current checked out revision Fetching a remote (version controlled) dependency turns it for our purpose\ninto a local path dependency which is handled by the same means. Updating dependencies For a given dependency tree all top-level dependencies can be updated.\nWe have two cases to consider, a remote dependency and a local dependency,\nagain, remote dependencies turn into local dependencies by fetching.\nTherefore we will update remote dependencies by simply refetching them. For remote dependencies we have to refetch if the revision in the manifest\nchanges or the upstream HEAD has changed (for branches and tags). Note For our purpose a tag is just a fancy branch name. Tags can be delete and\n modified afterwards, therefore they do not differ too much from branches\n from our perspective. For the latter case we only know if we actually fetch from the upstream URL. In case of local (and fetched remote) dependencies we have to read the package\nmanifest and compare its dependencies against our dependency tree, any change\nrequires updating the respective dependencies as well. Handling dependency compatibilties Currenly ignored. First come, first serve. Uses fpm_environment fpm_toml fpm_manifest fpm_strings fpm_versioning jonquil fpm_manifest_preprocess fpm_git fpm_downloader fpm_manifest_dependency fpm_settings iso_fortran_env fpm_filesystem fpm_error Contents Interfaces resize Derived Types dependency_node_t dependency_tree_t Subroutines check_and_read_pkg_data new_dependency_node new_dependency_tree Interfaces public interface resize Overloaded reallocation interface private pure subroutine resize_dependency_node(var, n) Reallocate a list of dependencies Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(inout), allocatable :: var (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size Derived Types type, public, extends( dependency_config_t ) :: dependency_node_t Dependency node in the projects dependency tree Components Type Visibility Attributes Name Initial logical, public :: cached = .false. Dependency was loaded from a cache logical, public :: done = .false. Dependency is handled type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency character(len=:), public, allocatable :: proj_dir Installation prefix of this dependencies type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. character(len=:), public, allocatable :: revision Checked out revision of the version control system logical, public :: update = .false. Dependency should be updated type( version_t ), public, allocatable :: version Actual version of this dependency Type-Bound Procedures procedure\n , public\n, :: get_from_registry Subroutine Get dependency from the registry. procedure\n , public\n, :: info Subroutine Print information on this instance procedure\n , public\n, :: register Subroutine Update dependency from project manifest. type, public :: dependency_tree_t Respresentation of a projects dependencies Read more… Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cache Cache file type( dependency_node_t ), public, allocatable :: dep (:) Flattend list of all dependencies character(len=:), public, allocatable :: dep_dir Installation prefix for dependencies integer, public :: ndep = 0 Number of currently registered dependencies integer, public :: unit = output_unit Unit for IO integer, public :: verbosity = 1 Verbosity of printout Type-Bound Procedures generic,\n public\n, :: add =>\n add_project, add_project_dependencies, add_dependencies, add_dependency, add_dependency_node Overload procedure to add new dependencies to the tree generic,\n public\n, :: dump =>\n dump_to_file, dump_to_unit, dump_to_toml Writing of dependency tree generic,\n public\n, :: find =>\n find_name Find a dependency in the tree procedure\n , public\n, :: finished Function Depedendncy resolution finished generic,\n public\n, :: has =>\n has_dependency True if entity can be found generic,\n public\n, :: load =>\n load_from_file, load_from_unit, load_from_toml Reading of dependency tree generic,\n public\n, :: resolve =>\n resolve_dependencies, resolve_dependency Resolve dependencies generic,\n public\n, :: update =>\n update_dependency, update_tree Update dependency tree Subroutines public subroutine check_and_read_pkg_data (json, node, download_url, version, error) Arguments Type Intent Optional Attributes Name type(json_object), intent(inout) :: json class( dependency_node_t ), intent(in) :: node character(len=:), intent(out), allocatable :: download_url type( version_t ), intent(out) :: version type( error_t ), intent(out), allocatable :: error public subroutine new_dependency_node (self, dependency, version, proj_dir, update) Create a new dependency node from a configuration Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(out) :: self Instance of the dependency node type( dependency_config_t ), intent(in) :: dependency Dependency configuration data type( version_t ), intent(in), optional :: version Version of the dependency character(len=*), intent(in), optional :: proj_dir Installation prefix of the dependency logical, intent(in), optional :: update Dependency should be updated public subroutine new_dependency_tree (self, verbosity, cache) Create a new dependency tree Arguments Type Intent Optional Attributes Name type( dependency_tree_t ), intent(out) :: self Instance of the dependency tree integer, intent(in), optional :: verbosity Verbosity of printout character(len=*), intent(in), optional :: cache Name of the cache file","tags":"","loc":"module/fpm_dependency.html"},{"title":"fpm_versioning – Fortran-lang/fpm","text":"Implementation of versioning data for comparing packages Uses fpm_strings fpm_error regex_module Contents Interfaces new_version Derived Types version_t Functions regex_version_from_text Interfaces public interface new_version private subroutine new_version_from_string(self, string, error) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data character(len=*), intent(in) :: string String describing the version information type( error_t ), intent(out), allocatable :: error Error handling private subroutine new_version_from_int(self, num) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data integer, intent(in) :: num (:) Subversion numbers to define version data Derived Types type, public :: version_t Type-Bound Procedures generic,\n public\n, :: operator(.match.) =>\n match Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) generic,\n public\n, :: operator(/=) =>\n not_equals generic,\n public\n, :: operator(<) =>\n less generic,\n public\n, :: operator(<=) =>\n less_equals generic,\n public\n, :: operator(==) =>\n equals generic,\n public\n, :: operator(>) =>\n greater generic,\n public\n, :: operator(>=) =>\n greater_equals procedure\n , public\n, :: s Function Create a printable string from a version data type Functions public function regex_version_from_text (text, what, error) result(ver) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: text character(len=*), intent(in) :: what type( error_t ), intent(out), allocatable :: error Return Value type( string_t )","tags":"","loc":"module/fpm_versioning.html"},{"title":"fpm_release – Fortran-lang/fpm","text":"Release parameters Module fpm_release contains public constants storing this build’s unique version IDs Uses fpm_versioning fpm_error Contents Functions fpm_version Functions public function fpm_version () Return the current fpm version from fpm_version_ID as a version type Arguments None Return Value type( version_t )","tags":"","loc":"module/fpm_release.html"},{"title":"fpm_error – Fortran-lang/fpm","text":"Implementation of basic error handling. Uses fpm_strings iso_fortran_env Contents Derived Types error_t Functions bad_name_error Subroutines fatal_error file_not_found_error file_parse_error fpm_stop syntax_error Derived Types type, public :: error_t Data type defining an error Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: message Error message Functions public function bad_name_error (error, label, name) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: label Error message label to add to message character(len=*), intent(in) :: name name value to check Return Value logical Subroutines public subroutine fatal_error (error, message) Generic fatal runtime error Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message public subroutine file_not_found_error (error, file_name) Error created when a file is missing or not found Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of the missing file public subroutine file_parse_error (error, file_name, message, line_num, line_string, line_col) Error created when file parsing fails Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of file character(len=*), intent(in) :: message Parse error message integer, intent(in), optional :: line_num Line number of parse error character(len=*), intent(in), optional :: line_string Line context string integer, intent(in), optional :: line_col Line context column public subroutine fpm_stop (value, message) Arguments Type Intent Optional Attributes Name integer, intent(in) :: value value to use on STOP character(len=*), intent(in) :: message Error message public subroutine syntax_error (error, message) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message","tags":"","loc":"module/fpm_error.html"},{"title":"fpm_git – Fortran-lang/fpm","text":"Implementation for interacting with git repositories. Uses fpm_filesystem fpm_error Contents Variables compressed_package_name git_descriptor out_fmt Interfaces operator(==) Derived Types enum_descriptor git_target_t Functions git_matches_manifest git_target_branch git_target_default git_target_eq git_target_revision git_target_tag Subroutines checkout git_archive git_revision info Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: compressed_package_name = 'compressed_package' Name of the compressed package that is generated temporarily. type( enum_descriptor ), public, parameter :: git_descriptor = enum_descriptor() Actual enumerator for descriptors character(len=*), public, parameter :: out_fmt = '(\"#\", *(1x, g0))' Common output format for writing to the command line Interfaces public interface operator(==) public function git_target_eq (this, that) result(is_equal) Check that two git targets are equal Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: this Two input git targets type( git_target_t ), intent(in) :: that Two input git targets Return Value logical Derived Types type, public :: enum_descriptor Possible git target Components Type Visibility Attributes Name Initial integer, public :: branch = 201 Branch in git repository integer, public :: default = 200 Default target integer, public :: revision = 203 Commit hash integer, public :: tag = 202 Tag in git repository type, public :: git_target_t Description of an git target Components Type Visibility Attributes Name Initial integer, public :: descriptor = git_descriptor%default Kind of the git target character(len=:), public, allocatable :: object Additional descriptor of the git object character(len=:), public, allocatable :: url Target URL of the git repository Type-Bound Procedures procedure\n , public\n, :: checkout Subroutine Fetch and checkout in local directory procedure\n , public\n, :: info Subroutine Show information on instance Functions public function git_matches_manifest (cached, manifest, verbosity, iunit) Check that a cached dependency matches a manifest request Read more… Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: cached Two input git targets type( git_target_t ), intent(in) :: manifest Two input git targets integer, intent(in) :: verbosity integer, intent(in) :: iunit Return Value logical public function git_target_branch (url, branch) result(self) Target a branch in the git repository Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: branch Name of the branch of interest Return Value type( git_target_t ) New git target public function git_target_default (url) result(self) Default target Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository Return Value type( git_target_t ) New git target public function git_target_eq (this, that) result(is_equal) Check that two git targets are equal Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: this Two input git targets type( git_target_t ), intent(in) :: that Two input git targets Return Value logical public function git_target_revision (url, sha1) result(self) Target a specific git revision Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: sha1 Commit hash of interest Return Value type( git_target_t ) New git target public function git_target_tag (url, tag) result(self) Target a git tag Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: tag Tag name of interest Return Value type( git_target_t ) New git target Subroutines public subroutine checkout (self, local_path, error) Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target character(len=*), intent(in) :: local_path Local path to checkout in type( error_t ), intent(out), allocatable :: error Error public subroutine git_archive (source, destination, ref, verbose, error) Archive a folder using git archive . Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: source Directory to archive. character(len=*), intent(in) :: destination Destination of the archive. character(len=*), intent(in) :: ref (Symbolic) Reference to be archived. logical, intent(in) :: verbose Print additional information if true. type( error_t ), intent(out), allocatable :: error Error handling. public subroutine git_revision (local_path, object, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: local_path Local path to checkout in character(len=:), intent(out), allocatable :: object Git object reference type( error_t ), intent(out), allocatable :: error Error public subroutine info (self, unit, verbosity) Show information on git target Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout","tags":"","loc":"module/fpm_git.html"},{"title":"fpm_manifest – Fortran-lang/fpm","text":"Package configuration data. This module provides the necessary procedure to translate a TOML document\nto the corresponding Fortran type, while verifying it with respect to\nits schema. Additionally, the required data types for users of this module are reexported\nto hide the actual implementation details. Uses fpm_toml fpm_environment fpm_manifest_test fpm_strings fpm_manifest_example fpm_manifest_preprocess fpm_manifest_package fpm_manifest_executable fpm_manifest_dependency fpm_error fpm_filesystem fpm_manifest_library Contents Subroutines default_example default_executable default_library default_test get_package_data Subroutines public subroutine default_example (self, name) Populate test in case we find the default example/ directory Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package public subroutine default_executable (self, name) Populate executable in case we find the default app directory Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package public subroutine default_library (self) Populate library in case we find the default src directory Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library meta data public subroutine default_test (self, name) Populate test in case we find the default test/ directory Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package public subroutine get_package_data (package, file, error, apply_defaults) Obtain package meta data from a configuation file Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: package Parsed package meta data character(len=*), intent(in) :: file Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation logical, intent(in), optional :: apply_defaults Apply package defaults (uses file system operations)","tags":"","loc":"module/fpm_manifest.html"},{"title":"fpm_toml – Fortran-lang/fpm","text":"Interface to TOML processing library This module acts as a proxy to the toml-f public Fortran API and allows\n to selectively expose components from the library to fpm .\n The interaction with toml-f data types outside of this module should be\n limited to tables, arrays and key-lists, most of the necessary interactions\n are implemented in the building interface with the get_value and set_value procedures. This module allows to implement features necessary for fpm , which are\n not yet available in upstream toml-f . For more details on the library used see the TOML-Fortran developer pages. Uses fpm_strings tomlf fpm_error Contents Subroutines check_keys get_list read_package_file Subroutines public subroutine check_keys (table, valid_keys, error) Check if table contains only keys that are part of the list. If a key is\nfound that is not part of the list, an error is allocated. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: valid_keys (:) List of keys to check. type( error_t ), intent(out), allocatable :: error Error handling public subroutine get_list (table, key, list, error) Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Key to read from type( string_t ), intent(out), allocatable :: list (:) List of strings to read type( error_t ), intent(out), allocatable :: error Error handling public subroutine read_package_file (table, manifest, error) Process the configuration file to a TOML data structure Arguments Type Intent Optional Attributes Name type(toml_table), intent(out), allocatable :: table TOML data structure character(len=*), intent(in) :: manifest Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation","tags":"","loc":"module/fpm_toml.html"},{"title":"fpm_installer – Fortran-lang/fpm","text":"Implementation of an installer object. The installer provides a way to install objects to their respective directories\nin the installation prefix, a generic install command allows to install\nto any directory within the prefix. Uses fpm_error fpm_environment iso_fortran_env fpm_filesystem Contents Derived Types installer_t Subroutines new_installer Derived Types type, public :: installer_t Declaration of the installer type Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: bindir Binary dir relative to the installation prefix character(len=:), public, allocatable :: copy Command to copy objects into the installation prefix character(len=:), public, allocatable :: includedir Include directory relative to the installation prefix character(len=:), public, allocatable :: libdir Library directory relative to the installation prefix character(len=:), public, allocatable :: move Command to move objects into the installation prefix integer, public :: os Cached operating system character(len=:), public, allocatable :: prefix Path to installation directory integer, public :: unit = output_unit Output unit for informative printout integer, public :: verbosity = 1 Verbosity of the installer Type-Bound Procedures procedure\n , public\n, :: install Subroutine Install a generic file into a subdirectory in the installation prefix procedure\n , public\n, :: install_executable Subroutine Install an executable in its correct subdirectory procedure\n , public\n, :: install_header Subroutine Install a header/module in its correct subdirectory procedure\n , public\n, :: install_library Subroutine Install a library in its correct subdirectory procedure\n , public\n, :: make_dir Subroutine Create a new directory in the prefix, type-bound for unit testing purposes procedure\n , public\n, :: run Subroutine Run an installation command, type-bound for unit testing purposes Subroutines public subroutine new_installer (self, prefix, bindir, libdir, includedir, verbosity, copy, move) Create a new instance of an installer Arguments Type Intent Optional Attributes Name type( installer_t ), intent(out) :: self Instance of the installer character(len=*), intent(in), optional :: prefix Path to installation directory character(len=*), intent(in), optional :: bindir Binary dir relative to the installation prefix character(len=*), intent(in), optional :: libdir Library directory relative to the installation prefix character(len=*), intent(in), optional :: includedir Include directory relative to the installation prefix integer, intent(in), optional :: verbosity Verbosity of the installer character(len=*), intent(in), optional :: copy Copy command character(len=*), intent(in), optional :: move Move command","tags":"","loc":"module/fpm_installer.html"},{"title":"fpm_manifest_dependency – Fortran-lang/fpm","text":"Implementation of the meta data for dependencies. A dependency table can currently have the following fields [dependencies] \"dep1\" = { git = \"url\" } \"dep2\" = { git = \"url\" , branch = \"name\" } \"dep3\" = { git = \"url\" , tag = \"name\" } \"dep4\" = { git = \"url\" , rev = \"sha1\" } \"dep0\" = { path = \"path\" } To reduce the amount of boilerplate code this module provides two constructors\n for dependency types, one basic for an actual dependency (inline) table\n and another to collect all dependency objects from a dependencies table,\n which is handling the allocation of the objects and is forwarding the\n individual dependency tables to their respective constructors.\n The usual entry point should be the constructor for the super table. This objects contains a target to retrieve required fpm projects to\n build the target declaring the dependency.\n Resolving a dependency will result in obtaining a new package configuration\n data for the respective project. Uses fpm_toml fpm_environment fpm_strings fpm_versioning fpm_manifest_metapackages fpm_manifest_preprocess fpm_git fpm_filesystem fpm_error Contents Derived Types dependency_config_t Functions manifest_has_changed Subroutines new_dependencies new_dependency Derived Types type, public :: dependency_config_t Configuration meta data for a dependency Components Type Visibility Attributes Name Initial type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Functions public function manifest_has_changed (cached, manifest, verbosity, iunit) result(has_changed) Check if two dependency configurations are different Read more… Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: cached Two instances of the dependency configuration class( dependency_config_t ), intent(in) :: manifest Two instances of the dependency configuration integer, intent(in) :: verbosity Log verbosity integer, intent(in) :: iunit Log verbosity Return Value logical Subroutines public subroutine new_dependencies (deps, table, root, meta, error) Construct new dependency array from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out), allocatable :: deps (:) Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( metapackage_config_t ), intent(out), optional :: meta (optional) metapackages type( error_t ), intent(out), allocatable :: error Error handling public subroutine new_dependency (self, table, root, error) Construct a new dependency configuration from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out) :: self Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_dependency.html"},{"title":"fpm_manifest_example – Fortran-lang/fpm","text":"Implementation of the meta data for an example. The example data structure is effectively a decorated version of an executable\n and shares most of its properties, except for the defaults and can be\n handled under most circumstances just like any other executable. A example table can currently have the following fields [[ example ]] name = \"string\" source-dir = \"path\" main = \"file\" link = [ \"lib\" ] [example.dependencies] Uses fpm_error fpm_manifest_executable fpm_toml fpm_manifest_dependency Contents Derived Types example_config_t Subroutines new_example Derived Types type, public, extends( executable_config_t ) :: example_config_t Configuation meta data for an example Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_example (self, table, error) Construct a new example configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the example configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_example.html"},{"title":"fpm_manifest_metapackages – Fortran-lang/fpm","text":"Implementation of the metapackage configuration data. A metapackage table can currently have the following fields [metapackages] fpm = \"0.1.0\" openmp = bool stdlib = bool Uses fpm_toml fpm_environment fpm_error Contents Derived Types metapackage_config_t metapackage_request_t Functions is_meta_package Subroutines new_meta_config new_meta_request Derived Types type, public :: metapackage_config_t Configuration data for metapackages Components Type Visibility Attributes Name Initial type( metapackage_request_t ), public :: minpack fortran-lang minpack type( metapackage_request_t ), public :: mpi Request MPI support type( metapackage_request_t ), public :: openmp Request OpenMP support type( metapackage_request_t ), public :: stdlib Request stdlib support type, public :: metapackage_request_t Configuration data for a single metapackage request Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: name Metapackage name logical, public :: on = .false. Request flag character(len=:), public, allocatable :: version Version Specification string Functions public function is_meta_package (key) Check local schema for allowed entries Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: key Instance of the TOML data structure Return Value logical Subroutines public subroutine new_meta_config (self, table, meta_allowed, error) Construct a new build configuration from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( metapackage_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in) :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling public subroutine new_meta_request (self, key, table, meta_allowed, error) Construct a new metapackage request from the dependencies table Read more… Arguments Type Intent Optional Attributes Name type( metapackage_request_t ), intent(out) :: self character(len=*), intent(in) :: key The package name type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in), optional :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_metapackages.html"},{"title":"fpm_manifest_test – Fortran-lang/fpm","text":"Implementation of the meta data for a test. The test data structure is effectively a decorated version of an executable\n and shares most of its properties, except for the defaults and can be\n handled under most circumstances just like any other executable. A test table can currently have the following fields [[ test ]] name = \"string\" source-dir = \"path\" main = \"file\" link = [ \"lib\" ] [test.dependencies] Uses fpm_error fpm_manifest_executable fpm_toml fpm_manifest_dependency Contents Derived Types test_config_t Subroutines new_test Derived Types type, public, extends( executable_config_t ) :: test_config_t Configuation meta data for an test Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_test (self, table, error) Construct a new test configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the test configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_test.html"},{"title":"fpm_manifest_library – Fortran-lang/fpm","text":"Implementation of the meta data for libraries. A library table can currently have the following fields [library] source-dir = \"path\" include-dir = [ \"path1\" , \"path2\" ] build-script = \"file\" Uses fpm_toml fpm_strings fpm_error Contents Derived Types library_config_t Subroutines new_library Derived Types type, public :: library_config_t Configuration meta data for a library Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: build_script Alternative build script to be invoked type( string_t ), public, allocatable :: include_dir (:) Include path prefix character(len=:), public, allocatable :: source_dir Source path prefix Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_library (self, table, error) Construct a new library configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_library.html"},{"title":"fpm_manifest_executable – Fortran-lang/fpm","text":"Implementation of the meta data for an executables. An executable table can currently have the following fields [[ executable ]] name = \"string\" source-dir = \"path\" main = \"file\" link = [ \"lib\" ] [executable.dependencies] Uses fpm_error fpm_strings fpm_toml fpm_manifest_dependency Contents Derived Types executable_config_t Subroutines new_executable Derived Types type, public :: executable_config_t Configuation meta data for an executable Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_executable (self, table, error) Construct a new executable configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_executable.html"},{"title":"fpm_manifest_fortran – Fortran-lang/fpm","text":"Uses fpm_toml fpm_error Contents Derived Types fortran_config_t Subroutines new_fortran_config Derived Types type, public :: fortran_config_t Configuration data for Fortran Components Type Visibility Attributes Name Initial logical, public :: implicit_external Enable implicit external interfaces logical, public :: implicit_typing Enable default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Subroutines public subroutine new_fortran_config (self, table, error) Construct a new build configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( fortran_config_t ), intent(out) :: self Instance of the fortran configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_fortran.html"},{"title":"fpm_manifest_build – Fortran-lang/fpm","text":"Implementation of the build configuration data. A build table can currently have the following fields [build] auto-executables = bool auto-examples = bool auto-tests = bool link = [ \"lib\" ] Uses fpm_toml fpm_strings fpm_error Contents Derived Types build_config_t Subroutines new_build_config Derived Types type, public :: build_config_t Configuration data for build Components Type Visibility Attributes Name Initial logical, public :: auto_examples Automatic discovery of examples logical, public :: auto_executables Automatic discovery of executables logical, public :: auto_tests Automatic discovery of tests type( string_t ), public, allocatable :: external_modules (:) External modules to use type( string_t ), public, allocatable :: link (:) Libraries to link against logical, public :: module_naming = .false. Enforcing of package module names type( string_t ), public :: module_prefix Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_build_config (self, table, package_name, error) Construct a new build configuration from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( build_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: package_name Package name type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_build.html"},{"title":"fpm_manifest_install – Fortran-lang/fpm","text":"Implementation of the installation configuration. An install table can currently have the following fields library = bool Uses fpm_toml fpm_error Contents Derived Types install_config_t Subroutines new_install_config Derived Types type, public :: install_config_t Configuration data for installation Components Type Visibility Attributes Name Initial logical, public :: library Install library with this project Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_install_config (self, table, error) Create a new installation configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( install_config_t ), intent(out) :: self Instance of the install configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_install.html"},{"title":"fpm_manifest_preprocess – Fortran-lang/fpm","text":"Implementation of the meta data for preprocessing. A preprocess table can currently have the following fields [preprocess] [preprocess.cpp] suffixes = [ \"F90\" , \"f90\" ] directories = [ \"src/feature1\" , \"src/models\" ] macros = [] Uses fpm_toml fpm_strings fpm_error Contents Interfaces operator(==) Derived Types preprocess_config_t Subroutines new_preprocess_config new_preprocessors Interfaces public interface operator(==) private function preprocess_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: this class( preprocess_config_t ), intent(in) :: that Return Value logical Derived Types type, public :: preprocess_config_t Configuration meta data for a preprocessor Components Type Visibility Attributes Name Initial type( string_t ), public, allocatable :: directories (:) Directories to search for files to be preprocessed type( string_t ), public, allocatable :: macros (:) Macros to be defined for the preprocessor character(len=:), public, allocatable :: name Name of the preprocessor type( string_t ), public, allocatable :: suffixes (:) Suffixes of the files to be preprocessed Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_preprocess_config (self, table, error) Construct a new preprocess configuration from TOML data structure Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out) :: self Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure. type( error_t ), intent(out), allocatable :: error Error handling public subroutine new_preprocessors (preprocessors, table, error) Construct new preprocess array from a TOML data structure. Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out), allocatable :: preprocessors (:) Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_preprocess.html"},{"title":"fpm_manifest_package – Fortran-lang/fpm","text":"Define the package data containing the meta data from the configuration file. The package data defines a Fortran type corresponding to the respective\n TOML document, after creating it from a package file no more interaction\n with the TOML document is required. Every configuration type provides it custom constructor (prefixed with new_ )\n and knows how to deserialize itself from a TOML document.\n To ensure we find no untracked content in the package file all keywords are\n checked and possible entries have to be explicitly allowed in the check function.\n If entries are mutally exclusive or interdependent inside the current table\n the check function is required to enforce this schema on the data structure. The package file root allows the following keywords name = \"string\" version = \"string\" license = \"string\" author = \"string\" maintainer = \"string\" copyright = \"string\" [library] [dependencies] [dev-dependencies] [profiles] [build] [install] [fortran] [[ executable ]] [[ example ]] [[ test ]] [extra] Uses fpm_toml fpm_manifest_profile fpm_manifest_fortran fpm_manifest_test fpm_versioning fpm_manifest_example fpm_manifest_install fpm_manifest_preprocess fpm_manifest_metapackages fpm_manifest_executable fpm_manifest_dependency fpm_error fpm_manifest_build fpm_manifest_library fpm_filesystem Contents Derived Types package_config_t Subroutines new_package Derived Types type, public :: package_config_t Package meta data Components Type Visibility Attributes Name Initial type( build_config_t ), public :: build Build configuration data type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data type( dependency_config_t ), public, allocatable :: dev_dependency (:) Development dependency meta data type( example_config_t ), public, allocatable :: example (:) Example meta data type( executable_config_t ), public, allocatable :: executable (:) Executable meta data type( fortran_config_t ), public :: fortran Fortran meta data type( install_config_t ), public :: install Installation configuration data type( library_config_t ), public, allocatable :: library Library meta data character(len=:), public, allocatable :: license License meta data type( metapackage_config_t ), public :: meta Metapackage data character(len=:), public, allocatable :: name Name of the package type( preprocess_config_t ), public, allocatable :: preprocess (:) Preprocess meta data type( profile_config_t ), public, allocatable :: profiles (:) Profiles meta data type( test_config_t ), public, allocatable :: test (:) Test meta data type( version_t ), public :: version Package version Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Subroutines public subroutine new_package (self, table, root, error) Construct a new package configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: self Instance of the package configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling","tags":"","loc":"module/fpm_manifest_package.html"},{"title":"fpm_manifest_profile – Fortran-lang/fpm","text":"Implementation of the meta data for compiler flag profiles. A profiles table can currently have the following subtables:\n Profile names - any string, if omitted, flags are appended to all matching profiles\n Compiler - any from the following list, omitting it yields an error “gfortran” “ifort” “ifx” “pgfortran” “nvfortran” “flang” “caf” “f95” “lfortran” “lfc” “nagfor” “crayftn” “xlf90” “ftn95” OS - any from the following list, if omitted, the profile is used if and only\n if there is no profile perfectly matching the current configuration “linux” “macos” “windows” “cygwin” “solaris” “freebsd” “openbsd” “unknown” Each of the subtables currently supports the following fields: [profiles.debug.gfortran.linux] flags = \"-Wall -g -Og\" c-flags = \"-g O1\" cxx-flags = \"-g O1\" link-time-flags = \"-xlinkopt\" files = { \"hello_world.f90\" = \"-Wall -O3\" } Uses fpm_toml fpm_environment fpm_strings fpm_filesystem fpm_error Contents Variables DEFAULT_COMPILER OS_ALL path Derived Types file_scope_flag profile_config_t Functions get_default_profiles info_profile new_profile Subroutines find_profile get_flags info match_os_type new_profiles traverse_compilers traverse_oss traverse_oss_for_size validate_compiler_name validate_os_name validate_profile_table Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: DEFAULT_COMPILER = 'gfortran' Name of the default compiler integer, public, parameter :: OS_ALL = -1 character(len=:), public, allocatable :: path Derived Types type, public :: file_scope_flag Type storing file name - file scope compiler flags pairs Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: file_name Name of the file character(len=:), public, allocatable :: flags File scope flags type, public :: profile_config_t Configuration meta data for a profile Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags C compiler flags character(len=:), public, allocatable :: compiler Name of the compiler character(len=:), public, allocatable :: cxx_flags C++ compiler flags type( file_scope_flag ), public, allocatable :: file_scope_flags (:) File scope flags character(len=:), public, allocatable :: flags Fortran compiler flags logical, public :: is_built_in Is this profile one of the built-in ones? character(len=:), public, allocatable :: link_time_flags Link time compiler flags integer, public :: os_type Value repesenting OS character(len=:), public, allocatable :: profile_name Name of the profile Type-Bound Procedures procedure\n , public\n, :: info Subroutine Print information on this instance Functions public function get_default_profiles (error) result(default_profiles) Construct an array of built-in profiles Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Error handling Return Value type( profile_config_t ), allocatable, (:) public function info_profile (profile) result(s) Print a representation of profile_config_t Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in) :: profile Profile to be represented Return Value character(len=:), allocatable String representation of given profile public function new_profile (profile_name, compiler, os_type, flags, c_flags, cxx_flags, link_time_flags, file_scope_flags, is_built_in) result(profile) Construct a new profile configuration from a TOML data structure Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: profile_name Name of the profile character(len=*), intent(in) :: compiler Name of the compiler integer, intent(in) :: os_type Type of the OS character(len=*), intent(in), optional :: flags Fortran compiler flags character(len=*), intent(in), optional :: c_flags C compiler flags character(len=*), intent(in), optional :: cxx_flags C++ compiler flags character(len=*), intent(in), optional :: link_time_flags Link time compiler flags type( file_scope_flag ), intent(in), optional :: file_scope_flags (:) File scope flags logical, intent(in), optional :: is_built_in Is this profile one of the built-in ones? Return Value type( profile_config_t ) Subroutines public subroutine find_profile (profiles, profile_name, compiler, os_type, found_matching, chosen_profile) Look for profile with given configuration in array profiles Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in), allocatable :: profiles (:) Array of profiles character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler Name of compiler integer, intent(in) :: os_type Type of operating system (enum) logical, intent(out) :: found_matching Boolean value containing true if matching profile was found type( profile_config_t ), intent(out) :: chosen_profile Last matching profile in the profiles array public subroutine get_flags (profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid) Look for flags, c-flags, link-time-flags key-val pairs\nand files table in a given table and create new profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler integer, intent(in) :: os_type OS type type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles logical, intent(in) :: os_valid Was called with valid operating system public subroutine info (self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: self Instance of the profile configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout public subroutine match_os_type (os_name, os_type) Match os_type enum to a lowercase string with name of OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of operating system integer, intent(out) :: os_type Enum representing type of OS public subroutine new_profiles (profiles, table, error) Construct new profiles array from a TOML data structure Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(out), allocatable :: profiles (:) Instance of the dependency configuration type(toml_table), intent(inout), target :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine traverse_compilers (profile_name, comp_list, table, error, profiles_size, profiles, profindex) Traverse compiler tables Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile type(toml_key), intent(in), allocatable :: comp_list (:) List of OSs in table with profile name given type(toml_table), intent(in), pointer :: table Table containing compiler tables type( error_t ), intent(out), allocatable :: error Error handling integer, intent(inout), optional :: profiles_size Number of profiles in list of profiles type( profile_config_t ), intent(inout), optional, allocatable :: profiles (:) List of profiles integer, intent(inout), optional :: profindex Index in the list of profiles public subroutine traverse_oss (profile_name, compiler_name, os_list, table, profiles, profindex, error) Traverse operating system tables to obtain profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles type( error_t ), intent(out), allocatable :: error Error handling public subroutine traverse_oss_for_size (profile_name, compiler_name, os_list, table, profiles_size, error) Traverse operating system tables to obtain number of profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables integer, intent(inout) :: profiles_size Number of profiles in list of profiles type( error_t ), intent(out), allocatable :: error Error handling public subroutine validate_compiler_name (compiler_name, is_valid) Check if compiler name is a valid compiler name Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: compiler_name Name of a compiler logical, intent(out) :: is_valid Boolean value of whether compiler_name is valid or not public subroutine validate_os_name (os_name, is_valid) Check if os_name is a valid name of a supported OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of an operating system logical, intent(out) :: is_valid Boolean value of whether os_name is valid or not public subroutine validate_profile_table (profile_name, compiler_name, key_list, table, error, os_valid) Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in) :: os_valid Was called with valid operating system","tags":"","loc":"module/fpm_manifest_profile.html"},{"title":"fpm_cmd_publish – Fortran-lang/fpm","text":"Upload a package to the registry using the publish command. To upload a package you need to provide a token that will be linked to your username and created for a namespace.\nThe token can be obtained from the registry website. It can be used as fpm publish --token . Uses fpm_filesystem fpm_manifest fpm_strings fpm_versioning fpm_git fpm_downloader fpm fpm_settings fpm_command_line fpm_error fpm_model Contents Subroutines cmd_publish Subroutines public subroutine cmd_publish (settings) The publish command first builds the root package to obtain all the relevant information such as the\npackage version. It then creates a tarball of the package and uploads it to the registry.\nChecks before uploading the package. Arguments Type Intent Optional Attributes Name type( fpm_publish_settings ), intent(inout) :: settings","tags":"","loc":"module/fpm_cmd_publish.html"},{"title":"fpm_cmd_new – Fortran-lang/fpm","text":"Definition of the “new” subcommand A type of the general command base class fpm_cmd_settings was created for the “new” subcommand ==> type fpm_new_settings .\n This procedure read the values that were set on the command line\n from this type to decide what actions to take. It is virtually self-contained and so independant of the rest of the\n application that it could function as a separate program. The “new” subcommand options currently consist of a SINGLE top\n directory name to create that must have a name that is an\n allowable Fortran variable name. That should have been ensured\n by the command line processing before this procedure is called.\n So basically this routine has already had the options vetted and\n just needs to conditionally create a few files. As described in the documentation it will selectively\n create the subdirectories app/, test/, src/, and example/\n and populate them with sample files. It also needs to create an initial manifest file “fpm.toml”. It then calls the system command “git init”. It should test for file existence and not overwrite existing\n files and inform the user if there were conflicts. Any changes should be reflected in the documentation in fpm_command_line.f90 FUTURE\n A filename like “.” would need system commands or a standard routine\n like realpath(3c) to process properly. Perhaps allow more than one name on a single command. It is an arbitrary\n restriction based on a concensus preference, not a required limitation. Initially the name of the directory is used as the module name in the\n src file so it must be an allowable Fortran variable name. If there are\n complaints about it it might be changed. Handling unicode at this point\n might be problematic as not all current compilers handle it. Other\n utilities like content trackers (ie. git) or repositories like github\n might also have issues with alternative names or names with spaces, etc.\n So for the time being it seems prudent to encourage simple ASCII top directory\n names (similiar to the primary programming language Fortran itself). Should be able to create or pull more complicated initial examples\n based on various templates. It should place or mention other relevant\n documents such as a description of the manifest file format in user hands;\n or how to access registered packages and local packages,\n although some other command might provide that (and the help command should\n be the first go-to for a CLI utility). Uses fpm_environment fpm_strings iso_fortran_env fpm_command_line fpm_error fpm_filesystem Contents Subroutines cmd_new Subroutines public subroutine cmd_new (settings) TOP DIRECTORY NAME PROCESSING\nsee if requested new directory already exists and process appropriately\ntemporarily change to new directory as a test. NB: System dependent Arguments Type Intent Optional Attributes Name type( fpm_new_settings ), intent(in) :: settings","tags":"","loc":"module/fpm_cmd_new.html"},{"title":"fpm_cmd_install – Fortran-lang/fpm","text":"Uses fpm_installer fpm_manifest fpm_strings fpm fpm_targets fpm_model iso_fortran_env fpm_command_line fpm_backend fpm_error fpm_filesystem Contents Subroutines cmd_install Subroutines public subroutine cmd_install (settings) Entry point for the fpm-install subcommand Arguments Type Intent Optional Attributes Name type( fpm_install_settings ), intent(inout) :: settings Representation of the command line settings","tags":"","loc":"module/fpm_cmd_install.html"},{"title":"fpm_cmd_update – Fortran-lang/fpm","text":"Uses fpm_manifest fpm_dependency fpm_command_line fpm_error fpm_filesystem Contents Subroutines cmd_update Subroutines public subroutine cmd_update (settings) Entry point for the update subcommand Arguments Type Intent Optional Attributes Name type( fpm_update_settings ), intent(in) :: settings Representation of the command line arguments","tags":"","loc":"module/fpm_cmd_update.html"},{"title":"main – Fortran-lang/fpm","text":"Uses fpm_cmd_install fpm_cmd_publish fpm_os fpm_cmd_update fpm_cmd_new fpm iso_fortran_env fpm_command_line fpm_error fpm_filesystem Contents Variables cmd_settings error project_root pwd_start pwd_working working_dir Functions has_manifest Subroutines get_working_dir handle_error Source Code main Variables Type Attributes Name Initial class( fpm_cmd_settings ), allocatable :: cmd_settings type( error_t ), allocatable :: error character(len=:), allocatable :: project_root character(len=:), allocatable :: pwd_start character(len=:), allocatable :: pwd_working character(len=:), allocatable :: working_dir Functions function has_manifest (dir) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical Subroutines subroutine get_working_dir (settings, working_dir_) Save access to working directory in settings, in case setting have not been allocated Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(in), optional :: settings character(len=:), intent(out), allocatable :: working_dir_ subroutine handle_error (error_) Arguments Type Intent Optional Attributes Name type( error_t ), intent(in), optional :: error_ Source Code program main use , intrinsic :: iso_fortran_env , only : error_unit , output_unit use fpm_command_line , only : & fpm_cmd_settings , & fpm_new_settings , & fpm_build_settings , & fpm_run_settings , & fpm_test_settings , & fpm_install_settings , & fpm_update_settings , & fpm_clean_settings , & fpm_publish_settings , & get_command_line_settings use fpm_error , only : error_t use fpm_filesystem , only : exists , parent_dir , join_path use fpm , only : cmd_build , cmd_run , cmd_clean use fpm_cmd_install , only : cmd_install use fpm_cmd_new , only : cmd_new use fpm_cmd_update , only : cmd_update use fpm_cmd_publish , only : cmd_publish use fpm_os , only : change_directory , get_current_directory implicit none class ( fpm_cmd_settings ), allocatable :: cmd_settings type ( error_t ), allocatable :: error character ( len = :), allocatable :: pwd_start , pwd_working , working_dir , project_root call get_command_line_settings ( cmd_settings ) call get_current_directory ( pwd_start , error ) call handle_error ( error ) call get_working_dir ( cmd_settings , working_dir ) if ( allocated ( working_dir )) then ! Change working directory if requested if ( len_trim ( working_dir ) > 0 ) then call change_directory ( working_dir , error ) call handle_error ( error ) call get_current_directory ( pwd_working , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // pwd_working // \"'\" else pwd_working = pwd_start end if else pwd_working = pwd_start end if select type ( settings => cmd_settings ) type is ( fpm_new_settings ) class default if (. not . has_manifest ( pwd_working )) then project_root = pwd_working do while (. not . has_manifest ( project_root )) working_dir = parent_dir ( project_root ) if ( len ( working_dir ) == 0 ) exit project_root = working_dir end do if ( has_manifest ( project_root )) then call change_directory ( project_root , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // project_root // \"'\" end if end if end select select type ( settings => cmd_settings ) type is ( fpm_new_settings ) call cmd_new ( settings ) type is ( fpm_build_settings ) call cmd_build ( settings ) type is ( fpm_run_settings ) call cmd_run ( settings , test = . false .) type is ( fpm_test_settings ) call cmd_run ( settings , test = . true .) type is ( fpm_install_settings ) call cmd_install ( settings ) type is ( fpm_update_settings ) call cmd_update ( settings ) type is ( fpm_clean_settings ) call cmd_clean ( settings ) type is ( fpm_publish_settings ) call cmd_publish ( settings ) end select if ( allocated ( project_root )) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // project_root // \"'\" end if if ( pwd_start /= pwd_working ) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // pwd_working // \"'\" end if contains function has_manifest ( dir ) character ( len =* ), intent ( in ) :: dir logical :: has_manifest has_manifest = exists ( join_path ( dir , \"fpm.toml\" )) end function has_manifest subroutine handle_error ( error_ ) type ( error_t ), optional , intent ( in ) :: error_ if ( present ( error_ )) then write ( error_unit , '(\"[Error]\", 1x, a)' ) error_ % message stop 1 end if end subroutine handle_error !> Save access to working directory in settings, in case setting have not been allocated subroutine get_working_dir ( settings , working_dir_ ) class ( fpm_cmd_settings ), optional , intent ( in ) :: settings character ( len = :), allocatable , intent ( out ) :: working_dir_ if ( present ( settings )) then working_dir_ = settings % working_dir end if end subroutine get_working_dir end program main","tags":"","loc":"program/main.html"},{"title":"fpm_backend.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_backend Source Code fpm_backend.F90 Source Code !># Build backend !> Uses a list of `[[build_target_ptr]]` and a valid `[[fpm_model]]` instance !> to schedule and execute the compilation and linking of package targets. !> !> The package build process (`[[build_package]]`) comprises three steps: !> !> 1. __Target sorting:__ topological sort of the target dependency graph (`[[sort_target]]`) !> 2. __Target scheduling:__ group targets into schedule regions based on the sorting (`[[schedule_targets]]`) !> 3. __Target building:__ generate targets by compilation or linking !> !> @note If compiled with OpenMP, targets will be build in parallel where possible. !> !>### Incremental compilation !> The backend process supports *incremental* compilation whereby targets are not !> re-compiled if their corresponding dependencies have not been modified. !> !> - Source-based targets (*i.e.* objects) are not re-compiled if the corresponding source !> file is unmodified AND all of the target dependencies are not marked for re-compilation !> !> - Link targets (*i.e.* executables and libraries) are not re-compiled if the !> target output file already exists AND all of the target dependencies are not marked for !> re-compilation !> !> Source file modification is determined by a file digest (hash) which is calculated during !> the source parsing phase ([[fpm_source_parsing]]) and cached to disk after a target is !> successfully generated. !> module fpm_backend use , intrinsic :: iso_fortran_env , only : stdin => input_unit , stdout => output_unit , stderr => error_unit use fpm_error , only : fpm_stop use fpm_filesystem , only : basename , dirname , join_path , exists , mkdir , run , getline use fpm_model , only : fpm_model_t use fpm_strings , only : string_t , operator (. in .) use fpm_targets , only : build_target_t , build_target_ptr , FPM_TARGET_OBJECT , & FPM_TARGET_C_OBJECT , FPM_TARGET_ARCHIVE , FPM_TARGET_EXECUTABLE , & FPM_TARGET_CPP_OBJECT use fpm_backend_output implicit none private public :: build_package , sort_target , schedule_targets #ifndef FPM_BOOTSTRAP interface function c_isatty () bind ( C , name = 'c_isatty' ) use , intrinsic :: iso_c_binding , only : c_int integer ( c_int ) :: c_isatty end function end interface #endif contains !> Top-level routine to build package described by `model` subroutine build_package ( targets , model , verbose ) type ( build_target_ptr ), intent ( inout ) :: targets (:) type ( fpm_model_t ), intent ( in ) :: model logical , intent ( in ) :: verbose integer :: i , j type ( build_target_ptr ), allocatable :: queue (:) integer , allocatable :: schedule_ptr (:), stat (:) logical :: build_failed , skip_current type ( string_t ), allocatable :: build_dirs (:) type ( string_t ) :: temp type ( build_progress_t ) :: progress logical :: plain_output ! Need to make output directory for include (mod) files allocate ( build_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % output_dir . in . build_dirs ) cycle temp % s = target % output_dir build_dirs = [ build_dirs , temp ] end associate end do do i = 1 , size ( build_dirs ) call mkdir ( build_dirs ( i )% s , verbose ) end do ! Perform depth-first topological sort of targets do i = 1 , size ( targets ) call sort_target ( targets ( i )% ptr ) end do ! Construct build schedule queue call schedule_targets ( queue , schedule_ptr , targets ) ! Check if queue is empty if (. not . verbose . and . size ( queue ) < 1 ) then write ( stderr , '(a)' ) 'Project is up to date' return end if ! Initialise build status flags allocate ( stat ( size ( queue ))) stat (:) = 0 build_failed = . false . ! Set output mode #ifndef FPM_BOOTSTRAP plain_output = (. not .( c_isatty () == 1 )) . or . verbose #else plain_output = . true . #endif progress = build_progress_t ( queue , plain_output ) ! Loop over parallel schedule regions do i = 1 , size ( schedule_ptr ) - 1 ! Build targets in schedule region i !$omp parallel do default(shared) private(skip_current) schedule(dynamic,1) do j = schedule_ptr ( i ),( schedule_ptr ( i + 1 ) - 1 ) ! Check if build already failed !$omp atomic read skip_current = build_failed if (. not . skip_current ) then call progress % compiling_status ( j ) call build_target ( model , queue ( j )% ptr , verbose , stat ( j )) call progress % completed_status ( j , stat ( j )) end if ! Set global flag if this target failed to build if ( stat ( j ) /= 0 ) then !$omp atomic write build_failed = . true . end if end do ! Check if this schedule region failed: exit with message if failed if ( build_failed ) then write ( * , * ) do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) Then call print_build_log ( queue ( j )% ptr ) end if end do do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Compilation failed for object \"' , basename ( queue ( j )% ptr % output_file ), '\"' end if end do call fpm_stop ( 1 , 'stopping due to failed compilation' ) end if end do call progress % success () end subroutine build_package !> Topologically sort a target for scheduling by !> recursing over its dependencies. !> !> Checks disk-cached source hashes to determine if objects are !> up-to-date. Up-to-date sources are tagged as skipped. !> !> On completion, `target` should either be marked as !> sorted (`target%sorted=.true.`) or skipped (`target%skip=.true.`) !> !> If `target` is marked as sorted, `target%schedule` should be an !> integer greater than zero indicating the region for scheduling !> recursive subroutine sort_target ( target ) type ( build_target_t ), intent ( inout ), target :: target integer :: i , fh , stat ! Check if target has already been processed (as a dependency) if ( target % sorted . or . target % skip ) then return end if ! Check for a circular dependency ! (If target has been touched but not processed) if ( target % touched ) then call fpm_stop ( 1 , '(!) Circular dependency found with: ' // target % output_file ) else target % touched = . true . ! Set touched flag end if ! Load cached source file digest if present if (. not . allocated ( target % digest_cached ) . and . & exists ( target % output_file ) . and . & exists ( target % output_file // '.digest' )) then allocate ( target % digest_cached ) open ( newunit = fh , file = target % output_file // '.digest' , status = 'old' ) read ( fh , * , iostat = stat ) target % digest_cached close ( fh ) if ( stat /= 0 ) then ! Cached digest is not recognized deallocate ( target % digest_cached ) end if end if if ( allocated ( target % source )) then ! Skip if target is source-based and source file is unmodified if ( allocated ( target % digest_cached )) then if ( target % digest_cached == target % source % digest ) target % skip = . true . end if elseif ( exists ( target % output_file )) then ! Skip if target is not source-based and already exists target % skip = . true . end if ! Loop over target dependencies target % schedule = 1 do i = 1 , size ( target % dependencies ) ! Sort dependency call sort_target ( target % dependencies ( i )% ptr ) if (. not . target % dependencies ( i )% ptr % skip ) then ! Can't skip target if any dependency is not skipped target % skip = . false . ! Set target schedule after all of its dependencies target % schedule = max ( target % schedule , target % dependencies ( i )% ptr % schedule + 1 ) end if end do ! Mark flag as processed: either sorted or skipped target % sorted = . not . target % skip end subroutine sort_target !> Construct a build schedule from the sorted targets. !> !> The schedule is broken into regions, described by `schedule_ptr`, !> where targets in each region can be compiled in parallel. !> subroutine schedule_targets ( queue , schedule_ptr , targets ) type ( build_target_ptr ), allocatable , intent ( out ) :: queue (:) integer , allocatable :: schedule_ptr (:) type ( build_target_ptr ), intent ( in ) :: targets (:) integer :: i , j integer :: n_schedule , n_sorted n_schedule = 0 ! Number of schedule regions n_sorted = 0 ! Total number of targets to build do i = 1 , size ( targets ) if ( targets ( i )% ptr % sorted ) then n_sorted = n_sorted + 1 end if n_schedule = max ( n_schedule , targets ( i )% ptr % schedule ) end do allocate ( queue ( n_sorted )) allocate ( schedule_ptr ( n_schedule + 1 )) ! Construct the target queue and schedule region pointer n_sorted = 1 schedule_ptr ( n_sorted ) = 1 do i = 1 , n_schedule do j = 1 , size ( targets ) if ( targets ( j )% ptr % sorted ) then if ( targets ( j )% ptr % schedule == i ) then queue ( n_sorted )% ptr => targets ( j )% ptr n_sorted = n_sorted + 1 end if end if end do schedule_ptr ( i + 1 ) = n_sorted end do end subroutine schedule_targets !> Call compile/link command for a single target. !> !> If successful, also caches the source file digest to disk. !> subroutine build_target ( model , target , verbose , stat ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_t ), intent ( in ), target :: target logical , intent ( in ) :: verbose integer , intent ( out ) :: stat integer :: fh !$omp critical if (. not . exists ( dirname ( target % output_file ))) then call mkdir ( dirname ( target % output_file ), verbose ) end if !$omp end critical select case ( target % target_type ) case ( FPM_TARGET_OBJECT ) call model % compiler % compile_fortran ( target % source % file_name , target % output_file , & & target % compile_flags , target % output_log_file , stat ) case ( FPM_TARGET_C_OBJECT ) call model % compiler % compile_c ( target % source % file_name , target % output_file , & & target % compile_flags , target % output_log_file , stat ) case ( FPM_TARGET_CPP_OBJECT ) call model % compiler % compile_cpp ( target % source % file_name , target % output_file , & & target % compile_flags , target % output_log_file , stat ) case ( FPM_TARGET_EXECUTABLE ) call model % compiler % link ( target % output_file , & & target % compile_flags // \" \" // target % link_flags , target % output_log_file , stat ) case ( FPM_TARGET_ARCHIVE ) call model % archiver % make_archive ( target % output_file , target % link_objects , & & target % output_log_file , stat ) end select if ( stat == 0 . and . allocated ( target % source )) then open ( newunit = fh , file = target % output_file // '.digest' , status = 'unknown' ) write ( fh , * ) target % source % digest close ( fh ) end if end subroutine build_target !> Read and print the build log for target !> subroutine print_build_log ( target ) type ( build_target_t ), intent ( in ), target :: target integer :: fh , ios character (:), allocatable :: line if ( exists ( target % output_log_file )) then open ( newunit = fh , file = target % output_log_file , status = 'old' ) do call getline ( fh , line , ios ) if ( ios /= 0 ) exit write ( * , '(A)' ) trim ( line ) end do close ( fh ) else write ( stderr , '(*(g0:,1x))' ) ' Unable to find build log \"' , basename ( target % output_log_file ), '\"' end if end subroutine print_build_log end module fpm_backend","tags":"","loc":"sourcefile/fpm_backend.f90.html"},{"title":"fpm_compiler.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_compiler Source Code fpm_compiler.F90 Source Code !># Define compiler command options !! !! This module defines compiler options to use for the debug and release builds. ! vendor Fortran C Module output Module include OpenMP Free for OSS ! compiler compiler directory directory ! Gnu gfortran gcc -J -I -fopenmp X ! Intel ifort icc -module -I -qopenmp X ! Intel(Windows) ifort icc /module:path /I /Qopenmp X ! Intel oneAPI ifx icx -module -I -qopenmp X ! PGI pgfortran pgcc -module -I -mp X ! NVIDIA nvfortran nvc -module -I -mp X ! LLVM flang flang clang -module -I -mp X ! LFortran lfortran --- -J -I --openmp X ! Lahey/Futjitsu lfc ? -M -I -openmp ? ! NAG nagfor ? -mdir -I -openmp x ! Cray crayftn craycc -J -I -homp ? ! IBM xlf90 ? -qmoddir -I -qsmp X ! Oracle/Sun ? ? -moddir= -M -xopenmp ? ! Silverfrost FTN95 ftn95 ? ? /MOD_PATH ? ? ! Elbrus ? lcc -J -I -fopenmp ? ! Hewlett Packard ? ? ? ? ? discontinued ! Watcom ? ? ? ? ? discontinued ! PathScale ? ? -module -I -mp discontinued ! G95 ? ? -fmod= -I -fopenmp discontinued ! Open64 ? ? -module -I -mp discontinued ! Unisys ? ? ? ? ? discontinued module fpm_compiler use , intrinsic :: iso_fortran_env , only : stderr => error_unit use fpm_environment , only : & get_os_type , & OS_LINUX , & OS_MACOS , & OS_WINDOWS , & OS_CYGWIN , & OS_SOLARIS , & OS_FREEBSD , & OS_OPENBSD , & OS_UNKNOWN use fpm_filesystem , only : join_path , basename , get_temp_filename , delete_file , unix_path , & & getline , run use fpm_strings , only : split , string_cat , string_t , str_ends_with , str_begins_with_str use fpm_error , only : error_t implicit none public :: compiler_t , new_compiler , archiver_t , new_archiver , get_macros public :: debug enum , bind ( C ) enumerator :: & id_unknown , & id_gcc , & id_f95 , & id_caf , & id_intel_classic_nix , & id_intel_classic_mac , & id_intel_classic_windows , & id_intel_llvm_nix , & id_intel_llvm_windows , & id_intel_llvm_unknown , & id_pgi , & id_nvhpc , & id_nag , & id_flang , & id_flang_new , & id_f18 , & id_ibmxl , & id_cray , & id_lahey , & id_lfortran end enum integer , parameter :: compiler_enum = kind ( id_unknown ) !> Definition of compiler object type :: compiler_t !> Identifier of the compiler integer ( compiler_enum ) :: id = id_unknown !> Path to the Fortran compiler character ( len = :), allocatable :: fc !> Path to the C compiler character ( len = :), allocatable :: cc !> Path to the C++ compiler character ( len = :), allocatable :: cxx !> Print all commands logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Get default compiler flags procedure :: get_default_flags !> Get flag for module output directories procedure :: get_module_flag !> Get flag for include directories procedure :: get_include_flag !> Get feature flag procedure :: get_feature_flag !> Get flags for the main linking command procedure :: get_main_flags !> Compile a Fortran object procedure :: compile_fortran !> Compile a C object procedure :: compile_c !> Compile a CPP object procedure :: compile_cpp !> Link executable procedure :: link !> Check whether compiler is recognized procedure :: is_unknown !> Check whether this is an Intel compiler procedure :: is_intel !> Check whether this is a GNU compiler procedure :: is_gnu !> Enumerate libraries, based on compiler and platform procedure :: enumerate_libraries !> Return compiler name procedure :: name => compiler_name end type compiler_t !> Definition of archiver object type :: archiver_t !> Path to archiver character ( len = :), allocatable :: ar !> Use response files to pass arguments logical :: use_response_file = . false . !> Print all command logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Create static archive procedure :: make_archive end type archiver_t !> Create debug printout interface debug module procedure :: debug_compiler module procedure :: debug_archiver end interface debug character ( * ), parameter :: & flag_gnu_coarray = \" -fcoarray=single\" , & flag_gnu_backtrace = \" -fbacktrace\" , & flag_gnu_opt = \" -O3 -funroll-loops\" , & flag_gnu_debug = \" -g\" , & flag_gnu_pic = \" -fPIC\" , & flag_gnu_warn = \" -Wall -Wextra\" , & flag_gnu_check = \" -fcheck=bounds -fcheck=array-temps\" , & flag_gnu_limit = \" -fmax-errors=1\" , & flag_gnu_external = \" -Wimplicit-interface\" , & flag_gnu_openmp = \" -fopenmp\" , & flag_gnu_no_implicit_typing = \" -fimplicit-none\" , & flag_gnu_no_implicit_external = \" -Werror=implicit-interface\" , & flag_gnu_free_form = \" -ffree-form\" , & flag_gnu_fixed_form = \" -ffixed-form\" character ( * ), parameter :: & flag_pgi_backslash = \" -Mbackslash\" , & flag_pgi_traceback = \" -traceback\" , & flag_pgi_debug = \" -g\" , & flag_pgi_check = \" -Mbounds -Mchkptr -Mchkstk\" , & flag_pgi_warn = \" -Minform=inform\" , & flag_pgi_openmp = \" -mp\" , & flag_pgi_free_form = \" -Mfree\" , & flag_pgi_fixed_form = \" -Mfixed\" character ( * ), parameter :: & flag_ibmxl_backslash = \" -qnoescape\" character ( * ), parameter :: & flag_intel_backtrace = \" -traceback\" , & flag_intel_warn = \" -warn all\" , & flag_intel_check = \" -check all\" , & flag_intel_debug = \" -O0 -g\" , & flag_intel_fp = \" -fp-model precise -pc64\" , & flag_intel_align = \" -align all\" , & flag_intel_limit = \" -error-limit 1\" , & flag_intel_pthread = \" -reentrancy threaded\" , & flag_intel_nogen = \" -nogen-interfaces\" , & flag_intel_byterecl = \" -assume byterecl\" , & flag_intel_openmp = \" -qopenmp\" , & flag_intel_free_form = \" -free\" , & flag_intel_fixed_form = \" -fixed\" , & flag_intel_standard_compliance = \" -standard-semantics\" character ( * ), parameter :: & flag_intel_backtrace_win = \" /traceback\" , & flag_intel_warn_win = \" /warn:all\" , & flag_intel_check_win = \" /check:all\" , & flag_intel_debug_win = \" /Od /Z7\" , & flag_intel_fp_win = \" /fp:precise\" , & flag_intel_align_win = \" /align:all\" , & flag_intel_limit_win = \" /error-limit:1\" , & flag_intel_pthread_win = \" /reentrancy:threaded\" , & flag_intel_nogen_win = \" /nogen-interfaces\" , & flag_intel_byterecl_win = \" /assume:byterecl\" , & flag_intel_openmp_win = \" /Qopenmp\" , & flag_intel_free_form_win = \" /free\" , & flag_intel_fixed_form_win = \" /fixed\" , & flag_intel_standard_compliance_win = \" /standard-semantics\" character ( * ), parameter :: & flag_nag_coarray = \" -coarray=single\" , & flag_nag_pic = \" -PIC\" , & flag_nag_check = \" -C\" , & flag_nag_debug = \" -g -O0\" , & flag_nag_opt = \" -O4\" , & flag_nag_backtrace = \" -gline\" , & flag_nag_openmp = \" -openmp\" , & flag_nag_free_form = \" -free\" , & flag_nag_fixed_form = \" -fixed\" , & flag_nag_no_implicit_typing = \" -u\" character ( * ), parameter :: & flag_lfortran_opt = \" --fast\" , & flag_lfortran_openmp = \" --openmp\" , & flag_lfortran_implicit_typing = \" --implicit-typing\" , & flag_lfortran_implicit_external = \" --allow-implicit-interface\" , & flag_lfortran_fixed_form = \" --fixed-form\" character ( * ), parameter :: & flag_cray_no_implicit_typing = \" -dl\" , & flag_cray_implicit_typing = \" -el\" , & flag_cray_fixed_form = \" -ffixed\" , & flag_cray_free_form = \" -ffree\" contains function get_default_flags ( self , release ) result ( flags ) class ( compiler_t ), intent ( in ) :: self logical , intent ( in ) :: release character ( len = :), allocatable :: flags if ( release ) then call get_release_compile_flags ( self % id , flags ) else call get_debug_compile_flags ( self % id , flags ) end if end function get_default_flags subroutine get_release_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_gcc ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_nvhpc ) flags = & flag_pgi_backslash case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_classic_mac ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_classic_windows ) flags = & & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_intel_llvm_nix ) flags = & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl // & flag_intel_standard_compliance case ( id_intel_llvm_windows ) flags = & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_nag ) flags = & flag_nag_opt // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = & flag_lfortran_opt end select end subroutine get_release_compile_flags subroutine get_debug_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace case ( id_gcc ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & ' -Wno-maybe-uninitialized -Wno-uninitialized' // & flag_gnu_backtrace case ( id_nvhpc ) flags = & flag_pgi_warn // & flag_pgi_backslash // & flag_pgi_check // & flag_pgi_traceback case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_classic_mac ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_classic_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win // & flag_intel_backtrace_win case ( id_intel_llvm_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_standard_compliance // & flag_intel_backtrace case ( id_intel_llvm_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_standard_compliance_win case ( id_nag ) flags = & flag_nag_debug // & flag_nag_check // & flag_nag_backtrace // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = \"\" end select end subroutine get_debug_compile_flags pure subroutine set_cpp_preprocessor_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( inout ) :: flags character ( len = :), allocatable :: flag_cpp_preprocessor !> Modify the flag_cpp_preprocessor on the basis of the compiler. select case ( id ) case default flag_cpp_preprocessor = \"\" case ( id_caf , id_gcc , id_f95 , id_nvhpc ) flag_cpp_preprocessor = \"-cpp\" case ( id_intel_classic_windows , id_intel_llvm_windows ) flag_cpp_preprocessor = \"/fpp\" case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , id_nag ) flag_cpp_preprocessor = \"-fpp\" case ( id_lfortran ) flag_cpp_preprocessor = \"--cpp\" end select flags = flag_cpp_preprocessor // flags end subroutine set_cpp_preprocessor_flags !> This function will parse and read the macros list and !> return them as defined flags. function get_macros ( id , macros_list , version ) result ( macros ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( in ) :: version type ( string_t ), allocatable , intent ( in ) :: macros_list (:) character ( len = :), allocatable :: macros character ( len = :), allocatable :: macro_definition_symbol character (:), allocatable :: valued_macros (:) integer :: i if (. not . allocated ( macros_list )) then macros = \"\" return end if !> Set macro defintion symbol on the basis of compiler used select case ( id ) case default macro_definition_symbol = \" -D\" case ( id_intel_classic_windows , id_intel_llvm_windows ) macro_definition_symbol = \" /D\" end select !> Check if macros are not allocated. if (. not . allocated ( macros )) then macros = \"\" end if do i = 1 , size ( macros_list ) !> Split the macro name and value. call split ( macros_list ( i )% s , valued_macros , delimiters = \"=\" ) if ( size ( valued_macros ) > 1 ) then !> Check if the value of macro starts with '{' character. if ( str_begins_with_str ( trim ( valued_macros ( size ( valued_macros ))), \"{\" )) then !> Check if the value of macro ends with '}' character. if ( str_ends_with ( trim ( valued_macros ( size ( valued_macros ))), \"}\" )) then !> Check if the string contains \"version\" as substring. if ( index ( valued_macros ( size ( valued_macros )), \"version\" ) /= 0 ) then !> These conditions are placed in order to ensure proper spacing between the macros. macros = macros // macro_definition_symbol // trim ( valued_macros ( 1 )) // '=' // version cycle end if end if end if end if macros = macros // macro_definition_symbol // macros_list ( i )% s end do end function get_macros function get_include_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-I \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_nvhpc , id_pgi , & & id_flang , id_flang_new , id_f18 , & & id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix , id_lahey , id_nag , id_ibmxl , & & id_lfortran ) flags = \"-I \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/I\" // path end select end function get_include_flag function get_module_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-module \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_lfortran ) flags = \"-J \" // path case ( id_nvhpc , id_pgi , id_flang ) flags = \"-module \" // path case ( id_flang_new , id_f18 ) flags = \"-module-dir \" // path case ( id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix ) flags = \"-module \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/module:\" // path case ( id_lahey ) flags = \"-M \" // path case ( id_nag ) flags = \"-mdir \" // path case ( id_ibmxl ) flags = \"-qmoddir \" // path end select end function get_module_flag function get_feature_flag ( self , feature ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: feature character ( len = :), allocatable :: flags flags = \"\" select case ( feature ) case ( \"no-implicit-typing\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_typing case ( id_nag ) flags = flag_nag_no_implicit_typing case ( id_cray ) flags = flag_cray_no_implicit_typing end select case ( \"implicit-typing\" ) select case ( self % id ) case ( id_cray ) flags = flag_cray_implicit_typing case ( id_lfortran ) flags = flag_lfortran_implicit_typing end select case ( \"no-implicit-external\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_external end select case ( \"implicit-external\" ) select case ( self % id ) case ( id_lfortran ) flags = flag_lfortran_implicit_external end select case ( \"free-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_free_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_free_form case ( id_nag ) flags = flag_nag_free_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_free_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_free_form_win case ( id_cray ) flags = flag_cray_free_form end select case ( \"fixed-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_fixed_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_fixed_form case ( id_nag ) flags = flag_nag_fixed_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_fixed_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_fixed_form_win case ( id_cray ) flags = flag_cray_fixed_form case ( id_lfortran ) flags = flag_lfortran_fixed_form end select case ( \"default-form\" ) continue case default error stop \"Unknown feature '\" // feature // \"'\" end select end function get_feature_flag !> Get special flags for the main linker subroutine get_main_flags ( self , language , flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: language character ( len = :), allocatable , intent ( out ) :: flags flags = \"\" select case ( language ) case ( \"fortran\" ) flags = \"\" case ( \"c\" ) ! If the main program is on a C/C++ source, the Intel Fortran compiler requires option ! -nofor-main to avoid \"duplicate main\" errors. ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case ( \"c++\" , \"cpp\" , \"cxx\" ) select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case default error stop \"Unknown language '\" // language // '\", try \"fortran\", \"c\", \"c++\"' end select end subroutine get_main_flags subroutine get_default_c_compiler ( f_compiler , c_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: c_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) c_compiler = 'icc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) c_compiler = 'icx' case ( id_flang , id_flang_new , id_f18 ) c_compiler = 'clang' case ( id_ibmxl ) c_compiler = 'xlc' case ( id_lfortran ) c_compiler = 'cc' case ( id_gcc ) c_compiler = 'gcc' case default ! Fall-back to using Fortran compiler c_compiler = f_compiler end select end subroutine get_default_c_compiler !> Get C++ Compiler. subroutine get_default_cxx_compiler ( f_compiler , cxx_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: cxx_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) cxx_compiler = 'icpc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) cxx_compiler = 'icpx' case ( id_flang , id_flang_new , id_f18 ) cxx_compiler = 'clang++' case ( id_ibmxl ) cxx_compiler = 'xlc++' case ( id_lfortran ) cxx_compiler = 'cc' case ( id_gcc ) cxx_compiler = 'g++' case default ! Fall-back to using Fortran compiler cxx_compiler = f_compiler end select end subroutine get_default_cxx_compiler function get_compiler_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id character ( len = :), allocatable :: full_command , full_command_parts (:), command , output integer :: stat , io ! Check whether we are dealing with an MPI compiler wrapper first if ( check_compiler ( compiler , \"mpifort\" ) & & . or . check_compiler ( compiler , \"mpif90\" ) & & . or . check_compiler ( compiler , \"mpif77\" )) then output = get_temp_filename () call run ( compiler // \" -show > \" // output // \" 2>&1\" , & & echo = . false ., exitstat = stat ) if ( stat == 0 ) then open ( file = output , newunit = io , iostat = stat ) if ( stat == 0 ) call getline ( io , full_command , stat ) close ( io , iostat = stat ) ! If we get a command from the wrapper, we will try to identify it call split ( full_command , full_command_parts , delimiters = ' ' ) if ( size ( full_command_parts ) > 0 ) then command = trim ( full_command_parts ( 1 )) endif if ( allocated ( command )) then id = get_id ( command ) if ( id /= id_unknown ) return end if end if end if id = get_id ( compiler ) end function get_compiler_id function get_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id if ( check_compiler ( compiler , \"gfortran\" )) then id = id_gcc return end if if ( check_compiler ( compiler , \"f95\" )) then id = id_f95 return end if if ( check_compiler ( compiler , \"caf\" )) then id = id_caf return end if if ( check_compiler ( compiler , \"ifort\" )) then select case ( get_os_type ()) case default id = id_intel_classic_nix case ( OS_MACOS ) id = id_intel_classic_mac case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_classic_windows end select return end if if ( check_compiler ( compiler , \"ifx\" )) then select case ( get_os_type ()) case default id = id_intel_llvm_nix case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_llvm_windows end select return end if if ( check_compiler ( compiler , \"nvfortran\" )) then id = id_nvhpc return end if if ( check_compiler ( compiler , \"pgfortran\" ) & & . or . check_compiler ( compiler , \"pgf90\" ) & & . or . check_compiler ( compiler , \"pgf95\" )) then id = id_pgi return end if if ( check_compiler ( compiler , \"nagfor\" )) then id = id_nag return end if if ( check_compiler ( compiler , \"flang-new\" )) then id = id_flang_new return end if if ( check_compiler ( compiler , \"f18\" )) then id = id_f18 return end if if ( check_compiler ( compiler , \"flang\" )) then id = id_flang return end if if ( check_compiler ( compiler , \"xlf90\" )) then id = id_ibmxl return end if if ( check_compiler ( compiler , \"crayftn\" )) then id = id_cray return end if if ( check_compiler ( compiler , \"lfc\" )) then id = id_lahey return end if if ( check_compiler ( compiler , \"lfortran\" )) then id = id_lfortran return end if id = id_unknown end function get_id function check_compiler ( compiler , expected ) result ( match ) character ( len =* ), intent ( in ) :: compiler character ( len =* ), intent ( in ) :: expected logical :: match match = compiler == expected if (. not . match ) then match = index ( basename ( compiler ), expected ) > 0 end if end function check_compiler pure function is_unknown ( self ) class ( compiler_t ), intent ( in ) :: self logical :: is_unknown is_unknown = self % id == id_unknown end function is_unknown pure logical function is_intel ( self ) class ( compiler_t ), intent ( in ) :: self is_intel = any ( self % id == [ id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows , & id_intel_llvm_nix , id_intel_llvm_windows , id_intel_llvm_unknown ]) end function is_intel pure logical function is_gnu ( self ) class ( compiler_t ), intent ( in ) :: self is_gnu = any ( self % id == [ id_f95 , id_gcc , id_caf ]) end function is_gnu !> !> Enumerate libraries, based on compiler and platform !> function enumerate_libraries ( self , prefix , libs ) result ( r ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: prefix type ( string_t ), intent ( in ) :: libs (:) character ( len = :), allocatable :: r if ( self % id == id_intel_classic_windows . or . & self % id == id_intel_llvm_windows ) then r = prefix // \" \" // string_cat ( libs , \".lib \" ) // \".lib\" else r = prefix // \" -l\" // string_cat ( libs , \" -l\" ) end if end function enumerate_libraries !> Create new compiler instance subroutine new_compiler ( self , fc , cc , cxx , echo , verbose ) !> New instance of the compiler type ( compiler_t ), intent ( out ) :: self !> Fortran compiler name or path character ( len =* ), intent ( in ) :: fc !> C compiler name or path character ( len =* ), intent ( in ) :: cc !> C++ Compiler name or path character ( len =* ), intent ( in ) :: cxx !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose self % id = get_compiler_id ( fc ) self % echo = echo self % verbose = verbose self % fc = fc if ( len_trim ( cc ) > 0 ) then self % cc = cc else call get_default_c_compiler ( self % fc , self % cc ) end if if ( len_trim ( cxx ) > 0 ) then self % cxx = cxx else call get_default_cxx_compiler ( self % fc , self % cxx ) end if end subroutine new_compiler !> Create new archiver instance subroutine new_archiver ( self , ar , echo , verbose ) !> New instance of the archiver type ( archiver_t ), intent ( out ) :: self !> User provided archiver command character ( len =* ), intent ( in ) :: ar !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose integer :: estat , os_type character ( len =* ), parameter :: arflags = \" -rs \" , libflags = \" /OUT:\" if ( len_trim ( ar ) > 0 ) then ! Check first for ar-like commands if ( check_compiler ( ar , \"ar\" )) then self % ar = ar // arflags end if ! Check for lib-like commands if ( check_compiler ( ar , \"lib\" )) then self % ar = ar // libflags end if ! Fallback and assume ar-like behaviour self % ar = ar // arflags else os_type = get_os_type () if ( os_type /= OS_WINDOWS . and . os_type /= OS_UNKNOWN ) then self % ar = \"ar\" // arflags else call execute_command_line ( \"ar --version > \" // get_temp_filename () // \" 2>&1\" , & & exitstat = estat ) if ( estat /= 0 ) then self % ar = \"lib\" // libflags else self % ar = \"ar\" // arflags end if end if end if self % use_response_file = os_type == OS_WINDOWS self % echo = echo self % verbose = verbose end subroutine new_archiver !> Compile a Fortran object subroutine compile_fortran ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % fc // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_fortran !> Compile a C object subroutine compile_c ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % cc // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_c !> Compile a CPP object subroutine compile_cpp ( self , input , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % cxx // \" -c \" // input // \" \" // args // \" -o \" // output , & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine compile_cpp !> Link an executable subroutine link ( self , output , args , log_file , stat ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat call run ( self % fc // \" \" // args // \" -o \" // output , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine link !> Create an archive !> @todo For Windows OS, use the local `delete_file_win32` in stead of `delete_file`. !> This may be related to a bug in Mingw64-openmp and is expected to be resolved in the future, !> see issue #707, #708 and #808. subroutine make_archive ( self , output , args , log_file , stat ) !> Instance of the archiver object class ( archiver_t ), intent ( in ) :: self !> Name of the archive to generate character ( len =* ), intent ( in ) :: output !> Object files to include into the archive type ( string_t ), intent ( in ) :: args (:) !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat if ( self % use_response_file ) then call write_response_file ( output // \".resp\" , args ) call run ( self % ar // output // \" @\" // output // \".resp\" , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) call delete_file_win32 ( output // \".resp\" ) else call run ( self % ar // output // \" \" // string_cat ( args , \" \" ), & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end if contains subroutine delete_file_win32 ( file ) character ( len =* ), intent ( in ) :: file logical :: exist integer :: unit , iostat inquire ( file = file , exist = exist ) if ( exist ) then open ( file = file , newunit = unit ) close ( unit , status = 'delete' , iostat = iostat ) end if end subroutine delete_file_win32 end subroutine make_archive !> Response files allow to read command line options from files. !> Whitespace is used to separate the arguments, we will use newlines !> as separator to create readable response files which can be inspected !> in case of errors. subroutine write_response_file ( name , argv ) character ( len =* ), intent ( in ) :: name type ( string_t ), intent ( in ) :: argv (:) integer :: iarg , io open ( file = name , newunit = io , status = 'replace' ) do iarg = 1 , size ( argv ) write ( io , '(a)' ) unix_path ( argv ( iarg )% s ) end do close ( io ) end subroutine write_response_file !> String representation of a compiler object pure function debug_compiler ( self ) result ( repr ) !> Instance of the compiler object type ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'fc=\"' // self % fc // '\", cc=\"' // self % cc // '\"' end function debug_compiler !> String representation of an archiver object pure function debug_archiver ( self ) result ( repr ) !> Instance of the archiver object type ( archiver_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'ar=\"' // self % ar // '\"' end function debug_archiver !> Return a compiler name string pure function compiler_name ( self ) result ( name ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: name select case ( self % id ) case ( id_gcc ); name = \"gfortran\" case ( id_f95 ); name = \"f95\" case ( id_caf ); name = \"caf\" case ( id_intel_classic_nix ); name = \"ifort\" case ( id_intel_classic_mac ); name = \"ifort\" case ( id_intel_classic_windows ); name = \"ifort\" case ( id_intel_llvm_nix ); name = \"ifx\" case ( id_intel_llvm_windows ); name = \"ifx\" case ( id_intel_llvm_unknown ); name = \"ifx\" case ( id_pgi ); name = \"pgfortran\" case ( id_nvhpc ); name = \"nvfortran\" case ( id_nag ); name = \"nagfor\" case ( id_flang ); name = \"flang\" case ( id_flang_new ); name = \"flang-new\" case ( id_f18 ); name = \"f18\" case ( id_ibmxl ); name = \"xlf90\" case ( id_cray ); name = \"crayftn\" case ( id_lahey ); name = \"lfc\" case ( id_lfortran ); name = \"lFortran\" case default ; name = \"invalid/unknown\" end select end function compiler_name end module fpm_compiler","tags":"","loc":"sourcefile/fpm_compiler.f90.html"},{"title":"fpm_settings.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_settings Source Code fpm_settings.f90 Source Code !> Manages global settings which are defined in the global config file. module fpm_settings use fpm_filesystem , only : exists , join_path , get_local_prefix , is_absolute_path , mkdir use fpm_environment , only : os_is_unix use fpm_error , only : error_t , fatal_error use fpm_toml , only : toml_table , toml_error , toml_stat , get_value , toml_load , check_keys use fpm_os , only : get_current_directory , change_directory , get_absolute_path , convert_to_absolute_path implicit none private public :: fpm_global_settings , get_global_settings , get_registry_settings , official_registry_base_url character ( * ), parameter :: official_registry_base_url = 'https://registry-apis.vercel.app' character ( * ), parameter :: default_config_file_name = 'config.toml' type :: fpm_global_settings !> Path to the global config file excluding the file name. character ( len = :), allocatable :: path_to_config_folder !> Name of the global config file. The default is `config.toml`. character ( len = :), allocatable :: config_file_name !> Registry configs. type ( fpm_registry_settings ), allocatable :: registry_settings contains procedure :: has_custom_location , full_path , path_to_config_folder_or_empty end type type :: fpm_registry_settings !> The path to the local registry. If allocated, the local registry !> will be used instead of the remote registry and replaces the !> local cache. character ( len = :), allocatable :: path !> The URL to the remote registry. Can be used to get packages !> from the official or a custom registry. character ( len = :), allocatable :: url !> The path to the cache folder. If not specified, the default cache !> folders are `~/.local/share/fpm/dependencies` on Unix and !> `%APPDATA%\\local\\fpm\\dependencies` on Windows. !> Cannot be used together with `path`. character ( len = :), allocatable :: cache_path end type contains !> Obtain global settings from the global config file. subroutine get_global_settings ( global_settings , error ) !> Global settings to be obtained. type ( fpm_global_settings ), intent ( inout ) :: global_settings !> Error reading config file. type ( error_t ), allocatable , intent ( out ) :: error !> TOML table to be filled with global config settings. type ( toml_table ), allocatable :: table !> Error parsing to TOML table. type ( toml_error ), allocatable :: parse_error type ( toml_table ), pointer :: registry_table integer :: stat ! Use custom path to the config file if it was specified. if ( global_settings % has_custom_location ()) then ! Throw error if folder doesn't exist. if (. not . exists ( global_settings % path_to_config_folder )) then call fatal_error ( error , \"Folder not found: '\" // global_settings % path_to_config_folder // \"'.\" ); return end if ! Throw error if the file doesn't exist. if (. not . exists ( global_settings % full_path ())) then call fatal_error ( error , \"File not found: '\" // global_settings % full_path () // \"'.\" ); return end if ! Make sure that the path to the global config file is absolute. call convert_to_absolute_path ( global_settings % path_to_config_folder , error ) if ( allocated ( error )) return else ! Use default path if it wasn't specified. if ( os_is_unix ()) then global_settings % path_to_config_folder = join_path ( get_local_prefix (), 'share' , 'fpm' ) else global_settings % path_to_config_folder = join_path ( get_local_prefix (), 'fpm' ) end if ! Use default file name. global_settings % config_file_name = default_config_file_name ! Apply default registry settings and return if config file doesn't exist. if (. not . exists ( global_settings % full_path ())) then call use_default_registry_settings ( global_settings ); return end if end if ! Load into TOML table. call toml_load ( table , global_settings % full_path (), error = parse_error ) if ( allocated ( parse_error )) then allocate ( error ); call move_alloc ( parse_error % message , error % message ); return end if call get_value ( table , 'registry' , registry_table , requested = . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading registry from config file '\" // & & global_settings % full_path () // \"'.\" ); return end if ! A registry table was found. if ( associated ( registry_table )) then call get_registry_settings ( registry_table , global_settings , error ) else call use_default_registry_settings ( global_settings ) end if end !> Default registry settings are typically applied if the config file doesn't exist or no registry table was found in !> the global config file. subroutine use_default_registry_settings ( global_settings ) type ( fpm_global_settings ), intent ( inout ) :: global_settings allocate ( global_settings % registry_settings ) global_settings % registry_settings % url = official_registry_base_url global_settings % registry_settings % cache_path = join_path ( global_settings % path_to_config_folder_or_empty (), & & 'dependencies' ) end !> Read registry settings from the global config file. subroutine get_registry_settings ( table , global_settings , error ) !> The [registry] subtable from the global config file. type ( toml_table ), target , intent ( inout ) :: table !> The global settings which can be filled with the registry settings. type ( fpm_global_settings ), intent ( inout ) :: global_settings !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: path , url , cache_path integer :: stat !> List of valid keys for the dependency table. character ( * ), dimension ( * ), parameter :: valid_keys = [ character ( 10 ) :: & & 'path' , & & 'url' , & & 'cache_path' & & ] call check_keys ( table , valid_keys , error ) if ( allocated ( error )) return allocate ( global_settings % registry_settings ) if ( table % has_key ( 'path' )) then call get_value ( table , 'path' , path , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading registry path: '\" // path // \"'.\" ); return end if end if if ( allocated ( path )) then if ( is_absolute_path ( path )) then global_settings % registry_settings % path = path else ! Get canonical, absolute path on both Unix and Windows. call get_absolute_path ( join_path ( global_settings % path_to_config_folder_or_empty (), path ), & & global_settings % registry_settings % path , error ) if ( allocated ( error )) return ! Check if the path to the registry exists. if (. not . exists ( global_settings % registry_settings % path )) then call fatal_error ( error , \"Directory '\" // global_settings % registry_settings % path // & & \"' doesn't exist.\" ); return end if end if end if if ( table % has_key ( 'url' )) then call get_value ( table , 'url' , url , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading registry url: '\" // url // \"'.\" ); return end if end if if ( allocated ( url )) then ! Throw error when both path and url were provided. if ( allocated ( path )) then call fatal_error ( error , 'Do not provide both path and url to the registry.' ); return end if global_settings % registry_settings % url = url else if (. not . allocated ( path )) then global_settings % registry_settings % url = official_registry_base_url end if if ( table % has_key ( 'cache_path' )) then call get_value ( table , 'cache_path' , cache_path , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading path to registry cache: '\" // cache_path // \"'.\" ); return end if end if if ( allocated ( cache_path )) then ! Throw error when both path and cache_path were provided. if ( allocated ( path )) then call fatal_error ( error , \"Do not provide both 'path' and 'cache_path'.\" ); return end if if ( is_absolute_path ( cache_path )) then if (. not . exists ( cache_path )) call mkdir ( cache_path ) global_settings % registry_settings % cache_path = cache_path else cache_path = join_path ( global_settings % path_to_config_folder_or_empty (), cache_path ) if (. not . exists ( cache_path )) call mkdir ( cache_path ) ! Get canonical, absolute path on both Unix and Windows. call get_absolute_path ( cache_path , global_settings % registry_settings % cache_path , error ) if ( allocated ( error )) return end if else if (. not . allocated ( path )) then global_settings % registry_settings % cache_path = & join_path ( global_settings % path_to_config_folder_or_empty (), 'dependencies' ) end if end !> True if the global config file is not at the default location. elemental logical function has_custom_location ( self ) class ( fpm_global_settings ), intent ( in ) :: self has_custom_location = allocated ( self % path_to_config_folder ) . and . allocated ( self % config_file_name ) if (. not . has_custom_location ) return has_custom_location = len_trim ( self % path_to_config_folder ) > 0 . and . len_trim ( self % config_file_name ) > 0 end !> The full path to the global config file. function full_path ( self ) result ( result ) class ( fpm_global_settings ), intent ( in ) :: self character ( len = :), allocatable :: result result = join_path ( self % path_to_config_folder_or_empty (), self % config_file_name ) end !> The path to the global config directory. pure function path_to_config_folder_or_empty ( self ) class ( fpm_global_settings ), intent ( in ) :: self character ( len = :), allocatable :: path_to_config_folder_or_empty if ( allocated ( self % path_to_config_folder )) then path_to_config_folder_or_empty = self % path_to_config_folder else path_to_config_folder_or_empty = \"\" end if end end","tags":"","loc":"sourcefile/fpm_settings.f90.html"},{"title":"fpm_backend_console.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_backend_console Source Code fpm_backend_console.f90 Source Code !># Build Backend Console !> This module provides a lightweight implementation for printing to the console !> and updating previously-printed console lines. It used by `[[fpm_backend_output]]` !> for pretty-printing build status and progress. !> !> @note The implementation for updating previous lines relies on no other output !> going to `stdout`/`stderr` except through the `console_t` object provided. !> !> @note All write statements to `stdout` are enclosed within OpenMP `critical` regions !> module fpm_backend_console use iso_fortran_env , only : stdout => output_unit implicit none private public :: console_t public :: LINE_RESET public :: COLOR_RED , COLOR_GREEN , COLOR_YELLOW , COLOR_RESET character ( len =* ), parameter :: ESC = char ( 27 ) !> Escape code for erasing current line character ( len =* ), parameter :: LINE_RESET = ESC // \"[2K\" // ESC // \"[1G\" !> Escape code for moving up one line character ( len =* ), parameter :: LINE_UP = ESC // \"[1A\" !> Escape code for moving down one line character ( len =* ), parameter :: LINE_DOWN = ESC // \"[1B\" !> Escape code for red foreground color character ( len =* ), parameter :: COLOR_RED = ESC // \"[31m\" !> Escape code for green foreground color character ( len =* ), parameter :: COLOR_GREEN = ESC // \"[32m\" !> Escape code for yellow foreground color character ( len =* ), parameter :: COLOR_YELLOW = ESC // \"[93m\" !> Escape code to reset foreground color character ( len =* ), parameter :: COLOR_RESET = ESC // \"[0m\" !> Console object type console_t !> Number of lines printed integer :: n_line = 1 contains !> Write a single line to the console procedure :: write_line => console_write_line !> Update a previously-written console line procedure :: update_line => console_update_line end type console_t contains !> Write a single line to the standard output subroutine console_write_line ( console , str , line , advance ) !> Console object class ( console_t ), intent ( inout ) :: console !> String to write character ( * ), intent ( in ) :: str !> Integer needed to later update console line integer , intent ( out ), optional :: line !> Advancing output (print newline?) logical , intent ( in ), optional :: advance character ( 3 ) :: adv adv = \"yes\" if ( present ( advance )) then if (. not . advance ) then adv = \"no\" end if end if !$omp critical if ( present ( line )) then line = console % n_line end if write ( stdout , '(A)' , advance = trim ( adv )) LINE_RESET // str if ( adv == \"yes\" ) then console % n_line = console % n_line + 1 end if !$omp end critical end subroutine console_write_line !> Overwrite a previously-written line in standard output subroutine console_update_line ( console , line_no , str ) !> Console object class ( console_t ), intent ( in ) :: console !> Integer output from `[[console_write_line]]` integer , intent ( in ) :: line_no !> New string to overwrite line character ( * ), intent ( in ) :: str integer :: n !$omp critical n = console % n_line - line_no ! Step back to line write ( stdout , '(A)' , advance = \"no\" ) repeat ( LINE_UP , n ) // LINE_RESET write ( stdout , '(A)' , advance = \"no\" ) str ! Step forward to end write ( stdout , '(A)' , advance = \"no\" ) repeat ( LINE_DOWN , n ) // LINE_RESET !$omp end critical end subroutine console_update_line end module fpm_backend_console","tags":"","loc":"sourcefile/fpm_backend_console.f90.html"},{"title":"fpm_command_line.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_command_line Source Code fpm_command_line.f90 Source Code !># 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 , OS_OPENBSD use M_CLI2 , only : set_args , lget , sget , unnamed , remaining , specified use M_CLI2 , only : get_subcommand , CLI_RESPONSE_FILE use fpm_strings , only : lower , split , to_fortran_name , is_fortran_name , remove_characters_in_set , string_t use fpm_filesystem , only : basename , canon_path , which , run use fpm_environment , only : get_command_arguments_quoted use fpm_error , only : fpm_stop , error_t use fpm_os , only : get_current_directory use fpm_release , only : fpm_version , version_t 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 , & fpm_clean_settings , & fpm_publish_settings , & get_command_line_settings type , abstract :: fpm_cmd_settings character ( len = :), allocatable :: working_dir 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 . logical :: build_tests = . false . logical :: prune = . true . character ( len = :), allocatable :: compiler character ( len = :), allocatable :: c_compiler character ( len = :), allocatable :: cxx_compiler character ( len = :), allocatable :: archiver character ( len = :), allocatable :: profile character ( len = :), allocatable :: flag character ( len = :), allocatable :: cflag character ( len = :), allocatable :: cxxflag character ( len = :), allocatable :: ldflag end type type , extends ( fpm_build_settings ) :: fpm_run_settings character ( len = ibug ), allocatable :: name (:) character ( len = :), allocatable :: args ! passed to the app character ( len = :), allocatable :: runner character ( len = :), allocatable :: runner_args ! passed to the runner logical :: example contains procedure :: runner_command 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 type , extends ( fpm_cmd_settings ) :: fpm_clean_settings logical :: clean_skip = . false . logical :: clean_call = . false . end type type , extends ( fpm_build_settings ) :: fpm_publish_settings logical :: show_package_version = . false . logical :: show_upload_data = . false . logical :: is_dry_run = . false . character ( len = :), allocatable :: token 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 (:), & & help_clean (:), help_publish (:) character ( len = 20 ), parameter :: manual ( * ) = [ character ( len = 20 ) :: & & ' ' , 'fpm' , 'new' , 'build' , 'run' , 'clean' , & & 'test' , 'runner' , 'install' , 'update' , 'list' , 'help' , 'version' , 'publish' ] character ( len = :), allocatable :: val_runner , val_compiler , val_flag , val_cflag , val_cxxflag , val_ldflag , & val_profile , val_runner_args ! '12345678901234567890123456789012345678901234567890123456789012345678901234567890',& character ( len = 80 ), parameter :: help_text_build_common ( * ) = [ character ( len = 80 ) :: & ' --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. ' ,& ' --no-prune Disable tree-shaking/pruning of unused module dependencies ' & ] ! '12345678901234567890123456789012345678901234567890123456789012345678901234567890',& character ( len = 80 ), parameter :: help_text_compiler ( * ) = [ character ( len = 80 ) :: & ' --compiler NAME Specify a compiler name. The default is \"gfortran\" ' ,& ' unless set by the environment variable FPM_FC. ' ,& ' --c-compiler NAME Specify the C compiler name. Automatically determined by ' ,& ' default unless set by the environment variable FPM_CC. ' ,& ' --cxx-compiler NAME Specify the C++ compiler name. Automatically determined by' ,& ' default unless set by the environment variable FPM_CXX. ' ,& ' --archiver NAME Specify the archiver name. Automatically determined by ' ,& ' default unless set by the environment variable FPM_AR. ' & ] ! '12345678901234567890123456789012345678901234567890123456789012345678901234567890',& character ( len = 80 ), parameter :: help_text_flag ( * ) = [ character ( len = 80 ) :: & ' --flag FFLAGS selects compile arguments for the build, the default value is' ,& ' set by the FPM_FFLAGS environment variable. 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. ' ,& ' --c-flag CFLAGS selects compile arguments specific for C source in the build.' ,& ' The default value is set by the FPM_CFLAGS environment ' ,& ' variable. ' ,& ' --cxx-flag CFLAGS selects compile arguments specific for C++ source in the ' ,& ' build. The default value is set by the FPM_CXXFLAGS ' ,& ' environment variable. ' ,& ' --link-flag LDFLAGS select arguments passed to the linker for the build. The ' ,& ' default value is set by the FPM_LDFLAGS environment variable.' & ] character ( len = 80 ), parameter :: help_text_environment ( * ) = [ character ( len = 80 ) :: & 'ENVIRONMENT VARIABLES' ,& ' FPM_FC sets the path to the Fortran compiler used for the build,' , & ' will be overwritten by --compiler command line option' , & '' , & ' FPM_FFLAGS sets the arguments for the Fortran compiler' , & ' will be overwritten by --flag command line option' , & '' , & ' FPM_CC sets the path to the C compiler used for the build,' , & ' will be overwritten by --c-compiler command line option' , & '' , & ' FPM_CFLAGS sets the arguments for the C compiler' , & ' will be overwritten by --c-flag command line option' , & '' , & ' FPM_CXX sets the path to the C++ compiler used for the build,' , & ' will be overwritten by --cxx-compiler command line option' , & '' , & ' FPM_CXXFLAGS sets the arguments for the C++ compiler' , & ' will be overwritten by --cxx-flag command line option' , & '' , & ' FPM_AR sets the path to the archiver used for the build,' , & ' will be overwritten by --archiver command line option' , & '' , & ' FPM_LDFLAGS sets additional link arguments for creating executables' , & ' will be overwritten by --link-flag command line option' & ] contains subroutine get_command_line_settings ( cmd_settings ) class ( fpm_cmd_settings ), allocatable , intent ( out ) :: cmd_settings integer , parameter :: widest = 256 character ( len = 4096 ) :: cmdarg integer :: i integer :: os type ( fpm_install_settings ), allocatable :: install_settings type ( version_t ) :: version character ( len = :), allocatable :: common_args , compiler_args , run_args , working_dir , & & c_compiler , cxx_compiler , archiver , version_s , token_s character ( len =* ), parameter :: fc_env = \"FC\" , cc_env = \"CC\" , ar_env = \"AR\" , & & fflags_env = \"FFLAGS\" , cflags_env = \"CFLAGS\" , cxxflags_env = \"CXXFLAGS\" , ldflags_env = \"LDFLAGS\" , & & fc_default = \"gfortran\" , cc_default = \" \" , ar_default = \" \" , flags_default = \" \" , & & cxx_env = \"CXX\" , cxx_default = \" \" type ( error_t ), allocatable :: error call set_help () os = get_os_type () ! text for --version switch, select case ( os ) 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_OPENBSD ); os_type = \"OS Type: OpenBSD\" case ( OS_UNKNOWN ); os_type = \"OS Type: Unknown\" case default ; os_type = \"OS Type: UNKNOWN\" end select ! Get current release version version = fpm_version () version_s = version % s () version_text = [ character ( len = 80 ) :: & & 'Version: ' // trim ( version_s ) // ', 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 CLI_RESPONSE_FILE = . true . cmdarg = get_subcommand () common_args = & ' --directory:C \" \"' // & ' --verbose F' run_args = & ' --target \" \"' // & ' --list F' // & ' --runner \" \"' // & ' --runner-args \" \"' compiler_args = & ' --profile \" \"' // & ' --no-prune F' // & ' --compiler \"' // get_fpm_env ( fc_env , fc_default ) // '\"' // & ' --c-compiler \"' // get_fpm_env ( cc_env , cc_default ) // '\"' // & ' --cxx-compiler \"' // get_fpm_env ( cxx_env , cxx_default ) // '\"' // & ' --archiver \"' // get_fpm_env ( ar_env , ar_default ) // '\"' // & ' --flag:: \"' // get_fpm_env ( fflags_env , flags_default ) // '\"' // & ' --c-flag:: \"' // get_fpm_env ( cflags_env , flags_default ) // '\"' // & ' --cxx-flag:: \"' // get_fpm_env ( cxxflags_env , flags_default ) // '\"' // & ' --link-flag:: \"' // get_fpm_env ( ldflags_env , flags_default ) // '\"' ! now set subcommand-specific help text and process commandline ! arguments. Then call subcommand routine select case ( trim ( cmdarg )) case ( 'run' ) call set_args ( common_args // compiler_args // run_args // '& & --all F & & --example F& & --' , help_run , version_text ) call check_build_vals () if ( size ( unnamed ) > 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 ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_run_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_run_settings (& & args = remaining ,& & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = lget ( 'example' ), & & list = lget ( 'list' ),& & build_tests = . false .,& & name = names ,& & runner = val_runner ,& & runner_args = val_runner_args , & & verbose = lget ( 'verbose' ) ) case ( 'build' ) call set_args ( common_args // compiler_args // '& & --list F & & --show-model F & & --tests F & & --' , help_build , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_build_settings :: cmd_settings ) cmd_settings = fpm_build_settings ( & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ) ) case ( 'new' ) call set_args ( common_args // '& & --src F & & --lib F & & --app F & & --test F & & --example F & & --backfill F & & --full F & & --bare F' , & & help_new , version_text ) select case ( size ( unnamed )) case ( 1 ) if ( lget ( 'backfill' )) then name = '.' else write ( stderr , '(*(7x,g0,/))' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|[--full|--bare] [--backfill]' call fpm_stop ( 1 , 'directory name required' ) endif case ( 2 ) name = trim ( unnamed ( 2 )) case default write ( stderr , '(7x,g0)' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| [--full|--bare] [--backfill]' call fpm_stop ( 2 , 'only one directory name allowed' ) end select !*! canon_path is not converting \".\", etc. if ( name == '.' ) then call get_current_directory ( name , error ) if ( allocated ( error )) then write ( stderr , '(\"[Error]\", 1x, a)' ) error % message stop 1 endif endif name = canon_path ( name ) if ( . not . is_fortran_name ( to_fortran_name ( basename ( name ))) ) then write ( stderr , '(g0)' ) [ character ( len = 72 ) :: & & ' the fpm project name must be made of up to 63 ASCII letters,' , & & ' numbers, underscores, or hyphens, and start with a letter.' ] call fpm_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))' )& & ' --full and any of [--src|--lib,--app,--test,--example,--bare]' , & & ' are mutually exclusive.' call fpm_stop ( 5 , ' ' ) elseif ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' , 'full' ])) & & . and . lget ( 'bare' ) ) then write ( stderr , '(*(a))' )& & ' --bare and any of [--src|--lib,--app,--test,--example,--full]' , & & ' are mutually exclusive.' call fpm_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 ( common_args , help_help , version_text ) if ( size ( unnamed ) < 2 ) then if ( unnamed ( 1 ) == 'help' ) then unnamed = [ ' ' , 'fpm' ] else unnamed = manual endif elseif ( unnamed ( 2 ) == 'manual' ) then unnamed = manual endif 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 ( 'clean' ) help_text = [ character ( len = widest ) :: help_text , help_clean ] case ( 'publish' ) help_text = [ character ( len = widest ) :: help_text , help_publish ] case default help_text = [ character ( len = widest ) :: help_text , & & ' unknown help topic \"' // trim ( unnamed ( i )) // '\"' ] !!& ' unknown help topic \"'//trim(unnamed(i)).'not found in:',manual] end select enddo call printhelp ( help_text ) case ( 'install' ) call set_args ( common_args // compiler_args // '& & --no-rebuild F --prefix \" \" & & --list F & & --libdir \"lib\" --bindir \"bin\" --includedir \"include\"' , & help_install , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( install_settings , source = fpm_install_settings (& list = lget ( 'list' ), & profile = val_profile ,& prune = . not . lget ( 'no-prune' ), & compiler = val_compiler , & c_compiler = c_compiler , & cxx_compiler = cxx_compiler , & archiver = archiver , & flag = val_flag , & cflag = val_cflag , & cxxflag = val_cxxflag , & ldflag = val_ldflag , & 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 ( common_args // '& & --list F& &' , help_list , version_text ) if ( lget ( 'list' )) then help_text = [ character ( widest ) :: help_list_nodash , help_list_dash ] else help_text = help_list_nodash endif call printhelp ( help_text ) case ( 'test' ) call set_args ( common_args // compiler_args // run_args // ' --' , & help_test , version_text ) call check_build_vals () if ( size ( unnamed ) > 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 ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( fpm_test_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_test_settings (& & args = remaining , & & profile = val_profile , & & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = . false ., & & list = lget ( 'list' ), & & build_tests = . true ., & & name = names , & & runner = val_runner , & & runner_args = val_runner_args , & & verbose = lget ( 'verbose' )) case ( 'update' ) call set_args ( common_args // ' --fetch-only F --clean F' , & help_update , version_text ) if ( size ( unnamed ) > 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 ( 'clean' ) call set_args ( common_args // & & ' --skip' // & & ' --all' , & help_clean , version_text ) allocate ( fpm_clean_settings :: cmd_settings ) call get_current_directory ( working_dir , error ) cmd_settings = fpm_clean_settings ( & & clean_skip = lget ( 'skip' ), & & clean_call = lget ( 'all' )) case ( 'publish' ) call set_args ( common_args // compiler_args // '& & --show-package-version F & & --show-upload-data F & & --dry-run F & & --token \" \" & & --list F & & --show-model F & & --tests F & & --' , help_publish , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) token_s = sget ( 'token' ) allocate ( fpm_publish_settings :: cmd_settings ) cmd_settings = fpm_publish_settings ( & & show_package_version = lget ( 'show-package-version' ), & & show_upload_data = lget ( 'show-upload-data' ), & & is_dry_run = lget ( 'dry-run' ), & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ),& & token = token_s ) case default if ( cmdarg . ne . '' . and . which ( 'fpm-' // cmdarg ). ne . '' ) then call run ( 'fpm-' // trim ( cmdarg ) // ' ' // get_command_arguments_quoted (),. false .) stop else call set_args ( '& & --list F& &' , help_fpm , version_text ) ! Note: will not get here if --version or --usage or --help ! is present on commandline if ( lget ( 'list' )) then help_text = help_list_dash elseif ( len_trim ( cmdarg ) == 0 ) then write ( stdout , '(*(a))' ) 'Fortran Package Manager:' write ( stdout , '(*(a))' ) ' ' help_text = [ character ( widest ) :: help_list_nodash , help_usage ] else write ( stderr , '(*(a))' ) ' unknown subcommand [' , & & trim ( cmdarg ), ']' help_text = [ character ( widest ) :: help_list_dash , help_usage ] endif call printhelp ( help_text ) endif end select if ( allocated ( cmd_settings )) then working_dir = sget ( \"directory\" ) call move_alloc ( working_dir , cmd_settings % working_dir ) end if contains subroutine check_build_vals () val_compiler = sget ( 'compiler' ) if ( val_compiler == '' ) val_compiler = 'gfortran' val_flag = \" \" // sget ( 'flag' ) val_cflag = \" \" // sget ( 'c-flag' ) val_cxxflag = \" \" // sget ( 'cxx-flag' ) val_ldflag = \" \" // sget ( 'link-flag' ) val_profile = sget ( 'profile' ) end subroutine check_build_vals !> Print help text and stop subroutine printhelp ( lines ) character ( len = :), intent ( in ), allocatable :: lines (:) integer :: iii , ii if ( allocated ( lines )) then ii = size ( lines ) if ( ii > 0 . and . len ( lines ) > 0 ) then write ( stdout , '(g0)' )( trim ( lines ( iii )), iii = 1 , ii ) else write ( stdout , '(a)' ) ' *printhelp* output requested is empty' endif endif stop end subroutine printhelp end subroutine get_command_line_settings 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 ' , & ' clean Delete the build ' , & ' publish Publish package to the registry ' , & ' ' , & ' 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] ' , & ' [--tests] [--no-prune] ' , & ' 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] ' , & ' clean [--skip] [--all] ' , & ' publish [--token TOKEN] [--show-package-version] [--show-upload-data] ' , & ' [--dry-run] [--verbose] ' , & ' ' ] 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 ... --runner-args ARGS -- 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\". ' , & ' --runner-args \"args\" an additional option to pass command-line arguments ' , & ' to the runner command, instead of to the fpm app. ' , & ' -- SUFFIX_OPTIONS additional options to suffix the command CMD and executable ' , & ' file names with. These options are passed as command-line ' , & ' arguments to the app. ' , & '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 \"mpiexec\" --runner-args \"-np 12\" ' , & ' 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 to the --help switch for displaying help text. ' , & ' + list Display brief descriptions of all subcommands. ' , & ' + install Install project. ' , & ' + clean Delete directories in the \"build/\" directory, except ' , & ' dependencies. Prompts for confirmation to delete. ' , & ' + publish Publish package to the registry. ' , & ' ' , & ' Their syntax is ' , & ' ' , & ' build [--profile PROF] [--flag FFLAGS] [--list] [--compiler COMPILER_NAME] ' , & ' [--tests] [--no-prune] ' , & ' 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] [--all] ' , & ' [--example] [--runner \"CMD\"] [--compiler COMPILER_NAME] ' , & ' [--no-prune] [-- ARGS] ' , & ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] ' , & ' [--runner \"CMD\"] [--compiler COMPILER_NAME] [--no-prune] [-- ARGS] ' , & ' help [NAME(s)] ' , & ' list [--list] ' , & ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH] ' , & ' [options] ' , & ' clean [--skip] [--all] ' , & ' publish [--token TOKEN] [--show-package-version] [--show-upload-data] ' , & ' [--dry-run] [--verbose] ' , & ' ' , & 'SUBCOMMAND OPTIONS ' , & ' -C, --directory PATH' , & ' Change working directory to PATH before running any command' , & help_text_build_common , & help_text_compiler , & help_text_flag , & ' --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. ' , & ' -- ARGS Arguments to pass to executables. ' , & ' --skip Delete directories in the build/ directory without ' , & ' prompting, but skip dependencies. ' , & ' --all Delete directories in the build/ directory without ' , & ' prompting, including dependencies. ' , & ' ' , & 'VALID FOR ALL SUBCOMMANDS ' , & ' --help Show help text and exit ' , & ' --verbose Display additional information when available ' , & ' --version Show version information and exit. ' , & ' ' , & '@file ' , & ' You may replace the default options for the fpm(1) command from a ' , & ' file if your first options begin with @file. Initial options will ' , & ' then be read from the \"response file\" \"file.rsp\" in the current ' , & ' directory. ' , & ' ' , & ' If \"file\" does not exist or cannot be read, then an error occurs and' , & ' the program stops. Each line of the file is prefixed with \"options\" ' , & ' and interpreted as a separate argument. The file itself may not ' , & ' contain @file arguments. That is, it is not processed recursively. ' , & ' ' , & ' For more information on response files see ' , & ' ' , & ' https://urbanjost.github.io/M_CLI2/set_args.3m_cli2.html ' , & ' ' , & ' The basic functionality described here will remain the same, but ' , & ' other features described at the above reference may change. ' , & ' ' , & ' An example file: ' , & ' ' , & ' # my build options ' , & ' options build ' , & ' options --compiler gfortran ' , & ' options --flag \"-pg -static -pthread -Wunreachable-code -Wunused ' , & ' -Wuninitialized -g -O -fbacktrace -fdump-core -fno-underscoring ' , & ' -frecord-marker=4 -L/usr/X11R6/lib -L/usr/X11R6/lib64 -lX11\" ' , & ' ' , & ' Note --flag would have to be on one line as response files do not ' , & ' (currently) allow for continued lines or multiple specifications of ' , & ' the same option. ' , & ' ' , & help_text_environment , & ' ' , & '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 ' , & ' fpm clean --all ' , & ' ' , & '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://fpm.fortran-lang.org/en/spec/manifest.html ' , & '' ] help_list = [ character ( len = 80 ) :: & 'NAME ' , & ' list(1) - list summary of fpm(1) subcommands ' , & ' ' , & 'SYNOPSIS ' , & ' fpm 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. ' , & help_text_build_common , & help_text_compiler , & help_text_flag , & ' --runner CMD A command to prefix the program execution paths with. ' , & ' see \"fpm help runner\" for further details. ' , & ' --list list basenames 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. ' , & ' ' , & help_text_environment , & ' ' , & 'EXAMPLES ' , & ' fpm(1) - run or display project applications: ' , & ' ' , & ' fpm run # run a target when only one exists or list targets ' , & ' fpm run --list # list basename of all targets, running nothing. ' , & ' fpm run \"demo*\" --list # list target basenames starting with \"demo*\".' , & ' fpm run \"psi*\" --runner # list target pathnames starting with \"psi*\".' , & ' 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] [--tests] ' , & ' ' , & ' 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 ' , & help_text_build_common ,& help_text_compiler , & help_text_flag , & ' --list list candidates instead of building or running them ' , & ' --tests build all tests (otherwise only if needed) ' , & ' --show-model show the model and exit (do not build) ' , & ' --help print this help and exit ' , & ' --version print program version information and exit ' , & ' ' , & help_text_environment , & ' ' , & '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 ' , & ' ' , & ' The default file structure (that will be automatically scanned) is ' , & ' ' , & ' NAME/ ' , & ' fpm.toml ' , & ' 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 ' , & ' \"README.md\" file is created but no directories or ' , & ' sample Fortran are 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 --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.' , & help_text_build_common ,& help_text_compiler , & help_text_flag , & ' --runner CMD A command to prefix the program execution paths with. ' , & ' see \"fpm help runner\" for further details. ' , & ' --list list candidate basenames instead of running them. Note they' , & ' --list will still be built if not currently up to date. ' , & ' -- ARGS optional arguments to pass to the test program(s). ' , & ' The same arguments are passed to all test names ' , & ' specified. ' , & ' ' , & help_text_environment , & ' ' , & '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' , & help_text_build_common ,& help_text_flag , & ' --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' , & '' , & help_text_environment , & '' , & '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' , & '' ] help_clean = [ character ( len = 80 ) :: & 'NAME' , & ' clean(1) - delete the build' , & '' , & 'SYNOPSIS' , & ' fpm clean' , & '' , & 'DESCRIPTION' , & ' Prompts the user to confirm deletion of the build. If affirmative,' , & ' directories in the build/ directory are deleted, except dependencies.' , & '' , & 'OPTIONS' , & ' --skip delete the build without prompting but skip dependencies.' , & ' --all delete the build without prompting including dependencies.' , & '' ] help_publish = [ character ( len = 80 ) :: & 'NAME' , & ' publish(1) - publish package to the registry' , & '' , & 'SYNOPSIS' , & ' fpm publish [--token TOKEN] [--show-package-version] [--show-upload-data]' , & ' [--dry-run] [--verbose] ' , & '' , & ' fpm publish --help|--version' , & '' , & 'DESCRIPTION' , & ' Follow the steps to create a tarball and upload a package to the registry:' , & '' , & ' 1. Register on the website (https://registry-frontend.vercel.app/).' , & ' 2. Create a namespace. Uploaded packages must be assigned to a unique' , & ' namespace to avoid conflicts among packages with similar names. A' , & ' namespace can accommodate multiple packages.' , & ' 3. Create a token for that namespace. A token is linked to your username' , & ' and is used to authenticate you during the upload process. Do not share' , & ' the token with others.' , & ' 4. Run fpm publish --token TOKEN to upload the package to the registry.' , & ' But be aware that the upload is permanent. An uploaded package cannot be' , & ' deleted.' , & '' , & ' See documentation for more information regarding package upload and usage:' , & '' , & ' Package upload:' , & ' https://fpm.fortran-lang.org/en/spec/publish.html' , & '' , & ' Package usage:' , & ' https://fpm.fortran-lang.org/en/spec/manifest.html#dependencies-from-a-registry' , & '' , & 'OPTIONS' , & ' --show-package-version show package version without publishing' , & ' --show-upload-data show upload data without publishing' , & ' --dry-run perform dry run without publishing' , & ' --help print this help and exit' , & ' --version print program version information and exit' , & ' --verbose print more information' , & '' , & 'EXAMPLES' , & '' , & ' fpm publish --show-package-version # show package version without publishing' , & ' fpm publish --show-upload-data # show upload data without publishing' , & ' fpm publish --token TOKEN --dry-run # perform dry run without publishing' , & ' fpm publish --token TOKEN # upload package to the registry' , & '' ] 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 !> Get an environment variable for fpm, this routine ensures that every variable !> used by fpm is prefixed with FPM_. function get_fpm_env ( env , default ) result ( val ) character ( len =* ), intent ( in ) :: env character ( len =* ), intent ( in ) :: default character ( len = :), allocatable :: val character ( len =* ), parameter :: fpm_prefix = \"FPM_\" val = get_env ( fpm_prefix // env , default ) end function get_fpm_env !> Build a full runner command (executable + command-line arguments) function runner_command ( cmd ) result ( run_cmd ) class ( fpm_run_settings ), intent ( in ) :: cmd character ( len = :), allocatable :: run_cmd !> Get executable if ( len_trim ( cmd % runner ) > 0 ) then run_cmd = trim ( cmd % runner ) else run_cmd = '' end if !> Append command-line arguments if ( len_trim ( cmd % runner_args ) > 0 ) run_cmd = run_cmd // ' ' // trim ( cmd % runner_args ) end function runner_command end module fpm_command_line","tags":"","loc":"sourcefile/fpm_command_line.f90.html"},{"title":"fpm_os.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_os Source Code fpm_os.F90 Source Code module fpm_os use , intrinsic :: iso_c_binding , only : c_char , c_int , c_null_char , c_ptr , c_associated use fpm_filesystem , only : exists , join_path , get_home use fpm_environment , only : os_is_unix use fpm_error , only : error_t , fatal_error implicit none private public :: change_directory , get_current_directory , get_absolute_path , convert_to_absolute_path , & & get_absolute_path_by_cd integer ( c_int ), parameter :: buffersize = 1000_c_int #ifndef _WIN32 character ( len =* ), parameter :: pwd_env = \"PWD\" #else character ( len =* ), parameter :: pwd_env = \"CD\" #endif interface function chdir_ ( path ) result ( stat ) & #ifndef _WIN32 bind ( C , name = \"chdir\" ) #else bind ( C , name = \"_chdir\" ) #endif import :: c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) integer ( c_int ) :: stat end function chdir_ function getcwd_ ( buf , bufsize ) result ( path ) & #ifndef _WIN32 bind ( C , name = \"getcwd\" ) #else bind ( C , name = \"_getcwd\" ) #endif import :: c_char , c_int , c_ptr character ( kind = c_char , len = 1 ), intent ( in ) :: buf ( * ) integer ( c_int ), value , intent ( in ) :: bufsize type ( c_ptr ) :: path end function getcwd_ !> Determine the absolute, canonicalized path for a given path. Unix-only. function realpath ( path , resolved_path ) result ( ptr ) bind ( C ) import :: c_ptr , c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) character ( kind = c_char , len = 1 ), intent ( out ) :: resolved_path ( * ) type ( c_ptr ) :: ptr end function realpath !> Determine the absolute, canonicalized path for a given path. Windows-only. function fullpath ( resolved_path , path , maxLength ) result ( ptr ) bind ( C , name = \"_fullpath\" ) import :: c_ptr , c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) character ( kind = c_char , len = 1 ), intent ( out ) :: resolved_path ( * ) integer ( c_int ), value , intent ( in ) :: maxLength type ( c_ptr ) :: ptr end function fullpath !> Determine the absolute, canonicalized path for a given path. !> Calls custom C routine because the `_WIN32` macro is correctly exported !> in C using `gfortran`. function c_realpath ( path , resolved_path , maxLength ) result ( ptr ) & bind ( C , name = \"c_realpath\" ) import :: c_ptr , c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) character ( kind = c_char , len = 1 ), intent ( out ) :: resolved_path ( * ) integer ( c_int ), value , intent ( in ) :: maxLength type ( c_ptr ) :: ptr end function c_realpath end interface contains subroutine change_directory ( path , error ) character ( len =* ), intent ( in ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) integer :: stat allocate ( cpath ( len ( path ) + 1 )) call f_c_character ( path , cpath , len ( path ) + 1 ) stat = chdir_ ( cpath ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to change directory to '\" // path // \"'\" ) end if end subroutine change_directory subroutine get_current_directory ( path , error ) character ( len = :), allocatable , intent ( out ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) type ( c_ptr ) :: tmp allocate ( cpath ( buffersize )) tmp = getcwd_ ( cpath , buffersize ) if ( c_associated ( tmp )) then call c_f_character ( cpath , path ) else call fatal_error ( error , \"Failed to retrieve current directory\" ) end if end subroutine get_current_directory subroutine f_c_character ( rhs , lhs , len ) character ( kind = c_char ), intent ( out ) :: lhs ( * ) character ( len =* ), intent ( in ) :: rhs integer , intent ( in ) :: len integer :: length length = min ( len - 1 , len_trim ( rhs )) lhs ( 1 : length ) = transfer ( rhs ( 1 : length ), lhs ( 1 : length )) lhs ( length + 1 : length + 1 ) = c_null_char end subroutine f_c_character subroutine c_f_character ( rhs , lhs ) character ( kind = c_char ), intent ( in ) :: rhs ( * ) character ( len = :), allocatable , intent ( out ) :: lhs integer :: ii do ii = 1 , huge ( ii ) - 1 if ( rhs ( ii ) == c_null_char ) then exit end if end do allocate ( character ( len = ii - 1 ) :: lhs ) lhs = transfer ( rhs ( 1 : ii - 1 ), lhs ) end subroutine c_f_character !> Determine the canonical, absolute path for the given path. !> !> Calls a C routine that uses the `_WIN32` macro to determine the correct function. !> !> Cannot be used in bootstrap mode. subroutine get_realpath ( path , real_path , error ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable , intent ( out ) :: real_path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: appended_path (:) character ( kind = c_char , len = 1 ), allocatable :: cpath (:) type ( c_ptr ) :: ptr if (. not . exists ( path )) then call fatal_error ( error , \"Cannot determine absolute path. Path '\" // path // \"' does not exist.\" ) return end if allocate ( appended_path ( len ( path ) + 1 )) call f_c_character ( path , appended_path , len ( path ) + 1 ) allocate ( cpath ( buffersize )) #ifndef FPM_BOOTSTRAP ptr = c_realpath ( appended_path , cpath , buffersize ) #endif if ( c_associated ( ptr )) then call c_f_character ( cpath , real_path ) else call fatal_error ( error , \"Failed to retrieve absolute path for '\" // path // \"'.\" ) end if end subroutine !> Determine the canonical, absolute path for the given path. !> Expands home folder (~) on both Unix and Windows. subroutine get_absolute_path ( path , absolute_path , error ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable , intent ( out ) :: absolute_path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: home #ifdef FPM_BOOTSTRAP call get_absolute_path_by_cd ( path , absolute_path , error ); return #endif if ( len_trim ( path ) < 1 ) then call fatal_error ( error , 'Path cannot be empty' ); return else if ( path ( 1 : 1 ) == '~' ) then call get_home ( home , error ) if ( allocated ( error )) return if ( len_trim ( path ) == 1 ) then absolute_path = home ; return end if if ( os_is_unix ()) then if ( path ( 2 : 2 ) /= '/' ) then call fatal_error ( error , \"Wrong separator in path: '\" // path // \"'\" ); return end if else if ( path ( 2 : 2 ) /= '\\') then call fatal_error(error, \"Wrong separator in path: ' \"//path//\" '\"); return end if end if if (len_trim(path) == 2) then absolute_path = home; return end if absolute_path = join_path(home, path(3:len_trim(path))) if (.not. exists(absolute_path)) then call fatal_error(error, \"Path not found: ' \"//absolute_path//\" '\" ); return end if else ! Get canonicalized absolute path from either the absolute or the relative path. call get_realpath ( path , absolute_path , error ) end if end subroutine !> Alternative to `get_absolute_path` that uses `chdir`/`_chdir` to determine the absolute path. !> !> `get_absolute_path` is preferred but `get_absolute_path_by_cd` can be used in bootstrap mode. subroutine get_absolute_path_by_cd ( path , absolute_path , error ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable , intent ( out ) :: absolute_path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: current_path call get_current_directory ( current_path , error ) if ( allocated ( error )) return call change_directory ( path , error ) if ( allocated ( error )) return call get_current_directory ( absolute_path , error ) if ( allocated ( error )) return call change_directory ( current_path , error ) if ( allocated ( error )) return end subroutine !> Converts a path to an absolute, canonical path. subroutine convert_to_absolute_path ( path , error ) character ( len = :), allocatable , intent ( inout ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: absolute_path call get_absolute_path ( path , absolute_path , error ) path = absolute_path end subroutine end module fpm_os","tags":"","loc":"sourcefile/fpm_os.f90.html"},{"title":"fpm_sources.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_sources Source Code fpm_sources.f90 Source Code !># Discovery of sources !> !> This module implements subroutines for building a list of !> `[[srcfile_t]]` objects by looking for source files in the filesystem. !> module fpm_sources use fpm_error , only : error_t use fpm_model , only : srcfile_t , FPM_UNIT_PROGRAM use fpm_filesystem , only : basename , canon_path , dirname , join_path , list_files , is_hidden_file use fpm_environment , only : get_os_type , OS_WINDOWS use fpm_strings , only : lower , str_ends_with , string_t , operator (. in .) use fpm_source_parsing , only : parse_f_source , parse_c_source use fpm_manifest_executable , only : executable_config_t implicit none private public :: add_sources_from_dir , add_executable_sources public :: get_exe_name_with_suffix character ( 4 ), parameter :: fortran_suffixes ( 2 ) = [ \".f90\" , & \".f \" ] character ( 4 ), parameter :: c_suffixes ( 4 ) = [ \".c \" , \".h \" , \".cpp\" , \".hpp\" ] contains !> Wrapper to source parsing routines. !> Selects parsing routine based on source file name extension function parse_source ( source_file_path , error ) result ( source ) character ( * ), intent ( in ) :: source_file_path type ( error_t ), allocatable , intent ( out ) :: error type ( srcfile_t ) :: source if ( str_ends_with ( lower ( source_file_path ), fortran_suffixes )) then source = parse_f_source ( source_file_path , error ) if ( source % unit_type == FPM_UNIT_PROGRAM ) then source % exe_name = basename ( source_file_path , suffix = . false .) end if else if ( str_ends_with ( lower ( source_file_path ), c_suffixes )) then source = parse_c_source ( source_file_path , error ) end if if ( allocated ( error )) then return end if end function parse_source !> Add to `sources` by looking for source files in `directory` subroutine add_sources_from_dir ( sources , directory , scope , with_executables , recurse , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> Directory in which to search for source files character ( * ), intent ( in ) :: directory !> Scope to apply to the discovered sources, see [[fpm_model]] for enumeration integer , intent ( in ) :: scope !> Executable sources (fortran `program`s) are ignored unless `with_executables=.true.` logical , intent ( in ), optional :: with_executables !> Whether to recursively search subdirectories, default is `.true.` logical , intent ( in ), optional :: recurse !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i logical , allocatable :: is_source (:), exclude_source (:) logical :: recurse_ type ( string_t ), allocatable :: file_names (:) type ( string_t ), allocatable :: src_file_names (:) type ( string_t ), allocatable :: existing_src_files (:) type ( srcfile_t ), allocatable :: dir_sources (:) recurse_ = . true . if ( present ( recurse )) recurse_ = recurse ! Scan directory for sources call list_files ( directory , file_names , recurse = recurse_ ) if ( allocated ( sources )) then allocate ( existing_src_files ( size ( sources ))) do i = 1 , size ( sources ) existing_src_files ( i )% s = canon_path ( sources ( i )% file_name ) end do else allocate ( existing_src_files ( 0 )) end if is_source = [(. not .( is_hidden_file ( basename ( file_names ( i )% s ))) . and . & . not .( canon_path ( file_names ( i )% s ) . in . existing_src_files ) . and . & ( str_ends_with ( lower ( file_names ( i )% s ), fortran_suffixes ) . or . & str_ends_with ( lower ( file_names ( i )% s ), c_suffixes ) ), i = 1 , size ( file_names ))] src_file_names = pack ( file_names , is_source ) allocate ( dir_sources ( size ( src_file_names ))) allocate ( exclude_source ( size ( src_file_names ))) do i = 1 , size ( src_file_names ) dir_sources ( i ) = parse_source ( src_file_names ( i )% s , error ) if ( allocated ( error )) return dir_sources ( i )% unit_scope = scope allocate ( dir_sources ( i )% link_libraries ( 0 )) ! Exclude executables unless specified otherwise exclude_source ( i ) = ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM ) if ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM . and . & & present ( with_executables )) then if ( with_executables ) then exclude_source ( i ) = . false . end if end if end do if (. not . allocated ( sources )) then sources = pack ( dir_sources ,. not . exclude_source ) else sources = [ sources , pack ( dir_sources ,. not . exclude_source )] end if end subroutine add_sources_from_dir !> Add to `sources` using the executable and test entries in the manifest and !> applies any executable-specific overrides such as `executable%name`. !> Adds all sources (including modules) from each `executable%source_dir` subroutine add_executable_sources ( sources , executables , scope , auto_discover , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> List of `[[executable_config_t]]` entries from manifest class ( executable_config_t ), intent ( in ) :: executables (:) !> Scope to apply to the discovered sources: either `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`, see [[fpm_model]] integer , intent ( in ) :: scope !> If `.false.` only executables and tests specified in the manifest are added to `sources` logical , intent ( in ) :: auto_discover !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( string_t ), allocatable :: exe_dirs (:) type ( srcfile_t ) :: exe_source call get_executable_source_dirs ( exe_dirs , executables ) do i = 1 , size ( exe_dirs ) call add_sources_from_dir ( sources , exe_dirs ( i )% s , scope , & with_executables = auto_discover , recurse = . false ., error = error ) if ( allocated ( error )) then return end if end do exe_loop : do i = 1 , size ( executables ) ! Check if executable already discovered automatically ! and apply any overrides do j = 1 , size ( sources ) if ( basename ( sources ( j )% file_name , suffix = . true .) == executables ( i )% main . and .& canon_path ( dirname ( sources ( j )% file_name )) == & canon_path ( executables ( i )% source_dir ) ) then sources ( j )% exe_name = executables ( i )% name if ( allocated ( executables ( i )% link )) then sources ( j )% link_libraries = executables ( i )% link end if sources ( j )% unit_type = FPM_UNIT_PROGRAM cycle exe_loop end if end do ! Add if not already discovered (auto_discovery off) associate ( exe => executables ( i )) exe_source = parse_source ( join_path ( exe % source_dir , exe % main ), error ) exe_source % exe_name = exe % name if ( allocated ( exe % link )) then exe_source % link_libraries = exe % link end if exe_source % unit_type = FPM_UNIT_PROGRAM exe_source % unit_scope = scope end associate if ( allocated ( error )) return if (. not . allocated ( sources )) then sources = [ exe_source ] else sources = [ sources , exe_source ] end if end do exe_loop end subroutine add_executable_sources !> Build a list of unique source directories !> from executables specified in manifest subroutine get_executable_source_dirs ( exe_dirs , executables ) type ( string_t ), allocatable , intent ( inout ) :: exe_dirs (:) class ( executable_config_t ), intent ( in ) :: executables (:) type ( string_t ) :: dirs_temp ( size ( executables )) integer :: i , n n = 0 do i = 1 , size ( executables ) dirs_temp ( i )% s = ' ' enddo do i = 1 , size ( executables ) if (. not .( executables ( i )% source_dir . in . dirs_temp )) then n = n + 1 dirs_temp ( n )% s = executables ( i )% source_dir end if end do if (. not . allocated ( exe_dirs )) then exe_dirs = dirs_temp ( 1 : n ) else exe_dirs = [ exe_dirs , dirs_temp ( 1 : n )] end if end subroutine get_executable_source_dirs !> Build an executable name with suffix. Safe routine that always returns an allocated string function get_exe_name_with_suffix ( source ) result ( suffixed ) type ( srcfile_t ), intent ( in ) :: source character ( len = :), allocatable :: suffixed if ( allocated ( source % exe_name )) then if ( get_os_type () == OS_WINDOWS ) then suffixed = source % exe_name // '.exe' else suffixed = source % exe_name end if else suffixed = \"\" endif end function get_exe_name_with_suffix end module fpm_sources","tags":"","loc":"sourcefile/fpm_sources.f90.html"},{"title":"fpm.f90 – Fortran-lang/fpm","text":"Contents Modules fpm Source Code fpm.f90 Source Code module fpm use fpm_strings , only : string_t , operator (. in .), glob , join , string_cat , & lower , str_ends_with , is_fortran_name , str_begins_with_str , & is_valid_module_name , len_trim use fpm_backend , only : build_package use fpm_command_line , only : fpm_build_settings , fpm_new_settings , & fpm_run_settings , fpm_install_settings , fpm_test_settings , & fpm_clean_settings use fpm_dependency , only : new_dependency_tree use fpm_filesystem , only : is_dir , join_path , list_files , exists , & basename , filewrite , mkdir , run , os_delete_dir use fpm_model , only : fpm_model_t , srcfile_t , show_model , fortran_features_t , & FPM_SCOPE_UNKNOWN , FPM_SCOPE_LIB , FPM_SCOPE_DEP , & FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST use fpm_compiler , only : new_compiler , new_archiver , set_cpp_preprocessor_flags use fpm_sources , only : add_executable_sources , add_sources_from_dir use fpm_targets , only : targets_from_sources , build_target_t , build_target_ptr , & FPM_TARGET_EXECUTABLE , FPM_TARGET_ARCHIVE use fpm_manifest , only : get_package_data , package_config_t use fpm_meta , only : resolve_metapackages use fpm_error , only : error_t , fatal_error , fpm_stop use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit use iso_c_binding , only : c_char , c_ptr , c_int , c_null_char , c_associated , c_f_pointer use fpm_environment , only : os_is_unix implicit none private public :: cmd_build , cmd_run , cmd_clean public :: build_model , check_modules_for_duplicates contains !> Constructs a valid fpm model from command line settings and the toml manifest. subroutine build_model ( model , settings , package , error ) type ( fpm_model_t ), intent ( out ) :: model class ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ), intent ( inout ) :: package type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( package_config_t ) :: dependency character ( len = :), allocatable :: manifest , lib_dir logical :: has_cpp logical :: duplicates_found type ( string_t ) :: include_dir model % package_name = package % name allocate ( model % include_dirs ( 0 )) allocate ( model % link_libraries ( 0 )) allocate ( model % external_modules ( 0 )) call new_compiler ( model % compiler , settings % compiler , settings % c_compiler , & & settings % cxx_compiler , echo = settings % verbose , verbose = settings % verbose ) call new_archiver ( model % archiver , settings % archiver , & & echo = settings % verbose , verbose = settings % verbose ) if ( model % compiler % is_unknown ()) then write ( * , '(*(a:,1x))' ) & \"\" , \"Unknown compiler\" , model % compiler % fc , \"requested!\" , & \"Defaults for this compiler might be incorrect\" end if call new_compiler_flags ( model , settings ) model % build_prefix = join_path ( \"build\" , basename ( model % compiler % fc )) model % include_tests = settings % build_tests model % enforce_module_names = package % build % module_naming model % module_prefix = package % build % module_prefix ! Resolve meta-dependencies into the package and the model call resolve_metapackages ( model , package , settings , error ) if ( allocated ( error )) return ! Create dependencies call new_dependency_tree ( model % deps , cache = join_path ( \"build\" , \"cache.toml\" )) ! Build and resolve model dependencies call model % deps % add ( package , error ) if ( allocated ( error )) return ! Update dependencies where needed call model % deps % update ( error ) if ( allocated ( error )) return ! build/ directory should now exist if (. not . exists ( \"build/.gitignore\" )) then call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if allocate ( model % packages ( model % deps % ndep )) has_cpp = . false . do i = 1 , model % deps % ndep associate ( dep => model % deps % dep ( i )) manifest = join_path ( dep % proj_dir , \"fpm.toml\" ) call get_package_data ( dependency , manifest , error , apply_defaults = . true .) if ( allocated ( error )) exit model % packages ( i )% name = dependency % name associate ( features => model % packages ( i )% features ) features % implicit_typing = dependency % fortran % implicit_typing features % implicit_external = dependency % fortran % implicit_external features % source_form = dependency % fortran % source_form end associate model % packages ( i )% version = package % version % s () !> Add this dependency's manifest macros allocate ( model % packages ( i )% macros ( 0 )) if ( allocated ( dependency % preprocess )) then do j = 1 , size ( dependency % preprocess ) if ( dependency % preprocess ( j )% name == \"cpp\" ) then if (. not . has_cpp ) has_cpp = . true . if ( allocated ( dependency % preprocess ( j )% macros )) then model % packages ( i )% macros = [ model % packages ( i )% macros , dependency % preprocess ( j )% macros ] end if else write ( stderr , '(a)' ) 'Warning: Preprocessor ' // package % preprocess ( i )% name // & ' is not supported; will ignore it' end if end do end if !> Add this dependency's package-level macros if ( allocated ( dep % preprocess )) then do j = 1 , size ( dep % preprocess ) if ( dep % preprocess ( j )% name == \"cpp\" ) then if (. not . has_cpp ) has_cpp = . true . if ( allocated ( dep % preprocess ( j )% macros )) then model % packages ( i )% macros = [ model % packages ( i )% macros , dep % preprocess ( j )% macros ] end if else write ( stderr , '(a)' ) 'Warning: Preprocessor ' // package % preprocess ( i )% name // & ' is not supported; will ignore it' end if end do end if if (. not . allocated ( model % packages ( i )% sources )) allocate ( model % packages ( i )% sources ( 0 )) if ( allocated ( dependency % library )) then if ( allocated ( dependency % library % source_dir )) then lib_dir = join_path ( dep % proj_dir , dependency % library % source_dir ) if ( is_dir ( lib_dir )) then call add_sources_from_dir ( model % packages ( i )% sources , lib_dir , FPM_SCOPE_LIB , & error = error ) if ( allocated ( error )) exit end if end if if ( allocated ( dependency % library % include_dir )) then do j = 1 , size ( dependency % library % include_dir ) include_dir % s = join_path ( dep % proj_dir , dependency % library % include_dir ( j )% s ) if ( is_dir ( include_dir % s )) then model % include_dirs = [ model % include_dirs , include_dir ] end if end do end if end if if ( allocated ( dependency % build % link )) then model % link_libraries = [ model % link_libraries , dependency % build % link ] end if if ( allocated ( dependency % build % external_modules )) then model % external_modules = [ model % external_modules , dependency % build % external_modules ] end if ! Copy naming conventions from this dependency's manifest model % packages ( i )% enforce_module_names = dependency % build % module_naming model % packages ( i )% module_prefix = dependency % build % module_prefix end associate end do if ( allocated ( error )) return ! Add optional flags if ( has_cpp ) call set_cpp_preprocessor_flags ( model % compiler % id , model % fortran_compile_flags ) ! Add sources from executable directories if ( is_dir ( 'app' ) . and . package % build % auto_executables ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'app' , FPM_SCOPE_APP , & with_executables = . true ., error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'example' ) . and . package % build % auto_examples ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'example' , FPM_SCOPE_EXAMPLE , & with_executables = . true ., error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'test' ) . and . package % build % auto_tests ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'test' , FPM_SCOPE_TEST , & with_executables = . true ., error = error ) if ( allocated ( error )) then return endif end if if ( allocated ( package % executable )) then call add_executable_sources ( model % packages ( 1 )% sources , package % executable , FPM_SCOPE_APP , & auto_discover = package % build % auto_executables , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % example )) then call add_executable_sources ( model % packages ( 1 )% sources , package % example , FPM_SCOPE_EXAMPLE , & auto_discover = package % build % auto_examples , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % test )) then call add_executable_sources ( model % packages ( 1 )% sources , package % test , FPM_SCOPE_TEST , & auto_discover = package % build % auto_tests , & error = error ) if ( allocated ( error )) then return endif endif if ( settings % verbose ) then write ( * , * ) ' BUILD_NAME: ' , model % build_prefix write ( * , * ) ' COMPILER: ' , model % compiler % fc write ( * , * ) ' C COMPILER: ' , model % compiler % cc write ( * , * ) ' CXX COMPILER: ' , model % compiler % cxx write ( * , * ) ' COMPILER OPTIONS: ' , model % fortran_compile_flags write ( * , * ) ' C COMPILER OPTIONS: ' , model % c_compile_flags write ( * , * ) ' CXX COMPILER OPTIONS: ' , model % cxx_compile_flags write ( * , * ) ' LINKER OPTIONS: ' , model % link_flags write ( * , * ) ' INCLUDE DIRECTORIES: [' , string_cat ( model % include_dirs , ',' ), ']' end if ! Check for invalid module names call check_module_names ( model , error ) if ( allocated ( error )) return ! Check for duplicate modules duplicates_found = . false . call check_modules_for_duplicates ( model , duplicates_found ) if ( duplicates_found ) then call fpm_stop ( 1 , '*build_model*:Error: One or more duplicate module names found.' ) end if end subroutine build_model !> Initialize model compiler flags subroutine new_compiler_flags ( model , settings ) type ( fpm_model_t ), intent ( inout ) :: model type ( fpm_build_settings ), intent ( in ) :: settings character ( len = :), allocatable :: flags , cflags , cxxflags , ldflags if ( settings % flag == '' ) then flags = model % compiler % get_default_flags ( settings % profile == \"release\" ) else flags = settings % flag select case ( settings % profile ) case ( \"release\" , \"debug\" ) flags = flags // model % compiler % get_default_flags ( settings % profile == \"release\" ) end select end if cflags = trim ( settings % cflag ) cxxflags = trim ( settings % cxxflag ) ldflags = trim ( settings % ldflag ) model % fortran_compile_flags = flags model % c_compile_flags = cflags model % cxx_compile_flags = cxxflags model % link_flags = ldflags end subroutine new_compiler_flags ! Check for duplicate modules subroutine check_modules_for_duplicates ( model , duplicates_found ) type ( fpm_model_t ), intent ( in ) :: model integer :: maxsize integer :: i , j , k , l , m , modi type ( string_t ), allocatable :: modules (:) logical :: duplicates_found ! Initialise the size of array maxsize = 0 ! Get number of modules provided by each source file of every package do i = 1 , size ( model % packages ) do j = 1 , size ( model % packages ( i )% sources ) if ( allocated ( model % packages ( i )% sources ( j )% modules_provided )) then maxsize = maxsize + size ( model % packages ( i )% sources ( j )% modules_provided ) end if end do end do ! Allocate array to contain distinct names of modules allocate ( modules ( maxsize )) ! Initialise index to point at start of the newly allocated array modi = 1 ! Loop through modules provided by each source file of every package ! Add it to the array if it is not already there ! Otherwise print out warning about duplicates do k = 1 , size ( model % packages ) do l = 1 , size ( model % packages ( k )% sources ) if ( allocated ( model % packages ( k )% sources ( l )% modules_provided )) then do m = 1 , size ( model % packages ( k )% sources ( l )% modules_provided ) if ( model % packages ( k )% sources ( l )% modules_provided ( m )% s . in . modules (: modi - 1 )) then write ( stderr , * ) \"Warning: Module \" , model % packages ( k )% sources ( l )% modules_provided ( m )% s , & \" in \" , model % packages ( k )% sources ( l )% file_name , \" is a duplicate\" duplicates_found = . true . else modules ( modi ) = model % packages ( k )% sources ( l )% modules_provided ( m ) modi = modi + 1 end if end do end if end do end do end subroutine check_modules_for_duplicates ! Check names of all modules in this package and its dependencies subroutine check_module_names ( model , error ) type ( fpm_model_t ), intent ( in ) :: model type ( error_t ), allocatable , intent ( out ) :: error integer :: k , l , m logical :: valid , errors_found , enforce_this_file type ( string_t ) :: package_name , module_name , package_prefix errors_found = . false . ! Loop through modules provided by each source file of every package ! Add it to the array if it is not already there ! Otherwise print out warning about duplicates do k = 1 , size ( model % packages ) package_name = string_t ( model % packages ( k )% name ) ! Custom prefix is taken from each dependency's manifest if ( model % packages ( k )% enforce_module_names ) then package_prefix = model % packages ( k )% module_prefix else package_prefix = string_t ( \"\" ) end if ! Warn the user if some of the dependencies have loose naming if ( model % enforce_module_names . and . . not . model % packages ( k )% enforce_module_names ) then write ( stderr , * ) \"Warning: Dependency \" , package_name % s // & \" does not enforce module naming, but project does. \" end if do l = 1 , size ( model % packages ( k )% sources ) ! Module naming is not enforced in test modules enforce_this_file = model % enforce_module_names . and . & model % packages ( k )% sources ( l )% unit_scope /= FPM_SCOPE_TEST if ( allocated ( model % packages ( k )% sources ( l )% modules_provided )) then do m = 1 , size ( model % packages ( k )% sources ( l )% modules_provided ) module_name = model % packages ( k )% sources ( l )% modules_provided ( m ) valid = is_valid_module_name ( module_name , & package_name , & package_prefix , & enforce_this_file ) if (. not . valid ) then if ( enforce_this_file ) then if ( len_trim ( package_prefix ) > 0 ) then write ( stderr , * ) \"ERROR: Module \" , module_name % s , & \" in \" , model % packages ( k )% sources ( l )% file_name , & \" does not match its package name (\" // package_name % s // & \") or custom prefix (\" // package_prefix % s // \").\" else write ( stderr , * ) \"ERROR: Module \" , module_name % s , & \" in \" , model % packages ( k )% sources ( l )% file_name , & \" does not match its package name (\" // package_name % s // \").\" endif else write ( stderr , * ) \"ERROR: Module \" , module_name % s , & \" in \" , model % packages ( k )% sources ( l )% file_name , & \" has an invalid Fortran name. \" end if errors_found = . true . end if end do end if end do end do if ( errors_found ) then if ( model % enforce_module_names ) & write ( stderr , * ) \" Hint: Try disabling module naming in the manifest: [build] module-naming=false . \" call fatal_error ( error , \"The package contains invalid module names. \" // & \"Naming conventions \" // merge ( 'are' , 'not' , model % enforce_module_names ) // & \" being requested.\" ) end if end subroutine check_module_names subroutine cmd_build ( settings ) type ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( error_t ), allocatable :: error integer :: i call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Target error: ' // error % message ) end if if ( settings % list ) then do i = 1 , size ( targets ) write ( stderr , * ) targets ( i )% ptr % output_file enddo else if ( settings % show_model ) then call show_model ( model ) else call build_package ( targets , model , verbose = settings % verbose ) endif end subroutine cmd_build subroutine cmd_run ( settings , test ) class ( fpm_run_settings ), intent ( inout ) :: settings logical , intent ( in ) :: test integer :: i , j , col_width logical :: found ( size ( settings % name )) type ( error_t ), allocatable :: error type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( string_t ) :: exe_cmd type ( string_t ), allocatable :: executables (:) type ( build_target_t ), pointer :: exe_target type ( srcfile_t ), pointer :: exe_source integer :: run_scope , firsterror integer , allocatable :: stat (:) character ( len = :), allocatable :: line logical :: toomany call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Targets error: ' // error % message ) end if if ( test ) then run_scope = FPM_SCOPE_TEST else run_scope = merge ( FPM_SCOPE_EXAMPLE , FPM_SCOPE_APP , settings % example ) end if ! Enumerate executable targets to run col_width = - 1 found (:) = . false . allocate ( executables ( 0 )) do i = 1 , size ( targets ) exe_target => targets ( i )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then col_width = max ( col_width , len ( basename ( exe_target % output_file )) + 2 ) if ( size ( settings % name ) == 0 ) then exe_cmd % s = exe_target % output_file executables = [ executables , exe_cmd ] else do j = 1 , size ( settings % name ) if ( glob ( trim ( exe_source % exe_name ), trim ( settings % name ( j )))) then found ( j ) = . true . exe_cmd % s = exe_target % output_file executables = [ executables , exe_cmd ] end if end do end if end if end if end do ! Check if any apps/tests were found if ( col_width < 0 ) then if ( test ) then call fpm_stop ( 0 , 'No tests to run' ) else call fpm_stop ( 0 , 'No executables to run' ) end if end if ! Check all names are valid ! or no name and found more than one file toomany = size ( settings % name ) == 0 . and . size ( executables ) > 1 if ( any (. not . found ) & & . or . & & ( ( toomany . and . . not . test ) . or . ( toomany . and . settings % runner /= '' ) ) & & . and . & & . not . settings % list ) then line = join ( settings % name ) if ( line /= '.' ) then ! do not report these special strings if ( any (. not . found )) then write ( stderr , '(A)' , advance = \"no\" ) '*cmd_run*:specified names ' do j = 1 , size ( settings % name ) if (. not . found ( j )) write ( stderr , '(A)' , advance = \"no\" ) '\"' // trim ( settings % name ( j )) // '\" ' end do write ( stderr , '(A)' ) 'not found.' write ( stderr , * ) else if ( settings % verbose ) then write ( stderr , '(A)' , advance = \"yes\" ) 'when more than one executable is available' write ( stderr , '(A)' , advance = \"yes\" ) ' program names must be specified.' endif endif call compact_list_all () if ( line == '.' . or . line == ' ' ) then ! do not report these special strings call fpm_stop ( 0 , '' ) else call fpm_stop ( 1 , '' ) endif end if call build_package ( targets , model , verbose = settings % verbose ) if ( settings % list ) then call compact_list () else allocate ( stat ( size ( executables ))) do i = 1 , size ( executables ) if ( exists ( executables ( i )% s )) then if ( settings % runner /= ' ' ) then if (. not . allocated ( settings % args )) then call run ( settings % runner_command () // ' ' // executables ( i )% s , & echo = settings % verbose , exitstat = stat ( i )) else call run ( settings % runner_command () // ' ' // executables ( i )% s // \" \" // settings % args , & echo = settings % verbose , exitstat = stat ( i )) endif else if (. not . allocated ( settings % args )) then call run ( executables ( i )% s , echo = settings % verbose , exitstat = stat ( i )) else call run ( executables ( i )% s // \" \" // settings % args , echo = settings % verbose , & exitstat = stat ( i )) endif endif else call fpm_stop ( 1 , '*cmd_run*:' // executables ( i )% s // ' not found' ) end if end do if ( any ( stat /= 0 )) then do i = 1 , size ( stat ) if ( stat ( i ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Execution for object \"' , basename ( executables ( i )% s ),& '\" returned exit code ' , stat ( i ) end if end do firsterror = findloc ( stat /= 0 , value = . true ., dim = 1 ) call fpm_stop ( stat ( firsterror ), '*cmd_run*:stopping due to failed executions' ) end if end if contains subroutine compact_list_all () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Available names:' do ii = 1 , size ( targets ) exe_target => targets ( ii )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( exe_target % output_file , suffix = . false .)] jj = jj + 1 end if end if end do write ( stderr , * ) end subroutine compact_list_all subroutine compact_list () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Matched names:' do ii = 1 , size ( executables ) write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( executables ( ii )% s , suffix = . false .)] jj = jj + 1 end do write ( stderr , * ) end subroutine compact_list end subroutine cmd_run subroutine delete_skip ( is_unix ) !> delete directories in the build folder, skipping dependencies logical , intent ( in ) :: is_unix character ( len = :), allocatable :: dir type ( string_t ), allocatable :: files (:) integer :: i call list_files ( 'build' , files , . false .) do i = 1 , size ( files ) if ( is_dir ( files ( i )% s )) then dir = files ( i )% s if (. not . str_ends_with ( dir , 'dependencies' )) call os_delete_dir ( is_unix , dir ) end if end do end subroutine delete_skip !> Delete the build directory including or excluding dependencies. subroutine cmd_clean ( settings ) !> Settings for the clean command. class ( fpm_clean_settings ), intent ( in ) :: settings character :: user_response if ( is_dir ( 'build' )) then ! Remove the entire build directory if ( settings % clean_call ) then call os_delete_dir ( os_is_unix (), 'build' ); return end if ! Remove the build directory but skip dependencies if ( settings % clean_skip ) then call delete_skip ( os_is_unix ()); return end if ! Prompt to remove the build directory but skip dependencies write ( stdout , '(A)' , advance = 'no' ) \"Delete build, excluding dependencies (y/n)? \" read ( stdin , '(A1)' ) user_response if ( lower ( user_response ) == 'y' ) call delete_skip ( os_is_unix ()) else write ( stdout , '(A)' ) \"fpm: No build directory found.\" end if end subroutine cmd_clean end module fpm","tags":"","loc":"sourcefile/fpm.f90.html"},{"title":"fpm_meta.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_meta Source Code fpm_meta.f90 Source Code !># The fpm meta-package model !> !> This is a wrapper data type that encapsulate all pre-processing information !> (compiler flags, linker libraries, etc.) required to correctly enable a package !> to use a core library. !> !> !>### Available core libraries !> !> - OpenMP !> - MPI !> - fortran-lang stdlib !> - fortran-lang minpack !> !> !> @note Core libraries are enabled in the [build] section of the fpm.toml manifest !> !> module fpm_meta use fpm_strings , only : string_t , len_trim , remove_newline_characters use fpm_error , only : error_t , fatal_error , syntax_error , fpm_stop use fpm_compiler use fpm_model use fpm_command_line use fpm_manifest_dependency , only : dependency_config_t use fpm_git , only : git_target_branch , git_target_tag use fpm_manifest , only : package_config_t use fpm_environment , only : get_env , os_is_unix use fpm_filesystem , only : run , get_temp_filename , getline , exists , canon_path , is_dir , get_dos_path use fpm_versioning , only : version_t , new_version , regex_version_from_text use fpm_os , only : get_absolute_path use iso_fortran_env , only : stdout => output_unit implicit none private public :: resolve_metapackages !> Type for describing a source file type , public :: metapackage_t !> Package version (if supported) type ( version_t ), allocatable :: version logical :: has_link_libraries = . false . logical :: has_link_flags = . false . logical :: has_build_flags = . false . logical :: has_fortran_flags = . false . logical :: has_c_flags = . false . logical :: has_cxx_flags = . false . logical :: has_include_dirs = . false . logical :: has_dependencies = . false . logical :: has_run_command = . false . logical :: has_external_modules = . false . !> List of compiler flags and options to be added type ( string_t ) :: flags type ( string_t ) :: fflags type ( string_t ) :: cflags type ( string_t ) :: cxxflags type ( string_t ) :: link_flags type ( string_t ) :: run_command type ( string_t ), allocatable :: incl_dirs (:) type ( string_t ), allocatable :: link_libs (:) type ( string_t ), allocatable :: external_modules (:) !> Special fortran features type ( fortran_features_t ), allocatable :: fortran !> List of Development dependency meta data. !> Metapackage dependencies are never exported from the model type ( dependency_config_t ), allocatable :: dependency (:) contains !> Clean metapackage structure procedure :: destroy !> Initialize the metapackage structure from its given name procedure :: new => init_from_name !> Add metapackage dependencies to the model procedure , private :: resolve_cmd procedure , private :: resolve_model procedure , private :: resolve_package_config generic :: resolve => resolve_cmd , resolve_model , resolve_package_config end type metapackage_t interface resolve_metapackages module procedure resolve_metapackage_model end interface resolve_metapackages integer , parameter :: MPI_TYPE_NONE = 0 integer , parameter :: MPI_TYPE_OPENMPI = 1 integer , parameter :: MPI_TYPE_MPICH = 2 integer , parameter :: MPI_TYPE_INTEL = 3 integer , parameter :: MPI_TYPE_MSMPI = 4 public :: MPI_TYPE_NAME !> Debugging information logical , parameter , private :: verbose = . false . integer , parameter , private :: LANG_FORTRAN = 1 integer , parameter , private :: LANG_C = 2 integer , parameter , private :: LANG_CXX = 3 contains !> Return a name for the MPI library pure function MPI_TYPE_NAME ( mpilib ) result ( name ) integer , intent ( in ) :: mpilib character ( len = :), allocatable :: name select case ( mpilib ) case ( MPI_TYPE_NONE ); name = \"none\" case ( MPI_TYPE_OPENMPI ); name = \"OpenMPI\" case ( MPI_TYPE_MPICH ); name = \"MPICH\" case ( MPI_TYPE_INTEL ); name = \"INTELMPI\" case ( MPI_TYPE_MSMPI ); name = \"MS-MPI\" case default ; name = \"UNKNOWN\" end select end function MPI_TYPE_NAME !> Clean the metapackage structure elemental subroutine destroy ( this ) class ( metapackage_t ), intent ( inout ) :: this this % has_link_libraries = . false . this % has_link_flags = . false . this % has_build_flags = . false . this % has_fortran_flags = . false . this % has_c_flags = . false . this % has_cxx_flags = . false . this % has_include_dirs = . false . this % has_dependencies = . false . this % has_run_command = . false . this % has_external_modules = . false . if ( allocated ( this % fortran )) deallocate ( this % fortran ) if ( allocated ( this % version )) deallocate ( this % version ) if ( allocated ( this % flags % s )) deallocate ( this % flags % s ) if ( allocated ( this % fflags % s )) deallocate ( this % fflags % s ) if ( allocated ( this % cflags % s )) deallocate ( this % cflags % s ) if ( allocated ( this % cxxflags % s )) deallocate ( this % cxxflags % s ) if ( allocated ( this % link_flags % s )) deallocate ( this % link_flags % s ) if ( allocated ( this % run_command % s )) deallocate ( this % run_command % s ) if ( allocated ( this % link_libs )) deallocate ( this % link_libs ) if ( allocated ( this % dependency )) deallocate ( this % dependency ) if ( allocated ( this % incl_dirs )) deallocate ( this % incl_dirs ) if ( allocated ( this % external_modules )) deallocate ( this % external_modules ) end subroutine destroy !> Initialize a metapackage from the given name subroutine init_from_name ( this , name , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this character ( * ), intent ( in ) :: name type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error !> Initialize metapackage by name select case ( name ) case ( \"openmp\" ); call init_openmp ( this , compiler , error ) case ( \"stdlib\" ); call init_stdlib ( this , compiler , error ) case ( \"minpack\" ); call init_minpack ( this , compiler , error ) case ( \"mpi\" ); call init_mpi ( this , compiler , error ) case default call syntax_error ( error , \"Package \" // name // \" is not supported in [metapackages]\" ) return end select end subroutine init_from_name !> Initialize OpenMP metapackage for the current system subroutine init_openmp ( this , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> OpenMP has compiler flags this % has_build_flags = . true . this % has_link_flags = . true . !> OpenMP flags should be added to which_compiler : select case ( compiler % id ) case ( id_gcc , id_f95 ) this % flags = string_t ( flag_gnu_openmp ) this % link_flags = string_t ( flag_gnu_openmp ) case ( id_intel_classic_windows , id_intel_llvm_windows ) this % flags = string_t ( flag_intel_openmp_win ) this % link_flags = string_t ( flag_intel_openmp_win ) case ( id_intel_classic_nix , id_intel_classic_mac ,& id_intel_llvm_nix ) this % flags = string_t ( flag_intel_openmp ) this % link_flags = string_t ( flag_intel_openmp ) case ( id_pgi , id_nvhpc ) this % flags = string_t ( flag_pgi_openmp ) this % link_flags = string_t ( flag_pgi_openmp ) case ( id_ibmxl ) this % flags = string_t ( \" -qsmp=omp\" ) this % link_flags = string_t ( \" -qsmp=omp\" ) case ( id_nag ) this % flags = string_t ( flag_nag_openmp ) this % link_flags = string_t ( flag_nag_openmp ) case ( id_lfortran ) this % flags = string_t ( flag_lfortran_openmp ) this % link_flags = string_t ( flag_lfortran_openmp ) case default call fatal_error ( error , 'openmp not supported on compiler ' // compiler % name () // ' yet' ) end select which_compiler end subroutine init_openmp !> Initialize minpack metapackage for the current system subroutine init_minpack ( this , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> minpack is queried as a dependency from the official repository this % has_dependencies = . true . allocate ( this % dependency ( 1 )) !> 1) minpack. There are no true releases currently. Fetch HEAD this % dependency ( 1 )% name = \"minpack\" this % dependency ( 1 )% git = git_target_tag ( \"https://github.com/fortran-lang/minpack\" , \"v2.0.0-rc.1\" ) if (. not . allocated ( this % dependency ( 1 )% git )) then call fatal_error ( error , 'cannot initialize git repo dependency for minpack metapackage' ) return end if end subroutine init_minpack !> Initialize stdlib metapackage for the current system subroutine init_stdlib ( this , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> Stdlib is queried as a dependency from the official repository this % has_dependencies = . true . allocate ( this % dependency ( 2 )) !> 1) Test-drive this % dependency ( 1 )% name = \"test-drive\" this % dependency ( 1 )% git = git_target_branch ( \"https://github.com/fortran-lang/test-drive\" , \"v0.4.0\" ) if (. not . allocated ( this % dependency ( 1 )% git )) then call fatal_error ( error , 'cannot initialize test-drive git dependency for stdlib metapackage' ) return end if !> 2) stdlib this % dependency ( 2 )% name = \"stdlib\" this % dependency ( 2 )% git = git_target_branch ( \"https://github.com/fortran-lang/stdlib\" , \"stdlib-fpm\" ) if (. not . allocated ( this % dependency ( 2 )% git )) then call fatal_error ( error , 'cannot initialize git repo dependency for stdlib metapackage' ) return end if end subroutine init_stdlib ! Resolve metapackage dependencies into the command line settings subroutine resolve_cmd ( self , settings , error ) class ( metapackage_t ), intent ( in ) :: self class ( fpm_cmd_settings ), intent ( inout ) :: settings type ( error_t ), allocatable , intent ( out ) :: error ! Add customize run commands if ( self % has_run_command ) then select type ( cmd => settings ) class is ( fpm_run_settings ) ! includes fpm_test_settings ! Only override runner if user has not provided a custom one if (. not . len_trim ( cmd % runner ) > 0 ) cmd % runner = self % run_command % s end select endif end subroutine resolve_cmd ! Resolve metapackage dependencies into the model subroutine resolve_model ( self , model , error ) class ( metapackage_t ), intent ( in ) :: self type ( fpm_model_t ), intent ( inout ) :: model type ( error_t ), allocatable , intent ( out ) :: error ! Add global build flags, to apply to all sources if ( self % has_build_flags ) then model % fortran_compile_flags = model % fortran_compile_flags // self % flags % s model % c_compile_flags = model % c_compile_flags // self % flags % s model % cxx_compile_flags = model % cxx_compile_flags // self % flags % s endif ! Add language-specific flags if ( self % has_fortran_flags ) model % fortran_compile_flags = model % fortran_compile_flags // self % fflags % s if ( self % has_c_flags ) model % c_compile_flags = model % c_compile_flags // self % cflags % s if ( self % has_cxx_flags ) model % cxx_compile_flags = model % cxx_compile_flags // self % cxxflags % s if ( self % has_link_flags ) then model % link_flags = model % link_flags // self % link_flags % s end if if ( self % has_link_libraries ) then model % link_libraries = [ model % link_libraries , self % link_libs ] end if if ( self % has_include_dirs ) then model % include_dirs = [ model % include_dirs , self % incl_dirs ] end if if ( self % has_external_modules ) then model % external_modules = [ model % external_modules , self % external_modules ] end if end subroutine resolve_model subroutine resolve_package_config ( self , package , error ) class ( metapackage_t ), intent ( in ) :: self type ( package_config_t ), intent ( inout ) :: package type ( error_t ), allocatable , intent ( out ) :: error ! All metapackage dependencies are added as dev-dependencies, ! as they may change if built upstream if ( self % has_dependencies ) then if ( allocated ( package % dev_dependency )) then package % dev_dependency = [ package % dev_dependency , self % dependency ] else package % dev_dependency = self % dependency end if end if ! Check if there are any special fortran requests which the package does not comply to if ( allocated ( self % fortran )) then if ( self % fortran % implicit_external . neqv . package % fortran % implicit_external ) then call fatal_error ( error , 'metapackage fortran error: metapackage ' // & dn ( self % fortran % implicit_external ) // ' require implicit-external, main package ' // & dn ( package % fortran % implicit_external )) return end if if ( self % fortran % implicit_typing . neqv . package % fortran % implicit_typing ) then call fatal_error ( error , 'metapackage fortran error: metapackage ' // & dn ( self % fortran % implicit_external ) // ' require implicit-typing, main package ' // & dn ( package % fortran % implicit_external )) return end if end if contains pure function dn ( bool ) logical , intent ( in ) :: bool character ( len = :), allocatable :: dn if ( bool ) then dn = \"does\" else dn = \"does not\" end if end function dn end subroutine resolve_package_config ! Add named metapackage dependency to the model subroutine add_metapackage_model ( model , package , settings , name , error ) type ( fpm_model_t ), intent ( inout ) :: model type ( package_config_t ), intent ( inout ) :: package class ( fpm_cmd_settings ), intent ( inout ) :: settings character ( * ), intent ( in ) :: name type ( error_t ), allocatable , intent ( out ) :: error type ( metapackage_t ) :: meta !> Init metapackage call meta % new ( name , model % compiler , error ) if ( allocated ( error )) return !> Add it into the model call meta % resolve ( model , error ) if ( allocated ( error )) return !> Add it into the package call meta % resolve ( package , error ) if ( allocated ( error )) return !> Add it into the settings call meta % resolve ( settings , error ) if ( allocated ( error )) return ! If we need to run executables, there should be an MPI runner if ( name == \"mpi\" ) then select type ( settings ) class is ( fpm_run_settings ) ! run, test if (. not . meta % has_run_command ) & call fatal_error ( error , \"cannot find a valid mpi runner on the local host\" ) end select endif end subroutine add_metapackage_model !> Resolve all metapackages into the package config subroutine resolve_metapackage_model ( model , package , settings , error ) type ( fpm_model_t ), intent ( inout ) :: model type ( package_config_t ), intent ( inout ) :: package class ( fpm_build_settings ), intent ( inout ) :: settings type ( error_t ), allocatable , intent ( out ) :: error ! Dependencies are added to the package config, so they're properly resolved ! into the dependency tree later. ! Flags are added to the model (whose compiler needs to be already initialized) if ( model % compiler % is_unknown ()) then call fatal_error ( error , \"compiler not initialized: cannot build metapackages\" ) return end if ! OpenMP if ( package % meta % openmp % on ) then call add_metapackage_model ( model , package , settings , \"openmp\" , error ) if ( allocated ( error )) return endif ! stdlib if ( package % meta % stdlib % on ) then call add_metapackage_model ( model , package , settings , \"stdlib\" , error ) if ( allocated ( error )) return endif ! stdlib if ( package % meta % minpack % on ) then call add_metapackage_model ( model , package , settings , \"minpack\" , error ) if ( allocated ( error )) return endif ! Stdlib is not 100% thread safe. print a warning to the user if ( package % meta % stdlib % on . and . package % meta % openmp % on ) then write ( stdout , '(a)' ) ' both openmp and stdlib requested: some functions may not be thread-safe!' end if ! MPI if ( package % meta % mpi % on ) then call add_metapackage_model ( model , package , settings , \"mpi\" , error ) if ( allocated ( error )) return endif end subroutine resolve_metapackage_model !> Initialize MPI metapackage for the current system subroutine init_mpi ( this , compiler , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ), allocatable :: c_wrappers (:), cpp_wrappers (:), fort_wrappers (:) type ( string_t ) :: output , fwrap , cwrap , cxxwrap character ( 256 ) :: msg_out character ( len = :), allocatable :: tokens (:) integer :: wcfit ( 3 ), mpilib ( 3 ), ic , icpp , i logical :: found !> Cleanup call destroy ( this ) !> Get all candidate MPI wrappers call mpi_wrappers ( compiler , fort_wrappers , c_wrappers , cpp_wrappers ) if ( verbose ) print 1 , size ( fort_wrappers ), size ( c_wrappers ), size ( cpp_wrappers ) call wrapper_compiler_fit ( fort_wrappers , c_wrappers , cpp_wrappers , compiler , wcfit , mpilib , error ) if ( allocated ( error ) . or . all ( wcfit == 0 )) then !> No wrapper compiler fit. Are we on Windows? use MSMPI-specific search found = msmpi_init ( this , compiler , error ) if ( allocated ( error )) return !> All attempts failed if (. not . found ) then call fatal_error ( error , \"cannot find MPI wrappers or libraries for \" // compiler % name () // \" compiler\" ) return endif else if ( wcfit ( LANG_FORTRAN ) > 0 ) fwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) if ( wcfit ( LANG_C ) > 0 ) cwrap = c_wrappers ( wcfit ( LANG_C )) if ( wcfit ( LANG_CXX ) > 0 ) cxxwrap = cpp_wrappers ( wcfit ( LANG_CXX )) !> If there's only an available Fortran wrapper, and the compiler's different than fpm's baseline !> fortran compiler suite, we still want to enable C language flags as that is most likely being !> ABI-compatible anyways. However, issues may arise. !> see e.g. Homebrew with clabng C/C++ and GNU fortran at https://gitlab.kitware.com/cmake/cmake/-/issues/18139 if ( wcfit ( LANG_FORTRAN ) > 0 . and . all ( wcfit ([ LANG_C , LANG_CXX ]) == 0 )) then cwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) cxxwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) end if if ( verbose ) print * , '+ MPI fortran wrapper: ' , fwrap % s if ( verbose ) print * , '+ MPI c wrapper: ' , cwrap % s if ( verbose ) print * , '+ MPI c++ wrapper: ' , cxxwrap % s !> Initialize MPI package from wrapper command call init_mpi_from_wrappers ( this , compiler , mpilib ( LANG_FORTRAN ), fwrap , cwrap , cxxwrap , error ) if ( allocated ( error )) return !> Request Fortran implicit typing if ( mpilib ( LANG_FORTRAN ) /= MPI_TYPE_INTEL ) then allocate ( this % fortran ) this % fortran % implicit_typing = . true . this % fortran % implicit_external = . true . endif end if !> Not all MPI implementations offer modules mpi and mpi_f08: hence, include them !> to the list of external modules, so they won't be requested as standard source files this % has_external_modules = . true . this % external_modules = [ string_t ( \"mpi\" ), string_t ( \"mpi_f08\" )] 1 format ( 'MPI wrappers found: fortran=' , i0 , ' c=' , i0 , ' c++=' , i0 ) end subroutine init_mpi !> Check if we're on a 64-bit environment !> Accept answer from https://stackoverflow.com/questions/49141093/get-system-information-with-fortran logical function is_64bit_environment () use iso_c_binding , only : c_intptr_t integer , parameter :: nbits = bit_size ( 0_c_intptr_t ) is_64bit_environment = nbits == 64 end function is_64bit_environment !> Check if there is a wrapper-compiler fit subroutine wrapper_compiler_fit ( fort_wrappers , c_wrappers , cpp_wrappers , compiler , wrap , mpi , error ) type ( string_t ), allocatable , intent ( in ) :: fort_wrappers (:), c_wrappers (:), cpp_wrappers (:) type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error integer , intent ( out ), dimension ( 3 ) :: wrap , mpi type ( error_t ), allocatable :: wrap_error wrap = 0 mpi = MPI_TYPE_NONE if ( size ( fort_wrappers ) > 0 ) & call mpi_compiler_match ( LANG_FORTRAN , fort_wrappers , compiler , wrap ( LANG_FORTRAN ), mpi ( LANG_FORTRAN ), wrap_error ) if ( size ( c_wrappers ) > 0 ) & call mpi_compiler_match ( LANG_C , c_wrappers , compiler , wrap ( LANG_C ), mpi ( LANG_C ), wrap_error ) if ( size ( cpp_wrappers ) > 0 ) & call mpi_compiler_match ( LANG_CXX , cpp_wrappers , compiler , wrap ( LANG_CXX ), mpi ( LANG_CXX ), wrap_error ) !> Find a Fortran wrapper for the current compiler if ( all ( wrap == 0 )) then call fatal_error ( error , 'no valid wrappers match current compiler, ' // compiler_name ( compiler )) return end if end subroutine wrapper_compiler_fit !> Check if a local MS-MPI SDK build is found logical function msmpi_init ( this , compiler , error ) result ( found ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: incdir , windir , libdir , bindir , post , reall , msysdir type ( version_t ) :: ver , ver10 type ( string_t ) :: cpath , msys_path , runner_path logical :: msys2 !> Default: not found found = . false . if ( get_os_type () == OS_WINDOWS ) then ! to run MSMPI on Windows, is_minGW : if ( compiler % id == id_gcc ) then call compiler_get_version ( compiler , ver , msys2 , error ) if ( allocated ( error )) return endif is_minGW ! Check we're on a 64-bit environment if ( is_64bit_environment ()) then libdir = get_env ( 'MSMPI_LIB64' ) post = 'x64' else libdir = get_env ( 'MSMPI_LIB32' ) post = 'x86' !> Not working on 32-bit Windows yet call fatal_error ( error , 'MS-MPI error: this package requires 64-bit Windows environment' ) return end if ! Check that the runtime is installed bindir = \"\" call get_absolute_path ( get_env ( 'MSMPI_BIN' ), bindir , error ) if ( verbose ) print * , '+ %MSMPI_BIN%=' , bindir ! In some environments, variable %MSMPI_BIN% is missing (i.e. in GitHub Action images). ! Do a second attempt: search for the default location if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ %MSMPI_BIN% empty, searching C:\\Program Files\\Microsoft MPI\\Bin\\ ...' call get_absolute_path ( 'C:\\Program Files\\Microsoft MPI\\Bin\\mpiexec.exe' , bindir , error ) endif ! Do a third attempt: search for mpiexec.exe in PATH location if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ C:\\Program Files\\Microsoft MPI\\Bin\\ not found. searching %PATH%...' call get_mpi_runner ( runner_path , verbose , error ) if (. not . allocated ( error )) then if ( verbose ) print * , '+ mpiexec found: ' , runner_path % s call find_command_location ( runner_path % s , bindir , verbose = verbose , error = error ) endif endif if ( allocated ( error ) . or . . not . exists ( bindir )) then call fatal_error ( error , 'MS-MPI error: MS-MPI Runtime directory is missing. ' // & 'check environment variable %MSMPI_BIN% or that the folder is in %PATH%.' ) return end if ! Success! found = . true . ! Init ms-mpi call destroy ( this ) ! MSYS2 provides a pre-built static msmpi.dll.a library. Use that if possible use_prebuilt : if ( msys2 ) then ! MSYS executables are in %MSYS_ROOT%/bin call compiler_get_path ( compiler , cpath , error ) if ( allocated ( error )) return call get_absolute_path ( join_path ( cpath % s , '..' ), msys_path % s , error ) if ( allocated ( error )) return call get_absolute_path ( join_path ( msys_path % s , 'include' ), incdir , error ) if ( allocated ( error )) return call get_absolute_path ( join_path ( msys_path % s , 'lib' ), libdir , error ) if ( allocated ( error )) return if ( verbose ) print 1 , 'include' , incdir , exists ( incdir ) if ( verbose ) print 1 , 'library' , libdir , exists ( libdir ) ! Check that the necessary files exist call get_absolute_path ( join_path ( libdir , 'libmsmpi.dll.a' ), post , error ) if ( allocated ( error )) return if ( len_trim ( post ) <= 0 . or . . not . exists ( post )) then call fatal_error ( error , 'MS-MPI available through the MSYS2 system not found. ' // & 'Run ' // & 'or your system-specific version to install.' ) return end if ! Add dir cpath this % has_link_flags = . true . this % link_flags = string_t ( ' -L' // get_dos_path ( libdir , error )) this % has_link_libraries = . true . this % link_libs = [ string_t ( 'msmpi.dll' )] if ( allocated ( error )) return this % has_include_dirs = . true . this % incl_dirs = [ string_t ( get_dos_path ( incdir , error ))] if ( allocated ( error )) return else call fatal_error ( error , 'MS-MPI cannot work with non-MSYS2 GNU compilers yet' ) return ! Add dir path this % has_link_flags = . true . this % link_flags = string_t ( ' -L' // get_dos_path ( libdir , error )) this % has_link_libraries = . true . this % link_libs = [ string_t ( 'msmpi' ), string_t ( 'msmpifec' ), string_t ( 'msmpifmc' )] if ( allocated ( error )) return this % has_include_dirs = . true . this % incl_dirs = [ string_t ( get_dos_path ( incdir , error )), & string_t ( get_dos_path ( incdir // post , error ))] if ( allocated ( error )) return end if use_prebuilt !> Request Fortran implicit typing allocate ( this % fortran ) this % fortran % implicit_typing = . true . this % fortran % implicit_external = . true . ! gfortran>=10 is incompatible with the old-style mpif.h MS-MPI headers. ! If so, add flags to allow old-style BOZ constants in mpif.h allow_BOZ : if ( compiler % id == id_gcc ) then call new_version ( ver10 , '10.0.0' , error ) if ( allocated ( error )) return if ( ver >= ver10 ) then this % has_build_flags = . true . this % flags = string_t ( ' -fallow-invalid-boz' ) end if endif allow_BOZ !> Add default run command this % has_run_command = . true . this % run_command = string_t ( join_path ( get_dos_path ( bindir , error ), 'mpiexec.exe' ) // ' -np * ' ) else !> Not on Windows found = . false . end if 1 format ( 'MSMSPI ' , a , ' directory: PATH=' , a , ' EXISTS=' , l1 ) end function msmpi_init !> Check if we're under a WSL bash shell logical function wsl_shell () if ( get_os_type () == OS_WINDOWS ) then wsl_shell = exists ( '/proc/sys/fs/binfmt_misc/WSLInterop' ) else wsl_shell = . false . endif end function wsl_shell !> Find the location of a valid command subroutine find_command_location ( command , path , echo , verbose , error ) character ( * ), intent ( in ) :: command character ( len = :), allocatable , intent ( out ) :: path logical , optional , intent ( in ) :: echo , verbose type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: tmp_file , screen_output , line , fullpath , search_command integer :: stat , iunit , ire , length , try character ( * ), parameter :: search ( 2 ) = [ \"where \" , \"which \" ] if ( len_trim ( command ) <= 0 ) then call fatal_error ( error , 'empty command provided in find_command_location' ) return end if tmp_file = get_temp_filename () ! On Windows, we try both commands because we may be on WSL do try = merge ( 1 , 2 , get_os_type () == OS_WINDOWS ), 2 search_command = search ( try ) // command call run ( search_command , echo = echo , exitstat = stat , verbose = verbose , redirect = tmp_file ) if ( stat == 0 ) exit end do if ( stat /= 0 ) then call fatal_error ( error , 'find_command_location failed for ' // command ) return end if ! Only read first instance (first line) allocate ( character ( len = 0 ) :: screen_output ) open ( newunit = iunit , file = tmp_file , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit if ( len ( screen_output ) > 0 ) then screen_output = screen_output // new_line ( 'a' ) // line else screen_output = line endif end do ! Close and delete file close ( iunit , status = 'delete' ) else call fatal_error ( error , 'cannot read temporary file from successful find_command_location' ) return endif ! Only use the first instance length = index ( screen_output , new_line ( 'a' )) multiline : if ( length > 1 ) then fullpath = screen_output ( 1 : length - 1 ) else fullpath = screen_output endif multiline if ( len_trim ( fullpath ) < 1 ) then call fatal_error ( error , 'no paths found to command (' // command // ')' ) return end if ! Extract path only length = index ( fullpath , command , BACK = . true .) if ( length <= 0 ) then call fatal_error ( error , 'full path to command (' // command // ') does not include command name' ) return elseif ( length == 1 ) then ! Compiler is in the current folder path = '.' else path = fullpath ( 1 : length - 1 ) end if if ( allocated ( error )) return ! On Windows, be sure to return a path with no spaces if ( get_os_type () == OS_WINDOWS ) path = get_dos_path ( path , error ) if ( allocated ( error ) . or . . not . is_dir ( path )) then call fatal_error ( error , 'full path (' // path // ') to command (' // command // ') is not a directory' ) return end if end subroutine find_command_location !> Get MPI runner in $PATH subroutine get_mpi_runner ( command , verbose , error ) type ( string_t ), intent ( out ) :: command logical , intent ( in ) :: verbose type ( error_t ), allocatable , intent ( out ) :: error character ( * ), parameter :: try ( * ) = [ 'mpiexec ' , 'mpirun ' , 'mpiexec.exe' , 'mpirun.exe ' ] character (:), allocatable :: bindir integer :: itri logical :: success ! Try several commands do itri = 1 , size ( try ) call find_command_location ( trim ( try ( itri )), command % s , verbose = verbose , error = error ) if ( allocated ( error )) cycle ! Success! success = len_trim ( command % s ) > 0 if ( success ) then if ( verbose ) print * , '+ runner folder found: ' // command % s command % s = join_path ( command % s , trim ( try ( itri ))) return endif end do ! On windows, also search in %MSMPI_BIN% if ( get_os_type () == OS_WINDOWS ) then ! Check that the runtime is installed bindir = \"\" call get_absolute_path ( get_env ( 'MSMPI_BIN' ), bindir , error ) if ( verbose ) print * , '+ %MSMPI_BIN%=' , bindir ! In some environments, variable %MSMPI_BIN% is missing (i.e. in GitHub Action images). ! Do a second attempt: search for the default location if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ %MSMPI_BIN% empty, searching C:\\Program Files\\Microsoft MPI\\Bin\\ ...' call get_absolute_path ( 'C:\\Program Files\\Microsoft MPI\\Bin\\mpiexec.exe' , bindir , error ) endif if ( len_trim ( bindir ) > 0 . and . . not . allocated ( error )) then ! MSMPI_BIN directory found command % s = join_path ( bindir , 'mpiexec.exe' ) return endif endif ! No valid command found call fatal_error ( error , 'cannot find a valid mpi runner command' ) return end subroutine get_mpi_runner !> Return compiler path subroutine compiler_get_path ( self , path , error ) type ( compiler_t ), intent ( in ) :: self type ( string_t ), intent ( out ) :: path type ( error_t ), allocatable , intent ( out ) :: error call find_command_location ( self % fc , path % s , self % echo , self % verbose , error ) end subroutine compiler_get_path !> Return compiler version subroutine compiler_get_version ( self , version , is_msys2 , error ) type ( compiler_t ), intent ( in ) :: self type ( version_t ), intent ( out ) :: version logical , intent ( out ) :: is_msys2 type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: tmp_file , screen_output , line type ( string_t ) :: ver integer :: stat , iunit , ire , length is_msys2 = . false . select case ( self % id ) case ( id_gcc ) tmp_file = get_temp_filename () call run ( self % fc // \" --version \" , echo = self % echo , verbose = self % verbose , redirect = tmp_file , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'compiler_get_version failed for ' // self % fc ) return end if allocate ( character ( len = 0 ) :: screen_output ) open ( newunit = iunit , file = tmp_file , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output = screen_output // ' ' // line // ' ' end do ! Close and delete file close ( iunit , status = 'delete' ) else call fatal_error ( error , 'cannot read temporary file from successful compiler_get_version' ) return endif ! Check if this gcc is from the MSYS2 project is_msys2 = index ( screen_output , 'MSYS2' ) > 0 ver = regex_version_from_text ( screen_output , self % fc // ' compiler' , error ) if ( allocated ( error )) return ! Extract version call new_version ( version , ver % s , error ) case default call fatal_error ( error , 'compiler_get_version not yet implemented for compiler ' // self % fc ) return end select end subroutine compiler_get_version !> Initialize an MPI metapackage from a valid wrapper command ('mpif90', etc...) subroutine init_mpi_from_wrappers ( this , compiler , mpilib , fort_wrapper , c_wrapper , cxx_wrapper , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: fort_wrapper , c_wrapper , cxx_wrapper type ( error_t ), allocatable , intent ( out ) :: error type ( version_t ) :: version type ( error_t ), allocatable :: runner_error ! Cleanup structure call destroy ( this ) ! Get linking flags if ( mpilib /= MPI_TYPE_INTEL ) then this % link_flags = mpi_wrapper_query ( mpilib , fort_wrapper , 'link' , verbose , error ) ! We fix OpenMPI's Fortran wrapper bug (https://github.com/open-mpi/ompi/issues/11636) !call fix_openmpi_link_flags(this%link_flags,compiler,mpilib,fort_wrapper,c_wrapper,cxx_wrapper,error) if ( allocated ( error )) return this % has_link_flags = len_trim ( this % link_flags ) > 0 endif ! Request to use libs in arbitrary order if ( this % has_link_flags . and . compiler % is_gnu () . and . os_is_unix () . and . get_os_type () /= OS_MACOS ) then this % link_flags = string_t ( ' -Wl,--start-group ' // this % link_flags % s ) end if ! Add language-specific flags call set_language_flags ( mpilib , fort_wrapper , this % has_fortran_flags , this % fflags , verbose , error ) if ( allocated ( error )) return call set_language_flags ( mpilib , c_wrapper , this % has_c_flags , this % cflags , verbose , error ) if ( allocated ( error )) return call set_language_flags ( mpilib , cxx_wrapper , this % has_cxx_flags , this % cxxflags , verbose , error ) if ( allocated ( error )) return ! Get library version version = mpi_version_get ( mpilib , fort_wrapper , error ) if ( allocated ( error )) then return else allocate ( this % version , source = version ) end if !> Add default run command, if present this % run_command = mpi_wrapper_query ( mpilib , fort_wrapper , 'runner' , verbose , runner_error ) this % has_run_command = ( len_trim ( this % run_command ) > 0 ) . and . . not . allocated ( runner_error ) contains subroutine set_language_flags ( mpilib , wrapper , has_flags , flags , verbose , error ) integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: wrapper logical , intent ( inout ) :: has_flags type ( string_t ), intent ( inout ) :: flags logical , intent ( in ) :: verbose type ( error_t ), allocatable , intent ( out ) :: error ! Get build flags for each language if ( len_trim ( wrapper ) > 0 ) then flags = mpi_wrapper_query ( mpilib , wrapper , 'flags' , verbose , error ) if ( allocated ( error )) return has_flags = len_trim ( flags ) > 0 ! Add heading space flags = string_t ( ' ' // flags % s ) if ( verbose ) print * , '+ MPI language flags from wrapper <' , wrapper % s , '>: flags=' , flags % s endif end subroutine set_language_flags end subroutine init_mpi_from_wrappers !> Match one of the available compiler wrappers with the current compiler subroutine mpi_compiler_match ( language , wrappers , compiler , which_one , mpilib , error ) integer , intent ( in ) :: language type ( string_t ), intent ( in ) :: wrappers (:) type ( compiler_t ), intent ( in ) :: compiler integer , intent ( out ) :: which_one , mpilib type ( error_t ), allocatable , intent ( out ) :: error integer :: i type ( string_t ) :: screen character ( 128 ) :: msg_out type ( compiler_t ) :: mpi_compiler which_one = 0 mpilib = MPI_TYPE_NONE do i = 1 , size ( wrappers ) mpilib = which_mpi_library ( wrappers ( i ), compiler , verbose = . false .) screen = mpi_wrapper_query ( mpilib , wrappers ( i ), 'compiler' , verbose = . false ., error = error ) if ( allocated ( error )) return select case ( language ) case ( LANG_FORTRAN ) ! Build compiler type. The ID is created based on the Fortran name call new_compiler ( mpi_compiler , screen % s , '' , '' , echo = . true ., verbose = . false .) ! Fortran match found! if ( mpi_compiler % id == compiler % id ) then which_one = i return end if case ( LANG_C ) ! For other languages, we can only hope that the name matches the expected one if ( screen % s == compiler % cc . or . screen % s == compiler % fc ) then which_one = i return end if case ( LANG_CXX ) if ( screen % s == compiler % cxx . or . screen % s == compiler % fc ) then which_one = i return end if end select end do ! None of the available wrappers matched the current Fortran compiler write ( msg_out , 1 ) size ( wrappers ), compiler % fc call fatal_error ( error , trim ( msg_out )) 1 format ( ' None out of ' , i0 , ' valid MPI wrappers matches compiler ' , a ) end subroutine mpi_compiler_match !> Return library version from the MPI wrapper command type ( version_t ) function mpi_version_get ( mpilib , wrapper , error ) integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: wrapper type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ) :: version_line ! Get version string version_line = mpi_wrapper_query ( mpilib , wrapper , 'version' , error = error ) if ( allocated ( error )) return ! Wrap to object call new_version ( mpi_version_get , version_line % s , error ) end function mpi_version_get !> Return several mpi wrappers, and return subroutine mpi_wrappers ( compiler , fort_wrappers , c_wrappers , cpp_wrappers ) type ( compiler_t ), intent ( in ) :: compiler type ( string_t ), allocatable , intent ( out ) :: c_wrappers (:), cpp_wrappers (:), fort_wrappers (:) character ( len = :), allocatable :: mpi_root , intel_wrap type ( error_t ), allocatable :: error ! Attempt gathering MPI wrapper names from the environment variables c_wrappers = [ string_t ( get_env ( 'MPICC' , 'mpicc' ))] cpp_wrappers = [ string_t ( get_env ( 'MPICXX' , 'mpic++' ))] fort_wrappers = [ string_t ( get_env ( 'MPIFC' , 'mpifc' )),& string_t ( get_env ( 'MPIf90' , 'mpif90' )),& string_t ( get_env ( 'MPIf77' , 'mpif77' ))] if ( get_os_type () == OS_WINDOWS ) then c_wrappers = [ c_wrappers , string_t ( 'mpicc.bat' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'mpicxx.bat' )] fort_wrappers = [ fort_wrappers , string_t ( 'mpifc.bat' )] endif ! Add compiler-specific wrappers compiler_specific : select case ( compiler % id ) case ( id_gcc , id_f95 ) c_wrappers = [ c_wrappers , string_t ( 'mpigcc' ), string_t ( 'mpgcc' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'mpig++' ), string_t ( 'mpg++' )] fort_wrappers = [ fort_wrappers , string_t ( 'mpigfortran' ), string_t ( 'mpgfortran' ),& string_t ( 'mpig77' ), string_t ( 'mpg77' )] case ( id_intel_classic_windows , id_intel_llvm_windows , & id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , id_intel_llvm_unknown ) c_wrappers = [ string_t ( get_env ( 'I_MPI_CC' , 'mpiicc' ))] cpp_wrappers = [ string_t ( get_env ( 'I_MPI_CXX' , 'mpiicpc' ))] fort_wrappers = [ string_t ( get_env ( 'I_MPI_F90' , 'mpiifort' ))] ! Also search MPI wrappers via the base MPI folder mpi_root = get_env ( 'I_MPI_ROOT' ) if ( mpi_root /= \"\" ) then mpi_root = join_path ( mpi_root , 'bin' ) intel_wrap = join_path ( mpi_root , 'mpiifort' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) fort_wrappers = [ fort_wrappers , string_t ( intel_wrap )] intel_wrap = join_path ( mpi_root , 'mpiicc' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) c_wrappers = [ c_wrappers , string_t ( intel_wrap )] intel_wrap = join_path ( mpi_root , 'mpiicpc' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) cpp_wrappers = [ cpp_wrappers , string_t ( intel_wrap )] end if case ( id_pgi , id_nvhpc ) c_wrappers = [ c_wrappers , string_t ( 'mpipgicc' ), string_t ( 'mpgcc' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'mpipgic++' )] fort_wrappers = [ fort_wrappers , string_t ( 'mpipgifort' ), string_t ( 'mpipgf90' )] case ( id_cray ) c_wrappers = [ c_wrappers , string_t ( 'cc' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'CC' )] fort_wrappers = [ fort_wrappers , string_t ( 'ftn' )] end select compiler_specific call assert_mpi_wrappers ( fort_wrappers , compiler ) call assert_mpi_wrappers ( c_wrappers , compiler ) call assert_mpi_wrappers ( cpp_wrappers , compiler ) end subroutine mpi_wrappers !> Filter out invalid/unavailable mpi wrappers subroutine assert_mpi_wrappers ( wrappers , compiler , verbose ) type ( string_t ), allocatable , intent ( inout ) :: wrappers (:) type ( compiler_t ), intent ( in ) :: compiler logical , optional , intent ( in ) :: verbose integer :: i integer , allocatable :: works (:) allocate ( works ( size ( wrappers ))) do i = 1 , size ( wrappers ) if ( present ( verbose )) then if ( verbose ) print * , '+ MPI test wrapper <' , wrappers ( i )% s , '>' endif works ( i ) = which_mpi_library ( wrappers ( i ), compiler , verbose ) end do ! Filter out non-working wrappers wrappers = pack ( wrappers , works /= MPI_TYPE_NONE ) end subroutine assert_mpi_wrappers !> Simple call to execute_command_line involving one mpi* wrapper subroutine run_mpi_wrapper ( wrapper , args , verbose , exitcode , cmd_success , screen_output ) type ( string_t ), intent ( in ) :: wrapper type ( string_t ), intent ( in ), optional :: args (:) logical , intent ( in ), optional :: verbose integer , intent ( out ), optional :: exitcode logical , intent ( out ), optional :: cmd_success type ( string_t ), intent ( out ), optional :: screen_output logical :: echo_local character (:), allocatable :: redirect_str , command , redirect , line integer :: iunit , iarg , stat , cmdstat if ( present ( verbose )) then echo_local = verbose else echo_local = . false . end if ! No redirection and non-verbose output if ( present ( screen_output )) then redirect = get_temp_filename () redirect_str = \">\" // redirect // \" 2>&1\" else if ( os_is_unix ()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if ! Empty command if ( len_trim ( wrapper ) <= 0 ) then if ( echo_local ) print * , '+ ' if ( present ( exitcode )) exitcode = 0 if ( present ( cmd_success )) cmd_success = . true . if ( present ( screen_output )) screen_output = string_t ( \"\" ) return end if ! Init command command = trim ( wrapper % s ) add_arguments : if ( present ( args )) then do iarg = 1 , size ( args ) if ( len_trim ( args ( iarg )) <= 0 ) cycle command = trim ( command ) // ' ' // args ( iarg )% s end do endif add_arguments if ( echo_local ) print * , '+ ' , command ! Test command call execute_command_line ( command // redirect_str , exitstat = stat , cmdstat = cmdstat ) ! Command successful? if ( present ( cmd_success )) cmd_success = cmdstat == 0 ! Program exit code? if ( present ( exitcode )) exitcode = stat ! Want screen output? if ( present ( screen_output ) . and . cmdstat == 0 ) then allocate ( character ( len = 0 ) :: screen_output % s ) open ( newunit = iunit , file = redirect , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output % s = screen_output % s // new_line ( 'a' ) // line if ( echo_local ) write ( * , '(A)' ) trim ( line ) end do ! Close and delete file close ( iunit , status = 'delete' ) else call fpm_stop ( 1 , 'cannot read temporary file from successful MPI wrapper' ) endif end if end subroutine run_mpi_wrapper !> Get MPI library type from the wrapper command. Currently, only OpenMPI is supported integer function which_mpi_library ( wrapper , compiler , verbose ) type ( string_t ), intent ( in ) :: wrapper type ( compiler_t ), intent ( in ) :: compiler logical , intent ( in ), optional :: verbose logical :: is_mpi_wrapper integer :: stat ! Init as currently unsupported library which_mpi_library = MPI_TYPE_NONE if ( len_trim ( wrapper ) <= 0 ) return ! Run mpi wrapper first call run_mpi_wrapper ( wrapper , verbose = verbose , cmd_success = is_mpi_wrapper ) if ( is_mpi_wrapper ) then if ( compiler % is_intel ()) then which_mpi_library = MPI_TYPE_INTEL return end if ! Attempt to decipher which library this wrapper comes from. ! OpenMPI responds to '--showme' calls call run_mpi_wrapper ( wrapper ,[ string_t ( '--showme' )], verbose ,& exitcode = stat , cmd_success = is_mpi_wrapper ) if ( stat == 0 . and . is_mpi_wrapper ) then which_mpi_library = MPI_TYPE_OPENMPI return endif ! MPICH responds to '-show' calls call run_mpi_wrapper ( wrapper ,[ string_t ( '-show' )], verbose ,& exitcode = stat , cmd_success = is_mpi_wrapper ) if ( stat == 0 . and . is_mpi_wrapper ) then which_mpi_library = MPI_TYPE_MPICH return endif end if end function which_mpi_library !> Test if an MPI wrapper works type ( string_t ) function mpi_wrapper_query ( mpilib , wrapper , command , verbose , error ) result ( screen ) integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: wrapper character ( * ), intent ( in ) :: command logical , intent ( in ), optional :: verbose type ( error_t ), allocatable , intent ( out ) :: error logical :: success character (:), allocatable :: redirect_str , tokens (:), unsupported_msg type ( string_t ) :: cmdstr type ( compiler_t ) :: mpi_compiler integer :: stat , cmdstat , ire , length unsupported_msg = 'the MPI library of wrapper ' // wrapper % s // ' does not support task ' // trim ( command ) select case ( command ) ! Get MPI compiler name case ( 'compiler' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ); cmdstr = string_t ( '--showme:command' ) case ( MPI_TYPE_MPICH ); cmdstr = string_t ( '-compile-info' ) case ( MPI_TYPE_INTEL ); cmdstr = string_t ( '-show' ) case default call fatal_error ( error , unsupported_msg ) return end select call run_mpi_wrapper ( wrapper ,[ cmdstr ], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local ' // MPI_TYPE_NAME ( mpilib ) // & ' library wrapper does not support flag ' // cmdstr % s ) return end if ! Take out the first command from the whole line call split ( screen % s , tokens , delimiters = ' ' ) screen % s = trim ( adjustl ( tokens ( 1 ))) ! Get a list of additional compiler flags case ( 'flags' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ); cmdstr = string_t ( '--showme:compile' ) case ( MPI_TYPE_MPICH ); cmdstr = string_t ( '-compile-info' ) case ( MPI_TYPE_INTEL ); cmdstr = string_t ( '-show' ) case default call fatal_error ( error , unsupported_msg ) return end select call run_mpi_wrapper ( wrapper ,[ cmdstr ], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local ' // MPI_TYPE_NAME ( mpilib ) // & ' library wrapper does not support flag ' // cmdstr % s ) return end if ! Post-process output select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! This library reports the compiler name only call remove_newline_characters ( screen ) case ( MPI_TYPE_MPICH , MPI_TYPE_INTEL ) ! These libraries report the full command including the compiler name. Remove it if so call remove_newline_characters ( screen ) call split ( screen % s , tokens ) ! Remove trailing compiler name screen % s = screen % s ( len_trim ( tokens ( 1 )) + 1 :) case default call fatal_error ( error , 'invalid MPI library type' ) return end select ! Get a list of additional linker flags case ( 'link' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ); cmdstr = string_t ( '--showme:link' ) case ( MPI_TYPE_MPICH ); cmdstr = string_t ( '-link-info' ) case default call fatal_error ( error , unsupported_msg ) return end select call run_mpi_wrapper ( wrapper ,[ cmdstr ], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local ' // MPI_TYPE_NAME ( mpilib ) // & ' library wrapper does not support flag ' // cmdstr % s ) return end if select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) call remove_newline_characters ( screen ) case ( MPI_TYPE_MPICH ) ! MPICH reports the full command including the compiler name. Remove it if so call remove_newline_characters ( screen ) call split ( screen % s , tokens ) ! Remove trailing compiler name screen % s = screen % s ( len_trim ( tokens ( 1 )) + 1 :) case default call fatal_error ( error , unsupported_msg ) return end select ! Get a list of MPI library directories case ( 'link_dirs' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! --showme:command returns the build command of this wrapper call run_mpi_wrapper ( wrapper ,[ string_t ( '--showme:libdirs' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local OpenMPI library does not support --showme:libdirs' ) return end if case default call fatal_error ( error , unsupported_msg ) return end select ! Get a list of include directories for the MPI headers/modules case ( 'incl_dirs' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! --showme:command returns the build command of this wrapper call run_mpi_wrapper ( wrapper ,[ string_t ( '--showme:incdirs' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local OpenMPI library does not support --showme:incdirs' ) return end if case default call fatal_error ( error , unsupported_msg ) return end select call remove_newline_characters ( screen ) ! Retrieve library version case ( 'version' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! --showme:command returns the build command of this wrapper call run_mpi_wrapper ( wrapper ,[ string_t ( '--showme:version' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local OpenMPI library does not support --showme:version' ) return else call remove_newline_characters ( screen ) end if case ( MPI_TYPE_MPICH ) !> MPICH offers command \"mpichversion\" in the same system folder as the MPI wrappers. !> So, attempt to run that first cmdstr = string_t ( 'mpichversion' ) call run_mpi_wrapper ( cmdstr , verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) ! Second option: run mpich wrapper + \"-v\" if ( stat /= 0 . or . . not . success ) then call run_mpi_wrapper ( wrapper ,[ string_t ( '-v' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) call remove_newline_characters ( screen ) endif ! Third option: mpiexec --version if ( stat /= 0 . or . . not . success ) then cmdstr = string_t ( 'mpiexec --version' ) call run_mpi_wrapper ( cmdstr , verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) endif if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'cannot retrieve MPICH library version from ' ) return end if case ( MPI_TYPE_INTEL ) ! --showme:command returns the build command of this wrapper call run_mpi_wrapper ( wrapper ,[ string_t ( '-v' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local INTEL MPI library does not support -v' ) return else call remove_newline_characters ( screen ) end if case default call fatal_error ( error , unsupported_msg ) return end select ! Extract version screen = regex_version_from_text ( screen % s , MPI_TYPE_NAME ( mpilib ) // ' library' , error ) if ( allocated ( error )) return ! Get path to the MPI runner command case ( 'runner' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI , MPI_TYPE_MPICH , MPI_TYPE_MSMPI , MPI_TYPE_INTEL ) call get_mpi_runner ( screen , verbose , error ) case default call fatal_error ( error , unsupported_msg ) return end select case default ; call fatal_error ( error , 'an invalid MPI wrapper command (' // command // & ') was invoked for wrapper <' // wrapper % s // '>.' ) return end select end function mpi_wrapper_query end module fpm_meta","tags":"","loc":"sourcefile/fpm_meta.f90.html"},{"title":"fpm_backend_output.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_backend_output Source Code fpm_backend_output.f90 Source Code !># Build Backend Progress Output !> This module provides a derived type `build_progress_t` for printing build status !> and progress messages to the console while the backend is building the package. !> !> The `build_progress_t` type supports two modes: `normal` and `plain` !> where the former does 'pretty' output and the latter does not. !> The `normal` mode is intended for typical interactive usage whereas !> 'plain' mode is used with the `--verbose` flag or when `stdout` is not attached !> to a terminal (e.g. when piping or redirecting `stdout`). In these cases, !> the pretty output must be suppressed to avoid control codes being output. module fpm_backend_output use iso_fortran_env , only : stdout => output_unit use fpm_filesystem , only : basename use fpm_targets , only : build_target_ptr use fpm_backend_console , only : console_t , LINE_RESET , COLOR_RED , COLOR_GREEN , COLOR_YELLOW , COLOR_RESET implicit none private public build_progress_t !> Build progress object type build_progress_t !> Console object for updating console lines type ( console_t ) :: console !> Number of completed targets integer :: n_complete !> Total number of targets scheduled integer :: n_target !> 'Plain' output (no colors or updating) logical :: plain_mode = . true . !> Store needed when updating previous console lines integer , allocatable :: output_lines (:) !> Queue of scheduled build targets type ( build_target_ptr ), pointer :: target_queue (:) contains !> Output 'compiling' status for build target procedure :: compiling_status => output_status_compiling !> Output 'complete' status for build target procedure :: completed_status => output_status_complete !> Output finished status for whole package procedure :: success => output_progress_success end type build_progress_t !> Constructor for build_progress_t interface build_progress_t procedure :: new_build_progress end interface build_progress_t contains !> Initialise a new build progress object function new_build_progress ( target_queue , plain_mode ) result ( progress ) !> The queue of scheduled targets type ( build_target_ptr ), intent ( in ), target :: target_queue (:) !> Enable 'plain' output for progress object logical , intent ( in ), optional :: plain_mode !> Progress object to initialise type ( build_progress_t ) :: progress progress % n_target = size ( target_queue , 1 ) progress % target_queue => target_queue progress % plain_mode = plain_mode progress % n_complete = 0 allocate ( progress % output_lines ( progress % n_target )) end function new_build_progress !> Output 'compiling' status for build target and overall percentage progress subroutine output_status_compiling ( progress , queue_index ) !> Progress object class ( build_progress_t ), intent ( inout ) :: progress !> Index of build target in the target queue integer , intent ( in ) :: queue_index character (:), allocatable :: target_name character ( 100 ) :: output_string character ( 7 ) :: overall_progress associate ( target => progress % target_queue ( queue_index )% ptr ) if ( allocated ( target % source )) then target_name = basename ( target % source % file_name ) else target_name = basename ( target % output_file ) end if write ( overall_progress , '(A,I3,A)' ) '[' , 100 * progress % n_complete / progress % n_target , '%] ' if ( progress % plain_mode ) then ! Plain output !$omp critical write ( * , '(A7,A30)' ) overall_progress , target_name !$omp end critical else ! Pretty output write ( output_string , '(A,T40,A,A)' ) target_name , COLOR_YELLOW // 'compiling...' // COLOR_RESET call progress % console % write_line ( trim ( output_string ), progress % output_lines ( queue_index )) call progress % console % write_line ( overall_progress // 'Compiling...' , advance = . false .) end if end associate end subroutine output_status_compiling !> Output 'complete' status for build target and update overall percentage progress subroutine output_status_complete ( progress , queue_index , build_stat ) !> Progress object class ( build_progress_t ), intent ( inout ) :: progress !> Index of build target in the target queue integer , intent ( in ) :: queue_index !> Build status flag integer , intent ( in ) :: build_stat character (:), allocatable :: target_name character ( 100 ) :: output_string character ( 7 ) :: overall_progress !$omp critical progress % n_complete = progress % n_complete + 1 !$omp end critical associate ( target => progress % target_queue ( queue_index )% ptr ) if ( allocated ( target % source )) then target_name = basename ( target % source % file_name ) else target_name = basename ( target % output_file ) end if if ( build_stat == 0 ) then write ( output_string , '(A,T40,A,A)' ) target_name , COLOR_GREEN // 'done.' // COLOR_RESET else write ( output_string , '(A,T40,A,A)' ) target_name , COLOR_RED // 'failed.' // COLOR_RESET end if write ( overall_progress , '(A,I3,A)' ) '[' , 100 * progress % n_complete / progress % n_target , '%] ' if ( progress % plain_mode ) then ! Plain output !$omp critical write ( * , '(A7,A30,A7)' ) overall_progress , target_name , 'done.' !$omp end critical else ! Pretty output call progress % console % update_line ( progress % output_lines ( queue_index ), trim ( output_string )) call progress % console % write_line ( overall_progress // 'Compiling...' , advance = . false .) end if end associate end subroutine output_status_complete !> Output finished status for whole package subroutine output_progress_success ( progress ) class ( build_progress_t ), intent ( inout ) :: progress if ( progress % plain_mode ) then ! Plain output write ( * , '(A)' ) '[100%] Project compiled successfully.' else ! Pretty output write ( * , '(A)' ) LINE_RESET // COLOR_GREEN // '[100%] Project compiled successfully.' // COLOR_RESET end if end subroutine output_progress_success end module fpm_backend_output","tags":"","loc":"sourcefile/fpm_backend_output.f90.html"},{"title":"fpm_strings.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_strings Source Code fpm_strings.f90 Source Code !> This module defines general procedures for **string operations** for both CHARACTER and !! TYPE(STRING_T) variables ! !>## general routines for performing __string operations__ !! !!### Types !! - **TYPE(STRING_T)** define a type to contain strings of variable length !!### Type Conversions !! - [[F_STRING]] return Fortran **CHARACTER** variable when given a C-like array of !! single characters terminated with a C_NULL_CHAR **CHARACTER** !! - [[STR]] Converts **INTEGER** or** LOGICAL** to **CHARACTER** string !!### Case !! - [[LOWER]] Changes a string to lowercase over optional specified column range !!### Parsing and joining !! - [[SPLIT]] parse string on delimiter characters and store tokens into an allocatable array !! - [[STRING_CAT]] Concatenate an array of **type(string_t)** into a single **CHARACTER** variable !! - [[JOIN]] append an array of **CHARACTER** variables into a single **CHARACTER** variable !!### Testing !! - [[STR_ENDS_WITH]] test if a **CHARACTER** string or array ends with a specified suffix !! - [[STRING_ARRAY_CONTAINS]] Check if array of **TYPE(STRING_T)** matches a particular **CHARACTER** string !! - **OPERATOR(.IN.)** Check if array of **TYPE(STRING_T)** matches a particular **CHARACTER** string !! - [[GLOB]] function compares text strings, one of which can have wildcards ('*' or '?'). !! - [[IS_FORTRAN_NAME]] determine whether a string is an acceptable Fortran entity name !! - [[TO_FORTRAN_NAME]] replace allowed special but unusuable characters in names with underscore !!### Whitespace !! - [[NOTABS]] subroutine to expand tab characters assuming a tab space every eight characters !! - [[DILATE]] function to expand tab characters assuming a tab space every eight characters !! - [[LEN_TRIM]] Determine total trimmed length of **STRING_T** array !!### Miscellaneous !! - [[FNV_1A]] Hash a **CHARACTER(*)** string of default kind or a **TYPE(STRING_T)** array !! - [[REPLACE]] Returns string with characters in charset replaced with target_char. !! - [[RESIZE]] increase the size of a **TYPE(STRING_T)** array by N elements !! module fpm_strings use iso_fortran_env , only : int64 use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit use iso_c_binding , only : c_char , c_ptr , c_int , c_null_char , c_associated , c_f_pointer , c_size_t implicit none private public :: f_string , lower , split , str_ends_with , string_t , str_begins_with_str public :: to_fortran_name , is_fortran_name public :: string_array_contains , string_cat , len_trim , operator (. in .), fnv_1a public :: replace , resize , str , join , glob public :: notabs , dilate , remove_newline_characters , remove_characters_in_set !> Module naming public :: is_valid_module_name , is_valid_module_prefix , & has_valid_custom_prefix , has_valid_standard_prefix , & module_prefix_template , module_prefix_type type string_t character ( len = :), allocatable :: s end type interface len_trim module procedure :: string_len_trim module procedure :: strings_len_trim end interface len_trim interface resize module procedure :: resize_string end interface interface operator (. in .) module procedure string_array_contains end interface interface fnv_1a procedure :: fnv_1a_char procedure :: fnv_1a_string_t end interface fnv_1a interface str_ends_with procedure :: str_ends_with_str procedure :: str_ends_with_any end interface str_ends_with interface str module procedure str_int , str_int64 , str_logical end interface interface string_t module procedure new_string_t end interface string_t interface f_string module procedure f_string , f_string_cptr , f_string_cptr_n end interface f_string contains !> test if a CHARACTER string ends with a specified suffix pure logical function str_ends_with_str ( s , e ) result ( r ) character ( * ), intent ( in ) :: s , e integer :: n1 , n2 n1 = len ( s ) - len ( e ) + 1 n2 = len ( s ) if ( n1 < 1 ) then r = . false . else r = ( s ( n1 : n2 ) == e ) end if end function str_ends_with_str !> test if a CHARACTER string ends with any of an array of suffixs pure logical function str_ends_with_any ( s , e ) result ( r ) character ( * ), intent ( in ) :: s character ( * ), intent ( in ) :: e (:) integer :: i r = . true . do i = 1 , size ( e ) if ( str_ends_with ( s , trim ( e ( i )))) return end do r = . false . end function str_ends_with_any !> test if a CHARACTER string begins with a specified prefix pure logical function str_begins_with_str ( s , e , case_sensitive ) result ( r ) character ( * ), intent ( in ) :: s , e logical , optional , intent ( in ) :: case_sensitive ! Default option: case sensitive integer :: n1 , n2 logical :: lower_case ! Check if case sensitive if ( present ( case_sensitive )) then lower_case = . not . case_sensitive else lower_case = . false . end if n1 = 1 n2 = 1 + len ( e ) - 1 if ( n2 > len ( s )) then r = . false . elseif ( lower_case ) then r = lower ( s ( n1 : n2 )) == lower ( e ) else r = ( s ( n1 : n2 ) == e ) end if end function str_begins_with_str !> return Fortran character variable when given a C-like array of !! single characters terminated with a C_NULL_CHAR character function f_string ( c_string ) use iso_c_binding character ( len = 1 ), intent ( in ) :: c_string (:) character (:), allocatable :: f_string integer :: i , n i = 0 do while ( c_string ( i + 1 ) /= C_NULL_CHAR ) i = i + 1 end do n = i allocate ( character ( n ) :: f_string ) do i = 1 , n f_string ( i : i ) = c_string ( i ) end do end function f_string !> return Fortran character variable when given a null-terminated c_ptr function f_string_cptr ( cptr ) result ( s ) type ( c_ptr ), intent ( in ), value :: cptr character ( len = :, kind = c_char ), allocatable :: s interface function c_strlen ( s ) result ( r ) bind ( c , name = \"strlen\" ) import c_size_t , c_ptr type ( c_ptr ), intent ( in ), value :: s integer ( kind = c_size_t ) :: r end function end interface s = f_string_cptr_n ( cptr , c_strlen ( cptr )) end function !> return Fortran character variable when given a null-terminated c_ptr and its length function f_string_cptr_n ( cptr , n ) result ( s ) type ( c_ptr ), intent ( in ), value :: cptr integer ( kind = c_size_t ), intent ( in ) :: n character ( len = n , kind = c_char ) :: s character ( len = n , kind = c_char ), pointer :: sptr call c_f_pointer ( cptr , sptr ) s = sptr end function !> Hash a character(*) string of default kind pure function fnv_1a_char ( input , seed ) result ( hash ) character ( * ), intent ( in ) :: input integer ( int64 ), intent ( in ), optional :: seed integer ( int64 ) :: hash integer :: i integer ( int64 ), parameter :: FNV_OFFSET_32 = 2166136261_int64 integer ( int64 ), parameter :: FNV_PRIME_32 = 16777619_int64 if ( present ( seed )) then hash = seed else hash = FNV_OFFSET_32 end if do i = 1 , len ( input ) hash = ieor ( hash , iachar ( input ( i : i ), int64 )) * FNV_PRIME_32 end do end function fnv_1a_char !> Hash a string_t array of default kind pure function fnv_1a_string_t ( input , seed ) result ( hash ) type ( string_t ), intent ( in ) :: input (:) integer ( int64 ), intent ( in ), optional :: seed integer ( int64 ) :: hash integer :: i hash = fnv_1a ( input ( 1 )% s , seed ) do i = 2 , size ( input ) hash = fnv_1a ( input ( i )% s , hash ) end do end function fnv_1a_string_t !>Author: John S. Urban !!License: Public Domain !! Changes a string to lowercase over optional specified column range elemental pure function lower ( str , begin , end ) result ( string ) character ( * ), intent ( In ) :: str character ( len ( str )) :: string integer , intent ( in ), optional :: begin , end integer :: i integer :: ibegin , iend string = str ibegin = 1 if ( present ( begin )) then ibegin = max ( ibegin , begin ) endif iend = len_trim ( str ) if ( present ( end )) then iend = min ( iend , end ) endif do i = ibegin , iend ! step thru each letter in the string in specified range select case ( str ( i : i )) case ( 'A' : 'Z' ) string ( i : i ) = char ( iachar ( str ( i : i )) + 32 ) ! change letter to miniscule case default end select end do end function lower !> Helper function to generate a new string_t instance !> (Required due to the allocatable component) function new_string_t ( s ) result ( string ) character ( * ), intent ( in ) :: s type ( string_t ) :: string string % s = s end function new_string_t !> Check if array of TYPE(STRING_T) matches a particular CHARACTER string !! logical function string_array_contains ( search_string , array ) character ( * ), intent ( in ) :: search_string type ( string_t ), intent ( in ) :: array (:) integer :: i string_array_contains = any ([( array ( i )% s == search_string , & i = 1 , size ( array ))]) end function string_array_contains !> Concatenate an array of type(string_t) into !> a single CHARACTER variable function string_cat ( strings , delim ) result ( cat ) type ( string_t ), intent ( in ) :: strings (:) character ( * ), intent ( in ), optional :: delim character (:), allocatable :: cat integer :: i character (:), allocatable :: delim_str if ( size ( strings ) < 1 ) then cat = '' return end if if ( present ( delim )) then delim_str = delim else delim_str = '' end if cat = strings ( 1 )% s do i = 2 , size ( strings ) cat = cat // delim_str // strings ( i )% s end do end function string_cat !> Determine total trimmed length of `string_t` array pure function strings_len_trim ( strings ) result ( n ) type ( string_t ), intent ( in ) :: strings (:) integer :: i , n n = 0 do i = 1 , size ( strings ) n = n + len_trim ( strings ( i )% s ) end do end function strings_len_trim !> Determine total trimmed length of `string_t` array elemental integer function string_len_trim ( string ) result ( n ) type ( string_t ), intent ( in ) :: string if ( allocated ( string % s )) then n = len_trim ( string % s ) else n = 0 end if end function string_len_trim !>Author: John S. Urban !!License: Public Domain !! parse string on delimiter characters and store tokens into an allocatable array subroutine split ( input_line , array , delimiters , order , nulls ) !! given a line of structure \" par1 par2 par3 ... parn \" store each par(n) into a separate variable in array. !! !! * by default adjacent delimiters in the input string do not create an empty string in the output array !! * no quoting of delimiters is supported character ( len =* ), intent ( in ) :: input_line !! input string to tokenize character ( len =* ), optional , intent ( in ) :: delimiters !! list of delimiter characters character ( len =* ), optional , intent ( in ) :: order !! order of output array sequential|[reverse|right] character ( len =* ), optional , intent ( in ) :: nulls !! return strings composed of delimiters or not ignore|return|ignoreend character ( len = :), allocatable , intent ( out ) :: array (:) !! output array of tokens integer :: n ! max number of strings INPUT_LINE could split into if all delimiter integer , allocatable :: ibegin (:) ! positions in input string where tokens start integer , allocatable :: iterm (:) ! positions in input string where tokens end character ( len = :), allocatable :: dlim ! string containing delimiter characters character ( len = :), allocatable :: ordr ! string containing order keyword character ( len = :), allocatable :: nlls ! string containing nulls keyword integer :: ii , iiii ! loop parameters used to control print order integer :: icount ! number of tokens found integer :: ilen ! length of input string with trailing spaces trimmed integer :: i10 , i20 , i30 ! loop counters integer :: icol ! pointer into input string as it is being parsed integer :: idlim ! number of delimiter characters integer :: ifound ! where next delimiter character is found in remaining input string data integer :: inotnull ! count strings not composed of delimiters integer :: ireturn ! number of tokens returned integer :: imax ! length of longest token ! decide on value for optional DELIMITERS parameter if ( present ( delimiters )) then ! optional delimiter list was present if ( delimiters /= '' ) then ! if DELIMITERS was specified and not null use it dlim = delimiters else ! DELIMITERS was specified on call as empty string dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif else ! no delimiter value was specified dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif idlim = len ( dlim ) ! dlim a lot of blanks on some machines if dlim is a big string if ( present ( order )) then ; ordr = lower ( adjustl ( order )); else ; ordr = 'sequential' ; endif ! decide on value for optional ORDER parameter if ( present ( nulls )) then ; nlls = lower ( adjustl ( nulls )); else ; nlls = 'ignore' ; endif ! optional parameter n = len ( input_line ) + 1 ! max number of strings INPUT_LINE could split into if all delimiter allocate ( ibegin ( n )) ! allocate enough space to hold starting location of tokens if string all tokens allocate ( iterm ( n )) ! allocate enough space to hold ending location of tokens if string all tokens ibegin (:) = 1 iterm (:) = 1 ilen = len ( input_line ) ! ILEN is the column position of the last non-blank character icount = 0 ! how many tokens found inotnull = 0 ! how many tokens found not composed of delimiters imax = 0 ! length of longest token found select case ( ilen ) case ( 0 ) ! command was totally blank case default ! there is at least one non-delimiter in INPUT_LINE if get here icol = 1 ! initialize pointer into input line INFINITE : do i30 = 1 , ilen , 1 ! store into each array element ibegin ( i30 ) = icol ! assume start new token on the character if ( index ( dlim ( 1 : idlim ), input_line ( icol : icol )) == 0 ) then ! if current character is not a delimiter iterm ( i30 ) = ilen ! initially assume no more tokens do i10 = 1 , idlim ! search for next delimiter ifound = index ( input_line ( ibegin ( i30 ): ilen ), dlim ( i10 : i10 )) IF ( ifound > 0 ) then iterm ( i30 ) = min ( iterm ( i30 ), ifound + ibegin ( i30 ) - 2 ) endif enddo icol = iterm ( i30 ) + 2 ! next place to look as found end of this token inotnull = inotnull + 1 ! increment count of number of tokens not composed of delimiters else ! character is a delimiter for a null string iterm ( i30 ) = icol - 1 ! record assumed end of string. Will be less than beginning icol = icol + 1 ! advance pointer into input string endif imax = max ( imax , iterm ( i30 ) - ibegin ( i30 ) + 1 ) icount = i30 ! increment count of number of tokens found if ( icol > ilen ) then ! no text left exit INFINITE endif enddo INFINITE end select select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) ireturn = inotnull case default ireturn = icount end select allocate ( character ( len = imax ) :: array ( ireturn )) ! allocate the array to return !allocate(array(ireturn)) ! allocate the array to turn select case ( trim ( adjustl ( ordr ))) ! decide which order to store tokens case ( 'reverse' , 'right' ) ; ii = ireturn ; iiii =- 1 ! last to first case default ; ii = 1 ; iiii = 1 ! first to last end select do i20 = 1 , icount ! fill the array with the tokens that were found if ( iterm ( i20 ) < ibegin ( i20 )) then select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) case default array ( ii ) = ' ' ii = ii + iiii end select else array ( ii ) = input_line ( ibegin ( i20 ): iterm ( i20 )) ii = ii + iiii endif enddo end subroutine split !> Returns string with characters in charset replaced with target_char. pure function replace ( string , charset , target_char ) result ( res ) character ( * ), intent ( in ) :: string character , intent ( in ) :: charset (:), target_char character ( len ( string )) :: res integer :: n res = string do n = 1 , len ( string ) if ( any ( string ( n : n ) == charset )) then res ( n : n ) = target_char end if end do end function replace !> increase the size of a TYPE(STRING_T) array by N elements subroutine resize_string ( list , n ) !> Instance of the array to be resized type ( string_t ), allocatable , intent ( inout ) :: list (:) !> Dimension of the final array size integer , intent ( in ), optional :: n type ( string_t ), allocatable :: tmp (:) integer :: this_size , new_size , i integer , parameter :: initial_size = 16 if ( allocated ( list )) then this_size = size ( list , 1 ) call move_alloc ( list , tmp ) else this_size = initial_size end if if ( present ( n )) then new_size = n else new_size = this_size + this_size / 2 + 1 end if allocate ( list ( new_size )) if ( allocated ( tmp )) then this_size = min ( size ( tmp , 1 ), size ( list , 1 )) do i = 1 , this_size call move_alloc ( tmp ( i )% s , list ( i )% s ) end do deallocate ( tmp ) end if end subroutine resize_string !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!##NAME !! join(3f) - [M_strings:EDITING] append CHARACTER variable array into !! a single CHARACTER variable with specified separator !! (LICENSE:PD) !! !!##SYNOPSIS !! !! pure function join(str,sep,trm,left,right,start,end) result (string) !! !! character(len=*),intent(in) :: str(:) !! character(len=*),intent(in),optional :: sep !! logical,intent(in),optional :: trm !! character(len=*),intent(in),optional :: right !! character(len=*),intent(in),optional :: left !! character(len=*),intent(in),optional :: start !! character(len=*),intent(in),optional :: end !! character(len=:),allocatable :: string !! !!##DESCRIPTION !! JOIN(3f) appends the elements of a CHARACTER array into a single !! CHARACTER variable, with elements 1 to N joined from left to right. !! By default each element is trimmed of trailing spaces and the !! default separator is a null string. !! !!##OPTIONS !! STR(:) array of CHARACTER variables to be joined !! SEP separator string to place between each variable. defaults !! to a null string. !! LEFT string to place at left of each element !! RIGHT string to place at right of each element !! START prefix string !! END suffix string !! TRM option to trim each element of STR of trailing !! spaces. Defaults to .TRUE. !! !!##RESULT !! STRING CHARACTER variable composed of all of the elements of STR() !! appended together with the optional separator SEP placed !! between the elements. !! !!##EXAMPLE !! !! Sample program: !! !! program demo_join !! use M_strings, only: join !! implicit none !! character(len=:),allocatable :: s(:) !! character(len=:),allocatable :: out !! integer :: i !! s=[character(len=10) :: 'United',' we',' stand,', & !! & ' divided',' we fall.'] !! out=join(s) !! write(*,'(a)') out !! write(*,'(a)') join(s,trm=.false.) !! write(*,'(a)') (join(s,trm=.false.,sep='|'),i=1,3) !! write(*,'(a)') join(s,sep='<>') !! write(*,'(a)') join(s,sep=';',left='[',right=']') !! write(*,'(a)') join(s,left='[',right=']') !! write(*,'(a)') join(s,left='>>') !! end program demo_join !! !! Expected output: !! !! United we stand, divided we fall. !! United we stand, divided we fall. !! United | we | stand, | divided | we fall. !! United | we | stand, | divided | we fall. !! United | we | stand, | divided | we fall. !! United<> we<> stand,<> divided<> we fall. !! [United];[ we];[ stand,];[ divided];[ we fall.] !! [United][ we][ stand,][ divided][ we fall.] !! >>United>> we>> stand,>> divided>> we fall. pure function join ( str , sep , trm , left , right , start , end ) result ( string ) ! @(#)M_strings::join(3f): merge string array into a single CHARACTER value adding specified separators, caps, prefix and suffix character ( len =* ), intent ( in ) :: str (:) character ( len =* ), intent ( in ), optional :: sep , right , left , start , end logical , intent ( in ), optional :: trm character ( len = :), allocatable :: sep_local , left_local , right_local character ( len = :), allocatable :: string logical :: trm_local integer :: i if ( present ( sep )) then ; sep_local = sep ; else ; sep_local = '' ; endif if ( present ( trm )) then ; trm_local = trm ; else ; trm_local = . true . ; endif if ( present ( left )) then ; left_local = left ; else ; left_local = '' ; endif if ( present ( right )) then ; right_local = right ; else ; right_local = '' ; endif string = '' if ( size ( str ) == 0 ) then string = string // left_local // right_local else do i = 1 , size ( str ) - 1 if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local // sep_local else string = string // left_local // str ( i ) // right_local // sep_local endif enddo if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local else string = string // left_local // str ( i ) // right_local endif endif if ( present ( start )) string = start // string if ( present ( end )) string = string // end end function join !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!## NAME !! glob(3f) - [fpm_strings:COMPARE] compare given string for match to !! pattern which may contain wildcard characters !! (LICENSE:PD) !! !!## SYNOPSIS !! !! logical function glob(string, pattern ) !! !! character(len=*),intent(in) :: string !! character(len=*),intent(in) :: pattern !! !!## DESCRIPTION !! glob(3f) compares given STRING for match to PATTERN which may !! contain wildcard characters. !! !! In this version to get a match the entire string must be described !! by PATTERN. Trailing whitespace is significant, so trim the input !! string to have trailing whitespace ignored. !! !!## OPTIONS !! string the input string to test to see if it contains the pattern. !! pattern the following simple globbing options are available !! !! o \"?\" matching any one character !! o \"*\" matching zero or more characters. !! Do NOT use adjacent asterisks. !! o Both strings may have trailing spaces which !! are ignored. !! o There is no escape character, so matching strings with !! literal question mark and asterisk is problematic. !! !!## EXAMPLES !! !! Example program !! !! program demo_glob !! implicit none !! ! This main() routine passes a bunch of test strings !! ! into the above code. In performance comparison mode, !! ! it does that over and over. Otherwise, it does it just !! ! once. Either way, it outputs a passed/failed result. !! ! !! integer :: nReps !! logical :: allpassed !! integer :: i !! allpassed = .true. !! !! nReps = 10000 !! ! Can choose as many repetitions as you're expecting !! ! in the real world. !! nReps = 1 !! !! do i=1,nReps !! ! Cases with repeating character sequences. !! allpassed=allpassed .and. test(\"a*abab\", \"a*b\", .true.) !! !!cycle !! allpassed=allpassed .and. test(\"ab\", \"*?\", .true.) !! allpassed=allpassed .and. test(\"abc\", \"*?\", .true.) !! allpassed=allpassed .and. test(\"abcccd\", \"*ccd\", .true.) !! allpassed=allpassed .and. test(\"bLah\", \"bLaH\", .false.) !! allpassed=allpassed .and. test(\"mississippi\", \"*sip*\", .true.) !! allpassed=allpassed .and. & !! & test(\"xxxx*zzzzzzzzy*f\", \"xxx*zzy*f\", .true.) !! allpassed=allpassed .and. & !! & test(\"xxxx*zzzzzzzzy*f\", \"xxxx*zzy*fffff\", .false.) !! allpassed=allpassed .and. & !! & test(\"mississipissippi\", \"*issip*ss*\", .true.) !! allpassed=allpassed .and. & !! & test(\"xxxxzzzzzzzzyf\", \"xxxx*zzy*fffff\", .false.) !! allpassed=allpassed .and. & !! & test(\"xxxxzzzzzzzzyf\", \"xxxx*zzy*f\", .true.) !! allpassed=allpassed .and. test(\"xyxyxyzyxyz\", \"xy*z*xyz\", .true.) !! allpassed=allpassed .and. test(\"xyxyxyxyz\", \"xy*xyz\", .true.) !! allpassed=allpassed .and. test(\"mississippi\", \"mi*sip*\", .true.) !! allpassed=allpassed .and. test(\"ababac\", \"*abac*\", .true.) !! allpassed=allpassed .and. test(\"aaazz\", \"a*zz*\", .true.) !! allpassed=allpassed .and. test(\"a12b12\", \"*12*23\", .false.) !! allpassed=allpassed .and. test(\"a12b12\", \"a12b\", .false.) !! allpassed=allpassed .and. test(\"a12b12\", \"*12*12*\", .true.) !! !! ! Additional cases where the '*' char appears in the tame string. !! allpassed=allpassed .and. test(\"*\", \"*\", .true.) !! allpassed=allpassed .and. test(\"a*r\", \"a*\", .true.) !! allpassed=allpassed .and. test(\"a*ar\", \"a*aar\", .false.) !! !! ! More double wildcard scenarios. !! allpassed=allpassed .and. test(\"XYXYXYZYXYz\", \"XY*Z*XYz\", .true.) !! allpassed=allpassed .and. test(\"missisSIPpi\", \"*SIP*\", .true.) !! allpassed=allpassed .and. test(\"mississipPI\", \"*issip*PI\", .true.) !! allpassed=allpassed .and. test(\"xyxyxyxyz\", \"xy*xyz\", .true.) !! allpassed=allpassed .and. test(\"miSsissippi\", \"mi*sip*\", .true.) !! allpassed=allpassed .and. test(\"miSsissippi\", \"mi*Sip*\", .false.) !! allpassed=allpassed .and. test(\"abAbac\", \"*Abac*\", .true.) !! allpassed=allpassed .and. test(\"aAazz\", \"a*zz*\", .true.) !! allpassed=allpassed .and. test(\"A12b12\", \"*12*23\", .false.) !! allpassed=allpassed .and. test(\"a12B12\", \"*12*12*\", .true.) !! allpassed=allpassed .and. test(\"oWn\", \"*oWn*\", .true.) !! !! ! Completely tame (no wildcards) cases. !! allpassed=allpassed .and. test(\"bLah\", \"bLah\", .true.) !! !! ! Simple mixed wildcard tests suggested by IBMer Marlin Deckert. !! allpassed=allpassed .and. test(\"a\", \"*?\", .true.) !! !! ! More mixed wildcard tests including coverage for false positives. !! allpassed=allpassed .and. test(\"a\", \"??\", .false.) !! allpassed=allpassed .and. test(\"ab\", \"?*?\", .true.) !! allpassed=allpassed .and. test(\"ab\", \"*?*?*\", .true.) !! allpassed=allpassed .and. test(\"abc\", \"?**?*?\", .true.) !! allpassed=allpassed .and. test(\"abc\", \"?**?*&?\", .false.) !! allpassed=allpassed .and. test(\"abcd\", \"?b*??\", .true.) !! allpassed=allpassed .and. test(\"abcd\", \"?a*??\", .false.) !! allpassed=allpassed .and. test(\"abcd\", \"?**?c?\", .true.) !! allpassed=allpassed .and. test(\"abcd\", \"?**?d?\", .false.) !! allpassed=allpassed .and. test(\"abcde\", \"?*b*?*d*?\", .true.) !! !! ! Single-character-match cases. !! allpassed=allpassed .and. test(\"bLah\", \"bL?h\", .true.) !! allpassed=allpassed .and. test(\"bLaaa\", \"bLa?\", .false.) !! allpassed=allpassed .and. test(\"bLah\", \"bLa?\", .true.) !! allpassed=allpassed .and. test(\"bLaH\", \"?Lah\", .false.) !! allpassed=allpassed .and. test(\"bLaH\", \"?LaH\", .true.) !! !! ! Many-wildcard scenarios. !! allpassed=allpassed .and. test(& !! &\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa& !! &aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab\",& !! &\"a*a*a*a*a*a*aa*aaa*a*a*b\",& !! &.true.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacacac& !! &adaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*a*aa*aaa*fa*ga*b*\",& !! &.true.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacaca& !! &cadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*a*x*aaa*fa*ga*b*\",& !! &.false.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacacacad& !! &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*aaaa*fa*ga*gggg*b*\",& !! &.false.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacacacad& !! &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*aaaa*fa*ga*ggg*b*\",& !! &.true.) !! allpassed=allpassed .and. test(\"aaabbaabbaab\", \"*aabbaa*a*\", .true.) !! allpassed=allpassed .and. & !! test(\"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\",& !! &\"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\", .true.) !! allpassed=allpassed .and. test(\"aaaaaaaaaaaaaaaaa\",& !! &\"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\", .true.) !! allpassed=allpassed .and. test(\"aaaaaaaaaaaaaaaa\",& !! &\"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\", .false.) !! allpassed=allpassed .and. test(& !! &\"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& !! &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn\",& !! & \"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc& !! &*abc*abc*abc*\",& !! &.false.) !! allpassed=allpassed .and. test(& !! &\"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& !! &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn\",& !! &\"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*\",& !! &.true.) !! allpassed=allpassed .and. test(\"abc*abcd*abcd*abc*abcd\",& !! &\"abc*abc*abc*abc*abc\", .false.) !! allpassed=allpassed .and. test( \"abc*abcd*abcd*abc*abcd*abcd& !! &*abc*abcd*abc*abc*abcd\", & !! &\"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd\",& !! &.true.) !! allpassed=allpassed .and. test(\"abc\",& !! &\"********a********b********c********\", .true.) !! allpassed=allpassed .and.& !! &test(\"********a********b********c********\", \"abc\", .false.) !! allpassed=allpassed .and. & !! &test(\"abc\", \"********a********b********b********\", .false.) !! allpassed=allpassed .and. test(\"*abc*\", \"***a*b*c***\", .true.) !! !! ! A case-insensitive algorithm test. !! ! allpassed=allpassed .and. test(\"mississippi\", \"*issip*PI\", .true.) !! enddo !! !! if (allpassed)then !! write(*,'(a)')\"Passed\",nReps !! else !! write(*,'(a)')\"Failed\" !! endif !! contains !! ! This is a test program for wildcard matching routines. !! ! It can be used either to test a single routine for correctness, !! ! or to compare the timings of two (or more) different wildcard !! ! matching routines. !! ! !! function test(tame, wild, bExpectedResult) result(bpassed) !! use fpm_strings, only : glob !! character(len=*) :: tame !! character(len=*) :: wild !! logical :: bExpectedResult !! logical :: bResult !! logical :: bPassed !! bResult = .true. ! We'll do \"&=\" cumulative checking. !! bPassed = .false. ! Assume the worst. !! write(*,*)repeat('=',79) !! bResult = glob(tame, wild) ! Call a wildcard matching routine. !! !! ! To assist correctness checking, output the two strings in any !! ! failing scenarios. !! if (bExpectedResult .eqv. bResult) then !! bPassed = .true. !! if(nReps == 1) write(*,*)\"Passed match on \",tame,\" vs. \", wild !! else !! if(nReps == 1) write(*,*)\"Failed match on \",tame,\" vs. \", wild !! endif !! !! end function test !! end program demo_glob !! !! Expected output !! !! !!## REFERENCE !! The article \"Matching Wildcards: An Empirical Way to Tame an Algorithm\" !! in Dr Dobb's Journal, By Kirk J. Krauss, October 07, 2014 !! function glob ( tame , wild ) ! @(#)fpm_strings::glob(3f): function compares text strings, one of which can have wildcards ('*' or '?'). logical :: glob !! result of test character ( len =* ) :: tame !! A string without wildcards to compare to the globbing expression character ( len =* ) :: wild !! A (potentially) corresponding string with wildcards character ( len = len ( tame ) + 1 ) :: tametext character ( len = len ( wild ) + 1 ) :: wildtext character ( len = 1 ), parameter :: NULL = char ( 0 ) integer :: wlen integer :: ti , wi integer :: i character ( len = :), allocatable :: tbookmark , wbookmark ! These two values are set when we observe a wildcard character. They ! represent the locations, in the two strings, from which we start once we've observed it. tametext = tame // NULL wildtext = wild // NULL tbookmark = NULL wbookmark = NULL wlen = len ( wild ) wi = 1 ti = 1 do ! Walk the text strings one character at a time. if ( wildtext ( wi : wi ) == '*' ) then ! How do you match a unique text string? do i = wi , wlen ! Easy: unique up on it! if ( wildtext ( wi : wi ) == '*' ) then wi = wi + 1 else exit endif enddo if ( wildtext ( wi : wi ) == NULL ) then ! \"x\" matches \"*\" glob = . true . return endif if ( wildtext ( wi : wi ) /= '?' ) then ! Fast-forward to next possible match. do while ( tametext ( ti : ti ) /= wildtext ( wi : wi )) ti = ti + 1 if ( tametext ( ti : ti ) == NULL ) then glob = . false . return ! \"x\" doesn't match \"*y*\" endif enddo endif wbookmark = wildtext ( wi :) tbookmark = tametext ( ti :) elseif ( tametext ( ti : ti ) /= wildtext ( wi : wi ) . and . wildtext ( wi : wi ) /= '?' ) then ! Got a non-match. If we've set our bookmarks, back up to one or both of them and retry. if ( wbookmark /= NULL ) then if ( wildtext ( wi :) /= wbookmark ) then wildtext = wbookmark ; wlen = len_trim ( wbookmark ) wi = 1 ! Don't go this far back again. if ( tametext ( ti : ti ) /= wildtext ( wi : wi )) then tbookmark = tbookmark ( 2 :) tametext = tbookmark ti = 1 cycle ! \"xy\" matches \"*y\" else wi = wi + 1 endif endif if ( tametext ( ti : ti ) /= NULL ) then ti = ti + 1 cycle ! \"mississippi\" matches \"*sip*\" endif endif glob = . false . return ! \"xy\" doesn't match \"x\" endif ti = ti + 1 wi = wi + 1 if ( tametext ( ti : ti ) == NULL ) then ! How do you match a tame text string? if ( wildtext ( wi : wi ) /= NULL ) then do while ( wildtext ( wi : wi ) == '*' ) ! The tame way: unique up on it! wi = wi + 1 ! \"x\" matches \"x*\" if ( wildtext ( wi : wi ) == NULL ) exit enddo endif if ( wildtext ( wi : wi ) == NULL ) then glob = . true . return ! \"x\" matches \"x\" endif glob = . false . return ! \"x\" doesn't match \"xy\" endif enddo end function glob !> Returns the length of the string representation of 'i' pure integer function str_int_len ( i ) result ( sz ) integer , intent ( in ) :: i integer , parameter :: MAX_STR = 100 character ( MAX_STR ) :: s ! If 's' is too short (MAX_STR too small), Fortran will abort with: ! \"Fortran runtime error: End of record\" write ( s , '(i0)' ) i sz = len_trim ( s ) end function !> Converts integer \"i\" to string pure function str_int ( i ) result ( s ) integer , intent ( in ) :: i character ( len = str_int_len ( i )) :: s write ( s , '(i0)' ) i end function !> Returns the length of the string representation of 'i' pure integer function str_int64_len ( i ) result ( sz ) integer ( int64 ), intent ( in ) :: i integer , parameter :: MAX_STR = 100 character ( MAX_STR ) :: s ! If 's' is too short (MAX_STR too small), Fortran will abort with: ! \"Fortran runtime error: End of record\" write ( s , '(i0)' ) i sz = len_trim ( s ) end function !> Converts integer \"i\" to string pure function str_int64 ( i ) result ( s ) integer ( int64 ), intent ( in ) :: i character ( len = str_int64_len ( i )) :: s write ( s , '(i0)' ) i end function !> Returns the length of the string representation of 'l' pure integer function str_logical_len ( l ) result ( sz ) logical , intent ( in ) :: l if ( l ) then sz = 6 else sz = 7 end if end function !> Converts logical \"l\" to string pure function str_logical ( l ) result ( s ) logical , intent ( in ) :: l character ( len = str_logical_len ( l )) :: s if ( l ) then s = \".true.\" else s = \".false.\" end if end function !> Returns string with special characters replaced with an underscore. !! For now, only a hyphen is treated as a special character, but this can be !! expanded to other characters if needed. pure function to_fortran_name ( string ) result ( res ) character ( * ), intent ( in ) :: string character ( len ( string )) :: res character , parameter :: SPECIAL_CHARACTERS ( * ) = [ '-' ] res = replace ( string , SPECIAL_CHARACTERS , '_' ) end function to_fortran_name elemental 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 ) /= 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 !> Check that a module name fits the current naming rules: !> 1) It must be a valid FORTRAN name (<=63 chars, begin with letter, \"_\" is only allowed non-alphanumeric) !> 2) It must begin with the package name !> 3) If longer, package name must be followed by default separator plus at least one char logical function is_valid_module_name ( module_name , package_name , custom_prefix , enforce_module_names ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name type ( string_t ), intent ( in ) :: custom_prefix logical , intent ( in ) :: enforce_module_names !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ); if (. not . valid ) return !> FPM package enforcing: check that the module name begins with the package name if ( enforce_module_names ) then ! Default prefixing is always valid valid = has_valid_standard_prefix ( module_name , package_name ) ! If a custom prefix was validated, it provides additional naming options ! Because they never overlap with the default prefix, the former is always an option if ( len_trim ( custom_prefix ) > 0 . and . . not . valid ) & valid = has_valid_custom_prefix ( module_name , custom_prefix ) end if end function is_valid_module_name !> Check that a custom module prefix fits the current naming rules: !> 1) Only alphanumeric characters (no spaces, dashes, underscores or other characters) !> 2) Does not begin with a number (Fortran-compatible syntax) logical function is_valid_module_prefix ( module_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_prefix character ( len =* ), parameter :: num = '0123456789' character ( len =* ), parameter :: lower = 'abcdefghijklmnopqrstuvwxyz' character ( len =* ), parameter :: upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' character ( len =* ), parameter :: alpha = upper // lower character ( len =* ), parameter :: allowed = alpha // num character ( len = :), allocatable :: name name = trim ( module_prefix % s ) if ( len ( name ) > 0 . and . len ( name ) <= 63 ) then valid = verify ( name ( 1 : 1 ), alpha ) == 0 . and . & verify ( name , allowed ) == 0 else valid = . false . endif end function is_valid_module_prefix type ( string_t ) function module_prefix_template ( project_name , custom_prefix ) result ( prefix ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then prefix = string_t ( trim ( custom_prefix % s ) // \"_\" ) else prefix = string_t ( to_fortran_name ( project_name % s ) // \"__\" ) end if end function module_prefix_template type ( string_t ) function module_prefix_type ( project_name , custom_prefix ) result ( ptype ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then ptype = string_t ( \"custom\" ) else ptype = string_t ( \"default\" ) end if end function module_prefix_type !> Check that a module name is prefixed with a custom prefix: !> 1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed) !> 2) It must begin with the prefix !> 3) If longer, package name must be followed by default separator (\"_\") plus at least one char logical function has_valid_custom_prefix ( module_name , custom_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: custom_prefix !> custom_module separator: single underscore character ( * ), parameter :: SEP = \"_\" logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check that both names are individually valid valid = is_fortran_name ( module_name % s ) . and . & is_valid_module_prefix ( custom_prefix ) !> FPM package enforcing: check that the module name begins with the custom prefix if ( valid ) then !> Query string lengths lpkg = len_trim ( custom_prefix ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , custom_prefix % s , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator )) end if end function has_valid_custom_prefix !> Check that a module name is prefixed with the default package prefix: !> 1) It must be a valid FORTRAN name (<=63 chars, begin with letter, \"_\" is only allowed non-alphanumeric) !> 2) It must begin with the package name !> 3) If longer, package name must be followed by default separator plus at least one char logical function has_valid_standard_prefix ( module_name , package_name ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name !> Default package__module separator: two underscores character ( * ), parameter :: SEP = \"__\" character ( len = :), allocatable :: fortranized_pkg logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ) !> FPM package enforcing: check that the module name begins with the package name if ( valid ) then fortranized_pkg = to_fortran_name ( package_name % s ) !> Query string lengths lpkg = len_trim ( fortranized_pkg ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , fortranized_pkg , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = is_fortran_name ( fortranized_pkg ) . and . & fortranized_pkg ( lpkg : lpkg ) /= '_' . and . & ( same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator ))) end if end function has_valid_standard_prefix ! Remove all characters from a set from a string subroutine remove_characters_in_set ( string , set , replace_with ) character ( len = :), allocatable , intent ( inout ) :: string character ( * ), intent ( in ) :: set character , optional , intent ( in ) :: replace_with ! Replace with this character instead of removing integer :: feed , length if (. not . allocated ( string )) return if ( len ( set ) <= 0 ) return length = len ( string ) feed = scan ( string , set ) do while ( length > 0 . and . feed > 0 ) ! Remove heading if ( length == 1 ) then string = \"\" elseif ( feed == 1 ) then string = string ( 2 : length ) ! Remove trailing elseif ( feed == length ) then string = string ( 1 : length - 1 ) ! In between: replace with given character elseif ( present ( replace_with )) then string ( feed : feed ) = replace_with ! Or just remove else string = string ( 1 : feed - 1 ) // string ( feed + 1 : length ) end if length = len ( string ) feed = scan ( string , set ) end do end subroutine remove_characters_in_set ! Remove all new line characters from the current string, replace them with spaces subroutine remove_newline_characters ( string ) type ( string_t ), intent ( inout ) :: string integer :: feed , length character ( * ), parameter :: CRLF = new_line ( 'a' ) // achar ( 13 ) character ( * ), parameter :: SPACE = ' ' call remove_characters_in_set ( string % s , set = CRLF , replace_with = SPACE ) end subroutine remove_newline_characters !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!### NAME !! notabs(3f) - [fpm_strings:NONALPHA] expand tab characters !! (LICENSE:PD) !! !!### SYNOPSIS !! !! subroutine notabs(INSTR,OUTSTR,ILEN) !! !! character(len=*),intent=(in) :: INSTR !! character(len=*),intent=(out) :: OUTSTR !! integer,intent=(out) :: ILEN !! !!### DESCRIPTION !! NOTABS() converts tabs in INSTR to spaces in OUTSTR while maintaining !! columns. It assumes a tab is set every 8 characters. Trailing spaces !! are removed. !! !! In addition, trailing carriage returns and line feeds are removed !! (they are usually a problem created by going to and from MSWindows). !! !! What are some reasons for removing tab characters from an input line? !! Some Fortran compilers have problems with tabs, as tabs are not !! part of the Fortran character set. Some editors and printers will !! have problems with tabs. It is often useful to expand tabs in input !! files to simplify further processing such as tokenizing an input line. !! !!### OPTIONS !! instr Input line to remove tabs from !! !!### RESULTS !! outstr Output string with tabs expanded. Assumed to be of sufficient !! length !! ilen Significant length of returned string !! !!### EXAMPLES !! !! Sample program: !! !! program demo_notabs !! !! ! test filter to remove tabs and trailing white space from input !! ! on files up to 1024 characters wide !! use fpm_strings, only : notabs !! character(len=1024) :: in,out !! integer :: ios,iout !! do !! read(*,'(A)',iostat=ios)in !! if(ios /= 0) exit !! call notabs(in,out,iout) !! write(*,'(a)')out(:iout) !! enddo !! end program demo_notabs !! !!### SEE ALSO !! GNU/Unix commands expand(1) and unexpand(1) !! elemental impure subroutine notabs ( instr , outstr , ilen ) ! ident_31=\"@(#)fpm_strings::notabs(3f): convert tabs to spaces while maintaining columns, remove CRLF chars\" character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len =* ), intent ( out ) :: outstr ! tab-expanded version of INSTR produced integer , intent ( out ) :: ilen ! column position of last character put into output string ! that is, ILEN holds the position of the last non-blank character in OUTSTR integer , parameter :: tabsize = 8 ! assume a tab stop is set every 8th column integer :: ipos ! position in OUTSTR to put next character of INSTR integer :: lenin ! length of input string trimmed of trailing spaces integer :: lenout ! number of characters output string can hold integer :: istep ! counter that advances thru input string INSTR one character at a time character ( len = 1 ) :: c ! character in input line being processed integer :: iade ! ADE (ASCII Decimal Equivalent) of character being tested ipos = 1 ! where to put next character in output string OUTSTR lenin = len_trim ( instr ( 1 : len ( instr ) )) ! length of INSTR trimmed of trailing spaces lenout = len ( outstr ) ! number of characters output string OUTSTR can hold outstr = \" \" ! this SHOULD blank-fill string, a buggy machine required a loop to set all characters SCAN_LINE : do istep = 1 , lenin ! look through input string one character at a time c = instr ( istep : istep ) ! get next character iade = ichar ( c ) ! get ADE of the character EXPAND_TABS : select case ( iade ) ! take different actions depending on which character was found case ( 9 ) ! test if character is a tab and move pointer out to appropriate column ipos = ipos + ( tabsize - ( mod ( ipos - 1 , tabsize ))) case ( 10 , 13 ) ! convert carriage-return and new-line to space ,typically to handle DOS-format files ipos = ipos + 1 case default ! c is anything else other than a tab,newline,or return insert it in output string if ( ipos > lenout ) then write ( stderr , * ) \"*notabs* output string overflow\" exit else outstr ( ipos : ipos ) = c ipos = ipos + 1 endif end select EXPAND_TABS enddo SCAN_LINE ipos = min ( ipos , lenout ) ! tabs or newline or return characters or last character might have gone too far ilen = len_trim ( outstr (: ipos )) ! trim trailing spaces end subroutine notabs !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!##NAME !! dilate(3f) - [M_strings:NONALPHA] expand tab characters !! (LICENSE:PD) !! !!##SYNOPSIS !! !! function dilate(INSTR) result(OUTSTR) !! !! character(len=*),intent=(in) :: INSTR !! character(len=:),allocatable :: OUTSTR !! !!##DESCRIPTION !! dilate() converts tabs in INSTR to spaces in OUTSTR. It assumes a !! tab is set every 8 characters. Trailing spaces are removed. !! !! In addition, trailing carriage returns and line feeds are removed !! (they are usually a problem created by going to and from MSWindows). !! !!##OPTIONS !! instr Input line to remove tabs from !! !!##RESULTS !! outstr Output string with tabs expanded. !! !!##EXAMPLES !! !! Sample program: !! !! program demo_dilate !! !! use M_strings, only : dilate !! implicit none !! character(len=:),allocatable :: in !! integer :: i !! in=' this is my string ' !! ! change spaces to tabs to make a sample input !! do i=1,len(in) !! if(in(i:i) == ' ')in(i:i)=char(9) !! enddo !! write(*,'(a)')in,dilate(in) !! end program demo_dilate !! function dilate ( instr ) result ( outstr ) character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len = :), allocatable :: outstr ! tab-expanded version of INSTR produced integer :: i integer :: icount integer :: lgth icount = 0 do i = 1 , len ( instr ) if ( instr ( i : i ) == char ( 9 )) icount = icount + 1 end do allocate ( character ( len = ( len ( instr ) + 8 * icount )) :: outstr ) call notabs ( instr , outstr , lgth ) outstr = outstr (: lgth ) end function dilate end module fpm_strings","tags":"","loc":"sourcefile/fpm_strings.f90.html"},{"title":"fpm_filesystem.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_filesystem Source Code fpm_filesystem.F90 Source Code !> This module contains general routines for interacting with the file system !! module fpm_filesystem use , intrinsic :: iso_fortran_env , only : stdin => input_unit , stdout => output_unit , stderr => error_unit use fpm_environment , only : get_os_type , & OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_WINDOWS , & OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD use fpm_environment , only : separator , get_env , os_is_unix use fpm_strings , only : f_string , replace , string_t , split , dilate , str_begins_with_str use iso_c_binding , only : c_char , c_ptr , c_int , c_null_char , c_associated , c_f_pointer use fpm_error , only : fpm_stop , error_t , fatal_error implicit none private public :: basename , canon_path , dirname , is_dir , join_path , number_of_rows , list_files , get_local_prefix , & mkdir , exists , get_temp_filename , windows_path , unix_path , getline , delete_file , fileopen , fileclose , & filewrite , warnwrite , parent_dir , is_hidden_file , read_lines , read_lines_expanded , which , run , & os_delete_dir , is_absolute_path , get_home , execute_and_read_output , get_dos_path #ifndef FPM_BOOTSTRAP interface function c_opendir ( dir ) result ( r ) bind ( c , name = \"c_opendir\" ) import c_char , c_ptr character ( kind = c_char ), intent ( in ) :: dir ( * ) type ( c_ptr ) :: r end function c_opendir function c_readdir ( dir ) result ( r ) bind ( c , name = \"c_readdir\" ) import c_ptr type ( c_ptr ), intent ( in ), value :: dir type ( c_ptr ) :: r end function c_readdir function c_closedir ( dir ) result ( r ) bind ( c , name = \"closedir\" ) import c_ptr , c_int type ( c_ptr ), intent ( in ), value :: dir integer ( kind = c_int ) :: r end function c_closedir function c_get_d_name ( dir ) result ( r ) bind ( c , name = \"get_d_name\" ) import c_ptr type ( c_ptr ), intent ( in ), value :: dir type ( c_ptr ) :: r end function c_get_d_name function c_is_dir ( path ) result ( r ) bind ( c , name = \"c_is_dir\" ) import c_char , c_int character ( kind = c_char ), intent ( in ) :: path ( * ) integer ( kind = c_int ) :: r end function c_is_dir end interface #endif contains !> Extract filename from path with/without suffix function basename ( path , suffix ) result ( base ) character ( * ), intent ( In ) :: path logical , intent ( in ), optional :: suffix character (:), allocatable :: base character (:), allocatable :: file_parts (:) logical :: with_suffix if (. not . present ( suffix )) then with_suffix = . true . else with_suffix = suffix end if call split ( path , file_parts , delimiters = '\\/' ) if ( size ( file_parts ) > 0 ) then base = trim ( file_parts ( size ( file_parts ))) else base = '' endif if (. not . with_suffix ) then call split ( base , file_parts , delimiters = '.' ) if ( size ( file_parts ) >= 2 ) then base = trim ( file_parts ( size ( file_parts ) - 1 )) endif endif end function basename !> Canonicalize path for comparison !! * Handles path string redundancies !! * Does not test existence of path !! !! To be replaced by realpath/_fullname in stdlib_os !! !! FIXME: Lot's of ugly hacks following here function canon_path ( path ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: canon_path character ( len = :), allocatable :: nixpath integer :: istart , iend , nn , last logical :: is_path , absolute nixpath = unix_path ( path ) istart = 0 nn = 0 iend = 0 absolute = nixpath ( 1 : 1 ) == \"/\" if ( absolute ) then canon_path = \"/\" else canon_path = \"\" end if do while ( iend < len ( nixpath )) call next ( nixpath , istart , iend , is_path ) if ( is_path ) then select case ( nixpath ( istart : iend )) case ( \".\" , \"\" ) ! always drop empty paths case ( \"..\" ) if ( nn > 0 ) then last = scan ( canon_path (: len ( canon_path ) - 1 ), \"/\" , back = . true .) canon_path = canon_path (: last ) nn = nn - 1 else if (. not . absolute ) then canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end if end if case default nn = nn + 1 canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end select end if end do if ( len ( canon_path ) == 0 ) canon_path = \".\" if ( len ( canon_path ) > 1 . and . canon_path ( len ( canon_path ):) == \"/\" ) then canon_path = canon_path (: len ( canon_path ) - 1 ) end if contains subroutine next ( string , istart , iend , is_path ) character ( len =* ), intent ( in ) :: string integer , intent ( inout ) :: istart integer , intent ( inout ) :: iend logical , intent ( inout ) :: is_path integer :: ii , nn character :: tok nn = len ( string ) if ( iend >= nn ) then istart = nn iend = nn return end if ii = min ( iend + 1 , nn ) tok = string ( ii : ii ) is_path = tok /= '/' if (. not . is_path ) then is_path = . false . istart = ii iend = ii return end if istart = ii do ii = min ( iend + 1 , nn ), nn tok = string ( ii : ii ) select case ( tok ) case ( '/' ) exit case default iend = ii cycle end select end do end subroutine next end function canon_path !> Extract dirname from path function dirname ( path ) result ( dir ) character ( * ), intent ( in ) :: path character (:), allocatable :: dir dir = path ( 1 : scan ( path , '/\\',back=.true.)) end function dirname !> Extract dirname from path function parent_dir(path) result (dir) character(*), intent(in) :: path character(:), allocatable :: dir dir = path(1:scan(path,' / \\ ',back=.true.)-1) end function parent_dir !> test if a name matches an existing directory path logical function is_dir(dir) character(*), intent(in) :: dir integer :: stat select case (get_os_type()) case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) call run( \"test -d \" // dir , & & exitstat=stat,echo=.false.,verbose=.false.) case (OS_WINDOWS) call run(' cmd / c \"if not exist ' // windows_path(dir) // '\\ exit /B 1\" ', & & exitstat=stat,echo=.false.,verbose=.false.) end select is_dir = (stat == 0) end function is_dir !> test if a file is hidden logical function is_hidden_file(file_basename) result(r) character(*), intent(in) :: file_basename if (len(file_basename) <= 2) then r = .false. else r = str_begins_with_str(file_basename, ' . ') end if end function is_hidden_file !> Construct path by joining strings with os file separator function join_path(a1,a2,a3,a4,a5) result(path) character(len=*), intent(in) :: a1, a2 character(len=*), intent(in), optional :: a3, a4, a5 character(len=:), allocatable :: path character(len=1) :: filesep logical, save :: has_cache = .false. character(len=1), save :: cache = ' / ' !$omp threadprivate(has_cache, cache) if (has_cache) then filesep = cache else select case (get_os_type()) case default filesep = ' / ' case (OS_WINDOWS) filesep = ' \\ ' end select cache = filesep has_cache = .true. end if if (a1 == \"\") then path = a2 else path = a1 // filesep // a2 end if if (present(a3)) then path = path // filesep // a3 else return end if if (present(a4)) then path = path // filesep // a4 else return end if if (present(a5)) then path = path // filesep // a5 else return end if end function join_path !> Determine number or rows in a file given a LUN integer function number_of_rows(s) result(nrows) integer,intent(in)::s integer :: ios rewind(s) nrows = 0 do read(s, *, iostat=ios) if (ios /= 0) exit nrows = nrows + 1 end do rewind(s) end function number_of_rows !> read lines into an array of TYPE(STRING_T) variables expanding tabs function read_lines_expanded(fh) result(lines) integer, intent(in) :: fh type(string_t), allocatable :: lines(:) integer :: i integer :: iostat character(len=:),allocatable :: line_buffer_read allocate(lines(number_of_rows(fh))) do i = 1, size(lines) call getline(fh, line_buffer_read, iostat) lines(i)%s = dilate(line_buffer_read) end do end function read_lines_expanded !> read lines into an array of TYPE(STRING_T) variables function read_lines(fh) result(lines) integer, intent(in) :: fh type(string_t), allocatable :: lines(:) integer :: i integer :: iostat allocate(lines(number_of_rows(fh))) do i = 1, size(lines) call getline(fh, lines(i)%s, iostat) end do end function read_lines !> Create a directory. Create subdirectories as needed subroutine mkdir(dir, echo) character(len=*), intent(in) :: dir logical, intent(in), optional :: echo integer :: stat if (is_dir(dir)) return select case (get_os_type()) case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) call run(' mkdir - p ' // dir, exitstat=stat,echo=echo,verbose=.false.) case (OS_WINDOWS) call run(\"mkdir \" // windows_path(dir), & & echo=echo, exitstat=stat,verbose=.false.) end select if (stat /= 0) then call fpm_stop(1, ' * mkdir * : directory creation failed ') end if end subroutine mkdir #ifndef FPM_BOOTSTRAP !> Get file & directory names in directory `dir` using iso_c_binding. !! !! - File/directory names return are relative to cwd, ie. preprended with `dir` !! - Includes files starting with `.` except current directory and parent directory !! recursive subroutine list_files(dir, files, recurse) character(len=*), intent(in) :: dir type(string_t), allocatable, intent(out) :: files(:) logical, intent(in), optional :: recurse integer :: i type(string_t), allocatable :: dir_files(:) type(string_t), allocatable :: sub_dir_files(:) type(c_ptr) :: dir_handle type(c_ptr) :: dir_entry_c character(len=:,kind=c_char), allocatable :: fortran_name character(len=:), allocatable :: string_fortran integer, parameter :: N_MAX = 256 type(string_t) :: files_tmp(N_MAX) integer(kind=c_int) :: r if (c_is_dir(dir(1:len_trim(dir))//c_null_char) == 0) then allocate (files(0)) return end if dir_handle = c_opendir(dir(1:len_trim(dir))//c_null_char) if (.not. c_associated(dir_handle)) then print *, ' c_opendir () failed ' error stop end if i = 0 allocate(files(0)) do dir_entry_c = c_readdir(dir_handle) if (.not. c_associated(dir_entry_c)) then exit else string_fortran = f_string(c_get_d_name(dir_entry_c)) if ((string_fortran == ' . ' .or. string_fortran == ' .. ')) then cycle end if i = i + 1 if (i > N_MAX) then files = [files, files_tmp] i = 1 end if files_tmp(i)%s = join_path(dir, string_fortran) end if end do r = c_closedir(dir_handle) if (r /= 0) then print *, ' c_closedir () failed ' error stop end if if (i > 0) then files = [files, files_tmp(1:i)] end if if (present(recurse)) then if (recurse) then allocate(sub_dir_files(0)) do i=1,size(files) if (c_is_dir(files(i)%s//c_null_char) /= 0) then call list_files(files(i)%s, dir_files, recurse=.true.) sub_dir_files = [sub_dir_files, dir_files] end if end do files = [files, sub_dir_files] end if end if end subroutine list_files #else !> Get file & directory names in directory `dir`. !! !! - File/directory names return are relative to cwd, ie. preprended with `dir` !! - Includes files starting with `.` except current directory and parent directory !! recursive subroutine list_files(dir, files, recurse) character(len=*), intent(in) :: dir type(string_t), allocatable, intent(out) :: files(:) logical, intent(in), optional :: recurse integer :: stat, fh, i character(:), allocatable :: temp_file type(string_t), allocatable :: dir_files(:) type(string_t), allocatable :: sub_dir_files(:) if (.not. is_dir(dir)) then allocate (files(0)) return end if allocate (temp_file, source=get_temp_filename()) select case (get_os_type()) case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) call run(' ls - A ' // dir , & & redirect=temp_file, exitstat=stat,echo=.false.,verbose=.false.) case (OS_WINDOWS) call run(' dir / b ' // windows_path(dir), & & redirect=temp_file, exitstat=stat,echo=.false.,verbose=.false.) end select if (stat /= 0) then call fpm_stop(2,' * list_files * : directory listing failed ') end if open (newunit=fh, file=temp_file, status=' old ') files = read_lines(fh) close(fh,status=\"delete\") do i=1,size(files) files(i)%s = join_path(dir,files(i)%s) end do if (present(recurse)) then if (recurse) then allocate(sub_dir_files(0)) do i=1,size(files) if (is_dir(files(i)%s)) then call list_files(files(i)%s, dir_files, recurse=.true.) sub_dir_files = [sub_dir_files, dir_files] end if end do files = [files, sub_dir_files] end if end if end subroutine list_files #endif !> test if pathname already exists logical function exists(filename) result(r) character(len=*), intent(in) :: filename inquire(file=filename, exist=r) !> Directories are not files for the Intel compilers. If so, also use this compiler-dependent extension #if defined(__INTEL_COMPILER) if (.not.r) inquire(directory=filename, exist=r) #endif end function !> Get a unused temporary filename !! Calls posix ' tempnam ' - not recommended, but !! we have no security concerns for this application !! and use here is temporary. !! Works with MinGW function get_temp_filename() result(tempfile) ! use iso_c_binding, only: c_ptr, C_NULL_PTR, c_f_pointer integer, parameter :: MAX_FILENAME_LENGTH = 32768 character(:), allocatable :: tempfile type(c_ptr) :: c_tempfile_ptr character(len=1), pointer :: c_tempfile(:) interface function c_tempnam(dir,pfx) result(tmp) bind(c,name=\"tempnam\") import type(c_ptr), intent(in), value :: dir type(c_ptr), intent(in), value :: pfx type(c_ptr) :: tmp end function c_tempnam subroutine c_free(ptr) BIND(C,name=\"free\") import type(c_ptr), value :: ptr end subroutine c_free end interface c_tempfile_ptr = c_tempnam(C_NULL_PTR, C_NULL_PTR) call c_f_pointer(c_tempfile_ptr,c_tempfile,[MAX_FILENAME_LENGTH]) tempfile = f_string(c_tempfile) call c_free(c_tempfile_ptr) end function get_temp_filename !> Replace file system separators for windows function windows_path(path) result(winpath) character(*), intent(in) :: path character(:), allocatable :: winpath integer :: idx winpath = path idx = index(winpath,' / ') do while(idx > 0) winpath(idx:idx) = ' \\ ' idx = index(winpath,' / ') end do end function windows_path !> Replace file system separators for unix function unix_path(path) result(nixpath) character(*), intent(in) :: path character(:), allocatable :: nixpath integer :: idx nixpath = path idx = index(nixpath,' \\ ') do while(idx > 0) nixpath(idx:idx) = ' / ' idx = index(nixpath,' \\ ') end do end function unix_path !>AUTHOR: fpm(1) contributors !!LICENSE: MIT !> !!##NAME !! getline(3f) - [M_io:READ] read a line of arbintrary length from specified !! LUN into allocatable string (up to system line length limit) !! (LICENSE:PD) !! !!##SYNTAX !! subroutine getline(unit,line,iostat,iomsg) !! !! integer,intent(in) :: unit !! character(len=:),allocatable,intent(out) :: line !! integer,intent(out) :: iostat !! character(len=:), allocatable, optional :: iomsg !! !!##DESCRIPTION !! Read a line of any length up to programming environment maximum !! line length. Requires Fortran 2003+. !! !! It is primarily expected to be used when reading input which will !! then be parsed or echoed. !! !! The input file must have a PAD attribute of YES for the function !! to work properly, which is typically true. !! !! The simple use of a loop that repeatedly re-allocates a character !! variable in addition to reading the input file one buffer at a !! time could (depending on the programming environment used) be !! inefficient, as it could reallocate and allocate memory used for !! the output string with each buffer read. !! !!##OPTIONS !! LINE The line read when IOSTAT returns as zero. !! LUN LUN (Fortran logical I/O unit) number of file open and ready !! to read. !! IOSTAT status returned by READ(IOSTAT=IOS). If not zero, an error !! occurred or an end-of-file or end-of-record was encountered. !! IOMSG error message returned by system when IOSTAT is not zero. !! !!##EXAMPLE !! !! Sample program: !! !! program demo_getline !! use,intrinsic :: iso_fortran_env, only : stdin=>input_unit !! use,intrinsic :: iso_fortran_env, only : iostat_end !! use FPM_filesystem, only : getline !! implicit none !! integer :: iostat !! character(len=:),allocatable :: line, iomsg !! open(unit=stdin,pad=' yes ') !! INFINITE: do !! call getline(stdin,line,iostat,iomsg) !! if(iostat /= 0) exit INFINITE !! write(*,' ( a ) ')' [ '//line//' ] ' !! enddo INFINITE !! if(iostat /= iostat_end)then !! write(*,*)' error reading input : ',iomsg !! endif !! end program demo_getline !! subroutine getline(unit, line, iostat, iomsg) !> Formatted IO unit integer, intent(in) :: unit !> Line to read character(len=:), allocatable, intent(out) :: line !> Status of operation integer, intent(out) :: iostat !> Error message character(len=:), allocatable, optional :: iomsg integer, parameter :: BUFFER_SIZE = 32768 character(len=BUFFER_SIZE) :: buffer character(len=256) :: msg integer :: size integer :: stat allocate(character(len=0) :: line) do read(unit, ' ( a ) ', advance=' no ', iostat=stat, iomsg=msg, size=size) & & buffer if (stat > 0) exit line = line // buffer(:size) if (stat < 0) then if (is_iostat_eor(stat)) then stat = 0 end if exit end if end do if (stat /= 0) then if (present(iomsg)) iomsg = trim(msg) end if iostat = stat end subroutine getline !> delete a file by filename subroutine delete_file(file) character(len=*), intent(in) :: file logical :: exist integer :: unit inquire(file=file, exist=exist) if (exist) then open(file=file, newunit=unit) close(unit, status=\"delete\") end if end subroutine delete_file !> write trimmed character data to a file if it does not exist subroutine warnwrite(fname,data) character(len=*),intent(in) :: fname character(len=*),intent(in) :: data(:) if(.not.exists(fname))then call filewrite(fname,data) else write(stderr,' ( * ( g0 , 1 x )) ')' < INFO > ',fname,& & ' already exists . Not overwriting ' endif end subroutine warnwrite !> procedure to open filename as a sequential \"text\" file subroutine fileopen(filename,lun,ier) character(len=*),intent(in) :: filename integer,intent(out) :: lun integer,intent(out),optional :: ier integer :: ios character(len=256) :: message message=' ' ios=0 if(filename/=' ')then open(file=filename, & & newunit=lun, & & form=' formatted ', & ! FORM = FORMATTED | UNFORMATTED & access=' sequential ', & ! ACCESS = SEQUENTIAL| DIRECT | STREAM & action=' write ', & ! ACTION = READ|WRITE| READWRITE & position=' rewind ', & ! POSITION= ASIS | REWIND | APPEND & status=' new ', & ! STATUS = NEW| REPLACE| OLD| SCRATCH| UNKNOWN & iostat=ios, & & iomsg=message) else lun=stdout ios=0 endif if(ios/=0)then lun=-1 if(present(ier))then ier=ios else call fpm_stop(3,' * fileopen * : '//filename//' : '//trim(message)) endif endif end subroutine fileopen !> simple close of a LUN. On error show message and stop (by default) subroutine fileclose(lun,ier) integer,intent(in) :: lun integer,intent(out),optional :: ier character(len=256) :: message integer :: ios if(lun/=-1)then close(unit=lun,iostat=ios,iomsg=message) if(ios/=0)then if(present(ier))then ier=ios else call fpm_stop(4,' * fileclose * : '//trim(message)) endif endif endif end subroutine fileclose !> procedure to write filedata to file filename subroutine filewrite(filename,filedata) character(len=*),intent(in) :: filename character(len=*),intent(in) :: filedata(:) integer :: lun, i, ios character(len=256) :: message call fileopen(filename,lun) if(lun/=-1)then ! program currently stops on error on open, but might ! want it to continue so -1 (unallowed LUN) indicates error ! write file do i=1,size(filedata) write(lun,' ( a ) ',iostat=ios,iomsg=message)trim(filedata(i)) if(ios/=0)then call fpm_stop(5,' * filewrite * : '//filename//' : '//trim(message)) endif enddo endif ! close file call fileclose(lun) end subroutine filewrite !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!##Name !! which(3f) - [M_io:ENVIRONMENT] given a command name find the pathname by searching !! the directories in the environment variable $PATH !! (LICENSE:PD) !! !!##Syntax !! function which(command) result(pathname) !! !! character(len=*),intent(in) :: command !! character(len=:),allocatable :: pathname !! !!##Description !! Given a command name find the first file with that name in the directories !! specified by the environment variable $PATH. !! !!##options !! COMMAND the command to search for !! !!##Returns !! PATHNAME the first pathname found in the current user path. Returns blank !! if the command is not found. !! !!##Example !! !! Sample program: !! !! Checking the error message and counting lines: !! !! program demo_which !! use M_io, only : which !! implicit none !! write(*,*)' ls is ',which(' ls ') !! write(*,*)' dir is ',which(' dir ') !! write(*,*)' install is ',which(' install ') !! end program demo_which !! function which(command) result(pathname) character(len=*),intent(in) :: command character(len=:),allocatable :: pathname, checkon, paths(:), exts(:) integer :: i, j pathname='' call split(get_env(' PATH '),paths,delimiters=merge(' ; ',' : ',separator()==' \\ ')) SEARCH: do i=1,size(paths) checkon=trim(join_path(trim(paths(i)),command)) select case(separator()) case(' / ') if(exists(checkon))then pathname=checkon exit SEARCH endif case(' \\ ') if(exists(checkon))then pathname=checkon exit SEARCH endif if(exists(checkon//' . bat '))then pathname=checkon//' . bat ' exit SEARCH endif if(exists(checkon//' . exe '))then pathname=checkon//' . exe ' exit SEARCH endif call split(get_env(' PATHEXT '),exts,delimiters=' ; ') do j=1,size(exts) if(exists(checkon//' . '//trim(exts(j))))then pathname=checkon//' . '//trim(exts(j)) exit SEARCH endif enddo end select enddo SEARCH end function which !>AUTHOR: fpm(1) contributors !!LICENSE: MIT !> !!##Name !! run(3f) - execute specified system command and selectively echo !! command and output to a file and/or stdout. !! (LICENSE:MIT) !! !!##Syntax !! subroutine run(cmd,echo,exitstat,verbose,redirect) !! !! character(len=*), intent(in) :: cmd !! logical,intent(in),optional :: echo !! integer, intent(out),optional :: exitstat !! logical, intent(in), optional :: verbose !! character(*), intent(in), optional :: redirect !! !!##Description !! Execute the specified system command. Optionally !! !! + echo the command before execution !! + return the system exit status of the command. !! + redirect the output of the command to a file. !! + echo command output to stdout !! !! Calling run(3f) is preferred to direct calls to !! execute_command_line(3f) in the fpm(1) source to provide a standard !! interface where output modes can be specified. !! !!##Options !! CMD System command to execute !! ECHO Whether to echo the command being executed or not !! Defaults to .TRUE. . !! VERBOSE Whether to redirect the command output to a null device or not !! Defaults to .TRUE. . !! REDIRECT Filename to redirect stdout and stderr of the command into. !! If generated it is closed before run(3f) returns. !! EXITSTAT The system exit status of the command when supported by !! the system. If not present and a non-zero status is !! generated program termination occurs. !! !!##Example !! !! Sample program: !! !! Checking the error message and counting lines: !! !! program demo_run !! use fpm_filesystem, only : run !! implicit none !! logical,parameter :: T=.true., F=.false. !! integer :: exitstat !! character(len=:),allocatable :: cmd !! cmd=' ls - ltrasd * . md ' !! call run(cmd) !! call run(cmd,exitstat=exitstat) !! call run(cmd,echo=F) !! call run(cmd,verbose=F) !! end program demo_run !! subroutine run(cmd,echo,exitstat,verbose,redirect) character(len=*), intent(in) :: cmd logical,intent(in),optional :: echo integer, intent(out),optional :: exitstat logical, intent(in), optional :: verbose character(*), intent(in), optional :: redirect integer :: cmdstat character(len=256) :: cmdmsg, iomsg logical :: echo_local, verbose_local character(:), allocatable :: redirect_str character(:), allocatable :: line integer :: stat, fh, iostat if(present(echo))then echo_local=echo else echo_local=.true. end if if(present(verbose))then verbose_local=verbose else verbose_local=.true. end if if (present(redirect)) then if(redirect /= '')then redirect_str = \">\"//redirect//\" 2>&1\" endif else if(verbose_local)then ! No redirection but verbose output redirect_str = \"\" else ! No redirection and non-verbose output if (os_is_unix()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if end if if(echo_local) print *, ' + ', cmd !//redirect_str call execute_command_line(cmd//redirect_str, exitstat=stat,cmdstat=cmdstat,cmdmsg=cmdmsg) if(cmdstat /= 0)then write(*,' ( a ) ')' < ERROR > : failed command '//cmd//redirect_str call fpm_stop(1,' * run * : '//trim(cmdmsg)) endif if (verbose_local.and.present(redirect)) then open(newunit=fh,file=redirect,status=' old ',iostat=iostat,iomsg=iomsg) if(iostat == 0)then do call getline(fh, line, iostat) if (iostat /= 0) exit write(*,' ( A ) ') trim(line) end do else write(*,' ( A ) ') trim(iomsg) endif close(fh) end if if (present(exitstat)) then exitstat = stat elseif (stat /= 0) then call fpm_stop(stat,' * run * : Command '//cmd//redirect_str//' returned a non - zero status code ') end if end subroutine run !> Delete directory using system OS remove directory commands subroutine os_delete_dir(is_unix, dir, echo) logical, intent(in) :: is_unix character(len=*), intent(in) :: dir logical, intent(in), optional :: echo if (is_unix) then call run(' rm - rf ' // dir, echo=echo,verbose=.false.) else call run(' rmdir / s / q ' // dir, echo=echo,verbose=.false.) end if end subroutine os_delete_dir !> Determine the path prefix to the local folder. Used for installation, registry etc. function get_local_prefix(os) result(prefix) !> Installation prefix character(len=:), allocatable :: prefix !> Platform identifier integer, intent(in), optional :: os !> Default installation prefix on Unix platforms character(len=*), parameter :: default_prefix_unix = \"/usr/local\" !> Default installation prefix on Windows platforms character(len=*), parameter :: default_prefix_win = \"C:\\\" character(len=:), allocatable :: home if (os_is_unix(os)) then home=get_env(' HOME ','') if (home /= '' ) then prefix = join_path(home, \".local\") else prefix = default_prefix_unix end if else home=get_env(' APPDATA ','') if (home /= '' ) then prefix = join_path(home, \"local\") else prefix = default_prefix_win end if end if end function get_local_prefix !> Returns .true. if provided path is absolute. !> !> `~` not treated as absolute. logical function is_absolute_path(path, is_unix) character(len=*), intent(in) :: path logical, optional, intent(in):: is_unix character(len=*), parameter :: letters = ' ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ' logical :: is_unix_os if (present(is_unix)) then is_unix_os = is_unix else is_unix_os = os_is_unix() end if if (is_unix_os) then is_absolute_path = path(1:1) == ' / ' else if (len(path) < 2) then is_absolute_path = .false. return end if is_absolute_path = index(letters, path(1:1)) /= 0 .and. path(2:2) == ' : ' end if end function is_absolute_path !> Get the HOME directory on Unix and the %USERPROFILE% directory on Windows. subroutine get_home(home, error) character(len=:), allocatable, intent(out) :: home type(error_t), allocatable, intent(out) :: error if (os_is_unix()) then home=get_env(' HOME ','') if ( home == '' ) then call fatal_error(error, \"Couldn' t retrieve 'HOME' variable \") return end if else home=get_env('USERPROFILE','') if ( home == '' ) then call fatal_error(error, \" Couldn 't retrieve ' % USERPROFILE % ' variable\") return end if end if end subroutine get_home !> Execute command line and return output as a string. subroutine execute_and_read_output(cmd, output, error, verbose) !> Command to execute. character(len=*), intent(in) :: cmd !> Command line output. character(len=:), allocatable, intent(out) :: output !> Error to handle. type(error_t), allocatable, intent(out) :: error !> Print additional information if true. logical, intent(in), optional :: verbose integer :: exitstat, unit, stat character(len=:), allocatable :: cmdmsg, tmp_file, output_line logical :: is_verbose if (present(verbose)) then is_verbose = verbose else is_verbose = .false. end if tmp_file = get_temp_filename() call run(cmd//' > '//tmp_file, exitstat=exitstat, echo=is_verbose) if (exitstat /= 0) call fatal_error(error, ' * run * : '//\"Command failed: ' \"//cmd//\" '. Message: ' \"//trim(cmdmsg)//\" '.\") open(newunit=unit, file=tmp_file, action=' read ', status=' old ') output = '' do call getline(unit, output_line, stat) if (stat /= 0) exit output = output//output_line//' ' end do if (is_verbose) print *, output close(unit, status=' delete ') end !> Ensure a windows path is converted to an 8.3 DOS path if it contains spaces function get_dos_path(path,error) character(len=*), intent(in) :: path type(error_t), allocatable, intent(out) :: error character(len=:), allocatable :: get_dos_path character(:), allocatable :: redirect,screen_output,line integer :: stat,cmdstat,iunit,last ! Non-Windows OS if (get_os_type()/=OS_WINDOWS) then get_dos_path = path return end if ! Trim path first get_dos_path = trim(path) !> No need to convert if there are no spaces has_spaces: if (scan(get_dos_path,' ')>0) then redirect = get_temp_filename() call execute_command_line(' cmd / c for % A in ( \"'//path//'\" ) do @ echo % ~ sA > '//redirect//' 2 > & 1 ',& exitstat=stat,cmdstat=cmdstat) !> Read screen output command_OK: if (cmdstat==0 .and. stat==0) then allocate(character(len=0) :: screen_output) open(newunit=iunit,file=redirect,status=' old ',iostat=stat) if (stat == 0)then do call getline(iunit, line, stat) if (stat /= 0) exit screen_output = screen_output//line//' ' end do ! Close and delete file close(iunit,status=' delete ') else call fatal_error(error,' cannot read temporary file from successful DOS path evaluation ') return endif else command_OK call fatal_error(error,' unsuccessful Windows -> DOS path command ') return end if command_OK get_dos_path = trim(adjustl(screen_output)) endif has_spaces !> Ensure there are no trailing slashes last = len_trim(get_dos_path) if (last>1 .and. get_dos_path(last:last)==' / ' .or. get_dos_path(last:last)==' \\' ) get_dos_path = get_dos_path ( 1 : last - 1 ) end function get_dos_path end module fpm_filesystem","tags":"","loc":"sourcefile/fpm_filesystem.f90.html"},{"title":"fpm_environment.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_environment Source Code fpm_environment.f90 Source Code !> This module contains procedures that interact with the programming environment. !! !! * [get_os_type] -- Determine the OS type !! * [get_env] -- return the value of an environment variable module fpm_environment use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit use fpm_error , only : fpm_stop implicit none private public :: get_os_type public :: os_is_unix public :: get_env public :: get_command_arguments_quoted public :: separator integer , parameter , public :: OS_UNKNOWN = 0 integer , parameter , public :: OS_LINUX = 1 integer , parameter , public :: OS_MACOS = 2 integer , parameter , public :: OS_WINDOWS = 3 integer , parameter , public :: OS_CYGWIN = 4 integer , parameter , public :: OS_SOLARIS = 5 integer , parameter , public :: OS_FREEBSD = 6 integer , parameter , public :: OS_OPENBSD = 7 contains !> Determine the OS type integer function get_os_type () result ( r ) !! !! Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN, !! OS_SOLARIS, OS_FREEBSD, OS_OPENBSD. !! !! At first, the environment variable `OS` is checked, which is usually !! found on Windows. Then, `OSTYPE` is read in and compared with common !! names. If this fails too, check the existence of files that can be !! found on specific system types only. !! !! Returns OS_UNKNOWN if the operating system cannot be determined. character ( len = 32 ) :: val integer :: length , rc logical :: file_exists logical , save :: first_run = . true . integer , save :: ret = OS_UNKNOWN !$omp threadprivate(ret, first_run) if (. not . first_run ) then r = ret return end if first_run = . false . r = OS_UNKNOWN ! Check environment variable `OSTYPE`. call get_environment_variable ( 'OSTYPE' , val , length , rc ) if ( rc == 0 . and . length > 0 ) then ! Linux if ( index ( val , 'linux' ) > 0 ) then r = OS_LINUX ret = r return end if ! macOS if ( index ( val , 'darwin' ) > 0 ) then r = OS_MACOS ret = r return end if ! Windows, MSYS, MinGW, Git Bash if ( index ( val , 'win' ) > 0 . or . index ( val , 'msys' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Cygwin if ( index ( val , 'cygwin' ) > 0 ) then r = OS_CYGWIN ret = r return end if ! Solaris, OpenIndiana, ... if ( index ( val , 'SunOS' ) > 0 . or . index ( val , 'solaris' ) > 0 ) then r = OS_SOLARIS ret = r return end if ! FreeBSD if ( index ( val , 'FreeBSD' ) > 0 . or . index ( val , 'freebsd' ) > 0 ) then r = OS_FREEBSD ret = r return end if ! OpenBSD if ( index ( val , 'OpenBSD' ) > 0 . or . index ( val , 'openbsd' ) > 0 ) then r = OS_OPENBSD ret = r return end if end if ! Check environment variable `OS`. call get_environment_variable ( 'OS' , val , length , rc ) if ( rc == 0 . and . length > 0 . and . index ( val , 'Windows_NT' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Linux inquire ( file = '/etc/os-release' , exist = file_exists ) if ( file_exists ) then r = OS_LINUX ret = r return end if ! macOS inquire ( file = '/usr/bin/sw_vers' , exist = file_exists ) if ( file_exists ) then r = OS_MACOS ret = r return end if ! FreeBSD inquire ( file = '/bin/freebsd-version' , exist = file_exists ) if ( file_exists ) then r = OS_FREEBSD ret = r return end if end function get_os_type !> Compare the output of [[get_os_type]] or the optional !! passed INTEGER value to the value for OS_WINDOWS !! and return .TRUE. if they match and .FALSE. otherwise logical function os_is_unix ( os ) integer , intent ( in ), optional :: os integer :: build_os if ( present ( os )) then build_os = os else build_os = get_os_type () end if os_is_unix = build_os /= OS_WINDOWS end function os_is_unix !> get named environment variable value. It it is blank or !! not set return the optional default value function get_env ( NAME , DEFAULT ) result ( VALUE ) implicit none !> name of environment variable to get the value of character ( len =* ), intent ( in ) :: NAME !> default value to return if the requested value is undefined or blank character ( len =* ), intent ( in ), optional :: DEFAULT !> the returned value character ( len = :), allocatable :: VALUE integer :: howbig integer :: stat integer :: length ! get length required to hold value length = 0 if ( NAME /= '' ) then call get_environment_variable ( NAME , length = howbig , status = stat , trim_name = . true .) select case ( stat ) case ( 1 ) !*!print *, NAME, \" is not defined in the environment. Strange...\" VALUE = '' case ( 2 ) !*!print *, \"This processor doesn't support environment variables. Boooh!\" VALUE = '' case default ! make string to hold value of sufficient size allocate ( character ( len = max ( howbig , 1 )) :: VALUE ) ! get value call get_environment_variable ( NAME , VALUE , status = stat , trim_name = . true .) if ( stat /= 0 ) VALUE = '' end select else VALUE = '' endif if ( VALUE == '' . and . present ( DEFAULT )) VALUE = DEFAULT end function get_env function get_command_arguments_quoted () result ( args ) character ( len = :), allocatable :: args character ( len = :), allocatable :: arg character ( len = 1 ) :: quote integer :: ilength , istatus , i ilength = 0 args = '' quote = merge ( '\"' , \"'\" , separator () == '\\') do i=2,command_argument_count() ! look at all arguments after subcommand call get_command_argument(number=i,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit else if(allocated(arg))deallocate(arg) allocate(character(len=ilength) :: arg) call get_command_argument(number=i,value=arg,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit elseif(ilength>0)then if(index(arg//' ',' - ')/=1)then args=args//quote//arg//quote//' ' elseif(index(arg,' ')/=0)then args=args//quote//arg//quote//' ' else args=args//arg//' ' endif else args=args//repeat(quote,2)//' ' endif endif enddo end function get_command_arguments_quoted function separator() result(sep) !> !!##NAME !! separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character !! (LICENSE:PD) !! !!##SYNOPSIS !! !! function separator() result(sep) !! !! character(len=1) :: sep !! !!##DESCRIPTION !! First using the name the program was invoked with, then the name !! returned by an INQUIRE(3f) of that name, then \".\\NAME\" and \"./NAME\" !! try to determine the separator character used to separate directory !! names from file basenames. !! !! If a slash or backslash is not found in the name, the environment !! variable PATH is examined first for a backslash, then a slash. !! !! Can be very system dependent. If the queries fail the default returned !! is \"/\". !! !!##EXAMPLE !! !! sample usage !! !! program demo_separator !! use M_io, only : separator !! implicit none !! write(*,*)' separator = ',separator() !! end program demo_separator ! use the pathname returned as arg0 to determine pathname separator implicit none character(len=:),allocatable :: arg0 integer :: arg0_length integer :: istat logical :: existing character(len=1) :: sep !*ifort_bug*!character(len=1),save :: sep_cache=' ' character(len=4096) :: name character(len=:),allocatable :: fname !*ifort_bug*! if(sep_cache/=' ')then ! use cached value. NOTE: A parallel code might theoretically use multiple OS !*ifort_bug*! sep=sep_cache !*ifort_bug*! return !*ifort_bug*! endif arg0_length=0 name=' ' call get_command_argument(0,length=arg0_length,status=istat) if(allocated(arg0))deallocate(arg0) allocate(character(len=arg0_length) :: arg0) call get_command_argument(0,arg0,status=istat) ! check argument name if(index(arg0,' \\ ')/=0)then sep=' \\ ' elseif(index(arg0,' / ')/=0)then sep=' / ' else ! try name returned by INQUIRE(3f) existing=.false. name=' ' inquire(file=arg0,iostat=istat,exist=existing,name=name) if(index(name,' \\ ')/=0)then sep=' \\ ' elseif(index(name,' / ')/=0)then sep=' / ' else ! well, try some common syntax and assume in current directory fname=' . \\ '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' \\ ' else fname=' . / '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' / ' else ! check environment variable PATH sep=merge(' \\ ',' / ',index(get_env(' PATH '),' \\ ')/=0) !*!write(*,*)' < WARNING > unknown system directory path separator ' endif endif endif endif !*ifort_bug*!sep_cache=sep end function separator end module fpm_environment","tags":"","loc":"sourcefile/fpm_environment.f90.html"},{"title":"fpm_source_parsing.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_source_parsing Source Code fpm_source_parsing.f90 Source Code !># Parsing of package source files !> !> This module exposes two functions, `[[parse_f_source]]` and `[[parse_c_source]]`, !> which perform a rudimentary parsing of fortran and c source files !> in order to extract information required for module dependency tracking. !> !> Both functions additionally calculate and store a file digest (hash) which !> is used by the backend ([[fpm_backend]]) to skip compilation of unmodified sources. !> !> Both functions return an instance of the [[srcfile_t]] type. !> !> For more information, please read the documentation for each function: !> !> - `[[parse_f_source]]` !> - `[[parse_c_source]]` !> module fpm_source_parsing use fpm_error , only : error_t , file_parse_error , fatal_error , file_not_found_error use fpm_strings , only : string_t , string_cat , len_trim , split , lower , str_ends_with , fnv_1a , is_fortran_name use fpm_model , only : srcfile_t , & FPM_UNIT_UNKNOWN , FPM_UNIT_PROGRAM , FPM_UNIT_MODULE , & FPM_UNIT_SUBMODULE , FPM_UNIT_SUBPROGRAM , & FPM_UNIT_CSOURCE , FPM_UNIT_CHEADER , FPM_SCOPE_UNKNOWN , & FPM_SCOPE_LIB , FPM_SCOPE_DEP , FPM_SCOPE_APP , FPM_SCOPE_TEST , & FPM_UNIT_CPPSOURCE use fpm_filesystem , only : read_lines , read_lines_expanded , exists implicit none private public :: parse_f_source , parse_c_source , parse_use_statement contains !> Parsing of free-form fortran source files !> !> The following statements are recognised and parsed: !> !> - `Module`/`submodule`/`program` declaration !> - Module `use` statement !> - `include` statement !> !> @note Intrinsic modules used by sources are not listed in !> the `modules_used` field of source objects. !> !> @note Submodules are treated as normal modules which `use` their !> corresponding parent modules. !> !>### Parsing limitations !> !> __Statements must not continued onto another line !> except for an `only:` list in the `use` statement.__ !> !> This is supported: !> !>```fortran !> use my_module, only: & !> my_var, my_function, my_subroutine !>``` !> !> This is __NOT supported:__ !> !>```fortran !> use & !> my_module !>``` !> function parse_f_source ( f_filename , error ) result ( f_source ) character ( * ), intent ( in ) :: f_filename type ( srcfile_t ) :: f_source type ( error_t ), allocatable , intent ( out ) :: error logical :: inside_module , inside_interface , using , intrinsic_module integer :: stat integer :: fh , n_use , n_include , n_mod , n_parent , i , j , ic , pass type ( string_t ), allocatable :: file_lines (:), file_lines_lower (:) character (:), allocatable :: temp_string , mod_name , string_parts (:) if (. not . exists ( f_filename )) then call file_not_found_error ( error , f_filename ) return end if f_source % file_name = f_filename open ( newunit = fh , file = f_filename , status = 'old' ) file_lines = read_lines_expanded ( fh ) close ( fh ) ! for efficiency in parsing make a lowercase left-adjusted copy of the file ! Need a copy because INCLUDE (and #include) file arguments are case-sensitive file_lines_lower = file_lines do i = 1 , size ( file_lines_lower ) file_lines_lower ( i )% s = adjustl ( lower ( file_lines_lower ( i )% s )) enddo ! fnv_1a can only be applied to non-zero-length arrays if ( len_trim ( file_lines_lower ) > 0 ) f_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_use = 0 n_include = 0 n_mod = 0 n_parent = 0 inside_module = . false . inside_interface = . false . file_loop : do i = 1 , size ( file_lines_lower ) ! Skip comment lines and preprocessor directives if ( index ( file_lines_lower ( i )% s , '!' ) == 1 . or . & index ( file_lines_lower ( i )% s , '#' ) == 1 . or . & len_trim ( file_lines_lower ( i )% s ) < 1 ) then cycle end if ! Detect exported C-API via bind(C) if (. not . inside_interface . and . & parse_subsequence ( file_lines_lower ( i )% s , 'bind' , '(' , 'c' )) then do j = i , 1 , - 1 if ( index ( file_lines_lower ( j )% s , 'function' ) > 0 . or . & index ( file_lines_lower ( j )% s , 'subroutine' ) > 0 ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM exit end if if ( j > 1 ) then ic = index ( file_lines_lower ( j - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( j - 1 )% s ) end if temp_string = trim ( file_lines_lower ( j - 1 )% s ( 1 : ic )) if ( index ( temp_string , '&' ) /= len ( temp_string )) then exit end if end if end do end if ! Skip lines that are continued: not statements if ( i > 1 ) then ic = index ( file_lines_lower ( i - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( i - 1 )% s ) end if temp_string = trim ( file_lines_lower ( i - 1 )% s ( 1 : ic )) if ( len ( temp_string ) > 0 . and . index ( temp_string , '&' ) == len ( temp_string )) then cycle end if end if ! Detect beginning of interface block if ( index ( file_lines_lower ( i )% s , 'interface' ) == 1 ) then inside_interface = . true . cycle end if ! Detect end of interface block if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'interface' )) then inside_interface = . false . cycle end if ! Process 'USE' statements call parse_use_statement ( f_filename , i , file_lines_lower ( i )% s , using , intrinsic_module , mod_name , error ) if ( allocated ( error )) return if ( using ) then ! Not a valid module name? if (. not . is_fortran_name ( mod_name )) cycle ! Valid intrinsic module: not a dependency if ( intrinsic_module ) cycle n_use = n_use + 1 if ( pass == 2 ) f_source % modules_used ( n_use )% s = mod_name cycle endif ! Process 'INCLUDE' statements ic = index ( file_lines_lower ( i )% s , 'include' ) if ( ic == 1 ) then ic = index ( lower ( file_lines ( i )% s ), 'include' ) if ( index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), '\"' ) == 1 . or . & index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), \"'\" ) == 1 ) then n_include = n_include + 1 if ( pass == 2 ) then f_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = \"'\" // '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find include file name' , i , & file_lines ( i )% s ) return end if end if cycle end if end if ! Extract name of module if is module if ( index ( file_lines_lower ( i )% s , 'module ' ) == 1 ) then ! Remove any trailing comments ic = index ( file_lines_lower ( i )% s , '!' ) - 1 if ( ic < 1 ) then ic = len ( file_lines_lower ( i )% s ) end if temp_string = trim ( file_lines_lower ( i )% s ( 1 : ic )) ! R1405 module-stmt := \"MODULE\" module-name ! module-stmt has two space-delimited parts only ! (no line continuations) call split ( temp_string , string_parts , ' ' ) if ( size ( string_parts ) /= 2 ) then cycle end if mod_name = trim ( adjustl ( string_parts ( 2 ))) if ( scan ( mod_name , '=(&' ) > 0 ) then ! Ignore these cases: ! module & ! module =* ! module (i) cycle end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for module' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 if ( pass == 2 ) then f_source % modules_provided ( n_mod ) = string_t ( mod_name ) end if if ( f_source % unit_type == FPM_UNIT_UNKNOWN ) then f_source % unit_type = FPM_UNIT_MODULE end if if (. not . inside_module ) then inside_module = . true . else ! Must have missed an end module statement (can't assume a pure module) if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end if cycle end if ! Extract name of submodule if is submodule if ( index ( file_lines_lower ( i )% s , 'submodule' ) == 1 ) then mod_name = split_n ( file_lines_lower ( i )% s , n = 3 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule name' , i , & file_lines_lower ( i )% s ) return end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule ancestry' , i , & file_lines_lower ( i )% s ) return end if if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBMODULE end if n_use = n_use + 1 inside_module = . true . n_parent = n_parent + 1 if ( pass == 2 ) then if ( index ( temp_string , ':' ) > 0 ) then temp_string = temp_string ( index ( temp_string , ':' ) + 1 :) end if if (. not . is_fortran_name ( temp_string )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule parent' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , temp_string )) return end if f_source % modules_used ( n_use )% s = temp_string f_source % parent_modules ( n_parent )% s = temp_string f_source % modules_provided ( n_mod )% s = mod_name end if cycle end if ! Detect if contains a program ! (no modules allowed after program def) if ( index ( file_lines_lower ( i )% s , 'program ' ) == 1 ) then temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = ' ' , stat = stat ) if ( stat == 0 ) then if ( scan ( temp_string , '=(' ) > 0 ) then ! Ignore: ! program =* ! program (i) =* cycle end if end if f_source % unit_type = FPM_UNIT_PROGRAM cycle end if ! Parse end module statement ! (to check for code outside of modules) if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'module' ) . or . & parse_sequence ( file_lines_lower ( i )% s , 'end' , 'submodule' )) then inside_module = . false . cycle end if ! Any statements not yet parsed are assumed to be other code statements if (. not . inside_module . and . f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end do file_loop ! If unable to parse end of module statement, then can't assume pure module ! (there could be non-module subprograms present) if ( inside_module . and . f_source % unit_type == FPM_UNIT_MODULE ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if if ( pass == 1 ) then allocate ( f_source % modules_used ( n_use )) allocate ( f_source % include_dependencies ( n_include )) allocate ( f_source % modules_provided ( n_mod )) allocate ( f_source % parent_modules ( n_parent )) end if end do end function parse_f_source !> Parsing of c, cpp source files !> !> The following statements are recognised and parsed: !> !> - `#include` preprocessor statement !> function parse_c_source ( c_filename , error ) result ( c_source ) character ( * ), intent ( in ) :: c_filename type ( srcfile_t ) :: c_source type ( error_t ), allocatable , intent ( out ) :: error integer :: fh , n_include , i , pass , stat type ( string_t ), allocatable :: file_lines (:) c_source % file_name = c_filename if ( str_ends_with ( lower ( c_filename ), \".c\" )) then c_source % unit_type = FPM_UNIT_CSOURCE else if ( str_ends_with ( lower ( c_filename ), \".h\" )) then c_source % unit_type = FPM_UNIT_CHEADER else if ( str_ends_with ( lower ( c_filename ), \".cpp\" )) then c_source % unit_type = FPM_UNIT_CPPSOURCE end if allocate ( c_source % modules_used ( 0 )) allocate ( c_source % modules_provided ( 0 )) allocate ( c_source % parent_modules ( 0 )) open ( newunit = fh , file = c_filename , status = 'old' ) file_lines = read_lines ( fh ) close ( fh ) ! Ignore empty files, returned as FPM_UNIT_UNKNOWN if ( len_trim ( file_lines ) < 1 ) then c_source % unit_type = FPM_UNIT_UNKNOWN return end if c_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_include = 0 file_loop : do i = 1 , size ( file_lines ) ! Process 'INCLUDE' statements if ( index ( adjustl ( lower ( file_lines ( i )% s )), '#include' ) == 1 . and . & index ( file_lines ( i )% s , '\"' ) > 0 ) then n_include = n_include + 1 if ( pass == 2 ) then c_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , c_filename , & 'unable to get c include file' , i , & file_lines ( i )% s , index ( file_lines ( i )% s , '\"' )) return end if end if end if end do file_loop if ( pass == 1 ) then allocate ( c_source % include_dependencies ( n_include )) end if end do end function parse_c_source !> Split a string on one or more delimeters !> and return the nth substring if it exists !> !> n=0 will return the last item !> n=-1 will return the penultimate item etc. !> !> stat = 1 on return if the index !> is not found !> function split_n ( string , delims , n , stat ) result ( substring ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: delims integer , intent ( in ) :: n integer , intent ( out ) :: stat character (:), allocatable :: substring integer :: i character (:), allocatable :: string_parts (:) call split ( string , string_parts , delims ) if ( n < 1 ) then i = size ( string_parts ) + n if ( i < 1 ) then allocate ( character ( len = 0 ) :: substring ) ! ifort bus error otherwise stat = 1 return end if else i = n end if if ( i > size ( string_parts )) then allocate ( character ( len = 0 ) :: substring ) ! ifort bus error otherwise stat = 1 return end if substring = trim ( adjustl ( string_parts ( i ))) stat = 0 end function split_n !> Parse a subsequence of blank-separated tokens within a string !> (see parse_sequence) function parse_subsequence ( string , t1 , t2 , t3 , t4 ) result ( found ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: t1 character ( * ), intent ( in ), optional :: t2 , t3 , t4 logical :: found integer :: offset , i found = . false . offset = 1 do i = index ( string ( offset :), t1 ) if ( i == 0 ) return offset = offset + i - 1 found = parse_sequence ( string ( offset :), t1 , t2 , t3 , t4 ) if ( found ) return offset = offset + len ( t1 ) if ( offset > len ( string )) return end do end function parse_subsequence !> Helper utility to parse sequences of tokens !> that may be optionally separated by zero or more spaces function parse_sequence ( string , t1 , t2 , t3 , t4 ) result ( found ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: t1 character ( * ), intent ( in ), optional :: t2 , t3 , t4 logical :: found integer :: post , n , incr , pos , token_n logical :: match n = len ( string ) found = . false . pos = 1 do token_n = 1 , 4 do while ( pos <= n ) if ( string ( pos : pos ) /= ' ' ) then exit end if pos = pos + 1 end do select case ( token_n ) case ( 1 ) incr = len ( t1 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t1 case ( 2 ) if (. not . present ( t2 )) exit incr = len ( t2 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t2 case ( 3 ) if (. not . present ( t3 )) exit incr = len ( t3 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t3 case ( 4 ) if (. not . present ( t4 )) exit incr = len ( t4 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t4 case default exit end select if (. not . match ) then return end if pos = pos + incr end do found = . true . end function parse_sequence ! USE [, intrinsic] :: module_name [, only: only_list] ! USE [, non_intrinsic] :: module_name [, only: only_list] subroutine parse_use_statement ( f_filename , i , line , use_stmt , is_intrinsic , module_name , error ) !> Current file name and line number (for error messaging) character ( * ), intent ( in ) :: f_filename integer , intent ( in ) :: i !> The line being parsed. MUST BE preprocessed with trim(adjustl() character ( * ), intent ( in ) :: line !> Does this line contain a `use` statement? logical , intent ( out ) :: use_stmt !> Is the module in this statement intrinsic? logical , intent ( out ) :: is_intrinsic !> used module name character (:), allocatable , intent ( out ) :: module_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( 15 ), parameter :: INTRINSIC_NAMES ( * ) = & [ 'iso_c_binding ' , & 'iso_fortran_env' , & 'ieee_arithmetic' , & 'ieee_exceptions' , & 'ieee_features ' , & 'omp_lib ' ] character ( len = :), allocatable :: temp_string integer :: colons , intr , nonintr , j , stat logical :: has_intrinsic_name use_stmt = . false . is_intrinsic = . false . if ( len_trim ( line ) <= 0 ) return ! Quick check that the line is preprocessed if ( line ( 1 : 1 ) == ' ' ) then call fatal_error ( error , 'internal_error: source file line is not trim(adjustl()) on input to parse_use_statement' ) return end if ! 'use' should be the first string in the adjustl line use_stmt = index ( line , 'use ' ) == 1 . or . index ( line , 'use::' ) == 1 . or . index ( line , 'use,' ) == 1 if (. not . use_stmt ) return colons = index ( line , '::' ) nonintr = 0 intr = 0 have_colons : if ( colons > 3 ) then ! there may be an intrinsic/non-intrinsic spec nonintr = index ( line ( 1 : colons - 1 ), 'non_intrinsic' ) if ( nonintr == 0 ) intr = index ( line ( 1 : colons - 1 ), 'intrinsic' ) temp_string = split_n ( line , delims = ':' , n = 2 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line , colons ) return end if module_name = split_n ( temp_string , delims = ' ,' , n = 1 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if else module_name = split_n ( line , n = 2 , delims = ' ,' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if end if have_colons ! If declared intrinsic, check that it is true has_intrinsic_name = any ([( index ( module_name , trim ( INTRINSIC_NAMES ( j ))) > 0 , & j = 1 , size ( INTRINSIC_NAMES ))]) if ( intr > 0 . and . . not . has_intrinsic_name ) then ! An intrinsic module was not found. Its name could be in the next line, ! in which case, we just skip this check. The compiler will do the job if the name is invalid. ! Module name was not read: it's in the next line if ( index ( module_name , '&' ) <= 0 ) then call file_parse_error ( error , f_filename , & 'module ' // module_name // ' is declared intrinsic but it is not ' , i , & line ) return endif endif ! Should we treat this as an intrinsic module is_intrinsic = nonintr == 0 . and . & ! not declared non-intrinsic ( intr > 0 . or . has_intrinsic_name ) end subroutine parse_use_statement end module fpm_source_parsing","tags":"","loc":"sourcefile/fpm_source_parsing.f90.html"},{"title":"fpm_model.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_model Source Code fpm_model.f90 Source Code !># The fpm package model !> !> Defines the fpm model data types which encapsulate all information !> required to correctly build a package and its dependencies. !> !> The process (see `[[build_model(subroutine)]]`) for generating a valid `[[fpm_model]]` involves !> source files discovery ([[fpm_sources]]) and parsing ([[fpm_source_parsing]]). !> !> Once a valid `[[fpm_model]]` has been constructed, it may be passed to `[[fpm_targets:targets_from_sources]]` to !> generate a list of build targets for the backend. !> !>### Enumerations !> !> __Source type:__ `FPM_UNIT_*` !> Describes the type of source file — determines build target generation !> !> The logical order of precedence for assigning `unit_type` is as follows: !> !>``` !> if source-file contains program then !> unit_type = FPM_UNIT_PROGRAM !> else if source-file contains non-module subroutine/function then !> unit_type = FPM_UNIT_SUBPROGRAM !> else if source-file contains submodule then !> unit_type = FPM_UNIT_SUBMODULE !> else if source-file contains module then !> unit_type = FPM_UNIT_MODULE !> end if !>``` !> !> @note A source file is only designated `FPM_UNIT_MODULE` if it **only** contains modules - no non-module subprograms. !> (This allows tree-shaking/pruning of build targets based on unused module dependencies.) !> !> __Source scope:__ `FPM_SCOPE_*` !> Describes the scoping rules for using modules — controls module dependency resolution !> module fpm_model use iso_fortran_env , only : int64 use fpm_compiler , only : compiler_t , archiver_t , debug use fpm_dependency , only : dependency_tree_t use fpm_strings , only : string_t , str , len_trim implicit none private public :: fpm_model_t , srcfile_t , show_model , fortran_features_t public :: FPM_UNIT_UNKNOWN , FPM_UNIT_PROGRAM , FPM_UNIT_MODULE , & FPM_UNIT_SUBMODULE , FPM_UNIT_SUBPROGRAM , FPM_UNIT_CSOURCE , & FPM_UNIT_CHEADER , FPM_SCOPE_UNKNOWN , FPM_SCOPE_LIB , & FPM_SCOPE_DEP , FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST , & FPM_UNIT_CPPSOURCE !> Source type unknown integer , parameter :: FPM_UNIT_UNKNOWN = - 1 !> Source contains a fortran program integer , parameter :: FPM_UNIT_PROGRAM = 1 !> Source **only** contains one or more fortran modules integer , parameter :: FPM_UNIT_MODULE = 2 !> Source contains one or more fortran submodules integer , parameter :: FPM_UNIT_SUBMODULE = 3 !> Source contains one or more fortran subprogram not within modules integer , parameter :: FPM_UNIT_SUBPROGRAM = 4 !> Source type is c source file integer , parameter :: FPM_UNIT_CSOURCE = 5 !> Source type is c header file integer , parameter :: FPM_UNIT_CHEADER = 6 !> Souce type is c++ source file. integer , parameter :: FPM_UNIT_CPPSOURCE = 7 !> Source has no module-use scope integer , parameter :: FPM_SCOPE_UNKNOWN = - 1 !> Module-use scope is library/dependency modules only integer , parameter :: FPM_SCOPE_LIB = 1 !> Module-use scope is library/dependency modules only integer , parameter :: FPM_SCOPE_DEP = 2 !> Module-use scope is library/dependency and app modules integer , parameter :: FPM_SCOPE_APP = 3 !> Module-use scope is library/dependency and test modules integer , parameter :: FPM_SCOPE_TEST = 4 integer , parameter :: FPM_SCOPE_EXAMPLE = 5 !> Enabled Fortran language features type :: fortran_features_t !> Use default implicit typing logical :: implicit_typing = . false . !> Use implicit external interface logical :: implicit_external = . false . !> Form to use for all Fortran sources character (:), allocatable :: source_form end type fortran_features_t !> Type for describing a source file type srcfile_t !> File path relative to cwd character (:), allocatable :: file_name !> Name of executable for FPM_UNIT_PROGRAM character (:), allocatable :: exe_name !> Target module-use scope integer :: unit_scope = FPM_SCOPE_UNKNOWN !> Modules provided by this source file (lowerstring) type ( string_t ), allocatable :: modules_provided (:) !> Type of source unit integer :: unit_type = FPM_UNIT_UNKNOWN !> Parent modules (submodules only) type ( string_t ), allocatable :: parent_modules (:) !> Modules USEd by this source file (lowerstring) type ( string_t ), allocatable :: modules_used (:) !> Files INCLUDEd by this source file type ( string_t ), allocatable :: include_dependencies (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Current hash integer ( int64 ) :: digest end type srcfile_t !> Type for describing a single package type package_t !> Name of package character (:), allocatable :: name !> Array of sources type ( srcfile_t ), allocatable :: sources (:) !> List of macros. type ( string_t ), allocatable :: macros (:) !> Package version number. character (:), allocatable :: version !> Module naming conventions logical :: enforce_module_names !> Prefix for all module names type ( string_t ) :: module_prefix !> Language features type ( fortran_features_t ) :: features end type package_t !> Type describing everything required to build !> the root package and its dependencies. type :: fpm_model_t !> Name of root package character (:), allocatable :: package_name !> Array of packages (including the root package) type ( package_t ), allocatable :: packages (:) !> Compiler object type ( compiler_t ) :: compiler !> Archiver object type ( archiver_t ) :: archiver !> Command line flags passed to fortran for compilation character (:), allocatable :: fortran_compile_flags !> Command line flags passed to C for compilation character (:), allocatable :: c_compile_flags !> Command line flags passed to C++ for compilation character (:), allocatable :: cxx_compile_flags !> Command line flags passed to the linker character (:), allocatable :: link_flags !> Base directory for build character (:), allocatable :: build_prefix !> Include directories type ( string_t ), allocatable :: include_dirs (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> External modules used type ( string_t ), allocatable :: external_modules (:) !> Project dependencies type ( dependency_tree_t ) :: deps !> Whether tests should be added to the build list logical :: include_tests = . true . !> Whether module names should be prefixed with the package name logical :: enforce_module_names = . false . !> Prefix for all module names type ( string_t ) :: module_prefix end type fpm_model_t contains function info_package ( p ) result ( s ) ! Returns representation of package_t type ( package_t ), intent ( in ) :: p character (:), allocatable :: s integer :: i s = s // 'package_t(' s = s // 'name=\"' // p % name // '\"' s = s // ', sources=[' do i = 1 , size ( p % sources ) s = s // info_srcfile ( p % sources ( i )) if ( i < size ( p % sources )) s = s // \", \" end do s = s // \"]\" ! Print module naming convention s = s // ', enforce_module_names=\"' // merge ( 'T' , 'F' , p % enforce_module_names ) // '\"' ! Print custom prefix if ( p % enforce_module_names . and . len_trim ( p % module_prefix ) > 0 ) & s = s // ', custom_prefix=\"' // p % module_prefix % s // '\"' s = s // \")\" end function info_package function info_srcfile ( source ) result ( s ) type ( srcfile_t ), intent ( in ) :: source character (:), allocatable :: s integer :: i !type srcfile_t s = \"srcfile_t(\" ! character(:), allocatable :: file_name s = s // 'file_name=\"' // source % file_name // '\"' ! character(:), allocatable :: exe_name s = s // ', exe_name=\"' // source % exe_name // '\"' ! integer :: unit_scope = FPM_SCOPE_UNKNOWN s = s // \", unit_scope=\" select case ( source % unit_scope ) case ( FPM_SCOPE_UNKNOWN ) s = s // \"FPM_SCOPE_UNKNOWN\" case ( FPM_SCOPE_LIB ) s = s // \"FPM_SCOPE_LIB\" case ( FPM_SCOPE_DEP ) s = s // \"FPM_SCOPE_DEP\" case ( FPM_SCOPE_APP ) s = s // \"FPM_SCOPE_APP\" case ( FPM_SCOPE_TEST ) s = s // \"FPM_SCOPE_TEST\" case ( FPM_SCOPE_EXAMPLE ) s = s // \"FPM_SCOPE_EXAMPLE\" case default s = s // \"INVALID\" end select ! type(string_t), allocatable :: modules_provided(:) s = s // \", modules_provided=[\" do i = 1 , size ( source % modules_provided ) s = s // '\"' // source % modules_provided ( i )% s // '\"' if ( i < size ( source % modules_provided )) s = s // \", \" end do s = s // \"]\" s = s // \", parent_modules=[\" do i = 1 , size ( source % parent_modules ) s = s // '\"' // source % parent_modules ( i )% s // '\"' if ( i < size ( source % parent_modules )) s = s // \", \" end do s = s // \"]\" ! integer :: unit_type = FPM_UNIT_UNKNOWN s = s // \", unit_type=\" select case ( source % unit_type ) case ( FPM_UNIT_UNKNOWN ) s = s // \"FPM_UNIT_UNKNOWN\" case ( FPM_UNIT_PROGRAM ) s = s // \"FPM_UNIT_PROGRAM\" case ( FPM_UNIT_MODULE ) s = s // \"FPM_UNIT_MODULE\" case ( FPM_UNIT_SUBMODULE ) s = s // \"FPM_UNIT_SUBMODULE\" case ( FPM_UNIT_SUBPROGRAM ) s = s // \"FPM_UNIT_SUBPROGRAM\" case ( FPM_UNIT_CSOURCE ) s = s // \"FPM_UNIT_CSOURCE\" case ( FPM_UNIT_CPPSOURCE ) s = s // \"FPM_UNIT_CPPSOURCE\" case ( FPM_UNIT_CHEADER ) s = s // \"FPM_UNIT_CHEADER\" case default s = s // \"INVALID\" end select ! type(string_t), allocatable :: modules_used(:) s = s // \", modules_used=[\" do i = 1 , size ( source % modules_used ) s = s // '\"' // source % modules_used ( i )% s // '\"' if ( i < size ( source % modules_used )) s = s // \", \" end do s = s // \"]\" ! type(string_t), allocatable :: include_dependencies(:) s = s // \", include_dependencies=[\" do i = 1 , size ( source % include_dependencies ) s = s // '\"' // source % include_dependencies ( i )% s // '\"' if ( i < size ( source % include_dependencies )) s = s // \", \" end do s = s // \"]\" ! type(string_t), allocatable :: link_libraries(:) s = s // \", link_libraries=[\" do i = 1 , size ( source % link_libraries ) s = s // '\"' // source % link_libraries ( i )% s // '\"' if ( i < size ( source % link_libraries )) s = s // \", \" end do s = s // \"]\" ! integer(int64) :: digest s = s // \", digest=\" // str ( source % digest ) !end type srcfile_t s = s // \")\" end function info_srcfile function info_srcfile_short ( source ) result ( s ) ! Prints a shortened version of srcfile_t type ( srcfile_t ), intent ( in ) :: source character (:), allocatable :: s s = \"srcfile_t(\" s = s // 'file_name=\"' // source % file_name // '\"' s = s // \", ...)\" end function info_srcfile_short function info_model ( model ) result ( s ) type ( fpm_model_t ), intent ( in ) :: model character (:), allocatable :: s integer :: i !type :: fpm_model_t s = \"fpm_model_t(\" ! character(:), allocatable :: package_name s = s // 'package_name=\"' // model % package_name // '\"' ! type(srcfile_t), allocatable :: sources(:) s = s // \", packages=[\" do i = 1 , size ( model % packages ) s = s // info_package ( model % packages ( i )) if ( i < size ( model % packages )) s = s // \", \" end do s = s // \"]\" s = s // ', compiler=(' // debug ( model % compiler ) // ')' s = s // ', archiver=(' // debug ( model % archiver ) // ')' ! character(:), allocatable :: fortran_compile_flags s = s // ', fortran_compile_flags=\"' // model % fortran_compile_flags // '\"' s = s // ', c_compile_flags=\"' // model % c_compile_flags // '\"' s = s // ', cxx_compile_flags=\"' // model % cxx_compile_flags // '\"' s = s // ', link_flags=\"' // model % link_flags // '\"' s = s // ', build_prefix=\"' // model % build_prefix // '\"' ! type(string_t), allocatable :: link_libraries(:) s = s // \", link_libraries=[\" do i = 1 , size ( model % link_libraries ) s = s // '\"' // model % link_libraries ( i )% s // '\"' if ( i < size ( model % link_libraries )) s = s // \", \" end do s = s // \"]\" ! type(string_t), allocatable :: external_modules(:) s = s // \", external_modules=[\" do i = 1 , size ( model % external_modules ) s = s // '\"' // model % external_modules ( i )% s // '\"' if ( i < size ( model % external_modules )) s = s // \", \" end do s = s // \"]\" ! type(dependency_tree_t) :: deps ! TODO: print `dependency_tree_t` properly, which should become part of the ! model, not imported from another file s = s // \", deps=dependency_tree_t(...)\" ! Print module naming convention s = s // ', enforce_module_names=\"' // merge ( 'T' , 'F' , model % enforce_module_names ) // '\"' ! Print custom prefix if ( model % enforce_module_names . and . len_trim ( model % module_prefix ) > 0 ) & s = s // ', custom_prefix=\"' // model % module_prefix % s // '\"' !end type fpm_model_t s = s // \")\" end function info_model subroutine show_model ( model ) ! Prints a human readable representation of the Model type ( fpm_model_t ), intent ( in ) :: model print * , info_model ( model ) end subroutine show_model end module fpm_model","tags":"","loc":"sourcefile/fpm_model.f90.html"},{"title":"fpm_targets.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_targets Source Code fpm_targets.f90 Source Code !># Build target handling !> !> This module handles the construction of the build target list !> from the sources list (`[[targets_from_sources]]`), the !> resolution of module-dependencies between build targets !> (`[[resolve_module_dependencies]]`), and the enumeration of !> objects required for link targets (`[[resolve_target_linking]]`). !> !> A build target (`[[build_target_t]]`) is a file to be generated !> by the backend (compilation and linking). !> !> @note The current implementation is ignorant to the existence of !> module files (`.mod`,`.smod`). Dependencies arising from modules !> are based on the corresponding object files (`.o`) only. !> !> For more information, please read the documentation for the procedures: !> !> - `[[build_target_list]]` !> - `[[resolve_module_dependencies]]` !> !>### Enumerations !> !> __Target type:__ `FPM_TARGET_*` !> Describes the type of build target — determines backend build rules !> module fpm_targets use iso_fortran_env , only : int64 use fpm_error , only : error_t , fatal_error , fpm_stop use fpm_model use fpm_compiler , only : compiler_t use fpm_environment , only : get_os_type , OS_WINDOWS , OS_MACOS use fpm_filesystem , only : dirname , join_path , canon_path use fpm_strings , only : string_t , operator (. in .), string_cat , fnv_1a , resize , lower , str_ends_with use fpm_compiler , only : get_macros use fpm_sources , only : get_exe_name_with_suffix implicit none private public FPM_TARGET_UNKNOWN , FPM_TARGET_EXECUTABLE , & FPM_TARGET_ARCHIVE , FPM_TARGET_OBJECT , & FPM_TARGET_C_OBJECT , FPM_TARGET_CPP_OBJECT public build_target_t , build_target_ptr public targets_from_sources , resolve_module_dependencies public add_target , add_dependency public filter_library_targets , filter_executable_targets , filter_modules !> Target type is unknown (ignored) integer , parameter :: FPM_TARGET_UNKNOWN = - 1 !> Target type is executable integer , parameter :: FPM_TARGET_EXECUTABLE = 1 !> Target type is library archive integer , parameter :: FPM_TARGET_ARCHIVE = 2 !> Target type is compiled object integer , parameter :: FPM_TARGET_OBJECT = 3 !> Target type is c compiled object integer , parameter :: FPM_TARGET_C_OBJECT = 4 !> Target type is cpp compiled object integer , parameter :: FPM_TARGET_CPP_OBJECT = 5 !> Wrapper type for constructing arrays of `[[build_target_t]]` pointers type build_target_ptr type ( build_target_t ), pointer :: ptr => null () end type build_target_ptr !> Type describing a generated build target type build_target_t !> File path of build target object relative to cwd character (:), allocatable :: output_file !> File path of build target object relative to output_dir character (:), allocatable :: output_name !> File path of output directory character (:), allocatable :: output_dir !> File path of build log file relative to cwd character (:), allocatable :: output_log_file !> Name of parent package character (:), allocatable :: package_name !> Primary source for this build target type ( srcfile_t ), allocatable :: source !> Resolved build dependencies type ( build_target_ptr ), allocatable :: dependencies (:) !> Target type integer :: target_type = FPM_TARGET_UNKNOWN !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Objects needed to link this target type ( string_t ), allocatable :: link_objects (:) !> Link flags for this build target character (:), allocatable :: link_flags !> Compile flags for this build target character (:), allocatable :: compile_flags !> Flag set when first visited to check for circular dependencies logical :: touched = . false . !> Flag set if build target is sorted for building logical :: sorted = . false . !> Flag set if build target will be skipped (not built) logical :: skip = . false . !> Language features type ( fortran_features_t ) :: features !> Targets in the same schedule group are guaranteed to be independent integer :: schedule = - 1 !> Previous source file hash integer ( int64 ), allocatable :: digest_cached !> List of macros type ( string_t ), allocatable :: macros (:) !> Version number character (:), allocatable :: version end type build_target_t contains !> High-level wrapper to generate build target information subroutine targets_from_sources ( targets , model , prune , error ) !> The generated list of build targets type ( build_target_ptr ), intent ( out ), allocatable :: targets (:) !> The package model from which to construct the target list type ( fpm_model_t ), intent ( inout ), target :: model !> Enable tree-shaking/pruning of module dependencies logical , intent ( in ) :: prune !> Error structure type ( error_t ), intent ( out ), allocatable :: error call build_target_list ( targets , model ) call collect_exe_link_dependencies ( targets ) call resolve_module_dependencies ( targets , model % external_modules , error ) if ( allocated ( error )) return if ( prune ) then call prune_build_targets ( targets , root_package = model % package_name ) end if call resolve_target_linking ( targets , model ) end subroutine targets_from_sources !> Constructs a list of build targets from a list of source files !> !>### Source-target mapping !> !> One compiled object target (`FPM_TARGET_OBJECT`) is generated for each !> non-executable source file (`FPM_UNIT_MODULE`,`FPM_UNIT_SUBMODULE`, !> `FPM_UNIT_SUBPROGRAM`,`FPM_UNIT_CSOURCE`). !> !> If any source file has scope `FPM_SCOPE_LIB` (*i.e.* there are library sources) !> then the first target in the target list will be a library archive target !> (`FPM_TARGET_ARCHIVE`). The archive target will have a dependency on every !> compiled object target corresponding to a library source file. !> !> One compiled object target (`FPM_TARGET_OBJECT`) and one executable target (`FPM_TARGET_EXECUTABLE`) is !> generated for each exectuable source file (`FPM_UNIT_PROGRAM`). The exectuble target !> always has a dependency on the corresponding compiled object target. If there !> is a library, then the executable target has an additional dependency on the library !> archive target. !> subroutine build_target_list ( targets , model ) !> The generated list of build targets type ( build_target_ptr ), intent ( out ), allocatable :: targets (:) !> The package model from which to construct the target list type ( fpm_model_t ), intent ( inout ), target :: model integer :: i , j , n_source , exe_type character (:), allocatable :: exe_dir , compile_flags logical :: with_lib ! Initialize targets allocate ( targets ( 0 )) ! Check for empty build (e.g. header-only lib) n_source = sum ([( size ( model % packages ( j )% sources ), & j = 1 , size ( model % packages ))]) if ( n_source < 1 ) return with_lib = any ([(( model % packages ( j )% sources ( i )% unit_scope == FPM_SCOPE_LIB , & i = 1 , size ( model % packages ( j )% sources )), & j = 1 , size ( model % packages ))]) if ( with_lib ) call add_target ( targets , package = model % package_name , type = FPM_TARGET_ARCHIVE ,& output_name = join_path (& model % package_name , 'lib' // model % package_name // '.a' )) do j = 1 , size ( model % packages ) associate ( sources => model % packages ( j )% sources ) do i = 1 , size ( sources ) if (. not . model % include_tests ) then if ( sources ( i )% unit_scope == FPM_SCOPE_TEST ) cycle end if select case ( sources ( i )% unit_type ) case ( FPM_UNIT_MODULE , FPM_UNIT_SUBMODULE , FPM_UNIT_SUBPROGRAM , FPM_UNIT_CSOURCE ) call add_target ( targets , package = model % packages ( j )% name , source = sources ( i ), & type = merge ( FPM_TARGET_C_OBJECT , FPM_TARGET_OBJECT ,& sources ( i )% unit_type == FPM_UNIT_CSOURCE ), & output_name = get_object_name ( sources ( i )), & features = model % packages ( j )% features , & macros = model % packages ( j )% macros , & version = model % packages ( j )% version ) if ( with_lib . and . sources ( i )% unit_scope == FPM_SCOPE_LIB ) then ! Archive depends on object call add_dependency ( targets ( 1 )% ptr , targets ( size ( targets ))% ptr ) end if case ( FPM_UNIT_CPPSOURCE ) call add_target ( targets , package = model % packages ( j )% name , source = sources ( i ), & type = FPM_TARGET_CPP_OBJECT , & output_name = get_object_name ( sources ( i )), & macros = model % packages ( j )% macros , & version = model % packages ( j )% version ) if ( with_lib . and . sources ( i )% unit_scope == FPM_SCOPE_LIB ) then ! Archive depends on object call add_dependency ( targets ( 1 )% ptr , targets ( size ( targets ))% ptr ) end if !> Add stdc++ as a linker flag. If not already there. if (. not . ( \"stdc++\" . in . model % link_libraries )) then if ( get_os_type () == OS_MACOS ) then model % link_libraries = [ model % link_libraries , string_t ( \"c++\" )] else model % link_libraries = [ model % link_libraries , string_t ( \"stdc++\" )] end if end if case ( FPM_UNIT_PROGRAM ) if ( str_ends_with ( lower ( sources ( i )% file_name ), [ \".c\" ])) then exe_type = FPM_TARGET_C_OBJECT else if ( str_ends_with ( lower ( sources ( i )% file_name ), [ \".cpp\" , \".cc \" ])) then exe_type = FPM_TARGET_CPP_OBJECT else ! Default to a Fortran object exe_type = FPM_TARGET_OBJECT end if call add_target ( targets , package = model % packages ( j )% name , type = exe_type ,& output_name = get_object_name ( sources ( i )), & source = sources ( i ), & features = model % packages ( j )% features , & macros = model % packages ( j )% macros & ) if ( sources ( i )% unit_scope == FPM_SCOPE_APP ) then exe_dir = 'app' else if ( sources ( i )% unit_scope == FPM_SCOPE_EXAMPLE ) then exe_dir = 'example' else exe_dir = 'test' end if call add_target ( targets , package = model % packages ( j )% name , type = FPM_TARGET_EXECUTABLE ,& link_libraries = sources ( i )% link_libraries , & output_name = join_path ( exe_dir , get_exe_name_with_suffix ( sources ( i )))) associate ( target => targets ( size ( targets ))% ptr ) ! Linker-only flags are necessary on some compilers for codes with non-Fortran main select case ( exe_type ) case ( FPM_TARGET_C_OBJECT ) call model % compiler % get_main_flags ( \"c\" , compile_flags ) case ( FPM_TARGET_CPP_OBJECT ) call model % compiler % get_main_flags ( \"c++\" , compile_flags ) case default compile_flags = \"\" end select target % compile_flags = target % compile_flags // ' ' // compile_flags ! Executable depends on object call add_dependency ( target , targets ( size ( targets ) - 1 )% ptr ) if ( with_lib ) then ! Executable depends on library call add_dependency ( target , targets ( 1 )% ptr ) end if endassociate end select end do end associate end do contains function get_object_name ( source ) result ( object_file ) ! Generate object target path from source name and model params ! ! type ( srcfile_t ), intent ( in ) :: source character (:), allocatable :: object_file integer :: i character ( 1 ), parameter :: filesep = '/' object_file = canon_path ( source % file_name ) ! Convert any remaining directory separators to underscores i = index ( object_file , filesep ) do while ( i > 0 ) object_file ( i : i ) = '_' i = index ( object_file , filesep ) end do object_file = join_path ( model % package_name , object_file ) // '.o' end function get_object_name end subroutine build_target_list !> Add non-library non-module dependencies for executable targets !> !> Executable targets will link to any non-program non-module source files that !> are in the same directory or in a subdirectory. !> !> (Note: Fortran module dependencies are handled separately in !> `resolve_module_dependencies` and `resolve_target_linking`.) !> subroutine collect_exe_link_dependencies ( targets ) type ( build_target_ptr ), intent ( inout ) :: targets (:) integer :: i , j character (:), allocatable :: exe_source_dir ! Add non-module dependencies for executables do j = 1 , size ( targets ) if ( targets ( j )% ptr % target_type == FPM_TARGET_EXECUTABLE ) then do i = 1 , size ( targets ) if ( i == j ) cycle associate ( exe => targets ( j )% ptr , dep => targets ( i )% ptr ) exe_source_dir = dirname ( exe % dependencies ( 1 )% ptr % source % file_name ) if ( allocated ( dep % source )) then if ( dep % source % unit_scope /= FPM_SCOPE_LIB . and . & dep % source % unit_type /= FPM_UNIT_PROGRAM . and . & dep % source % unit_type /= FPM_UNIT_MODULE . and . & index ( dirname ( dep % source % file_name ), exe_source_dir ) == 1 ) then call add_dependency ( exe , dep ) end if end if end associate end do end if end do end subroutine collect_exe_link_dependencies !> Allocate a new target and append to target list subroutine add_target ( targets , package , type , output_name , source , link_libraries , & & features , macros , version ) type ( build_target_ptr ), allocatable , intent ( inout ) :: targets (:) character ( * ), intent ( in ) :: package integer , intent ( in ) :: type character ( * ), intent ( in ) :: output_name type ( srcfile_t ), intent ( in ), optional :: source type ( string_t ), intent ( in ), optional :: link_libraries (:) type ( fortran_features_t ), intent ( in ), optional :: features type ( string_t ), intent ( in ), optional :: macros (:) character ( * ), intent ( in ), optional :: version integer :: i type ( build_target_t ), pointer :: new_target if (. not . allocated ( targets )) allocate ( targets ( 0 )) ! Check for duplicate outputs do i = 1 , size ( targets ) if ( targets ( i )% ptr % output_name == output_name ) then write ( * , * ) 'Error while building target list: duplicate output object \"' ,& output_name , '\"' if ( present ( source )) write ( * , * ) ' Source file: \"' , source % file_name , '\"' call fpm_stop ( 1 , ' ' ) end if end do allocate ( new_target ) new_target % target_type = type new_target % output_name = output_name new_target % package_name = package if ( present ( source )) new_target % source = source if ( present ( link_libraries )) new_target % link_libraries = link_libraries if ( present ( features )) new_target % features = features if ( present ( macros )) new_target % macros = macros if ( present ( version )) new_target % version = version allocate ( new_target % dependencies ( 0 )) targets = [ targets , build_target_ptr ( new_target )] end subroutine add_target !> Add pointer to dependeny in target%dependencies subroutine add_dependency ( target , dependency ) type ( build_target_t ), intent ( inout ) :: target type ( build_target_t ) , intent ( in ), target :: dependency target % dependencies = [ target % dependencies , build_target_ptr ( dependency )] end subroutine add_dependency !> Add dependencies to source-based targets (`FPM_TARGET_OBJECT`) !> based on any modules used by the corresponding source file. !> !>### Source file scoping !> !> Source files are assigned a scope of either `FPM_SCOPE_LIB`, !> `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`. The scope controls which !> modules may be used by the source file: !> !> - Library sources (`FPM_SCOPE_LIB`) may only use modules !> also with library scope. This includes library modules !> from dependencies. !> !> - Executable sources (`FPM_SCOPE_APP`,`FPM_SCOPE_TEST`) may use !> library modules (including dependencies) as well as any modules !> corresponding to source files in the same directory or a !> subdirectory of the executable source file. !> !> @warning If a module used by a source file cannot be resolved to !> a source file in the package of the correct scope, then a __fatal error__ !> is returned by the procedure and model construction fails. !> subroutine resolve_module_dependencies ( targets , external_modules , error ) type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( string_t ), intent ( in ) :: external_modules (:) type ( error_t ), allocatable , intent ( out ) :: error type ( build_target_ptr ) :: dep integer :: i , j do i = 1 , size ( targets ) if (. not . allocated ( targets ( i )% ptr % source )) cycle do j = 1 , size ( targets ( i )% ptr % source % modules_used ) if ( targets ( i )% ptr % source % modules_used ( j )% s . in . targets ( i )% ptr % source % modules_provided ) then ! Dependency satisfied in same file, skip cycle end if if ( targets ( i )% ptr % source % modules_used ( j )% s . in . external_modules ) then ! Dependency satisfied in system-installed module cycle end if if ( any ( targets ( i )% ptr % source % unit_scope == & [ FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST ])) then dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s , & include_dir = dirname ( targets ( i )% ptr % source % file_name )) else dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s ) end if if (. not . associated ( dep % ptr )) then call fatal_error ( error , & 'Unable to find source for module dependency: \"' // & targets ( i )% ptr % source % modules_used ( j )% s // & '\" used by \"' // targets ( i )% ptr % source % file_name // '\"' ) return end if call add_dependency ( targets ( i )% ptr , dep % ptr ) end do end do end subroutine resolve_module_dependencies function find_module_dependency ( targets , module_name , include_dir ) result ( target_ptr ) ! Find a module dependency in the library or a dependency library ! ! 'include_dir' specifies an allowable non-library search directory ! (Used for executable dependencies) ! type ( build_target_ptr ), intent ( in ), target :: targets (:) character ( * ), intent ( in ) :: module_name character ( * ), intent ( in ), optional :: include_dir type ( build_target_t ), pointer :: target_ptr integer :: k , l target_ptr => NULL () do k = 1 , size ( targets ) if (. not . allocated ( targets ( k )% ptr % source )) cycle do l = 1 , size ( targets ( k )% ptr % source % modules_provided ) if ( module_name == targets ( k )% ptr % source % modules_provided ( l )% s ) then select case ( targets ( k )% ptr % source % unit_scope ) case ( FPM_SCOPE_LIB , FPM_SCOPE_DEP ) target_ptr => targets ( k )% ptr exit case default if ( present ( include_dir )) then if ( index ( dirname ( targets ( k )% ptr % source % file_name ), include_dir ) == 1 ) then ! source file is within the include_dir or a subdirectory target_ptr => targets ( k )% ptr exit end if end if end select end if end do end do end function find_module_dependency !> Perform tree-shaking to remove unused module targets subroutine prune_build_targets ( targets , root_package ) !> Build target list to prune type ( build_target_ptr ), intent ( inout ), allocatable :: targets (:) !> Name of root package character ( * ), intent ( in ) :: root_package integer :: i , j , nexec type ( string_t ), allocatable :: modules_used (:) logical :: exclude_target ( size ( targets )) logical , allocatable :: exclude_from_archive (:) if ( size ( targets ) < 1 ) then return end if nexec = 0 allocate ( modules_used ( 0 )) ! Enumerate modules used by executables, non-module subprograms and their dependencies do i = 1 , size ( targets ) if ( targets ( i )% ptr % target_type == FPM_TARGET_EXECUTABLE ) then nexec = nexec + 1 call collect_used_modules ( targets ( i )% ptr ) elseif ( allocated ( targets ( i )% ptr % source )) then if ( targets ( i )% ptr % source % unit_type == FPM_UNIT_SUBPROGRAM ) then call collect_used_modules ( targets ( i )% ptr ) end if end if end do ! If there aren't any executables, then prune ! based on modules used in root package if ( nexec < 1 ) then do i = 1 , size ( targets ) if ( targets ( i )% ptr % package_name == root_package . and . & targets ( i )% ptr % target_type /= FPM_TARGET_ARCHIVE ) then call collect_used_modules ( targets ( i )% ptr ) end if end do end if call reset_target_flags ( targets ) exclude_target (:) = . false . ! Exclude purely module targets if they are not used anywhere do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( allocated ( target % source )) then if ( target % source % unit_type == FPM_UNIT_MODULE ) then exclude_target ( i ) = . true . target % skip = . true . do j = 1 , size ( target % source % modules_provided ) if ( target % source % modules_provided ( j )% s . in . modules_used ) then exclude_target ( i ) = . false . target % skip = . false . end if end do elseif ( target % source % unit_type == FPM_UNIT_SUBMODULE ) then ! Remove submodules if their parents are not used exclude_target ( i ) = . true . target % skip = . true . do j = 1 , size ( target % source % parent_modules ) if ( target % source % parent_modules ( j )% s . in . modules_used ) then exclude_target ( i ) = . false . target % skip = . false . end if end do end if end if ! (If there aren't any executables then we only prune modules from dependencies) if ( nexec < 1 . and . target % package_name == root_package ) then exclude_target ( i ) = . false . target % skip = . false . end if end associate end do targets = pack ( targets ,. not . exclude_target ) ! Remove unused targets from archive dependency list if ( targets ( 1 )% ptr % target_type == FPM_TARGET_ARCHIVE ) then associate ( archive => targets ( 1 )% ptr ) allocate ( exclude_from_archive ( size ( archive % dependencies ))) exclude_from_archive (:) = . false . do i = 1 , size ( archive % dependencies ) if ( archive % dependencies ( i )% ptr % skip ) then exclude_from_archive ( i ) = . true . end if end do archive % dependencies = pack ( archive % dependencies ,. not . exclude_from_archive ) end associate end if contains !> Recursively collect which modules are actually used recursive subroutine collect_used_modules ( target ) type ( build_target_t ), intent ( inout ) :: target integer :: j , k if ( target % touched ) then return else target % touched = . true . end if if ( allocated ( target % source )) then ! Add modules from this target and from any of it's children submodules do j = 1 , size ( target % source % modules_provided ) if (. not .( target % source % modules_provided ( j )% s . in . modules_used )) then modules_used = [ modules_used , target % source % modules_provided ( j )] end if ! Recurse into child submodules do k = 1 , size ( targets ) if ( allocated ( targets ( k )% ptr % source )) then if ( targets ( k )% ptr % source % unit_type == FPM_UNIT_SUBMODULE ) then if ( target % source % modules_provided ( j )% s . in . targets ( k )% ptr % source % parent_modules ) then call collect_used_modules ( targets ( k )% ptr ) end if end if end if end do end do end if ! Recurse into dependencies do j = 1 , size ( target % dependencies ) if ( target % dependencies ( j )% ptr % target_type /= FPM_TARGET_ARCHIVE ) then call collect_used_modules ( target % dependencies ( j )% ptr ) end if end do end subroutine collect_used_modules !> Reset target flags after recursive search subroutine reset_target_flags ( targets ) type ( build_target_ptr ), intent ( inout ) :: targets (:) integer :: i do i = 1 , size ( targets ) targets ( i )% ptr % touched = . false . end do end subroutine reset_target_flags end subroutine prune_build_targets !> Construct the linker flags string for each target !> `target%link_flags` includes non-library objects and library flags !> subroutine resolve_target_linking ( targets , model ) type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( fpm_model_t ), intent ( in ) :: model integer :: i character (:), allocatable :: global_link_flags , local_link_flags character (:), allocatable :: global_include_flags if ( size ( targets ) == 0 ) return global_link_flags = \"\" if ( allocated ( model % link_libraries )) then if ( size ( model % link_libraries ) > 0 ) then global_link_flags = model % compiler % enumerate_libraries ( global_link_flags , model % link_libraries ) end if end if allocate ( character ( 0 ) :: global_include_flags ) if ( allocated ( model % include_dirs )) then if ( size ( model % include_dirs ) > 0 ) then global_include_flags = global_include_flags // & & \" -I\" // string_cat ( model % include_dirs , \" -I\" ) end if end if do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) ! If the main program is a C/C++ one, some compilers require additional linking flags, see ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main ! In this case, compile_flags were already allocated if (. not . allocated ( target % compile_flags )) allocate ( character ( len = 0 ) :: target % compile_flags ) target % compile_flags = target % compile_flags // ' ' select case ( target % target_type ) case ( FPM_TARGET_C_OBJECT ) target % compile_flags = target % compile_flags // model % c_compile_flags case ( FPM_TARGET_CPP_OBJECT ) target % compile_flags = target % compile_flags // model % cxx_compile_flags case default target % compile_flags = target % compile_flags // model % fortran_compile_flags & & // get_feature_flags ( model % compiler , target % features ) end select !> Get macros as flags. target % compile_flags = target % compile_flags // get_macros ( model % compiler % id , & target % macros , & target % version ) if ( len ( global_include_flags ) > 0 ) then target % compile_flags = target % compile_flags // global_include_flags end if target % output_dir = get_output_dir ( model % build_prefix , target % compile_flags ) target % output_file = join_path ( target % output_dir , target % output_name ) target % output_log_file = join_path ( target % output_dir , target % output_name ) // '.log' end associate end do call add_include_build_dirs ( model , targets ) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) allocate ( target % link_objects ( 0 )) if ( target % target_type == FPM_TARGET_ARCHIVE ) then global_link_flags = target % output_file // global_link_flags call get_link_objects ( target % link_objects , target , is_exe = . false .) allocate ( character ( 0 ) :: target % link_flags ) else if ( target % target_type == FPM_TARGET_EXECUTABLE ) then call get_link_objects ( target % link_objects , target , is_exe = . true .) local_link_flags = \"\" if ( allocated ( model % link_flags )) local_link_flags = model % link_flags target % link_flags = model % link_flags // \" \" // string_cat ( target % link_objects , \" \" ) if ( allocated ( target % link_libraries )) then if ( size ( target % link_libraries ) > 0 ) then target % link_flags = model % compiler % enumerate_libraries ( target % link_flags , target % link_libraries ) local_link_flags = model % compiler % enumerate_libraries ( local_link_flags , target % link_libraries ) end if end if target % link_flags = target % link_flags // \" \" // global_link_flags target % output_dir = get_output_dir ( model % build_prefix , & & target % compile_flags // local_link_flags ) target % output_file = join_path ( target % output_dir , target % output_name ) target % output_log_file = join_path ( target % output_dir , target % output_name ) // '.log' end if end associate end do contains !> Wrapper to build link object list !> !> For libraries: just list dependency objects of lib target !> !> For executables: need to recursively discover non-library !> dependency objects. (i.e. modules in same dir as program) !> recursive subroutine get_link_objects ( link_objects , target , is_exe ) type ( string_t ), intent ( inout ), allocatable :: link_objects (:) type ( build_target_t ), intent ( in ) :: target logical , intent ( in ) :: is_exe integer :: i type ( string_t ) :: temp_str if (. not . allocated ( target % dependencies )) return do i = 1 , size ( target % dependencies ) associate ( dep => target % dependencies ( i )% ptr ) if (. not . allocated ( dep % source )) cycle ! Skip library dependencies for executable targets ! since the library archive will always be linked if ( is_exe . and .( dep % source % unit_scope == FPM_SCOPE_LIB )) cycle ! Skip if dependency object already listed if ( dep % output_file . in . link_objects ) cycle ! Add dependency object file to link object list temp_str % s = dep % output_file link_objects = [ link_objects , temp_str ] ! For executable objects, also need to include non-library ! dependencies from dependencies (recurse) if ( is_exe ) call get_link_objects ( link_objects , dep , is_exe = . true .) end associate end do end subroutine get_link_objects end subroutine resolve_target_linking subroutine add_include_build_dirs ( model , targets ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_ptr ), intent ( inout ), target :: targets (:) integer :: i type ( string_t ), allocatable :: build_dirs (:) type ( string_t ) :: temp allocate ( build_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % target_type /= FPM_TARGET_OBJECT ) cycle if ( target % output_dir . in . build_dirs ) cycle temp % s = target % output_dir build_dirs = [ build_dirs , temp ] end associate end do do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % target_type /= FPM_TARGET_OBJECT ) cycle target % compile_flags = target % compile_flags // & \" \" // model % compiler % get_module_flag ( target % output_dir ) // & \" -I\" // string_cat ( build_dirs , \" -I\" ) end associate end do end subroutine add_include_build_dirs function get_output_dir ( build_prefix , args ) result ( path ) character ( len =* ), intent ( in ) :: build_prefix character ( len =* ), intent ( in ) :: args character ( len = :), allocatable :: path character ( len = 16 ) :: build_hash write ( build_hash , '(z16.16)' ) fnv_1a ( args ) path = build_prefix // \"_\" // build_hash end function get_output_dir subroutine filter_library_targets ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( targets ( i )% ptr % target_type == FPM_TARGET_ARCHIVE ) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_library_targets subroutine filter_executable_targets ( targets , scope , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) integer , intent ( in ) :: scope type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( is_executable_target ( targets ( i )% ptr , scope )) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_executable_targets elemental function is_executable_target ( target_ptr , scope ) result ( is_exe ) type ( build_target_t ), intent ( in ) :: target_ptr integer , intent ( in ) :: scope logical :: is_exe is_exe = target_ptr % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( target_ptr % dependencies ) if ( is_exe ) then is_exe = target_ptr % dependencies ( 1 )% ptr % source % unit_scope == scope end if end function is_executable_target subroutine filter_modules ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , j , n n = 0 call resize ( list ) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if (. not . allocated ( target % source )) cycle if ( target % source % unit_type == FPM_UNIT_SUBMODULE ) cycle if ( n + size ( target % source % modules_provided ) >= size ( list )) call resize ( list ) do j = 1 , size ( target % source % modules_provided ) n = n + 1 list ( n )% s = join_path ( target % output_dir , & target % source % modules_provided ( j )% s ) end do end associate end do call resize ( list , n ) end subroutine filter_modules function get_feature_flags ( compiler , features ) result ( flags ) type ( compiler_t ), intent ( in ) :: compiler type ( fortran_features_t ), intent ( in ) :: features character (:), allocatable :: flags flags = \"\" if ( features % implicit_typing ) then flags = flags // compiler % get_feature_flag ( \"implicit-typing\" ) else flags = flags // compiler % get_feature_flag ( \"no-implicit-typing\" ) end if if ( features % implicit_external ) then flags = flags // compiler % get_feature_flag ( \"implicit-external\" ) else flags = flags // compiler % get_feature_flag ( \"no-implicit-external\" ) end if if ( allocated ( features % source_form )) then flags = flags // compiler % get_feature_flag ( features % source_form // \"-form\" ) end if end function get_feature_flags end module fpm_targets","tags":"","loc":"sourcefile/fpm_targets.f90.html"},{"title":"downloader.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_downloader Source Code downloader.f90 Source Code module fpm_downloader use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : which , run use fpm_versioning , only : version_t use jonquil , only : json_object , json_value , json_error , json_load , cast_to_object use fpm_strings , only : string_t implicit none private public :: downloader_t !> This type could be entirely avoided but it is quite practical because it can be mocked for testing. type downloader_t contains procedure , nopass :: get_pkg_data , get_file , upload_form , unpack end type contains !> Perform an http get request, save output to file, and parse json. subroutine get_pkg_data ( url , version , tmp_pkg_file , json , error ) character ( * ), intent ( in ) :: url type ( version_t ), allocatable , intent ( in ) :: version character ( * ), intent ( in ) :: tmp_pkg_file type ( json_object ), intent ( out ) :: json type ( error_t ), allocatable , intent ( out ) :: error class ( json_value ), allocatable :: j_value type ( json_object ), pointer :: ptr type ( json_error ), allocatable :: j_error if ( allocated ( version )) then ! Request specific version. call get_file ( url // '/' // version % s (), tmp_pkg_file , error ) else ! Request latest version. call get_file ( url , tmp_pkg_file , error ) end if if ( allocated ( error )) return call json_load ( j_value , tmp_pkg_file , error = j_error ) if ( allocated ( j_error )) then allocate ( error ); call move_alloc ( j_error % message , error % message ); call json % destroy (); return end if ptr => cast_to_object ( j_value ) if (. not . associated ( ptr )) then call fatal_error ( error , \"Error parsing JSON from '\" // url // \"'.\" ); return end if json = ptr end !> Download a file from a url using either curl or wget. subroutine get_file ( url , tmp_pkg_file , error ) character ( * ), intent ( in ) :: url character ( * ), intent ( in ) :: tmp_pkg_file type ( error_t ), allocatable , intent ( out ) :: error integer :: stat if ( which ( 'curl' ) /= '' ) then print * , \"Downloading '\" // url // \"' -> '\" // tmp_pkg_file // \"'\" call execute_command_line ( 'curl ' // url // ' -s -o ' // tmp_pkg_file , exitstat = stat ) else if ( which ( 'wget' ) /= '' ) then print * , \"Downloading '\" // url // \"' -> '\" // tmp_pkg_file // \"'\" call execute_command_line ( 'wget ' // url // ' -q -O ' // tmp_pkg_file , exitstat = stat ) else call fatal_error ( error , \"Neither 'curl' nor 'wget' installed.\" ); return end if if ( stat /= 0 ) then call fatal_error ( error , \"Error downloading package from '\" // url // \"'.\" ); return end if end !> Perform an http post request with form data. subroutine upload_form ( endpoint , form_data , verbose , error ) !> Endpoint to upload to. character ( len =* ), intent ( in ) :: endpoint !> Form data to upload. type ( string_t ), intent ( in ) :: form_data (:) !> Print additional information if true. logical , intent ( in ) :: verbose !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: form_data_str form_data_str = '' do i = 1 , size ( form_data ) form_data_str = form_data_str // \"-F '\" // form_data ( i )% s // \"' \" end do if ( which ( 'curl' ) /= '' ) then print * , 'Uploading package ...' call run ( 'curl -X POST -H \"Content-Type: multipart/form-data\" ' // & & form_data_str // endpoint , exitstat = stat , echo = verbose ) else call fatal_error ( error , \"'curl' not installed.\" ); return end if if ( stat /= 0 ) then call fatal_error ( error , \"Error uploading package to registry.\" ); return end if end !> Unpack a tarball to a destination. subroutine unpack ( tmp_pkg_file , destination , error ) !> Path to tarball. character ( * ), intent ( in ) :: tmp_pkg_file !> Destination to unpack to. character ( * ), intent ( in ) :: destination !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error integer :: stat if ( which ( 'tar' ) == '' ) then call fatal_error ( error , \"'tar' not installed.\" ); return end if print * , \"Unpacking '\" // tmp_pkg_file // \"' to '\" // destination // \"' ...\" call execute_command_line ( 'tar -zxf ' // tmp_pkg_file // ' -C ' // destination , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error unpacking '\" // tmp_pkg_file // \"'.\" ); return end if end end","tags":"","loc":"sourcefile/downloader.f90.html"},{"title":"dependency.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_dependency Source Code dependency.f90 Source Code !> # Dependency management !> !> ## Fetching dependencies and creating a dependency tree !> !> Dependencies on the top-level can be specified from: !> !> - `package%dependencies` !> - `package%dev_dependencies` !> - `package%executable(:)%dependencies` !> - `package%test(:)%dependencies` !> !> Each dependency is fetched in some way and provides a path to its package !> manifest. !> The `package%dependencies` of the dependencies are resolved recursively. !> !> To initialize the dependency tree all dependencies are recursively fetched !> and stored in a flat data structure to avoid retrieving a package twice. !> The data structure used to store this information should describe the current !> status of the dependency tree. Important information are: !> !> - name of the package !> - version of the package !> - path to the package root !> !> Additionally, for version controlled dependencies the following should be !> stored along with the package: !> !> - the upstream url !> - the current checked out revision !> !> Fetching a remote (version controlled) dependency turns it for our purpose !> into a local path dependency which is handled by the same means. !> !> ## Updating dependencies !> !> For a given dependency tree all top-level dependencies can be updated. !> We have two cases to consider, a remote dependency and a local dependency, !> again, remote dependencies turn into local dependencies by fetching. !> Therefore we will update remote dependencies by simply refetching them. !> !> For remote dependencies we have to refetch if the revision in the manifest !> changes or the upstream HEAD has changed (for branches _and_ tags). !> !> @Note For our purpose a tag is just a fancy branch name. Tags can be delete and !> modified afterwards, therefore they do not differ too much from branches !> from our perspective. !> !> For the latter case we only know if we actually fetch from the upstream URL. !> !> In case of local (and fetched remote) dependencies we have to read the package !> manifest and compare its dependencies against our dependency tree, any change !> requires updating the respective dependencies as well. !> !> ## Handling dependency compatibilties !> !> Currenly ignored. First come, first serve. module fpm_dependency use , intrinsic :: iso_fortran_env , only : output_unit use fpm_environment , only : get_os_type , OS_WINDOWS , os_is_unix use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : exists , join_path , mkdir , canon_path , windows_path , list_files , is_dir , basename , & os_delete_dir , get_temp_filename use fpm_git , only : git_target_revision , git_target_default , git_revision , operator ( == ) use fpm_manifest , only : package_config_t , dependency_config_t , get_package_data use fpm_manifest_dependency , only : manifest_has_changed use fpm_manifest_preprocess , only : operator ( == ) use fpm_strings , only : string_t , operator (. in .) use fpm_toml , only : toml_table , toml_key , toml_error , toml_serialize , & get_value , set_value , add_table , toml_load , toml_stat use fpm_versioning , only : version_t , new_version use fpm_settings , only : fpm_global_settings , get_global_settings , official_registry_base_url use fpm_downloader , only : downloader_t use jonquil , only : json_object use fpm_strings , only : str implicit none private public :: dependency_tree_t , new_dependency_tree , dependency_node_t , new_dependency_node , resize , & & check_and_read_pkg_data !> Overloaded reallocation interface interface resize module procedure :: resize_dependency_node end interface resize !> Dependency node in the projects dependency tree type , extends ( dependency_config_t ) :: dependency_node_t !> Actual version of this dependency type ( version_t ), allocatable :: version !> Installation prefix of this dependencies character ( len = :), allocatable :: proj_dir !> Checked out revision of the version control system character ( len = :), allocatable :: revision !> Dependency is handled logical :: done = . false . !> Dependency should be updated logical :: update = . false . !> Dependency was loaded from a cache logical :: cached = . false . contains !> Update dependency from project manifest. procedure :: register !> Get dependency from the registry. procedure :: get_from_registry procedure , private :: get_from_local_registry !> Print information on this instance procedure :: info end type dependency_node_t !> Respresentation of a projects dependencies !> !> The dependencies are stored in a simple array for now, this can be replaced !> with a binary-search tree or a hash table in the future. type :: dependency_tree_t !> Unit for IO integer :: unit = output_unit !> Verbosity of printout integer :: verbosity = 1 !> Installation prefix for dependencies character ( len = :), allocatable :: dep_dir !> Number of currently registered dependencies integer :: ndep = 0 !> Flattend list of all dependencies type ( dependency_node_t ), allocatable :: dep (:) !> Cache file character ( len = :), allocatable :: cache contains !> Overload procedure to add new dependencies to the tree generic :: add => add_project , add_project_dependencies , add_dependencies , & add_dependency , add_dependency_node !> Main entry point to add a project procedure , private :: add_project !> Add a project and its dependencies to the dependency tree procedure , private :: add_project_dependencies !> Add a list of dependencies to the dependency tree procedure , private :: add_dependencies !> Add a single dependency to the dependency tree procedure , private :: add_dependency !> Add a single dependency node to the dependency tree procedure , private :: add_dependency_node !> Resolve dependencies generic :: resolve => resolve_dependencies , resolve_dependency !> Resolve dependencies procedure , private :: resolve_dependencies !> Resolve dependency procedure , private :: resolve_dependency !> True if entity can be found generic :: has => has_dependency !> True if dependency is part of the tree procedure , private :: has_dependency !> Find a dependency in the tree generic :: find => find_name !> Find a dependency by its name procedure , private :: find_name !> Depedendncy resolution finished procedure :: finished !> Reading of dependency tree generic :: load => load_from_file , load_from_unit , load_from_toml !> Read dependency tree from file procedure , private :: load_from_file !> Read dependency tree from formatted unit procedure , private :: load_from_unit !> Read dependency tree from TOML data structure procedure , private :: load_from_toml !> Writing of dependency tree generic :: dump => dump_to_file , dump_to_unit , dump_to_toml !> Write dependency tree to file procedure , private :: dump_to_file !> Write dependency tree to formatted unit procedure , private :: dump_to_unit !> Write dependency tree to TOML data structure procedure , private :: dump_to_toml !> Update dependency tree generic :: update => update_dependency , update_tree !> Update a list of dependencies procedure , private :: update_dependency !> Update all dependencies in the tree procedure , private :: update_tree end type dependency_tree_t !> Common output format for writing to the command line character ( len =* ), parameter :: out_fmt = '(\"#\", *(1x, g0))' contains !> Create a new dependency tree subroutine new_dependency_tree ( self , verbosity , cache ) !> Instance of the dependency tree type ( dependency_tree_t ), intent ( out ) :: self !> Verbosity of printout integer , intent ( in ), optional :: verbosity !> Name of the cache file character ( len =* ), intent ( in ), optional :: cache call resize ( self % dep ) self % dep_dir = join_path ( \"build\" , \"dependencies\" ) if ( present ( verbosity )) self % verbosity = verbosity if ( present ( cache )) self % cache = cache end subroutine new_dependency_tree !> Create a new dependency node from a configuration subroutine new_dependency_node ( self , dependency , version , proj_dir , update ) !> Instance of the dependency node type ( dependency_node_t ), intent ( out ) :: self !> Dependency configuration data type ( dependency_config_t ), intent ( in ) :: dependency !> Version of the dependency type ( version_t ), intent ( in ), optional :: version !> Installation prefix of the dependency character ( len =* ), intent ( in ), optional :: proj_dir !> Dependency should be updated logical , intent ( in ), optional :: update self % dependency_config_t = dependency if ( present ( version )) then self % version = version end if if ( present ( proj_dir )) then self % proj_dir = proj_dir end if if ( present ( update )) then self % update = update end if end subroutine new_dependency_node !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the dependency configuration class ( dependency_node_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if !> Call base object info call self % dependency_config_t % info ( unit , pr ) if ( allocated ( self % version )) then write ( unit , fmt ) \"- version\" , self % version % s () end if if ( allocated ( self % proj_dir )) then write ( unit , fmt ) \"- dir\" , self % proj_dir end if if ( allocated ( self % revision )) then write ( unit , fmt ) \"- revision\" , self % revision end if write ( unit , fmt ) \"- done\" , merge ( 'YES' , 'NO ' , self % done ) write ( unit , fmt ) \"- update\" , merge ( 'YES' , 'NO ' , self % update ) end subroutine info !> Add project dependencies, each depth level after each other. !> !> We implement this algorithm in an interative rather than a recursive fashion !> as a choice of design. subroutine add_project ( self , package , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Project configuration to add type ( package_config_t ), intent ( in ) :: package !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( dependency_config_t ) :: dependency type ( dependency_tree_t ) :: cached character ( len =* ), parameter :: root = '.' integer :: id if (. not . exists ( self % dep_dir )) then call mkdir ( self % dep_dir ) end if ! Create this project as the first dependency node (depth 0) dependency % name = package % name dependency % path = root call self % add ( dependency , error ) if ( allocated ( error )) return ! Resolve the root project call self % resolve ( root , error ) if ( allocated ( error )) return ! Add the root project dependencies (depth 1) call self % add ( package , root , . true ., error ) if ( allocated ( error )) return ! After resolving all dependencies, check if we have cached ones to avoid updates if ( allocated ( self % cache )) then call new_dependency_tree ( cached , verbosity = self % verbosity , cache = self % cache ) call cached % load ( self % cache , error ) if ( allocated ( error )) return ! Skip root node do id = 2 , cached % ndep cached % dep ( id )% cached = . true . call self % add ( cached % dep ( id ), error ) if ( allocated ( error )) return end do end if ! Now decent into the dependency tree, level for level do while (. not . self % finished ()) call self % resolve ( root , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return if ( allocated ( self % cache )) then call self % dump ( self % cache , error ) if ( allocated ( error )) return end if end subroutine add_project !> Add a project and its dependencies to the dependency tree recursive subroutine add_project_dependencies ( self , package , root , main , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Project configuration to add type ( package_config_t ), intent ( in ) :: package !> Current project root directory character ( len =* ), intent ( in ) :: root !> Is the main project logical , intent ( in ) :: main !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii if ( allocated ( package % dependency )) then call self % add ( package % dependency , error ) if ( allocated ( error )) return end if if ( main ) then if ( allocated ( package % dev_dependency )) then call self % add ( package % dev_dependency , error ) if ( allocated ( error )) return end if if ( allocated ( package % executable )) then do ii = 1 , size ( package % executable ) if ( allocated ( package % executable ( ii )% dependency )) then call self % add ( package % executable ( ii )% dependency , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end if if ( allocated ( package % example )) then do ii = 1 , size ( package % example ) if ( allocated ( package % example ( ii )% dependency )) then call self % add ( package % example ( ii )% dependency , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end if if ( allocated ( package % test )) then do ii = 1 , size ( package % test ) if ( allocated ( package % test ( ii )% dependency )) then call self % add ( package % test ( ii )% dependency , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end if end if end subroutine add_project_dependencies !> Add a list of dependencies to the dependency tree subroutine add_dependencies ( self , dependency , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_config_t ), intent ( in ) :: dependency (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii , ndep ndep = size ( self % dep ) if ( ndep < size ( dependency ) + self % ndep ) then call resize ( self % dep , ndep + ndep / 2 + size ( dependency )) end if do ii = 1 , size ( dependency ) call self % add ( dependency ( ii ), error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end subroutine add_dependencies !> Add a single dependency node to the dependency tree !> Dependency nodes contain additional information (version, git, revision) subroutine add_dependency_node ( self , dependency , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_node_t ), intent ( in ) :: dependency !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: id if ( self % has_dependency ( dependency )) then ! A dependency with this same name is already in the dependency tree. ! Check if it needs to be updated id = self % find ( dependency % name ) ! If this dependency was in the cache, and we're now requesting a different version ! in the manifest, ensure it is marked for update. Otherwise, if we're just querying ! the same dependency from a lower branch of the dependency tree, the existing one from ! the manifest has priority if ( dependency % cached ) then if ( dependency_has_changed ( dependency , self % dep ( id ), self % verbosity , self % unit )) then if ( self % verbosity > 0 ) write ( self % unit , out_fmt ) \"Dependency change detected:\" , dependency % name self % dep ( id )% update = . true . else ! Store the cached one self % dep ( id ) = dependency self % dep ( id )% update = . false . end if end if else ! New dependency: add from scratch self % ndep = self % ndep + 1 self % dep ( self % ndep ) = dependency self % dep ( self % ndep )% update = . false . end if end subroutine add_dependency_node !> Add a single dependency to the dependency tree subroutine add_dependency ( self , dependency , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_config_t ), intent ( in ) :: dependency !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( dependency_node_t ) :: node call new_dependency_node ( node , dependency ) call add_dependency_node ( self , node , error ) end subroutine add_dependency !> Update dependency tree subroutine update_dependency ( self , name , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Name of the dependency to update character ( len =* ), intent ( in ) :: name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: id character ( len = :), allocatable :: proj_dir , root id = self % find ( name ) root = \".\" if ( id <= 0 ) then call fatal_error ( error , \"Cannot update dependency '\" // name // \"'\" ) return end if associate ( dep => self % dep ( id )) if ( allocated ( dep % git ) . and . dep % update ) then if ( self % verbosity > 0 ) write ( self % unit , out_fmt ) \"Update:\" , dep % name proj_dir = join_path ( self % dep_dir , dep % name ) call dep % git % checkout ( proj_dir , error ) if ( allocated ( error )) return ! Unset dependency and remove updatable attribute dep % done = . false . dep % update = . false . ! Now decent into the dependency tree, level for level do while (. not . self % finished ()) call self % resolve ( root , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end if end associate end subroutine update_dependency !> Update whole dependency tree subroutine update_tree ( self , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i ! Update dependencies where needed do i = 1 , self % ndep call self % update ( self % dep ( i )% name , error ) if ( allocated ( error )) return end do end subroutine update_tree !> Resolve all dependencies in the tree subroutine resolve_dependencies ( self , root , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Current installation prefix character ( len =* ), intent ( in ) :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( fpm_global_settings ) :: global_settings integer :: ii call get_global_settings ( global_settings , error ) if ( allocated ( error )) return do ii = 1 , self % ndep call self % resolve ( self % dep ( ii ), global_settings , root , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end subroutine resolve_dependencies !> Resolve a single dependency node subroutine resolve_dependency ( self , dependency , global_settings , root , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_node_t ), intent ( inout ) :: dependency !> Global configuration settings. type ( fpm_global_settings ), intent ( in ) :: global_settings !> Current installation prefix character ( len =* ), intent ( in ) :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( package_config_t ) :: package character ( len = :), allocatable :: manifest , proj_dir , revision logical :: fetch if ( dependency % done ) return fetch = . false . if ( allocated ( dependency % proj_dir )) then proj_dir = dependency % proj_dir else if ( allocated ( dependency % path )) then proj_dir = join_path ( root , dependency % path ) else if ( allocated ( dependency % git )) then proj_dir = join_path ( self % dep_dir , dependency % name ) fetch = . not . exists ( proj_dir ) if ( fetch ) then call dependency % git % checkout ( proj_dir , error ) if ( allocated ( error )) return end if else call dependency % get_from_registry ( proj_dir , global_settings , error ) if ( allocated ( error )) return end if if ( allocated ( dependency % git )) then call git_revision ( proj_dir , revision , error ) if ( allocated ( error )) return end if manifest = join_path ( proj_dir , \"fpm.toml\" ) call get_package_data ( package , manifest , error ) if ( allocated ( error )) return call dependency % register ( package , proj_dir , fetch , revision , error ) if ( allocated ( error )) return if ( self % verbosity > 1 ) then write ( self % unit , out_fmt ) & \"Dep:\" , dependency % name , \"version\" , dependency % version % s (), & \"at\" , dependency % proj_dir end if call self % add ( package , proj_dir , . false ., error ) if ( allocated ( error )) return end subroutine resolve_dependency !> Get a dependency from the registry. Whether the dependency is fetched !> from a local, a custom remote or the official registry is determined !> by the global configuration settings. subroutine get_from_registry ( self , target_dir , global_settings , error , downloader_ ) !> Instance of the dependency configuration. class ( dependency_node_t ), intent ( in ) :: self !> The target directory of the dependency. character (:), allocatable , intent ( out ) :: target_dir !> Global configuration settings. type ( fpm_global_settings ), intent ( in ) :: global_settings !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error !> Downloader instance. class ( downloader_t ), optional , intent ( in ) :: downloader_ character (:), allocatable :: cache_path , target_url , tmp_file type ( version_t ) :: version integer :: stat , unit type ( json_object ) :: json class ( downloader_t ), allocatable :: downloader if ( present ( downloader_ )) then downloader = downloader_ else allocate ( downloader ) end if ! Use local registry if it was specified in the global config file. if ( allocated ( global_settings % registry_settings % path )) then call self % get_from_local_registry ( target_dir , global_settings % registry_settings % path , error ); return end if ! Include namespace and package name in the cache path. cache_path = join_path ( global_settings % registry_settings % cache_path , self % namespace , self % name ) ! Check cache before downloading from the remote registry if a specific version was requested. When no specific ! version was requested, do network request first to check which is the newest version. if ( allocated ( self % requested_version )) then if ( exists ( join_path ( cache_path , self % requested_version % s (), 'fpm.toml' ))) then print * , \"Using cached version of '\" , join_path ( self % namespace , self % name , self % requested_version % s ()), \"'.\" target_dir = join_path ( cache_path , self % requested_version % s ()); return end if end if tmp_file = get_temp_filename () open ( newunit = unit , file = tmp_file , action = 'readwrite' , iostat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error creating temporary file for downloading package '\" // self % name // \"'.\" ); return end if ! Include namespace and package name in the target url and download package data. target_url = global_settings % registry_settings % url // '/packages/' // self % namespace // '/' // self % name call downloader % get_pkg_data ( target_url , self % requested_version , tmp_file , json , error ) close ( unit , status = 'delete' ) if ( allocated ( error )) return ! Verify package data and read relevant information. call check_and_read_pkg_data ( json , self , target_url , version , error ) if ( allocated ( error )) return ! Open new tmp file for downloading the actual package. open ( newunit = unit , file = tmp_file , action = 'readwrite' , iostat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error creating temporary file for downloading package '\" // self % name // \"'.\" ); return end if ! Include version number in the cache path. If no cached version exists, download it. cache_path = join_path ( cache_path , version % s ()) if (. not . exists ( join_path ( cache_path , 'fpm.toml' ))) then if ( is_dir ( cache_path )) call os_delete_dir ( os_is_unix (), cache_path ) call mkdir ( cache_path ) call downloader % get_file ( target_url , tmp_file , error ) if ( allocated ( error )) then close ( unit , status = 'delete' ); return end if ! Unpack the downloaded package to the final location. call downloader % unpack ( tmp_file , cache_path , error ) close ( unit , status = 'delete' ) if ( allocated ( error )) return end if target_dir = cache_path end subroutine get_from_registry subroutine check_and_read_pkg_data ( json , node , download_url , version , error ) type ( json_object ), intent ( inout ) :: json class ( dependency_node_t ), intent ( in ) :: node character (:), allocatable , intent ( out ) :: download_url type ( version_t ), intent ( out ) :: version type ( error_t ), allocatable , intent ( out ) :: error integer :: code , stat type ( json_object ), pointer :: p , q character (:), allocatable :: version_key , version_str , error_message , namespace , name namespace = \"\" name = \"UNNAMED_NODE\" if ( allocated ( node % namespace )) namespace = node % namespace if ( allocated ( node % name )) name = node % name if (. not . json % has_key ( 'code' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No status code.\" ); return end if call get_value ( json , 'code' , code , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': \" // & & \"Failed to read status code.\" ); return end if if ( code /= 200 ) then if (. not . json % has_key ( 'message' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No error message.\" ); return end if call get_value ( json , 'message' , error_message , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': \" // & & \"Failed to read error message.\" ); return end if call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"'. Status code: '\" // & & str ( code ) // \"'. Error message: '\" // error_message // \"'.\" ); return end if if (. not . json % has_key ( 'data' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No data.\" ); return end if call get_value ( json , 'data' , p , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to read package data for '\" // join_path ( namespace , name ) // \"'.\" ); return end if if ( allocated ( node % requested_version )) then version_key = 'version_data' else version_key = 'latest_version_data' end if if (. not . p % has_key ( version_key )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No version data.\" ); return end if call get_value ( p , version_key , q , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to retrieve version data for '\" // join_path ( namespace , name ) // \"'.\" ); return end if if (. not . q % has_key ( 'download_url' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No download url.\" ); return end if call get_value ( q , 'download_url' , download_url , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to read download url for '\" // join_path ( namespace , name ) // \"'.\" ); return end if download_url = official_registry_base_url // download_url if (. not . q % has_key ( 'version' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No version found.\" ); return end if call get_value ( q , 'version' , version_str , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to read version data for '\" // join_path ( namespace , name ) // \"'.\" ); return end if call new_version ( version , version_str , error ) if ( allocated ( error )) then call fatal_error ( error , \"'\" // version_str // \"' is not a valid version for '\" // & & join_path ( namespace , name ) // \"'.\" ); return end if end subroutine !> Get the dependency from a local registry. subroutine get_from_local_registry ( self , target_dir , registry_path , error ) !> Instance of the dependency configuration. class ( dependency_node_t ), intent ( in ) :: self !> The target directory to download the dependency to. character (:), allocatable , intent ( out ) :: target_dir !> The path to the local registry. character ( * ), intent ( in ) :: registry_path !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: path_to_name type ( string_t ), allocatable :: files (:) type ( version_t ), allocatable :: versions (:) type ( version_t ) :: version integer :: i path_to_name = join_path ( registry_path , self % namespace , self % name ) if (. not . exists ( path_to_name )) then call fatal_error ( error , \"Dependency resolution of '\" // self % name // & & \"': Directory '\" // path_to_name // \"' doesn't exist.\" ); return end if call list_files ( path_to_name , files ) if ( size ( files ) == 0 ) then call fatal_error ( error , \"No versions of '\" // self % name // \"' found in '\" // path_to_name // \"'.\" ); return end if ! Version requested, find it in the cache. if ( allocated ( self % requested_version )) then do i = 1 , size ( files ) ! Identify directory that matches the version number. if ( files ( i )% s == join_path ( path_to_name , self % requested_version % s ()) . and . is_dir ( files ( i )% s )) then if (. not . exists ( join_path ( files ( i )% s , 'fpm.toml' ))) then call fatal_error ( error , \"'\" // files ( i )% s // \"' is missing an 'fpm.toml' file.\" ); return end if target_dir = files ( i )% s ; return end if end do call fatal_error ( error , \"Version '\" // self % requested_version % s () // \"' not found in '\" // path_to_name // \"'\" ) return end if ! No specific version requested, therefore collect available versions. allocate ( versions ( 0 )) do i = 1 , size ( files ) if ( is_dir ( files ( i )% s )) then call new_version ( version , basename ( files ( i )% s ), error ) if ( allocated ( error )) return versions = [ versions , version ] end if end do if ( size ( versions ) == 0 ) then call fatal_error ( error , \"No versions found in '\" // path_to_name // \"'\" ); return end if ! Find the latest version. version = versions ( 1 ) do i = 1 , size ( versions ) if ( versions ( i ) > version ) version = versions ( i ) end do path_to_name = join_path ( path_to_name , version % s ()) if (. not . exists ( join_path ( path_to_name , 'fpm.toml' ))) then call fatal_error ( error , \"'\" // path_to_name // \"' is missing an 'fpm.toml' file.\" ); return end if target_dir = path_to_name end subroutine get_from_local_registry !> True if dependency is part of the tree pure logical function has_dependency ( self , dependency ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( in ) :: self !> Dependency configuration to check class ( dependency_node_t ), intent ( in ) :: dependency has_dependency = self % find ( dependency % name ) /= 0 end function has_dependency !> Find a dependency in the dependency tree pure function find_name ( self , name ) result ( pos ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( in ) :: self !> Dependency configuration to add character ( len =* ), intent ( in ) :: name !> Index of the dependency integer :: pos integer :: ii pos = 0 do ii = 1 , self % ndep if ( name == self % dep ( ii )% name ) then pos = ii exit end if end do end function find_name !> Check if we are done with the dependency resolution pure function finished ( self ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( in ) :: self !> All dependencies are updated logical :: finished finished = all ( self % dep (: self % ndep )% done ) end function finished !> Update dependency from project manifest subroutine register ( self , package , root , fetch , revision , error ) !> Instance of the dependency node class ( dependency_node_t ), intent ( inout ) :: self !> Package configuration data type ( package_config_t ), intent ( in ) :: package !> Project has been fetched logical , intent ( in ) :: fetch !> Root directory of the project character ( len =* ), intent ( in ) :: root !> Git revision of the project character ( len =* ), intent ( in ), optional :: revision !> Error handling type ( error_t ), allocatable , intent ( out ) :: error logical :: update update = . false . if ( self % name /= package % name ) then call fatal_error ( error , \"Dependency name '\" // package % name // & & \"' found, but expected '\" // self % name // \"' instead\" ) end if self % version = package % version self % proj_dir = root if ( allocated ( self % git ) . and . present ( revision )) then self % revision = revision if (. not . fetch ) then ! Change in revision ID was checked already. Only update if ALL git information is missing update = . not . allocated ( self % git % url ) end if end if if ( update ) self % update = update self % done = . true . end subroutine register !> Read dependency tree from file subroutine load_from_file ( self , file , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> File name character ( len =* ), intent ( in ) :: file !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: unit logical :: exist inquire ( file = file , exist = exist ) if (. not . exist ) return open ( file = file , newunit = unit ) call self % load ( unit , error ) close ( unit ) end subroutine load_from_file !> Read dependency tree from file subroutine load_from_unit ( self , unit , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> File name integer , intent ( in ) :: unit !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_error ), allocatable :: parse_error type ( toml_table ), allocatable :: table call toml_load ( table , unit , error = parse_error ) if ( allocated ( parse_error )) then allocate ( error ) call move_alloc ( parse_error % message , error % message ) return end if call self % load ( table , error ) if ( allocated ( error )) return end subroutine load_from_unit !> Read dependency tree from TOML data structure subroutine load_from_toml ( self , table , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ndep , ii logical :: is_unix character ( len = :), allocatable :: version , url , obj , rev , proj_dir type ( toml_key ), allocatable :: list (:) type ( toml_table ), pointer :: ptr call table % get_keys ( list ) ndep = size ( self % dep ) if ( ndep < size ( list ) + self % ndep ) then call resize ( self % dep , ndep + ndep / 2 + size ( list )) end if is_unix = get_os_type () /= OS_WINDOWS do ii = 1 , size ( list ) call get_value ( table , list ( ii )% key , ptr ) call get_value ( ptr , \"version\" , version ) call get_value ( ptr , \"proj-dir\" , proj_dir ) call get_value ( ptr , \"git\" , url ) call get_value ( ptr , \"obj\" , obj ) call get_value ( ptr , \"rev\" , rev ) if (. not . allocated ( proj_dir )) cycle self % ndep = self % ndep + 1 associate ( dep => self % dep ( self % ndep )) dep % name = list ( ii )% key if ( is_unix ) then dep % proj_dir = proj_dir else dep % proj_dir = windows_path ( proj_dir ) end if dep % done = . false . if ( allocated ( version )) then if (. not . allocated ( dep % version )) allocate ( dep % version ) call new_version ( dep % version , version , error ) if ( allocated ( error )) exit end if if ( allocated ( url )) then if ( allocated ( obj )) then dep % git = git_target_revision ( url , obj ) else dep % git = git_target_default ( url ) end if if ( allocated ( rev )) then dep % revision = rev end if else dep % path = proj_dir end if end associate end do if ( allocated ( error )) return self % ndep = size ( list ) end subroutine load_from_toml !> Write dependency tree to file subroutine dump_to_file ( self , file , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> File name character ( len =* ), intent ( in ) :: file !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: unit open ( file = file , newunit = unit ) call self % dump ( unit , error ) close ( unit ) if ( allocated ( error )) return end subroutine dump_to_file !> Write dependency tree to file subroutine dump_to_unit ( self , unit , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Formatted unit integer , intent ( in ) :: unit !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ) :: table table = toml_table () call self % dump ( table , error ) write ( unit , '(a)' ) toml_serialize ( table ) end subroutine dump_to_unit !> Write dependency tree to TOML datastructure subroutine dump_to_toml ( self , table , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii type ( toml_table ), pointer :: ptr character ( len = :), allocatable :: proj_dir do ii = 1 , self % ndep associate ( dep => self % dep ( ii )) call add_table ( table , dep % name , ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , \"Cannot create entry for \" // dep % name ) exit end if if ( allocated ( dep % version )) then call set_value ( ptr , \"version\" , dep % version % s ()) end if proj_dir = canon_path ( dep % proj_dir ) call set_value ( ptr , \"proj-dir\" , proj_dir ) if ( allocated ( dep % git )) then call set_value ( ptr , \"git\" , dep % git % url ) if ( allocated ( dep % git % object )) then call set_value ( ptr , \"obj\" , dep % git % object ) end if if ( allocated ( dep % revision )) then call set_value ( ptr , \"rev\" , dep % revision ) end if end if end associate end do if ( allocated ( error )) return end subroutine dump_to_toml !> Reallocate a list of dependencies pure subroutine resize_dependency_node ( var , n ) !> Instance of the array to be resized type ( dependency_node_t ), allocatable , intent ( inout ) :: var (:) !> Dimension of the final array size integer , intent ( in ), optional :: n type ( dependency_node_t ), allocatable :: tmp (:) integer :: this_size , new_size integer , parameter :: initial_size = 16 if ( allocated ( var )) then this_size = size ( var , 1 ) call move_alloc ( var , tmp ) else this_size = initial_size end if if ( present ( n )) then new_size = n else new_size = this_size + this_size / 2 + 1 end if allocate ( var ( new_size )) if ( allocated ( tmp )) then this_size = min ( size ( tmp , 1 ), size ( var , 1 )) var (: this_size ) = tmp (: this_size ) deallocate ( tmp ) end if end subroutine resize_dependency_node !> Check if a dependency node has changed logical function dependency_has_changed ( cached , manifest , verbosity , iunit ) result ( has_changed ) !> Two instances of the same dependency to be compared type ( dependency_node_t ), intent ( in ) :: cached , manifest !> Log verbosity integer , intent ( in ) :: verbosity , iunit integer :: ip has_changed = . true . !> All the following entities must be equal for the dependency to not have changed if ( manifest_has_changed ( cached = cached , manifest = manifest , verbosity = verbosity , iunit = iunit )) return !> For now, only perform the following checks if both are available. A dependency in cache.toml !> will always have this metadata; a dependency from fpm.toml which has not been fetched yet !> may not have it if ( allocated ( cached % version ) . and . allocated ( manifest % version )) then if ( cached % version /= manifest % version ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"VERSION has changed: \" // cached % version % s () // \" vs. \" // manifest % version % s () return end if else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"VERSION has changed presence \" end if if ( allocated ( cached % revision ) . and . allocated ( manifest % revision )) then if ( cached % revision /= manifest % revision ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"REVISION has changed: \" // cached % revision // \" vs. \" // manifest % revision return end if else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"REVISION has changed presence \" end if if ( allocated ( cached % proj_dir ) . and . allocated ( manifest % proj_dir )) then if ( cached % proj_dir /= manifest % proj_dir ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PROJECT DIR has changed: \" // cached % proj_dir // \" vs. \" // manifest % proj_dir return end if else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PROJECT DIR has changed presence \" end if if ( allocated ( cached % preprocess ) . eqv . allocated ( manifest % preprocess )) then if ( allocated ( cached % preprocess )) then if ( size ( cached % preprocess ) /= size ( manifest % preprocess )) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PREPROCESS has changed size\" return end if do ip = 1 , size ( cached % preprocess ) if (. not .( cached % preprocess ( ip ) == manifest % preprocess ( ip ))) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PREPROCESS config has changed\" return end if end do endif else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PREPROCESS has changed presence \" return end if !> All checks passed: the two dependencies have no differences has_changed = . false . end function dependency_has_changed end module fpm_dependency","tags":"","loc":"sourcefile/dependency.f90.html"},{"title":"versioning.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_versioning Source Code versioning.f90 Source Code !> Implementation of versioning data for comparing packages module fpm_versioning use fpm_error , only : error_t , syntax_error use fpm_strings , only : string_t use regex_module , only : regex implicit none private public :: version_t , new_version public :: regex_version_from_text type :: version_t private !> Version numbers found integer , allocatable :: num (:) contains generic :: operator ( == ) => equals procedure , private :: equals generic :: operator ( /= ) => not_equals procedure , private :: not_equals generic :: operator ( > ) => greater procedure , private :: greater generic :: operator ( < ) => less procedure , private :: less generic :: operator ( >= ) => greater_equals procedure , private :: greater_equals generic :: operator ( <= ) => less_equals procedure , private :: less_equals !> Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) generic :: operator (. match .) => match procedure , private :: match !> Create a printable string from a version data type procedure :: s end type version_t !> Arbitrary internal limit of the version parser integer , parameter :: max_limit = 3 interface new_version module procedure :: new_version_from_string module procedure :: new_version_from_int end interface new_version contains !> Create a new version from a string subroutine new_version_from_int ( self , num ) !> Instance of the versioning data type ( version_t ), intent ( out ) :: self !> Subversion numbers to define version data integer , intent ( in ) :: num (:) self % num = num end subroutine new_version_from_int !> Create a new version from a string subroutine new_version_from_string ( self , string , error ) !> Instance of the versioning data type ( version_t ), intent ( out ) :: self !> String describing the version information character ( len =* ), intent ( in ) :: string !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: istart , iend , stat , nn integer :: num ( max_limit ) logical :: is_number nn = 0 iend = 0 istart = 0 is_number = . false . do while ( iend < len ( string )) call next ( string , istart , iend , is_number , error ) if ( allocated ( error )) exit if ( is_number ) then if ( nn >= max_limit ) then call token_error ( error , string , istart , iend , & & \"Too many subversions found\" ) exit end if nn = nn + 1 read ( string ( istart : iend ), * , iostat = stat ) num ( nn ) if ( stat /= 0 ) then call token_error ( error , string , istart , iend , & & \"Failed to parse version number\" ) exit end if end if end do if ( allocated ( error )) return if (. not . is_number ) then call token_error ( error , string , istart , iend , & & \"Expected version number, but no characters are left\" ) return end if call new_version ( self , num (: nn )) end subroutine new_version_from_string !> Tokenize a version string subroutine next ( string , istart , iend , is_number , error ) !> String describing the version information character ( len =* ), intent ( in ) :: string !> Start of last token, start of next token on exit integer , intent ( inout ) :: istart !> End of last token on entry, end of next token on exit integer , intent ( inout ) :: iend !> Token produced is a number logical , intent ( inout ) :: is_number !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii , nn logical :: was_number character :: tok was_number = is_number nn = len ( string ) if ( iend >= nn ) then istart = nn iend = nn return end if ii = min ( iend + 1 , nn ) tok = string ( ii : ii ) is_number = tok /= '.' if ( is_number . eqv . was_number ) then call token_error ( error , string , istart , ii , & & \"Unexpected token found\" ) return end if if (. not . is_number ) then is_number = . false . istart = ii iend = ii return end if istart = ii do ii = min ( iend + 1 , nn ), nn tok = string ( ii : ii ) select case ( tok ) case default call token_error ( error , string , istart , ii , & & \"Invalid character in version number\" ) exit case ( '.' ) exit case ( '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ) iend = ii cycle end select end do end subroutine next !> Create an error on an invalid token, provide some visual context as well subroutine token_error ( error , string , istart , iend , message ) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> String describing the version information character ( len =* ), intent ( in ) :: string !> Start of last token, start of next token on exit integer , intent ( in ) :: istart !> End of last token on entry, end of next token on exit integer , intent ( in ) :: iend !> Error message character ( len =* ), intent ( in ) :: message character ( len =* ), parameter :: nl = new_line ( 'a' ) allocate ( error ) error % message = message // nl // \" | \" // string // nl // & & \" |\" // repeat ( '-' , istart ) // repeat ( '^' , iend - istart + 1 ) end subroutine token_error pure function s ( self ) result ( string ) !> Version number class ( version_t ), intent ( in ) :: self !> Character representation of the version character ( len = :), allocatable :: string integer , parameter :: buffersize = 64 character ( len = buffersize ) :: buffer integer :: ii do ii = 1 , size ( self % num ) if ( allocated ( string )) then write ( buffer , '(\".\", i0)' ) self % num ( ii ) string = string // trim ( buffer ) else write ( buffer , '(i0)' ) self % num ( ii ) string = trim ( buffer ) end if end do if (. not . allocated ( string )) then string = '0' end if end function s !> Check to version numbers for equality elemental function equals ( lhs , rhs ) result ( is_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> Version match logical :: is_equal is_equal = . not .( lhs > rhs ) if ( is_equal ) then is_equal = . not .( rhs > lhs ) end if end function equals !> Check two versions for inequality elemental function not_equals ( lhs , rhs ) result ( not_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> Version mismatch logical :: not_equal not_equal = lhs > rhs if (. not . not_equal ) then not_equal = rhs > lhs end if end function not_equals !> Relative comparison of two versions elemental function greater ( lhs , rhs ) result ( is_greater ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is greater logical :: is_greater integer :: ii do ii = 1 , min ( size ( lhs % num ), size ( rhs % num )) if ( lhs % num ( ii ) /= rhs % num ( ii )) then is_greater = lhs % num ( ii ) > rhs % num ( ii ) return end if end do is_greater = size ( lhs % num ) > size ( rhs % num ) if ( is_greater ) then do ii = size ( rhs % num ) + 1 , size ( lhs % num ) is_greater = lhs % num ( ii ) > 0 if ( is_greater ) return end do end if end function greater !> Relative comparison of two versions elemental function less ( lhs , rhs ) result ( is_less ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is less logical :: is_less is_less = rhs > lhs end function less !> Relative comparison of two versions elemental function greater_equals ( lhs , rhs ) result ( is_greater_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is greater or equal logical :: is_greater_equal is_greater_equal = . not . ( rhs > lhs ) end function greater_equals !> Relative comparison of two versions elemental function less_equals ( lhs , rhs ) result ( is_less_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is less or equal logical :: is_less_equal is_less_equal = . not . ( lhs > rhs ) end function less_equals !> Try to match first version against second version elemental function match ( lhs , rhs ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> Version match following semantic versioning rules logical :: match type ( version_t ) :: tmp match = . not .( rhs > lhs ) if ( match ) then tmp % num = rhs % num tmp % num ( size ( tmp % num )) = tmp % num ( size ( tmp % num )) + 1 match = tmp > lhs end if end function match ! Extract canonical version flags \"1.0.0\" or \"1.0\" as the first instance inside a text ! (whatever long) using regex type ( string_t ) function regex_version_from_text ( text , what , error ) result ( ver ) character ( * ), intent ( in ) :: text character ( * ), intent ( in ) :: what type ( error_t ), allocatable , intent ( out ) :: error integer :: ire , length if ( len_trim ( text ) <= 0 ) then call syntax_error ( error , 'cannot retrieve ' // what // ' version: empty input string' ) return end if ! Extract 3-sized version \"1.0.4\" ire = regex ( text , '\\d+\\.\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ! Parse version into the object (this should always work) ver = string_t ( text ( ire : ire + length - 1 )) else ! Try 2-sized version \"1.0\" ire = regex ( text , '\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ver = string_t ( text ( ire : ire + length - 1 )) else call syntax_error ( error , 'cannot retrieve ' // what // ' version.' ) end if end if end function regex_version_from_text end module fpm_versioning","tags":"","loc":"sourcefile/versioning.f90.html"},{"title":"fpm_release.F90 – Fortran-lang/fpm","text":"Contents Modules fpm_release Source Code fpm_release.F90 Source Code !># Release parameters !> Module fpm_release contains public constants storing this build's unique version IDs module fpm_release use fpm_versioning , only : version_t , new_version use fpm_error , only : error_t , fpm_stop implicit none private public :: fpm_version public :: version_t contains !> Return the current fpm version from fpm_version_ID as a version type type ( version_t ) function fpm_version () type ( error_t ), allocatable :: error ! Fallback to last known version in case of undefined macro #ifndef FPM_RELEASE_VERSION # define FPM_RELEASE_VERSION 0.8.0 #endif ! Accept solution from https://stackoverflow.com/questions/31649691/stringify-macro-with-gnu-gfortran ! which provides the \"easiest\" way to pass a macro to a string in Fortran complying with both ! gfortran's \"traditional\" cpp and the standard cpp syntaxes #ifdef __GFORTRAN__ /* traditional-cpp stringification */ # define STRINGIFY_START(X) \"& # define STRINGIFY_END(X) &X\" #else /* default stringification */ # define STRINGIFY_(X) #X # define STRINGIFY_START(X) & # define STRINGIFY_END(X) STRINGIFY_(X) #endif character ( len = :), allocatable :: ver_string ver_string = STRINGIFY_START ( FPM_RELEASE_VERSION ) STRINGIFY_END ( FPM_RELEASE_VERSION ) call new_version ( fpm_version , ver_string , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*fpm*:internal error: cannot get version - ' // error % message ) end function fpm_version end module fpm_release","tags":"","loc":"sourcefile/fpm_release.f90.html"},{"title":"error.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_error Source Code error.f90 Source Code !> Implementation of basic error handling. module fpm_error use , intrinsic :: iso_fortran_env , only : stdin => input_unit , stdout => output_unit , stderr => error_unit use fpm_strings , only : is_fortran_name , to_fortran_name implicit none private public :: error_t public :: fatal_error , syntax_error , file_not_found_error public :: file_parse_error public :: bad_name_error public :: fpm_stop !> Data type defining an error type :: error_t !> Error message character ( len = :), allocatable :: message end type error_t contains !> Generic fatal runtime error subroutine fatal_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine fatal_error subroutine syntax_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine syntax_error function bad_name_error ( error , label , name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message label to add to message character ( len =* ), intent ( in ) :: label !> name value to check character ( len =* ), intent ( in ) :: name logical :: bad_name_error if (. not . is_fortran_name ( to_fortran_name ( name ))) then bad_name_error = . true . allocate ( error ) error % message = 'manifest file syntax error: ' // label // ' name must be composed only of & &alphanumerics, \"-\" and \"_\" and start with a letter ::' // name else bad_name_error = . false . endif end function bad_name_error !> Error created when a file is missing or not found subroutine file_not_found_error ( error , file_name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of the missing file character ( len =* ), intent ( in ) :: file_name allocate ( error ) error % message = \"'\" // file_name // \"' could not be found, check if the file exists\" end subroutine file_not_found_error !> Error created when file parsing fails subroutine file_parse_error ( error , file_name , message , line_num , & line_string , line_col ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of file character ( len =* ), intent ( in ) :: file_name !> Parse error message character ( len =* ), intent ( in ) :: message !> Line number of parse error integer , intent ( in ), optional :: line_num !> Line context string character ( len =* ), intent ( in ), optional :: line_string !> Line context column integer , intent ( in ), optional :: line_col character ( 50 ) :: temp_string allocate ( error ) error % message = 'Parse error: ' // message // new_line ( 'a' ) error % message = error % message // file_name if ( present ( line_num )) then write ( temp_string , '(I0)' ) line_num error % message = error % message // ':' // trim ( temp_string ) end if if ( present ( line_col )) then if ( line_col > 0 ) then write ( temp_string , '(I0)' ) line_col error % message = error % message // ':' // trim ( temp_string ) end if end if if ( present ( line_string )) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // line_string if ( present ( line_col )) then if ( line_col > 0 ) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // repeat ( ' ' , line_col - 1 ) // '^' end if end if end if end subroutine file_parse_error subroutine fpm_stop ( value , message ) ! TODO: if verbose mode, call ERROR STOP instead of STOP ! TODO: if M_escape is used, add color ! to work with older compilers might need a case statement for values !> value to use on STOP integer , intent ( in ) :: value !> Error message character ( len =* ), intent ( in ) :: message integer :: iostat if ( message /= '' ) then flush ( unit = stderr , iostat = iostat ) flush ( unit = stdout , iostat = iostat ) if ( value > 0 ) then write ( stderr , '(\" \",a)' ) trim ( message ) else write ( stderr , '(\" \",a)' ) trim ( message ) endif flush ( unit = stderr , iostat = iostat ) endif stop value end subroutine fpm_stop end module fpm_error","tags":"","loc":"sourcefile/error.f90.html"},{"title":"git.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_git Source Code git.f90 Source Code !> Implementation for interacting with git repositories. module fpm_git use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : get_temp_filename , getline , join_path , execute_and_read_output , run implicit none public :: git_target_t , git_target_default , git_target_branch , git_target_tag , git_target_revision , git_revision , & & git_archive , git_matches_manifest , operator ( == ), compressed_package_name !> Name of the compressed package that is generated temporarily. character ( len =* ), parameter :: compressed_package_name = 'compressed_package' !> Possible git target type :: enum_descriptor !> Default target integer :: default = 200 !> Branch in git repository integer :: branch = 201 !> Tag in git repository integer :: tag = 202 !> Commit hash integer :: revision = 203 end type enum_descriptor !> Actual enumerator for descriptors type ( enum_descriptor ), parameter :: git_descriptor = enum_descriptor () !> Description of an git target type :: git_target_t !> Kind of the git target integer :: descriptor = git_descriptor % default !> Target URL of the git repository character ( len = :), allocatable :: url !> Additional descriptor of the git object character ( len = :), allocatable :: object contains !> Fetch and checkout in local directory procedure :: checkout !> Show information on instance procedure :: info end type git_target_t interface operator ( == ) module procedure git_target_eq end interface !> Common output format for writing to the command line character ( len =* ), parameter :: out_fmt = '(\"#\", *(1x, g0))' contains !> Default target function git_target_default ( url ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % default self % url = url end function git_target_default !> Target a branch in the git repository function git_target_branch ( url , branch ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Name of the branch of interest character ( len =* ), intent ( in ) :: branch !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % branch self % url = url self % object = branch end function git_target_branch !> Target a specific git revision function git_target_revision ( url , sha1 ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Commit hash of interest character ( len =* ), intent ( in ) :: sha1 !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % revision self % url = url self % object = sha1 end function git_target_revision !> Target a git tag function git_target_tag ( url , tag ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Tag name of interest character ( len =* ), intent ( in ) :: tag !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % tag self % url = url self % object = tag end function git_target_tag !> Check that two git targets are equal logical function git_target_eq ( this , that ) result ( is_equal ) !> Two input git targets type ( git_target_t ), intent ( in ) :: this , that is_equal = this % descriptor == that % descriptor . and . & this % url == that % url . and . & this % object == that % object end function git_target_eq !> Check that a cached dependency matches a manifest request logical function git_matches_manifest ( cached , manifest , verbosity , iunit ) !> Two input git targets type ( git_target_t ), intent ( in ) :: cached , manifest integer , intent ( in ) :: verbosity , iunit git_matches_manifest = cached % url == manifest % url if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT URL has changed: \" , cached % url , \" vs. \" , manifest % url return endif !> The manifest dependency only contains partial information (what's requested), !> while the cached dependency always stores a commit hash because it's built !> after the repo is available (saved as git_descriptor%revision==revision). !> So, comparing against the descriptor is not reliable git_matches_manifest = allocated ( cached % object ) . eqv . allocated ( manifest % object ) if ( git_matches_manifest . and . allocated ( cached % object )) & git_matches_manifest = cached % object == manifest % object if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT OBJECT has changed: \" , cached % object , \" vs. \" , manifest % object end if end function git_matches_manifest subroutine checkout ( self , local_path , error ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character ( len = :), allocatable :: object , workdir if ( allocated ( self % object )) then object = self % object else object = 'HEAD' end if workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) call execute_command_line ( \"git init \" // local_path , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while initiating git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" fetch --depth=1 \" // & self % url // \" \" // object , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while fetching git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" checkout -qf FETCH_HEAD\" , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while checking out git repository for remote dependency' ) return end if end subroutine checkout subroutine git_revision ( local_path , object , error ) !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Git object reference character ( len = :), allocatable , intent ( out ) :: object !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , unit , istart , iend character ( len = :), allocatable :: temp_file , line , iomsg , workdir character ( len =* ), parameter :: hexdigits = '0123456789abcdef' workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) allocate ( temp_file , source = get_temp_filename ()) line = \"git \" // workdir // \" log -n 1 > \" // temp_file call execute_command_line ( line , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error while retrieving commit information\" ) return end if open ( file = temp_file , newunit = unit ) call getline ( unit , line , stat , iomsg ) if ( stat /= 0 ) then call fatal_error ( error , iomsg ) return end if close ( unit , status = \"delete\" ) ! Tokenize: ! commit 0123456789abcdef (HEAD, ...) istart = scan ( line , ' ' ) + 1 iend = verify ( line ( istart :), hexdigits ) + istart - 1 if ( iend < istart ) iend = len ( line ) object = line ( istart : iend ) end subroutine git_revision !> Show information on git target subroutine info ( self , unit , verbosity ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Git target\" if ( allocated ( self % url )) then write ( unit , fmt ) \"- URL\" , self % url end if if ( allocated ( self % object )) then select case ( self % descriptor ) case default write ( unit , fmt ) \"- object\" , self % object case ( git_descriptor % tag ) write ( unit , fmt ) \"- tag\" , self % object case ( git_descriptor % branch ) write ( unit , fmt ) \"- branch\" , self % object case ( git_descriptor % revision ) write ( unit , fmt ) \"- sha1\" , self % object end select end if end subroutine info !> Archive a folder using `git archive`. subroutine git_archive ( source , destination , ref , verbose , error ) !> Directory to archive. character ( * ), intent ( in ) :: source !> Destination of the archive. character ( * ), intent ( in ) :: destination !> (Symbolic) Reference to be archived. character ( * ), intent ( in ) :: ref !> Print additional information if true. logical , intent ( in ) :: verbose !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character ( len = :), allocatable :: cmd_output , archive_format call execute_and_read_output ( 'git archive -l' , cmd_output , error , verbose ) if ( allocated ( error )) return if ( index ( cmd_output , 'tar.gz' ) /= 0 ) then archive_format = 'tar.gz' else call fatal_error ( error , \"Cannot find a suitable archive format for 'git archive'.\" ); return end if call run ( 'git archive ' // ref // ' --format=' // archive_format // ' -o ' // destination , echo = verbose , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error packing '\" // source // \"'.\" ); return end if end end module fpm_git","tags":"","loc":"sourcefile/git.f90.html"},{"title":"manifest.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest Source Code manifest.f90 Source Code !> Package configuration data. !> !> This module provides the necessary procedure to translate a TOML document !> to the corresponding Fortran type, while verifying it with respect to !> its schema. !> !> Additionally, the required data types for users of this module are reexported !> to hide the actual implementation details. module fpm_manifest use fpm_manifest_example , only : example_config_t use fpm_manifest_executable , only : executable_config_t use fpm_manifest_dependency , only : dependency_config_t use fpm_manifest_library , only : library_config_t use fpm_manifest_preprocess , only : preprocess_config_t use fpm_manifest_package , only : package_config_t , new_package use fpm_error , only : error_t , fatal_error use fpm_toml , only : toml_table , read_package_file use fpm_manifest_test , only : test_config_t use fpm_filesystem , only : join_path , exists , dirname , is_dir use fpm_environment , only : os_is_unix use fpm_strings , only : string_t implicit none private public :: get_package_data , default_executable , default_library , default_test public :: default_example public :: package_config_t , dependency_config_t , preprocess_config_t contains !> Populate library in case we find the default src directory subroutine default_library ( self ) !> Instance of the library meta data type ( library_config_t ), intent ( out ) :: self self % source_dir = \"src\" self % include_dir = [ string_t ( \"include\" )] end subroutine default_library !> Populate executable in case we find the default app directory subroutine default_executable ( self , name ) !> Instance of the executable meta data type ( executable_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name self % source_dir = \"app\" self % main = \"main.f90\" end subroutine default_executable !> Populate test in case we find the default example/ directory subroutine default_example ( self , name ) !> Instance of the executable meta data type ( example_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-demo\" self % source_dir = \"example\" self % main = \"main.f90\" end subroutine default_example !> Populate test in case we find the default test/ directory subroutine default_test ( self , name ) !> Instance of the executable meta data type ( test_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-test\" self % source_dir = \"test\" self % main = \"main.f90\" end subroutine default_test !> Obtain package meta data from a configuation file subroutine get_package_data ( package , file , error , apply_defaults ) !> Parsed package meta data type ( package_config_t ), intent ( out ) :: package !> Name of the package configuration file character ( len =* ), intent ( in ) :: file !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error !> Apply package defaults (uses file system operations) logical , intent ( in ), optional :: apply_defaults type ( toml_table ), allocatable :: table character ( len = :), allocatable :: root call read_package_file ( table , file , error ) if ( allocated ( error )) return if (. not . allocated ( table )) then call fatal_error ( error , \"Unclassified error while reading: '\" // file // \"'\" ) return end if call new_package ( package , table , dirname ( file ), error ) if ( allocated ( error )) return if ( present ( apply_defaults )) then if ( apply_defaults ) then root = dirname ( file ) if ( len_trim ( root ) == 0 ) root = \".\" call package_defaults ( package , root , error ) if ( allocated ( error )) return end if end if end subroutine get_package_data !> Apply package defaults subroutine package_defaults ( package , root , error ) !> Parsed package meta data type ( package_config_t ), intent ( inout ) :: package !> Current working directory character ( len =* ), intent ( in ) :: root !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error ! Populate library in case we find the default src directory if (. not . allocated ( package % library ) . and . & & ( is_dir ( join_path ( root , \"src\" )) . or . & & is_dir ( join_path ( root , \"include\" )))) then allocate ( package % library ) call default_library ( package % library ) end if ! Populate executable in case we find the default app if (. not . allocated ( package % executable ) . and . & & exists ( join_path ( root , \"app\" , \"main.f90\" ))) then allocate ( package % executable ( 1 )) call default_executable ( package % executable ( 1 ), package % name ) end if ! Populate example in case we find the default example directory if (. not . allocated ( package % example ) . and . & & exists ( join_path ( root , \"example\" , \"main.f90\" ))) then allocate ( package % example ( 1 )) call default_example ( package % example ( 1 ), package % name ) endif ! Populate test in case we find the default test directory if (. not . allocated ( package % test ) . and . & & exists ( join_path ( root , \"test\" , \"main.f90\" ))) then allocate ( package % test ( 1 )) call default_test ( package % test ( 1 ), package % name ) endif if (. not .( allocated ( package % library ) & & . or . allocated ( package % executable ) & & . or . allocated ( package % example ) & & . or . allocated ( package % test ))) then call fatal_error ( error , \"Neither library nor executable found, there is nothing to do\" ) return end if end subroutine package_defaults end module fpm_manifest","tags":"","loc":"sourcefile/manifest.f90.html"},{"title":"toml.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_toml Source Code toml.f90 Source Code !># Interface to TOML processing library !> !> This module acts as a proxy to the `toml-f` public Fortran API and allows !> to selectively expose components from the library to `fpm`. !> The interaction with `toml-f` data types outside of this module should be !> limited to tables, arrays and key-lists, most of the necessary interactions !> are implemented in the building interface with the `get_value` and `set_value` !> procedures. !> !> This module allows to implement features necessary for `fpm`, which are !> not yet available in upstream `toml-f`. !> !> For more details on the library used see the !> [TOML-Fortran](https://toml-f.github.io/toml-f) developer pages. module fpm_toml use fpm_error , only : error_t , fatal_error , file_not_found_error use fpm_strings , only : string_t use tomlf , only : toml_table , toml_array , toml_key , toml_stat , get_value , & & set_value , toml_parse , toml_error , new_table , add_table , add_array , & & toml_serialize , len , toml_load implicit none private public :: read_package_file , toml_table , toml_array , toml_key , toml_stat , & get_value , set_value , get_list , new_table , add_table , add_array , len , & toml_error , toml_serialize , toml_load , check_keys contains !> Process the configuration file to a TOML data structure subroutine read_package_file ( table , manifest , error ) !> TOML data structure type ( toml_table ), allocatable , intent ( out ) :: table !> Name of the package configuration file character ( len =* ), intent ( in ) :: manifest !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error type ( toml_error ), allocatable :: parse_error integer :: unit logical :: exist inquire ( file = manifest , exist = exist ) if (. not . exist ) then call file_not_found_error ( error , manifest ) return end if open ( file = manifest , newunit = unit ) call toml_load ( table , unit , error = parse_error ) close ( unit ) if ( allocated ( parse_error )) then allocate ( error ) call move_alloc ( parse_error % message , error % message ) return end if end subroutine read_package_file subroutine get_list ( table , key , list , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Key to read from character ( len =* ), intent ( in ) :: key !> List of strings to read type ( string_t ), allocatable , intent ( out ) :: list (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , ilist , nlist type ( toml_array ), pointer :: children character ( len = :), allocatable :: str if (. not . table % has_key ( key )) return call get_value ( table , key , children , requested = . false .) if ( associated ( children )) then nlist = len ( children ) allocate ( list ( nlist )) do ilist = 1 , nlist call get_value ( children , ilist , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) exit end if call move_alloc ( str , list ( ilist )% s ) end do if ( allocated ( error )) return else call get_value ( table , key , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) return end if if ( allocated ( str )) then allocate ( list ( 1 )) call move_alloc ( str , list ( 1 )% s ) end if end if end subroutine get_list !> Check if table contains only keys that are part of the list. If a key is !> found that is not part of the list, an error is allocated. subroutine check_keys ( table , valid_keys , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys to check. character ( len =* ), intent ( in ) :: valid_keys (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: keys (:) type ( toml_table ), pointer :: child character (:), allocatable :: name , value , valid_keys_string integer :: ikey , ivalid call table % get_key ( name ) call table % get_keys ( keys ) do ikey = 1 , size ( keys ) if (. not . any ( keys ( ikey )% key == valid_keys )) then ! Generate error message valid_keys_string = new_line ( 'a' ) // new_line ( 'a' ) do ivalid = 1 , size ( valid_keys ) valid_keys_string = valid_keys_string // trim ( valid_keys ( ivalid )) // new_line ( 'a' ) end do allocate ( error ) error % message = \"Key '\" // keys ( ikey )% key // \"' not allowed in the '\" // & & name // \"' table.\" // new_line ( 'a' ) // new_line ( 'a' ) // 'Valid keys: ' // valid_keys_string return end if ! Check if value can be mapped or else (wrong type) show error message with the error location. ! Right now, it can only be mapped to a string or to a child node, but this can be extended in the future. call get_value ( table , keys ( ikey )% key , value ) if (. not . allocated ( value )) then ! If value is not a string, check if it is a child node call get_value ( table , keys ( ikey )% key , child ) if (. not . associated ( child )) then allocate ( error ) error % message = \"'\" // name // \"' has an invalid '\" // keys ( ikey )% key // \"' entry.\" return endif end if end do end subroutine check_keys end module fpm_toml","tags":"","loc":"sourcefile/toml.f90.html"},{"title":"installer.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_installer Source Code installer.f90 Source Code !> Implementation of an installer object. !> !> The installer provides a way to install objects to their respective directories !> in the installation prefix, a generic install command allows to install !> to any directory within the prefix. module fpm_installer use , intrinsic :: iso_fortran_env , only : output_unit use fpm_environment , only : get_os_type , os_is_unix use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : join_path , mkdir , exists , unix_path , windows_path , get_local_prefix implicit none private public :: installer_t , new_installer !> Declaration of the installer type type :: installer_t !> Path to installation directory character ( len = :), allocatable :: prefix !> Binary dir relative to the installation prefix character ( len = :), allocatable :: bindir !> Library directory relative to the installation prefix character ( len = :), allocatable :: libdir !> Include directory relative to the installation prefix character ( len = :), allocatable :: includedir !> Output unit for informative printout integer :: unit = output_unit !> Verbosity of the installer integer :: verbosity = 1 !> Command to copy objects into the installation prefix character ( len = :), allocatable :: copy !> Command to move objects into the installation prefix character ( len = :), allocatable :: move !> Cached operating system integer :: os contains !> Install an executable in its correct subdirectory procedure :: install_executable !> Install a library in its correct subdirectory procedure :: install_library !> Install a header/module in its correct subdirectory procedure :: install_header !> Install a generic file into a subdirectory in the installation prefix procedure :: install !> Run an installation command, type-bound for unit testing purposes procedure :: run !> Create a new directory in the prefix, type-bound for unit testing purposes procedure :: make_dir end type installer_t !> Default name of the binary subdirectory character ( len =* ), parameter :: default_bindir = \"bin\" !> Default name of the library subdirectory character ( len =* ), parameter :: default_libdir = \"lib\" !> Default name of the include subdirectory character ( len =* ), parameter :: default_includedir = \"include\" !> Copy command on Unix platforms character ( len =* ), parameter :: default_copy_unix = \"cp\" !> Copy command on Windows platforms character ( len =* ), parameter :: default_copy_win = \"copy\" !> Copy command on Unix platforms character ( len =* ), parameter :: default_force_copy_unix = \"cp -f\" !> Copy command on Windows platforms character ( len =* ), parameter :: default_force_copy_win = \"copy /Y\" !> Move command on Unix platforms character ( len =* ), parameter :: default_move_unix = \"mv\" !> Move command on Windows platforms character ( len =* ), parameter :: default_move_win = \"move\" contains !> Create a new instance of an installer subroutine new_installer ( self , prefix , bindir , libdir , includedir , verbosity , & copy , move ) !> Instance of the installer type ( installer_t ), intent ( out ) :: self !> Path to installation directory character ( len =* ), intent ( in ), optional :: prefix !> Binary dir relative to the installation prefix character ( len =* ), intent ( in ), optional :: bindir !> Library directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: libdir !> Include directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: includedir !> Verbosity of the installer integer , intent ( in ), optional :: verbosity !> Copy command character ( len =* ), intent ( in ), optional :: copy !> Move command character ( len =* ), intent ( in ), optional :: move self % os = get_os_type () ! By default, never prompt the user for overwrites if ( present ( copy )) then self % copy = copy else if ( os_is_unix ( self % os )) then self % copy = default_force_copy_unix else self % copy = default_force_copy_win end if end if if ( present ( move )) then self % move = move else if ( os_is_unix ( self % os )) then self % move = default_move_unix else self % move = default_move_win end if end if if ( present ( includedir )) then self % includedir = includedir else self % includedir = default_includedir end if if ( present ( prefix )) then self % prefix = prefix else self % prefix = get_local_prefix ( self % os ) end if if ( present ( bindir )) then self % bindir = bindir else self % bindir = default_bindir end if if ( present ( libdir )) then self % libdir = libdir else self % libdir = default_libdir end if if ( present ( verbosity )) then self % verbosity = verbosity else self % verbosity = 1 end if end subroutine new_installer !> Install an executable in its correct subdirectory subroutine install_executable ( self , executable , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the executable character ( len =* ), intent ( in ) :: executable !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ll if (. not . os_is_unix ( self % os )) then ll = len ( executable ) if ( executable ( max ( 1 , ll - 3 ): ll ) /= \".exe\" ) then call self % install ( executable // \".exe\" , self % bindir , error ) return end if end if call self % install ( executable , self % bindir , error ) end subroutine install_executable !> Install a library in its correct subdirectory subroutine install_library ( self , library , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the library character ( len =* ), intent ( in ) :: library !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call self % install ( library , self % libdir , error ) end subroutine install_library !> Install a header/module in its correct subdirectory subroutine install_header ( self , header , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the header character ( len =* ), intent ( in ) :: header !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call self % install ( header , self % includedir , error ) end subroutine install_header !> Install a generic file into a subdirectory in the installation prefix subroutine install ( self , source , destination , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the original file character ( len =* ), intent ( in ) :: source !> Path to the destination inside the prefix character ( len =* ), intent ( in ) :: destination !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: install_dest install_dest = join_path ( self % prefix , destination ) if ( os_is_unix ( self % os )) then install_dest = unix_path ( install_dest ) else install_dest = windows_path ( install_dest ) end if call self % make_dir ( install_dest , error ) if ( allocated ( error )) return if ( self % verbosity > 0 ) then if ( exists ( install_dest )) then write ( self % unit , '(\"# Update:\", 1x, a, 1x, \"->\", 1x, a)' ) & source , install_dest else write ( self % unit , '(\"# Install:\", 1x, a, 1x, \"->\", 1x, a)' ) & source , install_dest end if end if ! Use force-copy to never prompt the user for overwrite if a package was already installed call self % run ( self % copy // ' \"' // source // '\" \"' // install_dest // '\"' , error ) if ( allocated ( error )) return end subroutine install !> Create a new directory in the prefix subroutine make_dir ( self , dir , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Directory to be created character ( len =* ), intent ( in ) :: dir !> Error handling type ( error_t ), allocatable , intent ( out ) :: error if (. not . exists ( dir )) then if ( self % verbosity > 1 ) then write ( self % unit , '(\"# Dir:\", 1x, a)' ) dir end if call mkdir ( dir ) end if end subroutine make_dir !> Run an installation command subroutine run ( self , command , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Command to be launched character ( len =* ), intent ( in ) :: command !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat if ( self % verbosity > 1 ) then write ( self % unit , '(\"# Run:\", 1x, a)' ) command end if call execute_command_line ( command , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed in command: '\" // command // \"'\" ) return end if end subroutine run end module fpm_installer","tags":"","loc":"sourcefile/installer.f90.html"},{"title":"dependency.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_dependency Source Code dependency.f90 Source Code !> Implementation of the meta data for dependencies. !> !> A dependency table can currently have the following fields !> !>```toml !>[dependencies] !>\"dep1\" = { git = \"url\" } !>\"dep2\" = { git = \"url\", branch = \"name\" } !>\"dep3\" = { git = \"url\", tag = \"name\" } !>\"dep4\" = { git = \"url\", rev = \"sha1\" } !>\"dep0\" = { path = \"path\" } !>``` !> !> To reduce the amount of boilerplate code this module provides two constructors !> for dependency types, one basic for an actual dependency (inline) table !> and another to collect all dependency objects from a dependencies table, !> which is handling the allocation of the objects and is forwarding the !> individual dependency tables to their respective constructors. !> The usual entry point should be the constructor for the super table. !> !> This objects contains a target to retrieve required `fpm` projects to !> build the target declaring the dependency. !> Resolving a dependency will result in obtaining a new package configuration !> data for the respective project. module fpm_manifest_dependency use fpm_error , only : error_t , syntax_error use fpm_git , only : git_target_t , git_target_tag , git_target_branch , & & git_target_revision , git_target_default , operator ( == ), git_matches_manifest use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , check_keys use fpm_filesystem , only : windows_path , join_path use fpm_environment , only : get_os_type , OS_WINDOWS use fpm_manifest_metapackages , only : metapackage_config_t , is_meta_package , new_meta_config , & metapackage_request_t , new_meta_request use fpm_versioning , only : version_t , new_version use fpm_strings , only : string_t use fpm_manifest_preprocess implicit none private public :: dependency_config_t , new_dependency , new_dependencies , manifest_has_changed !> Configuration meta data for a dependency type :: dependency_config_t !> Name of the dependency character ( len = :), allocatable :: name !> Local target character ( len = :), allocatable :: path !> Namespace which the dependency belongs to. !> Enables multiple dependencies with the same name. !> Required for dependencies that are obtained via the official registry. character ( len = :), allocatable :: namespace !> The requested version of the dependency. !> The latest version is used if not specified. type ( version_t ), allocatable :: requested_version !> Requested macros for the dependency type ( preprocess_config_t ), allocatable :: preprocess (:) !> Git descriptor type ( git_target_t ), allocatable :: git contains !> Print information on this instance procedure :: info end type dependency_config_t !> Common output format for writing to the command line character ( len =* ), parameter :: out_fmt = '(\"#\", *(1x, g0))' contains !> Construct a new dependency configuration from a TOML data structure subroutine new_dependency ( self , table , root , error ) !> Instance of the dependency configuration type ( dependency_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: uri , value , requested_version type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_value ( table , \"namespace\" , self % namespace ) call get_value ( table , \"v\" , requested_version ) if ( allocated ( requested_version )) then if (. not . allocated ( self % requested_version )) allocate ( self % requested_version ) call new_version ( self % requested_version , requested_version , error ) if ( allocated ( error )) return end if !> Get optional preprocessor directives call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return endif call get_value ( table , \"path\" , uri ) if ( allocated ( uri )) then if ( get_os_type () == OS_WINDOWS ) uri = windows_path ( uri ) if ( present ( root )) uri = join_path ( root , uri ) ! Relative to the fpm.toml it’s written in call move_alloc ( uri , self % path ) return end if call get_value ( table , \"git\" , uri ) if ( allocated ( uri )) then call get_value ( table , \"tag\" , value ) if ( allocated ( value )) then self % git = git_target_tag ( uri , value ) end if if (. not . allocated ( self % git )) then call get_value ( table , \"branch\" , value ) if ( allocated ( value )) then self % git = git_target_branch ( uri , value ) end if end if if (. not . allocated ( self % git )) then call get_value ( table , \"rev\" , value ) if ( allocated ( value )) then self % git = git_target_revision ( uri , value ) end if end if if (. not . allocated ( self % git )) then self % git = git_target_default ( uri ) end if return end if end subroutine new_dependency !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: name type ( toml_key ), allocatable :: list (:) type ( toml_table ), pointer :: child !> List of valid keys for the dependency table. character ( * ), dimension ( * ), parameter :: valid_keys = [ character ( 24 ) :: & & \"namespace\" , & \"v\" , & \"path\" , & \"git\" , & \"tag\" , & \"branch\" , & \"rev\" , & \"preprocess\" & & ] call table % get_key ( name ) call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Dependency '\" // name // \"' does not provide sufficient entries\" ) return end if call check_keys ( table , valid_keys , error ) if ( allocated ( error )) return if ( table % has_key ( \"path\" ) . and . table % has_key ( \"git\" )) then call syntax_error ( error , \"Dependency '\" // name // \"' cannot have both git and path entries\" ) return end if if (( table % has_key ( \"branch\" ) . and . table % has_key ( \"rev\" )) . or . & ( table % has_key ( \"branch\" ) . and . table % has_key ( \"tag\" )) . or . & ( table % has_key ( \"rev\" ) . and . table % has_key ( \"tag\" ))) then call syntax_error ( error , \"Dependency '\" // name // \"' can only have one of branch, rev or tag present\" ) return end if if (( table % has_key ( \"branch\" ) . or . table % has_key ( \"tag\" ) . or . table % has_key ( \"rev\" )) & . and . . not . table % has_key ( \"git\" )) then call syntax_error ( error , \"Dependency '\" // name // \"' has git identifier but no git url\" ) return end if if (. not . table % has_key ( \"path\" ) . and . . not . table % has_key ( \"git\" ) & . and . . not . table % has_key ( \"namespace\" )) then call syntax_error ( error , \"Please provide a 'namespace' for dependency '\" // name // & & \"' if it is not a local path or git repository\" ) return end if if ( table % has_key ( 'v' ) . and . ( table % has_key ( 'path' ) . or . table % has_key ( 'git' ))) then call syntax_error ( error , \"Dependency '\" // name // \"' cannot have both v and git/path entries\" ) return end if ! Check preprocess key if ( table % has_key ( 'preprocess' )) then call get_value ( table , 'preprocess' , child ) if (. not . associated ( child )) then call syntax_error ( error , \"Dependency '\" // name // \"' has invalid 'preprocess' entry\" ) return end if end if end subroutine check !> Construct new dependency array from a TOML data structure subroutine new_dependencies ( deps , table , root , meta , error ) !> Instance of the dependency configuration type ( dependency_config_t ), allocatable , intent ( out ) :: deps (:) !> (optional) metapackages type ( metapackage_config_t ), optional , intent ( out ) :: meta !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) type ( dependency_config_t ), allocatable :: all_deps (:) type ( metapackage_request_t ) :: meta_request logical , allocatable :: is_meta (:) logical :: metapackages_allowed integer :: idep , stat , ndep call table % get_keys ( list ) ! An empty table is okay if ( size ( list ) < 1 ) return !> Flag dependencies that should be treated as metapackages metapackages_allowed = present ( meta ) allocate ( is_meta ( size ( list )), source = . false .) allocate ( all_deps ( size ( list ))) !> Parse all meta- and non-metapackage dependencies do idep = 1 , size ( list ) ! Check if this is a standard dependency node call get_value ( table , list ( idep )% key , node , stat = stat ) is_standard_dependency : if ( stat /= toml_stat % success ) then ! See if it can be a valid metapackage name call new_meta_request ( meta_request , list ( idep )% key , table , error = error ) !> Neither a standard dep nor a metapackage if ( allocated ( error )) then call syntax_error ( error , \"Dependency \" // list ( idep )% key // \" is not a valid metapackage or a table entry\" ) return endif !> Valid meta dependency is_meta ( idep ) = . true . else ! Parse as a standard dependency is_meta ( idep ) = . false . call new_dependency ( all_deps ( idep ), node , root , error ) if ( allocated ( error )) return end if is_standard_dependency end do ! Non-meta dependencies ndep = count (. not . is_meta ) ! Finalize standard dependencies allocate ( deps ( ndep )) ndep = 0 do idep = 1 , size ( list ) if ( is_meta ( idep )) cycle ndep = ndep + 1 deps ( ndep ) = all_deps ( idep ) end do ! Finalize meta dependencies if ( metapackages_allowed ) call new_meta_config ( meta , table , is_meta , error ) end subroutine new_dependencies !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the dependency configuration class ( dependency_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if write ( unit , fmt ) \"Dependency\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % git )) then write ( unit , fmt ) \"- kind\" , \"git\" call self % git % info ( unit , pr - 1 ) end if if ( allocated ( self % path )) then write ( unit , fmt ) \"- kind\" , \"local\" write ( unit , fmt ) \"- path\" , self % path end if end subroutine info !> Check if two dependency configurations are different logical function manifest_has_changed ( cached , manifest , verbosity , iunit ) result ( has_changed ) !> Two instances of the dependency configuration class ( dependency_config_t ), intent ( in ) :: cached , manifest !> Log verbosity integer , intent ( in ) :: verbosity , iunit has_changed = . true . !> Perform all checks if ( allocated ( cached % git ). neqv . allocated ( manifest % git )) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT presence has changed. \" return endif if ( allocated ( cached % git )) then if (. not . git_matches_manifest ( cached % git , manifest % git , verbosity , iunit )) return end if !> All checks passed! The two instances are equal has_changed = . false . end function manifest_has_changed end module fpm_manifest_dependency","tags":"","loc":"sourcefile/dependency.f90~2.html"},{"title":"example.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_example Source Code example.f90 Source Code !> Implementation of the meta data for an example. !> !> The example data structure is effectively a decorated version of an executable !> and shares most of its properties, except for the defaults and can be !> handled under most circumstances just like any other executable. !> !> A example table can currently have the following fields !> !>```toml !>[[ example ]] !>name = \"string\" !>source-dir = \"path\" !>main = \"file\" !>link = [\"lib\"] !>[example.dependencies] !>``` module fpm_manifest_example use fpm_manifest_dependency , only : dependency_config_t , new_dependencies use fpm_manifest_executable , only : executable_config_t use fpm_error , only : error_t , syntax_error , bad_name_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: example_config_t , new_example !> Configuation meta data for an example type , extends ( executable_config_t ) :: example_config_t contains !> Print information on this instance procedure :: info end type example_config_t contains !> Construct a new example configuration from a TOML data structure subroutine new_example ( self , table , error ) !> Instance of the example configuration type ( example_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve example name\" ) return end if if ( bad_name_error ( error , 'example' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"example\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_example !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Example section does not provide sufficient entries\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in example entry\" ) exit case ( \"name\" ) name_present = . true . case ( \"source-dir\" , \"main\" , \"dependencies\" , \"link\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Example name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the example configuration class ( example_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Example target\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % source_dir )) then if ( self % source_dir /= \"example\" . or . pr > 2 ) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if end if if ( allocated ( self % main )) then if ( self % main /= \"main.f90\" . or . pr > 2 ) then write ( unit , fmt ) \"- example source\" , self % main end if end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info end module fpm_manifest_example","tags":"","loc":"sourcefile/example.f90.html"},{"title":"meta.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_metapackages Source Code meta.f90 Source Code !> Implementation of the metapackage configuration data. !> !> A metapackage table can currently have the following fields !> !>```toml !>[metapackages] !>fpm = \"0.1.0\" !>openmp = bool !>stdlib = bool !>``` module fpm_manifest_metapackages use fpm_error , only : error_t , fatal_error , syntax_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value use fpm_environment implicit none private public :: metapackage_config_t , new_meta_config , is_meta_package public :: metapackage_request_t , new_meta_request !> Configuration data for a single metapackage request type :: metapackage_request_t !> Request flag logical :: on = . false . !> Metapackage name character ( len = :), allocatable :: name !> Version Specification string character ( len = :), allocatable :: version end type metapackage_request_t !> Configuration data for metapackages type :: metapackage_config_t !> Request MPI support type ( metapackage_request_t ) :: mpi !> Request OpenMP support type ( metapackage_request_t ) :: openmp !> Request stdlib support type ( metapackage_request_t ) :: stdlib !> fortran-lang minpack type ( metapackage_request_t ) :: minpack end type metapackage_config_t contains !> Destroy a metapackage request elemental subroutine request_destroy ( self ) !> Instance of the request class ( metapackage_request_t ), intent ( inout ) :: self self % on = . false . if ( allocated ( self % version )) deallocate ( self % version ) if ( allocated ( self % name )) deallocate ( self % name ) end subroutine request_destroy !> Parse version string of a metapackage request subroutine request_parse ( self , version_request , error ) ! Instance of this metapackage type ( metapackage_request_t ), intent ( inout ) :: self ! Parse version request character ( len =* ), intent ( in ) :: version_request ! Error message type ( error_t ), allocatable , intent ( out ) :: error ! wildcard = use any versions if ( version_request == \"*\" ) then ! Any version is OK self % on = . true . self % version = version_request else call fatal_error ( error , 'Value <' // version_request // '> for metapackage ' // self % name // & 'is not currently supported. Try \"*\" instead. ' ) return end if end subroutine request_parse !> Construct a new metapackage request from the dependencies table subroutine new_meta_request ( self , key , table , meta_allowed , error ) type ( metapackage_request_t ), intent ( out ) :: self !> The package name character ( len =* ), intent ( in ) :: key !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ), optional :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: value logical , allocatable :: allow_meta (:) type ( toml_key ), allocatable :: keys (:) call request_destroy ( self ) !> Set name self % name = key if (. not . is_meta_package ( key )) then call fatal_error ( error , \"Error reading fpm.toml: <\" // key // \"> is not a valid metapackage name\" ) return end if !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call table % get_keys ( keys ) !> Set list of entries that are allowed to be metapackages if ( present ( meta_allowed )) then if ( size ( meta_allowed ) /= size ( keys )) then call fatal_error ( error , \"Internal error: list of metapackage-enable entries does not match table size\" ) return end if allow_meta = meta_allowed else allocate ( allow_meta ( size ( keys )), source = . true .) endif do i = 1 , size ( keys ) ! Skip standard dependencies if (. not . allow_meta ( i )) cycle if ( keys ( i )% key == key ) then call get_value ( table , key , value ) if (. not . allocated ( value )) then call syntax_error ( error , \"Could not retrieve version string for metapackage key <\" // key // \">. Check syntax\" ) return else call request_parse ( self , value , error ) return endif end if end do ! Key is not present, metapackage not requested return end subroutine new_meta_request !> Construct a new build configuration from a TOML data structure subroutine new_meta_config ( self , table , meta_allowed , error ) !> Instance of the build configuration type ( metapackage_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ) :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call new_meta_request ( self % openmp , \"openmp\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % stdlib , \"stdlib\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % minpack , \"minpack\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % mpi , \"mpi\" , table , meta_allowed , error ) if ( allocated ( error )) return end subroutine new_meta_config !> Check local schema for allowed entries logical function is_meta_package ( key ) !> Instance of the TOML data structure character ( * ), intent ( in ) :: key select case ( key ) !> Supported metapackages case ( \"openmp\" , \"stdlib\" , \"mpi\" , \"minpack\" ) is_meta_package = . true . case default is_meta_package = . false . end select end function is_meta_package end module fpm_manifest_metapackages","tags":"","loc":"sourcefile/meta.f90.html"},{"title":"test.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_test Source Code test.f90 Source Code !> Implementation of the meta data for a test. !> !> The test data structure is effectively a decorated version of an executable !> and shares most of its properties, except for the defaults and can be !> handled under most circumstances just like any other executable. !> !> A test table can currently have the following fields !> !>```toml !>[[ test ]] !>name = \"string\" !>source-dir = \"path\" !>main = \"file\" !>link = [\"lib\"] !>[test.dependencies] !>``` module fpm_manifest_test use fpm_manifest_dependency , only : new_dependencies use fpm_manifest_executable , only : executable_config_t use fpm_error , only : error_t , syntax_error , bad_name_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: test_config_t , new_test !> Configuation meta data for an test type , extends ( executable_config_t ) :: test_config_t contains !> Print information on this instance procedure :: info end type test_config_t contains !> Construct a new test configuration from a TOML data structure subroutine new_test ( self , table , error ) !> Instance of the test configuration type ( test_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve test name\" ) return end if if ( bad_name_error ( error , 'test' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"test\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_test !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Test section does not provide sufficient entries\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in test entry\" ) exit case ( \"name\" ) name_present = . true . case ( \"source-dir\" , \"main\" , \"dependencies\" , \"link\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Test name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the test configuration class ( test_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Test target\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % source_dir )) then if ( self % source_dir /= \"test\" . or . pr > 2 ) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if end if if ( allocated ( self % main )) then if ( self % main /= \"main.f90\" . or . pr > 2 ) then write ( unit , fmt ) \"- test source\" , self % main end if end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info end module fpm_manifest_test","tags":"","loc":"sourcefile/test.f90.html"},{"title":"library.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_library Source Code library.f90 Source Code !> Implementation of the meta data for libraries. !> !> A library table can currently have the following fields !> !>```toml !>[library] !>source-dir = \"path\" !>include-dir = [\"path1\",\"path2\"] !>build-script = \"file\" !>``` module fpm_manifest_library use fpm_error , only : error_t , syntax_error use fpm_strings , only : string_t , string_cat use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: library_config_t , new_library !> Configuration meta data for a library type :: library_config_t !> Source path prefix character ( len = :), allocatable :: source_dir !> Include path prefix type ( string_t ), allocatable :: include_dir (:) !> Alternative build script to be invoked character ( len = :), allocatable :: build_script contains !> Print information on this instance procedure :: info end type library_config_t contains !> Construct a new library configuration from a TOML data structure subroutine new_library ( self , table , error ) !> Instance of the library configuration type ( library_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"source-dir\" , self % source_dir , \"src\" ) call get_value ( table , \"build-script\" , self % build_script ) call get_list ( table , \"include-dir\" , self % include_dir , error ) if ( allocated ( error )) return ! Set default value of include-dir if not found in manifest if (. not . allocated ( self % include_dir )) then self % include_dir = [ string_t ( \"include\" )] end if end subroutine new_library !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) ! table can be empty if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in library\" ) exit case ( \"source-dir\" , \"include-dir\" , \"build-script\" ) continue end select end do end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the library configuration class ( library_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Library target\" if ( allocated ( self % source_dir )) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if if ( allocated ( self % include_dir )) then write ( unit , fmt ) \"- include directory\" , string_cat ( self % include_dir , \",\" ) end if if ( allocated ( self % build_script )) then write ( unit , fmt ) \"- custom build\" , self % build_script end if end subroutine info end module fpm_manifest_library","tags":"","loc":"sourcefile/library.f90.html"},{"title":"executable.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_executable Source Code executable.f90 Source Code !> Implementation of the meta data for an executables. !> !> An executable table can currently have the following fields !> !>```toml !>[[ executable ]] !>name = \"string\" !>source-dir = \"path\" !>main = \"file\" !>link = [\"lib\"] !>[executable.dependencies] !>``` module fpm_manifest_executable use fpm_manifest_dependency , only : dependency_config_t , new_dependencies use fpm_error , only : error_t , syntax_error , bad_name_error use fpm_strings , only : string_t use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: executable_config_t , new_executable !> Configuation meta data for an executable type :: executable_config_t !> Name of the resulting executable character ( len = :), allocatable :: name !> Source directory for collecting the executable character ( len = :), allocatable :: source_dir !> Name of the source file declaring the main program character ( len = :), allocatable :: main !> Dependency meta data for this executable type ( dependency_config_t ), allocatable :: dependency (:) !> Libraries to link against type ( string_t ), allocatable :: link (:) contains !> Print information on this instance procedure :: info end type executable_config_t contains !> Construct a new executable configuration from a TOML data structure subroutine new_executable ( self , table , error ) !> Instance of the executable configuration type ( executable_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve executable name\" ) return end if if ( bad_name_error ( error , 'executable' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"app\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_executable !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Executable section does not provide sufficient entries\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed as executable entry\" ) exit case ( \"name\" ) name_present = . true . case ( \"source-dir\" , \"main\" , \"dependencies\" , \"link\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Executable name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the executable configuration class ( executable_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Executable target\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % source_dir )) then if ( self % source_dir /= \"app\" . or . pr > 2 ) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if end if if ( allocated ( self % main )) then if ( self % main /= \"main.f90\" . or . pr > 2 ) then write ( unit , fmt ) \"- program source\" , self % main end if end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info end module fpm_manifest_executable","tags":"","loc":"sourcefile/executable.f90.html"},{"title":"fortran.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_fortran Source Code fortran.f90 Source Code module fpm_manifest_fortran use fpm_error , only : error_t , syntax_error , fatal_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value implicit none private public :: fortran_config_t , new_fortran_config !> Configuration data for Fortran type :: fortran_config_t !> Enable default implicit typing logical :: implicit_typing !> Enable implicit external interfaces logical :: implicit_external !> Form to use for all Fortran sources character (:), allocatable :: source_form end type fortran_config_t contains !> Construct a new build configuration from a TOML data structure subroutine new_fortran_config ( self , table , error ) !> Instance of the fortran configuration type ( fortran_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character (:), allocatable :: source_form call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"implicit-typing\" , self % implicit_typing , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-typing' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"implicit-external\" , self % implicit_external , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-external' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"source-form\" , source_form , \"free\" , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'source-form' in fpm.toml, expecting logical\" ) return end if select case ( source_form ) case default call fatal_error ( error , \"Value of source-form cannot be '\" // source_form // \"'\" ) return case ( \"free\" , \"fixed\" , \"default\" ) self % source_form = source_form end select end subroutine new_fortran_config !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) ! table can be empty if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case ( \"implicit-typing\" , \"implicit-external\" , \"source-form\" ) continue case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in fortran\" ) exit end select end do end subroutine check end module fpm_manifest_fortran","tags":"","loc":"sourcefile/fortran.f90.html"},{"title":"build.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_build Source Code build.f90 Source Code !> Implementation of the build configuration data. !> !> A build table can currently have the following fields !> !>```toml !>[build] !>auto-executables = bool !>auto-examples = bool !>auto-tests = bool !>link = [\"lib\"] !>``` module fpm_manifest_build use fpm_error , only : error_t , syntax_error , fatal_error use fpm_strings , only : string_t , len_trim , is_valid_module_prefix use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: build_config_t , new_build_config !> Configuration data for build type :: build_config_t !> Automatic discovery of executables logical :: auto_executables !> Automatic discovery of examples logical :: auto_examples !> Automatic discovery of tests logical :: auto_tests !> Enforcing of package module names logical :: module_naming = . false . type ( string_t ) :: module_prefix !> Libraries to link against type ( string_t ), allocatable :: link (:) !> External modules to use type ( string_t ), allocatable :: external_modules (:) contains !> Print information on this instance procedure :: info end type build_config_t contains !> Construct a new build configuration from a TOML data structure subroutine new_build_config ( self , table , package_name , error ) !> Instance of the build configuration type ( build_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Package name character ( len =* ), intent ( in ) :: package_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call check ( table , package_name , error ) if ( allocated ( error )) return call get_value ( table , \"auto-executables\" , self % auto_executables , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-executables' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-tests\" , self % auto_tests , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-tests' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-examples\" , self % auto_examples , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-examples' in fpm.toml, expecting logical\" ) return end if !> Module naming: fist, attempt boolean value first call get_value ( table , \"module-naming\" , self % module_naming , . false ., stat = stat ) if ( stat == toml_stat % success ) then ! Boolean value found. Set no custom prefix. This also falls back to ! key not provided self % module_prefix = string_t ( \"\" ) else !> Value found, but not a boolean. Attempt to read a prefix string call get_value ( table , \"module-naming\" , self % module_prefix % s ) if (. not . allocated ( self % module_prefix % s )) then call syntax_error ( error , \"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string\" ) return end if if (. not . is_valid_module_prefix ( self % module_prefix )) then call syntax_error ( error , \"Invalid custom module name prefix for in fpm.toml: <\" // self % module_prefix % s // & \">, expecting a valid alphanumeric string\" ) return end if ! Set module naming to ON self % module_naming = . true . end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return call get_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return end subroutine new_build_config !> Check local schema for allowed entries subroutine check ( table , package_name , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Package name character ( len =* ), intent ( in ) :: package_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) ! table can be empty if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case ( \"auto-executables\" , \"auto-examples\" , \"auto-tests\" , \"link\" , \"external-modules\" , \"module-naming\" ) continue case default call syntax_error ( error , 'Manifest file syntax error: key \"' // list ( ikey )% key // '\" found in the [build] ' // & 'section of package/dependency \"' // package_name // '\" fpm.toml is not allowed' ) exit end select end do end subroutine check !> Write information on build configuration instance subroutine info ( self , unit , verbosity ) !> Instance of the build configuration class ( build_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ilink , imod character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Build configuration\" write ( unit , fmt ) \" - auto-discovery (apps) \" , merge ( \"enabled \" , \"disabled\" , self % auto_executables ) write ( unit , fmt ) \" - auto-discovery (examples) \" , merge ( \"enabled \" , \"disabled\" , self % auto_examples ) write ( unit , fmt ) \" - auto-discovery (tests) \" , merge ( \"enabled \" , \"disabled\" , self % auto_tests ) write ( unit , fmt ) \" - enforce module naming \" , merge ( \"enabled \" , \"disabled\" , self % module_naming ) if ( allocated ( self % link )) then write ( unit , fmt ) \" - link against\" do ilink = 1 , size ( self % link ) write ( unit , fmt ) \" - \" // self % link ( ilink )% s end do end if if ( allocated ( self % external_modules )) then write ( unit , fmt ) \" - external modules\" do imod = 1 , size ( self % external_modules ) write ( unit , fmt ) \" - \" // self % external_modules ( imod )% s end do end if end subroutine info end module fpm_manifest_build","tags":"","loc":"sourcefile/build.f90.html"},{"title":"install.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_install Source Code install.f90 Source Code !> Implementation of the installation configuration. !> !> An install table can currently have the following fields !> !>```toml !>library = bool !>``` module fpm_manifest_install use fpm_error , only : error_t , fatal_error , syntax_error use fpm_toml , only : toml_table , toml_key , toml_stat , get_value implicit none private public :: install_config_t , new_install_config !> Configuration data for installation type :: install_config_t !> Install library with this project logical :: library contains !> Print information on this instance procedure :: info end type install_config_t contains !> Create a new installation configuration from a TOML data structure subroutine new_install_config ( self , table , error ) !> Instance of the install configuration type ( install_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"library\" , self % library , . false .) end subroutine new_install_config !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in install table\" ) exit case ( \"library\" ) continue end select end do if ( allocated ( error )) return end subroutine check !> Write information on install configuration instance subroutine info ( self , unit , verbosity ) !> Instance of the build configuration class ( install_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Install configuration\" write ( unit , fmt ) \" - library install\" , & & trim ( merge ( \"enabled \" , \"disabled\" , self % library )) end subroutine info end module fpm_manifest_install","tags":"","loc":"sourcefile/install.f90.html"},{"title":"preprocess.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_preprocess Source Code preprocess.f90 Source Code !> Implementation of the meta data for preprocessing. !> !> A preprocess table can currently have the following fields !> !> ```toml !> [preprocess] !> [preprocess.cpp] !> suffixes = [\"F90\", \"f90\"] !> directories = [\"src/feature1\", \"src/models\"] !> macros = [] !> ``` module fpm_manifest_preprocess use fpm_error , only : error_t , syntax_error use fpm_strings , only : string_t use fpm_toml , only : toml_table , toml_key , toml_stat , get_value , get_list implicit none private public :: preprocess_config_t , new_preprocess_config , new_preprocessors , operator ( == ) !> Configuration meta data for a preprocessor type :: preprocess_config_t !> Name of the preprocessor character ( len = :), allocatable :: name !> Suffixes of the files to be preprocessed type ( string_t ), allocatable :: suffixes (:) !> Directories to search for files to be preprocessed type ( string_t ), allocatable :: directories (:) !> Macros to be defined for the preprocessor type ( string_t ), allocatable :: macros (:) contains !> Print information on this instance procedure :: info end type preprocess_config_t interface operator ( == ) module procedure preprocess_is_same end interface contains !> Construct a new preprocess configuration from TOML data structure subroutine new_preprocess_config ( self , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), intent ( out ) :: self !> Instance of the TOML data structure. type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_list ( table , \"suffixes\" , self % suffixes , error ) if ( allocated ( error )) return call get_list ( table , \"directories\" , self % directories , error ) if ( allocated ( error )) return call get_list ( table , \"macros\" , self % macros , error ) if ( allocated ( error )) return end subroutine new_preprocess_config !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure. type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( inout ) :: error character ( len = :), allocatable :: name type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_key ( name ) call table % get_keys ( list ) do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) !> Valid keys. case ( \"suffixes\" , \"directories\" , \"macros\" ) case default call syntax_error ( error , \"Key '\" // list ( ikey )% key // \"' not allowed in preprocessor '\" // name // \"'.\" ); exit end select end do end subroutine check !> Construct new preprocess array from a TOML data structure. subroutine new_preprocessors ( preprocessors , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), allocatable , intent ( out ) :: preprocessors (:) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) integer :: iprep , stat call table % get_keys ( list ) ! An empty table is not allowed if ( size ( list ) == 0 ) then call syntax_error ( error , \"No preprocessors defined\" ) end if allocate ( preprocessors ( size ( list ))) do iprep = 1 , size ( list ) call get_value ( table , list ( iprep )% key , node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Preprocessor \" // list ( iprep )% key // \" must be a table entry\" ) exit end if call new_preprocess_config ( preprocessors ( iprep ), node , error ) if ( allocated ( error )) exit end do end subroutine new_preprocessors !> Write information on this instance subroutine info ( self , unit , verbosity ) !> Instance of the preprocess configuration class ( preprocess_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ilink character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Preprocessor\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % suffixes )) then write ( unit , fmt ) \" - suffixes\" do ilink = 1 , size ( self % suffixes ) write ( unit , fmt ) \" - \" // self % suffixes ( ilink )% s end do end if if ( allocated ( self % directories )) then write ( unit , fmt ) \" - directories\" do ilink = 1 , size ( self % directories ) write ( unit , fmt ) \" - \" // self % directories ( ilink )% s end do end if if ( allocated ( self % macros )) then write ( unit , fmt ) \" - macros\" do ilink = 1 , size ( self % macros ) write ( unit , fmt ) \" - \" // self % macros ( ilink )% s end do end if end subroutine info logical function preprocess_is_same ( this , that ) class ( preprocess_config_t ), intent ( in ) :: this class ( preprocess_config_t ), intent ( in ) :: that integer :: istr preprocess_is_same = . false . select type ( other => that ) type is ( preprocess_config_t ) if ( allocated ( this % name ). neqv . allocated ( other % name )) return if ( allocated ( this % name )) then if (. not .( this % name == other % name )) return endif if (. not .( allocated ( this % suffixes ). eqv . allocated ( other % suffixes ))) return if ( allocated ( this % suffixes )) then do istr = 1 , size ( this % suffixes ) if (. not .( this % suffixes ( istr )% s == other % suffixes ( istr )% s )) return end do end if if (. not .( allocated ( this % directories ). eqv . allocated ( other % directories ))) return if ( allocated ( this % directories )) then do istr = 1 , size ( this % directories ) if (. not .( this % directories ( istr )% s == other % directories ( istr )% s )) return end do end if if (. not .( allocated ( this % macros ). eqv . allocated ( other % macros ))) return if ( allocated ( this % macros )) then do istr = 1 , size ( this % macros ) if (. not .( this % macros ( istr )% s == other % macros ( istr )% s )) return end do end if class default ! Not the same type return end select !> All checks passed! preprocess_is_same = . true . end function preprocess_is_same end module fpm_manifest_preprocess","tags":"","loc":"sourcefile/preprocess.f90.html"},{"title":"package.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_package Source Code package.f90 Source Code !> Define the package data containing the meta data from the configuration file. !> !> The package data defines a Fortran type corresponding to the respective !> TOML document, after creating it from a package file no more interaction !> with the TOML document is required. !> !> Every configuration type provides it custom constructor (prefixed with `new_`) !> and knows how to deserialize itself from a TOML document. !> To ensure we find no untracked content in the package file all keywords are !> checked and possible entries have to be explicitly allowed in the `check` !> function. !> If entries are mutally exclusive or interdependent inside the current table !> the `check` function is required to enforce this schema on the data structure. !> !> The package file root allows the following keywords !> !>```toml !>name = \"string\" !>version = \"string\" !>license = \"string\" !>author = \"string\" !>maintainer = \"string\" !>copyright = \"string\" !>[library] !>[dependencies] !>[dev-dependencies] !>[profiles] !>[build] !>[install] !>[fortran] !>[[ executable ]] !>[[ example ]] !>[[ test ]] !>[extra] !>``` module fpm_manifest_package use fpm_manifest_build , only : build_config_t , new_build_config use fpm_manifest_dependency , only : dependency_config_t , new_dependencies use fpm_manifest_profile , only : profile_config_t , new_profiles , get_default_profiles use fpm_manifest_example , only : example_config_t , new_example use fpm_manifest_executable , only : executable_config_t , new_executable use fpm_manifest_fortran , only : fortran_config_t , new_fortran_config use fpm_manifest_library , only : library_config_t , new_library use fpm_manifest_install , only : install_config_t , new_install_config use fpm_manifest_test , only : test_config_t , new_test use fpm_manifest_preprocess , only : preprocess_config_t , new_preprocessors use fpm_manifest_metapackages , only : metapackage_config_t , new_meta_config use fpm_filesystem , only : exists , getline , join_path use fpm_error , only : error_t , fatal_error , syntax_error , bad_name_error use fpm_toml , only : toml_table , toml_array , toml_key , toml_stat , get_value , len use fpm_versioning , only : version_t , new_version implicit none private public :: package_config_t , new_package interface unique_programs module procedure :: unique_programs1 module procedure :: unique_programs2 end interface unique_programs !> Package meta data type :: package_config_t !> Name of the package character ( len = :), allocatable :: name !> Package version type ( version_t ) :: version !> Build configuration data type ( build_config_t ) :: build !> Metapackage data type ( metapackage_config_t ) :: meta !> Installation configuration data type ( install_config_t ) :: install !> Fortran meta data type ( fortran_config_t ) :: fortran !> License meta data character ( len = :), allocatable :: license !> Library meta data type ( library_config_t ), allocatable :: library !> Executable meta data type ( executable_config_t ), allocatable :: executable (:) !> Dependency meta data type ( dependency_config_t ), allocatable :: dependency (:) !> Development dependency meta data type ( dependency_config_t ), allocatable :: dev_dependency (:) !> Profiles meta data type ( profile_config_t ), allocatable :: profiles (:) !> Example meta data type ( example_config_t ), allocatable :: example (:) !> Test meta data type ( test_config_t ), allocatable :: test (:) !> Preprocess meta data type ( preprocess_config_t ), allocatable :: preprocess (:) contains !> Print information on this instance procedure :: info end type package_config_t contains !> Construct a new package configuration from a TOML data structure subroutine new_package ( self , table , root , error ) !> Instance of the package configuration type ( package_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( len =* ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error ! Backspace (8), tabulator (9), newline (10), formfeed (12) and carriage ! return (13) are invalid in package names character ( len =* ), parameter :: invalid_chars = & achar ( 8 ) // achar ( 9 ) // achar ( 10 ) // achar ( 12 ) // achar ( 13 ) type ( toml_table ), pointer :: child , node type ( toml_array ), pointer :: children character ( len = :), allocatable :: version , version_file integer :: ii , nn , stat , io call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve package name\" ) return end if if ( bad_name_error ( error , 'package' , self % name )) then return endif call get_value ( table , \"license\" , self % license ) if ( len ( self % name ) <= 0 ) then call syntax_error ( error , \"Package name must be a non-empty string\" ) return end if ii = scan ( self % name , invalid_chars ) if ( ii > 0 ) then call syntax_error ( error , \"Package name contains invalid characters\" ) return end if call get_value ( table , \"build\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for build entry, must be a table\" ) return end if call new_build_config ( self % build , child , self % name , error ) if ( allocated ( error )) return call get_value ( table , \"install\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for install entry, must be a table\" ) return end if call new_install_config ( self % install , child , error ) if ( allocated ( error )) return call get_value ( table , \"fortran\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for fortran entry, must be a table\" ) return end if call new_fortran_config ( self % fortran , child , error ) if ( allocated ( error )) return call get_value ( table , \"version\" , version , \"0\" ) call new_version ( self % version , version , error ) if ( allocated ( error ) . and . present ( root )) then version_file = join_path ( root , version ) if ( exists ( version_file )) then deallocate ( error ) open ( file = version_file , newunit = io , iostat = stat ) if ( stat == 0 ) then call getline ( io , version , iostat = stat ) end if if ( stat == 0 ) then close ( io , iostat = stat ) end if if ( stat == 0 ) then call new_version ( self % version , version , error ) else call fatal_error ( error , \"Reading version number from file '\" & & // version_file // \"' failed\" ) end if end if end if if ( allocated ( error )) return call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , root , self % meta , error ) if ( allocated ( error )) return end if call get_value ( table , \"dev-dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dev_dependency , child , root , error = error ) if ( allocated ( error )) return end if call get_value ( table , \"library\" , child , requested = . false .) if ( associated ( child )) then allocate ( self % library ) call new_library ( self % library , child , error ) if ( allocated ( error )) return end if call get_value ( table , \"profiles\" , child , requested = . false .) if ( associated ( child )) then call new_profiles ( self % profiles , child , error ) if ( allocated ( error )) return else self % profiles = get_default_profiles ( error ) if ( allocated ( error )) return end if call get_value ( table , \"executable\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % executable ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve executable from array entry\" ) exit end if call new_executable ( self % executable ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % executable , error ) if ( allocated ( error )) return end if call get_value ( table , \"example\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % example ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve example from array entry\" ) exit end if call new_example ( self % example ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % example , error ) if ( allocated ( error )) return if ( allocated ( self % executable )) then call unique_programs ( self % executable , self % example , error ) if ( allocated ( error )) return end if end if call get_value ( table , \"test\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % test ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve test from array entry\" ) exit end if call new_test ( self % test ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % test , error ) if ( allocated ( error )) return end if call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return end if end subroutine new_package !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Package file is empty\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in package file\" ) exit case ( \"name\" ) name_present = . true . case ( \"version\" , \"license\" , \"author\" , \"maintainer\" , \"copyright\" , & & \"description\" , \"keywords\" , \"categories\" , \"homepage\" , \"build\" , & & \"dependencies\" , \"dev-dependencies\" , \"profiles\" , \"test\" , \"executable\" , & & \"example\" , \"library\" , \"install\" , \"extra\" , \"preprocess\" , \"fortran\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Package name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the package configuration class ( package_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Package\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if call self % build % info ( unit , pr - 1 ) call self % install % info ( unit , pr - 1 ) if ( allocated ( self % library )) then write ( unit , fmt ) \"- target\" , \"archive\" call self % library % info ( unit , pr - 1 ) end if if ( allocated ( self % executable )) then if ( size ( self % executable ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- executables\" , size ( self % executable ) end if do ii = 1 , size ( self % executable ) call self % executable ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % example )) then if ( size ( self % example ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- examples\" , size ( self % example ) end if do ii = 1 , size ( self % example ) call self % example ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % test )) then if ( size ( self % test ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- tests\" , size ( self % test ) end if do ii = 1 , size ( self % test ) call self % test ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % dev_dependency )) then if ( size ( self % dev_dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- development deps.\" , size ( self % dev_dependency ) end if do ii = 1 , size ( self % dev_dependency ) call self % dev_dependency ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % profiles )) then if ( size ( self % profiles ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- profiles\" , size ( self % profiles ) end if do ii = 1 , size ( self % profiles ) call self % profiles ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info !> Check whether or not the names in a set of executables are unique subroutine unique_programs1 ( executable , error ) !> Array of executables class ( executable_config_t ), intent ( in ) :: executable (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j do i = 1 , size ( executable ) do j = 1 , i - 1 if ( executable ( i )% name == executable ( j )% name ) then call fatal_error ( error , \"The program named '\" // & executable ( j )% name // \"' is duplicated. \" // & \"Unique program names are required.\" ) exit end if end do end do if ( allocated ( error )) return end subroutine unique_programs1 !> Check whether or not the names in a set of executables are unique subroutine unique_programs2 ( executable_i , executable_j , error ) !> Array of executables class ( executable_config_t ), intent ( in ) :: executable_i (:) !> Array of executables class ( executable_config_t ), intent ( in ) :: executable_j (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j do i = 1 , size ( executable_i ) do j = 1 , size ( executable_j ) if ( executable_i ( i )% name == executable_j ( j )% name ) then call fatal_error ( error , \"The program named '\" // & executable_j ( j )% name // \"' is duplicated. \" // & \"Unique program names are required.\" ) exit end if end do end do if ( allocated ( error )) return end subroutine unique_programs2 end module fpm_manifest_package","tags":"","loc":"sourcefile/package.f90.html"},{"title":"profiles.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_manifest_profile Source Code profiles.f90 Source Code !> Implementation of the meta data for compiler flag profiles. !> !> A profiles table can currently have the following subtables: !> Profile names - any string, if omitted, flags are appended to all matching profiles !> Compiler - any from the following list, omitting it yields an error !> !> - \"gfortran\" !> - \"ifort\" !> - \"ifx\" !> - \"pgfortran\" !> - \"nvfortran\" !> - \"flang\" !> - \"caf\" !> - \"f95\" !> - \"lfortran\" !> - \"lfc\" !> - \"nagfor\" !> - \"crayftn\" !> - \"xlf90\" !> - \"ftn95\" !> !> OS - any from the following list, if omitted, the profile is used if and only !> if there is no profile perfectly matching the current configuration !> !> - \"linux\" !> - \"macos\" !> - \"windows\" !> - \"cygwin\" !> - \"solaris\" !> - \"freebsd\" !> - \"openbsd\" !> - \"unknown\" !> !> Each of the subtables currently supports the following fields: !>```toml !>[profiles.debug.gfortran.linux] !> flags=\"-Wall -g -Og\" !> c-flags=\"-g O1\" !> cxx-flags=\"-g O1\" !> link-time-flags=\"-xlinkopt\" !> files={\"hello_world.f90\"=\"-Wall -O3\"} !>``` !> module fpm_manifest_profile use fpm_error , only : error_t , syntax_error , fatal_error , fpm_stop use fpm_toml , only : toml_table , toml_key , toml_stat , get_value use fpm_strings , only : lower use fpm_environment , only : get_os_type , OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_WINDOWS , & OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD use fpm_filesystem , only : join_path implicit none public :: profile_config_t , new_profile , new_profiles , get_default_profiles , & & info_profile , find_profile , DEFAULT_COMPILER !> Name of the default compiler character ( len =* ), parameter :: DEFAULT_COMPILER = 'gfortran' integer , parameter :: OS_ALL = - 1 character ( len = :), allocatable :: path !> Type storing file name - file scope compiler flags pairs type :: file_scope_flag !> Name of the file character ( len = :), allocatable :: file_name !> File scope flags character ( len = :), allocatable :: flags end type file_scope_flag !> Configuration meta data for a profile type :: profile_config_t !> Name of the profile character ( len = :), allocatable :: profile_name !> Name of the compiler character ( len = :), allocatable :: compiler !> Value repesenting OS integer :: os_type !> Fortran compiler flags character ( len = :), allocatable :: flags !> C compiler flags character ( len = :), allocatable :: c_flags !> C++ compiler flags character ( len = :), allocatable :: cxx_flags !> Link time compiler flags character ( len = :), allocatable :: link_time_flags !> File scope flags type ( file_scope_flag ), allocatable :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical :: is_built_in contains !> Print information on this instance procedure :: info end type profile_config_t contains !> Construct a new profile configuration from a TOML data structure function new_profile ( profile_name , compiler , os_type , flags , c_flags , cxx_flags , & link_time_flags , file_scope_flags , is_built_in ) & & result ( profile ) !> Name of the profile character ( len =* ), intent ( in ) :: profile_name !> Name of the compiler character ( len =* ), intent ( in ) :: compiler !> Type of the OS integer , intent ( in ) :: os_type !> Fortran compiler flags character ( len =* ), optional , intent ( in ) :: flags !> C compiler flags character ( len =* ), optional , intent ( in ) :: c_flags !> C++ compiler flags character ( len =* ), optional , intent ( in ) :: cxx_flags !> Link time compiler flags character ( len =* ), optional , intent ( in ) :: link_time_flags !> File scope flags type ( file_scope_flag ), optional , intent ( in ) :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical , optional , intent ( in ) :: is_built_in type ( profile_config_t ) :: profile profile % profile_name = profile_name profile % compiler = compiler profile % os_type = os_type if ( present ( flags )) then profile % flags = flags else profile % flags = \"\" end if if ( present ( c_flags )) then profile % c_flags = c_flags else profile % c_flags = \"\" end if if ( present ( cxx_flags )) then profile % cxx_flags = cxx_flags else profile % cxx_flags = \"\" end if if ( present ( link_time_flags )) then profile % link_time_flags = link_time_flags else profile % link_time_flags = \"\" end if if ( present ( file_scope_flags )) then profile % file_scope_flags = file_scope_flags end if if ( present ( is_built_in )) then profile % is_built_in = is_built_in else profile % is_built_in = . false . end if end function new_profile !> Check if compiler name is a valid compiler name subroutine validate_compiler_name ( compiler_name , is_valid ) !> Name of a compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> Boolean value of whether compiler_name is valid or not logical , intent ( out ) :: is_valid select case ( compiler_name ) case ( \"gfortran\" , \"ifort\" , \"ifx\" , \"pgfortran\" , \"nvfortran\" , \"flang\" , \"caf\" , & & \"f95\" , \"lfortran\" , \"lfc\" , \"nagfor\" , \"crayftn\" , \"xlf90\" , \"ftn95\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_compiler_name !> Check if os_name is a valid name of a supported OS subroutine validate_os_name ( os_name , is_valid ) !> Name of an operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Boolean value of whether os_name is valid or not logical , intent ( out ) :: is_valid select case ( os_name ) case ( \"linux\" , \"macos\" , \"windows\" , \"cygwin\" , \"solaris\" , \"freebsd\" , & & \"openbsd\" , \"unknown\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_os_name !> Match os_type enum to a lowercase string with name of OS subroutine match_os_type ( os_name , os_type ) !> Name of operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Enum representing type of OS integer , intent ( out ) :: os_type select case ( os_name ) case ( \"linux\" ); os_type = OS_LINUX case ( \"macos\" ); os_type = OS_WINDOWS case ( \"cygwin\" ); os_type = OS_CYGWIN case ( \"solaris\" ); os_type = OS_SOLARIS case ( \"freebsd\" ); os_type = OS_FREEBSD case ( \"openbsd\" ); os_type = OS_OPENBSD case ( \"all\" ); os_type = OS_ALL case default ; os_type = OS_UNKNOWN end select end subroutine match_os_type subroutine validate_profile_table ( profile_name , compiler_name , key_list , table , error , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) integer :: ikey , ifile , stat logical :: is_valid if ( size ( key_list ). ge . 1 ) then do ikey = 1 , size ( key_list ) key_name = key_list ( ikey )% key if ( key_name . eq . 'flags' ) then call get_value ( table , 'flags' , flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'c-flags' ) then call get_value ( table , 'c-flags' , c_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"c-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'cxx-flags' ) then call get_value ( table , 'cxx-flags' , cxx_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"cxx-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'link-time-flags' ) then call get_value ( table , 'link-time-flags' , link_time_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"link-time-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'files' ) then call get_value ( table , 'files' , files , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"files has to be a table\" ) return end if call files % get_keys ( file_list ) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"file scope flags has to be a key-value pair\" ) return end if end do else if (. not . os_valid ) then call validate_os_name ( key_name , is_valid ) err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" if (. not . is_valid ) call syntax_error ( error , err_message ) else err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" call syntax_error ( error , err_message ) end if end do end if if ( allocated ( error )) return end subroutine validate_profile_table !> Look for flags, c-flags, link-time-flags key-val pairs !> and files table in a given table and create new profiles subroutine get_flags ( profile_name , compiler_name , os_type , key_list , table , profiles , profindex , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> OS type integer , intent ( in ) :: os_type !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) type ( file_scope_flag ), allocatable :: file_scope_flags (:) integer :: ikey , ifile , stat logical :: is_valid call get_value ( table , 'flags' , flags ) call get_value ( table , 'c-flags' , c_flags ) call get_value ( table , 'cxx-flags' , cxx_flags ) call get_value ( table , 'link-time-flags' , link_time_flags ) call get_value ( table , 'files' , files ) if ( associated ( files )) then call files % get_keys ( file_list ) allocate ( file_scope_flags ( size ( file_list ))) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags ) associate ( cur_file => file_scope_flags ( ifile )) if (. not .( path . eq . \"\" )) file_name = join_path ( path , file_name ) cur_file % file_name = file_name cur_file % flags = file_flags end associate end do end if profiles ( profindex ) = new_profile ( profile_name , compiler_name , os_type , & & flags , c_flags , cxx_flags , link_time_flags , file_scope_flags ) profindex = profindex + 1 end subroutine get_flags !> Traverse operating system tables to obtain number of profiles subroutine traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ) :: profiles_size type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat logical :: is_valid , key_val_added , is_key_val if ( size ( os_list ) < 1 ) return key_val_added = . false . do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) profiles_size = profiles_size + 1 call validate_profile_table ( profile_name , compiler_name , key_list , os_node , error , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table if ( is_key_val . and .. not . key_val_added ) then key_val_added = . true . is_key_val = . false . profiles_size = profiles_size + 1 else if (. not . is_key_val ) then profiles_size = profiles_size + 1 end if call validate_profile_table ( profile_name , compiler_name , os_list , os_node , error , . false .) end if end do end subroutine traverse_oss_for_size !> Traverse operating system tables to obtain profiles subroutine traverse_oss ( profile_name , compiler_name , os_list , table , profiles , profindex , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat , os_type logical :: is_valid , is_key_val if ( size ( os_list ) < 1 ) return do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) call match_os_type ( os_name , os_type ) call get_flags ( profile_name , compiler_name , os_type , key_list , os_node , profiles , profindex , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table os_type = OS_ALL call get_flags ( profile_name , compiler_name , os_type , os_list , os_node , profiles , profindex , . false .) end if end do end subroutine traverse_oss !> Traverse compiler tables subroutine traverse_compilers ( profile_name , comp_list , table , error , profiles_size , profiles , profindex ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> List of OSs in table with profile name given type ( toml_key ), allocatable , intent ( in ) :: comp_list (:) !> Table containing compiler tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ), optional :: profiles_size !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ), optional :: profiles (:) !> Index in the list of profiles integer , intent ( inout ), optional :: profindex character ( len = :), allocatable :: compiler_name type ( toml_table ), pointer :: comp_node type ( toml_key ), allocatable :: os_list (:) integer :: icomp , stat logical :: is_valid if ( size ( comp_list ) < 1 ) return do icomp = 1 , size ( comp_list ) call validate_compiler_name ( comp_list ( icomp )% key , is_valid ) if ( is_valid ) then compiler_name = comp_list ( icomp )% key call get_value ( table , compiler_name , comp_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Compiler \" // comp_list ( icomp )% key // \" must be a table entry\" ) exit end if call comp_node % get_keys ( os_list ) if ( present ( profiles_size )) then call traverse_oss_for_size ( profile_name , compiler_name , os_list , comp_node , profiles_size , error ) if ( allocated ( error )) return else if (. not .( present ( profiles ). and . present ( profindex ))) then call fatal_error ( error , \"Both profiles and profindex have to be present\" ) return end if call traverse_oss ( profile_name , compiler_name , os_list , comp_node , & & profiles , profindex , error ) if ( allocated ( error )) return end if else call fatal_error ( error , '*traverse_compilers*:Error: Compiler name not specified or invalid.' ) end if end do end subroutine traverse_compilers !> Construct new profiles array from a TOML data structure subroutine new_profiles ( profiles , table , error ) !> Instance of the dependency configuration type ( profile_config_t ), allocatable , intent ( out ) :: profiles (:) !> Instance of the TOML data structure type ( toml_table ), target , intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: prof_node type ( toml_key ), allocatable :: prof_list (:) type ( toml_key ), allocatable :: comp_list (:) type ( toml_key ), allocatable :: os_list (:) character ( len = :), allocatable :: profile_name , compiler_name integer :: profiles_size , iprof , stat , profindex logical :: is_valid type ( profile_config_t ), allocatable :: default_profiles (:) path = '' default_profiles = get_default_profiles ( error ) if ( allocated ( error )) return call table % get_keys ( prof_list ) if ( size ( prof_list ) < 1 ) return profiles_size = 0 do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER call traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Profile \" // prof_list ( iprof )% key // \" must be a table entry\" ) exit end if call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return end if end if end do profiles_size = profiles_size + size ( default_profiles ) allocate ( profiles ( profiles_size )) do profindex = 1 , size ( default_profiles ) profiles ( profindex ) = default_profiles ( profindex ) end do do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER prof_node => table call traverse_oss ( profile_name , compiler_name , os_list , prof_node , profiles , profindex , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return end if end if end do ! Apply profiles with profile name 'all' to matching profiles do iprof = 1 , size ( profiles ) if ( profiles ( iprof )% profile_name . eq . 'all' ) then do profindex = 1 , size ( profiles ) if (. not .( profiles ( profindex )% profile_name . eq . 'all' ) & & . and .( profiles ( profindex )% compiler . eq . profiles ( iprof )% compiler ) & & . and .( profiles ( profindex )% os_type . eq . profiles ( iprof )% os_type )) then profiles ( profindex )% flags = profiles ( profindex )% flags // & & \" \" // profiles ( iprof )% flags profiles ( profindex )% c_flags = profiles ( profindex )% c_flags // & & \" \" // profiles ( iprof )% c_flags profiles ( profindex )% cxx_flags = profiles ( profindex )% cxx_flags // & & \" \" // profiles ( iprof )% cxx_flags profiles ( profindex )% link_time_flags = profiles ( profindex )% link_time_flags // & & \" \" // profiles ( iprof )% link_time_flags end if end do end if end do end subroutine new_profiles !> Construct an array of built-in profiles function get_default_profiles ( error ) result ( default_profiles ) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( profile_config_t ), allocatable :: default_profiles (:) default_profiles = [ & & new_profile ( 'release' , & & 'caf' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'gfortran' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'f95' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -ffast-math -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Mbackslash' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_ALL , & & flags = ' -fp-model precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl -standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_ALL , & & flags = ' -fp-model=precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl -standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nagfor' , & & OS_ALL , & & flags = ' -O4 -coarray=single -PIC' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'lfortran' , & & OS_ALL , & & flags = ' flag_lfortran_opt' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'caf' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'gfortran' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'f95' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -Wno-maybe-uninitialized -Wno-uninitialized -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Minform=inform -Mbackslash -g -Mbounds -Mchkptr -Mchkstk -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -standard-semantics -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1& & /Od /Z7 /assume:byterecl /standard-semantics /traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -standard-semantics -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl /standard-semantics' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'lfortran' , & & OS_ALL , & & flags = '' , & & is_built_in = . true .) & &] end function get_default_profiles !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the profile configuration class ( profile_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if write ( unit , fmt ) \"Profile\" if ( allocated ( self % profile_name )) then write ( unit , fmt ) \"- profile name\" , self % profile_name end if if ( allocated ( self % compiler )) then write ( unit , fmt ) \"- compiler\" , self % compiler end if write ( unit , fmt ) \"- os\" , self % os_type if ( allocated ( self % flags )) then write ( unit , fmt ) \"- compiler flags\" , self % flags end if end subroutine info !> Print a representation of profile_config_t function info_profile ( profile ) result ( s ) !> Profile to be represented type ( profile_config_t ), intent ( in ) :: profile !> String representation of given profile character (:), allocatable :: s integer :: i s = \"profile_config_t(\" s = s // 'profile_name=\"' // profile % profile_name // '\"' s = s // ', compiler=\"' // profile % compiler // '\"' s = s // \", os_type=\" select case ( profile % os_type ) case ( OS_UNKNOWN ) s = s // \"OS_UNKNOWN\" case ( OS_LINUX ) s = s // \"OS_LINUX\" case ( OS_MACOS ) s = s // \"OS_MACOS\" case ( OS_WINDOWS ) s = s // \"OS_WINDOWS\" case ( OS_CYGWIN ) s = s // \"OS_CYGWIN\" case ( OS_SOLARIS ) s = s // \"OS_SOLARIS\" case ( OS_FREEBSD ) s = s // \"OS_FREEBSD\" case ( OS_OPENBSD ) s = s // \"OS_OPENBSD\" case ( OS_ALL ) s = s // \"OS_ALL\" case default s = s // \"INVALID\" end select if ( allocated ( profile % flags )) s = s // ', flags=\"' // profile % flags // '\"' if ( allocated ( profile % c_flags )) s = s // ', c_flags=\"' // profile % c_flags // '\"' if ( allocated ( profile % cxx_flags )) s = s // ', cxx_flags=\"' // profile % cxx_flags // '\"' if ( allocated ( profile % link_time_flags )) s = s // ', link_time_flags=\"' // profile % link_time_flags // '\"' if ( allocated ( profile % file_scope_flags )) then do i = 1 , size ( profile % file_scope_flags ) s = s // ', flags for ' // profile % file_scope_flags ( i )% file_name // & & ' =\"' // profile % file_scope_flags ( i )% flags // '\"' end do end if s = s // \")\" end function info_profile !> Look for profile with given configuration in array profiles subroutine find_profile ( profiles , profile_name , compiler , os_type , found_matching , chosen_profile ) !> Array of profiles type ( profile_config_t ), allocatable , intent ( in ) :: profiles (:) !> Name of profile character (:), allocatable , intent ( in ) :: profile_name !> Name of compiler character (:), allocatable , intent ( in ) :: compiler !> Type of operating system (enum) integer , intent ( in ) :: os_type !> Boolean value containing true if matching profile was found logical , intent ( out ) :: found_matching !> Last matching profile in the profiles array type ( profile_config_t ), intent ( out ) :: chosen_profile character (:), allocatable :: curr_profile_name character (:), allocatable :: curr_compiler integer :: curr_os integer :: i , priority , curr_priority found_matching = . false . if ( size ( profiles ) < 1 ) return ! Try to find profile with matching OS type do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . os_type ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do ! Try to find profile with OS type 'all' if (. not . found_matching ) then do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . OS_ALL ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do end if end subroutine find_profile end module fpm_manifest_profile","tags":"","loc":"sourcefile/profiles.f90.html"},{"title":"publish.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_cmd_publish Source Code publish.f90 Source Code !> Upload a package to the registry using the `publish` command. !> !> To upload a package you need to provide a token that will be linked to your username and created for a namespace. !> The token can be obtained from the registry website. It can be used as `fpm publish --token `. module fpm_cmd_publish use fpm_command_line , only : fpm_publish_settings use fpm_manifest , only : package_config_t , get_package_data use fpm_model , only : fpm_model_t use fpm_error , only : error_t , fpm_stop use fpm_versioning , only : version_t use fpm_filesystem , only : exists , join_path , get_temp_filename , delete_file use fpm_git , only : git_archive use fpm_downloader , only : downloader_t use fpm_strings , only : string_t use fpm_settings , only : official_registry_base_url use fpm , only : build_model implicit none private public :: cmd_publish contains !> The `publish` command first builds the root package to obtain all the relevant information such as the !> package version. It then creates a tarball of the package and uploads it to the registry. subroutine cmd_publish ( settings ) type ( fpm_publish_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( error_t ), allocatable :: error type ( version_t ), allocatable :: version type ( string_t ), allocatable :: upload_data (:) character ( len = :), allocatable :: tmp_file type ( downloader_t ) :: downloader integer :: i ! Get package data to determine package version. call get_package_data ( package , 'fpm.toml' , error , apply_defaults = . true .) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_build* Package error: ' // error % message ) version = package % version if ( settings % show_package_version ) then print * , version % s (); return end if !> Checks before uploading the package. if (. not . allocated ( package % license )) call fpm_stop ( 1 , 'No license specified in fpm.toml.' ) if (. not . package % build % module_naming ) call fpm_stop ( 1 , 'The package does not meet the module naming requirements. ' // & & 'Please set \"module-naming = true\" in fpm.toml [build] or specify a custom module prefix.' ) if (. not . allocated ( version )) call fpm_stop ( 1 , 'No version specified in fpm.toml.' ) if ( version % s () == '0' ) call fpm_stop ( 1 , 'Invalid version: \"' // version % s () // '\".' ) if (. not . exists ( 'fpm.toml' )) call fpm_stop ( 1 , \"Cannot find 'fpm.toml' file. Are you in the project root?\" ) ! Build model to obtain dependency tree. call build_model ( model , settings % fpm_build_settings , package , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_build* Model error: ' // error % message ) ! Check if package contains git dependencies. Only publish packages without git dependencies. do i = 1 , model % deps % ndep if ( allocated ( model % deps % dep ( i )% git )) then call fpm_stop ( 1 , 'Do not publish packages containing git dependencies. ' // & & \"Please upload '\" // model % deps % dep ( i )% name // \"' to the registry first.\" ) end if end do tmp_file = get_temp_filename () call git_archive ( '.' , tmp_file , 'HEAD' , settings % verbose , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_publish* Archive error: ' // error % message ) upload_data = [ & & string_t ( 'package_name=\"' // package % name // '\"' ), & & string_t ( 'package_license=\"' // package % license // '\"' ), & & string_t ( 'package_version=\"' // version % s () // '\"' ), & & string_t ( 'tarball=@\"' // tmp_file // '\"' ) & & ] if ( allocated ( settings % token )) upload_data = [ upload_data , string_t ( 'upload_token=\"' // settings % token // '\"' )] if ( settings % show_upload_data ) then call print_upload_data ( upload_data ); return end if ! Make sure a token is provided for publishing. if ( allocated ( settings % token )) then if ( settings % token == '' ) then call delete_file ( tmp_file ); call fpm_stop ( 1 , 'No token provided.' ) end if else call delete_file ( tmp_file ); call fpm_stop ( 1 , 'No token provided.' ) end if if ( settings % verbose ) then call print_upload_data ( upload_data ) print * , '' end if ! Perform network request and validate package, token etc. on the backend once ! https://github.com/fortran-lang/registry/issues/41 is resolved. if ( settings % is_dry_run ) then print * , 'Dry run successful. Generated tarball: ' , tmp_file ; return end if call downloader % upload_form ( official_registry_base_url // '/packages' , upload_data , settings % verbose , error ) call delete_file ( tmp_file ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_publish* Upload error: ' // error % message ) end subroutine print_upload_data ( upload_data ) type ( string_t ), intent ( in ) :: upload_data (:) integer :: i print * , 'Upload data:' do i = 1 , size ( upload_data ) print * , upload_data ( i )% s end do end end","tags":"","loc":"sourcefile/publish.f90.html"},{"title":"new.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_cmd_new Source Code new.f90 Source Code module fpm_cmd_new !># Definition of the \"new\" subcommand !> !> A type of the general command base class [[fpm_cmd_settings]] !> was created for the \"new\" subcommand ==> type [[fpm_new_settings]]. !> This procedure read the values that were set on the command line !> from this type to decide what actions to take. !> !> It is virtually self-contained and so independant of the rest of the !> application that it could function as a separate program. !> !> The \"new\" subcommand options currently consist of a SINGLE top !> directory name to create that must have a name that is an !> allowable Fortran variable name. That should have been ensured !> by the command line processing before this procedure is called. !> So basically this routine has already had the options vetted and !> just needs to conditionally create a few files. !> !> As described in the documentation it will selectively !> create the subdirectories app/, test/, src/, and example/ !> and populate them with sample files. !> !> It also needs to create an initial manifest file \"fpm.toml\". !> !> It then calls the system command \"git init\". !> !> It should test for file existence and not overwrite existing !> files and inform the user if there were conflicts. !> !> Any changes should be reflected in the documentation in !> [[fpm_command_line.f90]] !> !> FUTURE !> A filename like \".\" would need system commands or a standard routine !> like realpath(3c) to process properly. !> !> Perhaps allow more than one name on a single command. It is an arbitrary !> restriction based on a concensus preference, not a required limitation. !> !> Initially the name of the directory is used as the module name in the !> src file so it must be an allowable Fortran variable name. If there are !> complaints about it it might be changed. Handling unicode at this point !> might be problematic as not all current compilers handle it. Other !> utilities like content trackers (ie. git) or repositories like github !> might also have issues with alternative names or names with spaces, etc. !> So for the time being it seems prudent to encourage simple ASCII top directory !> names (similiar to the primary programming language Fortran itself). !> !> Should be able to create or pull more complicated initial examples !> based on various templates. It should place or mention other relevant !> documents such as a description of the manifest file format in user hands; !> or how to access registered packages and local packages, !> although some other command might provide that (and the help command should !> be the first go-to for a CLI utility). use fpm_command_line , only : fpm_new_settings use fpm_environment , only : OS_LINUX , OS_MACOS , OS_WINDOWS use fpm_filesystem , only : join_path , exists , basename , mkdir , is_dir use fpm_filesystem , only : fileopen , fileclose , warnwrite , which , run use fpm_strings , only : join , to_fortran_name use fpm_error , only : fpm_stop use , intrinsic :: iso_fortran_env , only : stderr => error_unit implicit none private public :: cmd_new contains subroutine cmd_new ( settings ) type ( fpm_new_settings ), intent ( in ) :: settings integer , parameter :: tfc = selected_char_kind ( 'DEFAULT' ) character ( len = :, kind = tfc ), allocatable :: bname ! baeename of NAME character ( len = :, kind = tfc ), allocatable :: tomlfile (:) character ( len = :, kind = tfc ), allocatable :: littlefile (:) !> TOP DIRECTORY NAME PROCESSING !> see if requested new directory already exists and process appropriately if ( exists ( settings % name ) . and . . not . settings % backfill ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists.' write ( stderr , '(*(g0,1x))' )& & ' perhaps you wanted to add --backfill ?' return elseif ( is_dir ( settings % name ) . and . settings % backfill ) then write ( * , '(*(g0))' ) 'backfilling ' , settings % name elseif ( exists ( settings % name ) ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists and is not a directory.' return else ! make new directory call mkdir ( settings % name ) endif !> temporarily change to new directory as a test. NB: System dependent call run ( 'cd ' // settings % name ) ! NOTE: need some system routines to handle filenames like \".\" ! like realpath() or getcwd(). bname = basename ( settings % name ) littlefile = [ character ( len = 80 ) :: '# ' // bname , 'My cool new project!' ] ! create NAME/README.md call warnwrite ( join_path ( settings % name , 'README.md' ), littlefile ) ! start building NAME/fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: & & ' # This is your fpm(Fortran Package Manager) manifest file ' ,& & ' # (\"fpm.toml\"). It is heavily annotated to help guide you though ' ,& & ' # customizing a package build, although the defaults are sufficient ' ,& & ' # for many basic packages. ' ,& & ' # ' ,& & ' # The manifest file is not only used to provide metadata identifying ' ,& & ' # your project (so it can be used by others as a dependency). It can ' ,& & ' # specify where your library and program sources live, what the name ' ,& & ' # of the executable(s) will be, what files to build, dependencies on ' ,& & ' # other fpm packages, and what external libraries are required. ' ,& & ' # ' ,& & ' # The manifest format must conform to the TOML configuration file ' ,& & ' # standard. ' ,& & ' # ' ,& & ' # TOML files support flexible use of white-space and commenting of the ' ,& & ' # configuration data, but for clarity in this sample active directives ' ,& & ' # begin in column one. Inactive example directives are commented ' ,& & ' # out with a pound character (\"#\") but begin in column one as well. ' ,& & ' # Commentary begins with a pound character in column three. ' ,& & ' # ' ,& & ' # This file draws heavily upon the following references: ' ,& & ' # ' ,& & ' # The fpm home page at ' ,& & ' # https://github.com/fortran-lang/fpm ' ,& & ' # A complete list of keys and their attributes at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/manifest-reference.md ' ,& & ' # examples of fpm project packaging at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/PACKAGING.md ' ,& & ' # The Fortran TOML file interface and it''s references at ' ,& & ' # https://github.com/toml-f/toml-f ' ,& & ' # ' ,& & ' #----------------------- ' ,& & ' # project Identification ' ,& & ' #----------------------- ' ,& & ' # We begin with project metadata at the manifest root. This data is designed ' ,& & ' # to aid others when searching for the project in a repository and to ' ,& & ' # identify how and when to contact the package supporters. ' ,& & ' ' ,& & 'name = \"' // bname // '\"' ,& & ' # The project name (required) is how the project will be referred to. ' ,& & ' # The name is used by other packages using it as a dependency. It also ' ,& & ' # is used as the default name of any library built and the optional ' ,& & ' # default executable built from app/main.f90. It must conform to the rules ' ,& & ' # for a Fortran variable name. ' ,& & ' ' ,& & 'version = \"0.1.0\" ' ,& & ' # The project version number is a string. A recommended scheme for ' ,& & ' # specifying versions is the Semantic Versioning scheme. ' ,& & ' ' ,& & 'license = \"license\" ' ,& & ' # Licensing information specified using SPDX identifiers is preferred ' ,& & ' # (eg. \"Apache-2.0 OR MIT\" or \"LGPL-3.0-or-later\"). ' ,& & ' ' ,& & 'maintainer = \"jane.doe@example.com\" ' ,& & ' # Information on the project maintainer and means to reach out to them. ' ,& & ' ' ,& & 'author = \"Jane Doe\" ' ,& & ' # Information on the project author. ' ,& & ' ' ,& & 'copyright = \"Copyright 2020 Jane Doe\" ' ,& & ' # A statement clarifying the Copyright status of the project. ' ,& & ' ' ,& & '#description = \"A short project summary in plain text\" ' ,& & ' # The description provides a short summary on the project. It should be ' ,& & ' # plain text and not use any markup formatting. ' ,& & ' ' ,& & '#categories = [\"fortran\", \"graphics\"] ' ,& & ' # Categories associated with the project. Listing only one is preferred. ' ,& & ' ' ,& & '#keywords = [\"hdf5\", \"mpi\"] ' ,& & ' # The keywords field is an array of strings describing the project. ' ,& & ' ' ,& & '#homepage = \"https://stdlib.fortran-lang.org\" ' ,& & ' # URL to the webpage of the project. ' ,& & ' ' ,& & ' # ----------------------------------------- ' ,& & ' # We are done with identifying the project. ' ,& & ' # ----------------------------------------- ' ,& & ' # ' ,& & ' # Now lets start describing how the project should be built. ' ,& & ' # ' ,& & ' # Note tables would go here but we will not be talking about them (much)!!' ,& & ' # ' ,& & ' # Tables are a way to explicitly specify large numbers of programs in ' ,& & ' # a compact format instead of individual per-program entries in the ' ,& & ' # [[executable]], [[test]], and [[example]] sections to follow but ' ,& & ' # will not be discussed further except for the following notes: ' ,& & ' # ' ,& & ' # + Tables must appear (here) before any sections are declared. Once a ' ,& & ' # section is specified in a TOML file everything afterwards must be ' ,& & ' # values for that section or the beginning of a new section. A simple ' ,& & ' # example looks like: ' ,& & ' ' ,& & '#executable = [ ' ,& & '# { name = \"a-prog\" }, ' ,& & '# { name = \"app-tool\", source-dir = \"tool\" }, ' ,& & '# { name = \"fpm-man\", source-dir = \"tool\", main=\"fman.f90\" } ' ,& & '#] ' ,& & ' ' ,& & ' # This would be in lieue of the [[executable]] section found later in this ' ,& & ' # configuration file. ' ,& & ' # + See the reference documents (at the beginning of this document) ' ,& & ' # for more information on tables if you have long lists of programs ' ,& & ' # to build and are not simply depending on auto-detection. ' ,& & ' # ' ,& & ' # Now lets begin the TOML sections (lines beginning with \"[\") ... ' ,& & ' # ' ,& & ' ' ,& & '[install] # Options for the \"install\" subcommand ' ,& & ' ' ,& & ' # When you run the \"install\" subcommand only executables are installed by ' ,& & ' # default on the local system. Library projects that will be used outside of ' ,& & ' # \"fpm\" can set the \"library\" boolean to also allow installing the module ' ,& & ' # files and library archive. Without this being set to \"true\" an \"install\" ' ,& & ' # subcommand ignores parameters that specify library installation. ' ,& & ' ' ,& & 'library = false ' ,& & ' ' ,& & '[build] # General Build Options ' ,& & ' ' ,& & ' ### Automatic target discovery ' ,& & ' # ' ,& & ' # Normally fpm recursively searches the app/, example/, and test/ directories ' ,& & ' # for program sources and builds them. To disable this automatic discovery of ' ,& & ' # program targets set the following to \"false\": ' ,& & ' ' ,& & '#auto-executables = true ' ,& & '#auto-examples = true ' ,& & '#auto-tests = true ' ,& & ' ' ,& & ' ### Package-level External Library Links ' ,& & ' # ' ,& & ' # To declare link-time dependencies on external libraries a list of ' ,& & ' # native libraries can be specified with the \"link\" entry. You may ' ,& & ' # have one library name or a list of strings in case several ' ,& & ' # libraries should be linked. This list of library dependencies is ' ,& & ' # exported to dependent packages. You may have to alter your library ' ,& & ' # search-path to ensure the libraries can be accessed. Typically, ' ,& & ' # this is done with the LD_LIBRARY_PATH environment variable on ULS ' ,& & ' # (Unix-Like Systems). You only specify the core name of the library ' ,& & ' # (as is typical with most programming environments, where you ' ,& & ' # would specify \"-lz\" on your load command to link against the zlib ' ,& & ' # compression library even though the library file would typically be ' ,& & ' # a file called \"libz.a\" \"or libz.so\"). So to link against that library ' ,& & ' # you would specify: ' ,& & ' ' ,& & '#link = \"z\" ' ,& & ' ' ,& & ' # Note that in some cases the order of the libraries matters: ' ,& & ' ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_lib ) then call mkdir ( join_path ( settings % name , 'src' ) ) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[library] ' ,& & ' ' ,& & ' # You can change the name of the directory to search for your library ' ,& & ' # source from the default of \"src/\". Library targets are exported ' ,& & ' # and usable by other projects. ' ,& & ' ' ,& & 'source-dir=\"src\" ' ,& & ' ' ,& & ' # this can be a list: ' ,& & ' ' ,& & '#source-dir=[\"src\", \"src2\"] ' ,& & ' ' ,& & ' # More complex libraries may organize their modules in subdirectories. ' ,& & ' # For modules in a top-level directory fpm requires (but does not ' ,& & ' # enforce) that: ' ,& & ' # ' ,& & ' # + The module has the same name as the source file. This is important. ' ,& & ' # + There should be only one module per file. ' ,& & ' # ' ,& & ' # These two requirements simplify the build process for fpm. As Fortran ' ,& & ' # compilers emit module files (.mod) with the same name as the module ' ,& & ' # itself (but not the source file, .f90), naming the module the same ' ,& & ' # as the source file allows fpm to: ' ,& & ' # ' ,& & ' # + Uniquely and exactly map a source file (.f90) to its object (.o) ' ,& & ' # and module (.mod) files. ' ,& & ' # + Avoid conflicts with modules of the same name that could appear ' ,& & ' # in dependency packages. ' ,& & ' # ' ,& & ' ### Multi-level library source ' ,& & ' # You can place your module source files in any number of levels of ' ,& & ' # subdirectories inside your source directory, but there are certain naming ' ,& & ' # conventions to be followed -- module names must contain the path components ' ,& & ' # of the directory that its source file is in. ' ,& & ' # ' ,& & ' # This rule applies generally to any number of nested directories and ' ,& & ' # modules. For example, src/a/b/c/d.f90 must define a module called a_b_c_d. ' ,& & ' # Again, this is not enforced but may be required in future releases. ' ,& & '' ] endif ! create placeholder module src/bname.f90 littlefile = [ character ( len = 80 ) :: & & 'module ' // to_fortran_name ( bname ), & & ' implicit none' , & & ' private' , & & '' , & & ' public :: say_hello' , & & 'contains' , & & ' subroutine say_hello' , & & ' print *, \"Hello, ' // bname // '!\"' , & & ' end subroutine say_hello' , & & 'end module ' // to_fortran_name ( bname )] ! create NAME/src/NAME.f90 call warnwrite ( join_path ( settings % name , 'src' , bname // '.f90' ),& & littlefile ) endif if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[dependencies] ' ,& & ' ' ,& & ' # Inevitably, you will want to be able to include other packages in ' ,& & ' # a project. Fpm makes this incredibly simple, by taking care of ' ,& & ' # fetching and compiling your dependencies for you. You just tell it ' ,& & ' # what your dependencies names are, and where to find them. ' ,& & ' # ' ,& & ' # If you are going to distribute your package only place dependencies ' ,& & ' # here someone using your package as a remote dependency needs built. ' ,& & ' # You can define dependencies just for developer executables in the ' ,& & ' # next section, or even for specific executables as we will see below ' ,& & ' # (Then fpm will still fetch and compile it when building your ' ,& & ' # developer executables, but users of your library will not have to). ' ,& & ' # ' ,& & ' ## GLOBAL DEPENDENCIES (exported with your project) ' ,& & ' # ' ,& & ' # Typically, dependencies are defined by specifying the project''s ' ,& & ' # git repository. ' ,& & ' # ' ,& & ' # You can be specific about which version of a dependency you would ' ,& & ' # like. By default the latest default branch is used. You can ' ,& & ' # optionally specify a branch, a tag or a commit value. ' ,& & ' # ' ,& & ' # So here are several alternates for specifying a remote dependency (you ' ,& & ' # can have at most one of \"branch\", \"rev\" or \"tag\" present): ' ,& & ' ' ,& & '#stdlib = { git = \"https://github.com/LKedward/stdlib-fpm.git\" } ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\",branch = \"master\" },' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", tag = \"v0.1.0\" }, ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", rev = \"5a9b7a8\" }. ' ,& & ' ' ,& & ' # There may be multiple packages listed: ' ,& & ' ' ,& & '#M_strings = { git = \"https://github.com/urbanjost/M_strings.git\" } ' ,& & '#M_time = { git = \"https://github.com/urbanjost/M_time.git\" } ' ,& & ' ' ,& & ' # ' ,& & ' # You can even specify the local path to another project if it is in ' ,& & ' # a sub-folder (If for example you have got another fpm package **in ' ,& & ' # the same repository**) like this: ' ,& & ' ' ,& & '#M_strings = { path = \"M_strings\" } ' ,& & ' ' ,& & ' # This tells fpm that we depend on a crate called M_strings which is found ' ,& & ' # in the M_strings folder (relative to the fpm.toml it’s written in). ' ,& & ' # ' ,& & ' # For a more verbose layout use normal tables rather than inline tables ' ,& & ' # to specify dependencies: ' ,& & ' ' ,& & '#[dependencies.toml-f] ' ,& & '#git = \"https://github.com/toml-f/toml-f\" ' ,& & '#rev = \"2f5eaba864ff630ba0c3791126a3f811b6e437f3\" ' ,& & ' ' ,& & ' # Now you can use any modules from these libraries anywhere in your ' ,& & ' # code -- whether is in your library source or a program source. ' ,& & ' ' ,& & '[dev-dependencies] ' ,& & ' ' ,& & ' ## Dependencies Only for Development ' ,& & ' # ' ,& & ' # You can specify dependencies your library or application does not ' ,& & ' # depend on in a similar way. The difference is that these will not ' ,& & ' # be exported as part of your project to those using it as a remote ' ,& & ' # dependency. ' ,& & ' # ' ,& & ' # Currently, like a global dependency it will still be available for ' ,& & ' # all codes. It is up to the developer to ensure that nothing except ' ,& & ' # developer test programs rely upon it. ' ,& & ' ' ,& & '#M_msg = { git = \"https://github.com/urbanjost/M_msg.git\" } ' ,& & '#M_verify = { git = \"https://github.com/urbanjost/M_verify.git\" } ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_executable ) then ! create next section of fpm.toml call mkdir ( join_path ( settings % name , 'app' )) ! create NAME/app or stop if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & ' #----------------------------------- ' ,& & ' ## Application-specific declarations ' ,& & ' #----------------------------------- ' ,& & ' # Now lets begin entries for the TOML tables (lines beginning with \"[[\") ' ,& & ' # that describe the program sources -- applications, tests, and examples. ' ,& & ' # ' ,& & ' # First we will configuration individual applications run with \"fpm run\". ' ,& & ' # ' ,& & ' # + the \"name\" entry for the executable to be built must always ' ,& & ' # be specified. The name must satisfy the rules for a Fortran ' ,& & ' # variable name. This will be the name of the binary installed by ' ,& & ' # the \"install\" subcommand and used on the \"run\" subcommand. ' ,& & ' # + The source directory for each executable can be adjusted by the ' ,& & ' # \"source-dir\" entry. ' ,& & ' # + The basename of the source file containing the program body can ' ,& & ' # be specified with the \"main\" entry. ' ,& & ' # + Executables can also specify their own external package and ' ,& & ' # library link dependencies. ' ,& & ' # ' ,& & ' # Currently, like a global dependency any external package dependency ' ,& & ' # will be available for all codes. It is up to the developer to ensure ' ,& & ' # that nothing except the application programs specified rely upon it. ' ,& & ' # ' ,& & ' # Note if your application needs to use a module internally, but you do not ' ,& & ' # intend to build it as a library to be used in other projects, you can ' ,& & ' # include the module in your program source file or directory as well. ' ,& & ' ' ,& & '[[executable]] ' ,& & 'name=\"' // bname // '\"' ,& & 'source-dir=\"app\" ' ,& & 'main=\"main.f90\" ' ,& & ' ' ,& & ' # You may repeat this pattern to define additional applications. For instance,' ,& & ' # the following sample illustrates all accepted options, where \"link\" and ' ,& & ' # \"executable.dependencies\" keys are the same as the global external library ' ,& & ' # links and package dependencies described previously except they apply ' ,& & ' # only to this executable: ' ,& & ' ' ,& & '#[[ executable ]] ' ,& & '#name = \"app-name\" ' ,& & '#source-dir = \"prog\" ' ,& & '#main = \"program.f90\" ' ,& & '#link = \"z\" ' ,& & '#[executable.dependencies] ' ,& & '#M_CLI = { git = \"https://github.com/urbanjost/M_CLI.git\" } ' ,& & '#helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } ' ,& & '#M_path = { git = \"https://github.com/urbanjost/M_path.git\" } ' ,& & '' ] endif if ( exists ( bname // '/src/' )) then littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' use ' // to_fortran_name ( bname ) // ', only: say_hello' , & & ' implicit none' , & & '' , & & ' call say_hello()' , & & 'end program main' ] else littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' implicit none' , & & '' , & & ' print *, \"hello from project ' // bname // '\"' , & & 'end program main' ] endif call warnwrite ( join_path ( settings % name , 'app/main.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_test ) then ! create NAME/test or stop call mkdir ( join_path ( settings % name , 'test' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[[test]] ' ,& & ' ' ,& & ' # The same declarations can be made for test programs, which are ' ,& & ' # executed with the \"fpm test\" command and are not build when your ' ,& & ' # package is used as a dependency by other packages. These are ' ,& & ' # typically unit tests of the package only used during package ' ,& & ' # development. ' ,& & ' ' ,& & 'name=\"runTests\" ' ,& & 'source-dir=\"test\" ' ,& & 'main=\"check.f90\" ' ,& & ' ' ,& & ' # you may repeat this pattern to add additional explicit test program ' ,& & ' # parameters. The following example contains a sample of all accepted ' ,& & ' # options. ' ,& & ' ' ,& & '#[[ test ]] ' ,& & '#name = \"tester\" ' ,& & '#source-dir=\"test\" ' ,& & '#main=\"tester.f90\" ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '#[test.dependencies] ' ,& & '#M_CLI2 = { git = \"https://github.com/urbanjost/M_CLI2.git\" } ' ,& & '#M_io = { git = \"https://github.com/urbanjost/M_io.git\" } ' ,& & '#M_system= { git = \"https://github.com/urbanjost/M_system.git\" } ' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program check' , & & 'implicit none' , & & '' , & & 'print *, \"Put some tests in here!\"' , & & 'end program check' ] ! create NAME/test/check.f90 call warnwrite ( join_path ( settings % name , 'test/check.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_example ) then ! create NAME/example or stop call mkdir ( join_path ( settings % name , 'example' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[[example]] ' ,& & ' ' ,& & ' # Example applications for a project are defined here. ' ,& & ' # These are run via \"fpm run --example NAME\" and like the ' ,& & ' # test applications, are not built when this package is used as a ' ,& & ' # dependency by other packages. ' ,& & ' ' ,& & 'name=\"demo\" ' ,& & 'source-dir=\"example\" ' ,& & 'main=\"demo.f90\" ' ,& & ' ' ,& & ' # ' ,& & ' # you may add additional programs to the example table. The following ' ,& & ' # example contains a sample of all accepted options ' ,& & ' ' ,& & '#[[ example ]] ' ,& & '#name = \"example-tool\" ' ,& & '#source-dir=\"example\" ' ,& & '#main=\"tool.f90\" ' ,& & '#link = \"z\" ' ,& & '#[example.dependencies] ' ,& & '#M_kracken95 = { git = \"https://github.com/urbanjost/M_kracken95.git\" } ' ,& & '#datetime = {git = \"https://github.com/wavebitscientific/datetime-fortran.git\" }' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program demo' , & & 'implicit none' , & & '' , & & 'print *, \"Put some examples in here!\"' , & & 'end program demo' ] ! create NAME/example/demo.f90 call warnwrite ( join_path ( settings % name , 'example/demo.f90' ), littlefile ) endif ! now that built it write NAME/fpm.toml if ( allocated ( tomlfile ) ) then call validate_toml_data ( tomlfile ) call warnwrite ( join_path ( settings % name , 'fpm.toml' ), tomlfile ) else call create_verified_basic_manifest ( join_path ( settings % name , 'fpm.toml' )) endif ! assumes git(1) is installed and in path if ( which ( 'git' ) /= '' ) then call run ( 'git init ' // settings % name ) endif contains function git_metadata ( what ) result ( returned ) !> get metadata values such as email address and git name from git(1) or return appropriate default use fpm_filesystem , only : get_temp_filename , getline character ( len =* ), intent ( in ) :: what ! keyword designating what git metatdata to query character ( len = :), allocatable :: returned ! value to return for requested keyword character ( len = :), allocatable :: command character ( len = :), allocatable :: temp_filename character ( len = :), allocatable :: iomsg character ( len = :), allocatable :: temp_value integer :: stat , unit temp_filename = get_temp_filename () ! for known keywords set default value for RETURNED and associated git(1) command for query select case ( what ) case ( 'uname' ) returned = \"Jane Doe\" command = \"git config --get user.name > \" // temp_filename case ( 'email' ) returned = \"jane.doe@example.com\" command = \"git config --get user.email > \" // temp_filename case default write ( stderr , '(*(g0,1x))' )& & ' *git_metadata* unknown metadata name ' , trim ( what ) returned = '' return end select ! Execute command if git(1) is in command path if ( which ( 'git' ) /= '' ) then call run ( command , exitstat = stat ) if ( stat /= 0 ) then ! If command failed just return default return else ! Command did not return an error so try to read expected output file open ( file = temp_filename , newunit = unit , iostat = stat ) if ( stat == 0 ) then ! Read file into a scratch variable until status of doing so is checked call getline ( unit , temp_value , stat , iomsg ) if ( stat == 0 . and . temp_value /= '' ) then ! Return output from successful command returned = temp_value endif endif ! Always do the CLOSE because a failed open has unpredictable results. ! Add IOSTAT so a failed close does not cause program to stop close ( unit , status = \"delete\" , iostat = stat ) endif endif end function git_metadata subroutine create_verified_basic_manifest ( filename ) !> create a basic but verified default manifest file use fpm_toml , only : toml_table , toml_serialize , set_value use fpm_manifest_package , only : package_config_t , new_package use fpm_error , only : error_t implicit none character ( len =* ), intent ( in ) :: filename type ( toml_table ) :: table type ( package_config_t ) :: package type ( error_t ), allocatable :: error integer :: lun character ( len = 8 ) :: date character (:), allocatable :: output if ( exists ( filename )) then write ( stderr , '(*(g0,1x))' ) ' ' , filename ,& & 'already exists. Not overwriting' return endif !> get date to put into metadata in manifest file \"fpm.toml\" call date_and_time ( DATE = date ) table = toml_table () call fileopen ( filename , lun ) ! fileopen stops on error call set_value ( table , \"name\" , BNAME ) call set_value ( table , \"version\" , \"0.1.0\" ) call set_value ( table , \"license\" , \"license\" ) call set_value ( table , \"author\" , git_metadata ( 'uname' )) call set_value ( table , \"maintainer\" , git_metadata ( 'email' )) call set_value ( table , \"copyright\" , 'Copyright ' // date ( 1 : 4 ) // ', ' // git_metadata ( 'uname' )) ! continue building of manifest ! ... call new_package ( package , table , error = error ) if ( allocated ( error )) call fpm_stop ( 3 , '' ) output = toml_serialize ( table ) if ( settings % verbose ) then print '(a)' , output endif write ( lun , '(a)' ) output call fileclose ( lun ) ! fileopen stops on error end subroutine create_verified_basic_manifest subroutine validate_toml_data ( input ) !> verify a string array is a valid fpm.toml file ! use tomlf , only : toml_load use fpm_toml , only : toml_table , toml_serialize implicit none character ( kind = tfc , len = :), intent ( in ), allocatable :: input (:) character ( len = 1 ), parameter :: nl = new_line ( 'a' ) type ( toml_table ), allocatable :: table character ( kind = tfc , len = :), allocatable :: joined_string ! you have to add a newline character by using the intrinsic ! function `new_line(\"a\")` to get the lines processed correctly. joined_string = join ( input , right = nl ) if ( allocated ( table )) deallocate ( table ) call toml_load ( table , joined_string ) if ( allocated ( table )) then if ( settings % verbose ) then ! If the TOML file is successfully parsed the table will be allocated and ! can be written by `toml_serialize` to the standard output print '(a)' , toml_serialize ( table ) endif call table % destroy endif end subroutine validate_toml_data end subroutine cmd_new end module fpm_cmd_new","tags":"","loc":"sourcefile/new.f90.html"},{"title":"install.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_cmd_install Source Code install.f90 Source Code module fpm_cmd_install use , intrinsic :: iso_fortran_env , only : output_unit use fpm , only : build_model use fpm_backend , only : build_package use fpm_command_line , only : fpm_install_settings use fpm_error , only : error_t , fatal_error , fpm_stop use fpm_filesystem , only : join_path , list_files use fpm_installer , only : installer_t , new_installer use fpm_manifest , only : package_config_t , get_package_data use fpm_model , only : fpm_model_t , FPM_SCOPE_APP use fpm_targets , only : targets_from_sources , build_target_t , & build_target_ptr , FPM_TARGET_EXECUTABLE , & filter_library_targets , filter_executable_targets , filter_modules use fpm_strings , only : string_t , resize implicit none private public :: cmd_install contains !> Entry point for the fpm-install subcommand subroutine cmd_install ( settings ) !> Representation of the command line settings type ( fpm_install_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( error_t ), allocatable :: error type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( installer_t ) :: installer type ( string_t ), allocatable :: list (:) logical :: installable call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) call build_model ( model , settings , package , error ) call handle_error ( error ) call targets_from_sources ( targets , model , settings % prune , error ) call handle_error ( error ) installable = ( allocated ( package % library ) . and . package % install % library ) & . or . allocated ( package % executable ) if (. not . installable ) then call fatal_error ( error , \"Project does not contain any installable targets\" ) call handle_error ( error ) end if if ( settings % list ) then call install_info ( output_unit , targets ) return end if if (. not . settings % no_rebuild ) then call build_package ( targets , model , verbose = settings % verbose ) end if call new_installer ( installer , prefix = settings % prefix , & bindir = settings % bindir , libdir = settings % libdir , & includedir = settings % includedir , & verbosity = merge ( 2 , 1 , settings % verbose )) if ( allocated ( package % library ) . and . package % install % library ) then call filter_library_targets ( targets , list ) if ( size ( list ) > 0 ) then call installer % install_library ( list ( 1 )% s , error ) call handle_error ( error ) call install_module_files ( installer , targets , error ) call handle_error ( error ) end if end if if ( allocated ( package % executable )) then call install_executables ( installer , targets , error ) call handle_error ( error ) end if end subroutine cmd_install subroutine install_info ( unit , targets ) integer , intent ( in ) :: unit type ( build_target_ptr ), intent ( in ) :: targets (:) integer :: ii , ntargets type ( string_t ), allocatable :: install_target (:), temp (:) allocate ( install_target ( 0 )) call filter_library_targets ( targets , temp ) install_target = [ install_target , temp ] call filter_executable_targets ( targets , FPM_SCOPE_APP , temp ) install_target = [ install_target , temp ] ntargets = size ( install_target ) write ( unit , '(\"#\", *(1x, g0))' ) & \"total number of installable targets:\" , ntargets do ii = 1 , ntargets write ( unit , '(\"-\", *(1x, g0))' ) install_target ( ii )% s end do end subroutine install_info subroutine install_module_files ( installer , targets , error ) type ( installer_t ), intent ( inout ) :: installer type ( build_target_ptr ), intent ( in ) :: targets (:) type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ), allocatable :: modules (:) integer :: ii call filter_modules ( targets , modules ) do ii = 1 , size ( modules ) call installer % install_header ( modules ( ii )% s // \".mod\" , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end subroutine install_module_files subroutine install_executables ( installer , targets , error ) type ( installer_t ), intent ( inout ) :: installer type ( build_target_ptr ), intent ( in ) :: targets (:) type ( error_t ), allocatable , intent ( out ) :: error integer :: ii do ii = 1 , size ( targets ) if ( is_executable_target ( targets ( ii )% ptr )) then call installer % install_executable ( targets ( ii )% ptr % output_file , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end subroutine install_executables elemental function is_executable_target ( target_ptr ) result ( is_exe ) type ( build_target_t ), intent ( in ) :: target_ptr logical :: is_exe is_exe = target_ptr % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( target_ptr % dependencies ) if ( is_exe ) then is_exe = target_ptr % dependencies ( 1 )% ptr % source % unit_scope == FPM_SCOPE_APP end if end function is_executable_target subroutine handle_error ( error ) type ( error_t ), intent ( in ), optional :: error if ( present ( error )) then call fpm_stop ( 1 , error % message ) end if end subroutine handle_error end module fpm_cmd_install","tags":"","loc":"sourcefile/install.f90~2.html"},{"title":"update.f90 – Fortran-lang/fpm","text":"Contents Modules fpm_cmd_update Source Code update.f90 Source Code module fpm_cmd_update use fpm_command_line , only : fpm_update_settings use fpm_dependency , only : dependency_tree_t , new_dependency_tree use fpm_error , only : error_t , fpm_stop use fpm_filesystem , only : exists , mkdir , join_path , delete_file , filewrite use fpm_manifest , only : package_config_t , get_package_data implicit none private public :: cmd_update contains !> Entry point for the update subcommand subroutine cmd_update ( settings ) !> Representation of the command line arguments type ( fpm_update_settings ), intent ( in ) :: settings type ( package_config_t ) :: package type ( dependency_tree_t ) :: deps type ( error_t ), allocatable :: error integer :: ii character ( len = :), allocatable :: cache call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) if (. not . exists ( \"build\" )) then call mkdir ( \"build\" ) call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if cache = join_path ( \"build\" , \"cache.toml\" ) if ( settings % clean ) call delete_file ( cache ) call new_dependency_tree ( deps , cache = cache , & verbosity = merge ( 2 , 1 , settings % verbose )) call deps % add ( package , error ) call handle_error ( error ) ! Force-update all dependencies if `--clean` if ( settings % clean ) then do ii = 1 , deps % ndep deps % dep ( ii )% update = . true . end do end if if ( settings % fetch_only ) return if ( size ( settings % name ) == 0 ) then call deps % update ( error ) call handle_error ( error ) else do ii = 1 , size ( settings % name ) call deps % update ( trim ( settings % name ( ii )), error ) call handle_error ( error ) end do end if end subroutine cmd_update !> Error handling for this command subroutine handle_error ( error ) !> Potential error type ( error_t ), intent ( in ), optional :: error if ( present ( error )) then call fpm_stop ( 1 , error % message ) end if end subroutine handle_error end module fpm_cmd_update","tags":"","loc":"sourcefile/update.f90.html"},{"title":"main.f90 – Fortran-lang/fpm","text":"Contents Programs main Source Code main.f90 Source Code program main use , intrinsic :: iso_fortran_env , only : error_unit , output_unit use fpm_command_line , only : & fpm_cmd_settings , & fpm_new_settings , & fpm_build_settings , & fpm_run_settings , & fpm_test_settings , & fpm_install_settings , & fpm_update_settings , & fpm_clean_settings , & fpm_publish_settings , & get_command_line_settings use fpm_error , only : error_t use fpm_filesystem , only : exists , parent_dir , join_path use fpm , only : cmd_build , cmd_run , cmd_clean use fpm_cmd_install , only : cmd_install use fpm_cmd_new , only : cmd_new use fpm_cmd_update , only : cmd_update use fpm_cmd_publish , only : cmd_publish use fpm_os , only : change_directory , get_current_directory implicit none class ( fpm_cmd_settings ), allocatable :: cmd_settings type ( error_t ), allocatable :: error character ( len = :), allocatable :: pwd_start , pwd_working , working_dir , project_root call get_command_line_settings ( cmd_settings ) call get_current_directory ( pwd_start , error ) call handle_error ( error ) call get_working_dir ( cmd_settings , working_dir ) if ( allocated ( working_dir )) then ! Change working directory if requested if ( len_trim ( working_dir ) > 0 ) then call change_directory ( working_dir , error ) call handle_error ( error ) call get_current_directory ( pwd_working , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // pwd_working // \"'\" else pwd_working = pwd_start end if else pwd_working = pwd_start end if select type ( settings => cmd_settings ) type is ( fpm_new_settings ) class default if (. not . has_manifest ( pwd_working )) then project_root = pwd_working do while (. not . has_manifest ( project_root )) working_dir = parent_dir ( project_root ) if ( len ( working_dir ) == 0 ) exit project_root = working_dir end do if ( has_manifest ( project_root )) then call change_directory ( project_root , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // project_root // \"'\" end if end if end select select type ( settings => cmd_settings ) type is ( fpm_new_settings ) call cmd_new ( settings ) type is ( fpm_build_settings ) call cmd_build ( settings ) type is ( fpm_run_settings ) call cmd_run ( settings , test = . false .) type is ( fpm_test_settings ) call cmd_run ( settings , test = . true .) type is ( fpm_install_settings ) call cmd_install ( settings ) type is ( fpm_update_settings ) call cmd_update ( settings ) type is ( fpm_clean_settings ) call cmd_clean ( settings ) type is ( fpm_publish_settings ) call cmd_publish ( settings ) end select if ( allocated ( project_root )) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // project_root // \"'\" end if if ( pwd_start /= pwd_working ) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // pwd_working // \"'\" end if contains function has_manifest ( dir ) character ( len =* ), intent ( in ) :: dir logical :: has_manifest has_manifest = exists ( join_path ( dir , \"fpm.toml\" )) end function has_manifest subroutine handle_error ( error_ ) type ( error_t ), optional , intent ( in ) :: error_ if ( present ( error_ )) then write ( error_unit , '(\"[Error]\", 1x, a)' ) error_ % message stop 1 end if end subroutine handle_error !> Save access to working directory in settings, in case setting have not been allocated subroutine get_working_dir ( settings , working_dir_ ) class ( fpm_cmd_settings ), optional , intent ( in ) :: settings character ( len = :), allocatable , intent ( out ) :: working_dir_ if ( present ( settings )) then working_dir_ = settings % working_dir end if end subroutine get_working_dir end program main","tags":"","loc":"sourcefile/main.f90.html"},{"title":"Packaging and contributing – Fortran-lang/fpm","text":"","tags":"","loc":"page/index.html"},{"title":"Contributing Guidelines – Fortran-lang/fpm","text":"Contributing to the Fortran Package Manager Thank you for considering contributing to the Fortran Package Manager ( fpm ).\nPlease review and follow these guidelines to make the contribution process\nsimple and effective for all involved. It will help communicate that you\nrespect the time of the community developers. In return, the community will\nhelp address your problem, evaluate changes, and guide you through your pull\nrequests. By contributing to fpm , you certify that you own or are allowed to share the\ncontent of your contribution under the fpm license . Style Reporting a bug Suggesting a feature Workflow General guidelines For new contributors Style Please follow the Fortran stdlib style guide for any Fortran code that you contribute.\nThis allows us to focus on substance rather than style. Reporting a bug A bug is a demonstrable problem caused by the code in this repository.\nGood bug reports are extremely valuable to us—thank you! Before opening a bug report: Check if the issue has already been reported\n ( issues ). Check if it is still an issue or it has been fixed?\n Try to reproduce it with the latest version from the default branch. Isolate the problem and create a minimal test case. A good bug report should include all information needed to reproduce the bug.\nPlease be as detailed as possible: Which version of fpm are you using? Please be specific. What are the steps to reproduce the issue? What is the expected outcome? What happens instead? This information will help the community diagnose the issue quickly and with\nminimal back-and-forth. Suggesting a feature Before suggesting a new feature, take a moment to find out if it fits the scope\nof the project, or if it has already been discussed. It is up to you to provide\na strong argument to convince the community of the benefits of this feature.\nPlease provide as much detail and context as possible. If applicable, include a\nmocked-up snippet of what the output or behavior would look like with this\nfeature implemented. “Crazy”, out-of-the-box ideas are especially welcome.\nIt’s quite possible that we are not considering an unusually creative solution. Workflow fpm is a community project. There is no one single person making final\ndecisions. This is the workflow that we follow: Open a new issue to\n describe a bug or propose a new feature.\n Refer to the earlier sections on how to write a good bug report or feature\n request. Discuss with the community and reach majority consensus about what should be\n done about the bug or feature request.\n We define “majority” loosely as 80%.\n This means that at least 4 of 5 people engaged in the discussion should be\n able to agree on the next step.\n This allows us to have the community mostly agree while not getting stuck if\n one person disagrees.\n At this stage, the scope of the fix/feature, its behavior, and API if\n applicable should be defined.\n Only when you have community consensus on these items you should proceed to\n writing code and opening a PR. When actively working on code towards a PR, please assign yourself to the\n issue on GitHub. This is good collaborative practice to avoid duplicated effort and also\n inform others what you are currently working on. Open a new Pull Request (PR) with your contribution.\n The body of the PR should at least include a bullet-point summary of the\n changes, and a detailed description is encouraged.\n If the PR completely addresses the issue you opened in step 1, include in\n the PR description the following line: Fixes # . Request reviewers to your PR.\n For small bug fixes or documentation improvements, 1 to 2 reviewers is\n sufficient.\n For implementation of bigger features, request 3 to 4 or more reviewers.\n Ideally, request reviewers that participated in step 2. If your PR implements a feature that adds or changes the behavior of fpm ,\n your PR must also include appropriate changes to the documentation. This workflow can evolve and change over time as we learn how best to work\ntogether. If you have an idea on how to improve the workflow itself, please\nopen an issue and we’ll discuss it. General guidelines A PR should implement only one feature or bug fix. Do not commit changes to files that are irrelevant to your feature or bug fix. Smaller PRs are better than large PRs, and will lead to a shorter review and\n merge cycle Add tests for your feature or bug fix to be sure that it stays functional and useful Be open to constructive criticism and requests for improving your code. Again, please follow the Fortran stdlib style guide . For new contributors If you have never created a pull request before, welcome :tada:.\nYou can learn how from this great tutorial . Don’t know where to start?\nYou can start by looking through the list of open issues .","tags":"","loc":"page/Contributing.html"},{"title":"License – Fortran-lang/fpm","text":"MIT License Copyright (c) 2020 fpm contributors Permission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the “Software”), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","tags":"","loc":"page/License.html"},{"title":"Manifest reference – Fortran-lang/fpm","text":"301 - Moved This document now lives at https://fpm.fortran-lang.org/en/spec/manifest.html.","tags":"","loc":"page/Manifest.html"},{"title":"Packaging with fpm – Fortran-lang/fpm","text":"Preparing your package for FPM This document describes how you need to organize your application or library for\nit to successfully build with the Fortran Package Manager ( fpm ). What kind of package can fpm build? Example package layouts Single program Single-module library Multi-module library Application and library Multi-level library Be more explicit Add some tests Adding dependencies Custom build scripts What kind of package can fpm build? You can use fpm to build: Applications (program only) Libraries (modules only) Combination of the two (programs and modules combined) Let’s look at some examples of different kinds of package layouts that you can\nuse with fpm . Example package layouts This section describes some example package layouts that you can build with fpm . You can use them to model the layout of your own package. Single program Let’s start with the simplest package imaginable—a single program without\ndependencies or modules. Here’s what the layout of the top-level directory\nlooks like: .\n├── app\n│ └── main.f90\n└── fpm.toml We have one source file ( main.f90 ) in one directory ( app ). Its contents\nare: program main print * , 'Hello, World!' end program main This program prints the usual greeting to the standard output, and nothing more. There’s another important file in the top-level directory, fpm.toml . This is fpm ’s configuration file specific to your package. It includes all the data\nthat fpm needs to build your app. In our simple case, it looks like this: name = \"hello\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" The preamble includes some metadata, such as license , author , and similar,\nthat you may have seen in other package manager configuration files. The one\noption that matters here right now is: name = \"hello\" This line specifies the name of your package, which determines the name of the\nexecutable file of your program. In this example, our program executable, once\nbuilt, will be called hello . Let’s now build this program using fpm : $ fpm build # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/hello) On the first line, we ran fpm build to compile and link the application.\nThe latter two lines are emitted by fpm , and indicate which command was\nexecuted at each build step ( gfortran ), and which files have been output\nby it: object file main.o , and executable hello . We can now run the app with fpm run : $ fpm run\n Hello, World! If your application needs to use a module internally, but you don’t intend\nto build it as a library to be used in other projects, you can include the\nmodule in your program source file as well.\nFor example: $ cat app / main . f90 module math_constants real , parameter :: pi = 4 * atan ( 1. ) end module math_constants program main use math_constants , only : pi print * , 'Hello, World!' print * , 'pi = ' , pi end program main Now, run this using fpm run : $ fpm run # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/hello) Hello, World! pi = 3 .14159274 Although we have named our program hello , which is the same name as the\npackage name in fpm.toml , you can name it anything you want as long as it’s\npermitted by the language. Notice that you can run fpm run , and if the package hasn’t been built yet, fpm build will run automatically for you. This is true if the source files\nhave been updated since the last build. Thus, if you want to run your\napplication, you can skip the fpm build step, and go straight to fpm run . When running your application using fpm run , the program’s exit code is\npassed by fpm back to the operating system. So, it is possible to use Fortran\nnumbered stop and error stop codes to pass termination reasons back to the terminal. Try running the following app with fpm run : program main use math_constants , only : pi real :: angle read ( * , * , iostat = ierr ) angle if ( ierr /= 0 ) then stop 2 ! Not real elseif ( angle > pi ) then stop 1 else stop 0 endif end program main and then checking that the error code matches. Note that error codes are passed to variable $? on Unix/Mac systems, and to environment variable %errorlevel% on Windows. In this last example, our source file defined a math_constants module inside\nthe same source file as the main program. Let’s see how we can define an fpm package that makes this module available as a library. Single-module library The package layout for this example looks like this: . ├── fpm . toml └── src └── math_constants . f90 In this example we’ll build a simple math constants library that exports\nthe number pi as a parameter: $ cat src / math_constants . f90 module math_constants real , parameter :: pi = 4 * atan ( 1. ) end module math_constants and our fpm.toml is the same as before. Now use fpm build to build the package: $ fpm build # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a Based on the output of fpm build , fpm first ran gfortran to emit the\nbinary object ( math_constants.o ) and module ( math_constants.mod ) files.\nThen it ran ar to create a static library archive math_constants.a . build/debug/library is thus both your include and library path, should you\nwant to compile and link an external program with this library. For modules in the top-level ( src ) directory, fpm requires that: The module has the same name as the source file. There is only one module per file. These two requirements simplify the build process for fpm . As Fortran\ncompilers emit module files ( .mod ) with the same name as the module itself\n(but not the source file, .f90 ), naming the module the same as the source file\nallows fpm to: Uniquely and exactly map a source file ( .f90 ) to its object ( .o ) and\nmodule ( .mod ) files. Avoid conflicts with modules of the same name that could appear in dependency\npackages (more on this in a bit). Since this is a library without executable programs, fpm run here does\nnothing. In this example, our library is made of only one module. However, most\nreal-world libraries are likely to use multiple modules. Let’s see how you can\npackage your multi-module library. Multi-module library In this example, we’ll use another module to define a 64-bit real kind\nparameter and make it available in math_constants to define pi with\nhigher precision. To make this exercise worthwhile, we’ll define another math\nconstant, Euler’s number. Our package layout looks like this: . ├── fpm . toml └── src ├── math_constants . f90 └── type_kinds . f90 And our source file contents are: $ cat src / math_constants . f90 module math_constants use type_kinds , only : rk real ( rk ), parameter :: pi = 4 * atan ( 1._rk ) real ( rk ), parameter :: e = exp ( 1._rk ) end module math_constants $ cat src / type_kinds . f90 module type_kinds use iso_fortran_env , only : real64 integer , parameter :: rk = real64 end module type_kinds and there are no changes to our fpm.toml relative to previous examples. Like before, notice that the module type_kinds is name exactly as the\nsource file that contains it.\nThis is important. By now you know how to build the package: $ fpm build # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a Our build path now contains: $ ls build/debug/library/\nmath_constants.a math_constants.mod math_constants.o type_kinds.mod type_kinds.o And the static library includes all the object files: $ nm build/debug/library/math_constants.a\n\nmath_constants.o:\n\ntype_kinds.o: The takeaways from this example are that: fpm automatically scanned the src directory for any source files. It also resolved the dependency order between different modules. Application and library Let’s now combine the two previous examples into one: We’ll build the math\nconstants library and an executable program that uses it. We’ll use this\nprogram as a demo, and to verify that defining higher-precision constants from\nthe previous example actually worked. Here’s the package layout for your application + library package: . ├── app │ └── main . f90 ├── fpm . toml └── src ├── math_constants . f90 └── type_kinds . f90 Our fpm.toml remains unchanged and our executable program source file is: $ cat app / main . f90 program main use math_constants , only : e , pi print * , 'math_constants library demo' print * , 'pi = ' , pi print * , 'e = ' , e end program main Let’s go straight to running the demo program: $ fpm run # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/math_constants) math_constants library demo pi = 3 .1415926535897931 e = 2 .7182818284590451 The fpm build + run process works as expected, and our program correctly\noutputs higher-precision constants. So far we covered how fpm builds: A single program A single-module library A multi-module library A program and a library However, all our modules so far have been organized in the top level source\ndirectory. More complex libraries may organize their modules in subdirectories.\nLet’s see how we can build this with fpm . Multi-level library In this example, we’ll define our library as a collection of modules, two of\nwhich are defined in a subdirectory: . ├── app │ └── main . f90 ├── fpm . toml └── src ├── math_constants │ ├── derived . f90 │ └── fundamental . f90 ├── math_constants . f90 └── type_kinds . f90 First, fpm.toml and src/type_kinds.f90 remain unchanged relative to the\nprevious example. The rest of the source files are: $ cat src / math_constants . f90 module math_constants use math_constants_fundamental , only : e , pi use math_constants_derived , only : half_pi , two_pi end module math_constants $ cat src / math_constants / fundamental . f90 module math_constants_fundamental use type_kinds , only : rk real ( rk ), parameter :: pi = 4 * atan ( 1._rk ) real ( rk ), parameter :: e = exp ( 1._rk ) end module math_constants_fundamental $ cat src / math_constants / derived . f90 module math_constants_derived use math_constants_fundamental , only : pi use type_kinds , only : rk real ( rk ), parameter :: two_pi = 2 * pi real ( rk ), parameter :: half_pi = pi / 2 end module math_constants_derived $ cat app / main . f90 program main use math_constants , only : e , pi , half_pi , two_pi print * , 'math_constants library demo' print * , 'pi = ' , pi print * , '2*pi = ' , two_pi print * , 'pi/2 = ' , half_pi print * , 'e = ' , e end program main Our top-level math_constants module now doesn’t define the constants, but\nimports them from the two modules in the subdirectory. Constants e and pi we define in the math_constants_fundamental module, and two_pi and half_pi in the math_constants_derived module. From the main program, we access all\nthe constants from the top-level module math_constants . Let’s build and run this package: $ fpm run # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod) # gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/math_constants) math_constants library demo pi = 3 .1415926535897931 2 *pi = 6 .2831853071795862\n pi/2 = 1 .5707963267948966 e = 2 .7182818284590451 Again, fpm built and run the package as expected. Recall from an earlier example that fpm required the modules in the top-level src directory to be named the same as their source file. This is why src/math_constants.f90 defines module math_constants . For modules defined in subdirectories, there’s an additional requirement: module\nname must contain the path components of the directory that its source file is\nin. In our case, src/math_constants/fundamental.f90 defines the math_constants_fundamental module. Likewise, src/math_constants/derived.f90 defines the math_constants_derived module. This rule applies generally to any number of nested directories and modules.\nFor example, src/a/b/c/d.f90 must define a module called a_b_c_d . Takeaways from this example are that: You can place your module source files in any levels of subdirectories inside src . The module name must include the path components and the source file name–for example, src/a/b/c/d.f90 must define a module called a_b_c_d . Be more explicit So far we’ve let fpm use its defaults to determine the layout of our package.\nIt determined where our library sources would live, what the name of the\nexecutable will be, and some other things. But we can be more explicit about it,\nand make some changes to those things. Let’s look at what the fpm.toml file from our last example would look like if\nwe specified everything. name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" You can see that by making these explicit in the fpm.toml we are able to\nchange many of the settings that fpm used by default. We can change the\nfolders where our sources are stored, we can change the name of our executable,\nand we can change the name of the file our program is defined in. Add some tests fpm also provides support for unit testing. By default, fpm looks for a\nprogram in test/main.f90 which it will compile and execute with the command fpm test . The tests are treated pretty much exactly like the executables.\nLet’s define one explicitly in our fpm.toml file. We’ll make sure that our\ndefinition of pi satisfies the property sin(pi) == 0.0 . Here’s the fpm.toml file: name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" where the contents of the main.f90 file are program main use math_constants , only : pi print * , \"sin(pi) = \" , sin ( pi ) end program main With this setup, we can run our tests. $ fpm test # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod) # gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/math_constants) # gfortran (for build/debug/test/main.o) # gfortran (for build/debug/test/runTests) sin ( pi ) = 1 .2246467991473532E-016 Adding dependencies Inevitably, you’ll want to be able to include other libraries in your project.\nfpm makes this incredibly simple, by taking care of fetching and compiling your\ndependencies for you. You just tell it what your dependencies are, and where to\nfind them. Let’s add a dependency to our library. Now our fpm.toml file looks\nlike this: name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [dependencies] helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" Now you can use any modules from this library anywhere in your code. Just like\nthis: program main use helloff , only : create_greeting use math_constants , only : e , pi , half_pi , two_pi print * , 'math_constants library demo' print * , 'pi = ' , pi print * , '2*pi = ' , two_pi print * , 'pi/2 = ' , half_pi print * , 'e = ' , e print * , create_greeting ( \"fpm\" ) end program main And now, fpm run will output the following: math_constants library demo pi = 3.1415926535897931 2 * pi = 6.2831853071795862 pi / 2 = 1.5707963267948966 e = 2.7182818284590451 Hello , fpm ! Additionally, any users of your library will now automatically depend on your\ndependencies too. So if you don’t need that dependency for the library, like in\nthe above example, then you can specify it for the specific executable like\nbelow. Then fpm will still fetch and compile it when building your executable,\nbut users of your library won’t have to. name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [executable.dependencies] helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" You can also specify dependencies for your tests in a similar way, with [test.dependencies] instead of [executable.dependencies] . There’s also\nanother option for test dependencies. The below example makes the dependencies\navailable for all the tests, but again your users won’t depend on these. name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [dev-dependencies] helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" You can also be specific about which version of a dependency you’d like. You can\nspecify a branch to use like helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\", branch = \"master\" } ,\nor a tag like helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\", tag = \"v1.2.3\" } ,\nor even a specific commit like helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\", rev = \"a1b2c3\" } .\nYou can even specify the path to another folder, if for example you’ve got\nanother fpm package in the same repository. Like this: helloff = { path = \"helloff\" } . Note that you should not specify paths\noutside of your repository, or things won’t work for your users. Custom build scripts If there is something special about your library that makes fpm unable to build\nit, you can provide your own build script. fpm will then simply call your build\nscript to build the library. To specify a build script to be used, put it in the library section of your fpm.toml file, like: [library] source-dir = \"src\" build-script = \"my_build_script\" fpm will set the following environment variables to specify some parameters to\nthe build script: FC – The Fortran compiler to be used. FFLAGS – The flags that should be passed to the Fortran compiler. BUILD_DIR – Where the compiled files should be placed. INCLUDE_DIRS – The folders where any dependencies can be found, space separated.\nIt is then the responsibility of the build script to generate the appropriate\ninclude flags. Additionally, script will be called with the name of the archive ( *.a file)\nthat should be produced as the command line argument. Note: If the name of the build script is Makefile or ends with .mk , then\nthe make program will be used to run it. Not the the archive file is explicitly\nspecified as the target to be built Note: All file and directory names are specified with their full canonical\npath.","tags":"","loc":"page/Packaging.html"}]}
\ No newline at end of file
diff --git a/type/archiver_t.html b/type/archiver_t.html
index 318222a72d..519800d886 100644
--- a/type/archiver_t.html
+++ b/type/archiver_t.html
@@ -489,7 +489,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/build_config_t.html b/type/build_config_t.html
index 8583341b26..9d2a90c4b4 100644
--- a/type/build_config_t.html
+++ b/type/build_config_t.html
@@ -172,7 +172,7 @@
@@ -240,7 +240,7 @@
@@ -399,7 +399,7 @@ Components
Type-Bound Procedures
-
procedure, public, :: info
+
procedure, public, :: info
@@ -526,7 +526,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/build_progress_t.html b/type/build_progress_t.html
index 04270596ee..73960d0171 100644
--- a/type/build_progress_t.html
+++ b/type/build_progress_t.html
@@ -715,7 +715,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/build_target_ptr.html b/type/build_target_ptr.html
index a021008b7a..7793bda412 100644
--- a/type/build_target_ptr.html
+++ b/type/build_target_ptr.html
@@ -285,7 +285,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/build_target_t.html b/type/build_target_t.html
index 515811ea89..13ef908e35 100644
--- a/type/build_target_t.html
+++ b/type/build_target_t.html
@@ -704,7 +704,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/compiler_t.html b/type/compiler_t.html
index f668945843..38149f9604 100644
--- a/type/compiler_t.html
+++ b/type/compiler_t.html
@@ -184,7 +184,7 @@
is_intel
is_unknown
link
- name
+ name
@@ -264,7 +264,7 @@
is_intel
is_unknown
link
- name
+ name
@@ -1488,7 +1488,7 @@ Arguments
-
procedure, public, :: name => compiler_name
+
@@ -1607,7 +1607,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/console_t.html b/type/console_t.html
index 99a5f9d1e3..5317807e7b 100644
--- a/type/console_t.html
+++ b/type/console_t.html
@@ -490,7 +490,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/dependency_config_t.html b/type/dependency_config_t.html
index dc85c92f56..ec378d1ae2 100644
--- a/type/dependency_config_t.html
+++ b/type/dependency_config_t.html
@@ -171,7 +171,7 @@
@@ -238,7 +238,7 @@
@@ -383,7 +383,7 @@ Components
Type-Bound Procedures
-
procedure, public, :: info
+
procedure, public, :: info
@@ -512,7 +512,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/dependency_node_t.html b/type/dependency_node_t.html
index 919779dbfe..9a78bde7ba 100644
--- a/type/dependency_node_t.html
+++ b/type/dependency_node_t.html
@@ -138,7 +138,7 @@
@@ -253,7 +253,7 @@
@@ -285,7 +285,7 @@ Components
-
+
logical,
|
public |
@@ -441,7 +441,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -611,7 +611,7 @@ Arguments
-
procedure, public, :: info
+
procedure, public, :: info
@@ -857,7 +857,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/dependency_tree_t.html b/type/dependency_tree_t.html
index 97d6f0b5cc..dfa8d1ab4e 100644
--- a/type/dependency_tree_t.html
+++ b/type/dependency_tree_t.html
@@ -142,8 +142,8 @@
dep
dep_dir
ndep
- unit
- verbosity
+ unit
+ verbosity
@@ -218,8 +218,8 @@
dep
dep_dir
ndep
- unit
- verbosity
+ unit
+ verbosity
@@ -353,7 +353,7 @@ Components
-
+
integer,
|
public |
@@ -370,7 +370,7 @@ Components
-
+
integer,
|
public |
@@ -1783,7 +1783,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/downloader_t.html b/type/downloader_t.html
index a18ca7e413..bb7f8cc049 100644
--- a/type/downloader_t.html
+++ b/type/downloader_t.html
@@ -579,7 +579,7 @@ Arguments
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/enum_descriptor.html b/type/enum_descriptor.html
index e585314b27..a158f51242 100644
--- a/type/enum_descriptor.html
+++ b/type/enum_descriptor.html
@@ -140,7 +140,7 @@
@@ -193,7 +193,7 @@
@@ -275,7 +275,7 @@ Components
-
+
integer,
|
public |
@@ -352,7 +352,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/error_t.html b/type/error_t.html
index 73b84dc2cf..cca5e90822 100644
--- a/type/error_t.html
+++ b/type/error_t.html
@@ -286,7 +286,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/example_config_t.html b/type/example_config_t.html
index 6115edebf3..50aee48e24 100644
--- a/type/example_config_t.html
+++ b/type/example_config_t.html
@@ -138,11 +138,11 @@
@@ -204,11 +204,11 @@
@@ -267,7 +267,7 @@ Components
-
+
type(dependency_config_t),
|
public, |
@@ -335,7 +335,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -469,7 +469,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/executable_config_t.html b/type/executable_config_t.html
index 85d34ca311..9c9139ed43 100644
--- a/type/executable_config_t.html
+++ b/type/executable_config_t.html
@@ -138,11 +138,11 @@
@@ -170,7 +170,7 @@
@@ -204,11 +204,11 @@
@@ -236,7 +236,7 @@
@@ -267,7 +267,7 @@ Components
-
+
type(dependency_config_t),
|
public, |
@@ -335,7 +335,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -361,7 +361,7 @@ Components
Type-Bound Procedures
-
procedure, public, :: info
+
procedure, public, :: info
@@ -484,7 +484,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/file_scope_flag.html b/type/file_scope_flag.html
index 40749252fc..a0bd4c3b81 100644
--- a/type/file_scope_flag.html
+++ b/type/file_scope_flag.html
@@ -308,7 +308,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fortran_config_t.html b/type/fortran_config_t.html
index 22cb497e42..64aa7cc915 100644
--- a/type/fortran_config_t.html
+++ b/type/fortran_config_t.html
@@ -330,7 +330,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fortran_features_t.html b/type/fortran_features_t.html
index 74ecc5c391..3122c53cbb 100644
--- a/type/fortran_features_t.html
+++ b/type/fortran_features_t.html
@@ -329,7 +329,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_build_settings.html b/type/fpm_build_settings.html
index 55ac3e790e..94f5a1721e 100644
--- a/type/fpm_build_settings.html
+++ b/type/fpm_build_settings.html
@@ -142,7 +142,7 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
flag
@@ -200,7 +200,7 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
flag
@@ -319,7 +319,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -529,7 +529,7 @@ Components
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_clean_settings.html b/type/fpm_clean_settings.html
index f5f8897ac1..52462f1399 100644
--- a/type/fpm_clean_settings.html
+++ b/type/fpm_clean_settings.html
@@ -320,7 +320,7 @@ Components
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_cmd_settings.html b/type/fpm_cmd_settings.html
index bbcd45b3d5..d2f1848e6f 100644
--- a/type/fpm_cmd_settings.html
+++ b/type/fpm_cmd_settings.html
@@ -282,7 +282,7 @@ Components
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_global_settings.html b/type/fpm_global_settings.html
index ee1fe0993c..5b6592c63f 100644
--- a/type/fpm_global_settings.html
+++ b/type/fpm_global_settings.html
@@ -479,7 +479,7 @@
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_install_settings.html b/type/fpm_install_settings.html
index 21c34ca9bf..9852e7b468 100644
--- a/type/fpm_install_settings.html
+++ b/type/fpm_install_settings.html
@@ -143,7 +143,7 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
flag
@@ -206,7 +206,7 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
flag
@@ -346,7 +346,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -624,7 +624,7 @@ Components
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_model_t.html b/type/fpm_model_t.html
index 04e6a81664..d041f3b093 100644
--- a/type/fpm_model_t.html
+++ b/type/fpm_model_t.html
@@ -617,7 +617,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_new_settings.html b/type/fpm_new_settings.html
index 04924de92f..a7c15f38a9 100644
--- a/type/fpm_new_settings.html
+++ b/type/fpm_new_settings.html
@@ -139,7 +139,7 @@
-
+
character(len=:),
|
public, |
@@ -434,7 +434,7 @@ Components
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_publish_settings.html b/type/fpm_publish_settings.html
index 19a30c3a00..0ae1d8d470 100644
--- a/type/fpm_publish_settings.html
+++ b/type/fpm_publish_settings.html
@@ -142,7 +142,7 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
flag
@@ -204,7 +204,7 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
flag
@@ -327,7 +327,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -605,7 +605,7 @@ Components
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_run_settings.html b/type/fpm_run_settings.html
index 450eefbeab..ade3606370 100644
--- a/type/fpm_run_settings.html
+++ b/type/fpm_run_settings.html
@@ -143,14 +143,14 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
example
flag
ldflag
list
- name
+ name
profile
prune
runner
@@ -218,14 +218,14 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
example
flag
ldflag
list
- name
+ name
profile
prune
runner
@@ -370,7 +370,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -489,7 +489,7 @@ Components
-
+
character(len=ibug),
|
public, |
@@ -702,7 +702,7 @@
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_test_settings.html b/type/fpm_test_settings.html
index 816c4f176a..9f457e2a04 100644
--- a/type/fpm_test_settings.html
+++ b/type/fpm_test_settings.html
@@ -143,14 +143,14 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
example
flag
ldflag
list
- name
+ name
profile
prune
runner
@@ -218,14 +218,14 @@
build_tests
c_compiler
cflag
- compiler
+ compiler
cxx_compiler
cxxflag
example
flag
ldflag
list
- name
+ name
profile
prune
runner
@@ -370,7 +370,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -489,7 +489,7 @@ Components
-
+
character(len=ibug),
|
public, |
@@ -702,7 +702,7 @@
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/fpm_update_settings.html b/type/fpm_update_settings.html
index 0699e1b1b4..53f814d42f 100644
--- a/type/fpm_update_settings.html
+++ b/type/fpm_update_settings.html
@@ -140,7 +140,7 @@
@@ -188,7 +188,7 @@
@@ -265,7 +265,7 @@ Components
-
+
character(len=ibug),
|
public, |
@@ -339,7 +339,7 @@ Components
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/git_target_t.html b/type/git_target_t.html
index de35ba1537..a064132ad9 100644
--- a/type/git_target_t.html
+++ b/type/git_target_t.html
@@ -169,7 +169,7 @@
@@ -234,7 +234,7 @@
@@ -404,7 +404,7 @@ Arguments
-
procedure, public, :: info
+
procedure, public, :: info
@@ -413,7 +413,7 @@
Arguments
diff --git a/type/install_config_t.html b/type/install_config_t.html
index b8cf267dda..6a8b7af77f 100644
--- a/type/install_config_t.html
+++ b/type/install_config_t.html
@@ -166,7 +166,7 @@
@@ -228,7 +228,7 @@
@@ -285,7 +285,7 @@ Components
Type-Bound Procedures
-
procedure, public, :: info
+
procedure, public, :: info
@@ -396,7 +396,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/installer_t.html b/type/installer_t.html
index 20024ee92a..3c617a9557 100644
--- a/type/installer_t.html
+++ b/type/installer_t.html
@@ -985,7 +985,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/library_config_t.html b/type/library_config_t.html
index 8fd269220d..3c343f6126 100644
--- a/type/library_config_t.html
+++ b/type/library_config_t.html
@@ -140,7 +140,7 @@
@@ -168,7 +168,7 @@
@@ -204,7 +204,7 @@
@@ -232,7 +232,7 @@
@@ -297,7 +297,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -323,7 +323,7 @@ Components
Type-Bound Procedures
-
procedure, public, :: info
+
procedure, public, :: info
@@ -440,7 +440,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/metapackage_config_t.html b/type/metapackage_config_t.html
index e669e377d8..df6e3b69ad 100644
--- a/type/metapackage_config_t.html
+++ b/type/metapackage_config_t.html
@@ -352,7 +352,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/metapackage_request_t.html b/type/metapackage_request_t.html
index 3b513a684e..8d7cddd609 100644
--- a/type/metapackage_request_t.html
+++ b/type/metapackage_request_t.html
@@ -138,9 +138,9 @@
@@ -190,9 +190,9 @@
@@ -239,7 +239,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -273,7 +273,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -330,7 +330,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/metapackage_t.html b/type/metapackage_t.html
index ebe3d92232..548c7d30b1 100644
--- a/type/metapackage_t.html
+++ b/type/metapackage_t.html
@@ -159,7 +159,7 @@
link_flags
link_libs
run_command
- version
+ version
@@ -244,7 +244,7 @@
link_flags
link_libs
run_command
- version
+ version
@@ -663,7 +663,7 @@ Components
-
+
type(version_t),
|
public, |
@@ -1110,7 +1110,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/package_config_t.html b/type/package_config_t.html
index fbec54ebdc..2090cfb6a3 100644
--- a/type/package_config_t.html
+++ b/type/package_config_t.html
@@ -139,7 +139,7 @@
@@ -180,7 +180,7 @@
@@ -215,7 +215,7 @@
@@ -256,7 +256,7 @@
@@ -304,7 +304,7 @@ Components
-
+
type(dependency_config_t),
|
public, |
@@ -457,7 +457,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -525,7 +525,7 @@ Components
-
+
type(version_t),
|
public |
@@ -551,7 +551,7 @@ Components
Type-Bound Procedures
-
procedure, public, :: info
+
procedure, public, :: info
@@ -704,7 +704,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/preprocess_config_t.html b/type/preprocess_config_t.html
index e5c1c5619a..b074d35baf 100644
--- a/type/preprocess_config_t.html
+++ b/type/preprocess_config_t.html
@@ -140,7 +140,7 @@
@@ -169,7 +169,7 @@
@@ -205,7 +205,7 @@
@@ -234,7 +234,7 @@
@@ -299,7 +299,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -342,7 +342,7 @@ Components
Type-Bound Procedures
-
procedure, public, :: info
+
procedure, public, :: info
@@ -462,7 +462,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/profile_config_t.html b/type/profile_config_t.html
index 9169005e0d..d0482c92c8 100644
--- a/type/profile_config_t.html
+++ b/type/profile_config_t.html
@@ -174,7 +174,7 @@
@@ -244,7 +244,7 @@
@@ -437,7 +437,7 @@ Components
Type-Bound Procedures
-
procedure, public, :: info
+
procedure, public, :: info
@@ -446,7 +446,7 @@
Type-Bound Procedures
diff --git a/type/srcfile_t.html b/type/srcfile_t.html
index 81d8228569..b49d2423d0 100644
--- a/type/srcfile_t.html
+++ b/type/srcfile_t.html
@@ -483,7 +483,7 @@
Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/string_t.html b/type/string_t.html
index 7a5f818fce..4bc7bb7c11 100644
--- a/type/string_t.html
+++ b/type/string_t.html
@@ -345,7 +345,7 @@
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/test_config_t.html b/type/test_config_t.html
index 22e5bf83db..738cedee24 100644
--- a/type/test_config_t.html
+++ b/type/test_config_t.html
@@ -138,11 +138,11 @@
@@ -204,11 +204,11 @@
@@ -267,7 +267,7 @@ Components
-
+
type(dependency_config_t),
|
public, |
@@ -335,7 +335,7 @@ Components
-
+
character(len=:),
|
public, |
@@ -469,7 +469,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43
diff --git a/type/version_t.html b/type/version_t.html
index 7254a552a2..19d08c82e4 100644
--- a/type/version_t.html
+++ b/type/version_t.html
@@ -802,7 +802,7 @@ Source Code
Documentation generated by
FORD
- on 2023-07-10 06:33
+ on 2023-08-09 07:43