diff --git a/.gitignore b/.gitignore index e534738ed7..ccaecbbead 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,19 @@ *.swp *~ html -*.log + + +# Build output +*.o +*.mod MOM6 -build/ -deps/ + + +# Autoconf +aclocal.m4 +autom4te.cache/ +config.log +config.status +configure +/Makefile +Makefile.mkmf diff --git a/.testing/.gitignore b/.testing/.gitignore index 441e73b8e8..488edabfe8 100644 --- a/.testing/.gitignore +++ b/.testing/.gitignore @@ -1,3 +1,6 @@ -config.mk -work/ -results/ +# Test output +/config.mk +/build/ +/work/ +/results/ +/deps/ diff --git a/.testing/Makefile b/.testing/Makefile index f6e0a31b97..6ea2d18370 100644 --- a/.testing/Makefile +++ b/.testing/Makefile @@ -4,36 +4,40 @@ SHELL = bash # User-defined configuration -include config.mk -# Default configurations +# Set the MPI launcher here MPIRUN ?= mpirun -DO_REPRO_TESTS ?= true + +# Default target compiler flags +# NOTE: FMS will be built using FCFLAGS_DEBUG +FCFLAGS_DEBUG ?= -g -O0 +FCFLAGS_REPRO ?= -g -O2 +FCFLAGS_INIT ?= +FCFLAGS_COVERAGE ?= +# Additional notes: +# +# - The default values are simple, minimalist flags, supported by nearly all +# compilers which are comparable to GFDL's canonical DEBUG and REPRO builds. +# +# - These flags should be configured outside of the Makefile, either with +# config.mk or as environment variables. +# +# - FMS cannot be built with the same aggressive initialization flags as MOM6, +# so FCFLAGS_INIT is used to provide additional MOM6 configuration. + +# Set to `true` to require identical results from DEBUG and REPRO builds +DO_REPRO_TESTS ?= + +# Many compilers (Intel, GCC on ARM64) do not yet produce identical results +# across DEBUG and REPRO builds (as defined below), so we disable on default. #--- # Dependencies DEPS = deps # mkmf, list_paths (GFDL build toolchain) -MKMF_URL ?= https://github.com/NOAA-GFDL/mkmf.git -MKMF_COMMIT ?= master -LIST_PATHS := $(abspath $(DEPS)/mkmf/bin/list_paths) -MKMF := $(abspath $(DEPS)/mkmf/bin/mkmf) - -# FMS framework -FMS_URL ?= https://github.com/NOAA-GFDL/FMS.git -FMS_COMMIT ?= 2019.01.03 -FMS := $(DEPS)/fms - -#--- -# Build configuration - -# Build settings -MKMF_CPP = "-Duse_libMPI -Duse_netCDF -DSPMD" +LIST_PATHS := $(DEPS)/bin/list_paths +MKMF := $(DEPS)/bin/mkmf -# Environment -# TODO: This info ought to be determined by CMake, automake, etc. -#MKMF_TEMPLATE ?= linux-ubuntu-xenial-gnu.mk -MKMF_TEMPLATE ?= deps/mkmf/templates/ncrc-gnu.mk -#MKMF_TEMPLATE ?= deps/mkmf/templates/ncrc-intel.mk #--- # Test configuration @@ -78,6 +82,7 @@ else TARGET_CODEBASE = endif + # List of source files to link this Makefile's dependencies to model Makefiles # Assumes a depth of two, and the following extensions: F90 inc c h # (1): Root directory @@ -85,13 +90,15 @@ endif SOURCE = \ $(foreach ext,F90 inc c h,$(wildcard $(1)/*/*.$(ext) $(1)/*/*/*.$(ext))) -MOM_SOURCE = $(call SOURCE,../src) $(wildcard ../config_src/solo_driver/*.F90) \ - $(wildcard ../config_src/ext*/*/*.F90) +MOM_SOURCE = $(call SOURCE,../src) \ + $(wildcard ../config_src/solo_driver/*.F90) \ + $(wildcard ../config_src/ext*/*/*.F90) TARGET_SOURCE = $(call SOURCE,build/target_codebase/src) \ $(wildcard build/target_codebase/config_src/solo_driver/*.F90) \ $(wildcard build/target_codebase/config_src/ext*/*.F90) FMS_SOURCE = $(call SOURCE,$(DEPS)/fms/src) + #--- # Python preprocessing environment configuration @@ -119,93 +126,140 @@ endif # Rules .PHONY: all build.regressions -all: $(foreach b,$(BUILDS),build/$(b)/MOM6) $(VENV_PATH) +all: $(foreach b,$(BUILDS),build/$(b)/MOM6) build.regressions: $(foreach b,symmetric target,build/$(b)/MOM6) # Executable BUILD_TARGETS = MOM6 Makefile path_names .PRECIOUS: $(foreach b,$(BUILDS),$(foreach f,$(BUILD_TARGETS),build/$(b)/$(f))) +# Compiler flags + # Conditionally build symmetric with coverage support -COVFLAG=$(if $(REPORT_COVERAGE),COVERAGE=1,) +COVERAGE=$(if $(REPORT_COVERAGE),"$(FCFLAGS_COVERAGE)",) + +# .testing dependencies +# TODO: We should probably build TARGET with the FMS that it was configured +# to use. But for now we use the same FMS over all builds. +FCFLAGS_FMS = -I../../$(DEPS)/include +LDFLAGS_FMS = -L../../$(DEPS)/lib +PATH_FMS = PATH="${PATH}:../../$(DEPS)/bin" + + +# Define the build targets in terms of the traditional DEBUG/REPRO/etc labels +SYMMETRIC_FCFLAGS := FCFLAGS="$(FCFLAGS_DEBUG) $(FCFLAGS_INIT) $(COVERAGE) $(FCFLAGS_FMS)" +ASYMMETRIC_FCFLAGS := FCFLAGS="$(FCFLAGS_DEBUG) $(FCFLAGS_INIT) $(FCFLAGS_FMS)" +REPRO_FCFLAGS := FCFLAGS="$(FCFLAGS_REPRO) $(FCFLAGS_FMS)" +OPENMP_FCFLAGS := FCFLAGS="$(FCFLAGS_DEBUG) $(FCFLAGS_INIT) $(FCFLAGS_FMS)" +TARGET_FCFLAGS := FCFLAGS="$(FCFLAGS_DEBUG) $(FCFLAGS_INIT) $(FCFLAGS_FMS)" + +MOM_LDFLAGS := LDFLAGS="$(LDFLAGS_FMS)" +SYMMETRIC_LDFLAGS := LDFLAGS="$(COVERAGE) $(LDFLAGS_FMS)" + + +# Environment variable configuration +build/symmetric/Makefile: MOM_ENV=$(PATH_FMS) $(SYMMETRIC_FCFLAGS) $(SYMMETRIC_LDFLAGS) +build/asymmetric/Makefile: MOM_ENV=$(PATH_FMS) $(ASYMMETRIC_FCFLAGS) $(MOM_LDFLAGS) +build/repro/Makefile: MOM_ENV=$(PATH_FMS) $(REPRO_FCFLAGS) $(MOM_LDFLAGS) +build/openmp/Makefile: MOM_ENV=$(PATH_FMS) $(OPENMP_FCFLAGS) $(MOM_LDFLAGS) +build/target/Makefile: MOM_ENV=$(PATH_FMS) $(TARGET_FCFLAGS) $(MOM_LDFLAGS) + + +# Configure script flags +build/symmetric/Makefile: MOM_ACFLAGS= +build/asymmetric/Makefile: MOM_ACFLAGS=--enable-asymmetric +build/repro/Makefile: MOM_ACFLAGS= +build/openmp/Makefile: MOM_ACFLAGS=--enable-openmp +build/target/Makefile: MOM_ACFLAGS= + + +# Fetch regression target source code +build/target/Makefile: | $(TARGET_CODEBASE) -build/target/MOM6: MOMFLAGS=NETCDF=3 DEBUG=1 INIT=1 -build/symmetric/MOM6: MOMFLAGS=NETCDF=3 DEBUG=1 INIT=1 $(COVFLAG) -build/asymmetric/MOM6: MOMFLAGS=NETCDF=3 DEBUG=1 INIT=1 -build/repro/MOM6: MOMFLAGS=NETCDF=3 REPRO=1 -build/openmp/MOM6: MOMFLAGS=NETCDF=3 DEBUG=1 OPENMP=1 INIT=1 -build/asymmetric/path_names: GRID_SRC=config_src/dynamic -build/%/path_names: GRID_SRC=config_src/dynamic_symmetric +# Define source code dependencies +# NOTE: ./configure is too much, but Makefile is not enough! +# Ideally we would want to re-run both Makefile and mkmf, but our mkmf call +# is inside ./configure, so we must re-run ./configure as well. +$(foreach b,$(filter-out target,$(BUILDS)),build/$(b)/Makefile): $(MOM_SOURCE) +build/target/configure: $(TARGET_SOURCE) -build/%/MOM6: build/%/Makefile $(FMS)/lib/libfms.a - $(MAKE) -C $(@D) $(MOMFLAGS) $(@F) -build/%/Makefile: build/%/path_names - cp $(MKMF_TEMPLATE) $(@D) - cd $(@D) && $(MKMF) \ - -t $(notdir $(MKMF_TEMPLATE)) \ - -o '-I ../../$(DEPS)/fms/build' \ - -p MOM6 \ - -l '../../$(DEPS)/fms/lib/libfms.a' \ - -c $(MKMF_CPP) \ - path_names +# Build MOM6 +.PRECIOUS: $(foreach b,$(BUILDS),build/$(b)/MOM6) +build/%/MOM6: build/%/Makefile + cd $(@D) && time $(MAKE) -j -# NOTE: These path_names rules could be merged -build/target/path_names: $(LIST_PATHS) $(TARGET_CODEBASE) $(TARGET_SOURCE) +# Use autoconf to construct the Makefile for each target +.PRECIOUS: $(foreach b,$(BUILDS),build/$(b)/Makefile) +build/%/Makefile: ../ac/configure ../ac/Makefile.in $(DEPS)/lib/libFMS.a $(MKMF) $(LIST_PATHS) mkdir -p $(@D) - cd $(@D) && $(LIST_PATHS) -l \ - ../../$(TARGET_CODEBASE)/src \ - ../../$(TARGET_CODEBASE)/config_src/solo_driver \ - ../../$(TARGET_CODEBASE)/config_src/ext* \ - ../../$(TARGET_CODEBASE)/$(GRID_SRC) + cd $(@D) \ + && $(MOM_ENV) ../../../ac/configure $(MOM_ACFLAGS) \ + || (cat config.log && false) + + +../ac/configure: ../ac/configure.ac ../ac/m4 + autoreconf -i $< -build/%/path_names: $(LIST_PATHS) $(MOM_SOURCE) + +# Fetch the regression target codebase +build/target/Makefile: $(TARGET_CODEBASE)/ac/configure $(DEPS)/lib/libFMS.a $(MKMF) $(LIST_PATHS) mkdir -p $(@D) - cd $(@D) && $(LIST_PATHS) -l \ - ../../../src \ - ../../../config_src/solo_driver \ - ../../../config_src/ext* \ - ../../../$(GRID_SRC) + cd $(@D) \ + && $(MOM_ENV) ../../$(TARGET_CODEBASE)/ac/configure $(MOM_ACFLAGS) \ + || (cat config.log && false) + + +$(TARGET_CODEBASE)/ac/configure: $(TARGET_CODEBASE) + autoreconf -i $ $$(@D)/MOM_override cd $$(@D) \ - && $(5) $(MPIRUN) -n $(6) ../../../$$< 2> std.err > std.out \ + && time $(5) $(MPIRUN) -n $(6) ../../../$$< 2> std.err > std.out \ || !( \ mkdir -p ../../../results/$$*/ ; \ cat std.out | tee ../../../results/$$*/std.$(1).out | tail -20 ; \ @@ -367,7 +422,8 @@ work/%/$(1)/ocean.stats work/%/$(1)/chksum_diag: build/$(2)/MOM6 mkdir -p results/$$* ; \ bash <(curl -s https://codecov.io/bash) -n $$@ \ > work/$$*/codecov.$(1).out \ - 2> work/$$*/codecov.$(1).err ; \ + 2> work/$$*/codecov.$(1).err \ + && echo -e "${MAGENTA}Report uploaded to codecov.${RESET}"; \ fi endef @@ -392,10 +448,10 @@ $(eval $(call STAT_RULE,dim.r,symmetric,,R_RESCALE_POWER=11,,1)) # Restart tests require significant preprocessing, and are handled separately. -work/%/restart/ocean.stats: build/symmetric/MOM6 +work/%/restart/ocean.stats: build/symmetric/MOM6 $(VENV_PATH) rm -rf $(@D) mkdir -p $(@D) - cp -rL $*/* $(@D) + cp -RL $*/* $(@D) if [ -f $(@D)/Makefile ]; then \ $(VENV_ACTIVATE) \ && cd work/$*/restart \ @@ -414,7 +470,7 @@ work/%/restart/ocean.stats: build/symmetric/MOM6 && halfperiod=$$(printf "%.f" $$(bc <<< "scale=10; 0.5 * $${daymax} * $${timeunit_int}")) \ && printf "\n&ocean_solo_nml\n seconds = $${halfperiod}\n/\n" >> input.nml # Run the first half-period - cd $(@D) && $(MPIRUN) -n 1 ../../../$< 2> std1.err > std1.out \ + cd $(@D) && time $(MPIRUN) -n 1 ../../../$< 2> std1.err > std1.out \ || !( \ cat std1.out | tee ../../../results/$*/std.restart1.out | tail ; \ cat std1.err | tee ../../../results/$*/std.restart1.err | tail ; \ @@ -425,7 +481,7 @@ work/%/restart/ocean.stats: build/symmetric/MOM6 mkdir $(@D)/RESTART cd $(@D) && sed -i -e "s/input_filename *= *'n'/input_filename = 'r'/g" input.nml # Run the second half-period - cd $(@D) && $(MPIRUN) -n 1 ../../../$< 2> std2.err > std2.out \ + cd $(@D) && time $(MPIRUN) -n 1 ../../../$< 2> std2.err > std2.out \ || !( \ cat std2.out | tee ../../../results/$*/std.restart2.out | tail ; \ cat std2.err | tee ../../../results/$*/std.restart2.err | tail ; \ @@ -469,6 +525,7 @@ clean: clean.stats @[ $$(basename $$(pwd)) = .testing ] rm -rf build + .PHONY: clean.stats clean.stats: @[ $$(basename $$(pwd)) = .testing ] diff --git a/.testing/README.md b/.testing/README.md index abad08ada8..adc56e56cd 100644 --- a/.testing/README.md +++ b/.testing/README.md @@ -2,30 +2,41 @@ This directory contains the Makefile and test configurations used to evaluate submissions to the MOM6 codebase. The tests are designed to run either locally -or in a Travis-CI. +or in a CI environment such as Travis. ## Overview This section gives a very brief overview of the test suite and how to use it. -To build and run the model tests +To build and run the model tests: ``` -make -make test +make -j +make -j test ``` +For new users, the default configuration should be suitable for most platforms. +If not, then the following options may need to be configured. + +`MPIRUN` (*default:* `mpirun`) + + Name of the MPI launcher. Often this is `mpirun` or `mpiexec` but may all + need to run through a scheduler, e.g. `srun` if using Slurm. + +`DO_REGRESSION_TESTS` (*default: none*) + + Set to `true` to compare output with `dev/gfdl`. + +`DO_REPRO_TESTS` (*default: none*) + + Set to `true` to compare DEBUG and REPRO builds, which typically correspond + to unoptimized and optimized builds. See TODO for more information. -Regression testing is disabled on default. To include regression tests: +These settings can either be specified at the command line, as shown below ``` make DO_REGRESSION_TESTS=true make test DO_REGRESSION_TESTS=true ``` - -On platforms other than Gaea, a MKMF build template may be required. To -specify the path to the template: -``` -make MKMF_TEMPLATE=/path/to/template.mk -``` +or saved in a configuration file, `config.mk`. To run individual classes of tests, use the subclass name: ``` @@ -33,11 +44,11 @@ make test.grids make test.layouts make DO_REGRESSION_TESTS=true test.regressions ``` - To test an individual test configuration (TC): ``` make tc0.grid ``` +See "Tests" and "Test Configurations" for the complete list of tests. The rest of the document describes the test suite in more detail, including names and descriptions of the test classes and configurations. @@ -45,20 +56,85 @@ names and descriptions of the test classes and configurations. ## Testing overview -The test suite consists of many comparisons of model output for different model -configurations when subjected to relevant numerical and mathematical -transformations, such as grid layout or dimensional rescaling, for which the -model output should be invariant. If the model state is unchanged after each -transformation, then the test is reported as passing. Any discrepancy in the -model state causes the test to fail. +The test suite checks for numerical consistency of the model output across +different model configurations when subjected to relevant numerical and +mathematical transformations, such as grid layout or dimensional rescaling. If +the model state is unchanged after each transformation, then the test is +reported as passing. Any discrepancy in the model state causes the test to +fail. Model state is currently defined by the `ocean.stats` output file, which reports the total energy (per unit mass) at machine precision alongside similar -global metrics, such as mass or mean sea level, at lower precision. +global metrics at lower precision, such as mass or mean sea level. + +Diagnostics are based on the MOM checksum function, which includes the mean, +minimum, and maximum values, alongside a bitcount checksum, in the physical +domain, which are saved in the `chksum_diag` output file. + + +## Build configuration -Checksums for every available diagnostic are also compared and the Makefile -will report any differences, but such differences are not yet considered a fail -condition. +The test suite defines a DEBUG and a REPRO build, which resemble targets used +at GFDL. The DEBUG build is intended for detecting potential errors and +troubleshooting, while the REPRO build has typically been optimized for +production runs. + +Ideally, the DEBUG and REPRO runs will produce identical results, although this +is often not the case for many compilers and platforms. The `DO_REPRO_TEST` +flag is used to test DEBUG/REPRO equivalency. + +The following options are provided to configure your compiler flags. + +`FCFLAGS_DEBUG` (*default:* `-g -O0`) + + Specify the flags used in the DEBUG build. These are the flags used for all + tests excepting the REPRO builds. They are also used to build the FMS + library. + + These should be used to enable settings favorable to debugging, such as no + optimizations, backtraces, range checking, and warnings. + + For more aggressive debugging flags which cannot be used with FMS, see + `FCFLAGS_INIT`. + +`FCFLAGS_REPRO:` (*default:* `-g -O2`) + + Specify the optimized reproducible run, typically used in production runs. + + Ideally, this should consist of optimization flags which improve peformance + but do not change model output. In practice, this is difficult to achieve, + and should only used in certain environments. + +`FCFLAGS_INIT` (*default: none*) + + This flag was historically used to specify variable initialization, such as + nonzero integers or floating point values, and is still generally used for + this purpose. + + As implemented, it is used for all MOM6 builds. It is not used for FMS + builds, so can also act as a debugging flag independent of FMS. + +`FCFLAGS_COVERAGE` (*default: none*) + + This flag is used to define a build which supports some sort of code + coverage, often one which is handled by the CI. + + For many compilers, this is set to `--coverage`, and is applied to both the + compiler (`FCFLAGS`) and linker (`LDFLAGS`). + +Example values used by GFDL and Travis for the GFortran compiler are shown +below. +``` +FCFLAGS_DEBUG="-g -O0 -Wextra -Wno-compare-reals -fbacktrace -ffpe-trap=invalid,zero,overflow -fcheck=bounds" +FCFLAGS_REPRO="-g -O2 -fbacktrace" +FCFLAGS_INIT="-finit-real=snan -finit-integer=2147483647 -finit-derived" +FCFLAGS_COVERAGE="--coverage" +``` + +Note that the default values for these flags are very minimal, in order to +ensure compatibility over the largest possible range of compilers. + +Like all configuration variables, these can be specified in a `config.mk` file. ## Building the executables @@ -71,66 +147,57 @@ This will fetch the MKMF build toolchain, fetch and compile the FMS framework library, and compile the executables used in the test suite. The default configuration uses the symmetric grid in the debug-compile mode, with optimizations disabled and stronger quality controls. The following -executables will be created: +executables will be created. -- `build/symmetric/MOM6`: Symmetric grid configuration (extended grids along - western and/or southern boundaries). This is the default configuration. +- `build/symmetric/MOM6`: Symmetric grid configuration (i.e. extended grids + along western and/or southern boundaries for selected fields). This is the + default configuration. - `build/asymmetric/MOM6`: Non-symmetric grid (equal-sized grids) - `build/repro/MOM6`: Optimized reproducible mode -- (optional) `build/target/MOM6`: A reference build for regression testing +- `build/target/MOM6`: A reference build for regression testing -The `target` build is only created when the `DO_REGRESSION_TESTS` flag is set -to `true`: -``` -make DO_REGRESSION_TESTS=true -``` -When set, the build will check out a second copy of the repository from a -specified URL and branch given by `MOM_TARGET_URL` and `MOM_TARGET_BRANCH`, -respectively. The code is checked out into the `TARGET_CODEBASE` directory. +- `build/openmp/MOM6`: OpenMP-enabled build -The current default settings are +The `target` and `repro` builds are only created when their respective tests +are set to `true`. + + +### Regression testing + +When regression tests are enabled, the Makefile will check out a second copy of +the repository from a specified URL and branch given by `MOM_TARGET_URL` and +`MOM_TARGET_BRANCH`, respectively. The code is checked out into the +`TARGET_CODEBASE` directory. + +The default settings, with resolved values as comments, are shown below. ``` MOM_TARGET_SLUG = NOAA-GFDL/MOM6 MOM_TARGET_URL = https://github.com/$(MOM_TARGET_SLUG) -# = https://github.com/NOAA-GFDL/MOM6 + #= https://github.com/NOAA-GFDL/MOM6 MOM_TARGET_LOCAL_BRANCH = dev/gfdl MOM_TARGET_BRANCH = origin/$(MOM_TARGET_LOCAL_BRANCH) -# = origin/dev/gfdl + #= origin/dev/gfdl TARGET_CODEBASE = $(BUILD)/target_codebase ``` These default values can be configured to target a particular development branch. +Currently the target can only be specifed by branch name, rather than hash. -#### MKMF template - -The MKMF build toolchain requires a template file when building the model. The -default template, `ncrc-gnu.mk`, is part of the MKMF repository, but has been -specifically configured for use on NOAA's Gaea computer, and other institutes -will require their own template files. - -The template can be specified as a Make flag. -``` -make MKMF_TEMPLATE=/path/to/template.mk -``` -The `linux-ubuntu-xenial-gnu.mk` template is provided in the `.testing` -directory, and is intended for Travis-CI builds, but may also be a good -reference point for other Linux distributions. - -In the future, this step may be replaced with a more generalized build system, -such as CMake or automake. +New diagnostics do not report as a fail, and are not tracked by any CIs, but +the test will report a warning to the user. ## Tests -Using `test` will run through the test suite. +Using `test` will run through the full test suite. ``` make test ``` -This will run through the following tests: +The tests are gathered into the following groups. - `test.regressions`: Regression tests relative to a code state (when enabled) - `test.grids`: Symmetric vs nonsymmetric grids @@ -140,13 +207,8 @@ This will run through the following tests: - `test.nans`: NaN initialization of allocated arrays - `test.dims`: Dimensional scaling (length, time, thickness, depth) -To enable the regression tests, use `DO_REGRESSION_TEST=true`. -``` -make test DO_REGRESSION_TESTS=true -``` - -Each test can also be run individually. For example, the following command -will only run the grid tests. +Each group of tests can also be run individually, such as in the following +example. ``` make test.grids ``` @@ -157,26 +219,27 @@ fail if the answers differ from this build. ## Test configurations -The following test configurations (TCs) are supported: +The following model test configurations (TCs) are supported, and are based on +configurations in the MOM6-examples repository. -- tc0: Unit testing of various model components, based on `unit_tests` -- tc1: A low-resolution version of the `benchmark` configuration - - tc1.a: Use the un-split mode with Runge-Kutta 3 time integration - - tc1.b: Use the un-split mode with Runge-Kutta 2 time integration -- tc2: An ALE configuration based on tc1 with tides - - tc2.a: Use sigma, PPM_H4 and no tides -- tc3: An open-boundary condition (OBC) test based on `circle_obcs` +- `tc0`: Unit testing of various model components, based on `unit_tests` +- `tc1`: A low-resolution version of the `benchmark` configuration + - `tc1.a`: Use the un-split mode with Runge-Kutta 3 time integration + - `tc1.b`: Use the un-split mode with Runge-Kutta 2 time integration +- `tc2`: An ALE configuration based on tc1 with tides + - `tc2.a`: Use sigma, PPM_H4 and no tides +- `tc3`: An open-boundary condition (OBC) test based on `circle_obcs` ## Code coverage -Code coverage reports the lines of code which have been tested, and can -explicitly demonstrate when a particular operation is untested. +Code coverage reports the lines of code which have been tested, and can be used +to determine if a particular section is untested. Coverage is measured using `gcov` and is reported for TCs using the `symmetric` executable. -Coverage reporting is optionally sent to the `codecov.io` site. +Coverage reporting is optionally uploaded to the `codecov.io` site. ``` https://codecov.io/gh/NOAA-GFDL/MOM6 ``` @@ -184,7 +247,7 @@ This is disabled on default, but can be enabled by the `REPORT_COVERAGE` flag. ``` make test REPORT_COVERAGE=true ``` -Note that any uploads will require a valid token generated by CodeCov. +Note that any uploads will require a valid CodeCov token. ## Running on Travis @@ -194,6 +257,8 @@ suite is triggered and the code changes are tested. When the tests are run on Travis, the following variables are re-defined: +- `DO_REPRO_TESTS` is set to `true` for all tests. + - `DO_REGRESSION_TESTS` is set to `true` for a PR submission, and is unset for code pushes. @@ -209,18 +274,3 @@ When the tests are run on Travis, the following variables are re-defined: a PR, this is the name of the branch which is receiving the PR. - `REPORT_COVERAGE` is set to `true`. - -## Running under slurm - -By default the executables are invoked using `mpirun`. Under slurm you might need to -use `srun` (such as on GFDL's gaea HPC): -``` -make MPIRUN=srun test -``` - -For convenience you can provide some macro in the file `config.mk`. For example, on -gaea, to be able to run `make test -s -j` you will find putting the line -``` -MPIRUN = srun -mblock --exclusive -``` -in `config.mk` very useful. diff --git a/.testing/linux-ubuntu-xenial-gnu.mk b/.testing/linux-ubuntu-xenial-gnu.mk deleted file mode 100644 index 04ba952408..0000000000 --- a/.testing/linux-ubuntu-xenial-gnu.mk +++ /dev/null @@ -1,279 +0,0 @@ -# Template for the GNU Compiler Collection on Xenial version of Ubuntu Linux systems (used by Travis-CI) -# -# Typical use with mkmf -# mkmf -t linux-ubuntu-xenial-gnu.mk -c"-Duse_libMPI -Duse_netCDF" path_names /usr/local/include - -############ -# Commands Macors -FC = mpif90 -CC = mpicc -LD = mpif90 $(MAIN_PROGRAM) - -####################### -# Build target macros -# -# Macros that modify compiler flags used in the build. Target -# macrose are usually set on the call to make: -# -# make REPRO=on NETCDF=3 -# -# Most target macros are activated when their value is non-blank. -# Some have a single value that is checked. Others will use the -# value of the macro in the compile command. - -DEBUG = # If non-blank, perform a debug build (Cannot be - # mixed with REPRO or TEST) - -REPRO = # If non-blank, perform a build that guarentees - # reprodicuibilty from run to run. Cannot be used - # with DEBUG or TEST - -TEST = # If non-blank, use the compiler options defined in - # the FFLAGS_TEST and CFLAGS_TEST macros. Cannot be - # use with REPRO or DEBUG - -VERBOSE = # If non-blank, add additional verbosity compiler - # options - -OPENMP = # If non-blank, compile with openmp enabled - -NO_OVERRIDE_LIMITS = # If non-blank, do not use the -qoverride-limits - # compiler option. Default behavior is to compile - # with -qoverride-limits. - -NETCDF = # If value is '3' and CPPDEFS contains - # '-Duse_netCDF', then the additional cpp macro - # '-Duse_LARGEFILE' is added to the CPPDEFS macro. - -INCLUDES = # A list of -I Include directories to be added to the - # the compile command. - -SSE = # The SSE options to be used to compile. If blank, - # than use the default SSE settings for the host. - # Current default is to use SSE2. - -COVERAGE = # Add the code coverage compile options. - -INIT = # Enable aggressive initialization - -# Need to use at least GNU Make version 3.81 -need := 3.81 -ok := $(filter $(need),$(firstword $(sort $(MAKE_VERSION) $(need)))) -ifneq ($(need),$(ok)) -$(error Need at least make version $(need). Load module gmake/3.81) -endif - -# REPRO, DEBUG and TEST need to be mutually exclusive of each other. -# Make sure the user hasn't supplied two at the same time -ifdef REPRO -ifneq ($(DEBUG),) -$(error Options REPRO and DEBUG cannot be used together) -else ifneq ($(TEST),) -$(error Options REPRO and TEST cannot be used together) -endif -else ifdef DEBUG -ifneq ($(TEST),) -$(error Options DEBUG and TEST cannot be used together) -endif -endif - -MAKEFLAGS += --jobs=$(shell grep '^processor' /proc/cpuinfo | wc -l) - -# Macro for Fortran preprocessor -FPPFLAGS := $(INCLUDES) -# Fortran Compiler flags for the NetCDF library -FPPFLAGS += $(shell nf-config --fflags) - -# Base set of Fortran compiler flags -FFLAGS := -fcray-pointer -fdefault-double-8 -fdefault-real-8 -Waliasing -ffree-line-length-none -fno-range-check - -# Flags based on perforance target (production (OPT), reproduction (REPRO), or debug (DEBUG) -FFLAGS_OPT = -O3 -FFLAGS_REPRO = -O2 -fbounds-check -FFLAGS_DEBUG = -O0 -g -W -Wno-compare-reals -fbounds-check -fbacktrace -ffpe-trap=invalid,zero,overflow -# Enable aggressive initialization -ifdef INIT -FFLAGS_DEBUG += -finit-real=snan -finit-integer=2147483647 -finit-derived -endif - -# Flags to add additional build options -FFLAGS_OPENMP = -fopenmp -FFLAGS_VERBOSE = -FFLAGS_COVERAGE = --coverage - -# Macro for C preprocessor -CPPFLAGS = $(INCLUDES) -# C Compiler flags for the NetCDF library -CPPFLAGS += $(shell nf-config --cflags) - -# Base set of C compiler flags -CFLAGS := -D__IFC - -# Flags based on perforance target (production (OPT), reproduction (REPRO), or debug (DEBUG) -CFLAGS_OPT = -O2 -CFLAGS_REPRO = -O2 -CFLAGS_DEBUG = -O0 -g - -# Flags to add additional build options -CFLAGS_OPENMP = -fopenmp -CFLAGS_VERBOSE = -CFLAGS_COVERAGE = --coverage - -# Optional Testing compile flags. Mutually exclusive from DEBUG, REPRO, and OPT -# *_TEST will match the production if no new option(s) is(are) to be tested. -FFLAGS_TEST = $(FFLAGS_OPT) -CFLAGS_TEST = $(CFLAGS_OPT) - -# Linking flags -LDFLAGS := -LDFLAGS_OPENMP := -fopenmp -LDFLAGS_VERBOSE := -LDFLAGS_COVERAGE := --coverage - -# Start with a blank LIBS -LIBS = -# NetCDF library flags -LIBS += $(shell nf-config --flibs) - -# Get compile flags based on target macros. -ifdef REPRO -CFLAGS += $(CFLAGS_REPRO) -FFLAGS += $(FFLAGS_REPRO) -else ifdef DEBUG -CFLAGS += $(CFLAGS_DEBUG) -FFLAGS += $(FFLAGS_DEBUG) -else ifdef TEST -CFLAGS += $(CFLAGS_TEST) -FFLAGS += $(FFLAGS_TEST) -else -CFLAGS += $(CFLAGS_OPT) -FFLAGS += $(FFLAGS_OPT) -endif - -ifdef OPENMP -CFLAGS += $(CFLAGS_OPENMP) -FFLAGS += $(FFLAGS_OPENMP) -LDFLAGS += $(LDFLAGS_OPENMP) -endif - -ifdef SSE -CFLAGS += $(SSE) -FFLAGS += $(SSE) -endif - -ifdef NO_OVERRIDE_LIMITS -FFLAGS += $(FFLAGS_OVERRIDE_LIMITS) -endif - -ifdef VERBOSE -CFLAGS += $(CFLAGS_VERBOSE) -FFLAGS += $(FFLAGS_VERBOSE) -LDFLAGS += $(LDFLAGS_VERBOSE) -endif - -ifeq ($(NETCDF),3) - # add the use_LARGEFILE cppdef - ifneq ($(findstring -Duse_netCDF,$(CPPDEFS)),) - CPPDEFS += -Duse_LARGEFILE - endif -endif - -ifdef COVERAGE -ifdef BUILDROOT -PROF_DIR=-prof-dir=$(BUILDROOT) -endif -CFLAGS += $(CFLAGS_COVERAGE) $(PROF_DIR) -FFLAGS += $(FFLAGS_COVERAGE) $(PROF_DIR) -LDFLAGS += $(LDFLAGS_COVERAGE) $(PROF_DIR) -endif - -LDFLAGS += $(LIBS) - -#--------------------------------------------------------------------------- -# you should never need to change any lines below. - -# see the MIPSPro F90 manual for more details on some of the file extensions -# discussed here. -# this makefile template recognizes fortran sourcefiles with extensions -# .f, .f90, .F, .F90. Given a sourcefile ., where is one of -# the above, this provides a number of default actions: - -# make .opt create an optimization report -# make .o create an object file -# make .s create an assembly listing -# make .x create an executable file, assuming standalone -# source -# make .i create a preprocessed file (for .F) -# make .i90 create a preprocessed file (for .F90) - -# The macro TMPFILES is provided to slate files like the above for removal. - -RM = rm -f -TMPFILES = .*.m *.B *.L *.i *.i90 *.l *.s *.mod *.opt - -.SUFFIXES: .F .F90 .H .L .T .f .f90 .h .i .i90 .l .o .s .opt .x - -.f.L: - $(FC) $(FFLAGS) -c -listing $*.f -.f.opt: - $(FC) $(FFLAGS) -c -opt_report_level max -opt_report_phase all -opt_report_file $*.opt $*.f -.f.l: - $(FC) $(FFLAGS) -c $(LIST) $*.f -.f.T: - $(FC) $(FFLAGS) -c -cif $*.f -.f.o: - $(FC) $(FFLAGS) -c $*.f -.f.s: - $(FC) $(FFLAGS) -S $*.f -.f.x: - $(FC) $(FFLAGS) -o $*.x $*.f *.o $(LDFLAGS) -.f90.L: - $(FC) $(FFLAGS) -c -listing $*.f90 -.f90.opt: - $(FC) $(FFLAGS) -c -opt_report_level max -opt_report_phase all -opt_report_file $*.opt $*.f90 -.f90.l: - $(FC) $(FFLAGS) -c $(LIST) $*.f90 -.f90.T: - $(FC) $(FFLAGS) -c -cif $*.f90 -.f90.o: - $(FC) $(FFLAGS) -c $*.f90 -.f90.s: - $(FC) $(FFLAGS) -c -S $*.f90 -.f90.x: - $(FC) $(FFLAGS) -o $*.x $*.f90 *.o $(LDFLAGS) -.F.L: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c -listing $*.F -.F.opt: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c -opt_report_level max -opt_report_phase all -opt_report_file $*.opt $*.F -.F.l: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c $(LIST) $*.F -.F.T: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c -cif $*.F -.F.f: - $(FC) $(CPPDEFS) $(FPPFLAGS) -EP $*.F > $*.f -.F.i: - $(FC) $(CPPDEFS) $(FPPFLAGS) -P $*.F -.F.o: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c $*.F -.F.s: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c -S $*.F -.F.x: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -o $*.x $*.F *.o $(LDFLAGS) -.F90.L: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c -listing $*.F90 -.F90.opt: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c -opt_report_level max -opt_report_phase all -opt_report_file $*.opt $*.F90 -.F90.l: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c $(LIST) $*.F90 -.F90.T: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c -cif $*.F90 -.F90.f90: - $(FC) $(CPPDEFS) $(FPPFLAGS) -EP $*.F90 > $*.f90 -.F90.i90: - $(FC) $(CPPDEFS) $(FPPFLAGS) -P $*.F90 -.F90.o: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c $*.F90 -.F90.s: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -c -S $*.F90 -.F90.x: - $(FC) $(CPPDEFS) $(FPPFLAGS) $(FFLAGS) -o $*.x $*.F90 *.o $(LDFLAGS) diff --git a/.travis.yml b/.travis.yml index 03bdff31dc..22c497f916 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,16 @@ addons: - python3 python3-dev python3-venv python3-pip - bc +# Environment variables +env: + global: + - TIMEFORMAT: "\"Time: %lR (user: %lU, sys: %lS)\"" + - FCFLAGS_DEBUG: "\"-g -O0 -Wextra -Wno-compare-reals -fbacktrace -ffpe-trap=invalid,zero,overflow -fcheck=bounds\"" + - FCFLAGS_REPRO: "\"-g -O2 -fbacktrace\"" + - FCFLAGS_INIT: "\"-finit-real=snan -finit-integer=2147483647 -finit-derived\"" + - FCFLAGS_COVERAGE: "\"--coverage\"" + - DO_REPRO_TESTS: true + jobs: include: - env: JOB="Code compliance" @@ -29,15 +39,14 @@ jobs: - test ! -s doxy_errors - env: - - JOB="x86 Configuration testing" + - JOB="x86 verification testing" - DO_REGRESSION_TESTS=false - - MKMF_TEMPLATE=linux-ubuntu-xenial-gnu.mk script: - cd .testing - echo 'Build executables...' && echo -en 'travis_fold:start:script.1\\r' - - make all + - time make all - echo -en 'travis_fold:end:script.1\\r' - - make -k -s test + - time make -k -s test - make test.summary # NOTE: Code coverage upload is here to reduce load imbalance @@ -48,15 +57,14 @@ jobs: - JOB="x86 Regression testing" - DO_REGRESSION_TESTS=true - REPORT_COVERAGE=true - - MKMF_TEMPLATE=linux-ubuntu-xenial-gnu.mk - MOM_TARGET_SLUG=${TRAVIS_REPO_SLUG} - MOM_TARGET_LOCAL_BRANCH=${TRAVIS_BRANCH} script: - cd .testing - echo 'Build executables...' && echo -en 'travis_fold:start:script.1\\r' - - make build.regressions + - time make build.regressions - echo -en 'travis_fold:end:script.1\\r' - - make -k -s test.regressions + - time make -k -s test.regressions - make test.summary - if: NOT type = pull_request @@ -64,7 +72,6 @@ jobs: - JOB="Coverage upload" - REPORT_COVERAGE=true - DO_REGRESSION_TESTS=false - - MKMF_TEMPLATE=linux-ubuntu-xenial-gnu.mk script: - cd .testing - echo 'Build executables...' && echo -en 'travis_fold:start:script.1\\r' @@ -74,14 +81,13 @@ jobs: - arch: arm64 env: - - JOB="ARM64 Configuration testing" + - JOB="ARM64 verification testing" - DO_REGRESSION_TESTS=false - DO_REPRO_TESTS=false - - MKMF_TEMPLATE=linux-ubuntu-xenial-gnu.mk script: - cd .testing - echo 'Build executables...' && echo -en 'travis_fold:start:script.1\\r' - - make all + - time make all - echo -en 'travis_fold:end:script.1\\r' - - make -k -s test + - time make -k -s test - make test.summary diff --git a/README.md b/README.md index 3e4ff016e3..17cf0310db 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,14 @@ This is the MOM6 source code. + # Where to find information Start at the [MOM6-examples wiki](https://github.com/NOAA-GFDL/MOM6-examples/wiki) which has installation instructions. [Source code documentation](http://mom6.readthedocs.io/) is hosted on read the docs. + # What files are what The top level directory structure groups source code and input files as follow: @@ -23,7 +25,19 @@ The top level directory structure groups source code and input files as follow: | ```src/``` | Contains the source code for MOM6 that is always compiled. | | ```config_src/``` | Contains optional source code depending on mode and configuration such as dynamic-memory versus static, ocean-only versus coupled. | | ```pkg/``` | Contains third party (non-MOM6 or FMS) code that is compiled into MOM6. | -| ```docs/``` | Workspace for generated documentation. | +| ```docs/``` | Workspace for generated documentation. See [docs/README.md](docs/README.md) | +| ```.testing/``` | Contains the verification test suite. See [.testing/README.md](testing/README.md) | +| ```ac/``` | Contains the autoconf build configuration files. See [ac/README.md](ac/README.md) | + + +# Quick start guide + +To quickly get started and build an ocean-only MOM6 executable, see the +[autoconf README](ac/README.md). + +For setting up an experiment, or building an executable for coupled modeling, +consult the [MOM6-examples wiki](https://github.com/NOAA-GFDL/MOM6-examples/wiki). + # Disclaimer diff --git a/ac/Makefile.in b/ac/Makefile.in new file mode 100644 index 0000000000..ce8173e6f1 --- /dev/null +++ b/ac/Makefile.in @@ -0,0 +1,78 @@ +# Makefile template for MOM6 +# +# Compiler flags are configured by autoconf's configure script. +# +# Source code dependencies are configured by mkmf and list_paths, specified in +# the `Makefile.mkmf` file. +# +# mkmf conventions are close, but not identical, to autoconf. We attempt to +# map the autoconf variables to the mkmf variables. +# +# The following variables are used by Makefiles generated by mkmf. +# +# CC: C compiler +# CXX: C++ compiler +# FC: Fortran compiler (f77 and f90) +# LD: Linker +# +# CPPDEFS: Preprocessor macros +# CPPFLAGS: C preprocessing flags +# CXXFLAGS: C++ preprocessing flags +# FPPFLAGS: Fortran preprocessing flags +# +# CFLAGS: C compiler flags +# FFLAGS: Fortran compiler flags +# LDFLAGS: Linker flags + libraries +# +# NOTES: +# - FPPFLAGS and FFLAGS always appear as a pair, and autoconf does not use +# FPPFLAGS, so FPPFLAGS does not serve much purpose. +# +# - mkmf's FFLAGS does not distinguish between autoconf's fixed-format +# FFLAGS and free-format FCFLAGS. +# +# - LDFLAGS does not distinguish between autoconf's LDFLAGS and LIBS. +# It also places both after the executable rather than just LIBS. +# +# OTHERFLAGS: Additional flags for all languages (C, C++, Fortran) +# OTHER_CFLAGS: Optional C flags +# OTHER_CXXFLAGS: Optional C++ flags +# OTHER_FFLAGS: Optional Fortran flags +# +# TMPFILES: Placeholder for `make clean` deletion (as `make neat`). + +FC = @FC@ +LD = @FC@ + +CPPDEFS = @DEFS@ +CPPFLAGS = @CPPFLAGS@ +FFLAGS = @FCFLAGS@ +LDFLAGS = @LDFLAGS@ @LIBS@ + +# Gather modulefiles +TMPFILES = $(wildcard *.mod) + +include Makefile.mkmf + + +# Delete any files associated with configuration (including the Makefile). +.PHONY: distclean +distclean: clean + # configure output + rm -f config.log + rm -f config.status + rm -f Makefile + # mkmf output + rm -f path_names + rm -f Makefile.mkmf + + +# This deletes all files generated by autoconf, including configure. +# It is more aggressive than automake's maintainer-clean. +# NOTE: Not a standard GNU target, this is for internal use only. +# Don't be surprised if the name changes or if it disappears someday. +.PHONY: ac-clean +ac-clean: distclean + rm -f @srcdir@/ac/aclocal.m4 + rm -rf @srcdir@/ac/autom4te.cache + rm -f @srcdir@/ac/configure diff --git a/ac/README.md b/ac/README.md new file mode 100644 index 0000000000..12cfbf2b00 --- /dev/null +++ b/ac/README.md @@ -0,0 +1,184 @@ +# Autoconf Build Configuration + +This directory contains the configuration files required to build MOM6 using +Autoconf. + +Note that a top-level `./configure` is not contained in the repository, and the +instruction below will generate this script in the `ac` directory. + + +# Requirements + +The following tools and libraries must be installed on your system. + +* Autoconf +* Fortran compiler (e.g. GFortran) +* MPI (e.g. Open MPI, MPICH) +* netCDF, with Fortran support + +On some platforms, such as macOS, the Autoconf package may also require an +installation of Automake. + +Some packages such as netCDF may require an additional packages for Fortran +support. + + +# Quick start guide + +The following instructions will allow a new user to quickly create a MOM6 +executable for ocean-only simulations. + +Each set of instructions is meant to be run from the root directory of the +repository. + +A separate Makefile in `ac/deps/` is provided to gather and build any GFDL +dependencies. +``` +$ cd ac/deps +$ make -j +``` +This will fetch the `mkmf` tool and build the FMS library. + +To build MOM6, first generate the Autoconf `configure` script. +``` +$ cd ac +$ autoreconf +``` +Then select your build directory, e.g. `./build`, run the configure script, and +build the model. +``` +$ mkdir -p build +$ cd build +$ ../ac/configure +$ make -j +``` +This will create the MOM6 executable in the build directory. + +This executable is only useable for ocean-only simulations, and cannot be used +for coupled modeling. It also requires the necessary experiment configuration +files, such as `input.nml` and `MOM_input`. For more information, consult the +[MOM6-examples wiki](https://github.com/NOAA-GFDL/MOM6-examples/wiki). + + +# Build rules + +The Makefile produced by Autoconf provides the following rules. + +``make`` + + Build the MOM6 executable. + +``make clean`` + + Delete the executable and any object and module files, but preserve the + Autoconf output. + +``make distclean`` + + Delete all of the files above, as well as any files generated by + `./configure`. Note that this will delete the Makefile containing this rule. + +``make ac-clean`` + + Delete all of the files above, including `./configure` and any other files + created by `autoreconf`. As with `make distclean`, this will also delete the + Makefile containing this rule. + + +# Build configuration settings + +Autoconf will resolve most model dependencies, and includes the standard set of +configuration options, such as `FC` or `FCFLAGS`. The `configure` settings +specific to MOM6 are described below. + +`--enable-asymmetric` + + The MOM6 executable is configured to use symmetric grids by default. + + Use the flag above to compile using uniform (asymmetric) grids. + + Symmetric grids are defined such that the fields for every C-grid cell are + fully specified by their local values. In particular, quantities such as + velocities or vorticity are defined along the boundaries of the domain. + + Use of symmetric grids simplifies many calculations, but also results in + nonuniform domain sizes for different fields, and slightly greater storage + since the additional values can be considered redundant. + +`--enable-openmp` + + Use this flag to enable OpenMP in the build. + +`--disable-real-8` + + While MOM6 does not explicitly use double precision reals, most of the + algorithms are designed and tested under this assumption, and the default + configuration is to enforce 8-byte reals. + + This flag may be used to relax this requirement, causing the compiler to use + the default size (usually single precision reals), although there is no + guarantee that the model will be usable. + +For the complete list of settings, run `./configure --help`. + + +# GFDL Dependencies + +This section briefly describes the management of GFDL dependencies `mkmf` and +FMS. + +The `configure` script will first check if the compiler and its configured +flags (`FCFLAGS`, `LDFLAGS`, etc.) can find `mkmf` and the FMS library. If +unavailable, then it will search in the local `ac/deps` library. If still +unavailable, then the build will abort. + +Running `make -C ac/deps` will ensure that the libraries are available. But if +the user wishes to target an external FMS library, then they should add the +appropriate `FCFLAGS` and `LDFLAGS` to find the library. + +Similar options are provided for `mkmf` with respect to `PATH`, although it +is usually not necessary to use an external `mkmf` script. + +Some configuration options are provided by the `ac/deps` Makefile: + +`PATH_ENV` + + This variable will override the value of `PATH` when building the dependencies. + +`FCFLAGS_ENV` + + Used to override the default Autoconf flags, `-g -O2`. This is useful if, + for example, one wants to build with `-O0` to speed up the build time. + +`MKMF_URL` (*default:* https://github.com/NOAA-GFDL/mkmf.git) +`MKMF_COMMIT`(*default:* `master`) +`FMS_URL` (*default:* https://github.com/NOAA-GFDL/FMS.git) +`FMS_COMMIT` (*default:* `2019.01.03`) + + These are used to specify where to check out the source code for each + respective project. + +Additional hooks for FMS builds do not yet exist, but can be added if +necessary. + + +# Known issues / Future development + +## MPI configuration + +There are minor issues with the MPI configuration macro, where it may use an +MPI build wrapper (e.g. `mpifort`) whose underlying compiler does not match +the `FC` compiler, which will often be auto-configured to `gfortran`. + +This is usually not an issue, but can cause confusion if `FCFLAGS` is +configured for the MPI wrapper but is incompatible with the `FC` compiler. + +To resolve this, ensure that `FC` and `FCFLAGS` are specified for the same +compiler. + + +## Coupled builds + +The Autoconf build is currently only capable of building ocean-only +executables, and cannot yet be built as part of a coupled model, nor as a +standalone library. This is planned to be addressed in a future release. diff --git a/ac/configure.ac b/ac/configure.ac new file mode 100644 index 0000000000..ee6b76dacb --- /dev/null +++ b/ac/configure.ac @@ -0,0 +1,174 @@ +# Autoconf configuration + +# NOTE: +# - We currently do not use a MOM6 version tag, but this would be one option in +# the future: +# [m4_esyscmd_s([git describe])] +# - Another option is `git rev-parse HEAD` for the full hash. +# - We would probably run this inside of a script to avoid the explicit +# dependency on git. + +AC_INIT( + [MOM6], + [ ], + [https://github.com/NOAA-GFDL/MOM6/issues], + [], + [https://github.com/NOAA-GFDL/MOM6]) + +#--- +# NOTE: For the autoconf-adverse, the configuration files and autoreconf output +# are kept in the `ac` directory. +# +# This breaks the convention where configure.ac resides in the top directory. +# +# As a result, $srcdir initially points to the `ac` directory, rather than the +# top directory of the codebase. +# +# In order to balance this, we up-path (../) srcdir and point AC_CONFIG_SRCDIR +# to srcdir and point AC_CONFIG_SRCDIR to the parent directory. +# +# Someday we may revert this and work from the top-level directory. But for +# now we will isolate autoconf to a subdirectory. +#--- + +# Validate srdcir and configure input +AC_CONFIG_SRCDIR([../src/core/MOM.F90]) +AC_CONFIG_MACRO_DIR([m4]) +srcdir=$srcdir/.. + + +# Default to symmetric grid +# NOTE: --enable is more properly used to add a feature, rather than to select +# a compile-time mode, so this is not exactly being used as intended. +MEM_LAYOUT=${srcdir}/config_src/dynamic_symmetric +AC_ARG_ENABLE([asymmetric], + AS_HELP_STRING([--enable-asymmetric], [Use the asymmetric grid])) +AS_IF([test "$enable_asymmetric" = yes], + [MEM_LAYOUT=${srcdir}/config_src/dynamic]) + + +# TODO: Rather than point to a pre-configured header file, autoconf could be +# used to configure a header based on a template. +#AC_CONFIG_HEADERS(["$MEM_LAYOUT/MOM_memory.h"]) + + +# Explicitly assume free-form Fortran +AC_LANG(Fortran) +AC_FC_SRCEXT(f90) + + +# Determine MPI compiler wrappers +# NOTE: +# - AX_MPI invokes AC_PROG_FC, often with gfortran, even if the MPI launcher +# does not use gfortran. +# - This can cause standard AC_PROG_FC tests to fail if FCFLAGS is configured +# with flags from another compiler. +# - I do not yet know how to resolve this possible issue. +AX_MPI([], + [AC_MSG_ERROR([Could not find MPI launcher.])]) + + +# Explicitly replace FC and LD with MPI wrappers +# NOTE: This is yet another attempt to manage the potential mismatches between +# FC and MPIFC. Without this step, the tests below would not use MPIFC. +AC_SUBST(FC, $MPIFC) +AC_SUBST(LD, $MPIFC) + +# Confirm that FC can see the Fortran 90 MPI module. +AX_FC_CHECK_MODULE([mpi], + [], [AC_MSG_ERROR([Could not find MPI Fortran module.])]) + + +# netCDF configuration +AC_PATH_PROG([NC_CONFIG], [nc-config]) +AS_IF([test -n "$NC_CONFIG"], + [CPPFLAGS="$CPPFLAGS -I$($NC_CONFIG --includedir)" + FCFLAGS="$FCFLAGS -I$($NC_CONFIG --includedir)" + LDFLAGS="$LDFLAGS -L$($NC_CONFIG --libdir)"], + [AC_MSG_ERROR([Could not find nc-config.])]) + +AX_FC_CHECK_MODULE([netcdf], + [], [AC_MSG_ERROR([Could not find FMS library.])]) +AX_FC_CHECK_LIB([netcdff], [nf_create], [netcdf], + [], [AC_MSG_ERROR([Could not link netcdff library.])] +) + + +# Force 8-byte reals +AX_FC_REAL8 +AS_IF( + [test "$enable_real8" != no], + [FCFLAGS="$FCFLAGS $REAL8_FCFLAGS"]) + + +# OpenMP configuration +AC_OPENMP +AS_IF( + [test "$enable_openmp" = yes], + [FCFLAGS="$FCFLAGS $OPENMP_FCFLAGS" + LDFLAGS="$LDFLAGS $OPENMP_FCFLAGS"]) + + +# FMS support + +# Test for fms_mod to verify FMS module access +AX_FC_CHECK_MODULE([fms_mod], [], [ + AS_UNSET([ax_fc_cv_mod_fms_mod]) + AX_FC_CHECK_MODULE([fms_mod], + [AC_SUBST([FCFLAGS], ["-I${srcdir}/ac/deps/include $FCFLAGS"])], + [AC_MSG_ERROR([Could not find fms_mod Fortran module.])], + [-I${srcdir}/ac/deps/include]) +]) + +# Test for fms_init to verify FMS library linking +AX_FC_CHECK_LIB([FMS], [fms_init], [fms_mod], + [], [ + AS_UNSET([ax_fc_cv_lib_FMS_fms_init]) + AX_FC_CHECK_LIB([FMS], [fms_init], [fms_mod], [ + AC_SUBST([LDFLAGS], ["-L${srcdir}/ac/deps/lib $LDFLAGS"]) + AC_SUBST([LIBS], ["-lFMS $LIBS"]) + ], + [AC_MSG_ERROR([Could not find FMS library.])], + [-L${srcdir}/ac/deps/lib]) + ] +) + + +# Search for mkmf build tools +AC_PATH_PROG([LIST_PATHS], [list_paths]) +AS_IF([test -z "$LIST_PATHS"], [ + AC_PATH_PROG([LIST_PATHS], [list_paths], [], ["$PATH:${srcdir}/ac/deps/bin"]) + AS_IF([test -z "$LIST_PATHS"], + [AC_MSG_ERROR([Could not find list_paths.])], + [AC_SUBST(PATH, ["$PATH:${srcdir}/ac/deps/bin"])]) + ] +) + +AC_PATH_PROG([MKMF], [mkmf]) +AS_IF([test -z "$MKMF"], [ + AC_PATH_PROG([MKMF], [mkmf], [], ["$PATH:${srcdir}/ac/deps/bin"]) + AS_IF([test -z "$MKMF"], + [AC_MSG_ERROR([Could not find mkmf.])], + [AC_SUBST(PATH, ["$PATH:${srcdir}/ac/deps/bin"])]) + ] +) + + +# NOTE: MEM_LAYOUT unneeded if we shift to MOM_memory.h.in template +AC_CONFIG_COMMANDS([path_names], + [list_paths -l \ + ${srcdir}/src \ + ${srcdir}/config_src/solo_driver \ + ${srcdir}/config_src/ext* \ + ${MEM_LAYOUT} +], [MEM_LAYOUT=$MEM_LAYOUT]) + + +AC_CONFIG_COMMANDS([Makefile.mkmf], + [mkmf -p MOM6 -m Makefile.mkmf path_names]) + + +# Prepare output +AC_SUBST(CPPFLAGS) +AC_CONFIG_FILES([Makefile:${srcdir}/ac/Makefile.in]) +AC_OUTPUT diff --git a/ac/deps/.gitignore b/ac/deps/.gitignore new file mode 100644 index 0000000000..8cfaa6ebcb --- /dev/null +++ b/ac/deps/.gitignore @@ -0,0 +1,5 @@ +/bin/ +/fms/ +/include/ +/lib/ +/mkmf/ diff --git a/ac/deps/Makefile b/ac/deps/Makefile new file mode 100644 index 0000000000..91fe343047 --- /dev/null +++ b/ac/deps/Makefile @@ -0,0 +1,106 @@ +SHELL = bash +.SUFFIXES: + +# FMS build configuration +PATH_ENV ?= +FCFLAGS_ENV ?= + +# Only set FCFLAGS if an argument is provided. +FMS_FCFLAGS = +ifneq ($(FCFLAGS_ENV),) + FMS_FCFLAGS := FCFLAGS="$(FCFLAGS_ENV)" +endif + + +# Ditto for path +FMS_PATH = +ifneq ($(PATH_ENV),) + FMS_PATH := PATH="$(PATH_ENV)" +endif + + +# mkmf, list_paths (GFDL build toolchain) +MKMF_URL ?= https://github.com/NOAA-GFDL/mkmf.git +MKMF_COMMIT ?= master + +# FMS framework +FMS_URL ?= https://github.com/NOAA-GFDL/FMS.git +FMS_COMMIT ?= 2019.01.03 + + +# List of source files to link this Makefile's dependencies to model Makefiles +# Assumes a depth of two, and the following extensions: F90 inc c h +# (1): Root directory +# NOTE: extensions could be a second variable +SOURCE = \ + $(foreach ext,F90 inc c h,$(wildcard $(1)/*/*.$(ext) $(1)/*/*/*.$(ext))) + +FMS_SOURCE = $(call SOURCE,fms/src) + + +#--- +# Rules + +.PHONY: all +all: bin/mkmf bin/list_paths lib/libFMS.a + + +#--- +# mkmf checkout + +bin/mkmf bin/list_paths: mkmf + mkdir -p $(@D) + cp $^/$@ $@ + +mkmf: + git clone $(MKMF_URL) $@ + git -C $@ checkout $(MKMF_COMMIT) + + +#--- +# FMS build + +# NOTE: We emulate the automake `make install` stage by storing libFMS.a to +# ${srcdir}/deps/lib and copying module files to ${srcdir}/deps/include. +# This is a flawed approach, since module files are untracked and could be +# handled more safely, but this is adequate for now. + +# TODO: track *.mod copy? +lib/libFMS.a: fms/build/libFMS.a fms/build/Makefile + mkdir -p {lib,include} + cp fms/build/libFMS.a lib/libFMS.a + cp fms/build/*.mod include + + +fms/build/libFMS.a: fms/build/Makefile + make -C fms/build libFMS.a + + +# TODO: Include FC, CC, CFLAGS? +fms/build/Makefile: FMS_ENV=$(FMS_PATH) $(FMS_FCFLAGS) + +fms/build/Makefile: Makefile.fms.in fms/src/configure bin/mkmf bin/list_paths + mkdir -p fms/build + cp Makefile.fms.in fms/src/Makefile.in + cd $(@D) && $(FMS_ENV) ../src/configure --srcdir=../src + + +# TODO: Track m4 macros? +fms/src/configure: configure.fms.ac $(FMS_SOURCE) | fms/src + cp configure.fms.ac fms/src/configure.ac + cp -r m4 $(@D) + cd $(@D) && autoreconf -i + +fms/src: + git clone $(FMS_URL) $@ + git -C $@ checkout $(FMS_COMMIT) + + +.PHONY: clean +clean: + rm -rf fms/build lib include bin + + +.PHONY: distclean +distclean: clean + rm -rf fms mkmf diff --git a/ac/deps/Makefile.fms.in b/ac/deps/Makefile.fms.in new file mode 100644 index 0000000000..694ad8e0b0 --- /dev/null +++ b/ac/deps/Makefile.fms.in @@ -0,0 +1,48 @@ +# Makefile template for MOM6 +# +# Previously this would have been generated by mkmf using a template file. +# +# The proposed autoconf build inverts this approach by constructing the +# information previously stored in the mkmf template, such as compiler names +# and flags, and importing the un-templated mkmf output for its rules and +# dependencies. +# +# While this approach does not eliminate our dependency on mkmf, it does +# promises to eliminate our reliance on platform-specific templates, and +# instead allows us to provide a configure script for determining our compilers +# and flags. As a last resort, we provide hooks to override such settings. + +# NOTE: mkmf conventions are close, but not identical, to autoconf. +# +# CC: C compiler +# CXX: C++ compiler +# FC: Fortran compiler (f77 and f90) +# LD: Linker +# +# CPPDEFS: Preprocessor macros +# CPPFLAGS: C preprocessing flags +# CXXFLAGS: C++ preprocessing flags +# FPPFLAGS: Fortran preprocessing flags +# +# CFLAGS: C compiler flags +# FFLAGS: Fortran compiler flags (f77 and f90) +# LDFLAGS: Linker flags +# +# OTHERFLAGS: Additional flags for all languages (C, C++, Fortran) +# OTHER_CFLAGS: Optional C flags +# OTHER_CXXFLAGS: Optional C++ flags +# OTHER_FFLAGS: Optional Fortran flags + +CC = @CC@ +FC = @FC@ +LD = @FC@ + +CPPDEFS = @DEFS@ +CPPFLAGS = @CPPFLAGS@ +FFLAGS = @FCFLAGS@ +LDFLAGS = @LDFLAGS@ + +# Gather modulefiles +TMPFILES = $(wildcard *.mod) + +include Makefile.mkmf diff --git a/ac/deps/configure.fms.ac b/ac/deps/configure.fms.ac new file mode 100644 index 0000000000..1d66194c81 --- /dev/null +++ b/ac/deps/configure.fms.ac @@ -0,0 +1,155 @@ +# Autoconf configuration +AC_INIT( + [FMS], + [ ], + [https://github.com/NOAA-GFDL/FMS/issues]) + +# Validate srdcir and configure input +AC_CONFIG_SRCDIR([fms/fms.F90]) +AC_CONFIG_MACRO_DIR([m4]) + +# C configuration +AC_PROG_CC +AX_MPI +CC=$MPICC + +# FMS configuration + +# Linux and OSX have a gettid system call, but it is not implemented in older +# glibc implementations. When unavailable, a native syscall is used. +# +# On Linux, this is defined in unistd.h as __NR_gettid, and FMS is hard-coded +# to use this value. In OS X, this is defined in sys/syscall.h as SYS_gettid, +# so we override this macro if __NR_gettid is unavailable. +AC_CHECK_FUNCS([gettid], [], [ + AC_MSG_CHECKING([if __NR_gettid must be redefined]) + AC_CACHE_VAL([ac_cv_cc_nr_gettid], [ + ac_cv_cc_nr_gettid='unknown' + for nr_gettid in __NR_gettid SYS_gettid; do + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ +#include +#include + ], [syscall($nr_gettid)] + )], [ac_cv_cc_nr_gettid=$nr_gettid] + ) + AS_IF([test "$ac_cv_cc_nr_gettid" != unknown], [break]) + done + ]) + AS_CASE([ac_cv_cc_nr_gettid], + [__NR_gettid], [AC_MSG_RESULT([none needed])], + [AC_MSG_RESULT([$ac_cv_cc_nr_gettid])] + ) + AS_IF([test "$ac_cv_cc_nr_gettid" != unknown], [ + AS_IF([test "$ac_cv_cc_nr_gettid" != __NR_gettid], + [AC_DEFINE_UNQUOTED([__NR_gettid], [$ac_cv_cc_nr_gettid])] + )], [ + AC_MSG_ERROR(["Could not find the gettid syscall ID"]) + ]) +]) + + +# FMS 2019.01.03 uses __APPLE__ to disable Linux CPU affinity calls. +AC_CHECK_FUNCS([sched_getaffinity], [], [AC_DEFINE([__APPLE__])]) + + +# Standard Fortran configuration +AC_LANG(Fortran) +AC_FC_SRCEXT(f90) +AC_PROG_FC + + +# Determine MPI compiler wrappers and override compilers +AX_MPI +AC_SUBST(FC, $MPIFC) +AC_SUBST(LD, $MPIFC) + + +# Module tests +AX_FC_CHECK_MODULE([mpi]) +AC_DEFINE([use_libMPI]) + + +# netCDF configuration +AC_PATH_PROG([NC_CONFIG], [nc-config]) +AS_IF([test -n "$NC_CONFIG"], + [CPPFLAGS="$CPPFLAGS -I$($NC_CONFIG --includedir)" + FCFLAGS="$FCFLAGS -I$($NC_CONFIG --includedir)" + LDFLAGS="$LDFLAGS -L$($NC_CONFIG --libdir)"], + [AC_MSG_ERROR([Could not find nc-config.])]) + +AX_FC_CHECK_MODULE([netcdf], + [], [AC_MSG_ERROR([Could not find FMS library.])]) +AX_FC_CHECK_LIB([netcdff], [nf_create], [netcdf], + [], [AC_MSG_ERROR([Could not link netcdff library.])] +) +AC_DEFINE([use_netCDF]) + + +# Enable Cray pointers +AX_FC_CRAY_POINTER + + +# Force 8-byte reals +AX_FC_REAL8 +AS_IF( + [test "$enable_real8" != no], + [FCFLAGS="$FCFLAGS $REAL8_FCFLAGS"]) + + +# OpenMP configuration +AC_OPENMP +AS_IF( + [test "$enable_openmp" = yes], + [FCFLAGS="$FCFLAGS $OPENMP_FCFLAGS" + LDFLAGS="$LDFLAGS $OPENMP_FCFLAGS"]) + + +# Unlimited line length +AC_FC_LINE_LENGTH([unlimited]) + +# Allow invaliz BOZ assignment +AX_FC_ALLOW_INVALID_BOZ +FCFLAGS="$FCFLAGS $ALLOW_INVALID_BOZ_FCFLAGS" + + +# Allow argument mismatch (for functions lacking interfaces) +AX_FC_ALLOW_ARG_MISMATCH +FCFLAGS="$FCFLAGS $ALLOW_ARG_MISMATCH_FCFLAGS" + + +# Search for mkmf build tools +AC_PATH_PROG([LIST_PATHS], [list_paths]) +AS_IF([test -z "$LIST_PATHS"], [ + AC_PATH_PROG([LIST_PATHS], [list_paths], [], ["$PATH:${srcdir}/../../bin"]) + AS_IF([test -z "$LIST_PATHS"], + [AC_MSG_ERROR([Could not find list_paths.])], + [AC_SUBST(PATH, ["$PATH:${srcdir}/../../bin"])]) + ] +) + +AC_PATH_PROG([MKMF], [mkmf]) +AS_IF([test -z "$MKMF"], [ + AC_PATH_PROG([MKMF], [mkmf], [], ["$PATH:${srcdir}/../../bin"]) + AS_IF([test -z "$MKMF"], + [AC_MSG_ERROR([Could not find mkmf.])], + [AC_SUBST(PATH, ["$PATH:${srcdir}/../../bin"])]) + ] +) + + +# MKMF commands +AC_CONFIG_COMMANDS([path_names], + [${LIST_PATHS} -l ${srcdir}], + [LIST_PATHS=${LIST_PATHS}]) + + +AC_CONFIG_COMMANDS([mkmf], + [${MKMF} -p libFMS.a -m Makefile.mkmf path_names], + [MKMF=${MKMF}]) + + +# Prepare output +AC_SUBST(CPPFLAGS) +AC_CONFIG_FILES(Makefile) +AC_OUTPUT diff --git a/ac/deps/m4/ax_fc_allow_arg_mismatch.m4 b/ac/deps/m4/ax_fc_allow_arg_mismatch.m4 new file mode 100644 index 0000000000..cffa302c66 --- /dev/null +++ b/ac/deps/m4/ax_fc_allow_arg_mismatch.m4 @@ -0,0 +1,58 @@ +dnl Test if mismatched function arguments are permitted. +dnl +dnl This macro tests if a flag is required to enable mismatched functions in +dnl a single translation unit (aka file). +dnl +dnl If a compiler encounters two undefined programs with different input +dnl argument types, then it may regard this as a mismatch which requires action +dnl from the user. A common example is a procedure which may be called with +dnl a variable of either an integer or a real type. +dnl +dnl This can happen, for example, if one is relying on an interface to resolve +dnl such differences, but one is also relying on a legacy header interface via +dnl `#include` rather than an explicit module which includes the complete +dnl interface specification. +dnl +dnl No modern project is expected to see these issues, but this is helpful for +dnl older projects which used legacy headers. +dnl +dnl Flags: +dnl GNU: -fallow-argument-mismatch +dnl +AC_DEFUN([AX_FC_ALLOW_ARG_MISMATCH], + [ALLOW_ARG_MISMATCH_FCFLAGS= + AC_CACHE_CHECK( + [for $FC option to support mismatched procedure arguments], + [ac_cv_prog_fc_arg_mismatch], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [ + call f(1) + call f(1.0) + ])], + [ac_cv_prog_fc_arg_mismatch='none needed'], + [ac_cv_prog_fc_arg_mismatch='unsupported' + for ac_option in -fallow-argument-mismatch; do + ac_save_FCFLAGS=$FCFLAGS + FCFLAGS="$FCFLAGS $ac_option" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [ + call f(1) + call f(1.0) + ])], + [ac_cv_prog_fc_arg_mismatch=$ac_option] + ) + FCFLAGS=$ac_save_FCFLAGS + if test "$ac_cv_prog_fc_arg_mismatch" != unsupported; then + break + fi + done]) + ] + ) + case $ac_cv_prog_fc_arg_mismatch in #( + "none needed" | unsupported) + ;; #( + *) + ALLOW_ARG_MISMATCH_FCFLAGS=$ac_cv_prog_fc_arg_mismatch ;; + esac + AC_SUBST(ALLOW_ARG_MISMATCH_FCFLAGS) +]) diff --git a/ac/deps/m4/ax_fc_allow_invalid_boz.m4 b/ac/deps/m4/ax_fc_allow_invalid_boz.m4 new file mode 100644 index 0000000000..5d4521b5fb --- /dev/null +++ b/ac/deps/m4/ax_fc_allow_invalid_boz.m4 @@ -0,0 +1,54 @@ +dnl Test if BOZ literal assignment is supported. +dnl +dnl This macro tests if a flag is required to enable BOZ literal assignments +dnl for variables. +dnl +dnl BOZ literals (e.g. Z'FFFF') are typeless, and formally cannot be assigned +dnl to typed variables. Nonetheless, few compilers forbid such operations, +dnl despite the potential pitfalls around interpreting such values. +dnl +dnl As of version 10.1, gfortran now forbids such assignments and requires a +dnl flag to convert the raised errors into warnings. +dnl +dnl While the best solution is to replace such assignments with proper +dnl conversion functions, this test is useful to accommodate older projects. +dnl +dnl Flags: +dnl GNU: -fallow-invalid-boz +AC_DEFUN([AX_FC_ALLOW_INVALID_BOZ], + [ALLOW_INVALID_BOZ_FCFLAGS= + AC_CACHE_CHECK( + [for $FC option to support invalid BOZ assignment], + [ac_cv_prog_fc_invalid_boz], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [ + integer n + n = z'ff' + ])], + [ac_cv_prog_fc_invalid_boz='none needed'], + [ac_cv_prog_fc_invalid_boz='unsupported' + for ac_option in -fallow-invalid-boz; do + ac_save_FCFLAGS=$FCFLAGS + FCFLAGS="$FCFLAGS $ac_option" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([], [ + integer n + n = z'ff' + ])], + [ac_cv_prog_fc_invalid_boz=$ac_option] + ) + FCFLAGS=$ac_save_FCFLAGS + if test "$ac_cv_prog_fc_invalid_boz" != unsupported; then + break + fi + done]) + ] + ) + case $ac_cv_prog_fc_invalid_boz in #( + "none needed" | unsupported) + ;; #( + *) + ALLOW_INVALID_BOZ_FCFLAGS=$ac_cv_prog_fc_invalid_boz ;; + esac + AC_SUBST(ALLOW_INVALID_BOZ_FCFLAGS)] +) diff --git a/ac/deps/m4/ax_fc_check_lib.m4 b/ac/deps/m4/ax_fc_check_lib.m4 new file mode 100644 index 0000000000..c0accab6cd --- /dev/null +++ b/ac/deps/m4/ax_fc_check_lib.m4 @@ -0,0 +1,52 @@ +dnl AX_FC_CHECK_LIB(LIBRARY, FUNCTION, +dnl [MODULE], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], +dnl [OTHER-LDFLAGS], [OTHER-LIBS]) +dnl +dnl This macro checks if a Fortran library containing a designated function +dnl is available to the compiler. For the most part, this macro should behave +dnl like the Autoconf AC_CHECK_LIB macro. +dnl +dnl This macro differs somewhat from AC_CHECK_LIB, since it includes two +dnl additional features: +dnl +dnl 1. The third argument (optional) allows us to specify a Fortran module, +dnl which may be required to access the library's functions. +dnl +dnl 2. The sixth argument (optional) allows specification of supplemental +dnl LDFLAGS arguments. This can be used, for example, to test for the +dnl library with different -L flags, or perhaps other ld configurations. +dnl +dnl Results are cached in the ax_fc_cv_lib_LIBRARY_FUNCTION variable. +dnl +AC_DEFUN([AX_FC_CHECK_LIB],[dnl + AS_VAR_PUSHDEF([ax_fc_Lib], [ax_fc_cv_lib_$1_$2]) + m4_ifval([$6], + [ax_fc_lib_msg_LDFLAGS=" with $6"], + [ax_fc_lib_msg_LDFLAGS=""] + ) + AC_CACHE_CHECK([for $2 in -l$1$ax_fc_lib_msg_LDFLAGS], [ax_fc_cv_lib_$1_$2],[ + ax_fc_check_lib_save_LDFLAGS=$LDFLAGS + LDFLAGS="$6 $LDFLAGS" + ax_fc_check_lib_save_LIBS=$LIBS + LIBS="-l$1 $7 $LIBS" + AS_IF([test -n $3], + [ax_fc_use_mod="use $3"], + [ax_fc_use_mod=""]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([], [dnl + $ax_fc_use_mod + call $2]dnl + ) + ], + [AS_VAR_SET([ax_fc_Lib], [yes])], + [AS_VAR_SET([ax_fc_Lib], [no])] + ) + LIBS=$ax_fc_check_lib_save_LIBS + LDFLAGS=$ax_fc_check_lib_save_LDFLAGS + ]) + AS_VAR_IF([ax_fc_Lib], [yes], + [m4_default([$4], [LIBS="-l$1 $LIBS"])], + [$5] + ) + AS_VAR_POPDEF([ax_fc_Lib]) +]) diff --git a/ac/deps/m4/ax_fc_check_module.m4 b/ac/deps/m4/ax_fc_check_module.m4 new file mode 100644 index 0000000000..1cfd0c5a5d --- /dev/null +++ b/ac/deps/m4/ax_fc_check_module.m4 @@ -0,0 +1,28 @@ +dnl AX_FC_CHECK_MODULE(MODULE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], +dnl [OTHER-FCFLAGS]) +dnl +dnl This macro checks if a Fortran module is available to the compiler. +dnl +dnl The fourth argument (optional) allows for specification of supplemental +dnl FCFLAGS arguments. This would primarily be used to test additional +dnl paths (typically using -I) for the module file. +dnl +dnl Results are cached in the ax_fc_cv_mod_MODULE variable. +dnl +AC_DEFUN([AX_FC_CHECK_MODULE], +[ + AS_VAR_PUSHDEF([ax_fc_Module], [ax_fc_cv_mod_$1]) + AC_CACHE_CHECK([if $FC can use module $1$ax_fc_mod_msg_FCFLAGS], [ax_fc_cv_mod_$1],[ + ax_fc_chk_mod_save_FCFLAGS=$FCFLAGS + FCFLAGS="$4 $FCFLAGS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([],[use $1])], + [AS_VAR_SET([ax_fc_Module], [yes])], + [AS_VAR_SET([ax_fc_Module], [no])] + ) + FCFLAGS=$ax_fc_chk_mod_save_FCFLAGS + ]) + AS_VAR_IF([ax_fc_Module], [yes], [$2], [$3]) + AS_VAR_POPDEF([ax_fc_Module]) +]) diff --git a/ac/deps/m4/ax_fc_cray_pointer.m4 b/ac/deps/m4/ax_fc_cray_pointer.m4 new file mode 100644 index 0000000000..a9f5d9bbe3 --- /dev/null +++ b/ac/deps/m4/ax_fc_cray_pointer.m4 @@ -0,0 +1,51 @@ +dnl AX_FC_CRAY_POINTER([ACTION-IF-SUCCESS], [ACTION-IF-FAILURE]) +dnl +dnl This macro tests if any flags are required to enable Cray pointers. +dnl +dnl Cray pointers provided a means for more direct access to memory. Since +dnl such references can potentially violate certain requirements of the +dnl language standard, they are typically considered a vendor extension. +dnl +dnl Most compilers provide these in some form. A partial list of supported +dnl flags are shown below, but additional feedback is required for other +dnl compilers. +dnl +dnl The known flags are: +dnl GCC -fcray-pointer +dnl Intel Fortran none +dnl PGI Fortran -Mcray=pointer +dnl Cray Fortran none +dnl +AC_DEFUN([AX_FC_CRAY_POINTER], [ + AC_LANG_ASSERT([Fortran]) + AC_MSG_CHECKING([for $FC option to support Cray pointers]) + AC_CACHE_VAL([ac_cv_prog_fc_cray_ptr], [ + ac_cv_prog_fc_cray_ptr='unknown' + ac_save_FCFLAGS=$FCFLAGS + for ac_option in none -fcray-pointer -Mcray=pointer; do + test "$ac_option" != none && FCFLAGS="$ac_save_FCFLAGS $ac_option" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [ + integer aptr(2) + pointer (iptr, aptr) + ])], + [ac_cv_prog_fc_cray_ptr=$ac_option], + ) + FCFLAGS=$ac_save_FCFLAGS + AS_IF([test "$ac_cv_prog_fc_cray_ptr" != unknown], [break]) + done + ]) + AS_CASE([ac_cv_prog_fc_cray_ptr], + [none], [AC_MSG_RESULT([none_needed])], + [unknown], [AC_MSG_RESULT([unsupported])], + [AC_MSG_RESULT([$ac_cv_prog_fc_cray_ptr])] + ) + AS_IF([test "$ac_cv_prog_fc_cray_ptr" != unknown], [ + m4_default([$1], [ + AS_IF([test "$ac_cv_prog_fc_cray_ptr" != none], + [FCFLAGS="$FCFLAGS $ac_cv_prog_fc_cray_ptr"] + ) + ])], + [m4_default([$2], [AC_MSG_ERROR(["$FC does not support Cray pointers"])])] + ) +]) diff --git a/ac/deps/m4/ax_fc_real8.m4 b/ac/deps/m4/ax_fc_real8.m4 new file mode 100644 index 0000000000..e914b9f39a --- /dev/null +++ b/ac/deps/m4/ax_fc_real8.m4 @@ -0,0 +1,86 @@ +dnl Determine the flag required to force 64-bit reals. +dnl +dnl Many applications do not specify the kind of its real variables, even +dnl though the code may intrinsically require double-precision. Most compilers +dnl will also default to using single-precision (32-bit) reals. +dnl +dnl This test determines the flag required to set reals without explcit kind to +dnl 64-bit double precision floats. Ideally, we also desire to leave any +dnl `DOUBLE PRECISION` variable as 64-bit. But this does not appear to always +dnl be possible, such as in NAG Fortran (see below). +dnl +dnl This does not test if the behavior of integers is changed; for example, +dnl Cray's Fortran wrapper's -default will double both. This is addressed by +dnl avoiding any flags with affect integers, but this should still be used with +dnl some care. +dnl +dnl GCC -fdefault-real-8, -fdefault-double-8 +dnl [Common alias] -r8 +dnl Intel Fortran -real-kind 64 +dnl PGI Fortran -Mr8 +dnl Cray Fortran -s real64 +dnl NAG -double +dnl +dnl NOTE: +dnl - Many compilers accept -r8 for real and double precision sizes, but +dnl several compiler-specific options are also provided. +dnl +dnl - -r8 in NAG will attempt to also set double precision to 16 bytes if +dnl available, which is generally undesired. +dnl +dnl Additionally, the -double flag, which doubles *all* types, appears to +dnl be the preferred flag here. +dnl +dnl Neither flag describes what we actually want, but we include it here +dnl as a last resort. +dnl +AC_DEFUN([AX_FC_REAL8], +[ + REAL8_FCFLAGS= + AC_ARG_ENABLE([real8], + [AS_HELP_STRING([--disable-real-8], [do not force 8-byte reals])]) + if test "$enable_real8" != no; then + AC_CACHE_CHECK([for $FC option to force 8-byte reals], + [ac_cv_prog_fc_real8], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [ + real :: x(4) + double precision :: y(4) + integer, parameter :: & + m = merge(1, 0, kind(x(1)) == selected_real_kind(15, 307)), & + n = merge(1, 0, kind(y(1)) == selected_real_kind(15, 307)) + print *, x(::m) + print *, y(::n) + ])], + [ac_cv_prog_fc_real8='none needed'], + [ac_cv_prog_fc_real8='unsupported' + for ac_option in "-fdefault-real-8 -fdefault-double-8" -r8 "-real-kind 64" -Mr8 "-s real64" -double; do + ac_save_FCFLAGS=$FCFLAGS + FCFLAGS="$FCFLAGS $ac_option" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([], [ + real :: x(4) + double precision :: y(4) + integer, parameter :: & + m = merge(1, 0, kind(x(1)) == selected_real_kind(15, 307)), & + n = merge(1, 0, kind(y(1)) == selected_real_kind(15, 307)) + print *, x(::m) + print *, y(::n) + ])], + [ac_cv_prog_fc_real8=$ac_option] + ) + FCFLAGS=$ac_save_FCFLAGS + if test "$ac_cv_prog_fc_real8" != unsupported; then + break + fi + done]) + ]) + case $ac_cv_prog_fc_real8 in #( + "none needed" | unsupported) + ;; #( + *) + REAL8_FCFLAGS=$ac_cv_prog_fc_real8 ;; + esac + fi + AC_SUBST(REAL8_FCFLAGS) +]) diff --git a/ac/deps/m4/ax_mpi.m4 b/ac/deps/m4/ax_mpi.m4 new file mode 100644 index 0000000000..ecce2e141a --- /dev/null +++ b/ac/deps/m4/ax_mpi.m4 @@ -0,0 +1,176 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_mpi.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_MPI([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro tries to find out how to compile programs that use MPI +# (Message Passing Interface), a standard API for parallel process +# communication (see http://www-unix.mcs.anl.gov/mpi/) +# +# On success, it sets the MPICC, MPICXX, MPIF77, or MPIFC output variable +# to the name of the MPI compiler, depending upon the current language. +# (This may just be $CC/$CXX/$F77/$FC, but is more often something like +# mpicc/mpiCC/mpif77/mpif90.) It also sets MPILIBS to any libraries that +# are needed for linking MPI (e.g. -lmpi or -lfmpi, if a special +# MPICC/MPICXX/MPIF77/MPIFC was not found). +# +# Note that this macro should be used only if you just have a few source +# files that need to be compiled using MPI. In particular, you should +# neither overwrite CC/CXX/F77/FC with the values of +# MPICC/MPICXX/MPIF77/MPIFC, nor assume that you can use the same flags +# etc. as the standard compilers. If you want to compile a whole program +# using the MPI compiler commands, use one of the macros +# AX_PROG_{CC,CXX,FC}_MPI. +# +# ACTION-IF-FOUND is a list of shell commands to run if an MPI library is +# found, and ACTION-IF-NOT-FOUND is a list of commands to run if it is not +# found. If ACTION-IF-FOUND is not specified, the default action will +# define HAVE_MPI. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Julian C. Cummings +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 9 + +AU_ALIAS([ACX_MPI], [AX_MPI]) +AC_DEFUN([AX_MPI], [ +AC_PREREQ(2.50) dnl for AC_LANG_CASE + +AC_LANG_CASE([C], [ + AC_REQUIRE([AC_PROG_CC]) + AC_ARG_VAR(MPICC,[MPI C compiler command]) + AC_CHECK_PROGS(MPICC, mpicc cc hcc mpxlc_r mpxlc mpcc cmpicc, $CC) + ax_mpi_save_CC="$CC" + CC="$MPICC" + AC_SUBST(MPICC) +], +[C++], [ + AC_REQUIRE([AC_PROG_CXX]) + AC_ARG_VAR(MPICXX,[MPI C++ compiler command]) + AC_CHECK_PROGS(MPICXX, mpic++ mpicxx mpiCC hcp mpxlC_r mpxlC mpCC cmpic++, $CXX) + ax_mpi_save_CXX="$CXX" + CXX="$MPICXX" + AC_SUBST(MPICXX) +], +[Fortran 77], [ + AC_REQUIRE([AC_PROG_F77]) + AC_ARG_VAR(MPIF77,[MPI Fortran 77 compiler command]) + AC_CHECK_PROGS(MPIF77, mpif77 hf77 mpxlf_r mpxlf mpf77 cmpifc, $F77) + ax_mpi_save_F77="$F77" + F77="$MPIF77" + AC_SUBST(MPIF77) +], +[Fortran], [ + AC_REQUIRE([AC_PROG_FC]) + AC_ARG_VAR(MPIFC,[MPI Fortran compiler command]) + AC_CHECK_PROGS(MPIFC, mpifort mpif90 ftn mpxlf95_r mpxlf90_r mpxlf95 mpxlf90 mpf90 cmpif90c, $FC) + ax_mpi_save_FC="$FC" + FC="$MPIFC" + AC_SUBST(MPIFC) +]) + +if test x = x"$MPILIBS"; then + AC_LANG_CASE([C], [AC_CHECK_FUNC(MPI_Init, [MPILIBS=" "])], + [C++], [AC_CHECK_FUNC(MPI_Init, [MPILIBS=" "])], + [Fortran 77], [AC_MSG_CHECKING([for MPI_Init]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[ call MPI_Init])],[MPILIBS=" " + AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)])], + [Fortran], [AC_MSG_CHECKING([for MPI_Init]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[ call MPI_Init])],[MPILIBS=" " + AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)])]) +fi +AC_LANG_CASE([Fortran 77], [ + if test x = x"$MPILIBS"; then + AC_CHECK_LIB(fmpi, MPI_Init, [MPILIBS="-lfmpi"]) + fi + if test x = x"$MPILIBS"; then + AC_CHECK_LIB(fmpich, MPI_Init, [MPILIBS="-lfmpich"]) + fi +], +[Fortran], [ + if test x = x"$MPILIBS"; then + AC_CHECK_LIB(fmpi, MPI_Init, [MPILIBS="-lfmpi"]) + fi + if test x = x"$MPILIBS"; then + AC_CHECK_LIB(mpichf90, MPI_Init, [MPILIBS="-lmpichf90"]) + fi +]) +if test x = x"$MPILIBS"; then + AC_CHECK_LIB(mpi, MPI_Init, [MPILIBS="-lmpi"]) +fi +if test x = x"$MPILIBS"; then + AC_CHECK_LIB(mpich, MPI_Init, [MPILIBS="-lmpich"]) +fi + +dnl We have to use AC_TRY_COMPILE and not AC_CHECK_HEADER because the +dnl latter uses $CPP, not $CC (which may be mpicc). +AC_LANG_CASE([C], [if test x != x"$MPILIBS"; then + AC_MSG_CHECKING([for mpi.h]) + AC_TRY_COMPILE([#include ],[],[AC_MSG_RESULT(yes)], [MPILIBS="" + AC_MSG_RESULT(no)]) +fi], +[C++], [if test x != x"$MPILIBS"; then + AC_MSG_CHECKING([for mpi.h]) + AC_TRY_COMPILE([#include ],[],[AC_MSG_RESULT(yes)], [MPILIBS="" + AC_MSG_RESULT(no)]) +fi], +[Fortran 77], [if test x != x"$MPILIBS"; then + AC_MSG_CHECKING([for mpif.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[ include 'mpif.h'])],[AC_MSG_RESULT(yes)], [MPILIBS="" + AC_MSG_RESULT(no)]) +fi], +[Fortran], [if test x != x"$MPILIBS"; then + AC_MSG_CHECKING([for mpif.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[ include 'mpif.h'])],[AC_MSG_RESULT(yes)], [MPILIBS="" + AC_MSG_RESULT(no)]) +fi]) + +AC_LANG_CASE([C], [CC="$ax_mpi_save_CC"], + [C++], [CXX="$ax_mpi_save_CXX"], + [Fortran 77], [F77="$ax_mpi_save_F77"], + [Fortran], [FC="$ax_mpi_save_FC"]) + +AC_SUBST(MPILIBS) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x = x"$MPILIBS"; then + $2 + : +else + ifelse([$1],,[AC_DEFINE(HAVE_MPI,1,[Define if you have the MPI library.])],[$1]) + : +fi +])dnl AX_MPI diff --git a/ac/m4/ax_fc_check_lib.m4 b/ac/m4/ax_fc_check_lib.m4 new file mode 100644 index 0000000000..c0accab6cd --- /dev/null +++ b/ac/m4/ax_fc_check_lib.m4 @@ -0,0 +1,52 @@ +dnl AX_FC_CHECK_LIB(LIBRARY, FUNCTION, +dnl [MODULE], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], +dnl [OTHER-LDFLAGS], [OTHER-LIBS]) +dnl +dnl This macro checks if a Fortran library containing a designated function +dnl is available to the compiler. For the most part, this macro should behave +dnl like the Autoconf AC_CHECK_LIB macro. +dnl +dnl This macro differs somewhat from AC_CHECK_LIB, since it includes two +dnl additional features: +dnl +dnl 1. The third argument (optional) allows us to specify a Fortran module, +dnl which may be required to access the library's functions. +dnl +dnl 2. The sixth argument (optional) allows specification of supplemental +dnl LDFLAGS arguments. This can be used, for example, to test for the +dnl library with different -L flags, or perhaps other ld configurations. +dnl +dnl Results are cached in the ax_fc_cv_lib_LIBRARY_FUNCTION variable. +dnl +AC_DEFUN([AX_FC_CHECK_LIB],[dnl + AS_VAR_PUSHDEF([ax_fc_Lib], [ax_fc_cv_lib_$1_$2]) + m4_ifval([$6], + [ax_fc_lib_msg_LDFLAGS=" with $6"], + [ax_fc_lib_msg_LDFLAGS=""] + ) + AC_CACHE_CHECK([for $2 in -l$1$ax_fc_lib_msg_LDFLAGS], [ax_fc_cv_lib_$1_$2],[ + ax_fc_check_lib_save_LDFLAGS=$LDFLAGS + LDFLAGS="$6 $LDFLAGS" + ax_fc_check_lib_save_LIBS=$LIBS + LIBS="-l$1 $7 $LIBS" + AS_IF([test -n $3], + [ax_fc_use_mod="use $3"], + [ax_fc_use_mod=""]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([], [dnl + $ax_fc_use_mod + call $2]dnl + ) + ], + [AS_VAR_SET([ax_fc_Lib], [yes])], + [AS_VAR_SET([ax_fc_Lib], [no])] + ) + LIBS=$ax_fc_check_lib_save_LIBS + LDFLAGS=$ax_fc_check_lib_save_LDFLAGS + ]) + AS_VAR_IF([ax_fc_Lib], [yes], + [m4_default([$4], [LIBS="-l$1 $LIBS"])], + [$5] + ) + AS_VAR_POPDEF([ax_fc_Lib]) +]) diff --git a/ac/m4/ax_fc_check_module.m4 b/ac/m4/ax_fc_check_module.m4 new file mode 100644 index 0000000000..1cfd0c5a5d --- /dev/null +++ b/ac/m4/ax_fc_check_module.m4 @@ -0,0 +1,28 @@ +dnl AX_FC_CHECK_MODULE(MODULE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], +dnl [OTHER-FCFLAGS]) +dnl +dnl This macro checks if a Fortran module is available to the compiler. +dnl +dnl The fourth argument (optional) allows for specification of supplemental +dnl FCFLAGS arguments. This would primarily be used to test additional +dnl paths (typically using -I) for the module file. +dnl +dnl Results are cached in the ax_fc_cv_mod_MODULE variable. +dnl +AC_DEFUN([AX_FC_CHECK_MODULE], +[ + AS_VAR_PUSHDEF([ax_fc_Module], [ax_fc_cv_mod_$1]) + AC_CACHE_CHECK([if $FC can use module $1$ax_fc_mod_msg_FCFLAGS], [ax_fc_cv_mod_$1],[ + ax_fc_chk_mod_save_FCFLAGS=$FCFLAGS + FCFLAGS="$4 $FCFLAGS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([],[use $1])], + [AS_VAR_SET([ax_fc_Module], [yes])], + [AS_VAR_SET([ax_fc_Module], [no])] + ) + FCFLAGS=$ax_fc_chk_mod_save_FCFLAGS + ]) + AS_VAR_IF([ax_fc_Module], [yes], [$2], [$3]) + AS_VAR_POPDEF([ax_fc_Module]) +]) diff --git a/ac/m4/ax_fc_real8.m4 b/ac/m4/ax_fc_real8.m4 new file mode 100644 index 0000000000..e914b9f39a --- /dev/null +++ b/ac/m4/ax_fc_real8.m4 @@ -0,0 +1,86 @@ +dnl Determine the flag required to force 64-bit reals. +dnl +dnl Many applications do not specify the kind of its real variables, even +dnl though the code may intrinsically require double-precision. Most compilers +dnl will also default to using single-precision (32-bit) reals. +dnl +dnl This test determines the flag required to set reals without explcit kind to +dnl 64-bit double precision floats. Ideally, we also desire to leave any +dnl `DOUBLE PRECISION` variable as 64-bit. But this does not appear to always +dnl be possible, such as in NAG Fortran (see below). +dnl +dnl This does not test if the behavior of integers is changed; for example, +dnl Cray's Fortran wrapper's -default will double both. This is addressed by +dnl avoiding any flags with affect integers, but this should still be used with +dnl some care. +dnl +dnl GCC -fdefault-real-8, -fdefault-double-8 +dnl [Common alias] -r8 +dnl Intel Fortran -real-kind 64 +dnl PGI Fortran -Mr8 +dnl Cray Fortran -s real64 +dnl NAG -double +dnl +dnl NOTE: +dnl - Many compilers accept -r8 for real and double precision sizes, but +dnl several compiler-specific options are also provided. +dnl +dnl - -r8 in NAG will attempt to also set double precision to 16 bytes if +dnl available, which is generally undesired. +dnl +dnl Additionally, the -double flag, which doubles *all* types, appears to +dnl be the preferred flag here. +dnl +dnl Neither flag describes what we actually want, but we include it here +dnl as a last resort. +dnl +AC_DEFUN([AX_FC_REAL8], +[ + REAL8_FCFLAGS= + AC_ARG_ENABLE([real8], + [AS_HELP_STRING([--disable-real-8], [do not force 8-byte reals])]) + if test "$enable_real8" != no; then + AC_CACHE_CHECK([for $FC option to force 8-byte reals], + [ac_cv_prog_fc_real8], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [ + real :: x(4) + double precision :: y(4) + integer, parameter :: & + m = merge(1, 0, kind(x(1)) == selected_real_kind(15, 307)), & + n = merge(1, 0, kind(y(1)) == selected_real_kind(15, 307)) + print *, x(::m) + print *, y(::n) + ])], + [ac_cv_prog_fc_real8='none needed'], + [ac_cv_prog_fc_real8='unsupported' + for ac_option in "-fdefault-real-8 -fdefault-double-8" -r8 "-real-kind 64" -Mr8 "-s real64" -double; do + ac_save_FCFLAGS=$FCFLAGS + FCFLAGS="$FCFLAGS $ac_option" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([], [ + real :: x(4) + double precision :: y(4) + integer, parameter :: & + m = merge(1, 0, kind(x(1)) == selected_real_kind(15, 307)), & + n = merge(1, 0, kind(y(1)) == selected_real_kind(15, 307)) + print *, x(::m) + print *, y(::n) + ])], + [ac_cv_prog_fc_real8=$ac_option] + ) + FCFLAGS=$ac_save_FCFLAGS + if test "$ac_cv_prog_fc_real8" != unsupported; then + break + fi + done]) + ]) + case $ac_cv_prog_fc_real8 in #( + "none needed" | unsupported) + ;; #( + *) + REAL8_FCFLAGS=$ac_cv_prog_fc_real8 ;; + esac + fi + AC_SUBST(REAL8_FCFLAGS) +]) diff --git a/ac/m4/ax_mpi.m4 b/ac/m4/ax_mpi.m4 new file mode 100644 index 0000000000..ecce2e141a --- /dev/null +++ b/ac/m4/ax_mpi.m4 @@ -0,0 +1,176 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_mpi.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_MPI([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro tries to find out how to compile programs that use MPI +# (Message Passing Interface), a standard API for parallel process +# communication (see http://www-unix.mcs.anl.gov/mpi/) +# +# On success, it sets the MPICC, MPICXX, MPIF77, or MPIFC output variable +# to the name of the MPI compiler, depending upon the current language. +# (This may just be $CC/$CXX/$F77/$FC, but is more often something like +# mpicc/mpiCC/mpif77/mpif90.) It also sets MPILIBS to any libraries that +# are needed for linking MPI (e.g. -lmpi or -lfmpi, if a special +# MPICC/MPICXX/MPIF77/MPIFC was not found). +# +# Note that this macro should be used only if you just have a few source +# files that need to be compiled using MPI. In particular, you should +# neither overwrite CC/CXX/F77/FC with the values of +# MPICC/MPICXX/MPIF77/MPIFC, nor assume that you can use the same flags +# etc. as the standard compilers. If you want to compile a whole program +# using the MPI compiler commands, use one of the macros +# AX_PROG_{CC,CXX,FC}_MPI. +# +# ACTION-IF-FOUND is a list of shell commands to run if an MPI library is +# found, and ACTION-IF-NOT-FOUND is a list of commands to run if it is not +# found. If ACTION-IF-FOUND is not specified, the default action will +# define HAVE_MPI. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Julian C. Cummings +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 9 + +AU_ALIAS([ACX_MPI], [AX_MPI]) +AC_DEFUN([AX_MPI], [ +AC_PREREQ(2.50) dnl for AC_LANG_CASE + +AC_LANG_CASE([C], [ + AC_REQUIRE([AC_PROG_CC]) + AC_ARG_VAR(MPICC,[MPI C compiler command]) + AC_CHECK_PROGS(MPICC, mpicc cc hcc mpxlc_r mpxlc mpcc cmpicc, $CC) + ax_mpi_save_CC="$CC" + CC="$MPICC" + AC_SUBST(MPICC) +], +[C++], [ + AC_REQUIRE([AC_PROG_CXX]) + AC_ARG_VAR(MPICXX,[MPI C++ compiler command]) + AC_CHECK_PROGS(MPICXX, mpic++ mpicxx mpiCC hcp mpxlC_r mpxlC mpCC cmpic++, $CXX) + ax_mpi_save_CXX="$CXX" + CXX="$MPICXX" + AC_SUBST(MPICXX) +], +[Fortran 77], [ + AC_REQUIRE([AC_PROG_F77]) + AC_ARG_VAR(MPIF77,[MPI Fortran 77 compiler command]) + AC_CHECK_PROGS(MPIF77, mpif77 hf77 mpxlf_r mpxlf mpf77 cmpifc, $F77) + ax_mpi_save_F77="$F77" + F77="$MPIF77" + AC_SUBST(MPIF77) +], +[Fortran], [ + AC_REQUIRE([AC_PROG_FC]) + AC_ARG_VAR(MPIFC,[MPI Fortran compiler command]) + AC_CHECK_PROGS(MPIFC, mpifort mpif90 ftn mpxlf95_r mpxlf90_r mpxlf95 mpxlf90 mpf90 cmpif90c, $FC) + ax_mpi_save_FC="$FC" + FC="$MPIFC" + AC_SUBST(MPIFC) +]) + +if test x = x"$MPILIBS"; then + AC_LANG_CASE([C], [AC_CHECK_FUNC(MPI_Init, [MPILIBS=" "])], + [C++], [AC_CHECK_FUNC(MPI_Init, [MPILIBS=" "])], + [Fortran 77], [AC_MSG_CHECKING([for MPI_Init]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[ call MPI_Init])],[MPILIBS=" " + AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)])], + [Fortran], [AC_MSG_CHECKING([for MPI_Init]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[ call MPI_Init])],[MPILIBS=" " + AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)])]) +fi +AC_LANG_CASE([Fortran 77], [ + if test x = x"$MPILIBS"; then + AC_CHECK_LIB(fmpi, MPI_Init, [MPILIBS="-lfmpi"]) + fi + if test x = x"$MPILIBS"; then + AC_CHECK_LIB(fmpich, MPI_Init, [MPILIBS="-lfmpich"]) + fi +], +[Fortran], [ + if test x = x"$MPILIBS"; then + AC_CHECK_LIB(fmpi, MPI_Init, [MPILIBS="-lfmpi"]) + fi + if test x = x"$MPILIBS"; then + AC_CHECK_LIB(mpichf90, MPI_Init, [MPILIBS="-lmpichf90"]) + fi +]) +if test x = x"$MPILIBS"; then + AC_CHECK_LIB(mpi, MPI_Init, [MPILIBS="-lmpi"]) +fi +if test x = x"$MPILIBS"; then + AC_CHECK_LIB(mpich, MPI_Init, [MPILIBS="-lmpich"]) +fi + +dnl We have to use AC_TRY_COMPILE and not AC_CHECK_HEADER because the +dnl latter uses $CPP, not $CC (which may be mpicc). +AC_LANG_CASE([C], [if test x != x"$MPILIBS"; then + AC_MSG_CHECKING([for mpi.h]) + AC_TRY_COMPILE([#include ],[],[AC_MSG_RESULT(yes)], [MPILIBS="" + AC_MSG_RESULT(no)]) +fi], +[C++], [if test x != x"$MPILIBS"; then + AC_MSG_CHECKING([for mpi.h]) + AC_TRY_COMPILE([#include ],[],[AC_MSG_RESULT(yes)], [MPILIBS="" + AC_MSG_RESULT(no)]) +fi], +[Fortran 77], [if test x != x"$MPILIBS"; then + AC_MSG_CHECKING([for mpif.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[ include 'mpif.h'])],[AC_MSG_RESULT(yes)], [MPILIBS="" + AC_MSG_RESULT(no)]) +fi], +[Fortran], [if test x != x"$MPILIBS"; then + AC_MSG_CHECKING([for mpif.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[ include 'mpif.h'])],[AC_MSG_RESULT(yes)], [MPILIBS="" + AC_MSG_RESULT(no)]) +fi]) + +AC_LANG_CASE([C], [CC="$ax_mpi_save_CC"], + [C++], [CXX="$ax_mpi_save_CXX"], + [Fortran 77], [F77="$ax_mpi_save_F77"], + [Fortran], [FC="$ax_mpi_save_FC"]) + +AC_SUBST(MPILIBS) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x = x"$MPILIBS"; then + $2 + : +else + ifelse([$1],,[AC_DEFINE(HAVE_MPI,1,[Define if you have the MPI library.])],[$1]) + : +fi +])dnl AX_MPI