From fd8317a1151f8f31599f4b754025c026a2d367b8 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Fri, 8 Apr 2022 21:23:09 -0400 Subject: [PATCH 1/2] Adds "makedep" script to replace mkmf `mkmf` is an external dependency that that uses a multi-stage approach to building a Makefile with dependencies but fails to yield an optimal link stage (it links everything, including unused modules). `makedep` is a bash script that constructs the link stage for as many programs as found, links only the necessary object files*, and is coded solely in bash thus removing an external dependency. The addition of this script is the bulk of this commit. Code changes: - when more than one program is encountered the executable is given the name following "program". Since all the programs were named "MOM_main" I have had to change them to provide unique names: - MOM_sum_driver.F90, "program MOM_main" has been changed to "MOM_sum_driver" - solo_driver/MOM_driver.F90, "program MOM_main" has been changed to "MOM6" Script changes: - Makefile.in now has a target "depend" to generate dependencies using makedep - configure.ac no longer checks for list_paths and mkmf - configure.ac now invokes "make depend" in place of mkmf - Added target "unit" to .testing/Makefile to build all programs in config_src/drivers/unit_drivers Ugliness: - I had to add a -f option to makedep to handle FMS non-standard macros - To compile FMS, the dependencies Makefile is passed CPPDEFS in addition to CPPFLAGS. - The first version of makedep was consistent with the standard gmake rules which were sufficient to build MOM6. Adding -f "rule command" allows FMS to be built: makemake -f '$(FC) $(FFLAGS) $(CPPFLAGS) $(CPPDEFS) -c $<' -x libFMS.a ../src - .inc suffix is included when searching for include directories - FMS has includes of .inc files which modify the search path passed to /lib/cpp . - Handling of badly formatted comments when searching for modules - FMS fm_util.F90, that generates fm_util_mod.mod, has some odd strings in a comment on the module declaration line. This was causing wierdness in the script. - Not just Fortran dependencies - makedep needs to also generate rules for C files in order to build FMS Todo: [ ] *A work around is used for TEOS10 (gsw_*) functions that are in separate object files even though accessed via a module (WTFortran!!!) --- .testing/Makefile | 19 +- ac/Makefile.in | 10 +- ac/configure.ac | 43 +--- ac/deps/Makefile | 21 +- ac/deps/Makefile.fms.in | 8 +- ac/deps/configure.fms.ac | 36 +-- ac/makedep | 225 ++++++++++++++++++ config_src/drivers/solo_driver/MOM_driver.F90 | 4 +- .../drivers/unit_drivers/MOM_sum_driver.F90 | 4 +- 9 files changed, 262 insertions(+), 108 deletions(-) create mode 100755 ac/makedep diff --git a/.testing/Makefile b/.testing/Makefile index d9feb25f0b..6e61ec8f39 100644 --- a/.testing/Makefile +++ b/.testing/Makefile @@ -119,10 +119,6 @@ DIMS ?= t l h z q r # Dependencies DEPS = deps -# mkmf, list_paths (GFDL build toolchain) -LIST_PATHS := $(DEPS)/bin/list_paths -MKMF := $(DEPS)/bin/mkmf - #--- # Test configuration @@ -295,7 +291,7 @@ build/%/MOM6: build/%/Makefile # 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) +build/%/Makefile: ../ac/configure ../ac/Makefile.in $(DEPS)/lib/libFMS.a mkdir -p $(@D) cd $(@D) \ && $(MOM_ENV) ../../../ac/configure $(MOM_ACFLAGS) --with-framework=$(FRAMEWORK) \ @@ -308,7 +304,7 @@ build/%/Makefile: ../ac/configure ../ac/Makefile.in $(DEPS)/lib/libFMS.a $(MKMF) # Fetch the regression target codebase build/target/Makefile build/opt_target/Makefile: \ - $(TARGET_CODEBASE)/ac/configure $(DEPS)/lib/libFMS.a $(MKMF) $(LIST_PATHS) + $(TARGET_CODEBASE)/ac/configure $(DEPS)/lib/libFMS.a mkdir -p $(@D) cd $(@D) \ && $(MOM_ENV) ../../$(TARGET_CODEBASE)/ac/configure $(MOM_ACFLAGS) \ @@ -337,7 +333,7 @@ $(DEPS)/lib/libFMS.a: $(DEPS)/fms/build/libFMS.a $(DEPS)/fms/build/libFMS.a: $(DEPS)/fms/build/Makefile $(MAKE) -C $(DEPS) fms/build/libFMS.a -$(DEPS)/fms/build/Makefile: $(DEPS)/fms/src/configure $(DEPS)/Makefile.fms.in $(MKMF) $(LIST_PATHS) +$(DEPS)/fms/build/Makefile: $(DEPS)/fms/src/configure $(DEPS)/Makefile.fms.in $(FMS_ENV) $(MAKE) -C $(DEPS) fms/build/Makefile $(MAKE) -C $(DEPS) fms/build/Makefile @@ -353,13 +349,6 @@ $(DEPS)/fms/src/configure: ../ac/deps/configure.fms.ac $(DEPS)/Makefile $(FMS_SO $(DEPS)/fms/src: $(DEPS)/Makefile make -C $(DEPS) fms/src -# mkmf -$(MKMF) $(LIST_PATHS): $(DEPS)/mkmf - $(MAKE) -C $(DEPS) bin/$(@F) - -$(DEPS)/mkmf: $(DEPS)/Makefile - $(MAKE) -C $(DEPS) mkmf - # Dependency init $(DEPS)/Makefile: ../ac/deps/Makefile mkdir -p $(@D) @@ -693,7 +682,7 @@ test.summary: .PHONY: unit.cov unit.cov: build/unit/MOM_new_unit_tests.gcov -work/unit/std.out: build/unit/MOM6 +work/unit/std.out: build/unit/MOM_unit_tests if [ $(REPORT_COVERAGE) ]; then \ find build/unit -name *.gcda -exec rm -f '{}' \; ; \ fi diff --git a/ac/Makefile.in b/ac/Makefile.in index 7be6c5bf2b..711fab1f6f 100644 --- a/ac/Makefile.in +++ b/ac/Makefile.in @@ -51,11 +51,16 @@ CPPFLAGS = @CPPFLAGS@ FFLAGS = @FCFLAGS@ LDFLAGS = @LDFLAGS@ @LIBS@ +SRC_DIRS = @SRC_DIRS@ + # Gather modulefiles TMPFILES = $(wildcard *.mod) -include Makefile.mkmf +-include Makefile.dep +.PHONY: depend +depend: + ../../../ac/makedep -o Makefile.dep $(SRC_DIRS) # Delete any files associated with configuration (including the Makefile). .PHONY: distclean @@ -64,9 +69,8 @@ distclean: clean rm -f config.log rm -f config.status rm -f Makefile - # mkmf output rm -f path_names - rm -f Makefile.mkmf + rm -f Makefile.dep # This deletes all files generated by autoconf, including configure. diff --git a/ac/configure.ac b/ac/configure.ac index 00c8917734..02e39c63a0 100644 --- a/ac/configure.ac +++ b/ac/configure.ac @@ -223,46 +223,13 @@ AC_COMPILE_IFELSE( ] ) - -# 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 \ - ${MODEL_FRAMEWORK} \ - ${srcdir}/config_src/ext* \ - ${DRIVER_DIR} \ - ${MEM_LAYOUT}], - [MODEL_FRAMEWORK=$MODEL_FRAMEWORK - MEM_LAYOUT=$MEM_LAYOUT - DRIVER_DIR=$DRIVER_DIR] -) - - -AC_CONFIG_COMMANDS([Makefile.mkmf], - [mkmf -p MOM6 -m Makefile.mkmf path_names]) - +SRC_DIRS="${srcdir}/src ${MODEL_FRAMEWORK} ${srcdir}/config_src/external ${DRIVER_DIR} ${MEM_LAYOUT}" +AC_CONFIG_COMMANDS([Makefile.dep], + [make depend]) # Prepare output AC_SUBST(CPPFLAGS) +AC_SUBST(SRC_DIRS) AC_CONFIG_FILES([Makefile:${srcdir}/ac/Makefile.in]) AC_OUTPUT + diff --git a/ac/deps/Makefile b/ac/deps/Makefile index 0ed4fd19a7..f56b762883 100644 --- a/ac/deps/Makefile +++ b/ac/deps/Makefile @@ -7,10 +7,6 @@ SHELL = bash MAKEFLAGS += -R -# 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 @@ -30,19 +26,14 @@ FMS_SOURCE = $(call SOURCE,fms/src) # Rules .PHONY: all -all: bin/mkmf bin/list_paths lib/libFMS.a +all: bin/makedep lib/libFMS.a #--- -# mkmf checkout +# makedep script -bin/mkmf bin/list_paths: mkmf +bin/makedep: ../../ac/makedep mkdir -p $(@D) - cp $^/$@ $@ - -mkmf: - git clone $(MKMF_URL) $@ - git -C $@ checkout $(MKMF_COMMIT) - + cp $^ $@ #--- # FMS build @@ -64,7 +55,7 @@ fms/build/libFMS.a: fms/build/Makefile make -C fms/build libFMS.a -fms/build/Makefile: Makefile.fms.in fms/src/configure bin/mkmf bin/list_paths +fms/build/Makefile: Makefile.fms.in fms/src/configure bin/makedep mkdir -p fms/build cp Makefile.fms.in fms/src/Makefile.in cd $(@D) && ../src/configure --srcdir=../src @@ -87,4 +78,4 @@ clean: .PHONY: distclean distclean: clean - rm -rf fms mkmf + rm -rf fms diff --git a/ac/deps/Makefile.fms.in b/ac/deps/Makefile.fms.in index 0286d94b58..499a1a6a72 100644 --- a/ac/deps/Makefile.fms.in +++ b/ac/deps/Makefile.fms.in @@ -54,7 +54,13 @@ FFLAGS = @FCFLAGS@ LDFLAGS = @LDFLAGS@ ARFLAGS = @ARFLAGS@ +SRC_DIRS = @SRC_DIRS@ + # Gather modulefiles TMPFILES = $(wildcard *.mod) -include Makefile.mkmf +-include Makefile.dep + +.PHONY: depend +depend: + ../../bin/makedep -o Makefile.dep -f '$$(FC) $$(CPPFLAGS) $$(CPPDEFS) $$(FFLAGS) -c $$<' -x libFMS.a -d $(SRC_DIRS) diff --git a/ac/deps/configure.fms.ac b/ac/deps/configure.fms.ac index bf899126cc..4dc1a6614f 100644 --- a/ac/deps/configure.fms.ac +++ b/ac/deps/configure.fms.ac @@ -158,38 +158,6 @@ 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}] -) - # Autoconf does not configure the archiver (ar), as it is handled by Automake. # TODO: Properly configure this tool. For now, we hard-set this to `ar`. @@ -198,8 +166,12 @@ ARFLAGS=rv AC_SUBST(AR) AC_SUBST(ARFLAGS) +SRC_DIRS="../src" +AC_CONFIG_COMMANDS([Makefile.dep], + [make depend]) # Prepare output AC_SUBST(CPPFLAGS) +AC_SUBST(SRC_DIRS) AC_CONFIG_FILES(Makefile) AC_OUTPUT diff --git a/ac/makedep b/ac/makedep new file mode 100755 index 0000000000..cb0a8896e3 --- /dev/null +++ b/ac/makedep @@ -0,0 +1,225 @@ +#!/bin/bash + +usage() { + echo "Construct Makfile.dep containing dependencies for F90 source code." + echo + echo "Syntax:" $0 "[-h|d] [-o FILE] [-x EXEC] PATH [PATH] [...]" + echo + echo "arguments:" + echo " PATH Directories containing source code. All subdirectories and" + echo " symbolic links are followed." + echo + echo "options:" + echo " -h Print this help message." + echo " -d Annotate the makefile with extra information." + echo " -o FILE Construct dependencies in FILE instead of Makefile.dep ." + echo " -x EXEC Name of executable to build. Fails if more than one" + echo " is found. If EXEC ends in .a then a library is built." + echo " -f CMD String to use in compile rule. Default is:" + echo " '$(FC) $(FFLAGS) $(CPPFLAGS) -c $<'" +} + +# Defaults +makefile=Makefile.dep +debug=0 +executable="" +librarymode=0 +compile_line='$(FC) $(FFLAGS) $(CPPFLAGS) -c $<' + +while getopts dho:x:f: option +do + case "${option}" + in + d)debug=1;; + h)usage; exit;; + o)makefile=${OPTARG};; + x)executable=${OPTARG};; + f)compile_line=${OPTARG};; + esac +done +SRC_DIRS=${@:$OPTIND} + +if [ -z "$SRC_DIRS" ]; then + echo "Error: no search path specified on command line!" + exit 1 +fi + +# Scan everything (Fortran related) (Fortran related) +A=$(find -L ${SRC_DIRS} \( -name "*.F90" -o -name "*.f90" \) ) # all source files +I=`find -L ${SRC_DIRS} \( -name "*.h" -o -name "*.inc" \) | xargs dirname | sort | uniq | sed 's:^:-I:'` # include paths to pass to cpp when checking to see which .h files are used +O=() +externals=() +declare -A o2src o2mod o2use o2H o2head o2inc p2o o2p all_modules +for F in ${A}; do # F is the relative path to source file + f=`basename $F` # file name stripped of path + o=${f/.?90/}.o # object file name + o2src["$o"]=$F + m=`egrep -i "^ *module " $F | sed 's/ *!.*//' | grep -vi procedure | tr '[A-Z]' '[a-z]' | sed 's/.*module *//' | tr -d '\r' | sed 's/$/.mod/' ` # name of module file(s) #### FAILS IF NO MODULE, DOES IT WORK FOR 2+? + u=`sed 's/!.*//' $F | egrep -i "^ *use " | sed 's/\ *[uU][sS][eE]\ *\([a-zA-Z_0-9]*\).*/\1.mod/' | tr '[A-Z]' '[a-z]' | egrep -v "mpi.mod|iso_fortran_env.mod" | sort | uniq ` # list of modules used + if [ ${#m} -ne 0 ]; then + o2mod["$o"]=$m + u=`echo $u | sed s:$m::g` + fi + if [ ${#u} -ne 0 ]; then o2use["$o"]=$u; fi + H=$(/lib/cpp -E -MM $I $F | tr -d '\n' | sed 's:\\::g') # line of form a.o: a.F b.h c.h ... + o2H["$o"]=$H + h=`echo ${H} | cut -d\ -f3- ` # header files + if [ ${#h} -ne 0 ]; then o2head["$o"]=$h; fi + i=`dirname _ignore_/ignore ${h} | grep -v _ignore_ | sort | uniq | sed 's:^:-I:'` # includes for compilation + if [ ${#i} -ne 0 ]; then o2inc["$o"]=$i; fi + p=`egrep -i "^ *program " $F | awk '{print $2}'` # name of program if any + if [ $librarymode -eq 0 ]; then + O+=($o) # List of all objects + if [ ${#p} -ne 0 ]; then p2o["$p"]=$o; o2p["$o"]=$p; fi + else + if [ ${#p} -eq 0 ]; then O+=($o); fi + fi + if [ ${#m} -ne 0 ]; then + for mm in $m; do all_modules["$mm"]=1; done + else + if [ ${#p} -eq 0 ]; then + externals+=($o) + fi + fi +done + +# Augment with C files +A=$(find -L ${SRC_DIRS} -name "*.c" ) # all C source files +declare -A o2c +OC=() +for F in ${A}; do # F is the relative path to source file + f=`basename $F` # file name stripped of path + o=${f/.c/}.o # object file name + o2c["$o"]=$F + H=$(/lib/cpp -E -MM $I $F | tr -d '\n' | sed 's:\\::g') # line of form a.o: a.F b.h c.h ... + o2H["$o"]=$H + h=`echo ${H} | cut -d\ -f3- ` # header files + if [ ${#h} -ne 0 ]; then o2head["$o"]=$h; fi + i=`dirname _ignore_/ignore ${h} | grep -v _ignore_ | sort | uniq | sed 's:^:-I:'` # includes for compilation + if [ ${#i} -ne 0 ]; then o2inc["$o"]=$i; fi + OC+=($o) # List of all objects + #externals+=($o) +done + +if [[ "$executable" == *\.a ]]; then + lib=$executable +else + lib="" + if [ -n "$executable" ]; then + if [ ${#p2o[@]} -eq 0 ]; then + echo 'Error: Option "-p' $executable'"' provided but no programs are present. + exit 1 + elif [ ${#p2o[@]} -eq 1 ]; then # rename executable + p="${o2p[@]}" + o=${p2o[@]} + unset p2o["$p"] + p2o["$executable"]=$o + o2p["$o"]=$executable + else + echo 'Error: Option "-p' $executable'"' cannot be used when multiple programs are present. + exit 1 + fi + fi +fi + +# Write the new makefile +rm -f ${makefile} +echo "#" ${makefile} "created by makedep" >> ${makefile} +echo >> ${makefile} +echo "all:" $lib ${!p2o[@]} >> ${makefile} +echo >> ${makefile} + +echo "# SRC_DIRS is usually set in the parent Makefile but in case is it not we" >> ${makefile} +echo "# record it here from when makedep was previously invoked." >> ${makefile} +echo "SRC_DIRS ?= ${SRC_DIRS}" >> ${makefile} +echo >> ${makefile} + +# Write rule for each object from Fortran +for o in ${O[@]}; do + F=${o2src["$o"]} # source file + m=${o2mod["$o"]} # modules produced with object file + u=${o2use["$o"]} # modules used/needed by object file + H=${o2H["$o"]} # basic C-style rule produced by cpp + i=${o2inc["$o"]} # -I paths needed at compilation + U=() # modules used that are in source tree + NU=() # modules used that were not found in source tree + if [ ${#u} -ne 0 ]; then + for uu in ${u}; do + if [[ ${all_modules["$uu"]} ]]; then + U+=($uu) # source for used module was found + else + NU+=($uu) # did not find source for module + fi + done + fi + if [ $debug -eq 1 ]; then + h=${o2head["$o"]} + p=${o2p["$o"]} + echo "# Source file" $F "produces:" >> ${makefile} + echo "# object:" $o >> ${makefile} + echo "# modules:" $m >> ${makefile} + echo "# uses:" $u >> ${makefile} + echo "# found:" ${U[@]} >> ${makefile} + echo "# missing:" ${NU[@]} >> ${makefile} + echo "# includes:" $h >> ${makefile} + echo "# incpath:" $i >> ${makefile} + echo "# program:" $p >> ${makefile} + fi + + if [ ${#m} -ne 0 ]; then + if [ ${#NU[@]} -ne 0 ]; then + echo "# Note:" $o "uses modules not found the search path:" ${NU[@]} >> ${makefile} + fi + echo $m":" $o >> ${makefile} # a.mod: a.o + fi + echo $H ${U[@]} >> ${makefile} # a.mod a.o: a.F b.mod + echo -e '\t'$compile_line ${i} >> ${makefile} # compile rule +done + +# Write rule for each object from C +for o in ${OC[@]}; do + F=${o2c["$o"]} # source file + H=${o2H["$o"]} # basic C-style rule produced by cpp + i=${o2inc["$o"]} # -I paths needed at compilation + if [ $debug -eq 1 ]; then + h=${o2head["$o"]} + echo "# Source file" $F "produces:" >> ${makefile} + echo "# object:" $o >> ${makefile} + echo "# includes:" $h >> ${makefile} + echo "# incpath:" $i >> ${makefile} + fi + echo $H ${U[@]} >> ${makefile} # a.mod a.o: a.F b.mod + echo -e '\t$(CC) $(CPPDEFS) $(CPPFLAGS) $(CFLAGS) -c $<' ${i} >> ${makefile} # compile rule +done + +if [ ${#lib} -ne 0 ]; then # rule to build library + echo >> ${makefile} + echo $lib: ${O[@]} ${OC[@]} >> ${makefile} + echo -e '\t$(AR) $(ARFLAGS) $@ $^' >> ${makefile} # archive rule +fi + +if [ ${#p2o[@]} -ne 0 ]; then # write rules for linking executables + echo >> ${makefile} + echo "# Note: The following object files are not associated with modules so we assume we should link with them:" ${externals[@]} >> ${makefile} + + echo >> ${makefile} + for p in ${!p2o[@]}; do # p is the executable name + o=${p2o[$p]} + l=$(make -f ${makefile} -B -n -t $o | egrep "\.o$" | sed 's:touch ::' | sort) + echo $p: $l ${externals[@]} >> ${makefile} + echo -e '\t$(LD) -o $@ $^ $(LDFLAGS)' >> ${makefile} # link rule + done +elif [ -z "$lib" ]; then + echo "Warning: no library target specified (with -x) and no programs found!" + echo "Created target 'obj': use 'make obj' to compile object files." + echo >> ${makefile} + echo "obj: ${O[@]}" >> ${makefile} +fi + +echo >> ${makefile} +echo clean: >> ${makefile} + echo -e '\trm -rf' ${!p2o[@]} $lib '*.o *.mod' >> ${makefile} # compile rule + +echo >> ${makefile} +echo "remakedep: # re-invoke makedep" >> ${makefile} +echo -e '\t' $0 -o ${makefile} '$(SRC_DIRS)' >> ${makefile} diff --git a/config_src/drivers/solo_driver/MOM_driver.F90 b/config_src/drivers/solo_driver/MOM_driver.F90 index d6630a0f17..e60240d359 100644 --- a/config_src/drivers/solo_driver/MOM_driver.F90 +++ b/config_src/drivers/solo_driver/MOM_driver.F90 @@ -1,4 +1,4 @@ -program MOM_main +program MOM6 ! This file is part of MOM6. See LICENSE.md for the license. @@ -692,4 +692,4 @@ subroutine initialize_ocean_only_ensembles() endif end subroutine initialize_ocean_only_ensembles -end program MOM_main +end program MOM6 diff --git a/config_src/drivers/unit_drivers/MOM_sum_driver.F90 b/config_src/drivers/unit_drivers/MOM_sum_driver.F90 index 9f3950ac7f..f962719d93 100644 --- a/config_src/drivers/unit_drivers/MOM_sum_driver.F90 +++ b/config_src/drivers/unit_drivers/MOM_sum_driver.F90 @@ -1,4 +1,4 @@ -program MOM_main +program MOM_sum_driver ! This file is part of MOM6. See LICENSE.md for the license. @@ -215,4 +215,4 @@ subroutine benchmark_init_topog_local(D, G, param_file, max_depth) end subroutine benchmark_init_topog_local -end program MOM_main +end program MOM_sum_driver From f7d0f9ced890fff68b1cc6544a1528e1182aef8f Mon Sep 17 00:00:00 2001 From: Marshall Ward Date: Tue, 14 Jun 2022 16:51:29 -0400 Subject: [PATCH 2/2] Makedep (#1) * Autoconf: Fix makedep path The current path of makedep in the autoconf build assumes a directory tree as in .testing. This patch uses the generalized @srcdir@ to support more general autoconf builds. Other minor changes: * The `depend` rule was split into an explicit Makefile.dep rule and a phony rule to support `make depend` * SRC_DIRS shell assignment is replaced with an Autoconf macro. * A "self-generate" rule was added to `Makefile.in`, so that changes to `Makefile.in` do not trigger a full `./configure` run and regeneration of `.config.status`. This could possibly be extended to support `make depend` but let's first see how this one goes. * Autoconf: makedep uses autoconf var conventions This patch changes the makedep script to use autoconf environment variable conventions rather than mkmf ones: * FCFLAGS in place of FFLAGS * DEFS in place of CPPDEFS * LDFLAGS and LIBS rather than just LDFLAGS (NOTE: This differs from Makefile's LDLFLAGS/LDLIBS) This also allowed us to remove the custom build rule in the FMS build. Note that we now use an autoconf-friendly rule, rather than the default Makefile rule (which was arguably for fixed-format Fortran anyway). The description of autoconf->mkmf translation from the Makefile templates has also been removed, since they're no longer relevant. Some other minor changes in this build: * The `make depend` rule was added to the FMS Makefile template. * @srcdir@ is directly passed to FMS makedep, rather than identically re-defining it in a variable. * Testing: Resolve makedep paths This patch resolves some issues relating to finding the path to makedep in both .testing and more generalized autoconf builds. An explicit autoconf test for makedep has been added, with a default path which includes the `ac` directory relative to `deps`. The .testing directory, which does not lie within `ac`, instead modifies the PATH to allow autoconf to find makedep. The absolute path is determined and substituted into the appropriate Makefile.in template. Some redundant operations in .testing/Makefile have been removed, but I suspect there are even more. Much of the structure required to support mkmf and list_paths is probably no longer needed. --- .testing/Makefile | 3 +- ac/Makefile.in | 65 +++++++++++----------------------------- ac/configure.ac | 17 +++++++---- ac/deps/Makefile | 16 ++++------ ac/deps/Makefile.fms.in | 59 ++++++------------------------------ ac/deps/configure.fms.ac | 22 +++++++++----- ac/makedep | 12 ++++---- 7 files changed, 64 insertions(+), 130 deletions(-) diff --git a/.testing/Makefile b/.testing/Makefile index 6e61ec8f39..972c213032 100644 --- a/.testing/Makefile +++ b/.testing/Makefile @@ -324,7 +324,7 @@ $(TARGET_CODEBASE): # FMS # Set up the FMS build environment variables -FMS_ENV = PATH="${PATH}:../../bin" FCFLAGS="$(FCFLAGS_DEBUG)" +FMS_ENV = PATH="${PATH}:$(realpath ../ac)" FCFLAGS="$(FCFLAGS_DEBUG)" # TODO: *.mod dependencies? $(DEPS)/lib/libFMS.a: $(DEPS)/fms/build/libFMS.a @@ -335,7 +335,6 @@ $(DEPS)/fms/build/libFMS.a: $(DEPS)/fms/build/Makefile $(DEPS)/fms/build/Makefile: $(DEPS)/fms/src/configure $(DEPS)/Makefile.fms.in $(FMS_ENV) $(MAKE) -C $(DEPS) fms/build/Makefile - $(MAKE) -C $(DEPS) fms/build/Makefile $(DEPS)/Makefile.fms.in: ../ac/deps/Makefile.fms.in $(DEPS)/Makefile cp $< $(DEPS) diff --git a/ac/Makefile.in b/ac/Makefile.in index 711fab1f6f..2e482ab0c5 100644 --- a/ac/Makefile.in +++ b/ac/Makefile.in @@ -2,65 +2,34 @@ # # 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 -# AR Archiver -# -# 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 -# ARFLAGS Archiver 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 -# TMPFILES Placeholder for `make clean` deletion (as `make neat`). -# -# -# 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. +# Source code dependencies are configured by makedep and saved to Makefile.dep. FC = @FC@ LD = @FC@ +MAKEDEP = @MAKEDEP@ -CPPDEFS = @DEFS@ +DEFS = @DEFS@ CPPFLAGS = @CPPFLAGS@ -FFLAGS = @FCFLAGS@ -LDFLAGS = @LDFLAGS@ @LIBS@ - +FCFLAGS = @FCFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ SRC_DIRS = @SRC_DIRS@ -# Gather modulefiles -TMPFILES = $(wildcard *.mod) -include Makefile.dep + +# Generate Makefile from template +Makefile: @srcdir@/ac/Makefile.in config.status + ./config.status + + +# Generate dependencies .PHONY: depend -depend: - ../../../ac/makedep -o Makefile.dep $(SRC_DIRS) +depend: Makefile.dep +Makefile.dep: + $(MAKEDEP) -o Makefile.dep $(SRC_DIRS) + # Delete any files associated with configuration (including the Makefile). .PHONY: distclean diff --git a/ac/configure.ac b/ac/configure.ac index 02e39c63a0..15a14708e0 100644 --- a/ac/configure.ac +++ b/ac/configure.ac @@ -223,13 +223,20 @@ AC_COMPILE_IFELSE( ] ) -SRC_DIRS="${srcdir}/src ${MODEL_FRAMEWORK} ${srcdir}/config_src/external ${DRIVER_DIR} ${MEM_LAYOUT}" -AC_CONFIG_COMMANDS([Makefile.dep], - [make depend]) + +# Verify that makedep is available +AC_PATH_PROG([MAKEDEP], [makedep], [${srcdir}/ac/makedep]) +AC_SUBST([MAKEDEP]) + + +# Generate source list and configure dependency command +AC_SUBST([SRC_DIRS], + ["${srcdir}/src ${MODEL_FRAMEWORK} ${srcdir}/config_src/external ${DRIVER_DIR} ${MEM_LAYOUT}"] +) +AC_CONFIG_COMMANDS([Makefile.dep], [make depend]) # Prepare output -AC_SUBST(CPPFLAGS) -AC_SUBST(SRC_DIRS) +AC_SUBST([CPPFLAGS]) AC_CONFIG_FILES([Makefile:${srcdir}/ac/Makefile.in]) AC_OUTPUT diff --git a/ac/deps/Makefile b/ac/deps/Makefile index f56b762883..af567f6a72 100644 --- a/ac/deps/Makefile +++ b/ac/deps/Makefile @@ -6,7 +6,6 @@ SHELL = bash # Disable implicit variables MAKEFLAGS += -R - # FMS framework FMS_URL ?= https://github.com/NOAA-GFDL/FMS.git FMS_COMMIT ?= 2019.01.03 @@ -26,14 +25,8 @@ FMS_SOURCE = $(call SOURCE,fms/src) # Rules .PHONY: all -all: bin/makedep lib/libFMS.a - -#--- -# makedep script +all: lib/libFMS.a -bin/makedep: ../../ac/makedep - mkdir -p $(@D) - cp $^ $@ #--- # FMS build @@ -45,7 +38,7 @@ bin/makedep: ../../ac/makedep # TODO: track *.mod copy? -lib/libFMS.a: fms/build/libFMS.a fms/build/Makefile +lib/libFMS.a: fms/build/libFMS.a mkdir -p {lib,include} cp fms/build/libFMS.a lib/libFMS.a cp fms/build/*.mod include @@ -55,7 +48,7 @@ fms/build/libFMS.a: fms/build/Makefile make -C fms/build libFMS.a -fms/build/Makefile: Makefile.fms.in fms/src/configure bin/makedep +fms/build/Makefile: Makefile.fms.in fms/src/configure mkdir -p fms/build cp Makefile.fms.in fms/src/Makefile.in cd $(@D) && ../src/configure --srcdir=../src @@ -67,6 +60,7 @@ fms/src/configure: configure.fms.ac $(FMS_SOURCE) | fms/src cp -r m4 $(@D) cd $(@D) && autoreconf -i + fms/src: git clone $(FMS_URL) $@ git -C $@ checkout $(FMS_COMMIT) @@ -74,7 +68,7 @@ fms/src: .PHONY: clean clean: - rm -rf fms/build lib include bin + rm -rf fms/build lib include .PHONY: distclean distclean: clean diff --git a/ac/deps/Makefile.fms.in b/ac/deps/Makefile.fms.in index 499a1a6a72..fc580a8c9e 100644 --- a/ac/deps/Makefile.fms.in +++ b/ac/deps/Makefile.fms.in @@ -1,66 +1,25 @@ -# Makefile template for autoconf builds using mkmf +# Makefile template for FMS # # 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 -# AR Archiver -# -# 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 -# ARFLAGS Archiver 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 -# TMPFILES Placeholder for `make clean` deletion (as `make neat`). -# -# -# 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. +# Source code dependencies are configured by makedep and saved to Makefile.dep. CC = @CC@ FC = @FC@ LD = @FC@ AR = @AR@ +MAKEDEP = @MAKEDEP@ -CPPDEFS = @DEFS@ +DEFS = @DEFS@ CPPFLAGS = @CPPFLAGS@ -FFLAGS = @FCFLAGS@ +FCFLAGS = @FCFLAGS@ LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ ARFLAGS = @ARFLAGS@ -SRC_DIRS = @SRC_DIRS@ - -# Gather modulefiles -TMPFILES = $(wildcard *.mod) - -include Makefile.dep .PHONY: depend -depend: - ../../bin/makedep -o Makefile.dep -f '$$(FC) $$(CPPFLAGS) $$(CPPDEFS) $$(FFLAGS) -c $$<' -x libFMS.a -d $(SRC_DIRS) +depend: Makefile.dep +Makefile.dep: + $(MAKEDEP) -o Makefile.dep -x libFMS.a @srcdir@ diff --git a/ac/deps/configure.fms.ac b/ac/deps/configure.fms.ac index 4dc1a6614f..4e0c0f1390 100644 --- a/ac/deps/configure.fms.ac +++ b/ac/deps/configure.fms.ac @@ -158,20 +158,26 @@ AX_FC_ALLOW_ARG_MISMATCH FCFLAGS="$FCFLAGS $ALLOW_ARG_MISMATCH_FCFLAGS" +# Verify makedep +AC_PATH_PROGS([MAKEDEP], [makedep], [], ["${PATH}:${srcdir}/../../.."]) +AS_IF([test -n "${MAKEDEP}"], [ + AC_SUBST([MAKEDEP]) +], [ + AC_MSG_ERROR(["Could not find makedep."]) +]) + # Autoconf does not configure the archiver (ar), as it is handled by Automake. # TODO: Properly configure this tool. For now, we hard-set this to `ar`. AR=ar ARFLAGS=rv -AC_SUBST(AR) -AC_SUBST(ARFLAGS) +AC_SUBST([AR]) +AC_SUBST([ARFLAGS]) + +AC_CONFIG_COMMANDS([Makefile.dep], [make depend]) -SRC_DIRS="../src" -AC_CONFIG_COMMANDS([Makefile.dep], - [make depend]) +AC_SUBST([CPPFLAGS]) # Prepare output -AC_SUBST(CPPFLAGS) -AC_SUBST(SRC_DIRS) -AC_CONFIG_FILES(Makefile) +AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/ac/makedep b/ac/makedep index cb0a8896e3..74d9200ce8 100755 --- a/ac/makedep +++ b/ac/makedep @@ -16,7 +16,7 @@ usage() { echo " -x EXEC Name of executable to build. Fails if more than one" echo " is found. If EXEC ends in .a then a library is built." echo " -f CMD String to use in compile rule. Default is:" - echo " '$(FC) $(FFLAGS) $(CPPFLAGS) -c $<'" + echo " '$(FC) $(DEFS) $(FCFLAGS) $(CPPFLAGS) -c $<'" } # Defaults @@ -24,7 +24,7 @@ makefile=Makefile.dep debug=0 executable="" librarymode=0 -compile_line='$(FC) $(FFLAGS) $(CPPFLAGS) -c $<' +compile_line='$(FC) $(DEFS) $(FCFLAGS) $(CPPFLAGS) -c $<' while getopts dho:x:f: option do @@ -61,7 +61,7 @@ for F in ${A}; do # F is the relative path to source file u=`echo $u | sed s:$m::g` fi if [ ${#u} -ne 0 ]; then o2use["$o"]=$u; fi - H=$(/lib/cpp -E -MM $I $F | tr -d '\n' | sed 's:\\::g') # line of form a.o: a.F b.h c.h ... + H=$(cpp -E -MM $I $F | tr -d '\n' | sed 's:\\::g') # line of form a.o: a.F b.h c.h ... o2H["$o"]=$H h=`echo ${H} | cut -d\ -f3- ` # header files if [ ${#h} -ne 0 ]; then o2head["$o"]=$h; fi @@ -91,7 +91,7 @@ for F in ${A}; do # F is the relative path to source file f=`basename $F` # file name stripped of path o=${f/.c/}.o # object file name o2c["$o"]=$F - H=$(/lib/cpp -E -MM $I $F | tr -d '\n' | sed 's:\\::g') # line of form a.o: a.F b.h c.h ... + H=$(cpp -E -MM $I $F | tr -d '\n' | sed 's:\\::g') # line of form a.o: a.F b.h c.h ... o2H["$o"]=$H h=`echo ${H} | cut -d\ -f3- ` # header files if [ ${#h} -ne 0 ]; then o2head["$o"]=$h; fi @@ -189,7 +189,7 @@ for o in ${OC[@]}; do echo "# incpath:" $i >> ${makefile} fi echo $H ${U[@]} >> ${makefile} # a.mod a.o: a.F b.mod - echo -e '\t$(CC) $(CPPDEFS) $(CPPFLAGS) $(CFLAGS) -c $<' ${i} >> ${makefile} # compile rule + echo -e '\t$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $<' ${i} >> ${makefile} # compile rule done if [ ${#lib} -ne 0 ]; then # rule to build library @@ -207,7 +207,7 @@ if [ ${#p2o[@]} -ne 0 ]; then # write rules for linking executables o=${p2o[$p]} l=$(make -f ${makefile} -B -n -t $o | egrep "\.o$" | sed 's:touch ::' | sort) echo $p: $l ${externals[@]} >> ${makefile} - echo -e '\t$(LD) -o $@ $^ $(LDFLAGS)' >> ${makefile} # link rule + echo -e '\t$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)' >> ${makefile} # link rule done elif [ -z "$lib" ]; then echo "Warning: no library target specified (with -x) and no programs found!"