fpm_meta.f90 Source File


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
!> - HDF5
!> - 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_compiler, only: compiler_t
    use fpm_manifest, only: package_config_t
    use fpm_model, only: fpm_model_t
    use fpm_command_line, only: fpm_cmd_settings, fpm_build_settings, fpm_run_settings
    use fpm_error, only: error_t, syntax_error, fatal_error

    use fpm_meta_base, only: metapackage_t, destroy
    use fpm_meta_openmp, only: init_openmp
    use fpm_meta_stdlib, only: init_stdlib
    use fpm_meta_minpack, only: init_minpack
    use fpm_meta_mpi, only: init_mpi
    use fpm_meta_hdf5, only: init_hdf5
    use fpm_meta_netcdf, only: init_netcdf
    use fpm_meta_blas, only: init_blas

    use shlex_module, only: shlex_split => split
    use regex_module, only: regex
    use iso_fortran_env, only: stdout => output_unit

    implicit none

    private

    public :: resolve_metapackages

    interface resolve_metapackages
        module procedure resolve_metapackage_model
    end interface resolve_metapackages

    contains

    !> 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("hdf5");    call init_hdf5   (this,compiler,error)
            case("netcdf");  call init_netcdf (this,compiler,error)
            case("blas");    call init_blas   (this,compiler,error)
            case default
                call syntax_error(error, "Package "//name//" is not supported in [metapackages]")
                return
        end select

    end subroutine init_from_name

    !> 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 init_from_name(meta,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()) &
        write(stdout,'(a)') '<WARNING> compiler not initialized: metapackages may not be available'

        ! 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

        ! minpack
        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)')'<WARNING> 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

        ! hdf5
        if (package%meta%hdf5%on) then
            call add_metapackage_model(model,package,settings,"hdf5",error)
            if (allocated(error)) return
        endif

        ! netcdf
        if (package%meta%netcdf%on) then
            call add_metapackage_model(model,package,settings,"netcdf",error)
            if (allocated(error)) return
        endif

        ! blas
        if (package%meta%blas%on) then
            call add_metapackage_model(model,package,settings,"blas",error)
            if (allocated(error)) return
        endif

    end subroutine resolve_metapackage_model

end module fpm_meta