diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/filesystem_utilities.c | 41 | ||||
-rw-r--r-- | src/fpm.f90 | 7 | ||||
-rw-r--r-- | src/fpm/cmd/install.f90 | 2 | ||||
-rw-r--r-- | src/fpm/cmd/new.f90 | 3 | ||||
-rw-r--r-- | src/fpm/cmd/update.f90 | 3 | ||||
-rw-r--r-- | src/fpm/dependency.f90 | 9 | ||||
-rw-r--r-- | src/fpm/manifest/build.f90 | 6 | ||||
-rw-r--r-- | src/fpm/manifest/example.f90 | 4 | ||||
-rw-r--r-- | src/fpm/manifest/executable.f90 | 6 | ||||
-rw-r--r-- | src/fpm/manifest/library.f90 | 4 | ||||
-rw-r--r-- | src/fpm/manifest/package.f90 | 5 | ||||
-rw-r--r-- | src/fpm/manifest/test.f90 | 4 | ||||
-rw-r--r-- | src/fpm/toml.f90 | 11 | ||||
-rw-r--r-- | src/fpm/versioning.f90 | 5 | ||||
-rw-r--r-- | src/fpm_backend.f90 | 8 | ||||
-rw-r--r-- | src/fpm_command_line.f90 | 57 | ||||
-rw-r--r-- | src/fpm_environment.f90 | 20 | ||||
-rw-r--r-- | src/fpm_filesystem.F90 (renamed from src/fpm_filesystem.f90) | 151 | ||||
-rw-r--r-- | src/fpm_model.f90 | 1 | ||||
-rw-r--r-- | src/fpm_strings.f90 | 36 | ||||
-rw-r--r-- | src/fpm_targets.f90 | 3 |
21 files changed, 298 insertions, 88 deletions
diff --git a/src/filesystem_utilities.c b/src/filesystem_utilities.c new file mode 100644 index 0000000..7075f42 --- /dev/null +++ b/src/filesystem_utilities.c @@ -0,0 +1,41 @@ +#include <sys/stat.h> +#include <dirent.h> + +#ifdef __APPLE__ +DIR * opendir$INODE64( const char * dirName ); +struct dirent * readdir$INODE64( DIR * dir ); +#endif + +int c_is_dir(const char *path) +{ + struct stat m; + int r = stat(path, &m); + return r == 0 && S_ISDIR(m.st_mode); +} + +const char *get_d_name(struct dirent *d) +{ + return (const char *) d->d_name; +} + + + +DIR *c_opendir(const char *dirname){ + +#ifdef __APPLE__ + return opendir$INODE64(dirname); +#else + return opendir(dirname); +#endif + +} + +struct dirent *c_readdir(DIR *dirp){ + +#ifdef __APPLE__ + return readdir$INODE64(dirp); +#else + return readdir(dirp); +#endif + +}
\ No newline at end of file diff --git a/src/fpm.f90 b/src/fpm.f90 index 89eca1a..68e2bbd 100644 --- a/src/fpm.f90 +++ b/src/fpm.f90 @@ -5,7 +5,7 @@ use fpm_command_line, only: fpm_build_settings, fpm_new_settings, & fpm_run_settings, fpm_install_settings, fpm_test_settings use fpm_dependency, only : new_dependency_tree use fpm_environment, only: run, get_env -use fpm_filesystem, only: is_dir, join_path, number_of_rows, list_files, exists, basename +use fpm_filesystem, only: is_dir, join_path, number_of_rows, list_files, exists, basename, filewrite, mkdir use fpm_model, only: fpm_model_t, srcfile_t, show_model, & FPM_SCOPE_UNKNOWN, FPM_SCOPE_LIB, FPM_SCOPE_DEP, & FPM_SCOPE_APP, FPM_SCOPE_EXAMPLE, FPM_SCOPE_TEST @@ -58,6 +58,11 @@ subroutine build_model(model, settings, package, error) call model%deps%add(package, error) if (allocated(error)) return + ! build/ directory should now exist + if (.not.exists("build/.gitignore")) then + call filewrite(join_path("build", ".gitignore"),["*"]) + end if + if(settings%compiler.eq.'')then model%fortran_compiler = 'gfortran' else diff --git a/src/fpm/cmd/install.f90 b/src/fpm/cmd/install.f90 index e53609b..4c8596e 100644 --- a/src/fpm/cmd/install.f90 +++ b/src/fpm/cmd/install.f90 @@ -27,7 +27,7 @@ contains type(fpm_model_t) :: model type(build_target_ptr), allocatable :: targets(:) type(installer_t) :: installer - character(len=:), allocatable :: lib, exe, dir + character(len=:), allocatable :: lib, dir logical :: installable call get_package_data(package, "fpm.toml", error, apply_defaults=.true.) diff --git a/src/fpm/cmd/new.f90 b/src/fpm/cmd/new.f90 index 2b8d990..abc1d67 100644 --- a/src/fpm/cmd/new.f90 +++ b/src/fpm/cmd/new.f90 @@ -98,9 +98,6 @@ character(len=:,kind=tfc),allocatable :: littlefile(:) ! like realpath() or getcwd(). bname=basename(settings%name) - ! create NAME/.gitignore file - call warnwrite(join_path(settings%name, '.gitignore'), ['build/*']) - littlefile=[character(len=80) :: '# '//bname, 'My cool new project!'] ! create NAME/README.md diff --git a/src/fpm/cmd/update.f90 b/src/fpm/cmd/update.f90 index aa99ca3..a9918bf 100644 --- a/src/fpm/cmd/update.f90 +++ b/src/fpm/cmd/update.f90 @@ -2,7 +2,7 @@ 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 + use fpm_filesystem, only : exists, mkdir, join_path, delete_file, filewrite use fpm_manifest, only : package_config_t, get_package_data implicit none private @@ -26,6 +26,7 @@ contains if (.not.exists("build")) then call mkdir("build") + call filewrite(join_path("build", ".gitignore"),["*"]) end if cache = join_path("build", "cache.toml") diff --git a/src/fpm/dependency.f90 b/src/fpm/dependency.f90 index 144ffbe..bd85b6f 100644 --- a/src/fpm/dependency.f90 +++ b/src/fpm/dependency.f90 @@ -233,7 +233,6 @@ contains type(dependency_config_t) :: dependency character(len=:), allocatable :: root - logical :: main if (allocated(self%cache)) then call self%load(self%cache, error) @@ -386,8 +385,7 @@ contains type(error_t), allocatable, intent(out) :: error integer :: id - type(package_config_t) :: package - character(len=:), allocatable :: manifest, proj_dir, revision, root + character(len=:), allocatable :: proj_dir, root id = self%find(name) root = "." @@ -507,8 +505,6 @@ contains !> Index of the dependency integer :: pos - integer :: ii - pos = self%find(dependency%name) end function find_dependency @@ -540,7 +536,6 @@ contains class(dependency_tree_t), intent(in) :: self !> All dependencies are updated logical :: finished - integer :: ii finished = all(self%dep(:self%ndep)%done) @@ -561,7 +556,6 @@ contains !> Error handling type(error_t), allocatable, intent(out) :: error - character(len=:), allocatable :: url logical :: update update = .false. @@ -649,7 +643,6 @@ contains character(len=:), allocatable :: version, url, obj, rev, proj_dir type(toml_key), allocatable :: list(:) type(toml_table), pointer :: ptr - type(dependency_config_t) :: dep call table%get_keys(list) diff --git a/src/fpm/manifest/build.f90 b/src/fpm/manifest/build.f90 index c9b3f44..b24cf43 100644 --- a/src/fpm/manifest/build.f90 +++ b/src/fpm/manifest/build.f90 @@ -12,7 +12,7 @@ module fpm_manifest_build use fpm_error, only : error_t, syntax_error, fatal_error use fpm_strings, only : string_t - use fpm_toml, only : toml_table, toml_key, toml_stat, get_value + use fpm_toml, only : toml_table, toml_key, toml_stat, get_value, get_list implicit none private @@ -87,10 +87,10 @@ contains end if - call get_value(table, "link", self%link, error) + call get_list(table, "link", self%link, error) if (allocated(error)) return - call get_value(table, "external-modules", self%external_modules, error) + call get_list(table, "external-modules", self%external_modules, error) if (allocated(error)) return end subroutine new_build_config diff --git a/src/fpm/manifest/example.f90 b/src/fpm/manifest/example.f90 index 3319401..0b1a5a2 100644 --- a/src/fpm/manifest/example.f90 +++ b/src/fpm/manifest/example.f90 @@ -18,7 +18,7 @@ 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 + use fpm_toml, only : toml_table, toml_key, toml_stat, get_value, get_list implicit none private @@ -73,7 +73,7 @@ contains if (allocated(error)) return end if - call get_value(table, "link", self%link, error) + call get_list(table, "link", self%link, error) if (allocated(error)) return end subroutine new_example diff --git a/src/fpm/manifest/executable.f90 b/src/fpm/manifest/executable.f90 index 60c20ec..3a018ec 100644 --- a/src/fpm/manifest/executable.f90 +++ b/src/fpm/manifest/executable.f90 @@ -13,8 +13,8 @@ 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 + use fpm_strings, only : string_t + use fpm_toml, only : toml_table, toml_key, toml_stat, get_value, get_list implicit none private @@ -84,7 +84,7 @@ contains if (allocated(error)) return end if - call get_value(table, "link", self%link, error) + call get_list(table, "link", self%link, error) if (allocated(error)) return end subroutine new_executable diff --git a/src/fpm/manifest/library.f90 b/src/fpm/manifest/library.f90 index c8ce049..68ccc20 100644 --- a/src/fpm/manifest/library.f90 +++ b/src/fpm/manifest/library.f90 @@ -11,7 +11,7 @@ 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 + use fpm_toml, only : toml_table, toml_key, toml_stat, get_value, get_list implicit none private @@ -59,7 +59,7 @@ contains call get_value(table, "source-dir", self%source_dir, "src") call get_value(table, "build-script", self%build_script) - call get_value(table, "include-dir", self%include_dir, error) + 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 diff --git a/src/fpm/manifest/package.f90 b/src/fpm/manifest/package.f90 index 1f85144..5cd8765 100644 --- a/src/fpm/manifest/package.f90 +++ b/src/fpm/manifest/package.f90 @@ -29,6 +29,7 @@ !>[[ executable ]] !>[[ example ]] !>[[ test ]] +!>[extra] !>``` module fpm_manifest_package use fpm_manifest_build, only: build_config_t, new_build_config @@ -161,7 +162,7 @@ contains end if call new_install_config(self%install, 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 @@ -303,7 +304,7 @@ contains case("version", "license", "author", "maintainer", "copyright", & & "description", "keywords", "categories", "homepage", "build", & & "dependencies", "dev-dependencies", "test", "executable", & - & "example", "library", "install") + & "example", "library", "install", "extra") continue end select diff --git a/src/fpm/manifest/test.f90 b/src/fpm/manifest/test.f90 index e689774..258d639 100644 --- a/src/fpm/manifest/test.f90 +++ b/src/fpm/manifest/test.f90 @@ -18,7 +18,7 @@ module fpm_manifest_test 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 + use fpm_toml, only : toml_table, toml_key, toml_stat, get_value, get_list implicit none private @@ -73,7 +73,7 @@ contains if (allocated(error)) return end if - call get_value(table, "link", self%link, error) + call get_list(table, "link", self%link, error) if (allocated(error)) return end subroutine new_test diff --git a/src/fpm/toml.f90 b/src/fpm/toml.f90 index dbaafcb..3b05229 100644 --- a/src/fpm/toml.f90 +++ b/src/fpm/toml.f90 @@ -22,16 +22,11 @@ module fpm_toml private public :: read_package_file - public :: toml_table, toml_array, toml_key, toml_stat, get_value, set_value + public :: toml_table, toml_array, toml_key, toml_stat, get_value, set_value, get_list public :: new_table, add_table, add_array, len public :: toml_error, toml_serializer, toml_parse - interface get_value - module procedure :: get_child_value_string_list - end interface get_value - - contains @@ -71,7 +66,7 @@ contains end subroutine read_package_file - subroutine get_child_value_string_list(table, key, list, error) + subroutine get_list(table, key, list, error) !> Instance of the TOML data structure type(toml_table), intent(inout) :: table @@ -114,7 +109,7 @@ contains end if end if - end subroutine get_child_value_string_list + end subroutine get_list end module fpm_toml diff --git a/src/fpm/versioning.f90 b/src/fpm/versioning.f90 index b24fc3c..da362ee 100644 --- a/src/fpm/versioning.f90 +++ b/src/fpm/versioning.f90 @@ -87,8 +87,7 @@ contains !> Error handling type(error_t), allocatable, intent(out) :: error - character :: tok - integer :: ii, istart, iend, stat, nn + integer :: istart, iend, stat, nn integer :: num(max_limit) logical :: is_number @@ -147,7 +146,7 @@ contains integer :: ii, nn logical :: was_number - character :: tok, last + character :: tok was_number = is_number nn = len(string) diff --git a/src/fpm_backend.f90 b/src/fpm_backend.f90 index e82d847..4d0c709 100644 --- a/src/fpm_backend.f90 +++ b/src/fpm_backend.f90 @@ -83,7 +83,7 @@ subroutine build_package(targets,model) ! Check if build already failed !$omp atomic read skip_current = build_failed - + if (.not.skip_current) then call build_target(model,queue(j)%ptr,stat(j)) end if @@ -126,8 +126,7 @@ end subroutine build_package recursive subroutine sort_target(target) type(build_target_t), intent(inout), target :: target - integer :: i, j, fh, stat - type(build_target_t), pointer :: exe_obj + integer :: i, fh, stat ! Check if target has already been processed (as a dependency) if (target%sorted .or. target%skip) then @@ -257,8 +256,7 @@ subroutine build_target(model,target,stat) type(build_target_t), intent(in), target :: target integer, intent(out) :: stat - integer :: ilib, fh - character(:), allocatable :: link_flags + integer :: fh if (.not.exists(dirname(target%output_file))) then call mkdir(dirname(target%output_file)) diff --git a/src/fpm_command_line.f90 b/src/fpm_command_line.f90 index 2ed7ac6..959a13f 100644 --- a/src/fpm_command_line.f90 +++ b/src/fpm_command_line.f90 @@ -537,17 +537,18 @@ contains ' '] help_list_dash = [character(len=80) :: & ' ', & - ' build [--compiler COMPILER_NAME] [--profile PROF] [--flag FFLAGS] [--list] ', & + ' build [--compiler COMPILER_NAME] [--profile PROF] [--flag FFLAGS] [--list] ', & ' help [NAME(s)] ', & ' new NAME [[--lib|--src] [--app] [--test] [--example]]| ', & ' [--full|--bare][--backfill] ', & ' update [NAME(s)] [--fetch-only] [--clean] [--verbose] ', & ' list [--list] ', & - ' run [[--target] NAME(s) [--example] [--profile PROF] [--flag FFLAGS] [--all] ', & + ' 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] ', & + ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--runner "CMD"] ', & + ' [--list] [--compiler COMPILER_NAME] [-- ARGS] ', & + ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH] ', & + ' [options] ', & ' '] help_usage=[character(len=80) :: & '' ] @@ -652,20 +653,21 @@ contains ' + install Install project ', & ' ', & ' Their syntax is ', & - ' ', & - ' build [--profile PROF] [--flag FFLAGS] [--list] [--compiler COMPILER_NAME]', & - ' new NAME [[--lib|--src] [--app] [--test] [--example]]| ', & - ' [--full|--bare][--backfill] ', & - ' update [NAME(s)] [--fetch-only] [--clean] ', & - ' run [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] [--example]', & - ' [--all] [--runner "CMD"] [--compiler COMPILER_NAME] [-- ARGS] ', & - ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] ', & - ' [--runner "CMD"] [--compiler COMPILER_NAME] [-- ARGS] ', & - ' help [NAME(s)] ', & - ' list [--list] ', & - ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH] [options]', & - ' ', & - 'SUBCOMMAND OPTIONS ', & + ' ', & + ' build [--profile PROF] [--flag FFLAGS] [--list] [--compiler COMPILER_NAME] ', & + ' new NAME [[--lib|--src] [--app] [--test] [--example]]| ', & + ' [--full|--bare][--backfill] ', & + ' update [NAME(s)] [--fetch-only] [--clean] ', & + ' run [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] [--all] ', & + ' [--example] [--runner "CMD"] [--compiler COMPILER_NAME] [-- ARGS] ', & + ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] ', & + ' [--runner "CMD"] [--compiler COMPILER_NAME] [-- ARGS] ', & + ' help [NAME(s)] ', & + ' list [--list] ', & + ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH] ', & + ' [options] ', & + ' ', & + 'SUBCOMMAND OPTIONS ', & ' -C, --directory PATH', & ' Change working directory to PATH before running any command', & ' --profile PROF selects the compilation profile for the build.',& @@ -730,11 +732,11 @@ contains ' fpm run ', & ' fpm run --example ', & ' fpm new --help ', & - ' fpm run myprogram --profile release -- -x 10 -y 20 --title "my title"', & - ' fpm install --prefix ~/.local ', & - ' ', & - 'SEE ALSO ', & - ' ', & + ' fpm run myprogram --profile release -- -x 10 -y 20 --title "my title" ', & + ' fpm install --prefix ~/.local ', & + ' ', & + 'SEE ALSO ', & + ' ', & ' + The fpm(1) home page is at https://github.com/fortran-lang/fpm ', & ' + Registered fpm(1) packages are at https://fortran-lang.org/packages ', & ' + The fpm(1) TOML file format is described at ', & @@ -936,14 +938,11 @@ contains ' o runs the command "git init" in that directory ', & ' o populates the directory with the default project directories ', & ' o adds sample Fortran source files ', & - ' o adds a ".gitignore" file for ignoring the build/ directory ', & - ' (where fpm-generated output will be placed) ', & ' ', & ' The default file structure (that will be automatically scanned) is ', & ' ', & ' NAME/ ', & ' fpm.toml ', & - ' .gitignore ', & ' src/ ', & ' NAME.f90 ', & ' app/ ', & @@ -1004,8 +1003,8 @@ contains ' depend extensively on non-default build options. ', & ' ', & ' --bare A minimal manifest file ("fpm.toml") is created and ', & - ' a ".gitignore" and "README.md" file is created but no ', & - ' directories or sample Fortran is generated. ', & + ' "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 ', & diff --git a/src/fpm_environment.f90 b/src/fpm_environment.f90 index e9da3c7..a9f8c65 100644 --- a/src/fpm_environment.f90 +++ b/src/fpm_environment.f90 @@ -40,7 +40,16 @@ contains 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 `OS`. @@ -48,6 +57,7 @@ contains if (rc == 0 .and. length > 0 .and. index(val, 'Windows_NT') > 0) then r = OS_WINDOWS + ret = r return end if @@ -58,42 +68,49 @@ contains ! 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 @@ -103,6 +120,7 @@ contains if (file_exists) then r = OS_LINUX + ret = r return end if @@ -111,6 +129,7 @@ contains if (file_exists) then r = OS_MACOS + ret = r return end if @@ -119,6 +138,7 @@ contains if (file_exists) then r = OS_FREEBSD + ret = r return end if end function get_os_type diff --git a/src/fpm_filesystem.f90 b/src/fpm_filesystem.F90 index 2a32b54..597ed7b 100644 --- a/src/fpm_filesystem.f90 +++ b/src/fpm_filesystem.F90 @@ -7,6 +7,7 @@ module fpm_filesystem OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD use fpm_environment, only: separator, get_env use fpm_strings, only: f_string, replace, string_t, split + 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 implicit none private @@ -17,6 +18,39 @@ module fpm_filesystem integer, parameter :: LINE_BUFFER_LEN = 1000 +#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 @@ -45,7 +79,7 @@ end subroutine env_variable !> 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 @@ -90,7 +124,7 @@ function canon_path(path) character(len=:), allocatable :: canon_path character(len=:), allocatable :: nixpath - integer :: ii, istart, iend, stat, nn, last + integer :: istart, iend, nn, last logical :: is_path, absolute nixpath = unix_path(path) @@ -141,7 +175,7 @@ contains logical, intent(inout) :: is_path integer :: ii, nn - character :: tok, last + character :: tok nn = len(string) @@ -226,13 +260,23 @@ function join_path(a1,a2,a3,a4,a5) result(path) 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) - select case (get_os_type()) - case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) - filesep = '/' - case (OS_WINDOWS) - filesep = '\' - end select + 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 path = a1 // filesep // a2 @@ -311,7 +355,94 @@ subroutine mkdir(dir) 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) .eq. 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 .eq. '.' .or. string_fortran .eq. '..')) then + cycle + end if + + i = i + 1 + + if (i .gt. 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 .ne. 0) then + print *, 'c_closedir() failed' + error stop + end if + + if (i .gt. 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) .ne. 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` @@ -376,6 +507,8 @@ recursive subroutine list_files(dir, files, recurse) end subroutine list_files +#endif + !> test if pathname already exists logical function exists(filename) result(r) diff --git a/src/fpm_model.f90 b/src/fpm_model.f90 index 9746e5f..49f598e 100644 --- a/src/fpm_model.f90 +++ b/src/fpm_model.f90 @@ -251,7 +251,6 @@ function info_srcfile_short(source) result(s) ! Prints a shortened version of srcfile_t type(srcfile_t), intent(in) :: source character(:), allocatable :: s - integer :: i s = "srcfile_t(" s = s // 'file_name="' // source%file_name // '"' s = s // ", ...)" diff --git a/src/fpm_strings.f90 b/src/fpm_strings.f90 index ee5c20a..6ce36cf 100644 --- a/src/fpm_strings.f90 +++ b/src/fpm_strings.f90 @@ -6,7 +6,7 @@ !!### 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 +!! - [[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 @@ -14,7 +14,7 @@ !!### 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 +!! - [[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 @@ -31,6 +31,7 @@ module fpm_strings use iso_fortran_env, only: int64 +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 @@ -73,6 +74,10 @@ 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 @@ -128,6 +133,33 @@ function f_string(c_string) 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 diff --git a/src/fpm_targets.f90 b/src/fpm_targets.f90 index 66bbdd5..d480866 100644 --- a/src/fpm_targets.f90 +++ b/src/fpm_targets.f90 @@ -160,7 +160,6 @@ subroutine build_target_list(targets,model) integer :: i, j, n_source character(:), allocatable :: xsuffix, exe_dir - type(build_target_t), pointer :: dep logical :: with_lib ! Check for empty build (e.g. header-only lib) @@ -258,7 +257,6 @@ subroutine build_target_list(targets,model) integer :: i character(1), parameter :: filesep = '/' - character(:), allocatable :: dir object_file = canon_path(source%file_name) @@ -285,7 +283,6 @@ subroutine add_target(targets,type,output_file,source,link_libraries) type(string_t), intent(in), optional :: link_libraries(:) integer :: i - type(build_target_ptr), allocatable :: temp(:) type(build_target_t), pointer :: new_target if (.not.allocated(targets)) allocate(targets(0)) |