diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml index cd00d820a7..ce97486950 100644 --- a/.github/workflows/meta.yml +++ b/.github/workflows/meta.yml @@ -4,17 +4,17 @@ on: # On push, only run if any of the metapackage files has changed push: paths: - - 'src/*meta*.f90' + - 'src/*meta*.f90' - 'src/fpm/*meta*.f90' - 'src/fpm/manifest/*meta*.f90' - 'src/ci/meta_tests.sh' - 'src/.github/workflows/meta.yml' - # Always run on PR or release + # Always run on PR or release pull_request: release: types: [published] # Allow manual triggering - workflow_dispatch: + workflow_dispatch: env: CI: "ON" # We can detect this in the build system and other vendors implement it @@ -51,7 +51,7 @@ jobs: - name: (Ubuntu/macOS) setup gcc version if: contains(matrix.os,'ubuntu') || contains(matrix.os,'macos') - run: | + run: | echo "GCC_V=14" >> $GITHUB_ENV - name: (Windows) Install MSYS2 @@ -67,6 +67,8 @@ jobs: unzip curl hdf5 + netcdf + netcdf-fortran - name: (Windows) Setup VS Build environment if: contains(matrix.os,'windows') && contains(matrix.mpi,'intel') @@ -84,7 +86,7 @@ jobs: Remove-Item "oneAPI" -Force -Recurse - name: (Ubuntu) Install gfortran - if: contains(matrix.os,'ubuntu') + if: contains(matrix.os,'ubuntu') run: | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_V} 100 \ --slave /usr/bin/gfortran gfortran /usr/bin/gfortran-${GCC_V} \ @@ -94,13 +96,15 @@ jobs: if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'openmpi') run: | sudo apt-get update - sudo apt install -y -q openmpi-bin libopenmpi-dev hwloc fabric libhdf5-dev libhdf5-fortran-102 + sudo apt install -y -q openmpi-bin libopenmpi-dev hwloc fabric libhdf5-dev \ + libhdf5-fortran-102 libnetcdf-dev libnetcdff-dev - name: (Ubuntu) Install MPICH if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'mpich') run: | sudo apt-get update - sudo apt install -y -q mpich hwloc fabric libhdf5-dev libhdf5-fortran-102 + sudo apt install -y -q mpich hwloc fabric libhdf5-dev libhdf5-fortran-102 \ + libnetcdf-dev libnetcdff-dev - name: (Ubuntu) Retrieve Intel toolchain if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'intel') @@ -115,16 +119,16 @@ jobs: uses: fortran-lang/setup-fortran@v1.6.1 id: setup-fortran with: - compiler: intel - version: 2024.1.0 + compiler: intel + version: 2024.1.0 - - name: (Ubuntu) finalize oneAPI environment + - name: (Ubuntu) finalize oneAPI environment if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'intel') run: | # Install MPI - sudo apt-get install -y -q intel-oneapi-mpi-devel ninja-build cmake + sudo apt-get install -y -q intel-oneapi-mpi-devel ninja-build cmake libcurl4-gnutls-dev source /opt/intel/oneapi/setvars.sh --force - printenv >> $GITHUB_ENV + printenv >> $GITHUB_ENV # To run HDF5 with oneAPI, we need to build it from source. Use CMake to generate pkg-config info curl -O -L https://github.com/HDFGroup/hdf5/archive/refs/tags/snapshot-1.14.tar.gz tar zxf snapshot-1.14.tar.gz @@ -133,6 +137,17 @@ jobs: cd build make -j sudo make install + curl -L https://github.com/Unidata/netcdf-c/archive/refs/tags/v4.9.2.tar.gz -o - | tar xz + cd netcdf-c-4.9.2 + CC=icx CXX=icpx FC=ifx ./configure --prefix=/usr --with-hdf5=/usr + CC=icx CXX=icpx FC=ifx make -j + sudo make install + curl -L https://github.com/Unidata/netcdf-fortran/archive/refs/tags/v4.6.1.tar.gz -o - | tar xz + cd netcdf-fortran-4.6.1 + cmake -B build -DCMAKE_Fortran_COMPILER=ifx -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DCMAKE_INSTALL_PREFIX=/usr + cd build + make -j + sudo make install - name: (Windows) Put MSYS2_MinGW64 on PATH if: contains(matrix.os,'windows') && (!contains(matrix.mpi,'intel')) @@ -214,8 +229,14 @@ jobs: - name: (macOS) Install homebrew HDF5 if: contains(matrix.os,'macos') - run: | - brew install hdf5 + run: | + brew install hdf5 + + - name: (macOS) Install homebrew NetCDF + if: contains(matrix.os,'macos') + run: | + brew install netcdf + brew install netcdf-fortran # Phase 1: Bootstrap fpm with existing version - name: Install fpm diff --git a/ci/meta_tests.sh b/ci/meta_tests.sh index d9749bb511..3d55cf07ac 100755 --- a/ci/meta_tests.sh +++ b/ci/meta_tests.sh @@ -33,17 +33,22 @@ pushd metapackage_minpack popd pushd metapackage_mpi -"$fpm" build --verbose +"$fpm" build --verbose "$fpm" run --verbose popd pushd metapackage_mpi_c -"$fpm" build --verbose +"$fpm" build --verbose "$fpm" run --verbose popd pushd metapackage_hdf5 -"$fpm" build --verbose +"$fpm" build --verbose +"$fpm" run --verbose +popd + +pushd metapackage_netcdf +"$fpm" build --verbose "$fpm" run --verbose popd diff --git a/example_packages/metapackage_netcdf/app/main.f90 b/example_packages/metapackage_netcdf/app/main.f90 new file mode 100644 index 0000000000..6e3a2d11e8 --- /dev/null +++ b/example_packages/metapackage_netcdf/app/main.f90 @@ -0,0 +1,10 @@ +program metapackage_netcdf + use netcdf4_f03 + implicit none + + integer(c_int) :: ncid, retval + + retval = nf_create("dummy.nc", NF_INMEMORY, ncid) + if (retval /= nf_noerr) error stop nf_strerror(retval) + stop 0 +end program metapackage_netcdf diff --git a/example_packages/metapackage_netcdf/fpm.toml b/example_packages/metapackage_netcdf/fpm.toml new file mode 100644 index 0000000000..f5fd4869d7 --- /dev/null +++ b/example_packages/metapackage_netcdf/fpm.toml @@ -0,0 +1,2 @@ +name = "metapackage_netcdf" +dependencies.netcdf="*" diff --git a/src/fpm/manifest/meta.f90 b/src/fpm/manifest/meta.f90 index 41bd113a99..b9f419be38 100644 --- a/src/fpm/manifest/meta.f90 +++ b/src/fpm/manifest/meta.f90 @@ -52,6 +52,9 @@ module fpm_manifest_metapackages !> HDF5 type(metapackage_request_t) :: hdf5 + !> NetCDF + type(metapackage_request_t) :: netcdf + end type metapackage_config_t @@ -203,6 +206,9 @@ subroutine new_meta_config(self, table, meta_allowed, error) call new_meta_request(self%hdf5, "hdf5", table, meta_allowed, error) if (allocated(error)) return + call new_meta_request(self%netcdf, "netcdf", table, meta_allowed, error) + if (allocated(error)) return + end subroutine new_meta_config !> Check local schema for allowed entries @@ -214,7 +220,7 @@ logical function is_meta_package(key) select case (key) !> Supported metapackages - case ("openmp","stdlib","mpi","minpack","hdf5") + case ("openmp","stdlib","mpi","minpack","hdf5","netcdf") is_meta_package = .true. case default diff --git a/src/fpm_meta.f90 b/src/fpm_meta.f90 index 6d5f6a46ce..d52284aecd 100644 --- a/src/fpm_meta.f90 +++ b/src/fpm_meta.f90 @@ -30,6 +30,7 @@ module fpm_meta 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 shlex_module, only: shlex_split => split use regex_module, only: regex @@ -61,6 +62,7 @@ subroutine init_from_name(this,name,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 default call syntax_error(error, "Package "//name//" is not supported in [metapackages]") return @@ -153,6 +155,12 @@ subroutine resolve_metapackage_model(model,package,settings,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 + end subroutine resolve_metapackage_model end module fpm_meta diff --git a/src/metapackage/fpm_meta_netcdf.f90 b/src/metapackage/fpm_meta_netcdf.f90 new file mode 100644 index 0000000000..d28209e383 --- /dev/null +++ b/src/metapackage/fpm_meta_netcdf.f90 @@ -0,0 +1,66 @@ +module fpm_meta_netcdf + use fpm_compiler, only: compiler_t, get_include_flag + use fpm_meta_base, only: metapackage_t, destroy + use fpm_meta_util, only: add_pkg_config_compile_options + use fpm_pkg_config, only: assert_pkg_config, pkgcfg_has_package + use fpm_strings, only: string_t + use fpm_error, only: error_t, fatal_error + + implicit none + + private + + public :: init_netcdf + +contains + + !> Initialize NetCDF metapackage for the current system + subroutine init_netcdf(this, compiler, error) + class(metapackage_t), intent(inout) :: this + type(compiler_t), intent(in) :: compiler + type(error_t), allocatable, intent(out) :: error + + logical :: s + character(len=:), allocatable :: include_flag, libdir + + include_flag = get_include_flag(compiler, "") + + !> Cleanup + call destroy(this) + allocate (this % link_libs(0), this % incl_dirs(0), this % external_modules(0)) + this % link_flags = string_t("") + this % flags = string_t("") + + !> Assert pkg-config is installed + if (.not. assert_pkg_config()) then + call fatal_error(error, 'netcdf metapackage requires pkg-config') + return + end if + + if (.not. pkgcfg_has_package('netcdf')) then + call fatal_error(error, 'pkg-config could not find a suitable netcdf package.') + end if + call add_pkg_config_compile_options(this, 'netcdf', include_flag, libdir, error) + if (allocated(error)) return + + if (.not. pkgcfg_has_package('netcdf-fortran')) then + call fatal_error(error, & + 'pkg-config could not find a suitable netcdf-fortran package.') + end if + call add_pkg_config_compile_options(this, 'netcdf-fortran', include_flag, libdir, error) + if (allocated(error)) return + + !> Add NetCDF modules as external + this % has_external_modules = .true. + this % external_modules = [string_t('netcdf'), & + string_t('netcdf4_f03'), & + string_t('netcdf4_nc_interfaces'), & + string_t('netcdf4_nf_interfaces'), & + string_t('netcdf_f03'), & + string_t('netcdf_fortv2_c_interfaces'), & + string_t('netcdf_nc_data'), & + string_t('netcdf_nc_interfaces'), & + string_t('netcdf_nf_data'), & + string_t('netcdf_nf_interfaces')] + end subroutine init_netcdf +end module fpm_meta_netcdf