From 07bf22cb8f6f0121a89a07946c7b0dce6c4fd40b Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Wed, 13 Dec 2023 14:34:11 +0100 Subject: [PATCH 01/13] Fix macOS MPI link flags; upgrade Intel oneAPI; MSMPI CI crash --- .github/workflows/meta.yml | 17 ++- fpm.toml | 2 + src/fpm_compiler.F90 | 5 +- src/fpm_environment.f90 | 12 +- src/fpm_filesystem.F90 | 2 +- src/fpm_meta.f90 | 219 ++++++++++++++++++++++++++++++++----- 6 files changed, 215 insertions(+), 42 deletions(-) diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml index 5deae0c166..61053cbd81 100644 --- a/.github/workflows/meta.yml +++ b/.github/workflows/meta.yml @@ -106,16 +106,14 @@ jobs: if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'intel') timeout-minutes: 1 run: | - wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list + wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null + echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list sudo apt-get update - name: (Ubuntu) Install Intel oneAPI if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'intel') - timeout-minutes: 5 - run: sudo apt-get install intel-oneapi-compiler-fortran intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic intel-oneapi-mpi intel-oneapi-mpi-devel intel-oneapi-mkl ninja-build + timeout-minutes: 15 + run: sudo apt-get install intel-oneapi-compiler-dpcpp-cpp-2023.1.0 intel-oneapi-compiler-fortran-2023.1.0 intel-oneapi-mpi-devel ninja-build - name: (Ubuntu) Setup Intel oneAPI environment if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'intel') @@ -152,6 +150,7 @@ jobs: if: contains(matrix.os,'windows') && contains(matrix.mpi,'msmpi') run: | echo "C:\Program Files\Microsoft MPI\Bin\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + echo "/c/Program Files/Microsoft MPI/Bin/" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "MSMPI_BIN=C:\Program Files\Microsoft MPI\Bin\" | Out-File -FilePath $env:GITHUB_ENV -Append - name: (Windows) load OneAPI environment variables @@ -216,9 +215,9 @@ jobs: if: contains(matrix.mpi,'intel') shell: bash run: | - echo "FPM_FC=ifort" >> $GITHUB_ENV - echo "FPM_CC=icc" >> $GITHUB_ENV - echo "FPM_CXX=icpc" >> $GITHUB_ENV + echo "FPM_FC=ifx" >> $GITHUB_ENV + echo "FPM_CC=icx" >> $GITHUB_ENV + echo "FPM_CXX=icpx" >> $GITHUB_ENV - name: (macOS) Use gcc/g++ instead of Clang for C/C++ if: contains(matrix.os,'macOS') diff --git a/fpm.toml b/fpm.toml index 1da1a00dcf..3956e42105 100644 --- a/fpm.toml +++ b/fpm.toml @@ -18,6 +18,8 @@ fortran-regex.git = "https://github.com/perazz/fortran-regex" fortran-regex.tag = "1.1.2" jonquil.git = "https://github.com/toml-f/jonquil" jonquil.rev = "4fbd4cf34d577c0fd25e32667ee9e41bf231ece8" +fortran-shlex.git = "https://github.com/perazz/fortran-shlex" +fortran-shlex.tag = "1.0.1" [[test]] name = "cli-test" diff --git a/src/fpm_compiler.F90 b/src/fpm_compiler.F90 index b93c092f4a..55565ee31d 100644 --- a/src/fpm_compiler.F90 +++ b/src/fpm_compiler.F90 @@ -185,6 +185,9 @@ module fpm_compiler flag_intel_fixed_form = " -fixed", & flag_intel_standard_compliance = " -standard-semantics" +character(*), parameter :: & + flag_intel_llvm_check = " -check all,nouninit" + character(*), parameter :: & flag_intel_backtrace_win = " /traceback", & flag_intel_warn_win = " /warn:all", & @@ -421,7 +424,7 @@ subroutine get_debug_compile_flags(id, flags) case(id_intel_llvm_nix) flags = & flag_intel_warn//& - flag_intel_check//& + flag_intel_llvm_check//& flag_intel_limit//& flag_intel_debug//& flag_intel_byterecl//& diff --git a/src/fpm_environment.f90 b/src/fpm_environment.f90 index 7e8aa2317d..f77ff47092 100644 --- a/src/fpm_environment.f90 +++ b/src/fpm_environment.f90 @@ -36,11 +36,11 @@ integer function get_os_type() result(r) !! 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 + character(len=255) :: 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 @@ -50,6 +50,8 @@ integer function get_os_type() result(r) first_run = .false. r = OS_UNKNOWN + length = 0 + rc = 0 ! Check environment variable `OSTYPE`. call get_environment_variable('OSTYPE', val, length, rc) diff --git a/src/fpm_filesystem.F90 b/src/fpm_filesystem.F90 index 177ee85fea..ca521346b3 100644 --- a/src/fpm_filesystem.F90 +++ b/src/fpm_filesystem.F90 @@ -654,7 +654,7 @@ end function unix_path !! integer :: iostat !! character(len=:),allocatable :: line, iomsg !! open(unit=stdin,pad='yes') -!! INFINITE: do +!! INFINITE: do !! call getline(stdin,line,iostat,iomsg) !! if(iostat /= 0) exit INFINITE !! write(*,'(a)')'['//line//']' diff --git a/src/fpm_meta.f90 b/src/fpm_meta.f90 index 827af3ca3c..96c1148854 100644 --- a/src/fpm_meta.f90 +++ b/src/fpm_meta.f90 @@ -3,21 +3,22 @@ !> 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 +!> +!>### 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_strings, only: string_t, len_trim, remove_newline_characters, str_begins_with_str, & + str_ends_with use fpm_error, only: error_t, fatal_error, syntax_error, fpm_stop use fpm_compiler use fpm_model @@ -29,6 +30,8 @@ module fpm_meta 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 shlex_module, only: shlex_split => split +use regex_module, only: regex use iso_fortran_env, only: stdout => output_unit implicit none @@ -106,6 +109,8 @@ module fpm_meta integer, parameter, private :: LANG_C = 2 integer, parameter, private :: LANG_CXX = 3 +character(*), parameter :: LANG_NAME(*) = [character(7) :: 'Fortran','C','C++'] + contains !> Return a name for the MPI library @@ -434,10 +439,8 @@ subroutine resolve_metapackage_model(model,package,settings,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 + if (model%compiler%is_unknown()) & + write(stdout,'(a)') ' compiler not initialized: metapackages may not be available' ! OpenMP if (package%meta%openmp%on) then @@ -487,6 +490,9 @@ subroutine init_mpi(this,compiler,error) !> Cleanup call destroy(this) + fwrap = string_t("") + cwrap = string_t("") + cxxwrap = string_t("") !> Get all candidate MPI wrappers call mpi_wrappers(compiler,fort_wrappers,c_wrappers,cpp_wrappers) @@ -634,7 +640,13 @@ logical function msmpi_init(this,compiler,error) result(found) 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 + ! Third attempt for bash-style shell + 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 fourth 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%...' @@ -647,7 +659,7 @@ logical function msmpi_init(this,compiler,error) result(found) endif - if (allocated(error) .or. .not.exists(bindir)) then + if (allocated(error)) 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 @@ -983,28 +995,25 @@ subroutine init_mpi_from_wrappers(this,compiler,mpilib,fort_wrapper,c_wrapper,cx call destroy(this) ! Get linking flags - if (mpilib/=MPI_TYPE_INTEL) then - this%link_flags = mpi_wrapper_query(mpilib,fort_wrapper,'link',verbose,error) + this%link_flags = mpi_wrapper_query(mpilib,fort_wrapper,'link',verbose,error) + if (allocated(error)) return - ! 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) + ! Remove useless/dangerous flags + call filter_link_arguments(compiler,this%link_flags) - if (allocated(error)) return - this%has_link_flags = len_trim(this%link_flags)>0 - endif + this%has_link_flags = len_trim(this%link_flags)>0 ! 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) + call set_language_flags(compiler,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) + call set_language_flags(compiler,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) + call set_language_flags(compiler,mpilib,cxx_wrapper,this%has_cxx_flags,this%cxxflags,verbose,error) if (allocated(error)) return ! Get library version @@ -1021,7 +1030,8 @@ subroutine init_mpi_from_wrappers(this,compiler,mpilib,fort_wrapper,c_wrapper,cx contains - subroutine set_language_flags(mpilib,wrapper,has_flags,flags,verbose,error) + subroutine set_language_flags(compiler,mpilib,wrapper,has_flags,flags,verbose,error) + type(compiler_t), intent(in) :: compiler integer, intent(in) :: mpilib type(string_t), intent(in) :: wrapper logical, intent(inout) :: has_flags @@ -1041,6 +1051,8 @@ subroutine set_language_flags(mpilib,wrapper,has_flags,flags,verbose,error) if (verbose) print *, '+ MPI language flags from wrapper <',wrapper%s,'>: flags=',flags%s + call filter_build_arguments(compiler,flags) + endif end subroutine set_language_flags @@ -1055,13 +1067,16 @@ subroutine mpi_compiler_match(language,wrappers,compiler,which_one,mpilib,error) integer, intent(out) :: which_one, mpilib type(error_t), allocatable, intent(out) :: error - integer :: i + integer :: i, same_vendor, vendor_mpilib type(string_t) :: screen character(128) :: msg_out type(compiler_t) :: mpi_compiler - which_one = 0 - mpilib = MPI_TYPE_NONE + which_one = 0 + same_vendor = 0 + mpilib = MPI_TYPE_NONE + + if (verbose) print *, '+ Trying to match available ',LANG_NAME(language),' MPI wrappers to ',compiler%fc,'...' do i=1,size(wrappers) @@ -1070,6 +1085,8 @@ subroutine mpi_compiler_match(language,wrappers,compiler,which_one,mpilib,error) screen = mpi_wrapper_query(mpilib,wrappers(i),'compiler',verbose=.false.,error=error) if (allocated(error)) return + if (verbose) print *, ' Wrapper ',wrappers(i)%s,' lib=',MPI_TYPE_NAME(mpilib),' uses ',screen%s + select case (language) case (LANG_FORTRAN) ! Build compiler type. The ID is created based on the Fortran name @@ -1081,21 +1098,50 @@ subroutine mpi_compiler_match(language,wrappers,compiler,which_one,mpilib,error) return end if + ! Because the intel mpi library does not support llvm_ compiler wrappers yet, + ! we must check for that manually + if (same_vendor==0 .and. mpi_compiler%is_intel() .and. compiler%is_intel()) then + same_vendor = i + vendor_mpilib = mpilib + 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 + + ! Because the intel mpi library does not support llvm_ compiler wrappers yet, + ! we must check for that manually + if (same_vendor==0 .and. screen%s=='icc' .and. compiler%cc=='icx') then + same_vendor = i + vendor_mpilib = mpilib + end if + case (LANG_CXX) if (screen%s==compiler%cxx .or. screen%s==compiler%fc) then which_one = i return end if + + ! Because the intel mpi library does not support llvm_ compiler wrappers yet, + ! we must check for that manually + if (same_vendor==0 .and. screen%s=='icpc' .and. compiler%cc=='icpx') then + same_vendor = i + vendor_mpilib = mpilib + end if + end select end do + ! Intel compiler: if an exact match is not found, attempt closest wrapper + if (which_one==0 .and. same_vendor>0) then + which_one = same_vendor + mpilib = vendor_mpilib + end if + ! 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)) @@ -1395,6 +1441,7 @@ type(string_t) function mpi_wrapper_query(mpilib,wrapper,command,verbose,error) end if ! Take out the first command from the whole line + call remove_newline_characters(screen) call split(screen%s,tokens,delimiters=' ') screen%s = trim(adjustl(tokens(1))) @@ -1441,6 +1488,7 @@ type(string_t) function mpi_wrapper_query(mpilib,wrapper,command,verbose,error) select case (mpilib) case (MPI_TYPE_OPENMPI); cmdstr = string_t('--showme:link') case (MPI_TYPE_MPICH); cmdstr = string_t('-link-info') + case (MPI_TYPE_INTEL); cmdstr = string_t('-show') case default call fatal_error(error,unsupported_msg) return @@ -1458,7 +1506,7 @@ type(string_t) function mpi_wrapper_query(mpilib,wrapper,command,verbose,error) select case (mpilib) case (MPI_TYPE_OPENMPI) call remove_newline_characters(screen) - case (MPI_TYPE_MPICH) + case (MPI_TYPE_MPICH,MPI_TYPE_INTEL) ! MPICH reports the full command including the compiler name. Remove it if so call remove_newline_characters(screen) call split(screen%s,tokens) @@ -1598,4 +1646,123 @@ type(string_t) function mpi_wrapper_query(mpilib,wrapper,command,verbose,error) end function mpi_wrapper_query +!> Check if input is a useful linker argument +logical function is_link_argument(compiler,string) + type(compiler_t), intent(in) :: compiler + character(*), intent(in) :: string + + select case (compiler%id) + case (id_intel_classic_windows,id_intel_llvm_windows) + is_link_argument = string=='/link' & + .or. str_begins_with_str(string,'/LIBPATH')& + .or. str_ends_with(string,'.lib') ! always .lib whether static or dynamic + case default + + ! fix OpenMPI's Fortran wrapper bug (https://github.com/open-mpi/ompi/issues/11636) here + is_link_argument = ( str_begins_with_str(string,'-L') & + .or. str_begins_with_str(string,'-l') & + .or. str_begins_with_str(string,'-Xlinker') & + .or. string=='-pthread' & + .or. (str_begins_with_str(string,'-W') .and. & + (string/='-Wall') .and. (.not.str_begins_with_str(string,'-Werror'))) ) & + .and. .not. ( & + (get_os_type()==OS_MACOS .and. index(string,'-commons,use_dylibs')>0) ) + end select + +end function is_link_argument + +!> From build, remove optimization and other unnecessary flags +subroutine filter_build_arguments(compiler,command) + type(compiler_t), intent(in) :: compiler + type(string_t), intent(inout) :: command + character(len=:), allocatable :: tokens(:) + + integer :: i,n,re_i,re_l + logical, allocatable :: keep(:) + logical :: keep_next + character(len=:), allocatable :: module_flag,include_flag + + if (len_trim(command)<=0) return + + ! Split command into arguments + tokens = shlex_split(command%s) + + module_flag = get_module_flag(compiler,"") + include_flag = get_include_flag(compiler,"") + + n = size(tokens) + allocate(keep(n),source=.false.) + keep_next = .false. + + do i=1,n + + if (get_os_type()==OS_MACOS .and. index(tokens(i),'-commons,use_dylibs')>0) then + keep(i) = .false. + keep_next = .false. + elseif (str_begins_with_str(tokens(i),'-D') .or. & + str_begins_with_str(tokens(i),'-f') .or. & + str_begins_with_str(tokens(i),'-I') .or. & + str_begins_with_str(tokens(i),module_flag) .or. & + str_begins_with_str(tokens(i),include_flag) .or. & + tokens(i)=='-pthread' .or. & + (str_begins_with_str(tokens(i),'-W') .and. tokens(i)/='-Wall' .and. .not.str_begins_with_str(tokens(i),'-Werror')) & + ) then + keep(i) = .true. + if (tokens(i)==module_flag .or. tokens(i)==include_flag .or. tokens(i)=='-I') keep_next = .true. + elseif (keep_next) then + keep(i) = .true. + keep_next = .false. + end if + end do + + ! Backfill + command = string_t("") + do i=1,n + if (.not.keep(i)) cycle + + command%s = command%s//' '//trim(tokens(i)) + end do + + +end subroutine filter_build_arguments + +!> From the linker flags, remove optimization and other unnecessary flags +subroutine filter_link_arguments(compiler,command) + type(compiler_t), intent(in) :: compiler + type(string_t), intent(inout) :: command + character(len=:), allocatable :: tokens(:) + + integer :: i,n + logical, allocatable :: keep(:) + logical :: keep_next + + if (len_trim(command)<=0) return + + ! Split command into arguments + tokens = shlex_split(command%s) + + n = size(tokens) + allocate(keep(n),source=.false.) + keep_next = .false. + + do i=1,n + if (is_link_argument(compiler,tokens(i))) then + keep(i) = .true. + if (tokens(i)=='-L' .or. tokens(i)=='-Xlinker') keep_next = .true. + elseif (keep_next) then + keep(i) = .true. + keep_next = .false. + end if + end do + + ! Backfill + command = string_t("") + do i=1,n + if (.not.keep(i)) cycle + command%s = command%s//' '//trim(tokens(i)) + end do + +end subroutine filter_link_arguments + + end module fpm_meta From 78f558a22e99c9676c3a1414ce06dec14f6cd320 Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Thu, 21 Dec 2023 21:28:07 +0100 Subject: [PATCH 02/13] collapse Intel-classic fallback option --- src/fpm_meta.f90 | 52 +++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/fpm_meta.f90 b/src/fpm_meta.f90 index 96c1148854..a6146977b9 100644 --- a/src/fpm_meta.f90 +++ b/src/fpm_meta.f90 @@ -1097,49 +1097,31 @@ subroutine mpi_compiler_match(language,wrappers,compiler,which_one,mpilib,error) which_one = i return end if - - ! Because the intel mpi library does not support llvm_ compiler wrappers yet, - ! we must check for that manually - if (same_vendor==0 .and. mpi_compiler%is_intel() .and. compiler%is_intel()) then - same_vendor = i - vendor_mpilib = mpilib - 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 - - ! Because the intel mpi library does not support llvm_ compiler wrappers yet, - ! we must check for that manually - if (same_vendor==0 .and. screen%s=='icc' .and. compiler%cc=='icx') then - same_vendor = i - vendor_mpilib = mpilib - end if - case (LANG_CXX) if (screen%s==compiler%cxx .or. screen%s==compiler%fc) then which_one = i return end if - - ! Because the intel mpi library does not support llvm_ compiler wrappers yet, - ! we must check for that manually - if (same_vendor==0 .and. screen%s=='icpc' .and. compiler%cc=='icpx') then - same_vendor = i - vendor_mpilib = mpilib - end if - end select + ! Because the intel mpi library does not support llvm_ compiler wrappers yet, + ! we must check for that manually + if (is_intel_classic_option(language,same_vendor,screen,compiler,mpi_compiler)) then + same_vendor = i + vendor_mpilib = mpilib + end if end do ! Intel compiler: if an exact match is not found, attempt closest wrapper if (which_one==0 .and. same_vendor>0) then which_one = same_vendor - mpilib = vendor_mpilib + mpilib = vendor_mpilib end if ! None of the available wrappers matched the current Fortran compiler @@ -1149,6 +1131,26 @@ subroutine mpi_compiler_match(language,wrappers,compiler,which_one,mpilib,error) end subroutine mpi_compiler_match +!> Because the Intel mpi library does not support llvm_ compiler wrappers yet, +!> we must save the Intel-classic option and later manually replace it +logical function is_intel_classic_option(language,same_vendor_ID,screen_out,compiler,mpi_compiler) + integer, intent(in) :: language,same_vendor_ID + type(string_t), intent(in) :: screen_out + type(compiler_t), intent(in) :: compiler,mpi_compiler + + if (same_vendor_ID/=0) return + + select case (language) + case (LANG_FORTRAN) + is_intel_classic_option = mpi_compiler%is_intel() .and. compiler%is_intel() + case (LANG_C) + is_intel_classic_option = screen_out%s=='icc' .and. compiler%cc=='icx' + case (LANG_CXX) + is_intel_classic_option = screen_out%s=='icpc' .and. compiler%cc=='icpx' + end select + +end function is_intel_classic_option + !> Return library version from the MPI wrapper command type(version_t) function mpi_version_get(mpilib,wrapper,error) integer, intent(in) :: mpilib From 82b9edaae7e9c79f9c454838ca48262f0b6cb118 Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Thu, 21 Dec 2023 21:29:03 +0100 Subject: [PATCH 03/13] remove redundant initializations --- src/fpm_environment.f90 | 2 -- src/fpm_meta.f90 | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/fpm_environment.f90 b/src/fpm_environment.f90 index f77ff47092..839fb17869 100644 --- a/src/fpm_environment.f90 +++ b/src/fpm_environment.f90 @@ -50,8 +50,6 @@ integer function get_os_type() result(r) first_run = .false. r = OS_UNKNOWN - length = 0 - rc = 0 ! Check environment variable `OSTYPE`. call get_environment_variable('OSTYPE', val, length, rc) diff --git a/src/fpm_meta.f90 b/src/fpm_meta.f90 index a6146977b9..7b6603f0b6 100644 --- a/src/fpm_meta.f90 +++ b/src/fpm_meta.f90 @@ -490,9 +490,6 @@ subroutine init_mpi(this,compiler,error) !> Cleanup call destroy(this) - fwrap = string_t("") - cwrap = string_t("") - cxxwrap = string_t("") !> Get all candidate MPI wrappers call mpi_wrappers(compiler,fort_wrappers,c_wrappers,cpp_wrappers) From cab2c2611e3a4683c2a9107ede66adbcb1f129fa Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Thu, 21 Dec 2023 21:33:56 +0100 Subject: [PATCH 04/13] prevent uninitialized variable --- src/fpm_meta.f90 | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/fpm_meta.f90 b/src/fpm_meta.f90 index 7b6603f0b6..3265b26e47 100644 --- a/src/fpm_meta.f90 +++ b/src/fpm_meta.f90 @@ -1135,16 +1135,18 @@ logical function is_intel_classic_option(language,same_vendor_ID,screen_out,comp type(string_t), intent(in) :: screen_out type(compiler_t), intent(in) :: compiler,mpi_compiler - if (same_vendor_ID/=0) return - - select case (language) - case (LANG_FORTRAN) - is_intel_classic_option = mpi_compiler%is_intel() .and. compiler%is_intel() - case (LANG_C) - is_intel_classic_option = screen_out%s=='icc' .and. compiler%cc=='icx' - case (LANG_CXX) - is_intel_classic_option = screen_out%s=='icpc' .and. compiler%cc=='icpx' - end select + if (same_vendor_ID/=0) then + is_intel_classic_option = .false. + else + select case (language) + case (LANG_FORTRAN) + is_intel_classic_option = mpi_compiler%is_intel() .and. compiler%is_intel() + case (LANG_C) + is_intel_classic_option = screen_out%s=='icc' .and. compiler%cc=='icx' + case (LANG_CXX) + is_intel_classic_option = screen_out%s=='icpc' .and. compiler%cc=='icpx' + end select + end if end function is_intel_classic_option From cf13403bdeacd3edb79b36b3a8500b0b8e5254d2 Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Thu, 28 Dec 2023 13:58:31 +0100 Subject: [PATCH 05/13] turn off Windows metapackage CI --- .github/workflows/meta.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml index 61053cbd81..192214e373 100644 --- a/.github/workflows/meta.yml +++ b/.github/workflows/meta.yml @@ -35,8 +35,6 @@ jobs: mpi: openmpi - os: ubuntu-latest mpi: mpich - - os: windows-latest - mpi: msmpi - os: macos-latest mpi: openmpi - os: macos-latest From 70ecab1de4707c4d64955265f6e2ee928b1bdd07 Mon Sep 17 00:00:00 2001 From: gnikit Date: Sun, 7 Jan 2024 19:36:57 +0200 Subject: [PATCH 06/13] chore: bump to v0.10.0 --- fpm.toml | 2 +- src/fpm/fpm_release.F90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fpm.toml b/fpm.toml index 3956e42105..927889e227 100644 --- a/fpm.toml +++ b/fpm.toml @@ -1,5 +1,5 @@ name = "fpm" -version = "0.9.0" +version = "0.10.0" license = "MIT" author = "fpm maintainers" maintainer = "" diff --git a/src/fpm/fpm_release.F90 b/src/fpm/fpm_release.F90 index e80050b3ee..fdd88c2781 100644 --- a/src/fpm/fpm_release.F90 +++ b/src/fpm/fpm_release.F90 @@ -18,7 +18,7 @@ type(version_t) function fpm_version() ! Fallback to last known version in case of undefined macro #ifndef FPM_RELEASE_VERSION -# define FPM_RELEASE_VERSION 0.8.0 +# define FPM_RELEASE_VERSION 0.10.0 #endif ! Accept solution from https://stackoverflow.com/questions/31649691/stringify-macro-with-gnu-gfortran From 4da5cc58c57ca2d91dcbc96b9aac55916fec26fe Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Sat, 13 Jan 2024 09:27:18 +0100 Subject: [PATCH 07/13] add gcc versions 11,12,13 for CI validation --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 08b8ed725a..16a6d52c02 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -22,7 +22,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-11, windows-latest] - gcc_v: [10] # Version of GFortran we want to use. + gcc_v: [10,11,12,13] # Version of GFortran we want to use. include: - os: ubuntu-latest os-arch: linux-x86_64 From 99543aead461ed0a9bc6671eadb02ec30a327202 Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Sat, 13 Jan 2024 16:04:08 +0100 Subject: [PATCH 08/13] add custom source extension capability to `preprocess` support preprocessor suffixes fix for allocatable string replace function wiht subroutine fix allocations check present use macros only if allocated --- ci/run_tests.sh | 4 + .../preprocess_cpp_suffix/.gitignore | 1 + .../preprocess_cpp_suffix/app/main.f90 | 8 ++ .../preprocess_cpp_suffix/fpm.toml | 7 ++ .../src/preprocess_cpp.fpp | 22 ++++++ src/fpm.f90 | 38 ++++------ src/fpm/manifest/preprocess.f90 | 74 +++++++++++++++++++ src/fpm_model.f90 | 3 +- src/fpm_sources.f90 | 56 +++++++++++--- src/fpm_strings.f90 | 18 +++++ src/fpm_targets.f90 | 15 ++-- 11 files changed, 206 insertions(+), 40 deletions(-) create mode 100644 example_packages/preprocess_cpp_suffix/.gitignore create mode 100644 example_packages/preprocess_cpp_suffix/app/main.f90 create mode 100644 example_packages/preprocess_cpp_suffix/fpm.toml create mode 100644 example_packages/preprocess_cpp_suffix/src/preprocess_cpp.fpp diff --git a/ci/run_tests.sh b/ci/run_tests.sh index d84a00f1c5..c31f134312 100755 --- a/ci/run_tests.sh +++ b/ci/run_tests.sh @@ -150,6 +150,10 @@ pushd preprocess_cpp_deps "$fpm" build popd +pushd preprocess_cpp_suffix +"$fpm" run +popd + pushd preprocess_per_dependency "$fpm" run popd diff --git a/example_packages/preprocess_cpp_suffix/.gitignore b/example_packages/preprocess_cpp_suffix/.gitignore new file mode 100644 index 0000000000..a007feab07 --- /dev/null +++ b/example_packages/preprocess_cpp_suffix/.gitignore @@ -0,0 +1 @@ +build/* diff --git a/example_packages/preprocess_cpp_suffix/app/main.f90 b/example_packages/preprocess_cpp_suffix/app/main.f90 new file mode 100644 index 0000000000..7d77b56a06 --- /dev/null +++ b/example_packages/preprocess_cpp_suffix/app/main.f90 @@ -0,0 +1,8 @@ +program test_preprocess_suffix + use preprocess_cpp +#ifndef TESTMACRO + stop -1 +#else + stop 0 +#endif +end program test_preprocess_suffix diff --git a/example_packages/preprocess_cpp_suffix/fpm.toml b/example_packages/preprocess_cpp_suffix/fpm.toml new file mode 100644 index 0000000000..6399f1a67d --- /dev/null +++ b/example_packages/preprocess_cpp_suffix/fpm.toml @@ -0,0 +1,7 @@ +name = "preprocess_cpp_suffix" +version = "1" + +[preprocess] +[preprocess.cpp] +macros = ["TESTMACRO", "TESTMACRO2=3", "TESTMACRO3={version}"] +suffixes = ["fpp"] diff --git a/example_packages/preprocess_cpp_suffix/src/preprocess_cpp.fpp b/example_packages/preprocess_cpp_suffix/src/preprocess_cpp.fpp new file mode 100644 index 0000000000..d7ab5d1485 --- /dev/null +++ b/example_packages/preprocess_cpp_suffix/src/preprocess_cpp.fpp @@ -0,0 +1,22 @@ +module preprocess_cpp + implicit none + private + + public :: say_hello +contains + subroutine say_hello + print *, "Hello, preprocess_cpp!" +#ifndef TESTMACRO + This breaks the build. +#endif + +#if TESTMACRO2 != 3 + This breaks the build. +#endif + +#if TESTMACRO3 != 1 + This breaks the build. +#endif + + end subroutine say_hello +end module preprocess_cpp diff --git a/src/fpm.f90 b/src/fpm.f90 index 0a2712e612..bb2972bd9e 100644 --- a/src/fpm.f90 +++ b/src/fpm.f90 @@ -110,37 +110,23 @@ subroutine build_model(model, settings, package, error) model%packages(i)%version = package%version%s() !> Add this dependency's manifest macros - allocate(model%packages(i)%macros(0)) + call model%packages(i)%preprocess%destroy() 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 + call model%packages(i)%preprocess%add_config(dependency%preprocess(j)) 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 + call model%packages(i)%preprocess%add_config(dep%preprocess(j)) end do end if + if (model%packages(i)%preprocess%is_cpp()) has_cpp = .true. + if (.not.allocated(model%packages(i)%sources)) allocate(model%packages(i)%sources(0)) if (allocated(dependency%library)) then @@ -149,7 +135,7 @@ subroutine build_model(model, settings, package, error) 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) + with_f_ext=model%packages(i)%preprocess%suffixes, error=error) if (allocated(error)) exit end if end if @@ -187,7 +173,8 @@ subroutine build_model(model, settings, package, error) ! 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) + with_executables=.true., with_f_ext=model%packages(1)%preprocess%suffixes,& + error=error) if (allocated(error)) then return @@ -196,7 +183,8 @@ subroutine build_model(model, settings, package, error) 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) + with_executables=.true., & + with_f_ext=model%packages(1)%preprocess%suffixes,error=error) if (allocated(error)) then return @@ -205,7 +193,8 @@ subroutine build_model(model, settings, package, error) 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) + with_executables=.true., & + with_f_ext=model%packages(1)%preprocess%suffixes,error=error) if (allocated(error)) then return @@ -215,6 +204,7 @@ subroutine build_model(model, settings, package, error) if (allocated(package%executable)) then call add_executable_sources(model%packages(1)%sources, package%executable, FPM_SCOPE_APP, & auto_discover=package%build%auto_executables, & + with_f_ext=model%packages(1)%preprocess%suffixes, & error=error) if (allocated(error)) then @@ -225,6 +215,7 @@ subroutine build_model(model, settings, package, error) if (allocated(package%example)) then call add_executable_sources(model%packages(1)%sources, package%example, FPM_SCOPE_EXAMPLE, & auto_discover=package%build%auto_examples, & + with_f_ext=model%packages(1)%preprocess%suffixes, & error=error) if (allocated(error)) then @@ -235,6 +226,7 @@ subroutine build_model(model, settings, package, error) if (allocated(package%test)) then call add_executable_sources(model%packages(1)%sources, package%test, FPM_SCOPE_TEST, & auto_discover=package%build%auto_tests, & + with_f_ext=model%packages(1)%preprocess%suffixes, & error=error) if (allocated(error)) then diff --git a/src/fpm/manifest/preprocess.f90 b/src/fpm/manifest/preprocess.f90 index 3f9754725a..f7faff2a9c 100644 --- a/src/fpm/manifest/preprocess.f90 +++ b/src/fpm/manifest/preprocess.f90 @@ -14,6 +14,7 @@ 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 + use,intrinsic :: iso_fortran_env, only : stderr=>error_unit implicit none private @@ -39,6 +40,14 @@ module fpm_manifest_preprocess !> Print information on this instance procedure :: info + !> Operations + procedure :: destroy + procedure :: add_config + + !> Properties + procedure :: is_cpp + procedure :: is_fypp + end type preprocess_config_t interface operator(==) @@ -228,4 +237,69 @@ logical function preprocess_is_same(this,that) end function preprocess_is_same + !> Clean preprocessor structure + elemental subroutine destroy(this) + class(preprocess_config_t), intent(inout) :: this + + if (allocated(this%name))deallocate(this%name) + if (allocated(this%suffixes))deallocate(this%suffixes) + if (allocated(this%directories))deallocate(this%directories) + if (allocated(this%macros))deallocate(this%macros) + + end subroutine destroy + + !> Add preprocessor settings + subroutine add_config(this,that) + class(preprocess_config_t), intent(inout) :: this + type(preprocess_config_t), intent(in) :: that + + if (.not.that%name=="cpp") then + write(stderr, '(a)') 'Warning: Preprocessor ' // that%name // & + ' is not supported; will ignore it' + return + end if + + if (.not.allocated(this%name)) this%name = that%name + + ! Add macros + if (allocated(that%macros)) then + if (allocated(this%macros)) then + this%macros = [this%macros, that%macros] + else + allocate(this%macros, source = that%macros) + end if + endif + + ! Add suffixes + if (allocated(that%suffixes)) then + if (allocated(this%suffixes)) then + this%suffixes = [this%suffixes, that%suffixes] + else + allocate(this%suffixes, source = that%suffixes) + end if + endif + + ! Add directories + if (allocated(that%directories)) then + if (allocated(this%directories)) then + this%directories = [this%directories, that%directories] + else + allocate(this%directories, source = that%directories) + end if + endif + + end subroutine add_config + + ! Check cpp + logical function is_cpp(this) + class(preprocess_config_t), intent(in) :: this + is_cpp = this%name == "cpp" + end function is_cpp + + ! Check cpp + logical function is_fypp(this) + class(preprocess_config_t), intent(in) :: this + is_fypp = this%name == "fypp" + end function is_fypp + end module fpm_manifest_preprocess diff --git a/src/fpm_model.f90 b/src/fpm_model.f90 index dba15a8161..910498c2a2 100644 --- a/src/fpm_model.f90 +++ b/src/fpm_model.f90 @@ -39,6 +39,7 @@ module fpm_model 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 +use fpm_manifest_preprocess, only: preprocess_config_t implicit none private @@ -137,7 +138,7 @@ module fpm_model type(srcfile_t), allocatable :: sources(:) !> List of macros. - type(string_t), allocatable :: macros(:) + type(preprocess_config_t) :: preprocess !> Package version number. character(:), allocatable :: version diff --git a/src/fpm_sources.f90 b/src/fpm_sources.f90 index 0165249f50..97c2feeb45 100644 --- a/src/fpm_sources.f90 +++ b/src/fpm_sources.f90 @@ -25,12 +25,16 @@ module fpm_sources !> Wrapper to source parsing routines. !> Selects parsing routine based on source file name extension -function parse_source(source_file_path,error) result(source) +function parse_source(source_file_path,custom_f_ext,error) result(source) character(*), intent(in) :: source_file_path + type(string_t), optional, intent(in) :: custom_f_ext(:) type(error_t), allocatable, intent(out) :: error type(srcfile_t) :: source + type(string_t), allocatable :: f_ext(:) - if (str_ends_with(lower(source_file_path), fortran_suffixes)) then + call list_fortran_suffixes(f_ext,custom_f_ext) + + if (str_ends_with(lower(source_file_path), f_ext)) then source = parse_f_source(source_file_path, error) @@ -42,7 +46,7 @@ function parse_source(source_file_path,error) result(source) source = parse_c_source(source_file_path,error) - end if + endif if (allocated(error)) then return @@ -50,8 +54,31 @@ function parse_source(source_file_path,error) result(source) end function parse_source +!> List fortran suffixes, including optional ones +subroutine list_fortran_suffixes(suffixes,with_f_ext) + type(string_t), allocatable, intent(out) :: suffixes(:) + !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources + type(string_t), intent(in), optional :: with_f_ext(:) + + integer :: ndefault,nuser,i + + ndefault = size(fortran_suffixes) + nuser = 0; if (present(with_f_ext)) nuser = size(with_f_ext) + + allocate(suffixes(ndefault + nuser)) + do i=1,ndefault + suffixes(i) = string_t(fortran_suffixes(i)) + end do + if (present(with_f_ext)) then + do i=1,nuser + suffixes(ndefault+1) = string_t(with_f_ext(i)%s) + end do + endif + +end subroutine list_fortran_suffixes + !> Add to `sources` by looking for source files in `directory` -subroutine add_sources_from_dir(sources,directory,scope,with_executables,recurse,error) +subroutine add_sources_from_dir(sources,directory,scope,with_executables,with_f_ext,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 @@ -60,6 +87,8 @@ subroutine add_sources_from_dir(sources,directory,scope,with_executables,recurse integer, intent(in) :: scope !> Executable sources (fortran `program`s) are ignored unless `with_executables=.true.` logical, intent(in), optional :: with_executables + !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources + type(string_t), intent(in), optional :: with_f_ext(:) !> Whether to recursively search subdirectories, default is `.true.` logical, intent(in), optional :: recurse !> Error handling @@ -69,7 +98,7 @@ subroutine add_sources_from_dir(sources,directory,scope,with_executables,recurse 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 :: src_file_names(:),f_ext(:) type(string_t), allocatable :: existing_src_files(:) type(srcfile_t), allocatable :: dir_sources(:) @@ -87,10 +116,15 @@ subroutine add_sources_from_dir(sources,directory,scope,with_executables,recurse allocate(existing_src_files(0)) end if + ! Get legal fortran suffixes + call list_fortran_suffixes(f_ext,with_f_ext) + 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), f_ext) .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))) @@ -98,7 +132,7 @@ subroutine add_sources_from_dir(sources,directory,scope,with_executables,recurse do i = 1, size(src_file_names) - dir_sources(i) = parse_source(src_file_names(i)%s,error) + dir_sources(i) = parse_source(src_file_names(i)%s,with_f_ext,error) if (allocated(error)) return dir_sources(i)%unit_scope = scope @@ -129,7 +163,7 @@ 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) +subroutine add_executable_sources(sources,executables,scope,auto_discover,with_f_ext,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 @@ -138,6 +172,8 @@ subroutine add_executable_sources(sources,executables,scope,auto_discover,error) integer, intent(in) :: scope !> If `.false.` only executables and tests specified in the manifest are added to `sources` logical, intent(in) :: auto_discover + !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources + type(string_t), intent(in), optional :: with_f_ext(:) !> Error handling type(error_t), allocatable, intent(out) :: error @@ -150,7 +186,7 @@ subroutine add_executable_sources(sources,executables,scope,auto_discover,error) 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) + with_executables=auto_discover, with_f_ext=with_f_ext,recurse=.false., error=error) if (allocated(error)) then return @@ -180,7 +216,7 @@ subroutine add_executable_sources(sources,executables,scope,auto_discover,error) ! 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 = parse_source(join_path(exe%source_dir,exe%main),with_f_ext,error) exe_source%exe_name = exe%name if (allocated(exe%link)) then exe_source%link_libraries = exe%link diff --git a/src/fpm_strings.f90 b/src/fpm_strings.f90 index 55f57537e5..c3187db786 100644 --- a/src/fpm_strings.f90 +++ b/src/fpm_strings.f90 @@ -76,6 +76,7 @@ module fpm_strings interface str_ends_with procedure :: str_ends_with_str procedure :: str_ends_with_any + procedure :: str_ends_with_any_string end interface str_ends_with interface str @@ -122,6 +123,23 @@ pure logical function str_ends_with_any(s, e) result(r) end function str_ends_with_any +!> Test if a CHARACTER string ends with any of an array of string suffixs +pure logical function str_ends_with_any_string(s, e) result(r) + character(*), intent(in) :: s + type(string_t), intent(in) :: e(:) + + integer :: i + + r = .true. + do i=1,size(e) + + if (str_ends_with(s,trim(e(i)%s))) return + + end do + r = .false. + +end function str_ends_with_any_string + !> 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 diff --git a/src/fpm_targets.f90 b/src/fpm_targets.f90 index df0d58810f..7c8c97b775 100644 --- a/src/fpm_targets.f90 +++ b/src/fpm_targets.f90 @@ -33,6 +33,7 @@ module fpm_targets 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 +use fpm_manifest_preprocess, only: preprocess_config_t implicit none private @@ -233,7 +234,7 @@ subroutine build_target_list(targets,model) sources(i)%unit_type==FPM_UNIT_CSOURCE), & output_name = get_object_name(sources(i)), & features = model%packages(j)%features, & - macros = model%packages(j)%macros, & + preprocess = model%packages(j)%preprocess, & version = model%packages(j)%version) @@ -247,7 +248,7 @@ subroutine build_target_list(targets,model) 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, & + preprocess = model%packages(j)%preprocess, & version = model%packages(j)%version) if (with_lib .and. sources(i)%unit_scope == FPM_SCOPE_LIB) then @@ -280,7 +281,7 @@ subroutine build_target_list(targets,model) output_name = get_object_name(sources(i)), & source = sources(i), & features = model%packages(j)%features, & - macros = model%packages(j)%macros & + preprocess = model%packages(j)%preprocess & ) if (sources(i)%unit_scope == FPM_SCOPE_APP) then @@ -413,7 +414,7 @@ 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) + & features, preprocess, version) type(build_target_ptr), allocatable, intent(inout) :: targets(:) character(*), intent(in) :: package integer, intent(in) :: type @@ -421,7 +422,7 @@ subroutine add_target(targets, package, type, output_name, source, link_librarie 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(:) + type(preprocess_config_t), intent(in), optional :: preprocess character(*), intent(in), optional :: version integer :: i @@ -450,7 +451,9 @@ subroutine add_target(targets, package, type, output_name, source, link_librarie 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(preprocess)) then + if (allocated(preprocess%macros)) new_target%macros = preprocess%macros + endif if (present(version)) new_target%version = version allocate(new_target%dependencies(0)) From 7b035fd5143591af9fdc47130a1de4ae95c881fd Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Sat, 13 Jan 2024 21:48:30 +0100 Subject: [PATCH 09/13] fix Intel error on unallocated character array --- src/fpm/manifest/preprocess.f90 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/fpm/manifest/preprocess.f90 b/src/fpm/manifest/preprocess.f90 index f7faff2a9c..2df2570e39 100644 --- a/src/fpm/manifest/preprocess.f90 +++ b/src/fpm/manifest/preprocess.f90 @@ -253,7 +253,7 @@ subroutine add_config(this,that) class(preprocess_config_t), intent(inout) :: this type(preprocess_config_t), intent(in) :: that - if (.not.that%name=="cpp") then + if (.not.that%is_cpp()) then write(stderr, '(a)') 'Warning: Preprocessor ' // that%name // & ' is not supported; will ignore it' return @@ -293,13 +293,15 @@ end subroutine add_config ! Check cpp logical function is_cpp(this) class(preprocess_config_t), intent(in) :: this - is_cpp = this%name == "cpp" + is_cpp = .false. + if (allocated(this%name)) is_cpp = this%name == "cpp" end function is_cpp ! Check cpp logical function is_fypp(this) class(preprocess_config_t), intent(in) :: this - is_fypp = this%name == "fypp" + is_fypp = .false. + if (allocated(this%name)) is_fypp = this%name == "fypp" end function is_fypp end module fpm_manifest_preprocess From 4c7356562b2c3d320948740a5e4b24b8292d3e38 Mon Sep 17 00:00:00 2001 From: gnikit Date: Mon, 15 Jan 2024 22:39:01 +0000 Subject: [PATCH 10/13] ci: adds monthly dependabot updates on GitHub Actions --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..8ac6b8c498 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" From e3e32cd851f6956c27e9ca79a420709ed24076b5 Mon Sep 17 00:00:00 2001 From: Federico Perini Date: Fri, 19 Jan 2024 17:46:42 +0100 Subject: [PATCH 11/13] Fix typo in `list_fortran_suffixes` by @jvdp1 Co-authored-by: Jeremie Vandenplas --- src/fpm_sources.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fpm_sources.f90 b/src/fpm_sources.f90 index 97c2feeb45..69c724eec6 100644 --- a/src/fpm_sources.f90 +++ b/src/fpm_sources.f90 @@ -71,7 +71,7 @@ subroutine list_fortran_suffixes(suffixes,with_f_ext) end do if (present(with_f_ext)) then do i=1,nuser - suffixes(ndefault+1) = string_t(with_f_ext(i)%s) + suffixes(ndefault+i) = string_t(with_f_ext(i)%s) end do endif From d05afd8fd93f41277887cbc480b9cedb4ef63a2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 Jan 2024 21:46:41 +0000 Subject: [PATCH 12/13] Bump actions/checkout from 1 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 1 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v1...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/CI.yml | 6 +++--- .github/workflows/docs.yml | 2 +- .github/workflows/meta.yml | 2 +- .github/workflows/release.yml | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 16a6d52c02..4d97f92f1f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Install GFortran macOS if: contains(matrix.os, 'macos') @@ -194,7 +194,7 @@ jobs: - build steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Download Artifacts uses: actions/download-artifact@v2 @@ -277,7 +277,7 @@ jobs: env: DEPLOY_BRANCH: ${{ secrets.DEPLOY_BRANCH && contains(github.ref, secrets.DEPLOY_BRANCH) && 1 || 0 }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 if: ${{ github.event_name == 'push' }} - name: Download Artifacts diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2ecb4183a1..9cd7789e0f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -6,7 +6,7 @@ jobs: build-and-deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: actions/setup-python@v1 with: python-version: '3.x' diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml index 192214e373..be6a46dcb9 100644 --- a/.github/workflows/meta.yml +++ b/.github/workflows/meta.yml @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: (Ubuntu) setup gcc version if: contains(matrix.os,'ubuntu') diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b4b030d5a9..b14537c8c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: FORMAT: ${{ matrix.format }} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -44,7 +44,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -124,7 +124,7 @@ jobs: env: DEPLOY_BRANCH: ${{ secrets.DEPLOY_BRANCH && contains(github.ref, secrets.DEPLOY_BRANCH) && 1 || 0 }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 if: ${{ github.event_name == 'push' }} - name: Download Artifacts From bb0a33d7df59b09a061391dcbcd6cb4020339e20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jan 2024 12:36:27 +0000 Subject: [PATCH 13/13] Bump actions/setup-python from 1 to 5 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 1 to 5. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v1...v5) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9cd7789e0f..e3418fe23a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install dependencies