From e2478f1fc6341f386b2f7070db8b36e975d25aab Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 7 Jun 2019 15:16:18 -0600 Subject: [PATCH 01/48] Make mpas-ocean build using CMake! [BFB] --- components/mpas-ocean/cime_config/buildlib | 146 ++++++++++----------- components/mpas-ocean/driver/Makefile | 27 ---- 2 files changed, 70 insertions(+), 103 deletions(-) delete mode 100644 components/mpas-ocean/driver/Makefile diff --git a/components/mpas-ocean/cime_config/buildlib b/components/mpas-ocean/cime_config/buildlib index 54347705ce8b..f7a4cdf9156a 100755 --- a/components/mpas-ocean/cime_config/buildlib +++ b/components/mpas-ocean/cime_config/buildlib @@ -1,76 +1,70 @@ -#! /usr/bin/env perl -use strict; -use File::Compare; - -my $component = "mpas-ocean"; -my $component_dir = "ocn"; -my $component_driver = "ocean_cesm_driver"; -my $core = "ocean"; -my $esm = "E3SM"; - -if ($#ARGV == -1) { - die " ERROR $component buildlib: must specify a caseroot input argument"; -} - -my ($CASEROOT) = @ARGV; -chdir "${CASEROOT}"; - -my $SRCROOT = `./xmlquery SRCROOT -value`; -my $OBJROOT = `./xmlquery OBJROOT -value`; -my $CASEBUILD = `./xmlquery CASEBUILD -value`; -my $CASETOOLS = `./xmlquery CASETOOLS -value`; -my $OBJROOT = `./xmlquery OBJROOT -value`; -my $LIBROOT = `./xmlquery LIBROOT -value`; -my $GMAKE_J = `./xmlquery GMAKE_J -value`; -my $GMAKE = `./xmlquery GMAKE -value`; -my $MACH = `./xmlquery MACH -value`; -my $MAKE_ARGS = `./Tools/get_standard_makefile_args`; -chomp($MAKE_ARGS); - -#--------------------------------------------------------------------------- -# Copy MPAS-O source -#--------------------------------------------------------------------------- - -mkdir "$OBJROOT/$component_dir"; -mkdir "$OBJROOT/$component_dir/source"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/Makefile* $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/core_ocean $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/external $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/operators $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/framework $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/tools $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; - -my $drvcpy = "cp -fpR $SRCROOT/components/$component/driver ${OBJROOT}/$component_dir/source/$component_driver"; -system($drvcpy) == 0 or die "ERROR: $component buildlib $drvcpy failed: $?\n"; - -my $root_path = "$OBJROOT/$component_dir/source"; - -my $bldcmd = "cd $root_path; ${GMAKE} all ${MAKE_ARGS} CORE=$core ESM=$esm DRIVER=$component_driver GEN_F90=true"; -$bldcmd .= ' ROOT_DIR="'; -$bldcmd .= "$root_path"; -$bldcmd .= '"'; - -if ( $MACH eq "edison" ) { - $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=sandybridge"'; -} elsif ( $MACH eq "titan" ) { - $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=istanbul"'; -} -if (defined $ENV{MPAS_TOOL_DIR}) { - $bldcmd .= " MPAS_TOOL_DIR=$ENV{MPAS_TOOL_DIR}"; -} - -system($bldcmd) == 0 or die "ERROR: $component buildlib $bldcmd failed: $?\n"; - -my $cpyobjs = "find $root_path -name *.mod -exec cp -p {} $OBJROOT/$component_dir/obj/. \\\;"; - -system($cpyobjs) == 0 or die "ERROR: $component buildlib $cpyobjs failed: $?\n"; - -my $cpylib = "cp -p $root_path/lib$component_dir.a ${LIBROOT}/lib$component_dir.a"; - -system($cpylib) == 0 or die "ERROR: $component buildlib $cpylib failed: $?\n"; +#!/usr/bin/env python + +""" +build mpas-o library +""" + +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy +from CIME.build import get_standard_cmake_args + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + component = "mpas-ocean" + component_dir = "ocn" + component_driver = "ocean_cesm_driver" + core = "ocean" + + srcroot = case.get_value("SRCROOT") + objroot = case.get_value("OBJROOT") + casebuild = case.get_value("CASEBUILD") + casetools = case.get_value("CASETOOLS") + objroot = case.get_value("OBJROOT") + libroot = case.get_value("LIBROOT") + gmake_j = case.get_value("GMAKE_J") + gmake = case.get_value("GMAKE") + mach = case.get_value("MACH") + cmake_args = get_standard_cmake_args(case) + + #--------------------------------------------------------------------------- + # Build MPAS-O source + #--------------------------------------------------------------------------- + + if mach == "edison": + cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=sandybridge"' + elif mach == "titan": + cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=istanbul"' + + if "MPAS_TOOL_DIR" in os.environ: + cmake_args += " -DMPAS_TOOL_DIR={}".format(os.environ["MPAS_TOOL_DIR"]) + + cmake_args += " -DGEN_F90=True" + + run_bld_cmd_ensure_logging('cmake -DCORE={core} -DDRIVER={component_driver} {cmake_args} {srcroot}/components/mpas-source/src'.format(core=core, component_driver=component_driver, cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) + run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() diff --git a/components/mpas-ocean/driver/Makefile b/components/mpas-ocean/driver/Makefile deleted file mode 100644 index afac96f436a0..000000000000 --- a/components/mpas-ocean/driver/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -.SUFFIXES: .F .o - -OBJS = ocn_comp_mct.o \ - mpaso_cpl_indices.o \ - mpaso_mct_vars.o - -OCEAN_SHARED_INCLUDES=-I../core_ocean/mode_forward -I../core_ocean/shared -I../core_ocean/analysis_members -I../core_ocean/cvmix -I../framework -I../operators - -all: $(OBJS) - -ocn_comp_mct.o: mpaso_cpl_indices.o mpaso_mct_vars.o - -mpaso_cpl_indices.o: - -mpaso_mct_vars.o: - -clean: - $(RM) *.o *.mod *.f90 - -.F.o: - $(RM) $@ $*.mod -ifeq "$(GEN_F90)" "true" - $(CPP) $(CPPFLAGS) $(CPPINCLUDES) $< > $*.f90 - $(FC) $(FFLAGS) -c $*.f90 $(FCINCLUDES) -I../framework -I../operators -I../external/esmf_time_f90 -else - $(FC) $(CPPFLAGS) $(FFLAGS) -c $*.F $(CPPINCLUDES) $(FCINCLUDES) -I../framework -I../operators -I../external/esmf_time_f90 -endif From d8ada07d0ece586fc849c1968ca634c5e73c7a86 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 10 Jun 2019 12:12:42 -0600 Subject: [PATCH 02/48] Updates to bld_diff to accomodate MPAS --- cime/scripts/Tools/bld_diff | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cime/scripts/Tools/bld_diff b/cime/scripts/Tools/bld_diff index 8b5256c23f89..8b4ea9e71990 100755 --- a/cime/scripts/Tools/bld_diff +++ b/cime/scripts/Tools/bld_diff @@ -41,7 +41,7 @@ OR ############################################################################### def is_compile_line(line): ############################################################################### - return line.count("-I") > 1 and not line.startswith("gmake ") and not line.startswith("make ") + return line.count("-I") > 1 and not line.startswith("gmake ") and not line.startswith("make ") and not line.startswith("cpp ") ############################################################################### def get_compile_lines_from_log(logfile_text): @@ -66,12 +66,13 @@ def parse_log(logfile_text): for ending in _SRCFILE_ENDINGS: if item.endswith(ending): expect(compiled_file is None, "Found multiple things that look like files in '{}'".format(compile_line)) - compiled_file = item + compiled_file = os.path.basename(item) if compiled_file is None: print("WARNING: Found nothing that looks like a file in '{}'".format(compile_line)) else: - expect(compiled_file not in result, "Found multiple compilations of {}?".format(compiled_file)) + if compiled_file in result: + print("WARNING: Found multiple compilations of {}".format(compiled_file)) result[compiled_file] = items # TODO - Need to capture link lines too From cefd17b95d70c65b29dd6fcc7810bdff0729c507 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 13 Jun 2019 14:07:45 -0600 Subject: [PATCH 03/48] Make MPAS seaice build using CMake! [BFB] --- components/mpas-seaice/cime_config/buildlib | 146 ++++++++++---------- 1 file changed, 70 insertions(+), 76 deletions(-) diff --git a/components/mpas-seaice/cime_config/buildlib b/components/mpas-seaice/cime_config/buildlib index de5f42863f31..f932d316385d 100755 --- a/components/mpas-seaice/cime_config/buildlib +++ b/components/mpas-seaice/cime_config/buildlib @@ -1,76 +1,70 @@ -#! /usr/bin/env perl -use strict; -use File::Compare; - -my $component = "mpas-seaice"; -my $component_dir = "ice"; -my $component_driver = "seaice_acme_driver"; -my $core = "seaice"; -my $esm = "E3SM"; - -if ($#ARGV == -1) { - die " ERROR $component buildlib: must specify a caseroot input argument"; -} - -my ($CASEROOT) = @ARGV; -chdir "${CASEROOT}"; - -my $SRCROOT = `./xmlquery SRCROOT -value`; -my $OBJROOT = `./xmlquery OBJROOT -value`; -my $CASEBUILD = `./xmlquery CASEBUILD -value`; -my $CASETOOLS = `./xmlquery CASETOOLS -value`; -my $OBJROOT = `./xmlquery OBJROOT -value`; -my $LIBROOT = `./xmlquery LIBROOT -value`; -my $GMAKE_J = `./xmlquery GMAKE_J -value`; -my $GMAKE = `./xmlquery GMAKE -value`; -my $MACH = `./xmlquery MACH -value`; -my $MAKE_ARGS = `./Tools/get_standard_makefile_args`; -chomp($MAKE_ARGS); - -#--------------------------------------------------------------------------- -# Copy MPASSI source -#--------------------------------------------------------------------------- - -mkdir "$OBJROOT/$component_dir"; -mkdir "$OBJROOT/$component_dir/source"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/Makefile* $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/core_seaice $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/external $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/operators $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/framework $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/tools $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; - -my $drvcpy = "cp -fpR $SRCROOT/components/$component/driver ${OBJROOT}/$component_dir/source/$component_driver"; -system($drvcpy) == 0 or die "ERROR: $component buildlib $drvcpy failed: $?\n"; - -my $root_path = "$OBJROOT/$component_dir/source"; - -my $bldcmd = "cd $root_path; ${GMAKE} all ${MAKE_ARGS} CORE=$core ESM=$esm DRIVER=$component_driver GEN_F90=true"; -$bldcmd .= ' ROOT_DIR="'; -$bldcmd .= "$root_path"; -$bldcmd .= '"'; - -if ( $MACH eq "edison" ) { - $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=sandybridge"'; -} elsif ( $MACH eq "titan" ) { - $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=istanbul"'; -} -if (defined $ENV{MPAS_TOOL_DIR}) { - $bldcmd .= " MPAS_TOOL_DIR=$ENV{MPAS_TOOL_DIR}"; -} - -system($bldcmd) == 0 or die "ERROR: $component buildlib $bldcmd failed: $?\n"; - -my $cpyobjs = "find $root_path -name *.mod -exec cp -p {} $OBJROOT/$component_dir/obj/. \\\;"; - -system($cpyobjs) == 0 or die "ERROR: $component buildlib $cpyobjs failed: $?\n"; - -my $cpylib = "cp -p $root_path/lib$component_dir.a ${LIBROOT}/lib$component_dir.a"; - -system($cpylib) == 0 or die "ERROR: $component buildlib $cpylib failed: $?\n"; +#!/usr/bin/env python + +""" +build mpas-si library +""" + +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy +from CIME.build import get_standard_cmake_args + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + component = "mpas-seaice" + component_dir = "ice" + component_driver = "seaice_acme_driver" + core = "seaice" + + srcroot = case.get_value("SRCROOT") + objroot = case.get_value("OBJROOT") + casebuild = case.get_value("CASEBUILD") + casetools = case.get_value("CASETOOLS") + objroot = case.get_value("OBJROOT") + libroot = case.get_value("LIBROOT") + gmake_j = case.get_value("GMAKE_J") + gmake = case.get_value("GMAKE") + mach = case.get_value("MACH") + cmake_args = get_standard_cmake_args(case) + + #--------------------------------------------------------------------------- + # Build MPAS-O source + #--------------------------------------------------------------------------- + + if mach == "edison": + cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=sandybridge"' + elif mach == "titan": + cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=istanbul"' + + if "MPAS_TOOL_DIR" in os.environ: + cmake_args += " -DMPAS_TOOL_DIR={}".format(os.environ["MPAS_TOOL_DIR"]) + + cmake_args += " -DGEN_F90=True" + + run_bld_cmd_ensure_logging('cmake -DCORE={core} -DDRIVER={component_driver} {cmake_args} {srcroot}/components/mpas-source/src'.format(core=core, component_driver=component_driver, cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) + run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() From 373a6ecc9a90c5f58381ff6fd6dd01d871342b4f Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 14 Jun 2019 14:02:36 -0600 Subject: [PATCH 04/48] Upgrades to bld_diff for cpp handling --- cime/scripts/Tools/bld_diff | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cime/scripts/Tools/bld_diff b/cime/scripts/Tools/bld_diff index 8b4ea9e71990..2189a0916dd1 100755 --- a/cime/scripts/Tools/bld_diff +++ b/cime/scripts/Tools/bld_diff @@ -41,7 +41,7 @@ OR ############################################################################### def is_compile_line(line): ############################################################################### - return line.count("-I") > 1 and not line.startswith("gmake ") and not line.startswith("make ") and not line.startswith("cpp ") + return line.count("-I") > 0 and not line.startswith("gmake ") and not line.startswith("make ") ############################################################################### def get_compile_lines_from_log(logfile_text): @@ -65,8 +65,12 @@ def parse_log(logfile_text): for item in items: for ending in _SRCFILE_ENDINGS: if item.endswith(ending): - expect(compiled_file is None, "Found multiple things that look like files in '{}'".format(compile_line)) + #expect(compiled_file is None, "Found multiple things that look like files in '{}'".format(compile_line)) compiled_file = os.path.basename(item) + break + + if compiled_file: + break if compiled_file is None: print("WARNING: Found nothing that looks like a file in '{}'".format(compile_line)) @@ -132,12 +136,12 @@ def log_diff(log1, log2, repls, ignore_includes): # Let's not worry about order yet even though some flags are order-sensitive for flag in missing: - if not (ignore_includes and flag.startswith("-I")): + if not (ignore_includes and flag.startswith("-I")) and item not in flag: print(" Missing flag {}".format(flag)) are_same = False for flag in extra: - if flag != "-o" and not flag.startswith("CMakeFiles") and not (ignore_includes and flag.startswith("-I")): + if flag != "-o" and not flag.startswith("CMakeFiles") and not (ignore_includes and flag.startswith("-I")) and item not in flag: print(" Extra flag {}".format(flag)) are_same = False From 6b0dde6793f929c683754056a4426f6aea40be04 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 14 Jun 2019 14:59:44 -0600 Subject: [PATCH 05/48] Make MPAS landice build using CMake! [BFB] --- .../mpas-albany-landice/cime_config/buildlib | 162 ++++++++---------- 1 file changed, 76 insertions(+), 86 deletions(-) diff --git a/components/mpas-albany-landice/cime_config/buildlib b/components/mpas-albany-landice/cime_config/buildlib index 7cde5b0a1293..8b9926c3d5e6 100755 --- a/components/mpas-albany-landice/cime_config/buildlib +++ b/components/mpas-albany-landice/cime_config/buildlib @@ -1,86 +1,76 @@ -#! /usr/bin/env perl -use strict; -use File::Compare; - -my $component = "mpas-albany-landice"; -my $component_dir = "glc"; -my $component_driver = "glc_cesm_driver"; -my $core = "landice"; -my $esm = "E3SM"; - -if ($#ARGV == -1) { - die " ERROR $component buildlib: must specify a caseroot input argument"; -} - -my ($CASEROOT) = @ARGV; -chdir "${CASEROOT}"; - -my $SRCROOT = `./xmlquery SRCROOT -value`; -my $OBJROOT = `./xmlquery OBJROOT -value`; -my $CASEBUILD = `./xmlquery CASEBUILD -value`; -my $CASETOOLS = `./xmlquery CASETOOLS -value`; -my $OBJROOT = `./xmlquery OBJROOT -value`; -my $LIBROOT = `./xmlquery LIBROOT -value`; -my $GMAKE_J = `./xmlquery GMAKE_J -value`; -my $GMAKE = `./xmlquery GMAKE -value`; -my $MACH = `./xmlquery MACH -value`; -my $MALI_USE_ALBANY = `./xmlquery MALI_USE_ALBANY -value`; -my $MAKE_ARGS = `./Tools/get_standard_makefile_args`; -chomp($MAKE_ARGS); - -#--------------------------------------------------------------------------- -# Copy MALI source -#--------------------------------------------------------------------------- - -mkdir "$OBJROOT/$component_dir"; -mkdir "$OBJROOT/$component_dir/source"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/Makefile* $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/core_landice $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/external $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/operators $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/framework $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/tools $OBJROOT/$component_dir/source/."; -system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; - -my $drvcpy = "cp -fpR $SRCROOT/components/$component/driver ${OBJROOT}/$component_dir/source/$component_driver"; -system($drvcpy) == 0 or die "ERROR: $component buildlib $drvcpy failed: $?\n"; - -my $root_path = "$OBJROOT/$component_dir/source"; - -my $bldcmd = "cd $root_path; ${GMAKE} all ${MAKE_ARGS} CORE=$core ESM=$esm DRIVER=$component_driver GEN_F90=true"; -$bldcmd .= ' ROOT_DIR="'; -$bldcmd .= "$root_path"; -$bldcmd .= '"'; - -if ( $MACH eq "edison" ) { - $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=sandybridge"'; -} elsif ( $MACH eq "titan" ) { - $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=istanbul"'; -} -if (defined $ENV{MPAS_TOOL_DIR}) { - $bldcmd .= " MPAS_TOOL_DIR=$ENV{MPAS_TOOL_DIR}"; -} - -# Check for Albany build -if ( $MALI_USE_ALBANY eq "TRUE" ) { - print "Building MALI with Albany support.\n"; - $bldcmd .= ' ALBANY=true'; - # Note MPAS_EXTERNAL_LIBS is not needed since E3SM is doing the linking! -} - -print "Compiling MALI with this command: $bldcmd \n"; - -system($bldcmd) == 0 or die "ERROR: $component buildlib $bldcmd failed: $?\n"; - -my $cpyobjs = "find $root_path -name *.mod -exec cp -p {} $OBJROOT/$component_dir/obj/. \\\;"; - -system($cpyobjs) == 0 or die "ERROR: $component buildlib $cpyobjs failed: $?\n"; - -my $cpylib = "cp -p $root_path/lib$component_dir.a ${LIBROOT}/lib$component_dir.a"; - -system($cpylib) == 0 or die "ERROR: $component buildlib $cpylib failed: $?\n"; +#!/usr/bin/env python + +""" +build mpas land ice library +""" + +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy +from CIME.build import get_standard_cmake_args + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + component = "mpas-albany-landice" + component_dir = "glc" + component_driver = "glc_cesm_driver" + core = "landice" + + srcroot = case.get_value("SRCROOT") + objroot = case.get_value("OBJROOT") + casebuild = case.get_value("CASEBUILD") + casetools = case.get_value("CASETOOLS") + objroot = case.get_value("OBJROOT") + libroot = case.get_value("LIBROOT") + gmake_j = case.get_value("GMAKE_J") + gmake = case.get_value("GMAKE") + mach = case.get_value("MACH") + use_albany = case.get_value("MALI_USE_ALBANY") + cmake_args = get_standard_cmake_args(case) + + #--------------------------------------------------------------------------- + # Build MPAS-O source + #--------------------------------------------------------------------------- + + if mach == "edison": + cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=sandybridge"' + elif mach == "titan": + cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=istanbul"' + + if "MPAS_TOOL_DIR" in os.environ: + cmake_args += " -DMPAS_TOOL_DIR={}".format(os.environ["MPAS_TOOL_DIR"]) + + cmake_args += " -DGEN_F90=True" + + # Check for Albany build + if use_albany: + logger.info("Building MALI with Albany support.") + cmake_args +=' -DALBANY=True'; + + run_bld_cmd_ensure_logging('cmake -DCORE={core} -DDRIVER={component_driver} {cmake_args} {srcroot}/components/mpas-source/src'.format(core=core, component_driver=component_driver, cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) + run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() From b2551e53b11bd642655641c218f77612a047cfd5 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 24 Jun 2019 17:22:44 -0600 Subject: [PATCH 06/48] Switch data/stub modules to cmake [BFB] --- cime/scripts/lib/CIME/buildlib.py | 35 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index d0a7941015db..cd81a21120f3 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -4,8 +4,8 @@ from CIME.XML.standard_module_setup import * from CIME.case import Case -from CIME.utils import parse_args_and_handle_standard_logging_options, setup_standard_logging_options -from CIME.build import get_standard_makefile_args +from CIME.utils import parse_args_and_handle_standard_logging_options, setup_standard_logging_options, get_model, run_bld_cmd_ensure_logging +from CIME.build import get_standard_makefile_args, get_standard_cmake_args import sys, os, argparse logger = logging.getLogger(__name__) @@ -62,21 +62,20 @@ def build_cime_component_lib(case, compname, libroot, bldroot): out.write(os.path.join(cimeroot, "src", "components", "stub_comps", compname, comp_interface) + "\n") # Build the component - run_gmake(case, compclass, libroot, bldroot) + if get_model() == "e3sm": + run_cmake(case, compclass, libroot, bldroot) + else: + run_gmake(case, compclass, libroot, bldroot) ############################################################################### -def run_gmake(case, compclass, libroot, bldroot, libname="", user_cppdefs=""): +def run_gmake(case, compclass, _, bldroot, libname="", user_cppdefs=""): ############################################################################### gmake_args = get_standard_makefile_args(case) gmake_j = case.get_value("GMAKE_J") gmake = case.get_value("GMAKE") - complib = "" - if libname: - complib = os.path.join(libroot, "lib{}.a".format(libname)) - else: - complib = os.path.join(libroot, "lib{}.a".format(compclass)) + complib = libname if libname else compclass makefile = os.path.join(case.get_value("CASETOOLS"), "Makefile") @@ -87,3 +86,21 @@ def run_gmake(case, compclass, libroot, bldroot, libname="", user_cppdefs=""): _, out, _ = run_cmd(cmd, combine_output=True) print(out.encode('utf-8')) + +############################################################################### +def run_cmake(case, compclass, _, bldroot, libname="", user_cppdefs=""): +############################################################################### + cmake_args = get_standard_cmake_args(case) + + srcroot = case.get_value("SRCROOT") + gmake_j = case.get_value("GMAKE_J") + gmake = case.get_value("GMAKE") + + complib = libname if libname else compclass + + cmd = 'cmake -DCOMPLIB={complib} -DMODEL={compclass} -DUSER_CPPDEFS="{user_cppdefs}" {cmake_args} {srcroot}/components' \ + .format(compclass=compclass, complib=complib, cmake_args=cmake_args, user_cppdefs=user_cppdefs, srcroot=srcroot) + + run_bld_cmd_ensure_logging(cmd, logger, from_dir=bldroot) + run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + From b6ed1f27f5ac7e3540630418a07648c151c9dee0 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 26 Jun 2019 18:25:40 -0600 Subject: [PATCH 07/48] The final link of e3sm.exe is now also done by cmake --- cime/src/drivers/mct/cime_config/buildexe | 50 +++++++++++------------ components/CMakeLists.txt | 31 +++++--------- 2 files changed, 34 insertions(+), 47 deletions(-) diff --git a/cime/src/drivers/mct/cime_config/buildexe b/cime/src/drivers/mct/cime_config/buildexe index 288f93f4d212..3a226d83a953 100755 --- a/cime/src/drivers/mct/cime_config/buildexe +++ b/cime/src/drivers/mct/cime_config/buildexe @@ -12,51 +12,49 @@ sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools")) from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case -from CIME.utils import expect, run_cmd -from CIME.build import get_standard_makefile_args +from CIME.utils import expect, run_bld_cmd_ensure_logging +from CIME.build import get_standard_cmake_args logger = logging.getLogger(__name__) ############################################################################### -def _main_func(): +def buildexe(case, bldroot): ############################################################################### - - caseroot, _, _ = parse_input(sys.argv) - logger.info("Building a single executable version of target coupled model") - with Case(caseroot) as case: - casetools = case.get_value("CASETOOLS") - cimeroot = case.get_value("CIMEROOT") - gmake = case.get_value("GMAKE") - gmake_j = case.get_value("GMAKE_J") - num_esp = case.get_value("NUM_COMP_INST_ESP") - ocn_model = case.get_value("COMP_OCN") - atm_model = case.get_value("COMP_ATM") - gmake_opts = get_standard_makefile_args(case) + caseroot = case.get_value("CASEROOT") + srcroot = case.get_value("SRCROOT") + cimeroot = case.get_value("CIMEROOT") + gmake = case.get_value("GMAKE") + gmake_j = case.get_value("GMAKE_J") + num_esp = case.get_value("NUM_COMP_INST_ESP") + ocn_model = case.get_value("COMP_OCN") + atm_model = case.get_value("COMP_ATM") + cmake_args = get_standard_cmake_args(case) if ocn_model == 'mom' or atm_model == "fv3gfs": - gmake_opts += "USE_FMS=TRUE" - + cmake_args += "-DUSE_FMS=TRUE" expect((num_esp is None) or (int(num_esp) == 1), "ESP component restricted to one instance") - with open('Filepath', 'w') as out: out.write(os.path.join(caseroot, "SourceMods", "src.drv") + "\n") out.write(os.path.join(cimeroot, "src", "drivers", "mct", "main") + "\n") # build model executable + exename = case.get_value("MODEL") + ".exe" + cmd = "cmake -DEXEC_SE={exename} -DMODEL=driver {cmake_args} {srcroot}/components".\ + format(exename=exename, cmake_args=cmake_args, srcroot=srcroot) - makefile = os.path.join(casetools, "Makefile") - exename = os.path.join(case.get_value("EXEROOT"), case.get_value("MODEL") + ".exe") + run_bld_cmd_ensure_logging(cmd, logger, from_dir=bldroot) + run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) - cmd = "{gmake} exec_se -j {gmake_j} EXEC_SE={exename} MODEL=driver {gmake_opts} -f {makefile} ".format(gmake=gmake, gmake_j=gmake_j, exename=exename, - gmake_opts=gmake_opts, makefile=makefile) - - rc, out, _ = run_cmd(cmd, combine_output=True) - expect(rc==0,"Command %s failed rc=%d\nout=%s"%(cmd,rc,out)) - logger.info(out) +############################################################################### +def _main_func(): +############################################################################### + caseroot, _, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildexe(case, bldroot) ############################################################################### diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index bad5d9f2864b..6e3ba69e1e0b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -492,9 +492,9 @@ endif() # System libraries (netcdf, mpi, pnetcdf, esmf, trilinos, etc.) if (NOT SLIBS) if (NOT NETCDF_SEPARATE) - set(SLIBS "${SLIBS} -L${LIB_NETCDF} -lnetcdff -lnetcdf") + set(SLIBS "-L${LIB_NETCDF} -lnetcdff -lnetcdf") else() - set(SLIBS "${SLIBS} -L${LIB_NETCDF_FORTRAN} -L${LIB_NETCDF_C} -lnetcdff -lnetcdf") + set(SLIBS "-L${LIB_NETCDF_FORTRAN} -L${LIB_NETCDF_C} -lnetcdff -lnetcdf") endif() endif() @@ -579,8 +579,6 @@ set(MCTLIBS "${MCT_LIBDIR}/libmct.a ${MCT_LIBDIR}/libmpeu.a") set(GPTLLIB "${GPTL_LIBDIR}/libgptl.a") -set(ULIBS "-L${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/lib -lcsm_share -L${INSTALL_SHAREDPATH}/lib ${PIOLIBNAME} -lgptl -lmct -lmpeu") - #------------------------------------------------------------------------------ # Drive cmake script for cism and pio #------------------------------------------------------------------------------ @@ -699,7 +697,7 @@ endif() if (NOT ULIBDEP) if (LIBROOT) - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libatm.a") + set(ULIBDEP "${LIBROOT}/libatm.a") set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libice.a") set(ULIBDEP "${ULIBDEP} ${LNDLIBDIR}/${LNDLIB}") set(INCLDIR "${INCLDIR} -I${LNDOBJDIR}") @@ -724,21 +722,6 @@ if (OCN_SUBMODEL STREQUAL "moby") set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libmoby.a") endif() -# JGF, this kind of thing should be done via target_link_library in cmake -if (NOT CLIBS) - if (ULIBDEP) - # For each occurrence of something like /path/to/foo/libbar.a in ULIBDEP, - # CLIBS will contain -L/path/to/foo -lbar - foreach (ITEM ${ULIBDEP}) - get_filename_component(ULIB_DIR ${ITEM} DIRECTORY) - get_filename_component(ULIB_LIB ${ITEM} NAME) - set(CLIBS "${CLIBS} -L${ULIB_DIR} -l${ULIB_LIB}") - endforeach() - endif() -endif() - -# libcsm_share.a is in ULIBDEP, but -lcsm_share is in ULIBS rather than CLIBS, -# so this needs to be added after creating CLIBS above set(CSMSHARELIB "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/lib/libcsm_share.a") set(ULIBDEP "${ULIBDEP} ${CSMSHARELIB}") @@ -803,6 +786,7 @@ endif() set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../..) if (COMPLIB) add_library(${COMPLIB}) @@ -818,5 +802,10 @@ endif() if (EXEC_SE) add_executable(${EXEC_SE}) - target_link_library(${EXEC_SE} ${COMPLIB} ${ULIBDEP} ${CSMSHARELIB} ${MCTLIBS} ${PIOLIB} ${GPTLLIB} ${CLIBS} ${ULIBS} ${SLIBS} ${MLIBS} ${F90_LDFLAGS}) + target_sources(${EXEC_SE} PRIVATE ${SOURCES}) + set(ALL_LIBS "${ULIBDEP} ${MCTLIBS} ${PIOLIB} ${GPTLLIB} ${SLIBS} ${MLIBS} ${F90_LDFLAGS}") + separate_arguments(ALL_LIBS_LIST UNIX_COMMAND "${ALL_LIBS}") + foreach(ITEM IN LISTS ALL_LIBS_LIST) + target_link_libraries(${EXEC_SE} ${ITEM}) + endforeach() endif() From 35006b1dd64f12b89484320b2eceab93f251d23c Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 27 Jun 2019 20:17:42 -0600 Subject: [PATCH 08/48] Progress, need to work on CMakelists file now --- cime/scripts/lib/CIME/build.py | 74 +++++++++++++++++-- cime/scripts/lib/CIME/buildlib.py | 37 ++++------ .../buildlib.internal_components | 4 +- cime/src/drivers/mct/cime_config/buildlib | 47 ++++++++++++ components/cam/cime_config/buildlib | 16 +--- components/cice/cime_config/buildlib | 26 +------ components/clm/cime_config/buildlib | 32 +------- components/mosart/cime_config/buildlib | 16 +--- 8 files changed, 139 insertions(+), 113 deletions(-) create mode 100755 cime/src/drivers/mct/cime_config/buildlib diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index dcb2ce5872bd..0f55e2f46cbe 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -1,7 +1,7 @@ """ functions for building CIME models """ -import glob, shutil, time, threading, subprocess +import glob, shutil, time, threading, subprocess, imp from CIME.XML.standard_module_setup import * from CIME.utils import get_model, analyze_build_log, stringify_bool, run_and_log_case_status, get_timestamp, run_sub_or_cmd, run_cmd, get_batch_script_for_job, gzip_existing_file, safe_copy from CIME.provenance import save_build_provenance as save_build_provenance_sub @@ -29,6 +29,12 @@ def get_standard_makefile_args(case, shared_lib=False): def get_standard_cmake_args(case, shared_lib=False): cmake_args = "-DCIME_MODEL={} ".format(case.get_value("MODEL")) + + ocn_model = case.get_value("COMP_OCN") + atm_model = case.get_value("COMP_ATM") + if ocn_model == 'mom' or atm_model == "fv3gfs": + cmake_args += " -DUSE_FMS=TRUE" + if not shared_lib: cmake_args += " -DUSE_KOKKOS={} ".format(stringify_bool(uses_kokkos(case))) for var in _CMD_ARGS_FOR_BUILD: @@ -96,7 +102,7 @@ def _build_model(build_threaded, exeroot, incroot, complist, # logs is a list of log files to be compressed and added to the case logs/bld directory t = threading.Thread(target=_build_model_thread, args=(config_dir, model, comp, caseroot, libroot, bldroot, incroot, file_build, - thread_bad_results, smp, compiler, case)) + thread_bad_results, smp, compiler)) t.start() logs.append(file_build) @@ -137,6 +143,50 @@ def _build_model(build_threaded, exeroot, incroot, complist, return logs +############################################################################### +def _build_model_cmake(build_threaded, exeroot, incroot, complist, + lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case): +############################################################################### + model = get_model() + bldroot = os.path.join(exeroot, "bld") + libroot = os.path.join(exeroot, "lib") + bldlog = os.path.join(exeroot, "{}.bldlog.{}".format(model, lid)) + srcroot = case.get_value("SRCROOT") + gmake_j = case.get_value("GMAKE_J") + gmake = case.get_value("GMAKE") + + # make sure bldroot and libroot exist + for build_dir in [bldroot, libroot]: + if not os.path.exists(build_dir): + os.makedirs(build_dir) + + for model, _, nthrds, _, config_dir in complist: + if buildlist is not None and model.lower() not in buildlist: + continue + + # Create the Filepath and CCSM_cppde3fs files + if model == "cpl": + config_dir = os.path.join(cimeroot, "src", "drivers", comp_interface, "cime_config") + + _create_build_metadata_for_component(config_dir, libroot, bldroot, case) + + # Call CMake + cmake_args = get_standard_cmake_args(case) + cmake_cmd = "cmake {} {}/components &> {}".format(cmake_args, srcroot, bldlog) + logger.info("Configuring with cmake cmd: {}".format(cmake_cmd)) + stat = run_cmd(cmake_cmd, from_dir=bldroot)[0] + + # Call Make + if stat == 0: + stat = run_cmd("{} -j {} >> {} 2>&1".format(gmake, gmake_j, bldlog), from_dir=bldroot)[0] + + expect(stat == 0, "BUILD FAIL: build {} failed, cat {}".format(model, bldlog)) + + # Copy the just-built ${MODEL}.exe to ${MODEL}.exe.$LID + safe_copy("{}/{}.exe".format(exeroot, model), "{}/{}.exe.{}".format(exeroot, model, lid)) + + return [bldlog] + ############################################################################### def _build_checks(case, build_threaded, comp_interface, use_esmf_lib, debug, compiler, mpilib, complist, ninst_build, smp_value, @@ -305,7 +355,7 @@ def _build_libraries(case, exeroot, sharedpath, caseroot, cimeroot, libroot, lid # logs is a list of log files to be compressed and added to the case logs/bld directory thread_bad_results = [] _build_model_thread(config_lnd_dir, "lnd", comp_lnd, caseroot, libroot, bldroot, incroot, - file_build, thread_bad_results, smp, compiler, case) + file_build, thread_bad_results, smp, compiler) logs.append(file_build) expect(not thread_bad_results, "\n".join(thread_bad_results)) @@ -314,7 +364,7 @@ def _build_libraries(case, exeroot, sharedpath, caseroot, cimeroot, libroot, lid ############################################################################### def _build_model_thread(config_dir, compclass, compname, caseroot, libroot, bldroot, incroot, file_build, - thread_bad_results, smp, compiler, _): # (case not used yet) + thread_bad_results, smp, compiler): ############################################################################### logger.info("Building {} with output to {}".format(compclass, file_build)) t1 = time.time() @@ -331,8 +381,6 @@ def _build_model_thread(config_dir, compclass, compname, caseroot, libroot, bldr from_dir=bldroot, arg_stdout=fd, arg_stderr=subprocess.STDOUT)[0] - analyze_build_log(compclass, file_build, compiler) - if stat != 0: thread_bad_results.append("BUILD FAIL: {}.buildlib failed, cat {}".format(compname, file_build)) @@ -344,6 +392,12 @@ def _build_model_thread(config_dir, compclass, compname, caseroot, libroot, bldr t2 = time.time() logger.info("{} built in {:f} seconds".format(compname, (t2 - t1))) +############################################################################### +def _create_build_metadata_for_component(config_dir, libroot, bldroot, case): +############################################################################### + buildlib = imp.load_source("buildlib", os.path.join(config_dir, "buildlib")) + buildlib.buildlib(bldroot, libroot, case) + ############################################################################### def _clean_impl(case, cleanlist, clean_all, clean_depends): ############################################################################### @@ -514,8 +568,12 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, if not sharedlib_only: os.environ["INSTALL_SHAREDPATH"] = os.path.join(exeroot, sharedpath) # for MPAS makefile generators - logs.extend(_build_model(build_threaded, exeroot, incroot, complist, - lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case)) + if get_model() == "e3sm": + logs.extend(_build_model_cmake(build_threaded, exeroot, incroot, complist, + lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case)) + else: + logs.extend(_build_model(build_threaded, exeroot, incroot, complist, + lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case)) if not buildlist: # in case component build scripts updated the xml files, update the case object diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index cd81a21120f3..bd2f1bf7fa87 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -4,7 +4,7 @@ from CIME.XML.standard_module_setup import * from CIME.case import Case -from CIME.utils import parse_args_and_handle_standard_logging_options, setup_standard_logging_options, get_model, run_bld_cmd_ensure_logging +from CIME.utils import parse_args_and_handle_standard_logging_options, setup_standard_logging_options, get_model, run_bld_cmd_ensure_logging, safe_copy from CIME.build import get_standard_makefile_args, get_standard_cmake_args import sys, os, argparse logger = logging.getLogger(__name__) @@ -43,10 +43,15 @@ def build_cime_component_lib(case, compname, libroot, bldroot): ############################################################################### cimeroot = case.get_value("CIMEROOT") + casebuild = case.get_value("CASEBUILD") compclass = compname[1:] comp_interface = case.get_value("COMP_INTERFACE") + confdir = os.path.join(casebuild, "{}conf".format(compname)) - with open(os.path.join(bldroot,'Filepath'), 'w') as out: + if not os.path.exists(confdir): + os.mkdir(confdir) + + with open(os.path.join(confdir, 'Filepath'), 'w') as out: out.write(os.path.join(case.get_value('CASEROOT'), "SourceMods", "src.{}\n".format(compname)) + "\n") if compname.startswith('d'): @@ -61,10 +66,14 @@ def build_cime_component_lib(case, compname, libroot, bldroot): elif compname.startswith('s'): out.write(os.path.join(cimeroot, "src", "components", "stub_comps", compname, comp_interface) + "\n") + with open(os.path.join(confdir, "CCSM_cppdefs"), "w") as out: + out.write("") + + safe_copy(os.path.join(confdir, "Filepath"), bldroot) + safe_copy(os.path.join(confdir, "CCSM_cppdefs"), bldroot) + # Build the component - if get_model() == "e3sm": - run_cmake(case, compclass, libroot, bldroot) - else: + if get_model() != "e3sm": run_gmake(case, compclass, libroot, bldroot) ############################################################################### @@ -86,21 +95,3 @@ def run_gmake(case, compclass, _, bldroot, libname="", user_cppdefs=""): _, out, _ = run_cmd(cmd, combine_output=True) print(out.encode('utf-8')) - -############################################################################### -def run_cmake(case, compclass, _, bldroot, libname="", user_cppdefs=""): -############################################################################### - cmake_args = get_standard_cmake_args(case) - - srcroot = case.get_value("SRCROOT") - gmake_j = case.get_value("GMAKE_J") - gmake = case.get_value("GMAKE") - - complib = libname if libname else compclass - - cmd = 'cmake -DCOMPLIB={complib} -DMODEL={compclass} -DUSER_CPPDEFS="{user_cppdefs}" {cmake_args} {srcroot}/components' \ - .format(compclass=compclass, complib=complib, cmake_args=cmake_args, user_cppdefs=user_cppdefs, srcroot=srcroot) - - run_bld_cmd_ensure_logging(cmd, logger, from_dir=bldroot) - run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) - diff --git a/cime/src/build_scripts/buildlib.internal_components b/cime/src/build_scripts/buildlib.internal_components index e33ea7ddb2a0..f5f7d4d9c8fb 100755 --- a/cime/src/build_scripts/buildlib.internal_components +++ b/cime/src/build_scripts/buildlib.internal_components @@ -14,7 +14,7 @@ from standard_script_setup import * from CIME.buildlib import build_cime_component_lib, parse_input from CIME.case import Case -def buildlib(case, libroot, bldroot, compname=None): +def buildlib(bldroot, libroot, case, compname=None): if compname is None: thisdir = os.path.dirname(os.path.abspath(__file__)) path, dir1 = os.path.split(thisdir) @@ -28,7 +28,7 @@ def buildlib(case, libroot, bldroot, compname=None): def _main_func(args): caseroot, libroot, bldroot = parse_input(args) with Case(caseroot) as case: - buildlib(case, libroot, bldroot) + buildlib(bldroot, libroot, case) if __name__ == "__main__": _main_func(sys.argv) diff --git a/cime/src/drivers/mct/cime_config/buildlib b/cime/src/drivers/mct/cime_config/buildlib new file mode 100755 index 000000000000..5b3cd66ba3ed --- /dev/null +++ b/cime/src/drivers/mct/cime_config/buildlib @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +""" +build model executable +""" + +import sys, os + +_CIMEROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..","..","..","..") +sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools")) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging +from CIME.build import get_standard_cmake_args + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + casebuild = case.get_value("CASEBUILD") + caseroot = case.get_value("CASEROOT") + cimeroot = case.get_value("CIMEROOT") + num_esp = case.get_value("NUM_COMP_INST_ESP") + + expect((num_esp is None) or (int(num_esp) == 1), "ESP component restricted to one instance") + + with open(os.path.join(casebuild, "cplconf", "Filepath"), "w") as out: + out.write(os.path.join(caseroot, "SourceMods", "src.drv") + "\n") + out.write(os.path.join(cimeroot, "src", "drivers", "mct", "main") + "\n") + + with open(os.path.join(casebuild, "cplconf", "CCSM_cppdefs"), "w") as out: + out.write("") + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() diff --git a/components/cam/cime_config/buildlib b/components/cam/cime_config/buildlib index 0209e1725f96..65e3f1361335 100755 --- a/components/cam/cime_config/buildlib +++ b/components/cam/cime_config/buildlib @@ -20,21 +20,7 @@ logger = logging.getLogger(__name__) ############################################################################### def buildlib(bldroot, installpath, case): ############################################################################### - casebuild = case.get_value("CASEBUILD") - srcroot = case.get_value("SRCROOT") - gmake_j = case.get_value("GMAKE_J") - gmake = case.get_value("GMAKE") - cmake_args = get_standard_cmake_args(case) - - filepath_src = os.path.join(casebuild, "camconf", "Filepath") - expect(os.path.exists(filepath_src), "Missing {}".format(filepath_src)) - safe_copy(filepath_src, bldroot) - - with open(os.path.join(casebuild, "camconf", "CCSM_cppdefs"), "r") as fd: - camdefs = fd.read().strip() - - run_bld_cmd_ensure_logging('cmake -DMODEL=cam -DCOMPLIB=atm -DUSER_CPPDEFS="{camdefs}" {cmake_args} {srcroot}/components'.format(camdefs=camdefs, cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) - run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + pass ############################################################################### def _main(argv, documentation): diff --git a/components/cice/cime_config/buildlib b/components/cice/cime_config/buildlib index a5a4b8ade466..0c69279fc14a 100755 --- a/components/cice/cime_config/buildlib +++ b/components/cice/cime_config/buildlib @@ -23,37 +23,19 @@ logger = logging.getLogger(__name__) ############################################################################### def buildlib(bldroot, installpath, case): ############################################################################### - casebuild = case.get_value("CASEBUILD") - srcroot = case.get_value("SRCROOT") - gmake_j = case.get_value("GMAKE_J") - gmake = case.get_value("GMAKE") cice_blckx = case.get_value("CICE_BLCKX") cice_blcky = case.get_value("CICE_BLCKY") cice_mxblcks = case.get_value("CICE_MXBLCKS") cppdefs = case.get_value("CICE_CPPDEFS") - cmake_args = get_standard_cmake_args(case) - - #------------------------------------------------------- - # Create Filepath in $CASEBUILD/ciceconf - #------------------------------------------------------- - - filepath_src = os.path.join(casebuild, "ciceconf", "Filepath") - expect(os.path.exists(filepath_src), "Missing {}".format(filepath_src)) - safe_copy(filepath_src, bldroot) - - #------------------------------------------------------- - # compute all cppdefs, unlike other components, ignores CCSM_cppdefs file - #------------------------------------------------------- - - cppdefs += " -DBLCKX={} -DBLCKY={} -DMXBLCKS={}".format(cice_blckx, cice_blcky, cice_mxblcks) #------------------------------------------------------- - # Build the library + # compute all cppdefs, unlike other components, needs to make a CCSM_cppdefs file #------------------------------------------------------- - run_bld_cmd_ensure_logging('cmake -DMODEL=cice -DCOMPLIB=ice -DUSER_CPPDEFS="{cppdefs}" {cmake_args} {srcroot}/components'.format(cppdefs=cppdefs, cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) - run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + cppdefs += " -DBLCKX={} -DBLCKY={} -DMXBLCKS={}\n".format(cice_blckx, cice_blcky, cice_mxblcks) + with open(os.path.join(casebuild, "ciceconf", "CCSM_cppdefs"), "w") as fd: + fd.write(cppdefs) ############################################################################### def _main_func(): diff --git a/components/clm/cime_config/buildlib b/components/clm/cime_config/buildlib index fc979d97bae5..24ca12ebe32e 100755 --- a/components/clm/cime_config/buildlib +++ b/components/clm/cime_config/buildlib @@ -23,37 +23,7 @@ logger = logging.getLogger(__name__) ############################################################################### def buildlib(bldroot, installpath, case): ############################################################################### - casebuild = case.get_value("CASEBUILD") - srcroot = case.get_value("SRCROOT") - gmake_j = case.get_value("GMAKE_J") - gmake = case.get_value("GMAKE") - cmake_args = get_standard_cmake_args(case) - - #------------------------------------------------------- - # create Filepath in bldroot - #------------------------------------------------------- - - filepath_src = os.path.join(casebuild, "clmconf", "Filepath") - expect(os.path.exists(filepath_src), "Missing {}".format(filepath_src)) - safe_copy(filepath_src, bldroot) - - #------------------------------------------------------- - # create the library in libroot - #------------------------------------------------------- - - # Note that casebuild/clmconf/CCSM_cppdefs is created - # by the call to clm's bld/configure in clm's cime_config/buildnml - - with open(os.path.join(casebuild, "clmconf", "CCSM_cppdefs"), "r") as fd: - clmdefs = fd.read().strip() - - clm_config_opts = case.get_value("CLM_CONFIG_OPTS") - complib = "clm" - if "clm4_0" in clm_config_opts: - complib = "lnd" - - run_bld_cmd_ensure_logging('cmake -DMODEL=clm -DCOMPLIB={complib} -DUSER_CPPDEFS="{clmdefs}" {cmake_args} {srcroot}/components'.format(complib=complib, clmdefs=clmdefs, cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) - run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + pass ############################################################################### def _main_func(): diff --git a/components/mosart/cime_config/buildlib b/components/mosart/cime_config/buildlib index 6f2cad32676c..c1ad8378afbe 100755 --- a/components/mosart/cime_config/buildlib +++ b/components/mosart/cime_config/buildlib @@ -23,11 +23,7 @@ logger = logging.getLogger(__name__) ############################################################################### def buildlib(bldroot, installpath, case): ############################################################################### - caseroot = case.get_value("CASEROOT") - srcroot = case.get_value("SRCROOT") - gmake_j = case.get_value("GMAKE_J") - gmake = case.get_value("GMAKE") - cmake_args = get_standard_cmake_args(case) + casebuild = case.get_value("CASEBUILD") #------------------------------------------------------- # create Filepath in bldroot, unlike most other components, @@ -41,15 +37,11 @@ def buildlib(bldroot, installpath, case): {srcroot}/components/mosart/src/cpl_share """.format(caseroot=caseroot, srcroot=srcroot) - with open(os.path.join(bldroot, "Filepath"), "w") as fd: + with open(os.path.join(casebuild, "mosartconf", "Filepath"), "w") as fd: fd.write(filepaths) - #------------------------------------------------------- - # create the library in libroot - #------------------------------------------------------- - - run_bld_cmd_ensure_logging('cmake -DMODEL=mosart -DCOMPLIB=rof {cmake_args} {srcroot}/components'.format(cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) - run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + with open(os.path.join(casebuild, "mosartconf", "CCSM_cppdefs"), "w") as fd: + fd.write("") ############################################################################### def _main_func(): From 19c63f2d67557ff39061b7a2587225c1033cedbd Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 27 Jun 2019 21:50:24 -0600 Subject: [PATCH 09/48] Progress --- components/CMakeLists.txt | 803 +--------------------------------- components/build_model.cmake | 222 ++++++++++ components/common_setup.cmake | 481 ++++++++++++++++++++ 3 files changed, 723 insertions(+), 783 deletions(-) create mode 100644 components/build_model.cmake create mode 100644 components/common_setup.cmake diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6e3ba69e1e0b..4ae7d80567f6 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -18,794 +18,31 @@ cmake_policy(SET CMP0057 NEW) project(E3SM C CXX Fortran) -# Set module path -set(CMAKE_MODULE_PATH ${CIMEROOT}/src/CMake) +include(${CMAKE_CURRENT_SOURCE_DIR}/common_setup.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/build_model.cmake) -# Load dependency search path. -file(STRINGS ${CMAKE_BINARY_DIR}/Filepath FILEPATH_DIRS) -set(CPP_DIRS ${FILEPATH_DIRS}) -list(APPEND CPP_DIRS ".") +# For each component that has registered itself to be built, read in Filepath and +# CCSM_cppdefs and build it. We identify the components by looking for Buildconf/*/Filepath +# files. -# Add INCROOT to path for Depends and Include -set(MINCROOT "") -if (INCROOT) - list(APPEND CPP_DIRS ${INCROOT}) - set(MINCROOT ${INCROOT}) -endif () +set(BUILDCONF ${CMAKE_BINARY_DIR}/../../Buildconf) +file(GLOB FILEPATHS "${BUILDCONF}/*/Filepath") +foreach(ITEM IN LISTS FILEPATHS) + get_filename_component(FILEPATH_DIR ${ITEM} DIRECTORY) + get_filename_component(MODELCONF ${FILEPATH_DIR} NAME) + string(REPLACE "conf" "" MODEL "${MODELCONF}") -# Determine whether to compile threaded or not -# Set the THREADDIR for the shared build -# based on the threaded build status -if (SMP_PRESENT) - set(THREADDIR "threads") - set(compile_threaded TRUE) -else() - set(THREADDIR "nothreads") - set(compile_threaded FALSE) -endif() + message("Found component model ${MODEL}") + list(APPEND MODELS ${MODEL}) -# set the debug directory based on the debug status -if (DEBUG) - set(DEBUGDIR "debug") -else() - set(DEBUGDIR "nodebug") -endif() - -if (USE_ESMF_LIB) - set(ESMFDIR "esmf") -else() - set(ESMFDIR "noesmf") -endif() - -# Determine whether any C++ code will be included in the build; -# currently, C++ code is included if and only if we're linking to the -# trilinos library or the Albany library. -set(USE_CXX FALSE) -if (USE_TRILINOS OR USE_ALBANY OR USE_KOKKOS) - set(USE_CXX TRUE) -endif() - -if (NOT MOD_SUFFIX) - set(MOD_SUFFIX "mod") -endif() - -#=============================================================================== -# set CPP options (must use this before any flags or cflags settings) -#=============================================================================== -include(${CASEROOT}/Macros.cmake) - -set(CPPDEFS "${CPPDEFS} ${USER_CPPDEFS} -D${OS}") - -# SLIBS comes from Macros, so this append must come after Macros are included -if (USE_FMS) - set(SLIBS "${SLIBS} -lfms") -endif() - -if (DEBUG) - # e3sm still has components that cannot build with -DDEBUG - if (CIME_MODEL STREQUAL "cesm") - set(CPPDEFS "${CPPDEFS} -DDEBUG") - endif() -else() - set(CPPDEFS "${CPPDEFS} -DNDEBUG") -endif() - -if (USE_ESMF_LIB) - set(CPPDEFS "${CPPDEFS} -DUSE_ESMF_LIB") -endif() - -if (COMP_INTERFACE STREQUAL "nuopc") - set(CPPDEFS "${CPPDEFS} -DNUOPC_INTERFACE") -else() - set(CPPDEFS "${CPPDEFS} -DMCT_INTERFACE") -endif() - -if (COMPARE_TO_NUOPC) - set(CPPDEFS "${CPPDEFS} -DCOMPARE_TO_NUOPC") -endif() - -if (MPILIB STREQUAL mpi-serial) - set(CPPDEFS "${CPPDEFS} -DNO_MPI2") -else() - set(CPPDEFS "${CPPDEFS} -DHAVE_MPI") -endif() - -if (PIO_VERSION STREQUAL "1") - set(CPPDEFS "${CPPDEFS} -DPIO1") -else() - set(USE_CXX TRUE) -endif() - -if (NOT SHAREDPATH) - set(SHAREDPATH ${COMPILER}/${MPILIB}/${DEBUGDIR}/${THREADDIR}/${COMP_INTERFACE}) - set(INSTALL_SHAREDPATH ${EXEROOT}/${SHAREDPATH}) -endif() - -# Decide whether to use a C++ or Fortran linker, based on whether we -# are using any C++ code and the compiler-dependent CXX_LINKER variable -if (USE_CXX AND CXX_LINKER STREQUAL "CXX") - if (MPILIB STREQUAL mpi-serial) - set(LD ${SCXX}) - else() - set(LD ${MPICXX}) - endif() -else() - if (MPILIB STREQUAL mpi-serial) - set(LD ${SFC}) - else() - set(LD ${MPIFC}) - endif() -endif() - -if (USE_CXX AND NOT SUPPORTS_CXX) - message(FATAL_ERROR "Fatal attempt to include C++ code on a compiler/machine combo that has not been set up to support C++") -endif() - -# Not clear how to escape commas for libraries with their own configure -# script, and they don't need this defined anyway, so leave this out of -# FPPDEFS. -if (HAS_F2008_CONTIGUOUS) - if (CPRE) - set(CONTIGUOUS_FLAG "${CPRE}USE_CONTIGUOUS=contiguous,") - else() - set(CONTIGUOUS_FLAG "-DUSE_CONTIGUOUS=contiguous,") - endif() -else() - if (CPRE) - set(CONTIGUOUS_FLAG "${CPRE}USE_CONTIGUOUS=") - else() - set(CONTIGUOUS_FLAG "-DUSE_CONTIGUOUS=") - endif() -endif() - -if (NOT AR) - set(AR "ar") -endif() -if (NOT ARFLAGS) - set(ARFLAGS "-r") -endif() - -if (NETCDF_C_PATH) - if (NOT NETCDF_FORTRAN_PATH) - message(FATAL_ERROR "NETCDF_C_PATH specified without NETCDF_FORTRAN_PATH") - endif() - set(NETCDF_SEPARATE TRUE) - if (NOT INC_NETCDF_C) - set(INC_NETCDF_C ${NETCDF_C_PATH}/include) - endif() - if (NOT INC_NETCDF_FORTRAN) - set(INC_NETCDF_FORTRAN ${NETCDF_FORTRAN_PATH}/include) - endif() - if (NOT LIB_NETCDF_C) - set(LIB_NETCDF_C ${NETCDF_C_PATH}/lib) - endif() - if (NOT LIB_NETCDF_FORTRAN) - set(LIB_NETCDF_FORTRAN ${NETCDF_FORTRAN_PATH}/lib) - endif() -elseif (NETCDF_FORTRAN_PATH) - message(FATAL_ERROR "NETCDF_FORTRAN_PATH specified without NETCDF_C_PATH") -elseif (NETCDF_PATH) - set(NETCDF_SEPARATE FALSE) - if (NOT INC_NETCDF) - set(INC_NETCDF ${NETCDF_PATH}/include) - endif() - if (NOT LIB_NETCDF) - set(LIB_NETCDF ${NETCDF_PATH}/lib) - endif() -else() - message(FATAL_ERROR "NETCDF not found: Define NETCDF_PATH or NETCDF_C_PATH and NETCDF_FORTRAN_PATH in config_machines.xml or config_compilers.xml") -endif() - -if (MPILIB STREQUAL mpi-serial) - if (PNETCDF_PATH) - unset(PNETCDF_PATH) - endif() -else() - if (PNETCDF_PATH) - if (NOT INC_PNETCDF) - set(INC_PNETCDF ${PNETCDF_PATH}/include) - endif() - if (NOT LIB_PNETCDF) - set(LIB_PNETCDF ${PNETCDF_PATH}/lib) - endif() - endif() -endif() - -# Set PETSc info if it is being used -if (USE_PETSC) - if (PETSC_PATH) - if (NOT INC_PETSC) - set(INC_PETSC ${PETSC_PATH}/include) - endif() - if (NOT LIB_PETSC) - set(LIB_PETSC ${PETSC_PATH}/lib) - endif() - else() - message(FATAL_ERROR "PETSC_PATH must be defined when USE_PETSC is TRUE") - endif() - - # Get the "PETSC_LIB" list an env var - set(PETSC_DIR ${PETSC_PATH}) - find_package(PETSc) - set(PETSC_LIB ${PETSC_LIBRARIES}) -endif() - -if (USE_TRILINOS) - if (TRILINOS_PATH) - if (NOT INC_TRILINOS) - set(INC_TRILINOS ${TRILINOS_PATH}/include) - endif() - if (NOT LIB_TRILINOS) - set(LIB_TRILINOS ${TRILINOS_PATH}/lib) - endif() - else() - message(FATAL_ERROR "TRILINOS_PATH must be defined when USE_TRILINOS is TRUE") - endif() - - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${TRILINOS_PATH}) - find_package(Trilinos) -endif() - -if (USE_ALBANY) - if (ALBANY_PATH) - if (NOT INC_ALBANY) - set(INC_ALBANY ${ALBANY_PATH}/include) - endif() - if (NOT LIB_ALBANY) - set(LIB_ALBANY ${ALBANY_PATH}/lib) - endif() - else() - message(FATAL_ERROR "ALBANY_PATH must be defined when USE_ALBANY is TRUE") - endif() - - # get the "ALBANY_LINK_LIBS" list as an env var - file(READ ${ALBANY_PATH}/export_albany.in ALBANY_OUTPUT) - string(REPLACE "ALBANY_LINK_LIBS=" "" ALBANY_LINK_LIBS "${ALBANY_OUTPUT}") -endif() - -if (USE_KOKKOS) - include(${INSTALL_SHAREDPATH}/kokkos_generated_settings.cmake) - string (REPLACE ";" " " KOKKOS_CXXFLAGS_STR "${KOKKOS_CXXFLAGS}") - string (REPLACE ";" " " KOKKOS_LDFLAGS_STR "${KOKKOS_LDFLAGS}") - set(SLIBS "${SLIBS} ${KOKKOS_LIBS_LIST}") - set(CXXFLAGS "${CXXFLAGS} ${KOKKOS_CXXFLAGS_STR}") - set(CXX_LDFLAGS "${CXX_LDFLAGS} ${KOKKOS_LDFLAGS_STR}") -endif() - -# JGF: No one seems to be using this -# if (USE_MOAB) -# if (MOAB_PATH) -# set(CPPDEFS "${CPPDEFS} -DHAVE_MOAB") -# if (NOT INC_MOAB) -# set(INC_MOAB ${MOAB_PATH}/include) -# endif() -# if (NOT LIB_MOAB) -# set(LIB_MOAB ${MOAB_PATH}/lib) -# endif() -# else() -# message(FATAL_ERROR "MOAB_PATH must be defined when USE_MOAB is TRUE") -# endif() - -# # # get the "IMESH_LIBS" list as an env var -# #include $(LIB_MOAB)/iMesh-Defs.inc -# endif() - -# Set HAVE_SLASHPROC on LINUX systems which are not bluegene or Darwin (OSx) -string(FIND "${CPPDEFS}" "-DLINUX" HAS_DLINUX) -string(FIND "${CPPDEFS}" "DBG" HAS_DBG) -string(FIND "${CPPDEFS}" "Darwin" HAS_DARWIN) -if (NOT HAS_DLINUX EQUAL -1 AND HAS_DBG EQUAL -1 AND HAS_DARWIN EQUAL -1) - set(CPPDEFS "${CPPDEFS} -DHAVE_SLASHPROC") -endif() - -# Atleast on Titan+cray mpi, MPI_Irsends() are buggy, causing hangs during I/O -# Force PIO to use MPI_Isends instead of the default, MPI_Irsends -if (PIO_VERSION STREQUAL 2) - set(EXTRA_PIO_CPPDEFS "-DUSE_MPI_ISEND_FOR_FC") -else() - set(EXTRA_PIO_CPPDEFS "-D_NO_MPI_RSEND") -endif() - -if (LIB_PNETCDF) - set(CPPDEFS "${CPPDEFS} -D_PNETCDF") - set(SLIBS "${SLIBS} -L${LIB_PNETCDF} -lpnetcdf") -endif() - -# Set esmf.mk location with ESMF_LIBDIR having precedent over ESMFMKFILE -set(CIME_ESMFMKFILE "undefined_ESMFMKFILE") -if (ESMFMKFILE) - set(CIME_ESMFMKFILE ${ESMFMKFILE}) -endif() -if (ESMF_LIBDIR) - set(CIME_ESMFMKFILE ${ESMF_LIBDIR}/esmf.mk) -endif() - -# For compiling and linking with external ESMF. -# If linking to external ESMF library then include esmf.mk -# ESMF_F90COMPILEPATHS -# ESMF_F90LINKPATHS -# ESMF_F90LINKRPATHS -# ESMF_F90ESMFLINKLIBS -if (USE_ESMF_LIB) - # include(${CIME_ESMFMKFILE}) # JGF SKIPPING FOR NOW - # Will need something like 'make -f esmf.mk -p 2> /dev/null | grep ESMF_F90COMPILEPATHS' - #set(CPPDEFS "${CPPDEFS} -DESMF_VERSION_MAJOR=${ESMF_VERSION_MAJOR} -DESMF_VERSION_MINOR=${ESMF_VERSION_MINOR}") - #set(FFLAGS "${FFLAGS} ${ESMF_F90COMPILEPATHS}") - #set(SLIBS "${SLIBS} ${ESMF_F90LINKPATHS} ${ESMF_F90LINKRPATHS} ${ESMF_F90ESMFLINKLIBS}") - message(FATAL_ERROR "ESMF not supported in CMake yet") -endif() - -if (CPRE) - foreach(ITEM ${CPPDEFS}) - string(REPLACE "-D" "" NOD ${ITEM}) - set(FPPDEFS "${FPPDEFS} ${CPRE}${NOD}") - endforeach() - foreach(ITEM ${EXTRA_PIO_CPPDEFS}) - string(REPLACE "-D" "" NOD ${ITEM}) - set(EXTRA_PIO_FPPDEFS "${EXTRA_PIO_FPPDEFS} ${CPRE}${NOD}") - endforeach() -else() - set(FPPDEFS "${CPPDEFS}") - set(EXTRA_PIO_FPPDEFS "${EXTRA_PIO_CPPDEFS}") -endif() - -#=============================================================================== -# Set config args for pio and mct to blank and then enable serial -#=============================================================================== -if (NOT CONFIG_ARGS) - set(CONFIG_ARGS "") -endif() -string(FIND "${MODEL}" "pio" HAS_PIO) -if (NOT HAS_PIO EQUAL -1) - set(CONFIG_ARGS "${CONFIG_ARGS} --enable-timing") - if (DEBUG) - set(CONFIG_ARGS "${CONFIG_ARGS} --enable-debug") - endif() -endif() - -#=============================================================================== -# User-specified INCLDIR -#=============================================================================== - -set(INCLDIR "-I.") -if (USER_INCLDIR) - set(INCLDIR "${INCLDIR} ${USER_INCLDIR}") -endif() - -#=============================================================================== -# MPI-serial library (part of MCT) -#=============================================================================== - -if (MPILIB STREQUAL "mpi-serial") - set(CC ${SCC}) - set(FC ${SFC}) - set(CXX ${SCXX}) - set(MPIFC ${SFC}) - set(MPICC ${SCC}) - set(MPICXX ${SCXX}) - set(CONFIG_ARGS "${CONFIG_ARGS} MCT_PATH=${SHAREDLIBROOT}/${SHAREDPATH}/mct/mpi-serial") -else() - set(CC ${MPICC}) - set(FC ${MPIFC}) - set(CXX ${MPICXX}) - if (MPI_PATH) - set(INC_MPI ${MPI_PATH}/include) - set(LIB_MPI ${MPI_PATH}/lib) - endif() -endif() -set(CSM_SHR_INCLUDE ${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/include) -# VPATH+=$(CSM_SHR_INCLUDE) # JGF - not sure if I need to do anything here - -#=============================================================================== -# Set include paths (needed after override for any model specific builds below) -#=============================================================================== -set(INCLDIR "${INCLDIR} -I${INSTALL_SHAREDPATH}/include -I${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/include") - -if (NOT NETCDF_SEPARATE) - set(INCLDIR "${INCLDIR} -I${INC_NETCDF}") -else() - set(INCLDIR "${INCLDIR} -I${INC_NETCDF_C} -I${INC_NETCDF_FORTRAN}") -endif() - -foreach(ITEM MOD_NETCDF INC_MPI INC_PNETCDF INC_PETSC INC_TRILINOS INC_ALBANY) # INC_MOAB) - if (${ITEM}) - set(INCLDIR "${INCLDIR} -I${${ITEM}}") - endif() -endforeach() - -if (MODEL STREQUAL "driver") - set(INCLDIR "${INCLDIR} -I${EXEROOT}/atm/obj -I${EXEROOT}/ice/obj -I${EXEROOT}/ocn/obj -I${EXEROOT}/glc/obj -I${EXEROOT}/rof/obj -I${EXEROOT}/wav/obj -I${EXEROOT}/esp/obj -I${EXEROOT}/iac/obj") -endif() - -if (NOT MCT_LIBDIR) - set(MCT_LIBDIR "${INSTALL_SHAREDPATH}/lib") -endif() - -if (PIO_LIBDIR) - if (PIO_VERSION STREQUAL ${PIO_VERSION_MAJOR}) - set(INCLDIR "${INCLDIR} -I${PIO_INCDIR}") - set(SLIBS "${SLIBS} -L${PIO_LIBDIR}") - else() - # If PIO_VERSION_MAJOR doesnt match, build from source - unset(PIO_LIBDIR) - endif() -endif() -if (NOT PIO_LIBDIR) - set(PIO_LIBDIR "${INSTALL_SHAREDPATH}/lib") -endif() - -if (NOT GPTL_LIBDIR) - set(GPTL_LIBDIR "${INSTALL_SHAREDPATH}/lib") -endif() - -if (NOT GLC_DIR) - set(GLC_DIR "${EXEROOT}/glc") -endif() - -if (NOT CISM_LIBDIR) - set(CISM_LIBDIR "${GLC_DIR}/lib") -endif() - -if (NOT GLCROOT) - # Backwards compatibility - set(GLCROOT "${CIMEROOT}/../components/cism") -endif() - -set(INCLDIR "${INCLDIR} -I${INSTALL_SHAREDPATH}/include") - -# -# Use the MCT dir for the cache for all configure calls because it is the first one -# -set(CFLAGS "${CFLAGS}") -set(CXXFLAGS "${CXXFLAGS}") -set(CONFIG_ARGS "CC=\"${CC}\" FC=\"${FC}\" MPICC=\"${MPICC}\" MPIFC=\"${MPIFC}\" FCFLAGS=\"${FFLAGS} ${FREEFLAGS} ${INCLDIR}\" CPPDEFS=\"${CPPDEFS}\" CFLAGS=\"${CFLAGS} -I.. ${INCLDIR}\" LDFLAGS=\"${LDFLAGS}\"") - -if (NOT NETCDF_SEPARATE) - set(CONFIG_ARGS "${CONFIG_ARGS} NETCDF_PATH=${NETCDF_PATH}") -else() - set(CONFIG_ARGS "${CONFIG_ARGS} NETCDF_PATH=${NETCDF_C_PATH}") -endif() - -if (COMPILER STREQUAL "nag") - set(CONFIG_ARGS "LIBS=${SLIBS}") -endif() - -string(FIND "${CAM_CONFIG_OPTS}" "-cosp" HAS_COSP) -if (NOT HAS_COSP EQUAL -1) - # The following is for the COSP simulator code: - get_filename_component(COSP_LIBDIR ${EXEROOT}/atm/obj/cam/src/physics/cosp ABSOLUTE) -endif() - - -if (MODEL STREQUAL "cam") - # These RRTMG files take an extraordinarily long time to compile with optimization. - # Until mods are made to read the data from files, just remove optimization from - # their compilation. - set(NOOPT_FILES "cam/src/physics/rrtmg/ext/rrtmg_lw/rrtmg_lw_k_g.f90;cam/src/physics/rrtmg/ext/rrtmg_sw/rrtmg_sw_k_g.f90") - - if (COSP_LIBDIR) - include(${CMAKE_CURRENT_SOURCE_DIR}/cam/src/physics/cosp/Cosp.cmake) - endif() - -endif() - -# System libraries (netcdf, mpi, pnetcdf, esmf, trilinos, etc.) -if (NOT SLIBS) - if (NOT NETCDF_SEPARATE) - set(SLIBS "-L${LIB_NETCDF} -lnetcdff -lnetcdf") - else() - set(SLIBS "-L${LIB_NETCDF_FORTRAN} -L${LIB_NETCDF_C} -lnetcdff -lnetcdf") - endif() -endif() - -if (LAPACK_LIBDIR) - set(SLIBS "${SLIBS} -L${LAPACK_LIBDIR} -llapack -lblas") -endif() - -if (LIB_MPI) - if (NOT MPI_LIB_NAME) - set(SLIBS "${SLIBS} -L${LIB_MPI} -lmpi") - else() - set(SLIBS "${SLIBS} -L${LIB_MPI} -l${MPI_LIB_NAME}") - endif() -endif() - -# Add PETSc libraries -if (USE_PETSC) - set(SLIBS "${SLIBS} ${PETSC_LIB}") -endif() - -# Add trilinos libraries; too be safe, we include all libraries included in the trilinos build, -# as well as all necessary third-party libraries -if (USE_TRILINOS) - set(SLIBS "${SLIBS} -L${LIB_TRILINOS} ${Trilinos_LIBRARIES} ${Trilinos_TPL_LIBRARY_DIRS} ${Trilinos_TPL_LIBRARIES}") -endif() - -# Add Albany libraries. These are defined in the ALBANY_LINK_LIBS env var that was included above -if (USE_ALBANY) - set(SLIBS "${SLIBS} ${ALBANY_LINK_LIBS}") -endif() - -# Add MOAB libraries. These are defined in the MOAB_LINK_LIBS env var that was included above -# if (USE_MOAB) -# set(SLIBS "${SLIBS} ${IMESH_LIBS}") -# endif() - -# Add libraries and flags that we need on the link line when C++ code is included -# We need to do these additions after CONFIG_ARGS is set, because they can sometimes break configure for mct, etc., -# if they are added to LDFLAGS in CONFIG_ARGS. -if (USE_CXX) - if (CXX_LIBS) - set(SLIBS "${SLIBS} ${CXX_LIBS}") - endif() - - if (CXX_LDFLAGS) - set(LDFLAGS "${LDFLAGS} ${SLIBS} ${CXX_LDFLAGS}") - endif() -endif() - -# Remove arch flag if it exists -string(REGEX REPLACE "-arch[^ ]+" "" F90_LDFLAGS "${LDFLAGS}") - -#------------------------------------------------------------------------------ -# Drive configure scripts for support libraries (mct) -#------------------------------------------------------------------------------ - -# if (NOT EXISTS ${SHAREDLIBROOT}/${SHAREDPATH}/mct/Makefile.conf) -# execute_process(COMMAND ${CIMEROOT}/src/externals/mct/configure ${CONFIG_ARGS} --srcdir ${CIMEROOT}/src/externals/mct) -# endif() - -# if (NOT EXISTS ${SHAREDLIBROOT}/${SHAREDPATH}/mct/mpi-serial/Makefile.conf) -# execute_process(COMMAND ${CIMEROOT}/src/externals/mct/mpi-serial/configure ${CONFIG_ARGS} --srcdir ${CIMEROOT}/src/externals/mct/mpi-serial) -# endif() - -if (PIO_VERSION STREQUAL 2) - # This is a pio2 library - set(PIOLIB "${PIO_LIBDIR}/libpiof.a ${PIO_LIBDIR}/libpioc.a") - set(PIOLIBNAME "-lpiof -lpioc") - set(PIO_SRC_DIR "${CIMEROOT}/src/externals/pio2") -else() - # This is a pio1 library - set(PIOLIB "${PIO_LIBDIR}/libpio.a") - set(PIOLIBNAME "-lpio") - if (NOT EXISTS "${CIMEROOT}/src/externals/pio1/pio") - set(PIO_SRC_DIR "${CIMEROOT}/src/externals/pio1") - else() - set(PIO_SRC_DIR "${CIMEROOT}/src/externals/pio1/pio") - endif() -endif() - -set(MCTLIBS "${MCT_LIBDIR}/libmct.a ${MCT_LIBDIR}/libmpeu.a") - -set(GPTLLIB "${GPTL_LIBDIR}/libgptl.a") - -#------------------------------------------------------------------------------ -# Drive cmake script for cism and pio -#------------------------------------------------------------------------------ - -set(CMAKE_Fortran_FLAGS "${FFLAGS} ${FPPDEFS} ${EXTRA_PIO_FPPDEFS} ${INCLDIR}") -set(CMAKE_C_FLAGS "${CFLAGS} ${CPPDEFS} ${EXTRA_PIO_CPPDEFS} ${INCLDIR}") -set(CMAKE_CXX_FLAGS "${CXXFLAGS} ${CPPDEFS} ${EXTRA_PIO_CPPDEFS} ${INCLDIR}") -set(CMAKE_VERBOSE_MAKEFILE TRUE) -set(GPTL_PATH "${INSTALL_SHAREDPATH}") -set(PIO_ENABLE_TESTS FALSE) -set(PIO_USE_MALLOC FALSE) -set(USER_CMAKE_MODULE_PATH "${CIMEROOT}/src/CMake;${CIMEROOT}/src/externals/pio2/cmake") - -if (NOT PNETCDF_PATH) - set(WITH_PNETCDF FALSE) -endif() - -if (MPILIB STREQUAL "mpi-serial") - set(PIO_USE_MPISERIAL TRUE) - set(MPISERIAL_PATH ${INSTALL_SHAREDPATH}) -endif() - -set(CMAKE_C_COMPILER ${CC}) -set(CMAKE_CXX_COMPILER ${CXX}) -set(CMAKE_Fortran_COMPILER ${FC}) -set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}") - -# JGF: We only want to do CAM for now -# add_subdirectory(${GLCROOT}/source_cism) -# add_subdirectory(${PIO_SRC_DIR}) - -#------------------------------------------------------------------------------- -# Build & include dependency files -#------------------------------------------------------------------------------- - -# JGF, I think we can rely on CMake's built-in dependency analysus - -# Get src files -# JGF: Cmake does not have a VPATH concept, so we need relative/absolute paths to source files -# Note: Using absolute paths seems to wreck CMake's ability to do a dep analysis on fortran -# sources and compile them in the right order. -# -# One additional subtley is that, when mkSrcfiles found multiple files with the same basename, -# only the one found first gets compiled. - -#execute_process(COMMAND ${CASETOOLS}/mkSrcfiles) -#file(STRINGS ${CMAKE_BINARY_DIR}/Srcfiles SOURCES) - -set(SRCROOT_REL "${CIMEROOT}/..") -set(BASENAME_SET) -file(TO_CMAKE_PATH ${SRCROOT_REL} SRCROOT_ABS) -foreach(DIRSEARCH ${FILEPATH_DIRS}) - file(GLOB MATCHES RELATIVE "${SRCROOT_ABS}/components" "${DIRSEARCH}/*.[Ffc]" "${DIRSEARCH}/*.[Ff]90" "${DIRSEARCH}/*.cpp" "${DIRSEARCH}/*.F90.in") - if (MATCHES) - foreach (MATCH IN LISTS MATCHES) - get_filename_component(BASENAME ${MATCH} NAME) - list(FIND BASENAME_SET ${BASENAME} BASENAME_WAS_FOUND) - if (BASENAME_WAS_FOUND EQUAL -1) - list(APPEND SOURCES ${MATCH}) - list(APPEND BASENAME_SET ${BASENAME}) - else() - message(WARNING "Skipping repeated base filename ${BASENAME} for ${MATCH}") - endif() - endforeach() - endif() -endforeach() - -foreach(SOURCE_FILE IN LISTS SOURCES) - get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) - if (SOURCE_EXT STREQUAL ".F90.in") - string(REPLACE ".in" "" SOURCE_NO_IN ${SOURCE_FILE}) - list(APPEND GEN_F90_SOURCES ${SOURCE_NO_IN}) - list(APPEND SOURCES ${SOURCE_NO_IN}) - list(REMOVE_ITEM SOURCES ${SOURCE_FILE}) - endif() -endforeach() - -foreach(ITEM IN LISTS CPP_DIRS) - if (EXISTS ${ITEM}) - set(INCLDIR "${INCLDIR} -I${ITEM}") - endif() -endforeach() - -#------------------------------------------------------------------------------- -# create list of component libraries - hard-wired for current ccsm components -#------------------------------------------------------------------------------- - -if (CIME_MODEL STREQUAL "cesm") - if (COMP_LND STREQUAL "clm") - set(USE_SHARED_CLM TRUE) - else() - set(USE_SHARED_CLM FALSE) - endif() -else() - set(USE_SHARED_CLM FALSE) -endif() - -if (NOT USE_SHARED_CLM) - set(LNDOBJDIR "${EXEROOT}/lnd/obj") - set(LNDLIBDIR "${LIBROOT}") - if (COMP_LND STREQUAL "clm") - set(LNDLIB "libclm.a") - else() - set(LNDLIB "liblnd.a") - endif() - set(INCLDIR "${INCLDIR} -I${LNDOBJDIR}") -else() - set(LNDLIB "libclm.a") - set(LNDOBJDIR "${SHAREDLIBROOT}/${SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/clm/obj") - set(LNDLIBDIR "${EXEROOT}/${SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/lib") - set(INCLDIR "${INCLDIR} -I${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/include") - if (MODEL STREQUAL "clm") - set(INCLUDE_DIR "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/include") - endif() -endif() - -if (NOT ULIBDEP) - if (LIBROOT) - set(ULIBDEP "${LIBROOT}/libatm.a") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libice.a") - set(ULIBDEP "${ULIBDEP} ${LNDLIBDIR}/${LNDLIB}") - set(INCLDIR "${INCLDIR} -I${LNDOBJDIR}") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libocn.a") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/librof.a") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libglc.a") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libwav.a") - if (NOT COMP_INTERFACE STREQUAL "nuopc") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libiac.a") - endif() - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libesp.a") - endif() -endif() - -if (COMP_GLC STREQUAL "cism") - set(ULIBDEP "${ULIBDEP} ${CISM_LIBDIR}/libglimmercismfortran.a") - if (CISM_USE_TRILINOS) - set(ULIBDEP "${ULIBDEP} ${CISM_LIBDIR}/libglimmercismcpp.a") - endif() -endif() -if (OCN_SUBMODEL STREQUAL "moby") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libmoby.a") -endif() - -set(CSMSHARELIB "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/lib/libcsm_share.a") -set(ULIBDEP "${ULIBDEP} ${CSMSHARELIB}") - -# Things may have been added to flags and we need to remove PIO stuff -set(CMAKE_Fortran_FLAGS "${FFLAGS} ${INCLDIR}") -set(CMAKE_C_FLAGS "${CFLAGS} ${INCLDIR}") -set(CMAKE_CXX_FLAGS "${CXXFLAGS} ${INCLDIR}") - -# do the necessary genf90s -add_custom_target(genf90 - DEPENDS ${CIMEROOT}/src/externals/genf90/genf90.pl) -foreach (SRC_FILE IN LISTS GEN_F90_SOURCES) - get_filename_component(BASENAME ${SRC_FILE} NAME) - add_custom_command ( - OUTPUT ${CMAKE_BINARY_DIR}/${BASENAME} - COMMAND ${CIMEROOT}/src/externals/genf90/genf90.pl - ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in > ${CMAKE_BINARY_DIR}/${BASENAME} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in genf90) - list(REMOVE_ITEM SOURCES ${SRC_FILE}) - list(APPEND SOURCES ${CMAKE_BINARY_DIR}/${BASENAME}) -endforeach () - -# Flags are slightly different for different fortran extensions -foreach (SOURCE_FILE IN LISTS SOURCES) - # Cosp manages its own flags - if (NOT SOURCE_FILE IN_LIST COSP_SOURCES) - get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) - if (SOURCE_EXT STREQUAL ".F" OR SOURCE_EXT STREQUAL ".f") - set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FIXEDFLAGS}") - elseif(SOURCE_EXT STREQUAL ".f90") - set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FREEFLAGS}") - elseif(SOURCE_EXT STREQUAL ".F90") - set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FREEFLAGS} ${CONTIGUOUS_FLAG}") - endif() - endif() + build_model(${MODEL} ${MODELCONF} ${ITEM}) endforeach() -# Load machine/compiler specific settings -set(COMPILER_SPECIFIC_DEPENDS ${CASEROOT}/Depends.${COMPILER}.cmake) -set(MACHINE_SPECIFIC_DEPENDS ${CASEROOT}/Depends.${MACH}.cmake) -set(PLATFORM_SPECIFIC_DEPENDS ${CASEROOT}/Depends.${MACH}.${COMPILER}.cmake) -set(TRY_TO_LOAD ${COMPILER_SPECIFIC_DEPENDS} ${MACHINE_SPECIFIC_DEPENDS} ${PLATFORM_SPECIFIC_DEPENDS}) -foreach(ITEM IN LISTS TRY_TO_LOAD) - if (EXISTS ${ITEM}) - include(${ITEM}) - endif() +set(EXEC_SE "${CIME_MODEL}.exe") +add_executable(${EXEC_SE}) +set(ALL_LIBS "${ULIBDEP} ${MCTLIBS} ${PIOLIB} ${GPTLLIB} ${SLIBS} ${MLIBS} ${F90_LDFLAGS}") +separate_arguments(ALL_LIBS_LIST UNIX_COMMAND "${ALL_LIBS}") +foreach(ITEM IN LISTS ALL_LIBS_LIST) + target_link_libraries(${EXEC_SE} ${ITEM}) endforeach() -# Disable optimizations on some files that would take too long to compile, expect these to all be fortran files -foreach (SOURCE_FILE IN LISTS NOOPT_FILES) - set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FFLAGS_NOOPT}") -endforeach() - -#------------------------------------------------------------------------------- -# build rules: -#------------------------------------------------------------------------------- - -if (MPILIB STREQUAL "mpi-serial") - set(MPISERIAL "${INSTALL_SHAREDPATH}/lib/lib-mpi-serial.a") - set(MLIBS "${MLIBS} ${MPISERIAL}") -endif() - -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../..) - -if (COMPLIB) - add_library(${COMPLIB}) - target_sources(${COMPLIB} PRIVATE ${SOURCES}) - - # Subtle: In order for fortran dependency scanning to work, our CPPFPP/DEFS must be registered - # as COMPILE_DEFINITIONS, not simple added via CMAKE_Fortran_Flags. Also, CPPDEFS *must* - # be provided as a list, not a whitespace-separated string; otherwise, things get wonky. - separate_arguments(CPPDEFS_LIST UNIX_COMMAND "${CPPDEFS}") - target_compile_definitions(${COMPLIB} PRIVATE ${CPPDEFS_LIST}) - add_dependencies(${COMPLIB} genf90) -endif() - -if (EXEC_SE) - add_executable(${EXEC_SE}) - target_sources(${EXEC_SE} PRIVATE ${SOURCES}) - set(ALL_LIBS "${ULIBDEP} ${MCTLIBS} ${PIOLIB} ${GPTLLIB} ${SLIBS} ${MLIBS} ${F90_LDFLAGS}") - separate_arguments(ALL_LIBS_LIST UNIX_COMMAND "${ALL_LIBS}") - foreach(ITEM IN LISTS ALL_LIBS_LIST) - target_link_libraries(${EXEC_SE} ${ITEM}) - endforeach() -endif() diff --git a/components/build_model.cmake b/components/build_model.cmake new file mode 100644 index 000000000000..ec9965e96376 --- /dev/null +++ b/components/build_model.cmake @@ -0,0 +1,222 @@ +function(build_model MODEL_ARG MODELCONF_ARG FILEPATH_ARG) + # Load dependency search path. + file(STRINGS ${FILEPATH_ARG} FILEPATH_DIRS) + set(CPP_DIRS ${FILEPATH_DIRS}) + list(APPEND CPP_DIRS ".") + + # Load cppdefs + set(CCSM_CPPDEFS_FILE "${MODELCONF_ARG}/CCSM_cppdefs") + if (EXISTS ${CCSM_CPPDEFS_FILE}) + file(READ ${CCSM_CPPDEFS_FILE} CCSM_CPPDEFS) + string(STRIP "${CCSM_CPPDEFS}" CCSM_CPPDEFS) + set(CPPDEFS "${CPPDEFS} ${CCSM_CPPDEFS}") + endif() + + if (MODEL_ARG STREQUAL "cpl") + set(INCLDIR "${INCLDIR} -I${EXEROOT}/atm/obj -I${EXEROOT}/ice/obj -I${EXEROOT}/ocn/obj -I${EXEROOT}/glc/obj -I${EXEROOT}/rof/obj -I${EXEROOT}/wav/obj -I${EXEROOT}/esp/obj -I${EXEROOT}/iac/obj") + endif() + + if (MODEL_ARG STREQUAL "cam") + # These RRTMG files take an extraordinarily long time to compile with optimization. + # Until mods are made to read the data from files, just remove optimization from + # their compilation. + set(NOOPT_FILES "cam/src/physics/rrtmg/ext/rrtmg_lw/rrtmg_lw_k_g.f90;cam/src/physics/rrtmg/ext/rrtmg_sw/rrtmg_sw_k_g.f90") + + if (COSP_LIBDIR) + include(${CMAKE_CURRENT_SOURCE_DIR}/cam/src/physics/cosp/Cosp.cmake) + endif() + + endif() + + #------------------------------------------------------------------------------- + # Build & include dependency files + #------------------------------------------------------------------------------- + + # Get src files + # JGF: Cmake does not have a VPATH concept, so we need relative/absolute paths to source files + # Note: Using absolute paths seems to wreck CMake's ability to do a dep analysis on fortran + # sources and compile them in the right order. + # + # One additional subtley is that, when mkSrcfiles found multiple files with the same basename, + # only the one found first gets compiled. + + set(SRCROOT_REL "${CIMEROOT}/..") + set(BASENAME_SET) + file(TO_CMAKE_PATH ${SRCROOT_REL} SRCROOT_ABS) + foreach(DIRSEARCH ${FILEPATH_DIRS}) + file(GLOB MATCHES RELATIVE "${SRCROOT_ABS}/components" "${DIRSEARCH}/*.[Ffc]" "${DIRSEARCH}/*.[Ff]90" "${DIRSEARCH}/*.cpp" "${DIRSEARCH}/*.F90.in") + if (MATCHES) + foreach (MATCH IN LISTS MATCHES) + get_filename_component(BASENAME ${MATCH} NAME) + list(FIND BASENAME_SET ${BASENAME} BASENAME_WAS_FOUND) + if (BASENAME_WAS_FOUND EQUAL -1) + list(APPEND SOURCES ${MATCH}) + list(APPEND BASENAME_SET ${BASENAME}) + else() + message(WARNING "Skipping repeated base filename ${BASENAME} for ${MATCH}") + endif() + endforeach() + endif() + endforeach() + + foreach(SOURCE_FILE IN LISTS SOURCES) +i get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) + if (SOURCE_EXT STREQUAL ".F90.in") + string(REPLACE ".in" "" SOURCE_NO_IN ${SOURCE_FILE}) + list(APPEND GEN_F90_SOURCES ${SOURCE_NO_IN}) + list(APPEND SOURCES ${SOURCE_NO_IN}) + list(REMOVE_ITEM SOURCES ${SOURCE_FILE}) + endif() + endforeach() + + foreach(ITEM IN LISTS CPP_DIRS) + if (EXISTS ${ITEM}) + set(INCLDIR "${INCLDIR} -I${ITEM}") + endif() + endforeach() + + #------------------------------------------------------------------------------- + # create list of component libraries - hard-wired for current ccsm components + #------------------------------------------------------------------------------- + + if (CIME_MODEL STREQUAL "cesm") + if (COMP_LND STREQUAL "clm") + set(USE_SHARED_CLM TRUE) + else() + set(USE_SHARED_CLM FALSE) + endif() + else() + set(USE_SHARED_CLM FALSE) + endif() + + if (NOT USE_SHARED_CLM) + set(LNDOBJDIR "${EXEROOT}/lnd/obj") + set(LNDLIBDIR "${LIBROOT}") + if (COMP_LND STREQUAL "clm") + set(LNDLIB "libclm.a") + else() + set(LNDLIB "liblnd.a") + endif() + set(INCLDIR "${INCLDIR} -I${LNDOBJDIR}") + else() + set(LNDLIB "libclm.a") + set(LNDOBJDIR "${SHAREDLIBROOT}/${SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/clm/obj") + set(LNDLIBDIR "${EXEROOT}/${SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/lib") + set(INCLDIR "${INCLDIR} -I${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/include") + if (MODEL_ARG STREQUAL "clm") + set(INCLUDE_DIR "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/include") + endif() + endif() + + if (NOT ULIBDEP) + if (LIBROOT) + set(ULIBDEP "${LIBROOT}/libatm.a") + set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libice.a") + set(ULIBDEP "${ULIBDEP} ${LNDLIBDIR}/${LNDLIB}") + set(INCLDIR "${INCLDIR} -I${LNDOBJDIR}") + set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libocn.a") + set(ULIBDEP "${ULIBDEP} ${LIBROOT}/librof.a") + set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libglc.a") + set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libwav.a") + if (NOT COMP_INTERFACE STREQUAL "nuopc") + set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libiac.a") + endif() + set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libesp.a") + endif() + endif() + + if (COMP_GLC STREQUAL "cism") + set(ULIBDEP "${ULIBDEP} ${CISM_LIBDIR}/libglimmercismfortran.a") + if (CISM_USE_TRILINOS) + set(ULIBDEP "${ULIBDEP} ${CISM_LIBDIR}/libglimmercismcpp.a") + endif() + endif() + if (OCN_SUBMODEL STREQUAL "moby") + set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libmoby.a") + endif() + + set(CSMSHARELIB "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/lib/libcsm_share.a") + set(ULIBDEP "${ULIBDEP} ${CSMSHARELIB}") + + #------------------------------------------------------------------------------ + # Set key cmake vars + #------------------------------------------------------------------------------ + + set(CMAKE_Fortran_FLAGS "${FFLAGS} ${INCLDIR}") + set(CMAKE_C_FLAGS "${CFLAGS} ${INCLDIR}") + set(CMAKE_CXX_FLAGS "${CXXFLAGS} ${INCLDIR}") + set(CMAKE_VERBOSE_MAKEFILE TRUE) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../..) + + set(CMAKE_C_COMPILER ${CC}) + set(CMAKE_CXX_COMPILER ${CXX}) + set(CMAKE_Fortran_COMPILER ${FC}) + set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}") + + # do the necessary genf90s + add_custom_target(genf90 + DEPENDS ${CIMEROOT}/src/externals/genf90/genf90.pl) + foreach (SRC_FILE IN LISTS GEN_F90_SOURCES) + get_filename_component(BASENAME ${SRC_FILE} NAME) + add_custom_command ( + OUTPUT ${CMAKE_BINARY_DIR}/${BASENAME} + COMMAND ${CIMEROOT}/src/externals/genf90/genf90.pl + ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in > ${CMAKE_BINARY_DIR}/${BASENAME} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in genf90) + list(REMOVE_ITEM SOURCES ${SRC_FILE}) + list(APPEND SOURCES ${CMAKE_BINARY_DIR}/${BASENAME}) + endforeach () + + # Flags are slightly different for different fortran extensions + foreach (SOURCE_FILE IN LISTS SOURCES) + # Cosp manages its own flags + if (NOT SOURCE_FILE IN_LIST COSP_SOURCES) + get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) + if (SOURCE_EXT STREQUAL ".F" OR SOURCE_EXT STREQUAL ".f") + set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FIXEDFLAGS}") + elseif(SOURCE_EXT STREQUAL ".f90") + set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FREEFLAGS}") + elseif(SOURCE_EXT STREQUAL ".F90") + set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FREEFLAGS} ${CONTIGUOUS_FLAG}") + endif() + endif() + endforeach() + + # Load machine/compiler specific settings + set(COMPILER_SPECIFIC_DEPENDS ${CASEROOT}/Depends.${COMPILER}.cmake) + set(MACHINE_SPECIFIC_DEPENDS ${CASEROOT}/Depends.${MACH}.cmake) + set(PLATFORM_SPECIFIC_DEPENDS ${CASEROOT}/Depends.${MACH}.${COMPILER}.cmake) + set(TRY_TO_LOAD ${COMPILER_SPECIFIC_DEPENDS} ${MACHINE_SPECIFIC_DEPENDS} ${PLATFORM_SPECIFIC_DEPENDS}) + foreach(ITEM IN LISTS TRY_TO_LOAD) + if (EXISTS ${ITEM}) + include(${ITEM}) + endif() + endforeach() + + # Disable optimizations on some files that would take too long to compile, expect these to all be fortran files + foreach (SOURCE_FILE IN LISTS NOOPT_FILES) + set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FFLAGS_NOOPT}") + endforeach() + + #------------------------------------------------------------------------------- + # build rules: + #------------------------------------------------------------------------------- + + if (MPILIB STREQUAL "mpi-serial") + set(MPISERIAL "${INSTALL_SHAREDPATH}/lib/lib-mpi-serial.a") + set(MLIBS "${MLIBS} ${MPISERIAL}") + endif() + + add_library(${MODEL_ARG}) + target_sources(${MODEL_ARG} PRIVATE ${SOURCES}) + + # Subtle: In order for fortran dependency scanning to work, our CPPFPP/DEFS must be registered + # as COMPILE_DEFINITIONS, not simple added via CMAKE_Fortran_Flags. Also, CPPDEFS *must* + # be provided as a list, not a whitespace-separated string; otherwise, things get wonky. + separate_arguments(CPPDEFS_LIST UNIX_COMMAND "${CPPDEFS}") + target_compile_definitions(${MODEL_ARG} PRIVATE ${CPPDEFS_LIST}) + add_dependencies(${MODEL_ARG} genf90) + +endfunction(build_model) diff --git a/components/common_setup.cmake b/components/common_setup.cmake new file mode 100644 index 000000000000..ab8a2be3b32c --- /dev/null +++ b/components/common_setup.cmake @@ -0,0 +1,481 @@ +# This file contains configuration that is independent of the library being +# built. + +# Set module path +set(CMAKE_MODULE_PATH ${CIMEROOT}/src/CMake) + +# Add INCROOT to path for Depends and Include +set(MINCROOT "") +if (INCROOT) + list(APPEND CPP_DIRS ${INCROOT}) + set(MINCROOT ${INCROOT}) +endif () + +# JGF: I think SHAREDLIB paths shoudl come from build.py and not have to +# be recomputed here + +# JGF: Find unused/unneeded variables + +# Determine whether to compile threaded or not +# Set the THREADDIR for the shared build +# based on the threaded build status +if (SMP_PRESENT) + set(THREADDIR "threads") + set(compile_threaded TRUE) +else() + set(THREADDIR "nothreads") + set(compile_threaded FALSE) +endif() + +# set the debug directory based on the debug status +if (DEBUG) + set(DEBUGDIR "debug") +else() + set(DEBUGDIR "nodebug") +endif() + +if (USE_ESMF_LIB) + set(ESMFDIR "esmf") +else() + set(ESMFDIR "noesmf") +endif() + +# Determine whether any C++ code will be included in the build; +# currently, C++ code is included if and only if we're linking to the +# trilinos library or the Albany library. +set(USE_CXX FALSE) +if (USE_TRILINOS OR USE_ALBANY OR USE_KOKKOS) + set(USE_CXX TRUE) +endif() + +if (NOT MOD_SUFFIX) + set(MOD_SUFFIX "mod") +endif() + +#=============================================================================== +# set CPP options (must use this before any flags or cflags settings) +#=============================================================================== +include(${CASEROOT}/Macros.cmake) + +set(CPPDEFS "${CPPDEFS} ${USER_CPPDEFS} -D${OS}") + +# SLIBS comes from Macros, so this append must come after Macros are included +if (USE_FMS) + set(SLIBS "${SLIBS} -lfms") +endif() + +if (DEBUG) + # e3sm still has components that cannot build with -DDEBUG + if (CIME_MODEL STREQUAL "cesm") + set(CPPDEFS "${CPPDEFS} -DDEBUG") + endif() +else() + set(CPPDEFS "${CPPDEFS} -DNDEBUG") +endif() + +if (USE_ESMF_LIB) + set(CPPDEFS "${CPPDEFS} -DUSE_ESMF_LIB") +endif() + +if (COMP_INTERFACE STREQUAL "nuopc") + set(CPPDEFS "${CPPDEFS} -DNUOPC_INTERFACE") +else() + set(CPPDEFS "${CPPDEFS} -DMCT_INTERFACE") +endif() + +if (COMPARE_TO_NUOPC) + set(CPPDEFS "${CPPDEFS} -DCOMPARE_TO_NUOPC") +endif() + +if (MPILIB STREQUAL mpi-serial) + set(CPPDEFS "${CPPDEFS} -DNO_MPI2") +else() + set(CPPDEFS "${CPPDEFS} -DHAVE_MPI") +endif() + +if (PIO_VERSION STREQUAL "1") + set(CPPDEFS "${CPPDEFS} -DPIO1") +else() + set(USE_CXX TRUE) +endif() + +if (NOT SHAREDPATH) + set(SHAREDPATH ${COMPILER}/${MPILIB}/${DEBUGDIR}/${THREADDIR}/${COMP_INTERFACE}) + set(INSTALL_SHAREDPATH ${EXEROOT}/${SHAREDPATH}) +endif() + +# Decide whether to use a C++ or Fortran linker, based on whether we +# are using any C++ code and the compiler-dependent CXX_LINKER variable +if (USE_CXX AND CXX_LINKER STREQUAL "CXX") + if (MPILIB STREQUAL mpi-serial) + set(LD ${SCXX}) + else() + set(LD ${MPICXX}) + endif() +else() + if (MPILIB STREQUAL mpi-serial) + set(LD ${SFC}) + else() + set(LD ${MPIFC}) + endif() +endif() + +if (USE_CXX AND NOT SUPPORTS_CXX) + message(FATAL_ERROR "Fatal attempt to include C++ code on a compiler/machine combo that has not been set up to support C++") +endif() + +# Not clear how to escape commas for libraries with their own configure +# script, and they don't need this defined anyway, so leave this out of +# FPPDEFS. +if (HAS_F2008_CONTIGUOUS) + if (CPRE) + set(CONTIGUOUS_FLAG "${CPRE}USE_CONTIGUOUS=contiguous,") + else() + set(CONTIGUOUS_FLAG "-DUSE_CONTIGUOUS=contiguous,") + endif() +else() + if (CPRE) + set(CONTIGUOUS_FLAG "${CPRE}USE_CONTIGUOUS=") + else() + set(CONTIGUOUS_FLAG "-DUSE_CONTIGUOUS=") + endif() +endif() + +# JGF TODO: replace with findnetcdf +if (NETCDF_C_PATH) + if (NOT NETCDF_FORTRAN_PATH) + message(FATAL_ERROR "NETCDF_C_PATH specified without NETCDF_FORTRAN_PATH") + endif() + set(NETCDF_SEPARATE TRUE) + if (NOT INC_NETCDF_C) + set(INC_NETCDF_C ${NETCDF_C_PATH}/include) + endif() + if (NOT INC_NETCDF_FORTRAN) + set(INC_NETCDF_FORTRAN ${NETCDF_FORTRAN_PATH}/include) + endif() + if (NOT LIB_NETCDF_C) + set(LIB_NETCDF_C ${NETCDF_C_PATH}/lib) + endif() + if (NOT LIB_NETCDF_FORTRAN) + set(LIB_NETCDF_FORTRAN ${NETCDF_FORTRAN_PATH}/lib) + endif() +elseif (NETCDF_FORTRAN_PATH) + message(FATAL_ERROR "NETCDF_FORTRAN_PATH specified without NETCDF_C_PATH") +elseif (NETCDF_PATH) + set(NETCDF_SEPARATE FALSE) + if (NOT INC_NETCDF) + set(INC_NETCDF ${NETCDF_PATH}/include) + endif() + if (NOT LIB_NETCDF) + set(LIB_NETCDF ${NETCDF_PATH}/lib) + endif() +else() + message(FATAL_ERROR "NETCDF not found: Define NETCDF_PATH or NETCDF_C_PATH and NETCDF_FORTRAN_PATH in config_machines.xml or config_compilers.xml") +endif() + +if (MPILIB STREQUAL mpi-serial) + if (PNETCDF_PATH) + unset(PNETCDF_PATH) + endif() +else() + if (PNETCDF_PATH) + if (NOT INC_PNETCDF) + set(INC_PNETCDF ${PNETCDF_PATH}/include) + endif() + if (NOT LIB_PNETCDF) + set(LIB_PNETCDF ${PNETCDF_PATH}/lib) + endif() + endif() +endif() + +# Set PETSc info if it is being used +if (USE_PETSC) + if (PETSC_PATH) + if (NOT INC_PETSC) + set(INC_PETSC ${PETSC_PATH}/include) + endif() + if (NOT LIB_PETSC) + set(LIB_PETSC ${PETSC_PATH}/lib) + endif() + else() + message(FATAL_ERROR "PETSC_PATH must be defined when USE_PETSC is TRUE") + endif() + + # Get the "PETSC_LIB" list an env var + set(PETSC_DIR ${PETSC_PATH}) + find_package(PETSc) + set(PETSC_LIB ${PETSC_LIBRARIES}) +endif() + +if (USE_TRILINOS) + if (TRILINOS_PATH) + if (NOT INC_TRILINOS) + set(INC_TRILINOS ${TRILINOS_PATH}/include) + endif() + if (NOT LIB_TRILINOS) + set(LIB_TRILINOS ${TRILINOS_PATH}/lib) + endif() + else() + message(FATAL_ERROR "TRILINOS_PATH must be defined when USE_TRILINOS is TRUE") + endif() + + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${TRILINOS_PATH}) + find_package(Trilinos) +endif() + +if (USE_ALBANY) + if (ALBANY_PATH) + if (NOT INC_ALBANY) + set(INC_ALBANY ${ALBANY_PATH}/include) + endif() + if (NOT LIB_ALBANY) + set(LIB_ALBANY ${ALBANY_PATH}/lib) + endif() + else() + message(FATAL_ERROR "ALBANY_PATH must be defined when USE_ALBANY is TRUE") + endif() + + # get the "ALBANY_LINK_LIBS" list as an env var + file(READ ${ALBANY_PATH}/export_albany.in ALBANY_OUTPUT) + string(REPLACE "ALBANY_LINK_LIBS=" "" ALBANY_LINK_LIBS "${ALBANY_OUTPUT}") +endif() + +if (USE_KOKKOS) + include(${INSTALL_SHAREDPATH}/kokkos_generated_settings.cmake) + string (REPLACE ";" " " KOKKOS_CXXFLAGS_STR "${KOKKOS_CXXFLAGS}") + string (REPLACE ";" " " KOKKOS_LDFLAGS_STR "${KOKKOS_LDFLAGS}") + set(SLIBS "${SLIBS} ${KOKKOS_LIBS_LIST}") + set(CXXFLAGS "${CXXFLAGS} ${KOKKOS_CXXFLAGS_STR}") + set(CXX_LDFLAGS "${CXX_LDFLAGS} ${KOKKOS_LDFLAGS_STR}") +endif() + +# JGF: No one seems to be using this +# if (USE_MOAB) +# if (MOAB_PATH) +# set(CPPDEFS "${CPPDEFS} -DHAVE_MOAB") +# if (NOT INC_MOAB) +# set(INC_MOAB ${MOAB_PATH}/include) +# endif() +# if (NOT LIB_MOAB) +# set(LIB_MOAB ${MOAB_PATH}/lib) +# endif() +# else() +# message(FATAL_ERROR "MOAB_PATH must be defined when USE_MOAB is TRUE") +# endif() + +# # # get the "IMESH_LIBS" list as an env var +# #include $(LIB_MOAB)/iMesh-Defs.inc +# endif() + +# Set HAVE_SLASHPROC on LINUX systems which are not bluegene or Darwin (OSx) +string(FIND "${CPPDEFS}" "-DLINUX" HAS_DLINUX) +string(FIND "${CPPDEFS}" "DBG" HAS_DBG) +string(FIND "${CPPDEFS}" "Darwin" HAS_DARWIN) +if (NOT HAS_DLINUX EQUAL -1 AND HAS_DBG EQUAL -1 AND HAS_DARWIN EQUAL -1) + set(CPPDEFS "${CPPDEFS} -DHAVE_SLASHPROC") +endif() + +# Atleast on Titan+cray mpi, MPI_Irsends() are buggy, causing hangs during I/O +# Force PIO to use MPI_Isends instead of the default, MPI_Irsends +if (PIO_VERSION STREQUAL 2) + set(EXTRA_PIO_CPPDEFS "-DUSE_MPI_ISEND_FOR_FC") +else() + set(EXTRA_PIO_CPPDEFS "-D_NO_MPI_RSEND") +endif() + +if (LIB_PNETCDF) + set(CPPDEFS "${CPPDEFS} -D_PNETCDF") + set(SLIBS "${SLIBS} -L${LIB_PNETCDF} -lpnetcdf") +endif() + +# Set esmf.mk location with ESMF_LIBDIR having precedent over ESMFMKFILE +set(CIME_ESMFMKFILE "undefined_ESMFMKFILE") +if (ESMFMKFILE) + set(CIME_ESMFMKFILE ${ESMFMKFILE}) +endif() +if (ESMF_LIBDIR) + set(CIME_ESMFMKFILE ${ESMF_LIBDIR}/esmf.mk) +endif() + +# For compiling and linking with external ESMF. +# If linking to external ESMF library then include esmf.mk +# ESMF_F90COMPILEPATHS +# ESMF_F90LINKPATHS +# ESMF_F90LINKRPATHS +# ESMF_F90ESMFLINKLIBS +if (USE_ESMF_LIB) + # include(${CIME_ESMFMKFILE}) # JGF SKIPPING FOR NOW + # Will need something like 'make -f esmf.mk -p 2> /dev/null | grep ESMF_F90COMPILEPATHS' + #set(CPPDEFS "${CPPDEFS} -DESMF_VERSION_MAJOR=${ESMF_VERSION_MAJOR} -DESMF_VERSION_MINOR=${ESMF_VERSION_MINOR}") + #set(FFLAGS "${FFLAGS} ${ESMF_F90COMPILEPATHS}") + #set(SLIBS "${SLIBS} ${ESMF_F90LINKPATHS} ${ESMF_F90LINKRPATHS} ${ESMF_F90ESMFLINKLIBS}") + message(FATAL_ERROR "ESMF not supported in CMake yet") +endif() + +#=============================================================================== +# User-specified INCLDIR +#=============================================================================== + +set(INCLDIR "-I.") +if (USER_INCLDIR) + set(INCLDIR "${INCLDIR} -I${USER_INCLDIR}") +endif() + +#=============================================================================== +# Set compilers +#=============================================================================== + +if (MPILIB STREQUAL "mpi-serial") + set(CC ${SCC}) + set(FC ${SFC}) + set(CXX ${SCXX}) + set(MPIFC ${SFC}) + set(MPICC ${SCC}) + set(MPICXX ${SCXX}) +else() + set(CC ${MPICC}) + set(FC ${MPIFC}) + set(CXX ${MPICXX}) + if (MPI_PATH) + set(INC_MPI ${MPI_PATH}/include) + set(LIB_MPI ${MPI_PATH}/lib) + endif() +endif() +set(CSM_SHR_INCLUDE ${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/include) + +#=============================================================================== +# Set include paths (needed after override for any model specific builds below) +#=============================================================================== +set(INCLDIR "${INCLDIR} -I${INSTALL_SHAREDPATH}/include -I${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/include") + +if (NOT NETCDF_SEPARATE) + set(INCLDIR "${INCLDIR} -I${INC_NETCDF}") +else() + set(INCLDIR "${INCLDIR} -I${INC_NETCDF_C} -I${INC_NETCDF_FORTRAN}") +endif() + +foreach(ITEM MOD_NETCDF INC_MPI INC_PNETCDF INC_PETSC INC_TRILINOS INC_ALBANY) # INC_MOAB) + if (${ITEM}) + set(INCLDIR "${INCLDIR} -I${${ITEM}}") + endif() +endforeach() + +if (NOT MCT_LIBDIR) + set(MCT_LIBDIR "${INSTALL_SHAREDPATH}/lib") +endif() + +if (PIO_LIBDIR) + if (PIO_VERSION STREQUAL ${PIO_VERSION_MAJOR}) + set(INCLDIR "${INCLDIR} -I${PIO_INCDIR}") + set(SLIBS "${SLIBS} -L${PIO_LIBDIR}") + else() + # If PIO_VERSION_MAJOR doesnt match, build from source + unset(PIO_LIBDIR) + endif() +endif() +if (NOT PIO_LIBDIR) + set(PIO_LIBDIR "${INSTALL_SHAREDPATH}/lib") +endif() + +if (NOT GPTL_LIBDIR) + set(GPTL_LIBDIR "${INSTALL_SHAREDPATH}/lib") +endif() + +if (NOT GLC_DIR) + set(GLC_DIR "${EXEROOT}/glc") +endif() + +if (NOT CISM_LIBDIR) + set(CISM_LIBDIR "${GLC_DIR}/lib") +endif() + +if (NOT GLCROOT) + # Backwards compatibility + set(GLCROOT "${CIMEROOT}/../components/cism") +endif() + +set(INCLDIR "${INCLDIR} -I${INSTALL_SHAREDPATH}/include") + +string(FIND "${CAM_CONFIG_OPTS}" "-cosp" HAS_COSP) +if (NOT HAS_COSP EQUAL -1) + # The following is for the COSP simulator code: + get_filename_component(COSP_LIBDIR ${EXEROOT}/atm/obj/cam/src/physics/cosp ABSOLUTE) +endif() + +# System libraries (netcdf, mpi, pnetcdf, esmf, trilinos, etc.) +if (NOT SLIBS) + if (NOT NETCDF_SEPARATE) + set(SLIBS "-L${LIB_NETCDF} -lnetcdff -lnetcdf") + else() + set(SLIBS "-L${LIB_NETCDF_FORTRAN} -L${LIB_NETCDF_C} -lnetcdff -lnetcdf") + endif() +endif() + +if (LAPACK_LIBDIR) + set(SLIBS "${SLIBS} -L${LAPACK_LIBDIR} -llapack -lblas") +endif() + +if (LIB_MPI) + if (NOT MPI_LIB_NAME) + set(SLIBS "${SLIBS} -L${LIB_MPI} -lmpi") + else() + set(SLIBS "${SLIBS} -L${LIB_MPI} -l${MPI_LIB_NAME}") + endif() +endif() + +# Add PETSc libraries +if (USE_PETSC) + set(SLIBS "${SLIBS} ${PETSC_LIB}") +endif() + +# Add trilinos libraries; too be safe, we include all libraries included in the trilinos build, +# as well as all necessary third-party libraries +if (USE_TRILINOS) + set(SLIBS "${SLIBS} -L${LIB_TRILINOS} ${Trilinos_LIBRARIES} ${Trilinos_TPL_LIBRARY_DIRS} ${Trilinos_TPL_LIBRARIES}") +endif() + +# Add Albany libraries. These are defined in the ALBANY_LINK_LIBS env var that was included above +if (USE_ALBANY) + set(SLIBS "${SLIBS} ${ALBANY_LINK_LIBS}") +endif() + +# Add MOAB libraries. These are defined in the MOAB_LINK_LIBS env var that was included above +# if (USE_MOAB) +# set(SLIBS "${SLIBS} ${IMESH_LIBS}") +# endif() + +# Add libraries and flags that we need on the link line when C++ code is included +# We need to do these additions after CONFIG_ARGS is set, because they can sometimes break configure for mct, etc., +# if they are added to LDFLAGS in CONFIG_ARGS. +if (USE_CXX) + if (CXX_LIBS) + set(SLIBS "${SLIBS} ${CXX_LIBS}") + endif() + + if (CXX_LDFLAGS) + set(LDFLAGS "${LDFLAGS} ${SLIBS} ${CXX_LDFLAGS}") + endif() +endif() + +# Remove arch flag if it exists +string(REGEX REPLACE "-arch[^ ]+" "" F90_LDFLAGS "${LDFLAGS}") + +if (PIO_VERSION STREQUAL 2) + # This is a pio2 library + set(PIOLIB "${PIO_LIBDIR}/libpiof.a ${PIO_LIBDIR}/libpioc.a") + set(PIOLIBNAME "-lpiof -lpioc") + set(PIO_SRC_DIR "${CIMEROOT}/src/externals/pio2") +else() + # This is a pio1 library + set(PIOLIB "${PIO_LIBDIR}/libpio.a") + set(PIOLIBNAME "-lpio") + if (NOT EXISTS "${CIMEROOT}/src/externals/pio1/pio") + set(PIO_SRC_DIR "${CIMEROOT}/src/externals/pio1") + else() + set(PIO_SRC_DIR "${CIMEROOT}/src/externals/pio1/pio") + endif() +endif() + +set(MCTLIBS "${MCT_LIBDIR}/libmct.a ${MCT_LIBDIR}/libmpeu.a") + +set(GPTLLIB "${GPTL_LIBDIR}/libgptl.a") From abc854e62a1813dfe4d683356b9f0188e65305b7 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 28 Jun 2019 16:04:37 -0600 Subject: [PATCH 10/48] Progress, A cases now seem to build with a single cmake invocation --- cime/scripts/lib/CIME/build.py | 11 +++-- cime/scripts/lib/CIME/buildlib.py | 6 +-- components/CMakeLists.txt | 17 ++++---- components/build_model.cmake | 69 +++++++++++++------------------ components/common_setup.cmake | 37 +++++++++++++---- 5 files changed, 74 insertions(+), 66 deletions(-) diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index 0f55e2f46cbe..2465afc47890 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -172,13 +172,18 @@ def _build_model_cmake(build_threaded, exeroot, incroot, complist, # Call CMake cmake_args = get_standard_cmake_args(case) - cmake_cmd = "cmake {} {}/components &> {}".format(cmake_args, srcroot, bldlog) - logger.info("Configuring with cmake cmd: {}".format(cmake_cmd)) + cmake_cmd = "cmake {} {}/components >> {} 2>&1".format(cmake_args, srcroot, bldlog) + with open(bldlog, "w") as fd: + fd.write("Configuring with cmake cmd:\n{}\n\n".format(cmake_cmd)) stat = run_cmd(cmake_cmd, from_dir=bldroot)[0] # Call Make if stat == 0: - stat = run_cmd("{} -j {} >> {} 2>&1".format(gmake, gmake_j, bldlog), from_dir=bldroot)[0] + make_cmd = "{} -j {} >> {} 2>&1".format(gmake, gmake_j, bldlog) + with open(bldlog, "a") as fd: + fd.write("\n\nBuilding with make cmd:\n{}\n\n".format(make_cmd)) + + stat = run_cmd(make_cmd, from_dir=bldroot)[0] expect(stat == 0, "BUILD FAIL: build {} failed, cat {}".format(model, bldlog)) diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index bd2f1bf7fa87..2bb37660c497 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -69,11 +69,11 @@ def build_cime_component_lib(case, compname, libroot, bldroot): with open(os.path.join(confdir, "CCSM_cppdefs"), "w") as out: out.write("") - safe_copy(os.path.join(confdir, "Filepath"), bldroot) - safe_copy(os.path.join(confdir, "CCSM_cppdefs"), bldroot) - # Build the component if get_model() != "e3sm": + safe_copy(os.path.join(confdir, "Filepath"), bldroot) + safe_copy(os.path.join(confdir, "CCSM_cppdefs"), bldroot) + run_gmake(case, compclass, libroot, bldroot) ############################################################################### diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 4ae7d80567f6..1cc5244e77db 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -32,17 +32,14 @@ foreach(ITEM IN LISTS FILEPATHS) get_filename_component(MODELCONF ${FILEPATH_DIR} NAME) string(REPLACE "conf" "" MODEL "${MODELCONF}") - message("Found component model ${MODEL}") - list(APPEND MODELS ${MODEL}) + if (NOT MODEL STREQUAL "cpl") + message("Found component model ${MODEL}") + list(APPEND MODELS ${MODEL}) - build_model(${MODEL} ${MODELCONF} ${ITEM}) + build_model(${MODEL} ${FILEPATH_DIR} "") + endif() endforeach() -set(EXEC_SE "${CIME_MODEL}.exe") -add_executable(${EXEC_SE}) -set(ALL_LIBS "${ULIBDEP} ${MCTLIBS} ${PIOLIB} ${GPTLLIB} ${SLIBS} ${MLIBS} ${F90_LDFLAGS}") -separate_arguments(ALL_LIBS_LIST UNIX_COMMAND "${ALL_LIBS}") -foreach(ITEM IN LISTS ALL_LIBS_LIST) - target_link_libraries(${EXEC_SE} ${ITEM}) -endforeach() +message("Configuring exe with cpl") +build_model("cpl" "${BUILDCONF}/cplconf" "${MODELS}") diff --git a/components/build_model.cmake b/components/build_model.cmake index ec9965e96376..34247fac8bde 100644 --- a/components/build_model.cmake +++ b/components/build_model.cmake @@ -1,11 +1,11 @@ -function(build_model MODEL_ARG MODELCONF_ARG FILEPATH_ARG) +function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) # Load dependency search path. - file(STRINGS ${FILEPATH_ARG} FILEPATH_DIRS) + file(STRINGS ${MODELCONF_DIR_ARG}/Filepath FILEPATH_DIRS) set(CPP_DIRS ${FILEPATH_DIRS}) list(APPEND CPP_DIRS ".") # Load cppdefs - set(CCSM_CPPDEFS_FILE "${MODELCONF_ARG}/CCSM_cppdefs") + set(CCSM_CPPDEFS_FILE "${MODELCONF_DIR_ARG}/CCSM_cppdefs") if (EXISTS ${CCSM_CPPDEFS_FILE}) file(READ ${CCSM_CPPDEFS_FILE} CCSM_CPPDEFS) string(STRIP "${CCSM_CPPDEFS}" CCSM_CPPDEFS) @@ -13,7 +13,7 @@ function(build_model MODEL_ARG MODELCONF_ARG FILEPATH_ARG) endif() if (MODEL_ARG STREQUAL "cpl") - set(INCLDIR "${INCLDIR} -I${EXEROOT}/atm/obj -I${EXEROOT}/ice/obj -I${EXEROOT}/ocn/obj -I${EXEROOT}/glc/obj -I${EXEROOT}/rof/obj -I${EXEROOT}/wav/obj -I${EXEROOT}/esp/obj -I${EXEROOT}/iac/obj") + list(APPEND INCLDIR "${EXEROOT}/atm/obj" "${EXEROOT}/ice/obj" "${EXEROOT}/ocn/obj" "${EXEROOT}/glc/obj" "${EXEROOT}/rof/obj" "${EXEROOT}/wav/obj" "${EXEROOT}/esp/obj" "${EXEROOT}/iac/obj") endif() if (MODEL_ARG STREQUAL "cam") @@ -60,7 +60,7 @@ function(build_model MODEL_ARG MODELCONF_ARG FILEPATH_ARG) endforeach() foreach(SOURCE_FILE IN LISTS SOURCES) -i get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) + get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) if (SOURCE_EXT STREQUAL ".F90.in") string(REPLACE ".in" "" SOURCE_NO_IN ${SOURCE_FILE}) list(APPEND GEN_F90_SOURCES ${SOURCE_NO_IN}) @@ -71,7 +71,7 @@ i get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) foreach(ITEM IN LISTS CPP_DIRS) if (EXISTS ${ITEM}) - set(INCLDIR "${INCLDIR} -I${ITEM}") + list(APPEND INCLDIR "${ITEM}") endif() endforeach() @@ -97,12 +97,12 @@ i get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) else() set(LNDLIB "liblnd.a") endif() - set(INCLDIR "${INCLDIR} -I${LNDOBJDIR}") + list(APPEND INCLDIR "${LNDOBJDIR}") else() set(LNDLIB "libclm.a") set(LNDOBJDIR "${SHAREDLIBROOT}/${SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/clm/obj") set(LNDLIBDIR "${EXEROOT}/${SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/lib") - set(INCLDIR "${INCLDIR} -I${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/include") + list(APPEND INCLDIR "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/include") if (MODEL_ARG STREQUAL "clm") set(INCLUDE_DIR "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/include") endif() @@ -110,18 +110,7 @@ i get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) if (NOT ULIBDEP) if (LIBROOT) - set(ULIBDEP "${LIBROOT}/libatm.a") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libice.a") - set(ULIBDEP "${ULIBDEP} ${LNDLIBDIR}/${LNDLIB}") - set(INCLDIR "${INCLDIR} -I${LNDOBJDIR}") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libocn.a") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/librof.a") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libglc.a") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libwav.a") - if (NOT COMP_INTERFACE STREQUAL "nuopc") - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libiac.a") - endif() - set(ULIBDEP "${ULIBDEP} ${LIBROOT}/libesp.a") + list(APPEND INCLDIR "${LNDOBJDIR}") endif() endif() @@ -138,26 +127,7 @@ i get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) set(CSMSHARELIB "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/lib/libcsm_share.a") set(ULIBDEP "${ULIBDEP} ${CSMSHARELIB}") - #------------------------------------------------------------------------------ - # Set key cmake vars - #------------------------------------------------------------------------------ - - set(CMAKE_Fortran_FLAGS "${FFLAGS} ${INCLDIR}") - set(CMAKE_C_FLAGS "${CFLAGS} ${INCLDIR}") - set(CMAKE_CXX_FLAGS "${CXXFLAGS} ${INCLDIR}") - set(CMAKE_VERBOSE_MAKEFILE TRUE) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../..) - - set(CMAKE_C_COMPILER ${CC}) - set(CMAKE_CXX_COMPILER ${CXX}) - set(CMAKE_Fortran_COMPILER ${FC}) - set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}") - # do the necessary genf90s - add_custom_target(genf90 - DEPENDS ${CIMEROOT}/src/externals/genf90/genf90.pl) foreach (SRC_FILE IN LISTS GEN_F90_SOURCES) get_filename_component(BASENAME ${SRC_FILE} NAME) add_custom_command ( @@ -209,8 +179,22 @@ i get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) set(MLIBS "${MLIBS} ${MPISERIAL}") endif() - add_library(${MODEL_ARG}) - target_sources(${MODEL_ARG} PRIVATE ${SOURCES}) + if (MODEL_ARG STREQUAL "cpl") + set(MODEL_ARG "${CIME_MODEL}.exe") + add_executable(${MODEL_ARG}) + target_sources(${MODEL_ARG} PRIVATE ${SOURCES}) + set(ALL_LIBS "${ULIBDEP} ${MCTLIBS} ${PIOLIB} ${GPTLLIB} ${SLIBS} ${MLIBS} ${F90_LDFLAGS}") + separate_arguments(ALL_LIBS_LIST UNIX_COMMAND "${ALL_LIBS}") + foreach(ITEM IN LISTS ALL_MODELS_ARG) + target_link_libraries(${MODEL_ARG} ${ITEM}) + endforeach() + foreach(ITEM IN LISTS ALL_LIBS_LIST) + target_link_libraries(${MODEL_ARG} ${ITEM}) + endforeach() + else() + add_library(${MODEL_ARG}) + target_sources(${MODEL_ARG} PRIVATE ${SOURCES}) + endif() # Subtle: In order for fortran dependency scanning to work, our CPPFPP/DEFS must be registered # as COMPILE_DEFINITIONS, not simple added via CMAKE_Fortran_Flags. Also, CPPDEFS *must* @@ -219,4 +203,7 @@ i get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) target_compile_definitions(${MODEL_ARG} PRIVATE ${CPPDEFS_LIST}) add_dependencies(${MODEL_ARG} genf90) + # Set flags for target + target_include_directories(${MODEL_ARG} PRIVATE ${INCLDIR}) + endfunction(build_model) diff --git a/components/common_setup.cmake b/components/common_setup.cmake index ab8a2be3b32c..e6ee008c8439 100644 --- a/components/common_setup.cmake +++ b/components/common_setup.cmake @@ -1,8 +1,12 @@ # This file contains configuration that is independent of the library being # built. -# Set module path +# Set global cmake settings set(CMAKE_MODULE_PATH ${CIMEROOT}/src/CMake) +set(CMAKE_VERBOSE_MAKEFILE TRUE) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../..) # Add INCROOT to path for Depends and Include set(MINCROOT "") @@ -316,9 +320,9 @@ endif() # User-specified INCLDIR #=============================================================================== -set(INCLDIR "-I.") +set(INCLDIR ".") if (USER_INCLDIR) - set(INCLDIR "${INCLDIR} -I${USER_INCLDIR}") + list(APPEND INCLDIR "${USER_INCLDIR}") endif() #=============================================================================== @@ -346,17 +350,17 @@ set(CSM_SHR_INCLUDE ${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_V #=============================================================================== # Set include paths (needed after override for any model specific builds below) #=============================================================================== -set(INCLDIR "${INCLDIR} -I${INSTALL_SHAREDPATH}/include -I${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/include") +list(APPEND INCLDIR "${INSTALL_SHAREDPATH}/include" "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/${NINST_VALUE}/include") if (NOT NETCDF_SEPARATE) - set(INCLDIR "${INCLDIR} -I${INC_NETCDF}") + list(APPEND INCLDIR "${INC_NETCDF}") else() - set(INCLDIR "${INCLDIR} -I${INC_NETCDF_C} -I${INC_NETCDF_FORTRAN}") + list(APPEND INCLDIR "${INC_NETCDF_C}" "${INC_NETCDF_FORTRAN}") endif() foreach(ITEM MOD_NETCDF INC_MPI INC_PNETCDF INC_PETSC INC_TRILINOS INC_ALBANY) # INC_MOAB) if (${ITEM}) - set(INCLDIR "${INCLDIR} -I${${ITEM}}") + list(APPEND INCLDIR "${${ITEM}}") endif() endforeach() @@ -366,7 +370,7 @@ endif() if (PIO_LIBDIR) if (PIO_VERSION STREQUAL ${PIO_VERSION_MAJOR}) - set(INCLDIR "${INCLDIR} -I${PIO_INCDIR}") + list(APPEND INCLDIR "${PIO_INCDIR}") set(SLIBS "${SLIBS} -L${PIO_LIBDIR}") else() # If PIO_VERSION_MAJOR doesnt match, build from source @@ -394,7 +398,7 @@ if (NOT GLCROOT) set(GLCROOT "${CIMEROOT}/../components/cism") endif() -set(INCLDIR "${INCLDIR} -I${INSTALL_SHAREDPATH}/include") +list(APPEND INCLDIR "${INSTALL_SHAREDPATH}/include") string(FIND "${CAM_CONFIG_OPTS}" "-cosp" HAS_COSP) if (NOT HAS_COSP EQUAL -1) @@ -479,3 +483,18 @@ endif() set(MCTLIBS "${MCT_LIBDIR}/libmct.a ${MCT_LIBDIR}/libmpeu.a") set(GPTLLIB "${GPTL_LIBDIR}/libgptl.a") + +add_custom_target(genf90 + DEPENDS ${CIMEROOT}/src/externals/genf90/genf90.pl) + +#------------------------------------------------------------------------------ +# Set key cmake vars +#------------------------------------------------------------------------------ +set(CMAKE_C_COMPILER ${CC}) +set(CMAKE_CXX_COMPILER ${CXX}) +set(CMAKE_Fortran_COMPILER ${FC}) + +set(CMAKE_Fortran_FLAGS "${FFLAGS}") +set(CMAKE_C_FLAGS "${CFLAGS}") +set(CMAKE_CXX_FLAGS "${CXXFLAGS}") +set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}") From 403d62b9b433ed12a7879d4f37dfacc3b323ddff Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 28 Jun 2019 20:35:32 -0600 Subject: [PATCH 11/48] Progress, MPAS working with single CMake call --- cime/scripts/Tools/get_standard_makefile_args | 7 +--- cime/scripts/lib/CIME/build.py | 20 +++++----- cime/scripts/lib/CIME/buildlib.py | 3 +- cime/src/drivers/mct/cime_config/buildlib | 1 - components/CMakeLists.txt | 19 ++++++++- components/build_model.cmake | 2 +- components/build_mpas_model.cmake | 24 +++++++++++ components/cam/cime_config/buildlib | 1 - components/cice/cime_config/buildlib | 1 - components/clm/cime_config/buildlib | 1 - components/common_setup.cmake | 31 ++------------ components/mosart/cime_config/buildlib | 1 - .../mpas-albany-landice/cime_config/buildlib | 40 +------------------ components/mpas-ocean/cime_config/buildlib | 34 +--------------- components/mpas-seaice/cime_config/buildlib | 34 +--------------- 15 files changed, 62 insertions(+), 157 deletions(-) create mode 100644 components/build_mpas_model.cmake diff --git a/cime/scripts/Tools/get_standard_makefile_args b/cime/scripts/Tools/get_standard_makefile_args index ba0d306ac46b..6f4f436bfb0d 100755 --- a/cime/scripts/Tools/get_standard_makefile_args +++ b/cime/scripts/Tools/get_standard_makefile_args @@ -8,7 +8,6 @@ should only be used when the components buildlib is not written in python from standard_script_setup import * from CIME.build import get_standard_makefile_args -from CIME.build import get_standard_cmake_args from CIME.case import Case from CIME.test_status import * @@ -24,11 +23,9 @@ def parse_command_line(args, description): help="Case directory to build.\n" "Default is current directory.") - parser.add_argument("--cmake", action="store_true", help="Get cmake-style args instead of Make") - args = CIME.utils.parse_args_and_handle_standard_logging_options(args, parser) - return args.caseroot, args.cmake + return args.caseroot ############################################################################### def _main_func(description): @@ -37,7 +34,7 @@ def _main_func(description): success = True with Case(caseroot) as case: - print("{}".format(get_standard_cmake_args(case) if cmake else get_standard_makefile_args(case))) + print(get_standard_makefile_args(case)) sys.exit(0 if success else 1) diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index 2465afc47890..4c506aece595 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -27,7 +27,7 @@ def get_standard_makefile_args(case, shared_lib=False): return make_args -def get_standard_cmake_args(case, shared_lib=False): +def get_standard_cmake_args(case, sharedpath, shared_lib=False): cmake_args = "-DCIME_MODEL={} ".format(case.get_value("MODEL")) ocn_model = case.get_value("COMP_OCN") @@ -35,6 +35,8 @@ def get_standard_cmake_args(case, shared_lib=False): if ocn_model == 'mom' or atm_model == "fv3gfs": cmake_args += " -DUSE_FMS=TRUE" + cmake_args += " -DINSTALL_SHAREDPATH={}".format(os.path.join(case.get_value("EXEROOT"), sharedpath)) + if not shared_lib: cmake_args += " -DUSE_KOKKOS={} ".format(stringify_bool(uses_kokkos(case))) for var in _CMD_ARGS_FOR_BUILD: @@ -145,12 +147,12 @@ def _build_model(build_threaded, exeroot, incroot, complist, ############################################################################### def _build_model_cmake(build_threaded, exeroot, incroot, complist, - lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case): + lid, caseroot, cimeroot, compiler, buildlist, comp_interface, sharedpath, case): ############################################################################### - model = get_model() + cime_model = get_model() bldroot = os.path.join(exeroot, "bld") libroot = os.path.join(exeroot, "lib") - bldlog = os.path.join(exeroot, "{}.bldlog.{}".format(model, lid)) + bldlog = os.path.join(exeroot, "{}.bldlog.{}".format(cime_model, lid)) srcroot = case.get_value("SRCROOT") gmake_j = case.get_value("GMAKE_J") gmake = case.get_value("GMAKE") @@ -171,7 +173,7 @@ def _build_model_cmake(build_threaded, exeroot, incroot, complist, _create_build_metadata_for_component(config_dir, libroot, bldroot, case) # Call CMake - cmake_args = get_standard_cmake_args(case) + cmake_args = get_standard_cmake_args(case, sharedpath) cmake_cmd = "cmake {} {}/components >> {} 2>&1".format(cmake_args, srcroot, bldlog) with open(bldlog, "w") as fd: fd.write("Configuring with cmake cmd:\n{}\n\n".format(cmake_cmd)) @@ -185,10 +187,10 @@ def _build_model_cmake(build_threaded, exeroot, incroot, complist, stat = run_cmd(make_cmd, from_dir=bldroot)[0] - expect(stat == 0, "BUILD FAIL: build {} failed, cat {}".format(model, bldlog)) + expect(stat == 0, "BUILD FAIL: build {} failed, cat {}".format(cime_model, bldlog)) # Copy the just-built ${MODEL}.exe to ${MODEL}.exe.$LID - safe_copy("{}/{}.exe".format(exeroot, model), "{}/{}.exe.{}".format(exeroot, model, lid)) + safe_copy("{}/{}.exe".format(exeroot, cime_model), "{}/{}.exe.{}".format(exeroot, cime_model, lid)) return [bldlog] @@ -571,11 +573,9 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, cimeroot, libroot, lid, compiler, buildlist, comp_interface) if not sharedlib_only: - os.environ["INSTALL_SHAREDPATH"] = os.path.join(exeroot, sharedpath) # for MPAS makefile generators - if get_model() == "e3sm": logs.extend(_build_model_cmake(build_threaded, exeroot, incroot, complist, - lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case)) + lid, caseroot, cimeroot, compiler, buildlist, comp_interface, sharedpath, case)) else: logs.extend(_build_model(build_threaded, exeroot, incroot, complist, lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case)) diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index 2bb37660c497..efe14f61c1ca 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -5,7 +5,8 @@ from CIME.XML.standard_module_setup import * from CIME.case import Case from CIME.utils import parse_args_and_handle_standard_logging_options, setup_standard_logging_options, get_model, run_bld_cmd_ensure_logging, safe_copy -from CIME.build import get_standard_makefile_args, get_standard_cmake_args +from CIME.build import get_standard_makefile_args + import sys, os, argparse logger = logging.getLogger(__name__) diff --git a/cime/src/drivers/mct/cime_config/buildlib b/cime/src/drivers/mct/cime_config/buildlib index 5b3cd66ba3ed..1133e66f26f5 100755 --- a/cime/src/drivers/mct/cime_config/buildlib +++ b/cime/src/drivers/mct/cime_config/buildlib @@ -13,7 +13,6 @@ from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import expect, run_bld_cmd_ensure_logging -from CIME.build import get_standard_cmake_args logger = logging.getLogger(__name__) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1cc5244e77db..a5e2d136c88f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -18,14 +18,29 @@ cmake_policy(SET CMP0057 NEW) project(E3SM C CXX Fortran) +include(${CMAKE_CURRENT_SOURCE_DIR}/build_mpas_model.cmake) + +set(BUILDCONF ${CMAKE_BINARY_DIR}/../../Buildconf) + +# Do any MPAS builds first since they manage their own flags +file(GLOB MPASCONFS "${BUILDCONF}/mpas*conf") +foreach(ITEM IN LISTS MPASCONFS) + message("JGF INFO ${ITEM}") + get_filename_component(MPASCONF ${ITEM} NAME) + string(REPLACE "conf" "" MODEL "${MPASCONF}") + + message("Found component model ${MODEL}") + build_mpas_model(${MODEL}) + + list(APPEND MODELS ${MPAS_COMPNAME}) +endforeach() + include(${CMAKE_CURRENT_SOURCE_DIR}/common_setup.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/build_model.cmake) # For each component that has registered itself to be built, read in Filepath and # CCSM_cppdefs and build it. We identify the components by looking for Buildconf/*/Filepath # files. - -set(BUILDCONF ${CMAKE_BINARY_DIR}/../../Buildconf) file(GLOB FILEPATHS "${BUILDCONF}/*/Filepath") foreach(ITEM IN LISTS FILEPATHS) get_filename_component(FILEPATH_DIR ${ITEM} DIRECTORY) diff --git a/components/build_model.cmake b/components/build_model.cmake index 34247fac8bde..47f5b5df86a3 100644 --- a/components/build_model.cmake +++ b/components/build_model.cmake @@ -13,7 +13,7 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) endif() if (MODEL_ARG STREQUAL "cpl") - list(APPEND INCLDIR "${EXEROOT}/atm/obj" "${EXEROOT}/ice/obj" "${EXEROOT}/ocn/obj" "${EXEROOT}/glc/obj" "${EXEROOT}/rof/obj" "${EXEROOT}/wav/obj" "${EXEROOT}/esp/obj" "${EXEROOT}/iac/obj") + list(APPEND INCLDIR "${EXEROOT}/atm/obj" "${EXEROOT}/ice/obj" "${EXEROOT}/ocn/obj" "${EXEROOT}/glc/obj" "${EXEROOT}/rof/obj" "${EXEROOT}/wav/obj" "${EXEROOT}/esp/obj" "${EXEROOT}/iac/obj" "${EXEROOT}/bld/mpas-source/src") endif() if (MODEL_ARG STREQUAL "cam") diff --git a/components/build_mpas_model.cmake b/components/build_mpas_model.cmake new file mode 100644 index 000000000000..65710f7c8d43 --- /dev/null +++ b/components/build_mpas_model.cmake @@ -0,0 +1,24 @@ +function(build_mpas_model MODEL_ARG) + + if (MODEL_ARG STREQUAL "mpaso") + set(CORE "ocean") + set(DRIVER "ocean_cesm_driver") + set(MPAS_COMPNAME "ocn" PARENT_SCOPE) + elseif (MODEL_ARG STREQUAL "mpassi") + set(CORE "seaice") + set(DRIVER "seaice_acme_driver") + set(MPAS_COMPNAME "ice" PARENT_SCOPE) + elseif (MODEL_ARG STREQUAL "mpasli") + set(CORE "landice") + set(DRIVER "glc_cesm_driver") + set(MPAS_COMPNAME "glc" PARENT_SCOPE) + if (USE_ALBANY) + set(ALBANY True) + endif() + else() + message(FATAL "Unrecognized MPAS model ${MODEL_ARG}") + endif() + + add_subdirectory("mpas-source/src") + +endfunction(build_mpas_model) diff --git a/components/cam/cime_config/buildlib b/components/cam/cime_config/buildlib index 65e3f1361335..9b6b5a0c28de 100755 --- a/components/cam/cime_config/buildlib +++ b/components/cam/cime_config/buildlib @@ -11,7 +11,6 @@ sys.path.append(_LIBDIR) from standard_script_setup import * from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy -from CIME.build import get_standard_cmake_args from CIME.case import Case from CIME.buildlib import parse_input diff --git a/components/cice/cime_config/buildlib b/components/cice/cime_config/buildlib index 0c69279fc14a..e1a168159f96 100755 --- a/components/cice/cime_config/buildlib +++ b/components/cice/cime_config/buildlib @@ -16,7 +16,6 @@ from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy -from CIME.build import get_standard_cmake_args logger = logging.getLogger(__name__) diff --git a/components/clm/cime_config/buildlib b/components/clm/cime_config/buildlib index 24ca12ebe32e..eaaeb054354f 100755 --- a/components/clm/cime_config/buildlib +++ b/components/clm/cime_config/buildlib @@ -16,7 +16,6 @@ from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy -from CIME.build import get_standard_cmake_args logger = logging.getLogger(__name__) diff --git a/components/common_setup.cmake b/components/common_setup.cmake index e6ee008c8439..87531096f4b1 100644 --- a/components/common_setup.cmake +++ b/components/common_setup.cmake @@ -4,9 +4,9 @@ # Set global cmake settings set(CMAKE_MODULE_PATH ${CIMEROOT}/src/CMake) set(CMAKE_VERBOSE_MAKEFILE TRUE) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../..) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/..) # Add INCROOT to path for Depends and Include set(MINCROOT "") @@ -18,26 +18,6 @@ endif () # JGF: I think SHAREDLIB paths shoudl come from build.py and not have to # be recomputed here -# JGF: Find unused/unneeded variables - -# Determine whether to compile threaded or not -# Set the THREADDIR for the shared build -# based on the threaded build status -if (SMP_PRESENT) - set(THREADDIR "threads") - set(compile_threaded TRUE) -else() - set(THREADDIR "nothreads") - set(compile_threaded FALSE) -endif() - -# set the debug directory based on the debug status -if (DEBUG) - set(DEBUGDIR "debug") -else() - set(DEBUGDIR "nodebug") -endif() - if (USE_ESMF_LIB) set(ESMFDIR "esmf") else() @@ -103,11 +83,6 @@ else() set(USE_CXX TRUE) endif() -if (NOT SHAREDPATH) - set(SHAREDPATH ${COMPILER}/${MPILIB}/${DEBUGDIR}/${THREADDIR}/${COMP_INTERFACE}) - set(INSTALL_SHAREDPATH ${EXEROOT}/${SHAREDPATH}) -endif() - # Decide whether to use a C++ or Fortran linker, based on whether we # are using any C++ code and the compiler-dependent CXX_LINKER variable if (USE_CXX AND CXX_LINKER STREQUAL "CXX") diff --git a/components/mosart/cime_config/buildlib b/components/mosart/cime_config/buildlib index c1ad8378afbe..5aa6f02c7905 100755 --- a/components/mosart/cime_config/buildlib +++ b/components/mosart/cime_config/buildlib @@ -16,7 +16,6 @@ from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import expect, run_bld_cmd_ensure_logging -from CIME.build import get_standard_cmake_args logger = logging.getLogger(__name__) diff --git a/components/mpas-albany-landice/cime_config/buildlib b/components/mpas-albany-landice/cime_config/buildlib index 8b9926c3d5e6..e208e21e8909 100755 --- a/components/mpas-albany-landice/cime_config/buildlib +++ b/components/mpas-albany-landice/cime_config/buildlib @@ -17,51 +17,13 @@ from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy -from CIME.build import get_standard_cmake_args logger = logging.getLogger(__name__) ############################################################################### def buildlib(bldroot, installpath, case): ############################################################################### - component = "mpas-albany-landice" - component_dir = "glc" - component_driver = "glc_cesm_driver" - core = "landice" - - srcroot = case.get_value("SRCROOT") - objroot = case.get_value("OBJROOT") - casebuild = case.get_value("CASEBUILD") - casetools = case.get_value("CASETOOLS") - objroot = case.get_value("OBJROOT") - libroot = case.get_value("LIBROOT") - gmake_j = case.get_value("GMAKE_J") - gmake = case.get_value("GMAKE") - mach = case.get_value("MACH") - use_albany = case.get_value("MALI_USE_ALBANY") - cmake_args = get_standard_cmake_args(case) - - #--------------------------------------------------------------------------- - # Build MPAS-O source - #--------------------------------------------------------------------------- - - if mach == "edison": - cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=sandybridge"' - elif mach == "titan": - cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=istanbul"' - - if "MPAS_TOOL_DIR" in os.environ: - cmake_args += " -DMPAS_TOOL_DIR={}".format(os.environ["MPAS_TOOL_DIR"]) - - cmake_args += " -DGEN_F90=True" - - # Check for Albany build - if use_albany: - logger.info("Building MALI with Albany support.") - cmake_args +=' -DALBANY=True'; - - run_bld_cmd_ensure_logging('cmake -DCORE={core} -DDRIVER={component_driver} {cmake_args} {srcroot}/components/mpas-source/src'.format(core=core, component_driver=component_driver, cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) - run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + pass ############################################################################### def _main_func(): diff --git a/components/mpas-ocean/cime_config/buildlib b/components/mpas-ocean/cime_config/buildlib index f7a4cdf9156a..72c485a0535b 100755 --- a/components/mpas-ocean/cime_config/buildlib +++ b/components/mpas-ocean/cime_config/buildlib @@ -17,45 +17,13 @@ from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy -from CIME.build import get_standard_cmake_args logger = logging.getLogger(__name__) ############################################################################### def buildlib(bldroot, installpath, case): ############################################################################### - component = "mpas-ocean" - component_dir = "ocn" - component_driver = "ocean_cesm_driver" - core = "ocean" - - srcroot = case.get_value("SRCROOT") - objroot = case.get_value("OBJROOT") - casebuild = case.get_value("CASEBUILD") - casetools = case.get_value("CASETOOLS") - objroot = case.get_value("OBJROOT") - libroot = case.get_value("LIBROOT") - gmake_j = case.get_value("GMAKE_J") - gmake = case.get_value("GMAKE") - mach = case.get_value("MACH") - cmake_args = get_standard_cmake_args(case) - - #--------------------------------------------------------------------------- - # Build MPAS-O source - #--------------------------------------------------------------------------- - - if mach == "edison": - cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=sandybridge"' - elif mach == "titan": - cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=istanbul"' - - if "MPAS_TOOL_DIR" in os.environ: - cmake_args += " -DMPAS_TOOL_DIR={}".format(os.environ["MPAS_TOOL_DIR"]) - - cmake_args += " -DGEN_F90=True" - - run_bld_cmd_ensure_logging('cmake -DCORE={core} -DDRIVER={component_driver} {cmake_args} {srcroot}/components/mpas-source/src'.format(core=core, component_driver=component_driver, cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) - run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + pass ############################################################################### def _main_func(): diff --git a/components/mpas-seaice/cime_config/buildlib b/components/mpas-seaice/cime_config/buildlib index f932d316385d..c88913893061 100755 --- a/components/mpas-seaice/cime_config/buildlib +++ b/components/mpas-seaice/cime_config/buildlib @@ -17,45 +17,13 @@ from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy -from CIME.build import get_standard_cmake_args logger = logging.getLogger(__name__) ############################################################################### def buildlib(bldroot, installpath, case): ############################################################################### - component = "mpas-seaice" - component_dir = "ice" - component_driver = "seaice_acme_driver" - core = "seaice" - - srcroot = case.get_value("SRCROOT") - objroot = case.get_value("OBJROOT") - casebuild = case.get_value("CASEBUILD") - casetools = case.get_value("CASETOOLS") - objroot = case.get_value("OBJROOT") - libroot = case.get_value("LIBROOT") - gmake_j = case.get_value("GMAKE_J") - gmake = case.get_value("GMAKE") - mach = case.get_value("MACH") - cmake_args = get_standard_cmake_args(case) - - #--------------------------------------------------------------------------- - # Build MPAS-O source - #--------------------------------------------------------------------------- - - if mach == "edison": - cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=sandybridge"' - elif mach == "titan": - cmake_args += ' -DTOOL_TARGET_ARCH="-target-cpu=istanbul"' - - if "MPAS_TOOL_DIR" in os.environ: - cmake_args += " -DMPAS_TOOL_DIR={}".format(os.environ["MPAS_TOOL_DIR"]) - - cmake_args += " -DGEN_F90=True" - - run_bld_cmd_ensure_logging('cmake -DCORE={core} -DDRIVER={component_driver} {cmake_args} {srcroot}/components/mpas-source/src'.format(core=core, component_driver=component_driver, cmake_args=cmake_args, srcroot=srcroot), logger, from_dir=bldroot) - run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + pass ############################################################################### def _main_func(): From 39944af068453b6da160cc6afaa8a9d5e26dbe36 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 28 Jun 2019 21:26:50 -0600 Subject: [PATCH 12/48] Minor fixes for mosart buildlib script --- components/mosart/cime_config/buildlib | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/mosart/cime_config/buildlib b/components/mosart/cime_config/buildlib index 5aa6f02c7905..045299d402ec 100755 --- a/components/mosart/cime_config/buildlib +++ b/components/mosart/cime_config/buildlib @@ -22,7 +22,9 @@ logger = logging.getLogger(__name__) ############################################################################### def buildlib(bldroot, installpath, case): ############################################################################### - casebuild = case.get_value("CASEBUILD") + casebuild = case.get_value("CASEBUILD") + caseroot = case.get_value("CASEROOT") + srcroot = case.get_value("SRCROOT") #------------------------------------------------------- # create Filepath in bldroot, unlike most other components, From af2c41b99eb0849f08af0ebfda87c6050ab06e55 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 1 Jul 2019 18:36:37 -0600 Subject: [PATCH 13/48] Compsets with multiple MPAS components are now working --- components/CMakeLists.txt | 14 ++-------- components/build_mpas_model.cmake | 45 ++++++++++++++++++------------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a5e2d136c88f..31a91967e02f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -23,17 +23,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/build_mpas_model.cmake) set(BUILDCONF ${CMAKE_BINARY_DIR}/../../Buildconf) # Do any MPAS builds first since they manage their own flags -file(GLOB MPASCONFS "${BUILDCONF}/mpas*conf") -foreach(ITEM IN LISTS MPASCONFS) - message("JGF INFO ${ITEM}") - get_filename_component(MPASCONF ${ITEM} NAME) - string(REPLACE "conf" "" MODEL "${MPASCONF}") - - message("Found component model ${MODEL}") - build_mpas_model(${MODEL}) - - list(APPEND MODELS ${MPAS_COMPNAME}) -endforeach() +build_mpas_models() include(${CMAKE_CURRENT_SOURCE_DIR}/common_setup.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/build_model.cmake) @@ -55,6 +45,6 @@ foreach(ITEM IN LISTS FILEPATHS) endif() endforeach() -message("Configuring exe with cpl") +message("Configuring exe with cpl and models ${MODELS}") build_model("cpl" "${BUILDCONF}/cplconf" "${MODELS}") diff --git a/components/build_mpas_model.cmake b/components/build_mpas_model.cmake index 65710f7c8d43..47af9499c19d 100644 --- a/components/build_mpas_model.cmake +++ b/components/build_mpas_model.cmake @@ -1,24 +1,31 @@ -function(build_mpas_model MODEL_ARG) +function(build_mpas_models) - if (MODEL_ARG STREQUAL "mpaso") - set(CORE "ocean") - set(DRIVER "ocean_cesm_driver") - set(MPAS_COMPNAME "ocn" PARENT_SCOPE) - elseif (MODEL_ARG STREQUAL "mpassi") - set(CORE "seaice") - set(DRIVER "seaice_acme_driver") - set(MPAS_COMPNAME "ice" PARENT_SCOPE) - elseif (MODEL_ARG STREQUAL "mpasli") - set(CORE "landice") - set(DRIVER "glc_cesm_driver") - set(MPAS_COMPNAME "glc" PARENT_SCOPE) - if (USE_ALBANY) - set(ALBANY True) + file(GLOB MPASCONFS "${BUILDCONF}/mpas*conf" "${BUILDCONF}/maliconf") + foreach(ITEM IN LISTS MPASCONFS) + get_filename_component(MPASCONF ${ITEM} NAME) + string(REPLACE "conf" "" MODEL "${MPASCONF}") + + if (MODEL STREQUAL "mpaso") + list(APPEND CORES "ocean") + list(APPEND MODELS "ocn") + elseif (MODEL STREQUAL "mpassi") + list(APPEND CORES "seaice") + list(APPEND MODELS "ice") + elseif (MODEL STREQUAL "mali") + list(APPEND CORES "landice") + list(APPEND MODELS "glc") + if (USE_ALBANY) + set(ALBANY True) + endif() + else() + message(FATAL_ERROR "Unrecognized MPAS model ${MODEL_ARG}") endif() - else() - message(FATAL "Unrecognized MPAS model ${MODEL_ARG}") - endif() + + message("Found MPAS component model '${MODEL}'") + endforeach() + + set(MODELS ${MODELS} PARENT_SCOPE) add_subdirectory("mpas-source/src") -endfunction(build_mpas_model) +endfunction(build_mpas_models) From 363b36836ebfd9611c7bc512024e3bb297419db9 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 3 Jul 2019 14:53:47 -0600 Subject: [PATCH 14/48] Add support for using old build system --- cime/scripts/Tools/case.build | 12 +- cime/scripts/Tools/get_standard_makefile_args | 2 +- .../CIME/SystemTests/system_tests_common.py | 6 +- cime/scripts/lib/CIME/build.py | 11 +- cime/scripts/lib/CIME/buildlib.py | 4 +- .../buildlib.internal_components | 4 +- .../buildlib_cmake.internal_components | 34 +++++ .../datm/cime_config/buildlib_cmake | 1 + .../desp/cime_config/buildlib_cmake | 1 + .../dice/cime_config/buildlib_cmake | 1 + .../dlnd/cime_config/buildlib_cmake | 1 + .../docn/cime_config/buildlib_cmake | 1 + .../drof/cime_config/buildlib_cmake | 1 + .../dwav/cime_config/buildlib_cmake | 1 + .../satm/cime_config/buildlib_cmake | 1 + .../sesp/cime_config/buildlib_cmake | 1 + .../sglc/cime_config/buildlib_cmake | 1 + .../siac/cime_config/buildlib_cmake | 1 + .../sice/cime_config/buildlib_cmake | 1 + .../slnd/cime_config/buildlib_cmake | 1 + .../socn/cime_config/buildlib_cmake | 1 + .../srof/cime_config/buildlib_cmake | 1 + .../swav/cime_config/buildlib_cmake | 1 + .../xatm/cime_config/buildlib_cmake | 1 + .../xglc/cime_config/buildlib_cmake | 1 + .../xice/cime_config/buildlib_cmake | 1 + .../xlnd/cime_config/buildlib_cmake | 1 + .../xocn/cime_config/buildlib_cmake | 1 + .../xrof/cime_config/buildlib_cmake | 1 + .../xwav/cime_config/buildlib_cmake | 1 + cime/src/drivers/mct/cime_config/buildexe | 50 +++---- .../cime_config/{buildlib => buildlib_cmake} | 0 components/cam/cime_config/buildlib | 73 ++++++----- components/cam/cime_config/buildlib_cmake | 32 +++++ components/cice/cime_config/buildlib | 124 +++++++++++------- components/cice/cime_config/buildlib_cmake | 49 +++++++ components/clm/cime_config/buildlib | 72 ++++++++-- components/clm/cime_config/buildlib_cmake | 37 ++++++ components/mosart/cime_config/buildlib | 100 ++++++-------- components/mosart/cime_config/buildlib_cmake | 57 ++++++++ .../mpas-albany-landice/cime_config/buildlib | 104 +++++++++++---- .../cime_config/buildlib_cmake | 38 ++++++ components/mpas-ocean/cime_config/buildlib | 94 +++++++++---- .../mpas-ocean/cime_config/buildlib_cmake | 38 ++++++ components/mpas-seaice/cime_config/buildlib | 94 +++++++++---- .../mpas-seaice/cime_config/buildlib_cmake | 38 ++++++ 46 files changed, 824 insertions(+), 272 deletions(-) create mode 100755 cime/src/build_scripts/buildlib_cmake.internal_components create mode 120000 cime/src/components/data_comps/datm/cime_config/buildlib_cmake create mode 120000 cime/src/components/data_comps/desp/cime_config/buildlib_cmake create mode 120000 cime/src/components/data_comps/dice/cime_config/buildlib_cmake create mode 120000 cime/src/components/data_comps/dlnd/cime_config/buildlib_cmake create mode 120000 cime/src/components/data_comps/docn/cime_config/buildlib_cmake create mode 120000 cime/src/components/data_comps/drof/cime_config/buildlib_cmake create mode 120000 cime/src/components/data_comps/dwav/cime_config/buildlib_cmake create mode 120000 cime/src/components/stub_comps/satm/cime_config/buildlib_cmake create mode 120000 cime/src/components/stub_comps/sesp/cime_config/buildlib_cmake create mode 120000 cime/src/components/stub_comps/sglc/cime_config/buildlib_cmake create mode 120000 cime/src/components/stub_comps/siac/cime_config/buildlib_cmake create mode 120000 cime/src/components/stub_comps/sice/cime_config/buildlib_cmake create mode 120000 cime/src/components/stub_comps/slnd/cime_config/buildlib_cmake create mode 120000 cime/src/components/stub_comps/socn/cime_config/buildlib_cmake create mode 120000 cime/src/components/stub_comps/srof/cime_config/buildlib_cmake create mode 120000 cime/src/components/stub_comps/swav/cime_config/buildlib_cmake create mode 120000 cime/src/components/xcpl_comps/xatm/cime_config/buildlib_cmake create mode 120000 cime/src/components/xcpl_comps/xglc/cime_config/buildlib_cmake create mode 120000 cime/src/components/xcpl_comps/xice/cime_config/buildlib_cmake create mode 120000 cime/src/components/xcpl_comps/xlnd/cime_config/buildlib_cmake create mode 120000 cime/src/components/xcpl_comps/xocn/cime_config/buildlib_cmake create mode 120000 cime/src/components/xcpl_comps/xrof/cime_config/buildlib_cmake create mode 120000 cime/src/components/xcpl_comps/xwav/cime_config/buildlib_cmake rename cime/src/drivers/mct/cime_config/{buildlib => buildlib_cmake} (100%) create mode 100755 components/cam/cime_config/buildlib_cmake create mode 100755 components/cice/cime_config/buildlib_cmake create mode 100755 components/clm/cime_config/buildlib_cmake create mode 100755 components/mosart/cime_config/buildlib_cmake create mode 100755 components/mpas-albany-landice/cime_config/buildlib_cmake create mode 100755 components/mpas-ocean/cime_config/buildlib_cmake create mode 100755 components/mpas-seaice/cime_config/buildlib_cmake diff --git a/cime/scripts/Tools/case.build b/cime/scripts/Tools/case.build index 162fd6123f84..f15131306a07 100755 --- a/cime/scripts/Tools/case.build +++ b/cime/scripts/Tools/case.build @@ -62,6 +62,9 @@ def parse_command_line(args, description): help="Case directory to build.\n" "Default is current directory.") + parser.add_argument("--use-old", action="store_true", + help="Use old Makefile build system (not cmake)") + mutex_group = parser.add_mutually_exclusive_group() # TODO mvertens: the following is hard-wired - otherwise it does not work with nuopc @@ -106,12 +109,12 @@ def parse_command_line(args, description): cleanlist = args.clean if args.clean is None or len(args.clean) else comps buildlist = None if args.build is None or len(args.build) == 0 else args.build - return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check + return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old ############################################################################### def _main_func(description): ############################################################################### - caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance = parse_command_line(sys.argv, description) + caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance, use_old = parse_command_line(sys.argv, description) success = True with Case(caseroot, read_only=False) as case: @@ -135,11 +138,12 @@ def _main_func(description): raise expect(buildlist is None, "Build lists don't work with tests") - success = test.build(sharedlib_only=sharedlib_only, model_only=model_only) + success = test.build(sharedlib_only=sharedlib_only, model_only=model_only, old_build=use_old) else: success = build.case_build(caseroot, case=case, sharedlib_only=sharedlib_only, model_only=model_only, buildlist=buildlist, - save_build_provenance=save_build_provenance) + save_build_provenance=save_build_provenance, + use_old=use_old) sys.exit(0 if success else 1) diff --git a/cime/scripts/Tools/get_standard_makefile_args b/cime/scripts/Tools/get_standard_makefile_args index 6f4f436bfb0d..ead2f3ece3f5 100755 --- a/cime/scripts/Tools/get_standard_makefile_args +++ b/cime/scripts/Tools/get_standard_makefile_args @@ -30,7 +30,7 @@ def parse_command_line(args, description): ############################################################################### def _main_func(description): ############################################################################### - caseroot, cmake = parse_command_line(sys.argv, description) + caseroot = parse_command_line(sys.argv, description) success = True with Case(caseroot) as case: diff --git a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py index 77c7c05ece86..80e2c567dd12 100644 --- a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py +++ b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py @@ -33,6 +33,7 @@ def __init__(self, case, expected=None): self._init_locked_files(caseroot, expected) self._skip_pnl = False self._cpllog = "med" if self._case.get_value("COMP_INTERFACE")=="nuopc" else "cpl" + self._old_build = False def _init_environment(self, caseroot): """ @@ -66,13 +67,14 @@ def _resetup_case(self, phase, reset=False): self._case.case_setup(reset=True, test_mode=True) - def build(self, sharedlib_only=False, model_only=False): + def build(self, sharedlib_only=False, model_only=False, old_build=False): """ Do NOT override this method, this method is the framework that controls the build phase. build_phase is the extension point that subclasses should use. """ success = True + self._old_build = old_build for phase_name, phase_bool in [(SHAREDLIB_BUILD_PHASE, not model_only), (MODEL_BUILD_PHASE, not sharedlib_only)]: if phase_bool: @@ -120,7 +122,7 @@ def build_indv(self, sharedlib_only=False, model_only=False): model = self._case.get_value('MODEL') build.case_build(self._caseroot, case=self._case, sharedlib_only=sharedlib_only, model_only=model_only, - save_build_provenance=not model=='cesm') + save_build_provenance=not model=='cesm', use_old=self._old_build) def clean_build(self, comps=None): if comps is None: diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index 4c506aece595..4f3f48364e17 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -402,7 +402,7 @@ def _build_model_thread(config_dir, compclass, compname, caseroot, libroot, bldr ############################################################################### def _create_build_metadata_for_component(config_dir, libroot, bldroot, case): ############################################################################### - buildlib = imp.load_source("buildlib", os.path.join(config_dir, "buildlib")) + buildlib = imp.load_source("buildlib_cmake", os.path.join(config_dir, "buildlib_cmake")) buildlib.buildlib(bldroot, libroot, case) ############################################################################### @@ -452,7 +452,7 @@ def _clean_impl(case, cleanlist, clean_all, clean_depends): ############################################################################### def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance): + save_build_provenance, use_old): ############################################################################### t1 = time.time() @@ -573,10 +573,11 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, cimeroot, libroot, lid, compiler, buildlist, comp_interface) if not sharedlib_only: - if get_model() == "e3sm": + if get_model() == "e3sm" and not use_old: logs.extend(_build_model_cmake(build_threaded, exeroot, incroot, complist, lid, caseroot, cimeroot, compiler, buildlist, comp_interface, sharedpath, case)) else: + os.environ["INSTALL_SHAREDPATH"] = os.path.join(exeroot, sharedpath) # for MPAS makefile generators logs.extend(_build_model(build_threaded, exeroot, incroot, complist, lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case)) @@ -619,10 +620,10 @@ def post_build(case, logs, build_complete=False, save_build_provenance=True): lock_file("env_build.xml", caseroot=case.get_value("CASEROOT")) ############################################################################### -def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True): +def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True, use_old=False): ############################################################################### functor = lambda: _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance) + save_build_provenance, use_old) return run_and_log_case_status(functor, "case.build", caseroot=caseroot) ############################################################################### diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index efe14f61c1ca..b8490d8967ea 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -40,7 +40,7 @@ def parse_input(argv): return args.caseroot, args.libroot, args.bldroot ############################################################################### -def build_cime_component_lib(case, compname, libroot, bldroot): +def build_cime_component_lib(case, compname, libroot, bldroot, use_old=True): ############################################################################### cimeroot = case.get_value("CIMEROOT") @@ -71,7 +71,7 @@ def build_cime_component_lib(case, compname, libroot, bldroot): out.write("") # Build the component - if get_model() != "e3sm": + if get_model() != "e3sm" or use_old: safe_copy(os.path.join(confdir, "Filepath"), bldroot) safe_copy(os.path.join(confdir, "CCSM_cppdefs"), bldroot) diff --git a/cime/src/build_scripts/buildlib.internal_components b/cime/src/build_scripts/buildlib.internal_components index f5f7d4d9c8fb..e33ea7ddb2a0 100755 --- a/cime/src/build_scripts/buildlib.internal_components +++ b/cime/src/build_scripts/buildlib.internal_components @@ -14,7 +14,7 @@ from standard_script_setup import * from CIME.buildlib import build_cime_component_lib, parse_input from CIME.case import Case -def buildlib(bldroot, libroot, case, compname=None): +def buildlib(case, libroot, bldroot, compname=None): if compname is None: thisdir = os.path.dirname(os.path.abspath(__file__)) path, dir1 = os.path.split(thisdir) @@ -28,7 +28,7 @@ def buildlib(bldroot, libroot, case, compname=None): def _main_func(args): caseroot, libroot, bldroot = parse_input(args) with Case(caseroot) as case: - buildlib(bldroot, libroot, case) + buildlib(case, libroot, bldroot) if __name__ == "__main__": _main_func(sys.argv) diff --git a/cime/src/build_scripts/buildlib_cmake.internal_components b/cime/src/build_scripts/buildlib_cmake.internal_components new file mode 100755 index 000000000000..bb842415c864 --- /dev/null +++ b/cime/src/build_scripts/buildlib_cmake.internal_components @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +""" +build cime component model library. This buildlib script is used by all cime internal +components. +""" + +import sys, os + +_CIMEROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..","..","..","..", "..") +sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools")) + +from standard_script_setup import * +from CIME.buildlib import build_cime_component_lib, parse_input +from CIME.case import Case + +def buildlib(bldroot, libroot, case, compname=None): + if compname is None: + thisdir = os.path.dirname(os.path.abspath(__file__)) + path, dir1 = os.path.split(thisdir) + _, dir2 = os.path.split(path) + if dir1 == "cime_config": + compname = dir2 + else: + compname = dir1.split('.')[1] + build_cime_component_lib(case, compname, libroot, bldroot, use_old=False) + +def _main_func(args): + caseroot, libroot, bldroot = parse_input(args) + with Case(caseroot) as case: + buildlib(bldroot, libroot, case) + +if __name__ == "__main__": + _main_func(sys.argv) diff --git a/cime/src/components/data_comps/datm/cime_config/buildlib_cmake b/cime/src/components/data_comps/datm/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/data_comps/datm/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/data_comps/desp/cime_config/buildlib_cmake b/cime/src/components/data_comps/desp/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/data_comps/desp/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/data_comps/dice/cime_config/buildlib_cmake b/cime/src/components/data_comps/dice/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/data_comps/dice/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/data_comps/dlnd/cime_config/buildlib_cmake b/cime/src/components/data_comps/dlnd/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/data_comps/dlnd/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/data_comps/docn/cime_config/buildlib_cmake b/cime/src/components/data_comps/docn/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/data_comps/docn/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/data_comps/drof/cime_config/buildlib_cmake b/cime/src/components/data_comps/drof/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/data_comps/drof/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/data_comps/dwav/cime_config/buildlib_cmake b/cime/src/components/data_comps/dwav/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/data_comps/dwav/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/stub_comps/satm/cime_config/buildlib_cmake b/cime/src/components/stub_comps/satm/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/stub_comps/satm/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/stub_comps/sesp/cime_config/buildlib_cmake b/cime/src/components/stub_comps/sesp/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/stub_comps/sesp/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/stub_comps/sglc/cime_config/buildlib_cmake b/cime/src/components/stub_comps/sglc/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/stub_comps/sglc/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/stub_comps/siac/cime_config/buildlib_cmake b/cime/src/components/stub_comps/siac/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/stub_comps/siac/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/stub_comps/sice/cime_config/buildlib_cmake b/cime/src/components/stub_comps/sice/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/stub_comps/sice/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/stub_comps/slnd/cime_config/buildlib_cmake b/cime/src/components/stub_comps/slnd/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/stub_comps/slnd/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/stub_comps/socn/cime_config/buildlib_cmake b/cime/src/components/stub_comps/socn/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/stub_comps/socn/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/stub_comps/srof/cime_config/buildlib_cmake b/cime/src/components/stub_comps/srof/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/stub_comps/srof/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/stub_comps/swav/cime_config/buildlib_cmake b/cime/src/components/stub_comps/swav/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/stub_comps/swav/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/xcpl_comps/xatm/cime_config/buildlib_cmake b/cime/src/components/xcpl_comps/xatm/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/xcpl_comps/xatm/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/xcpl_comps/xglc/cime_config/buildlib_cmake b/cime/src/components/xcpl_comps/xglc/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/xcpl_comps/xglc/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/xcpl_comps/xice/cime_config/buildlib_cmake b/cime/src/components/xcpl_comps/xice/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/xcpl_comps/xice/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/xcpl_comps/xlnd/cime_config/buildlib_cmake b/cime/src/components/xcpl_comps/xlnd/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/xcpl_comps/xlnd/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/xcpl_comps/xocn/cime_config/buildlib_cmake b/cime/src/components/xcpl_comps/xocn/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/xcpl_comps/xocn/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/xcpl_comps/xrof/cime_config/buildlib_cmake b/cime/src/components/xcpl_comps/xrof/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/xcpl_comps/xrof/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/components/xcpl_comps/xwav/cime_config/buildlib_cmake b/cime/src/components/xcpl_comps/xwav/cime_config/buildlib_cmake new file mode 120000 index 000000000000..292ce33d2526 --- /dev/null +++ b/cime/src/components/xcpl_comps/xwav/cime_config/buildlib_cmake @@ -0,0 +1 @@ +../../../../build_scripts/buildlib_cmake.internal_components \ No newline at end of file diff --git a/cime/src/drivers/mct/cime_config/buildexe b/cime/src/drivers/mct/cime_config/buildexe index 3a226d83a953..288f93f4d212 100755 --- a/cime/src/drivers/mct/cime_config/buildexe +++ b/cime/src/drivers/mct/cime_config/buildexe @@ -12,49 +12,51 @@ sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools")) from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case -from CIME.utils import expect, run_bld_cmd_ensure_logging -from CIME.build import get_standard_cmake_args +from CIME.utils import expect, run_cmd +from CIME.build import get_standard_makefile_args logger = logging.getLogger(__name__) ############################################################################### -def buildexe(case, bldroot): +def _main_func(): ############################################################################### + + caseroot, _, _ = parse_input(sys.argv) + logger.info("Building a single executable version of target coupled model") - caseroot = case.get_value("CASEROOT") - srcroot = case.get_value("SRCROOT") - cimeroot = case.get_value("CIMEROOT") - gmake = case.get_value("GMAKE") - gmake_j = case.get_value("GMAKE_J") - num_esp = case.get_value("NUM_COMP_INST_ESP") - ocn_model = case.get_value("COMP_OCN") - atm_model = case.get_value("COMP_ATM") - cmake_args = get_standard_cmake_args(case) + with Case(caseroot) as case: + casetools = case.get_value("CASETOOLS") + cimeroot = case.get_value("CIMEROOT") + gmake = case.get_value("GMAKE") + gmake_j = case.get_value("GMAKE_J") + num_esp = case.get_value("NUM_COMP_INST_ESP") + ocn_model = case.get_value("COMP_OCN") + atm_model = case.get_value("COMP_ATM") + gmake_opts = get_standard_makefile_args(case) if ocn_model == 'mom' or atm_model == "fv3gfs": - cmake_args += "-DUSE_FMS=TRUE" + gmake_opts += "USE_FMS=TRUE" + expect((num_esp is None) or (int(num_esp) == 1), "ESP component restricted to one instance") + with open('Filepath', 'w') as out: out.write(os.path.join(caseroot, "SourceMods", "src.drv") + "\n") out.write(os.path.join(cimeroot, "src", "drivers", "mct", "main") + "\n") # build model executable - exename = case.get_value("MODEL") + ".exe" - cmd = "cmake -DEXEC_SE={exename} -DMODEL=driver {cmake_args} {srcroot}/components".\ - format(exename=exename, cmake_args=cmake_args, srcroot=srcroot) - run_bld_cmd_ensure_logging(cmd, logger, from_dir=bldroot) - run_bld_cmd_ensure_logging("{} -j {}".format(gmake, gmake_j), logger, from_dir=bldroot) + makefile = os.path.join(casetools, "Makefile") + exename = os.path.join(case.get_value("EXEROOT"), case.get_value("MODEL") + ".exe") -############################################################################### -def _main_func(): -############################################################################### - caseroot, _, bldroot = parse_input(sys.argv) - with Case(caseroot, read_only=False) as case: - buildexe(case, bldroot) + cmd = "{gmake} exec_se -j {gmake_j} EXEC_SE={exename} MODEL=driver {gmake_opts} -f {makefile} ".format(gmake=gmake, gmake_j=gmake_j, exename=exename, + gmake_opts=gmake_opts, makefile=makefile) + + rc, out, _ = run_cmd(cmd, combine_output=True) + expect(rc==0,"Command %s failed rc=%d\nout=%s"%(cmd,rc,out)) + logger.info(out) ############################################################################### diff --git a/cime/src/drivers/mct/cime_config/buildlib b/cime/src/drivers/mct/cime_config/buildlib_cmake similarity index 100% rename from cime/src/drivers/mct/cime_config/buildlib rename to cime/src/drivers/mct/cime_config/buildlib_cmake diff --git a/components/cam/cime_config/buildlib b/components/cam/cime_config/buildlib index 9b6b5a0c28de..30c825f64722 100755 --- a/components/cam/cime_config/buildlib +++ b/components/cam/cime_config/buildlib @@ -1,32 +1,41 @@ -#! /usr/bin/env python - -import sys, os - -_CIMEROOT = os.environ.get("CIMEROOT") -if _CIMEROOT is None: - raise SystemExit("ERROR: must set CIMEROOT environment variable") - -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") -sys.path.append(_LIBDIR) - -from standard_script_setup import * -from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy -from CIME.case import Case -from CIME.buildlib import parse_input - -logger = logging.getLogger(__name__) - -############################################################################### -def buildlib(bldroot, installpath, case): -############################################################################### - pass - -############################################################################### -def _main(argv, documentation): -############################################################################### - caseroot, libroot, bldroot = parse_input(sys.argv) - with Case(caseroot, read_only=False) as case: - buildlib(bldroot, libroot, case) - -if (__name__ == "__main__"): - _main(sys.argv, __doc__) +#! /usr/bin/env perl +use strict; + +if ($#ARGV == -1) { + die " ERROR cam.buildexe: must specify a caseroot input argument"; +} +my ($CASEROOT) = @ARGV; +chdir "${CASEROOT}"; + +my $CASEBUILD = `./xmlquery CASEBUILD -value`; +my $CASETOOLS = `./xmlquery CASETOOLS -value`; +my $OBJROOT = `./xmlquery OBJROOT -value`; +my $LIBROOT = `./xmlquery LIBROOT -value`; +my $GMAKE_J = `./xmlquery GMAKE_J -value`; +my $GMAKE = `./xmlquery GMAKE -value`; +my $MAKE_ARGS = `./Tools/get_standard_makefile_args`; +chomp($MAKE_ARGS); + +chdir "${OBJROOT}/atm/obj"; + +if (-f "$CASEBUILD/camconf/Filepath") { + my $sysmod = "cp ${CASEBUILD}/camconf/Filepath ./tmp_filepath"; + system($sysmod) == 0 or die "ERROR cam.buildexe: $sysmod failed: $?\n"; +} else { + die "ERROR cam.buildexe - missing $CASEBUILD/camconf/Filepath"; +} + +if (-f "Filepath") { + my $sysmod = "cmp -s tmp_filepath Filepath || mv -f tmp_filepath Filepath "; + system($sysmod) == 0 or die "ERROR cam.buildexe: $sysmod failed: $?\n"; +} else { + my $sysmod = "mv -f tmp_filepath Filepath "; + system($sysmod) == 0 or die "ERROR cam.buildexe: $sysmod failed: $?\n"; +} + +my $camdefs = `cat $CASEBUILD/camconf/CCSM_cppdefs`; +chomp($camdefs); +my $sysmod = "$GMAKE complib -j ${GMAKE_J} MODEL=cam COMPLIB=${LIBROOT}/libatm.a USER_CPPDEFS=\"${camdefs}\" -f ${CASETOOLS}/Makefile ${MAKE_ARGS}"; +system($sysmod) == 0 or die "ERROR: cam.buildexe $sysmod failed: $?\n"; + +exit(0); diff --git a/components/cam/cime_config/buildlib_cmake b/components/cam/cime_config/buildlib_cmake new file mode 100755 index 000000000000..9b6b5a0c28de --- /dev/null +++ b/components/cam/cime_config/buildlib_cmake @@ -0,0 +1,32 @@ +#! /usr/bin/env python + +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy +from CIME.case import Case +from CIME.buildlib import parse_input + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + pass + +############################################################################### +def _main(argv, documentation): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +if (__name__ == "__main__"): + _main(sys.argv, __doc__) diff --git a/components/cice/cime_config/buildlib b/components/cice/cime_config/buildlib index e1a168159f96..1f05cb1acf89 100755 --- a/components/cice/cime_config/buildlib +++ b/components/cice/cime_config/buildlib @@ -1,49 +1,75 @@ -#!/usr/bin/env python - -""" -build cice library -""" -import sys, os - -_CIMEROOT = os.environ.get("CIMEROOT") -if _CIMEROOT is None: - raise SystemExit("ERROR: must set CIMEROOT environment variable") - -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") -sys.path.append(_LIBDIR) - -from standard_script_setup import * -from CIME.buildlib import parse_input -from CIME.case import Case -from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy - -logger = logging.getLogger(__name__) - -############################################################################### -def buildlib(bldroot, installpath, case): -############################################################################### - casebuild = case.get_value("CASEBUILD") - cice_blckx = case.get_value("CICE_BLCKX") - cice_blcky = case.get_value("CICE_BLCKY") - cice_mxblcks = case.get_value("CICE_MXBLCKS") - cppdefs = case.get_value("CICE_CPPDEFS") - - #------------------------------------------------------- - # compute all cppdefs, unlike other components, needs to make a CCSM_cppdefs file - #------------------------------------------------------- - - cppdefs += " -DBLCKX={} -DBLCKY={} -DMXBLCKS={}\n".format(cice_blckx, cice_blcky, cice_mxblcks) - with open(os.path.join(casebuild, "ciceconf", "CCSM_cppdefs"), "w") as fd: - fd.write(cppdefs) - -############################################################################### -def _main_func(): -############################################################################### - caseroot, libroot, bldroot = parse_input(sys.argv) - with Case(caseroot, read_only=False) as case: - buildlib(bldroot, libroot, case) - -############################################################################### - -if __name__ == "__main__": - _main_func() +#! /usr/bin/env perl +use strict; +use File::Compare; + +if ($#ARGV == -1) { + die " ERROR cice buildlib: must specify a caseroot input argument"; +} +my ($CASEROOT) = @ARGV; +chdir "${CASEROOT}"; + +my $CASEBUILD = `./xmlquery CASEBUILD -value`; +my $CASETOOLS = `./xmlquery CASETOOLS -value`; +my $OBJROOT = `./xmlquery OBJROOT -value`; +my $LIBROOT = `./xmlquery LIBROOT -value`; +my $GMAKE_J = `./xmlquery GMAKE_J -value`; +my $GMAKE = `./xmlquery GMAKE -value`; +my $MACH = `./xmlquery MACH -value`; +my $CICE_BLCKX = `./xmlquery CICE_BLCKX -value`; +my $CICE_BLCKY = `./xmlquery CICE_BLCKY -value`; +my $CICE_MXBLCKS = `./xmlquery CICE_MXBLCKS -value`; +my $MAKE_ARGS = `./Tools/get_standard_makefile_args`; +chomp($MAKE_ARGS); + +chdir "${OBJROOT}/ice/obj"; + +#------------------------------------------------------- +# Create Filepath in $CASEBUILD/ciceconf +#------------------------------------------------------- + +my $sysmod = "cp $CASEBUILD/ciceconf/Filepath ${OBJROOT}/ice/obj/tmp_filepath"; +system($sysmod) == 0 or die "ERROR cice buildlib: $sysmod failed: $?\n"; + +if (-f "Filepath") { + if (compare("tmp_filepath", "Filepath") != 0) { + my $sysmod = "mv -f tmp_filepath Filepath"; + system($sysmod) == 0 or die "ERROR cice buildlib: $sysmod failed: $?\n"; + } +} else { + my $sysmod = "mv -f tmp_filepath Filepath "; + system($sysmod) == 0 or die "ERROR cice buildlib: $sysmod failed: $?\n"; +#-------------------------------------------------------------- +# force gmake to recompile if any of the cppdefs are different +#-------------------------------------------------------------- +my $recompile = 'FALSE'; +if (-e "$OBJROOT/ice/obj/CCSM_cppdefs") { + if (compare("$OBJROOT/ice/obj/CCSM_cppdefs.new", "$OBJROOT/ice/obj/CCSM_cppdefs") != 0) { + $recompile = 'TRUE'; + } + # NOTE - the following remove statements are what force cice to recompile if + # the cppdefs are different + print "recompile is $recompile \n"; + if ($recompile eq 'TRUE') { + my $sysmod = "rm -f $OBJROOT/ice/obj/*.o"; + system($sysmod) == 0 or die "ERROR cice buildlib: $sysmod failed: $?\n"; + } +} +my $sysmod = "cp -f $OBJROOT/ice/obj/CCSM_cppdefs.new $OBJROOT/ice/obj/CCSM_cppdefs"; +system($sysmod) == 0 or die "ERROR: cice buidlib $sysmod failed: $?\n";} + +chdir $CASEROOT; +my $cppdefs = `./xmlquery CICE_CPPDEFS -value`; +chomp($cppdefs); +$cppdefs = "$cppdefs -DBLCKX=$CICE_BLCKX -DBLCKY=$CICE_BLCKY -DMXBLCKS=$CICE_MXBLCKS"; + +#------------------------------------------------------- +# Build the library +#------------------------------------------------------- + +chdir "${OBJROOT}/ice/obj"; +my $sysmod = "$GMAKE complib -j ${GMAKE_J} MODEL=cice COMPLIB=${LIBROOT}/libice.a MACFILE=${CASEROOT}/Macros.${MACH} USER_CPPDEFS=\"$cppdefs\" -f ${CASETOOLS}/Makefile ${MAKE_ARGS}"; +system($sysmod) == 0 or die "ERROR cice buildlib: $sysmod failed: $?\n"; + +exit(0); + + diff --git a/components/cice/cime_config/buildlib_cmake b/components/cice/cime_config/buildlib_cmake new file mode 100755 index 000000000000..e1a168159f96 --- /dev/null +++ b/components/cice/cime_config/buildlib_cmake @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +build cice library +""" +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + casebuild = case.get_value("CASEBUILD") + cice_blckx = case.get_value("CICE_BLCKX") + cice_blcky = case.get_value("CICE_BLCKY") + cice_mxblcks = case.get_value("CICE_MXBLCKS") + cppdefs = case.get_value("CICE_CPPDEFS") + + #------------------------------------------------------- + # compute all cppdefs, unlike other components, needs to make a CCSM_cppdefs file + #------------------------------------------------------- + + cppdefs += " -DBLCKX={} -DBLCKY={} -DMXBLCKS={}\n".format(cice_blckx, cice_blcky, cice_mxblcks) + with open(os.path.join(casebuild, "ciceconf", "CCSM_cppdefs"), "w") as fd: + fd.write(cppdefs) + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() diff --git a/components/clm/cime_config/buildlib b/components/clm/cime_config/buildlib index eaaeb054354f..da79a3603c73 100755 --- a/components/clm/cime_config/buildlib +++ b/components/clm/cime_config/buildlib @@ -3,7 +3,7 @@ """ build clm library """ -import sys, os +import sys, os, time, filecmp, shutil _CIMEROOT = os.environ.get("CIMEROOT") if _CIMEROOT is None: @@ -13,25 +13,77 @@ _LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") sys.path.append(_LIBDIR) from standard_script_setup import * -from CIME.buildlib import parse_input +from CIME.buildlib import parse_input, run_gmake from CIME.case import Case -from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy +from CIME.utils import run_cmd, expect +from CIME.build import get_standard_makefile_args logger = logging.getLogger(__name__) -############################################################################### -def buildlib(bldroot, installpath, case): -############################################################################### - pass - ############################################################################### def _main_func(): ############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) - with Case(caseroot, read_only=False) as case: - buildlib(bldroot, libroot, case) + + case = Case(caseroot) + + casebuild = case.get_value("CASEBUILD") + casetools = case.get_value("CASETOOLS") + gmake_j = case.get_value("GMAKE_J") + gmake = case.get_value("GMAKE") + mach = case.get_value("MACH") + + #------------------------------------------------------- + # create Filepath in bldroot + #------------------------------------------------------- + + filesrc = os.path.join(casebuild, "clmconf", "Filepath") + filedst = os.path.join(bldroot, "Filepath_tmp") + shutil.copy(filesrc,filedst) + + filedst = os.path.join(bldroot,"Filepath") + filedst_tmp = os.path.join(bldroot,"Filepath_tmp") + if os.path.isfile(filedst): + if not filecmp.cmp(filedst_tmp, filedst): + shutil.move(filedst_tmp, filedst) + else: + shutil.move(filedst_tmp, filedst) + + #------------------------------------------------------- + # create the library in libroot + #------------------------------------------------------- + + # Note that casebuild/clmconf/CCSM_cppdefs is created + # by the call to clm's bld/configure in clm's cime_config/buildnml + + cppdefs_file = os.path.join(casebuild, "clmconf", "CCSM_cppdefs") + user_cppdefs = "" + with open(cppdefs_file, 'r') as f: + cppdefs = f.readline() + if cppdefs: + user_cppdefs = cppdefs.rstrip() + + clm_config_opts = case.get_value("CLM_CONFIG_OPTS") + complib = os.path.join(libroot,"libclm.a") + if "clm4_0" in clm_config_opts: + complib = os.path.join(libroot,"liblnd.a") + makefile = os.path.join(casetools, "Makefile") + macfile = os.path.join(caseroot, "Macros.%s" % mach) + make_args = get_standard_makefile_args(case) + + if user_cppdefs: + cmd = "%s complib -j %d MODEL=clm COMPLIB=%s -f %s %s MACFILE=%s USER_CPPDEFS='%s'" \ + % (gmake, gmake_j, complib, makefile, make_args, macfile, user_cppdefs ) + else: + cmd = "%s complib -j %d MODEL=clm COMPLIB=%s -f %s %s MACFILE=%s " \ + % (gmake, gmake_j, complib, makefile, make_args, macfile ) + rc, out, err = run_cmd(cmd) + logger.info("%s: \n\n output:\n %s \n\n err:\n\n%s\n"%(cmd,out,err)) + expect(rc == 0, "Command %s failed with rc=%s" % (cmd, rc)) ############################################################################### if __name__ == "__main__": _main_func() + diff --git a/components/clm/cime_config/buildlib_cmake b/components/clm/cime_config/buildlib_cmake new file mode 100755 index 000000000000..eaaeb054354f --- /dev/null +++ b/components/clm/cime_config/buildlib_cmake @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +""" +build clm library +""" +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + pass + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() diff --git a/components/mosart/cime_config/buildlib b/components/mosart/cime_config/buildlib index 045299d402ec..9d499214e2c0 100755 --- a/components/mosart/cime_config/buildlib +++ b/components/mosart/cime_config/buildlib @@ -1,57 +1,43 @@ -#!/usr/bin/env python - -""" -build mosart library -""" -import sys, os - -_CIMEROOT = os.environ.get("CIMEROOT") -if _CIMEROOT is None: - raise SystemExit("ERROR: must set CIMEROOT environment variable") - -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") -sys.path.append(_LIBDIR) - -from standard_script_setup import * -from CIME.buildlib import parse_input -from CIME.case import Case -from CIME.utils import expect, run_bld_cmd_ensure_logging - -logger = logging.getLogger(__name__) - -############################################################################### -def buildlib(bldroot, installpath, case): -############################################################################### - casebuild = case.get_value("CASEBUILD") - caseroot = case.get_value("CASEROOT") - srcroot = case.get_value("SRCROOT") - - #------------------------------------------------------- - # create Filepath in bldroot, unlike most other components, - # mosart makes it's Filepath right here. - #------------------------------------------------------- - - filepaths = \ - """{caseroot}/SourceMods/src.mosart -{srcroot}/components/mosart/src/riverroute -{srcroot}/components/mosart/src/cpl -{srcroot}/components/mosart/src/cpl_share -""".format(caseroot=caseroot, srcroot=srcroot) - - with open(os.path.join(casebuild, "mosartconf", "Filepath"), "w") as fd: - fd.write(filepaths) - - with open(os.path.join(casebuild, "mosartconf", "CCSM_cppdefs"), "w") as fd: - fd.write("") - -############################################################################### -def _main_func(): -############################################################################### - caseroot, libroot, bldroot = parse_input(sys.argv) - with Case(caseroot, read_only=False) as case: - buildlib(bldroot, libroot, case) - -############################################################################### - -if __name__ == "__main__": - _main_func() +#! /usr/bin/env perl +use strict; + +if ($#ARGV == -1) { + die " ERROR mosart.buildexe: must specify a caseroot input argument"; +} +my ($CASEROOT) = @ARGV; +chdir "${CASEROOT}"; + +my $CASEBUILD = `./xmlquery CASEBUILD -value`; +my $SRCROOT = `./xmlquery SRCROOT -value`; +my $CASETOOLS = `./xmlquery CASETOOLS -value`; +my $OBJROOT = `./xmlquery OBJROOT -value`; +my $LIBROOT = `./xmlquery LIBROOT -value`; +my $GMAKE_J = `./xmlquery GMAKE_J -value`; +my $GMAKE = `./xmlquery GMAKE -value`; +my $MAKE_ARGS = `./Tools/get_standard_makefile_args`; +chomp($MAKE_ARGS); + +chdir "${OBJROOT}/rof/obj"; + +open(file,">tmp_filepath") or die "ERROT: mosart.buildexe could not open file Filepath to write"; +print file "$CASEROOT/SourceMods/src.mosart \n"; +print file "$SRCROOT/components/mosart/src/riverroute \n"; +print file "$SRCROOT/components/mosart/src/cpl \n"; +print file "$SRCROOT/components/mosart/src/cpl_share \n"; +close(file); + +if (-f "Filepath") { + my $sysmod = "cmp -s tmp_filepath Filepath || mv -f tmp_filepath Filepath "; + system($sysmod) == 0 or die "ERROR: mosart.buidexe $sysmod failed: $?\n"; +} else { + my $sysmod = "mv -f tmp_filepath Filepath "; + system($sysmod) == 0 or die "ERROR: mosart.buidexe $sysmod failed: $?\n"; +} + +my $sysmod = "$GMAKE complib -j $GMAKE_J MODEL=mosart COMPLIB=$LIBROOT/librof.a -f $CASETOOLS/Makefile ${MAKE_ARGS}"; +system($sysmod) == 0 or die "ERROR: mosart.buildexe $sysmod failed: $?\n"; + +exit(0); + + + diff --git a/components/mosart/cime_config/buildlib_cmake b/components/mosart/cime_config/buildlib_cmake new file mode 100755 index 000000000000..045299d402ec --- /dev/null +++ b/components/mosart/cime_config/buildlib_cmake @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +""" +build mosart library +""" +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + casebuild = case.get_value("CASEBUILD") + caseroot = case.get_value("CASEROOT") + srcroot = case.get_value("SRCROOT") + + #------------------------------------------------------- + # create Filepath in bldroot, unlike most other components, + # mosart makes it's Filepath right here. + #------------------------------------------------------- + + filepaths = \ + """{caseroot}/SourceMods/src.mosart +{srcroot}/components/mosart/src/riverroute +{srcroot}/components/mosart/src/cpl +{srcroot}/components/mosart/src/cpl_share +""".format(caseroot=caseroot, srcroot=srcroot) + + with open(os.path.join(casebuild, "mosartconf", "Filepath"), "w") as fd: + fd.write(filepaths) + + with open(os.path.join(casebuild, "mosartconf", "CCSM_cppdefs"), "w") as fd: + fd.write("") + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() diff --git a/components/mpas-albany-landice/cime_config/buildlib b/components/mpas-albany-landice/cime_config/buildlib index e208e21e8909..7cde5b0a1293 100755 --- a/components/mpas-albany-landice/cime_config/buildlib +++ b/components/mpas-albany-landice/cime_config/buildlib @@ -1,38 +1,86 @@ -#!/usr/bin/env python +#! /usr/bin/env perl +use strict; +use File::Compare; -""" -build mpas land ice library -""" +my $component = "mpas-albany-landice"; +my $component_dir = "glc"; +my $component_driver = "glc_cesm_driver"; +my $core = "landice"; +my $esm = "E3SM"; -import sys, os +if ($#ARGV == -1) { + die " ERROR $component buildlib: must specify a caseroot input argument"; +} -_CIMEROOT = os.environ.get("CIMEROOT") -if _CIMEROOT is None: - raise SystemExit("ERROR: must set CIMEROOT environment variable") +my ($CASEROOT) = @ARGV; +chdir "${CASEROOT}"; -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") -sys.path.append(_LIBDIR) +my $SRCROOT = `./xmlquery SRCROOT -value`; +my $OBJROOT = `./xmlquery OBJROOT -value`; +my $CASEBUILD = `./xmlquery CASEBUILD -value`; +my $CASETOOLS = `./xmlquery CASETOOLS -value`; +my $OBJROOT = `./xmlquery OBJROOT -value`; +my $LIBROOT = `./xmlquery LIBROOT -value`; +my $GMAKE_J = `./xmlquery GMAKE_J -value`; +my $GMAKE = `./xmlquery GMAKE -value`; +my $MACH = `./xmlquery MACH -value`; +my $MALI_USE_ALBANY = `./xmlquery MALI_USE_ALBANY -value`; +my $MAKE_ARGS = `./Tools/get_standard_makefile_args`; +chomp($MAKE_ARGS); -from standard_script_setup import * -from CIME.buildlib import parse_input -from CIME.case import Case -from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy +#--------------------------------------------------------------------------- +# Copy MALI source +#--------------------------------------------------------------------------- -logger = logging.getLogger(__name__) +mkdir "$OBJROOT/$component_dir"; +mkdir "$OBJROOT/$component_dir/source"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/Makefile* $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/core_landice $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/external $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/operators $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/framework $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/tools $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -############################################################################### -def buildlib(bldroot, installpath, case): -############################################################################### - pass +my $drvcpy = "cp -fpR $SRCROOT/components/$component/driver ${OBJROOT}/$component_dir/source/$component_driver"; +system($drvcpy) == 0 or die "ERROR: $component buildlib $drvcpy failed: $?\n"; -############################################################################### -def _main_func(): -############################################################################### - caseroot, libroot, bldroot = parse_input(sys.argv) - with Case(caseroot, read_only=False) as case: - buildlib(bldroot, libroot, case) +my $root_path = "$OBJROOT/$component_dir/source"; -############################################################################### +my $bldcmd = "cd $root_path; ${GMAKE} all ${MAKE_ARGS} CORE=$core ESM=$esm DRIVER=$component_driver GEN_F90=true"; +$bldcmd .= ' ROOT_DIR="'; +$bldcmd .= "$root_path"; +$bldcmd .= '"'; -if __name__ == "__main__": - _main_func() +if ( $MACH eq "edison" ) { + $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=sandybridge"'; +} elsif ( $MACH eq "titan" ) { + $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=istanbul"'; +} +if (defined $ENV{MPAS_TOOL_DIR}) { + $bldcmd .= " MPAS_TOOL_DIR=$ENV{MPAS_TOOL_DIR}"; +} + +# Check for Albany build +if ( $MALI_USE_ALBANY eq "TRUE" ) { + print "Building MALI with Albany support.\n"; + $bldcmd .= ' ALBANY=true'; + # Note MPAS_EXTERNAL_LIBS is not needed since E3SM is doing the linking! +} + +print "Compiling MALI with this command: $bldcmd \n"; + +system($bldcmd) == 0 or die "ERROR: $component buildlib $bldcmd failed: $?\n"; + +my $cpyobjs = "find $root_path -name *.mod -exec cp -p {} $OBJROOT/$component_dir/obj/. \\\;"; + +system($cpyobjs) == 0 or die "ERROR: $component buildlib $cpyobjs failed: $?\n"; + +my $cpylib = "cp -p $root_path/lib$component_dir.a ${LIBROOT}/lib$component_dir.a"; + +system($cpylib) == 0 or die "ERROR: $component buildlib $cpylib failed: $?\n"; diff --git a/components/mpas-albany-landice/cime_config/buildlib_cmake b/components/mpas-albany-landice/cime_config/buildlib_cmake new file mode 100755 index 000000000000..e208e21e8909 --- /dev/null +++ b/components/mpas-albany-landice/cime_config/buildlib_cmake @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +build mpas land ice library +""" + +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + pass + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() diff --git a/components/mpas-ocean/cime_config/buildlib b/components/mpas-ocean/cime_config/buildlib index 72c485a0535b..54347705ce8b 100755 --- a/components/mpas-ocean/cime_config/buildlib +++ b/components/mpas-ocean/cime_config/buildlib @@ -1,38 +1,76 @@ -#!/usr/bin/env python +#! /usr/bin/env perl +use strict; +use File::Compare; -""" -build mpas-o library -""" +my $component = "mpas-ocean"; +my $component_dir = "ocn"; +my $component_driver = "ocean_cesm_driver"; +my $core = "ocean"; +my $esm = "E3SM"; -import sys, os +if ($#ARGV == -1) { + die " ERROR $component buildlib: must specify a caseroot input argument"; +} -_CIMEROOT = os.environ.get("CIMEROOT") -if _CIMEROOT is None: - raise SystemExit("ERROR: must set CIMEROOT environment variable") +my ($CASEROOT) = @ARGV; +chdir "${CASEROOT}"; -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") -sys.path.append(_LIBDIR) +my $SRCROOT = `./xmlquery SRCROOT -value`; +my $OBJROOT = `./xmlquery OBJROOT -value`; +my $CASEBUILD = `./xmlquery CASEBUILD -value`; +my $CASETOOLS = `./xmlquery CASETOOLS -value`; +my $OBJROOT = `./xmlquery OBJROOT -value`; +my $LIBROOT = `./xmlquery LIBROOT -value`; +my $GMAKE_J = `./xmlquery GMAKE_J -value`; +my $GMAKE = `./xmlquery GMAKE -value`; +my $MACH = `./xmlquery MACH -value`; +my $MAKE_ARGS = `./Tools/get_standard_makefile_args`; +chomp($MAKE_ARGS); -from standard_script_setup import * -from CIME.buildlib import parse_input -from CIME.case import Case -from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy +#--------------------------------------------------------------------------- +# Copy MPAS-O source +#--------------------------------------------------------------------------- -logger = logging.getLogger(__name__) +mkdir "$OBJROOT/$component_dir"; +mkdir "$OBJROOT/$component_dir/source"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/Makefile* $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/core_ocean $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/external $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/operators $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/framework $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/tools $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -############################################################################### -def buildlib(bldroot, installpath, case): -############################################################################### - pass +my $drvcpy = "cp -fpR $SRCROOT/components/$component/driver ${OBJROOT}/$component_dir/source/$component_driver"; +system($drvcpy) == 0 or die "ERROR: $component buildlib $drvcpy failed: $?\n"; -############################################################################### -def _main_func(): -############################################################################### - caseroot, libroot, bldroot = parse_input(sys.argv) - with Case(caseroot, read_only=False) as case: - buildlib(bldroot, libroot, case) +my $root_path = "$OBJROOT/$component_dir/source"; -############################################################################### +my $bldcmd = "cd $root_path; ${GMAKE} all ${MAKE_ARGS} CORE=$core ESM=$esm DRIVER=$component_driver GEN_F90=true"; +$bldcmd .= ' ROOT_DIR="'; +$bldcmd .= "$root_path"; +$bldcmd .= '"'; -if __name__ == "__main__": - _main_func() +if ( $MACH eq "edison" ) { + $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=sandybridge"'; +} elsif ( $MACH eq "titan" ) { + $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=istanbul"'; +} +if (defined $ENV{MPAS_TOOL_DIR}) { + $bldcmd .= " MPAS_TOOL_DIR=$ENV{MPAS_TOOL_DIR}"; +} + +system($bldcmd) == 0 or die "ERROR: $component buildlib $bldcmd failed: $?\n"; + +my $cpyobjs = "find $root_path -name *.mod -exec cp -p {} $OBJROOT/$component_dir/obj/. \\\;"; + +system($cpyobjs) == 0 or die "ERROR: $component buildlib $cpyobjs failed: $?\n"; + +my $cpylib = "cp -p $root_path/lib$component_dir.a ${LIBROOT}/lib$component_dir.a"; + +system($cpylib) == 0 or die "ERROR: $component buildlib $cpylib failed: $?\n"; diff --git a/components/mpas-ocean/cime_config/buildlib_cmake b/components/mpas-ocean/cime_config/buildlib_cmake new file mode 100755 index 000000000000..72c485a0535b --- /dev/null +++ b/components/mpas-ocean/cime_config/buildlib_cmake @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +build mpas-o library +""" + +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + pass + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() diff --git a/components/mpas-seaice/cime_config/buildlib b/components/mpas-seaice/cime_config/buildlib index c88913893061..de5f42863f31 100755 --- a/components/mpas-seaice/cime_config/buildlib +++ b/components/mpas-seaice/cime_config/buildlib @@ -1,38 +1,76 @@ -#!/usr/bin/env python +#! /usr/bin/env perl +use strict; +use File::Compare; -""" -build mpas-si library -""" +my $component = "mpas-seaice"; +my $component_dir = "ice"; +my $component_driver = "seaice_acme_driver"; +my $core = "seaice"; +my $esm = "E3SM"; -import sys, os +if ($#ARGV == -1) { + die " ERROR $component buildlib: must specify a caseroot input argument"; +} -_CIMEROOT = os.environ.get("CIMEROOT") -if _CIMEROOT is None: - raise SystemExit("ERROR: must set CIMEROOT environment variable") +my ($CASEROOT) = @ARGV; +chdir "${CASEROOT}"; -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") -sys.path.append(_LIBDIR) +my $SRCROOT = `./xmlquery SRCROOT -value`; +my $OBJROOT = `./xmlquery OBJROOT -value`; +my $CASEBUILD = `./xmlquery CASEBUILD -value`; +my $CASETOOLS = `./xmlquery CASETOOLS -value`; +my $OBJROOT = `./xmlquery OBJROOT -value`; +my $LIBROOT = `./xmlquery LIBROOT -value`; +my $GMAKE_J = `./xmlquery GMAKE_J -value`; +my $GMAKE = `./xmlquery GMAKE -value`; +my $MACH = `./xmlquery MACH -value`; +my $MAKE_ARGS = `./Tools/get_standard_makefile_args`; +chomp($MAKE_ARGS); -from standard_script_setup import * -from CIME.buildlib import parse_input -from CIME.case import Case -from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy +#--------------------------------------------------------------------------- +# Copy MPASSI source +#--------------------------------------------------------------------------- -logger = logging.getLogger(__name__) +mkdir "$OBJROOT/$component_dir"; +mkdir "$OBJROOT/$component_dir/source"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/Makefile* $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/core_seaice $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/external $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/operators $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/framework $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; +my $srccpy = "cp -fpR $SRCROOT/components/mpas-source/src/tools $OBJROOT/$component_dir/source/."; +system($srccpy) == 0 or die "ERROR: $component buildlib $srccpy failed: $?\n"; -############################################################################### -def buildlib(bldroot, installpath, case): -############################################################################### - pass +my $drvcpy = "cp -fpR $SRCROOT/components/$component/driver ${OBJROOT}/$component_dir/source/$component_driver"; +system($drvcpy) == 0 or die "ERROR: $component buildlib $drvcpy failed: $?\n"; -############################################################################### -def _main_func(): -############################################################################### - caseroot, libroot, bldroot = parse_input(sys.argv) - with Case(caseroot, read_only=False) as case: - buildlib(bldroot, libroot, case) +my $root_path = "$OBJROOT/$component_dir/source"; -############################################################################### +my $bldcmd = "cd $root_path; ${GMAKE} all ${MAKE_ARGS} CORE=$core ESM=$esm DRIVER=$component_driver GEN_F90=true"; +$bldcmd .= ' ROOT_DIR="'; +$bldcmd .= "$root_path"; +$bldcmd .= '"'; -if __name__ == "__main__": - _main_func() +if ( $MACH eq "edison" ) { + $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=sandybridge"'; +} elsif ( $MACH eq "titan" ) { + $bldcmd .= ' TOOL_TARGET_ARCH="-target-cpu=istanbul"'; +} +if (defined $ENV{MPAS_TOOL_DIR}) { + $bldcmd .= " MPAS_TOOL_DIR=$ENV{MPAS_TOOL_DIR}"; +} + +system($bldcmd) == 0 or die "ERROR: $component buildlib $bldcmd failed: $?\n"; + +my $cpyobjs = "find $root_path -name *.mod -exec cp -p {} $OBJROOT/$component_dir/obj/. \\\;"; + +system($cpyobjs) == 0 or die "ERROR: $component buildlib $cpyobjs failed: $?\n"; + +my $cpylib = "cp -p $root_path/lib$component_dir.a ${LIBROOT}/lib$component_dir.a"; + +system($cpylib) == 0 or die "ERROR: $component buildlib $cpylib failed: $?\n"; diff --git a/components/mpas-seaice/cime_config/buildlib_cmake b/components/mpas-seaice/cime_config/buildlib_cmake new file mode 100755 index 000000000000..c88913893061 --- /dev/null +++ b/components/mpas-seaice/cime_config/buildlib_cmake @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +build mpas-si library +""" + +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import expect, run_bld_cmd_ensure_logging, safe_copy + +logger = logging.getLogger(__name__) + +############################################################################### +def buildlib(bldroot, installpath, case): +############################################################################### + pass + +############################################################################### +def _main_func(): +############################################################################### + caseroot, libroot, bldroot = parse_input(sys.argv) + with Case(caseroot, read_only=False) as case: + buildlib(bldroot, libroot, case) + +############################################################################### + +if __name__ == "__main__": + _main_func() From 6fcca3873c3c8d988423231f082dc4d574e2d4ba Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 3 Jul 2019 15:31:51 -0600 Subject: [PATCH 15/48] Add back Makefile --- components/mpas-ocean/driver/Makefile | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 components/mpas-ocean/driver/Makefile diff --git a/components/mpas-ocean/driver/Makefile b/components/mpas-ocean/driver/Makefile new file mode 100644 index 000000000000..afac96f436a0 --- /dev/null +++ b/components/mpas-ocean/driver/Makefile @@ -0,0 +1,27 @@ +.SUFFIXES: .F .o + +OBJS = ocn_comp_mct.o \ + mpaso_cpl_indices.o \ + mpaso_mct_vars.o + +OCEAN_SHARED_INCLUDES=-I../core_ocean/mode_forward -I../core_ocean/shared -I../core_ocean/analysis_members -I../core_ocean/cvmix -I../framework -I../operators + +all: $(OBJS) + +ocn_comp_mct.o: mpaso_cpl_indices.o mpaso_mct_vars.o + +mpaso_cpl_indices.o: + +mpaso_mct_vars.o: + +clean: + $(RM) *.o *.mod *.f90 + +.F.o: + $(RM) $@ $*.mod +ifeq "$(GEN_F90)" "true" + $(CPP) $(CPPFLAGS) $(CPPINCLUDES) $< > $*.f90 + $(FC) $(FFLAGS) -c $*.f90 $(FCINCLUDES) -I../framework -I../operators -I../external/esmf_time_f90 +else + $(FC) $(CPPFLAGS) $(FFLAGS) -c $*.F $(CPPINCLUDES) $(FCINCLUDES) -I../framework -I../operators -I../external/esmf_time_f90 +endif From 95efeeb185a6847db47211265f6f559209856e25 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 3 Jul 2019 16:54:38 -0600 Subject: [PATCH 16/48] Minor fix for old-style building of cime components --- cime/scripts/lib/CIME/buildlib.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index b8490d8967ea..1c1acdc799ca 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -78,14 +78,18 @@ def build_cime_component_lib(case, compname, libroot, bldroot, use_old=True): run_gmake(case, compclass, libroot, bldroot) ############################################################################### -def run_gmake(case, compclass, _, bldroot, libname="", user_cppdefs=""): +def run_gmake(case, compclass, libroot, bldroot, libname="", user_cppdefs=""): ############################################################################### gmake_args = get_standard_makefile_args(case) gmake_j = case.get_value("GMAKE_J") gmake = case.get_value("GMAKE") - complib = libname if libname else compclass + complib = "" + if libname: + complib = os.path.join(libroot, "lib{}.a".format(libname)) + else: + complib = os.path.join(libroot, "lib{}.a".format(compclass)) makefile = os.path.join(case.get_value("CASETOOLS"), "Makefile") From 1a02661914b79372ef00f131dfde2c4792f63767 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 3 Jul 2019 17:24:58 -0600 Subject: [PATCH 17/48] Now that we've exposed so much more parallelism in our builds, we don't need to lowball the proc-cost of a case build in test scheduler. --- cime/scripts/lib/CIME/test_scheduler.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cime/scripts/lib/CIME/test_scheduler.py b/cime/scripts/lib/CIME/test_scheduler.py index 5d9a66c950a5..b8f1f51c4437 100644 --- a/cime/scripts/lib/CIME/test_scheduler.py +++ b/cime/scripts/lib/CIME/test_scheduler.py @@ -145,7 +145,10 @@ def __init__(self, test_names, test_data=None, self._machobj = Machines(machine=machine_name) - self._model_build_cost = 4 + if get_model() == "e3sm": + self._model_build_cost = (self._machobj.get_value("GMAKE_J") * 2) / 3 + 1 + else: + self._model_build_cost = 4 # If user is forcing procs or threads, re-write test names to reflect this. if force_procs or force_threads: From ce410c862a592ceb133f565252403b7314f5f209 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 5 Jul 2019 14:29:10 -0600 Subject: [PATCH 18/48] Fix linker language --- components/build_model.cmake | 1 + components/common_setup.cmake | 12 ++---------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/components/build_model.cmake b/components/build_model.cmake index 47f5b5df86a3..435d33544851 100644 --- a/components/build_model.cmake +++ b/components/build_model.cmake @@ -191,6 +191,7 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) foreach(ITEM IN LISTS ALL_LIBS_LIST) target_link_libraries(${MODEL_ARG} ${ITEM}) endforeach() + set_target_properties(${MODEL_ARG} PROPERTIES LINKER_LANGUAGE ${LD}) else() add_library(${MODEL_ARG}) target_sources(${MODEL_ARG} PRIVATE ${SOURCES}) diff --git a/components/common_setup.cmake b/components/common_setup.cmake index 87531096f4b1..8da9fa22b149 100644 --- a/components/common_setup.cmake +++ b/components/common_setup.cmake @@ -86,17 +86,9 @@ endif() # Decide whether to use a C++ or Fortran linker, based on whether we # are using any C++ code and the compiler-dependent CXX_LINKER variable if (USE_CXX AND CXX_LINKER STREQUAL "CXX") - if (MPILIB STREQUAL mpi-serial) - set(LD ${SCXX}) - else() - set(LD ${MPICXX}) - endif() + set(LD "CXX") else() - if (MPILIB STREQUAL mpi-serial) - set(LD ${SFC}) - else() - set(LD ${MPIFC}) - endif() + set(LD "Fortran") endif() if (USE_CXX AND NOT SUPPORTS_CXX) From 47f5bb1ef554e060920748376f4347d68d8f22d1 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 5 Jul 2019 14:52:18 -0600 Subject: [PATCH 19/48] Fix cice cppdef filename --- components/cice/cime_config/buildnml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/cice/cime_config/buildnml b/components/cice/cime_config/buildnml index 7293a6e17f48..d091916d08f0 100755 --- a/components/cice/cime_config/buildnml +++ b/components/cice/cime_config/buildnml @@ -99,7 +99,7 @@ def buildnml(case, caseroot, compname): # this will force gmake to rebuild when $CASE.buildexe is called if testcase != "SBN": - with open(os.path.join(objroot, "ice/obj/CICE_cppdefs.new"), "w") as fd: + with open(os.path.join(objroot, "ice/obj/CCSM_cppdefs.new"), "w") as fd: fd.write(cppdefs + "\n") #-------------------------------------------------------------------- From dbcdb6ff77ab3a429cbe89d4142e6af953a37e5d Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 5 Jul 2019 15:30:02 -0600 Subject: [PATCH 20/48] Fix threads, buildconf for 2-case tests --- cime/scripts/lib/CIME/build.py | 1 + components/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index 4f3f48364e17..f84b3c67a01a 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -29,6 +29,7 @@ def get_standard_makefile_args(case, shared_lib=False): def get_standard_cmake_args(case, sharedpath, shared_lib=False): cmake_args = "-DCIME_MODEL={} ".format(case.get_value("MODEL")) + cmake_args += " -Dcompile_threaded={} ".format(stringify_bool(case.get_build_threaded())) ocn_model = case.get_value("COMP_OCN") atm_model = case.get_value("COMP_ATM") diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 31a91967e02f..3529d8ca9952 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -20,7 +20,7 @@ project(E3SM C CXX Fortran) include(${CMAKE_CURRENT_SOURCE_DIR}/build_mpas_model.cmake) -set(BUILDCONF ${CMAKE_BINARY_DIR}/../../Buildconf) +set(BUILDCONF ${CASEROOT}/Buildconf) # Do any MPAS builds first since they manage their own flags build_mpas_models() From b352f91d4aa78211b745788cc850fc7aa4663b7e Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 5 Jul 2019 17:46:17 -0600 Subject: [PATCH 21/48] Do not add mpas subdir if not using any MPAS components --- components/build_mpas_model.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/build_mpas_model.cmake b/components/build_mpas_model.cmake index 47af9499c19d..2cc500b5c1ab 100644 --- a/components/build_mpas_model.cmake +++ b/components/build_mpas_model.cmake @@ -26,6 +26,8 @@ function(build_mpas_models) set(MODELS ${MODELS} PARENT_SCOPE) - add_subdirectory("mpas-source/src") + if (CORES) + add_subdirectory("mpas-source/src") + endif() endfunction(build_mpas_models) From f448171176efc5e02b1a226baded658ae5b20bcd Mon Sep 17 00:00:00 2001 From: James Foucar Date: Sat, 6 Jul 2019 17:37:01 -0600 Subject: [PATCH 22/48] Fix X cases --- cime/scripts/lib/CIME/buildlib.py | 5 ++- components/CMakeLists.txt | 1 + components/build_model.cmake | 65 ++++++++++++++++--------------- components/cmake_util.cmake | 38 ++++++++++++++++++ 4 files changed, 75 insertions(+), 34 deletions(-) create mode 100644 components/cmake_util.cmake diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index 1c1acdc799ca..6cfda675767a 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -61,8 +61,9 @@ def build_cime_component_lib(case, compname, libroot, bldroot, use_old=True): out.write(os.path.join(cimeroot, "src", "components", "data_comps", compname, comp_interface) + "\n") out.write(os.path.join(cimeroot, "src", "components", "data_comps", compname) + "\n") elif compname.startswith('x'): - out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", "xshare") + "\n") - out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", "xshare", comp_interface) + "\n") + if use_old: + out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", "xshare") + "\n") + out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", "xshare", comp_interface) + "\n") out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", compname, comp_interface) + "\n") elif compname.startswith('s'): out.write(os.path.join(cimeroot, "src", "components", "stub_comps", compname, comp_interface) + "\n") diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3529d8ca9952..c3eac5762e17 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -18,6 +18,7 @@ cmake_policy(SET CMP0057 NEW) project(E3SM C CXX Fortran) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake_util.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/build_mpas_model.cmake) set(BUILDCONF ${CASEROOT}/Buildconf) diff --git a/components/build_model.cmake b/components/build_model.cmake index 435d33544851..dceac70c61bb 100644 --- a/components/build_model.cmake +++ b/components/build_model.cmake @@ -13,7 +13,7 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) endif() if (MODEL_ARG STREQUAL "cpl") - list(APPEND INCLDIR "${EXEROOT}/atm/obj" "${EXEROOT}/ice/obj" "${EXEROOT}/ocn/obj" "${EXEROOT}/glc/obj" "${EXEROOT}/rof/obj" "${EXEROOT}/wav/obj" "${EXEROOT}/esp/obj" "${EXEROOT}/iac/obj" "${EXEROOT}/bld/mpas-source/src") + list(APPEND INCLDIR "${EXEROOT}/bld/mpas-source/src") endif() if (MODEL_ARG STREQUAL "cam") @@ -40,34 +40,9 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) # One additional subtley is that, when mkSrcfiles found multiple files with the same basename, # only the one found first gets compiled. - set(SRCROOT_REL "${CIMEROOT}/..") - set(BASENAME_SET) - file(TO_CMAKE_PATH ${SRCROOT_REL} SRCROOT_ABS) - foreach(DIRSEARCH ${FILEPATH_DIRS}) - file(GLOB MATCHES RELATIVE "${SRCROOT_ABS}/components" "${DIRSEARCH}/*.[Ffc]" "${DIRSEARCH}/*.[Ff]90" "${DIRSEARCH}/*.cpp" "${DIRSEARCH}/*.F90.in") - if (MATCHES) - foreach (MATCH IN LISTS MATCHES) - get_filename_component(BASENAME ${MATCH} NAME) - list(FIND BASENAME_SET ${BASENAME} BASENAME_WAS_FOUND) - if (BASENAME_WAS_FOUND EQUAL -1) - list(APPEND SOURCES ${MATCH}) - list(APPEND BASENAME_SET ${BASENAME}) - else() - message(WARNING "Skipping repeated base filename ${BASENAME} for ${MATCH}") - endif() - endforeach() - endif() - endforeach() - - foreach(SOURCE_FILE IN LISTS SOURCES) - get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) - if (SOURCE_EXT STREQUAL ".F90.in") - string(REPLACE ".in" "" SOURCE_NO_IN ${SOURCE_FILE}) - list(APPEND GEN_F90_SOURCES ${SOURCE_NO_IN}) - list(APPEND SOURCES ${SOURCE_NO_IN}) - list(REMOVE_ITEM SOURCES ${SOURCE_FILE}) - endif() - endforeach() + gather_sources("${FILEPATH_DIRS}" "${CIMEROOT}") + set(SOURCES ${SOURCES_RESULT}) + set(GEN_F90_SOURCES ${GEN_F90_SOURCES_RESULT}) foreach(ITEM IN LISTS CPP_DIRS) if (EXISTS ${ITEM}) @@ -75,6 +50,21 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) endif() endforeach() + #------------------------------------------------------------------------------- + # x components need special handling due to xshare + #------------------------------------------------------------------------------- + if (MODEL_ARG MATCHES "x.*") + set(XCOMP True) + endif() + + if (XCOMP AND NOT TARGET xshare) + gather_sources("${CIMEROOT}/src/components/xcpl_comps/xshare;${CIMEROOT}/src/components/xcpl_comps/xshare/${COMP_INTERFACE}" "${CIMEROOT}") + set(XSHARE_SOURCES ${SOURCES_RESULT}) + if (GEN_F90_SOURCES_RESULT) + message(FATAL_ERROR "genf90 files not allows in xshare") + endif() + endif() + #------------------------------------------------------------------------------- # create list of component libraries - hard-wired for current ccsm components #------------------------------------------------------------------------------- @@ -140,7 +130,7 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) endforeach () # Flags are slightly different for different fortran extensions - foreach (SOURCE_FILE IN LISTS SOURCES) + foreach (SOURCE_FILE IN LISTS SOURCES XSHARE_SOURCES) # Cosp manages its own flags if (NOT SOURCE_FILE IN_LIST COSP_SOURCES) get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) @@ -179,6 +169,14 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) set(MLIBS "${MLIBS} ${MPISERIAL}") endif() + separate_arguments(CPPDEFS_LIST UNIX_COMMAND "${CPPDEFS}") + + if (XCOMP AND NOT TARGET xshare) + add_library(xshare OBJECT ${XSHARE_SOURCES}) + target_compile_definitions(xshare PRIVATE ${CPPDEFS_LIST}) + target_include_directories(xshare PRIVATE ${INCLDIR}) + endif() + if (MODEL_ARG STREQUAL "cpl") set(MODEL_ARG "${CIME_MODEL}.exe") add_executable(${MODEL_ARG}) @@ -194,13 +192,16 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) set_target_properties(${MODEL_ARG} PROPERTIES LINKER_LANGUAGE ${LD}) else() add_library(${MODEL_ARG}) - target_sources(${MODEL_ARG} PRIVATE ${SOURCES}) + if (XCOMP) + target_sources(${MODEL_ARG} PRIVATE ${SOURCES} $) + else() + target_sources(${MODEL_ARG} PRIVATE ${SOURCES}) + endif() endif() # Subtle: In order for fortran dependency scanning to work, our CPPFPP/DEFS must be registered # as COMPILE_DEFINITIONS, not simple added via CMAKE_Fortran_Flags. Also, CPPDEFS *must* # be provided as a list, not a whitespace-separated string; otherwise, things get wonky. - separate_arguments(CPPDEFS_LIST UNIX_COMMAND "${CPPDEFS}") target_compile_definitions(${MODEL_ARG} PRIVATE ${CPPDEFS_LIST}) add_dependencies(${MODEL_ARG} genf90) diff --git a/components/cmake_util.cmake b/components/cmake_util.cmake new file mode 100644 index 000000000000..a817c440693c --- /dev/null +++ b/components/cmake_util.cmake @@ -0,0 +1,38 @@ +function(gather_sources FILEPATH_DIRS_ARG CIMEROOT_ARG) + set(SRCROOT_REL "${CIMEROOT_ARG}/..") + set(BASENAME_SET) + set(SOURCES_RESULT) + set(GEN_F90_SOURCES_RESULT) + + file(TO_CMAKE_PATH ${SRCROOT_REL} SRCROOT_ABS) + foreach(DIRSEARCH ${FILEPATH_DIRS_ARG}) + file(GLOB MATCHES RELATIVE "${SRCROOT_ABS}/components" "${DIRSEARCH}/*.[Ffc]" "${DIRSEARCH}/*.[Ff]90" "${DIRSEARCH}/*.cpp" "${DIRSEARCH}/*.F90.in") + if (MATCHES) + foreach (MATCH IN LISTS MATCHES) + get_filename_component(BASENAME ${MATCH} NAME) + list(FIND BASENAME_SET ${BASENAME} BASENAME_WAS_FOUND) + if (BASENAME_WAS_FOUND EQUAL -1) + list(APPEND SOURCES_RESULT ${MATCH}) + list(APPEND BASENAME_SET ${BASENAME}) + else() + message(WARNING "Skipping repeated base filename ${BASENAME} for ${MATCH}") + endif() + endforeach() + endif() + endforeach() + + foreach(SOURCE_FILE IN LISTS SOURCES_RESULT) + get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) + if (SOURCE_EXT STREQUAL ".F90.in") + string(REPLACE ".in" "" SOURCE_NO_IN ${SOURCE_FILE}) + list(APPEND GEN_F90_SOURCES_RESULT ${SOURCE_NO_IN}) + list(APPEND SOURCES_RESULT ${SOURCE_NO_IN}) + list(REMOVE_ITEM SOURCES_RESULT ${SOURCE_FILE}) + endif() + endforeach() + + # Return data to parent + set(SOURCES_RESULT ${SOURCES_RESULT} PARENT_SCOPE) + set(GEN_F90_SOURCES_RESULT ${GEN_F90_SOURCES_RESULT} PARENT_SCOPE) + +endfunction() \ No newline at end of file From 35357509e011de400f31ba776ab6a4d978a5f220 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Sat, 6 Jul 2019 18:24:30 -0600 Subject: [PATCH 23/48] Fix bug in cosp handling for cam --- components/build_model.cmake | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/components/build_model.cmake b/components/build_model.cmake index dceac70c61bb..adb7c30ecc9f 100644 --- a/components/build_model.cmake +++ b/components/build_model.cmake @@ -16,18 +16,6 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) list(APPEND INCLDIR "${EXEROOT}/bld/mpas-source/src") endif() - if (MODEL_ARG STREQUAL "cam") - # These RRTMG files take an extraordinarily long time to compile with optimization. - # Until mods are made to read the data from files, just remove optimization from - # their compilation. - set(NOOPT_FILES "cam/src/physics/rrtmg/ext/rrtmg_lw/rrtmg_lw_k_g.f90;cam/src/physics/rrtmg/ext/rrtmg_sw/rrtmg_sw_k_g.f90") - - if (COSP_LIBDIR) - include(${CMAKE_CURRENT_SOURCE_DIR}/cam/src/physics/cosp/Cosp.cmake) - endif() - - endif() - #------------------------------------------------------------------------------- # Build & include dependency files #------------------------------------------------------------------------------- @@ -50,6 +38,22 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) endif() endforeach() + #------------------------------------------------------------------------------- + # Cam needs some special handling for cosp and turning off opts for some files + #------------------------------------------------------------------------------- + + if (MODEL_ARG STREQUAL "cam") + # These RRTMG files take an extraordinarily long time to compile with optimization. + # Until mods are made to read the data from files, just remove optimization from + # their compilation. + set(NOOPT_FILES "cam/src/physics/rrtmg/ext/rrtmg_lw/rrtmg_lw_k_g.f90;cam/src/physics/rrtmg/ext/rrtmg_sw/rrtmg_sw_k_g.f90") + + if (COSP_LIBDIR) + include(${CMAKE_CURRENT_SOURCE_DIR}/cam/src/physics/cosp/Cosp.cmake) + endif() + + endif() + #------------------------------------------------------------------------------- # x components need special handling due to xshare #------------------------------------------------------------------------------- From 387e84affd1d975de4ec6a86cf3a9a47ab7ab44c Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 8 Jul 2019 11:05:22 -0600 Subject: [PATCH 24/48] Add support for ninja backend --- cime/scripts/Tools/case.build | 12 ++++++++---- .../lib/CIME/SystemTests/system_tests_common.py | 6 ++++-- cime/scripts/lib/CIME/build.py | 15 +++++++++------ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/cime/scripts/Tools/case.build b/cime/scripts/Tools/case.build index f15131306a07..f79122ee0c92 100755 --- a/cime/scripts/Tools/case.build +++ b/cime/scripts/Tools/case.build @@ -65,6 +65,9 @@ def parse_command_line(args, description): parser.add_argument("--use-old", action="store_true", help="Use old Makefile build system (not cmake)") + parser.add_argument("--ninja", action="store_true", + help="Use ninja backed for CMake (instead of make)") + mutex_group = parser.add_mutually_exclusive_group() # TODO mvertens: the following is hard-wired - otherwise it does not work with nuopc @@ -109,12 +112,13 @@ def parse_command_line(args, description): cleanlist = args.clean if args.clean is None or len(args.clean) else comps buildlist = None if args.build is None or len(args.build) == 0 else args.build - return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old + return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old, args.ninja ############################################################################### def _main_func(description): ############################################################################### - caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance, use_old = parse_command_line(sys.argv, description) + caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance, use_old, ninja = \ + parse_command_line(sys.argv, description) success = True with Case(caseroot, read_only=False) as case: @@ -138,12 +142,12 @@ def _main_func(description): raise expect(buildlist is None, "Build lists don't work with tests") - success = test.build(sharedlib_only=sharedlib_only, model_only=model_only, old_build=use_old) + success = test.build(sharedlib_only=sharedlib_only, model_only=model_only, old_build=use_old, ninja=ninja) else: success = build.case_build(caseroot, case=case, sharedlib_only=sharedlib_only, model_only=model_only, buildlist=buildlist, save_build_provenance=save_build_provenance, - use_old=use_old) + use_old=use_old, ninja=ninja) sys.exit(0 if success else 1) diff --git a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py index 80e2c567dd12..09d664886dbe 100644 --- a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py +++ b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py @@ -34,6 +34,7 @@ def __init__(self, case, expected=None): self._skip_pnl = False self._cpllog = "med" if self._case.get_value("COMP_INTERFACE")=="nuopc" else "cpl" self._old_build = False + self._ninja = False def _init_environment(self, caseroot): """ @@ -67,7 +68,7 @@ def _resetup_case(self, phase, reset=False): self._case.case_setup(reset=True, test_mode=True) - def build(self, sharedlib_only=False, model_only=False, old_build=False): + def build(self, sharedlib_only=False, model_only=False, old_build=False, ninja=False): """ Do NOT override this method, this method is the framework that controls the build phase. build_phase is the extension point @@ -75,6 +76,7 @@ def build(self, sharedlib_only=False, model_only=False, old_build=False): """ success = True self._old_build = old_build + self._ninja = ninja for phase_name, phase_bool in [(SHAREDLIB_BUILD_PHASE, not model_only), (MODEL_BUILD_PHASE, not sharedlib_only)]: if phase_bool: @@ -122,7 +124,7 @@ def build_indv(self, sharedlib_only=False, model_only=False): model = self._case.get_value('MODEL') build.case_build(self._caseroot, case=self._case, sharedlib_only=sharedlib_only, model_only=model_only, - save_build_provenance=not model=='cesm', use_old=self._old_build) + save_build_provenance=not model=='cesm', use_old=self._old_build, ninja=self._ninja) def clean_build(self, comps=None): if comps is None: diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index f84b3c67a01a..a9c76099f6a7 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -148,7 +148,7 @@ def _build_model(build_threaded, exeroot, incroot, complist, ############################################################################### def _build_model_cmake(build_threaded, exeroot, incroot, complist, - lid, caseroot, cimeroot, compiler, buildlist, comp_interface, sharedpath, case): + lid, caseroot, cimeroot, compiler, buildlist, comp_interface, sharedpath, ninja, case): ############################################################################### cime_model = get_model() bldroot = os.path.join(exeroot, "bld") @@ -175,6 +175,8 @@ def _build_model_cmake(build_threaded, exeroot, incroot, complist, # Call CMake cmake_args = get_standard_cmake_args(case, sharedpath) + if ninja: + cmake_args += " -GNinja " cmake_cmd = "cmake {} {}/components >> {} 2>&1".format(cmake_args, srcroot, bldlog) with open(bldlog, "w") as fd: fd.write("Configuring with cmake cmd:\n{}\n\n".format(cmake_cmd)) @@ -182,7 +184,7 @@ def _build_model_cmake(build_threaded, exeroot, incroot, complist, # Call Make if stat == 0: - make_cmd = "{} -j {} >> {} 2>&1".format(gmake, gmake_j, bldlog) + make_cmd = "{} -j {} >> {} 2>&1".format("ninja" if ninja else gmake, gmake_j, bldlog) with open(bldlog, "a") as fd: fd.write("\n\nBuilding with make cmd:\n{}\n\n".format(make_cmd)) @@ -453,7 +455,7 @@ def _clean_impl(case, cleanlist, clean_all, clean_depends): ############################################################################### def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance, use_old): + save_build_provenance, use_old, ninja): ############################################################################### t1 = time.time() @@ -464,6 +466,7 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, logger.info("sharedlib_only is {}".format(sharedlib_only)) logger.info("model_only is {}".format(model_only)) + expect(not (use_old and ninja), "Ninja backend not supported for classic build system") expect(os.path.isdir(caseroot), "'{}' is not a valid directory".format(caseroot)) os.chdir(caseroot) @@ -576,7 +579,7 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, if not sharedlib_only: if get_model() == "e3sm" and not use_old: logs.extend(_build_model_cmake(build_threaded, exeroot, incroot, complist, - lid, caseroot, cimeroot, compiler, buildlist, comp_interface, sharedpath, case)) + lid, caseroot, cimeroot, compiler, buildlist, comp_interface, sharedpath, ninja, case)) else: os.environ["INSTALL_SHAREDPATH"] = os.path.join(exeroot, sharedpath) # for MPAS makefile generators logs.extend(_build_model(build_threaded, exeroot, incroot, complist, @@ -621,10 +624,10 @@ def post_build(case, logs, build_complete=False, save_build_provenance=True): lock_file("env_build.xml", caseroot=case.get_value("CASEROOT")) ############################################################################### -def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True, use_old=False): +def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True, use_old=False, ninja=False): ############################################################################### functor = lambda: _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance, use_old) + save_build_provenance, use_old, ninja) return run_and_log_case_status(functor, "case.build", caseroot=caseroot) ############################################################################### From f30ff29c70fe3513756cfad8610abaa8ecaa39f5 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 8 Jul 2019 13:00:40 -0600 Subject: [PATCH 25/48] Libs can live in their natural location --- components/CMakeLists.txt | 13 +++++++++---- components/{ => cmake}/build_model.cmake | 0 components/{ => cmake}/build_mpas_model.cmake | 0 components/{ => cmake}/cmake_util.cmake | 0 components/{ => cmake}/common_setup.cmake | 2 -- 5 files changed, 9 insertions(+), 6 deletions(-) rename components/{ => cmake}/build_model.cmake (100%) rename components/{ => cmake}/build_mpas_model.cmake (100%) rename components/{ => cmake}/cmake_util.cmake (100%) rename components/{ => cmake}/common_setup.cmake (99%) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index c3eac5762e17..485c2808b83b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -18,16 +18,21 @@ cmake_policy(SET CMP0057 NEW) project(E3SM C CXX Fortran) -include(${CMAKE_CURRENT_SOURCE_DIR}/cmake_util.cmake) -include(${CMAKE_CURRENT_SOURCE_DIR}/build_mpas_model.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_util.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_mpas_model.cmake) set(BUILDCONF ${CASEROOT}/Buildconf) +# set(COMP_CLASSES CPL ATM LND ICE OCN ROF GLC WAV IAC ESP) +# foreach(ITEM IN LISTS COMP_NAMES) +# message("JGF ITEM IS ${ITEM}") +# endforeach() + # Do any MPAS builds first since they manage their own flags build_mpas_models() -include(${CMAKE_CURRENT_SOURCE_DIR}/common_setup.cmake) -include(${CMAKE_CURRENT_SOURCE_DIR}/build_model.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/common_setup.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_model.cmake) # For each component that has registered itself to be built, read in Filepath and # CCSM_cppdefs and build it. We identify the components by looking for Buildconf/*/Filepath diff --git a/components/build_model.cmake b/components/cmake/build_model.cmake similarity index 100% rename from components/build_model.cmake rename to components/cmake/build_model.cmake diff --git a/components/build_mpas_model.cmake b/components/cmake/build_mpas_model.cmake similarity index 100% rename from components/build_mpas_model.cmake rename to components/cmake/build_mpas_model.cmake diff --git a/components/cmake_util.cmake b/components/cmake/cmake_util.cmake similarity index 100% rename from components/cmake_util.cmake rename to components/cmake/cmake_util.cmake diff --git a/components/common_setup.cmake b/components/cmake/common_setup.cmake similarity index 99% rename from components/common_setup.cmake rename to components/cmake/common_setup.cmake index 8da9fa22b149..4908086cf69d 100644 --- a/components/common_setup.cmake +++ b/components/cmake/common_setup.cmake @@ -4,8 +4,6 @@ # Set global cmake settings set(CMAKE_MODULE_PATH ${CIMEROOT}/src/CMake) set(CMAKE_VERBOSE_MAKEFILE TRUE) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/..) # Add INCROOT to path for Depends and Include From 34863ff6025161cb388110ac6ed7e488f04e3f67 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 8 Jul 2019 16:32:11 -0600 Subject: [PATCH 26/48] Progress towards separate build dirs for components --- cime/scripts/lib/CIME/build.py | 3 ++ components/CMakeLists.txt | 34 ++++++++------------- components/cmake/atm/CMakeLists.txt | 1 + components/cmake/build_model.cmake | 40 +++++++++++++++---------- components/cmake/build_mpas_model.cmake | 10 +++---- components/cmake/cmake_util.cmake | 6 ++-- components/cmake/cpl/CMakeLists.txt | 1 + components/cmake/esp/CMakeLists.txt | 1 + components/cmake/glc/CMakeLists.txt | 1 + components/cmake/iac/CMakeLists.txt | 1 + components/cmake/ice/CMakeLists.txt | 1 + components/cmake/lnd/CMakeLists.txt | 1 + components/cmake/ocn/CMakeLists.txt | 1 + components/cmake/rof/CMakeLists.txt | 1 + components/cmake/wav/CMakeLists.txt | 1 + 15 files changed, 55 insertions(+), 48 deletions(-) create mode 100644 components/cmake/atm/CMakeLists.txt create mode 100644 components/cmake/cpl/CMakeLists.txt create mode 100644 components/cmake/esp/CMakeLists.txt create mode 100644 components/cmake/glc/CMakeLists.txt create mode 100644 components/cmake/iac/CMakeLists.txt create mode 100644 components/cmake/ice/CMakeLists.txt create mode 100644 components/cmake/lnd/CMakeLists.txt create mode 100644 components/cmake/ocn/CMakeLists.txt create mode 100644 components/cmake/rof/CMakeLists.txt create mode 100644 components/cmake/wav/CMakeLists.txt diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index a9c76099f6a7..552bbf3814d7 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -40,6 +40,9 @@ def get_standard_cmake_args(case, sharedpath, shared_lib=False): if not shared_lib: cmake_args += " -DUSE_KOKKOS={} ".format(stringify_bool(uses_kokkos(case))) + comps = [case.get_value("COMP_{}".format(comp_class)) for comp_class in case.get_values("COMP_CLASSES")] + cmake_args += " -DCOMP_NAMES='{}' ".format(";".join(comps)) + for var in _CMD_ARGS_FOR_BUILD: cmake_args += xml_to_make_variable(case, var, cmake=True) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 485c2808b83b..0428855cf7aa 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -23,34 +23,24 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_mpas_model.cmake) set(BUILDCONF ${CASEROOT}/Buildconf) -# set(COMP_CLASSES CPL ATM LND ICE OCN ROF GLC WAV IAC ESP) -# foreach(ITEM IN LISTS COMP_NAMES) -# message("JGF ITEM IS ${ITEM}") -# endforeach() - # Do any MPAS builds first since they manage their own flags build_mpas_models() include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/common_setup.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_model.cmake) -# For each component that has registered itself to be built, read in Filepath and -# CCSM_cppdefs and build it. We identify the components by looking for Buildconf/*/Filepath -# files. -file(GLOB FILEPATHS "${BUILDCONF}/*/Filepath") -foreach(ITEM IN LISTS FILEPATHS) - get_filename_component(FILEPATH_DIR ${ITEM} DIRECTORY) - get_filename_component(MODELCONF ${FILEPATH_DIR} NAME) - string(REPLACE "conf" "" MODEL "${MODELCONF}") - - if (NOT MODEL STREQUAL "cpl") - message("Found component model ${MODEL}") - list(APPEND MODELS ${MODEL}) - - build_model(${MODEL} ${FILEPATH_DIR} "") +# Build E3SM components +set(IDX 0) +set(COMP_CLASSES cpl atm lnd ice ocn rof glc wav iac esp) +set(MPAS_COMPS "mpaso" "mpassi" "mali") +foreach(COMP_NAME IN LISTS COMP_NAMES) + list(GET COMP_CLASSES ${IDX} COMP_CLASS) + if (NOT COMP_CLASS STREQUAL "cpl" AND NOT COMP_NAME IN_LIST MPAS_COMPS) + message("Found component ${COMP_CLASS} model '${COMP_NAME}'") + add_subdirectory(cmake/${COMP_CLASS}) endif() -endforeach() -message("Configuring exe with cpl and models ${MODELS}") -build_model("cpl" "${BUILDCONF}/cplconf" "${MODELS}") + math(EXPR IDX "${IDX} + 1") +endforeach() +add_subdirectory(cmake/cpl) diff --git a/components/cmake/atm/CMakeLists.txt b/components/cmake/atm/CMakeLists.txt new file mode 100644 index 000000000000..a46cff483ee3 --- /dev/null +++ b/components/cmake/atm/CMakeLists.txt @@ -0,0 +1 @@ +build_model("${COMP_CLASS}" "${COMP_NAME}") diff --git a/components/cmake/build_model.cmake b/components/cmake/build_model.cmake index adb7c30ecc9f..0b5b09bfb50f 100644 --- a/components/cmake/build_model.cmake +++ b/components/cmake/build_model.cmake @@ -1,11 +1,13 @@ -function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) +function(build_model COMP_CLASS_ARG MODEL_ARG) + set(MODELCONF_DIR "${BUILDCONF}/${MODEL_ARG}conf") + # Load dependency search path. - file(STRINGS ${MODELCONF_DIR_ARG}/Filepath FILEPATH_DIRS) + file(STRINGS ${MODELCONF_DIR}/Filepath FILEPATH_DIRS) set(CPP_DIRS ${FILEPATH_DIRS}) list(APPEND CPP_DIRS ".") # Load cppdefs - set(CCSM_CPPDEFS_FILE "${MODELCONF_DIR_ARG}/CCSM_cppdefs") + set(CCSM_CPPDEFS_FILE "${MODELCONF_DIR}/CCSM_cppdefs") if (EXISTS ${CCSM_CPPDEFS_FILE}) file(READ ${CCSM_CPPDEFS_FILE} CCSM_CPPDEFS) string(STRIP "${CCSM_CPPDEFS}" CCSM_CPPDEFS) @@ -14,6 +16,9 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) if (MODEL_ARG STREQUAL "cpl") list(APPEND INCLDIR "${EXEROOT}/bld/mpas-source/src") + foreach(ITEM IN LISTS COMP_CLASSES) + list(APPEND INCLDIR "${EXEROOT}/bld/cmake/${ITEM}") + endforeach() endif() #------------------------------------------------------------------------------- @@ -182,34 +187,37 @@ function(build_model MODEL_ARG MODELCONF_DIR_ARG ALL_MODELS_ARG) endif() if (MODEL_ARG STREQUAL "cpl") - set(MODEL_ARG "${CIME_MODEL}.exe") - add_executable(${MODEL_ARG}) - target_sources(${MODEL_ARG} PRIVATE ${SOURCES}) + set(TARGET_NAME "${CIME_MODEL}.exe") + add_executable(${TARGET_NAME}) + target_sources(${TARGET_NAME} PRIVATE ${SOURCES}) set(ALL_LIBS "${ULIBDEP} ${MCTLIBS} ${PIOLIB} ${GPTLLIB} ${SLIBS} ${MLIBS} ${F90_LDFLAGS}") separate_arguments(ALL_LIBS_LIST UNIX_COMMAND "${ALL_LIBS}") - foreach(ITEM IN LISTS ALL_MODELS_ARG) - target_link_libraries(${MODEL_ARG} ${ITEM}) + foreach(ITEM IN LISTS COMP_CLASSES) + if (NOT ITEM STREQUAL "cpl") + target_link_libraries(${TARGET_NAME} ${ITEM}) + endif() endforeach() foreach(ITEM IN LISTS ALL_LIBS_LIST) - target_link_libraries(${MODEL_ARG} ${ITEM}) + target_link_libraries(${TARGET_NAME} ${ITEM}) endforeach() - set_target_properties(${MODEL_ARG} PROPERTIES LINKER_LANGUAGE ${LD}) + set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE ${LD}) else() - add_library(${MODEL_ARG}) + set(TARGET_NAME ${COMP_CLASS_ARG}) + add_library(${TARGET_NAME}) if (XCOMP) - target_sources(${MODEL_ARG} PRIVATE ${SOURCES} $) + target_sources(${TARGET_NAME} PRIVATE ${SOURCES} $) else() - target_sources(${MODEL_ARG} PRIVATE ${SOURCES}) + target_sources(${TARGET_NAME} PRIVATE ${SOURCES}) endif() endif() # Subtle: In order for fortran dependency scanning to work, our CPPFPP/DEFS must be registered # as COMPILE_DEFINITIONS, not simple added via CMAKE_Fortran_Flags. Also, CPPDEFS *must* # be provided as a list, not a whitespace-separated string; otherwise, things get wonky. - target_compile_definitions(${MODEL_ARG} PRIVATE ${CPPDEFS_LIST}) - add_dependencies(${MODEL_ARG} genf90) + target_compile_definitions(${TARGET_NAME} PRIVATE ${CPPDEFS_LIST}) + add_dependencies(${TARGET_NAME} genf90) # Set flags for target - target_include_directories(${MODEL_ARG} PRIVATE ${INCLDIR}) + target_include_directories(${TARGET_NAME} PRIVATE ${INCLDIR}) endfunction(build_model) diff --git a/components/cmake/build_mpas_model.cmake b/components/cmake/build_mpas_model.cmake index 2cc500b5c1ab..eccde092fc50 100644 --- a/components/cmake/build_mpas_model.cmake +++ b/components/cmake/build_mpas_model.cmake @@ -7,13 +7,13 @@ function(build_mpas_models) if (MODEL STREQUAL "mpaso") list(APPEND CORES "ocean") - list(APPEND MODELS "ocn") + set(COMP_CLASS "ocn") elseif (MODEL STREQUAL "mpassi") list(APPEND CORES "seaice") - list(APPEND MODELS "ice") + set(COMP_CLASS "ice") elseif (MODEL STREQUAL "mali") list(APPEND CORES "landice") - list(APPEND MODELS "glc") + set(COMP_CLASS "glc") if (USE_ALBANY) set(ALBANY True) endif() @@ -21,11 +21,9 @@ function(build_mpas_models) message(FATAL_ERROR "Unrecognized MPAS model ${MODEL_ARG}") endif() - message("Found MPAS component model '${MODEL}'") + message("Found MPAS component ${COMP_CLASS} model '${MODEL}'") endforeach() - set(MODELS ${MODELS} PARENT_SCOPE) - if (CORES) add_subdirectory("mpas-source/src") endif() diff --git a/components/cmake/cmake_util.cmake b/components/cmake/cmake_util.cmake index a817c440693c..e2df5da01a9c 100644 --- a/components/cmake/cmake_util.cmake +++ b/components/cmake/cmake_util.cmake @@ -1,12 +1,10 @@ function(gather_sources FILEPATH_DIRS_ARG CIMEROOT_ARG) - set(SRCROOT_REL "${CIMEROOT_ARG}/..") set(BASENAME_SET) set(SOURCES_RESULT) set(GEN_F90_SOURCES_RESULT) - file(TO_CMAKE_PATH ${SRCROOT_REL} SRCROOT_ABS) foreach(DIRSEARCH ${FILEPATH_DIRS_ARG}) - file(GLOB MATCHES RELATIVE "${SRCROOT_ABS}/components" "${DIRSEARCH}/*.[Ffc]" "${DIRSEARCH}/*.[Ff]90" "${DIRSEARCH}/*.cpp" "${DIRSEARCH}/*.F90.in") + file(GLOB MATCHES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${DIRSEARCH}/*.[Ffc]" "${DIRSEARCH}/*.[Ff]90" "${DIRSEARCH}/*.cpp" "${DIRSEARCH}/*.F90.in") if (MATCHES) foreach (MATCH IN LISTS MATCHES) get_filename_component(BASENAME ${MATCH} NAME) @@ -15,7 +13,7 @@ function(gather_sources FILEPATH_DIRS_ARG CIMEROOT_ARG) list(APPEND SOURCES_RESULT ${MATCH}) list(APPEND BASENAME_SET ${BASENAME}) else() - message(WARNING "Skipping repeated base filename ${BASENAME} for ${MATCH}") + message("Warning: Skipping repeated base filename ${BASENAME} for ${MATCH}") endif() endforeach() endif() diff --git a/components/cmake/cpl/CMakeLists.txt b/components/cmake/cpl/CMakeLists.txt new file mode 100644 index 000000000000..8e94ff8f308e --- /dev/null +++ b/components/cmake/cpl/CMakeLists.txt @@ -0,0 +1 @@ +build_model("cpl" "cpl") diff --git a/components/cmake/esp/CMakeLists.txt b/components/cmake/esp/CMakeLists.txt new file mode 100644 index 000000000000..0660d50f956e --- /dev/null +++ b/components/cmake/esp/CMakeLists.txt @@ -0,0 +1 @@ +build_model(${COMP_CLASS} ${COMP_NAME}) diff --git a/components/cmake/glc/CMakeLists.txt b/components/cmake/glc/CMakeLists.txt new file mode 100644 index 000000000000..0660d50f956e --- /dev/null +++ b/components/cmake/glc/CMakeLists.txt @@ -0,0 +1 @@ +build_model(${COMP_CLASS} ${COMP_NAME}) diff --git a/components/cmake/iac/CMakeLists.txt b/components/cmake/iac/CMakeLists.txt new file mode 100644 index 000000000000..0660d50f956e --- /dev/null +++ b/components/cmake/iac/CMakeLists.txt @@ -0,0 +1 @@ +build_model(${COMP_CLASS} ${COMP_NAME}) diff --git a/components/cmake/ice/CMakeLists.txt b/components/cmake/ice/CMakeLists.txt new file mode 100644 index 000000000000..0660d50f956e --- /dev/null +++ b/components/cmake/ice/CMakeLists.txt @@ -0,0 +1 @@ +build_model(${COMP_CLASS} ${COMP_NAME}) diff --git a/components/cmake/lnd/CMakeLists.txt b/components/cmake/lnd/CMakeLists.txt new file mode 100644 index 000000000000..0660d50f956e --- /dev/null +++ b/components/cmake/lnd/CMakeLists.txt @@ -0,0 +1 @@ +build_model(${COMP_CLASS} ${COMP_NAME}) diff --git a/components/cmake/ocn/CMakeLists.txt b/components/cmake/ocn/CMakeLists.txt new file mode 100644 index 000000000000..0660d50f956e --- /dev/null +++ b/components/cmake/ocn/CMakeLists.txt @@ -0,0 +1 @@ +build_model(${COMP_CLASS} ${COMP_NAME}) diff --git a/components/cmake/rof/CMakeLists.txt b/components/cmake/rof/CMakeLists.txt new file mode 100644 index 000000000000..0660d50f956e --- /dev/null +++ b/components/cmake/rof/CMakeLists.txt @@ -0,0 +1 @@ +build_model(${COMP_CLASS} ${COMP_NAME}) diff --git a/components/cmake/wav/CMakeLists.txt b/components/cmake/wav/CMakeLists.txt new file mode 100644 index 000000000000..0660d50f956e --- /dev/null +++ b/components/cmake/wav/CMakeLists.txt @@ -0,0 +1 @@ +build_model(${COMP_CLASS} ${COMP_NAME}) From ccc4d4fda069edf052b434e2e5fd7577b81e9d21 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 8 Jul 2019 17:08:07 -0600 Subject: [PATCH 27/48] With separate build dirs, special handling of xshare is no longer needed --- cime/scripts/lib/CIME/buildlib.py | 5 ++--- components/cmake/build_model.cmake | 32 +++--------------------------- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index 6cfda675767a..1c1acdc799ca 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -61,9 +61,8 @@ def build_cime_component_lib(case, compname, libroot, bldroot, use_old=True): out.write(os.path.join(cimeroot, "src", "components", "data_comps", compname, comp_interface) + "\n") out.write(os.path.join(cimeroot, "src", "components", "data_comps", compname) + "\n") elif compname.startswith('x'): - if use_old: - out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", "xshare") + "\n") - out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", "xshare", comp_interface) + "\n") + out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", "xshare") + "\n") + out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", "xshare", comp_interface) + "\n") out.write(os.path.join(cimeroot, "src", "components", "xcpl_comps", compname, comp_interface) + "\n") elif compname.startswith('s'): out.write(os.path.join(cimeroot, "src", "components", "stub_comps", compname, comp_interface) + "\n") diff --git a/components/cmake/build_model.cmake b/components/cmake/build_model.cmake index 0b5b09bfb50f..95ff55d677ec 100644 --- a/components/cmake/build_model.cmake +++ b/components/cmake/build_model.cmake @@ -59,21 +59,6 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) endif() - #------------------------------------------------------------------------------- - # x components need special handling due to xshare - #------------------------------------------------------------------------------- - if (MODEL_ARG MATCHES "x.*") - set(XCOMP True) - endif() - - if (XCOMP AND NOT TARGET xshare) - gather_sources("${CIMEROOT}/src/components/xcpl_comps/xshare;${CIMEROOT}/src/components/xcpl_comps/xshare/${COMP_INTERFACE}" "${CIMEROOT}") - set(XSHARE_SOURCES ${SOURCES_RESULT}) - if (GEN_F90_SOURCES_RESULT) - message(FATAL_ERROR "genf90 files not allows in xshare") - endif() - endif() - #------------------------------------------------------------------------------- # create list of component libraries - hard-wired for current ccsm components #------------------------------------------------------------------------------- @@ -139,7 +124,7 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) endforeach () # Flags are slightly different for different fortran extensions - foreach (SOURCE_FILE IN LISTS SOURCES XSHARE_SOURCES) + foreach (SOURCE_FILE IN LISTS SOURCES) # Cosp manages its own flags if (NOT SOURCE_FILE IN_LIST COSP_SOURCES) get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) @@ -178,14 +163,6 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) set(MLIBS "${MLIBS} ${MPISERIAL}") endif() - separate_arguments(CPPDEFS_LIST UNIX_COMMAND "${CPPDEFS}") - - if (XCOMP AND NOT TARGET xshare) - add_library(xshare OBJECT ${XSHARE_SOURCES}) - target_compile_definitions(xshare PRIVATE ${CPPDEFS_LIST}) - target_include_directories(xshare PRIVATE ${INCLDIR}) - endif() - if (MODEL_ARG STREQUAL "cpl") set(TARGET_NAME "${CIME_MODEL}.exe") add_executable(${TARGET_NAME}) @@ -204,16 +181,13 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) else() set(TARGET_NAME ${COMP_CLASS_ARG}) add_library(${TARGET_NAME}) - if (XCOMP) - target_sources(${TARGET_NAME} PRIVATE ${SOURCES} $) - else() - target_sources(${TARGET_NAME} PRIVATE ${SOURCES}) - endif() + target_sources(${TARGET_NAME} PRIVATE ${SOURCES}) endif() # Subtle: In order for fortran dependency scanning to work, our CPPFPP/DEFS must be registered # as COMPILE_DEFINITIONS, not simple added via CMAKE_Fortran_Flags. Also, CPPDEFS *must* # be provided as a list, not a whitespace-separated string; otherwise, things get wonky. + separate_arguments(CPPDEFS_LIST UNIX_COMMAND "${CPPDEFS}") target_compile_definitions(${TARGET_NAME} PRIVATE ${CPPDEFS_LIST}) add_dependencies(${TARGET_NAME} genf90) From 3c934e6404ca0df77bd41389f4b9d64f8aacbfe1 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 8 Jul 2019 18:29:12 -0600 Subject: [PATCH 28/48] Only E3SM needs --use-old option to case.build --- cime/scripts/Tools/case.build | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cime/scripts/Tools/case.build b/cime/scripts/Tools/case.build index f79122ee0c92..4b17dd804d61 100755 --- a/cime/scripts/Tools/case.build +++ b/cime/scripts/Tools/case.build @@ -46,7 +46,7 @@ from standard_script_setup import * import CIME.build as build from CIME.case import Case -from CIME.utils import find_system_test +from CIME.utils import find_system_test, get_model from CIME.test_status import * ############################################################################### @@ -62,8 +62,9 @@ def parse_command_line(args, description): help="Case directory to build.\n" "Default is current directory.") - parser.add_argument("--use-old", action="store_true", - help="Use old Makefile build system (not cmake)") + if get_model() == "e3sm": + parser.add_argument("--use-old", action="store_true", + help="Use old Makefile build system (not cmake)") parser.add_argument("--ninja", action="store_true", help="Use ninja backed for CMake (instead of make)") From 3ebac4b079a3ff121235e3dccb0926065b9343b0 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 10 Jul 2019 12:55:53 -0600 Subject: [PATCH 29/48] Fix pylint warnings --- cime/scripts/Tools/bld_diff | 2 +- cime/scripts/lib/CIME/build.py | 14 +++++++------- cime/scripts/lib/CIME/buildlib.py | 2 +- cime/src/drivers/mct/cime_config/buildlib_cmake | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cime/scripts/Tools/bld_diff b/cime/scripts/Tools/bld_diff index 2189a0916dd1..6d3323cd39f2 100755 --- a/cime/scripts/Tools/bld_diff +++ b/cime/scripts/Tools/bld_diff @@ -6,7 +6,7 @@ for the same component """ from standard_script_setup import * -from CIME.utils import expect, run_cmd_no_fail +from CIME.utils import run_cmd_no_fail import argparse, sys, os, gzip diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index 552bbf3814d7..c115fec1a5f2 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -64,7 +64,7 @@ def uses_kokkos(case): ############################################################################### def _build_model(build_threaded, exeroot, incroot, complist, - lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case): + lid, caseroot, cimeroot, compiler, buildlist, comp_interface): ############################################################################### logs = [] @@ -150,8 +150,8 @@ def _build_model(build_threaded, exeroot, incroot, complist, return logs ############################################################################### -def _build_model_cmake(build_threaded, exeroot, incroot, complist, - lid, caseroot, cimeroot, compiler, buildlist, comp_interface, sharedpath, ninja, case): +def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, + comp_interface, sharedpath, ninja, case): ############################################################################### cime_model = get_model() bldroot = os.path.join(exeroot, "bld") @@ -166,7 +166,7 @@ def _build_model_cmake(build_threaded, exeroot, incroot, complist, if not os.path.exists(build_dir): os.makedirs(build_dir) - for model, _, nthrds, _, config_dir in complist: + for model, _, _, _, config_dir in complist: if buildlist is not None and model.lower() not in buildlist: continue @@ -581,12 +581,12 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, if not sharedlib_only: if get_model() == "e3sm" and not use_old: - logs.extend(_build_model_cmake(build_threaded, exeroot, incroot, complist, - lid, caseroot, cimeroot, compiler, buildlist, comp_interface, sharedpath, ninja, case)) + logs.extend(_build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, + comp_interface, sharedpath, ninja, case)) else: os.environ["INSTALL_SHAREDPATH"] = os.path.join(exeroot, sharedpath) # for MPAS makefile generators logs.extend(_build_model(build_threaded, exeroot, incroot, complist, - lid, caseroot, cimeroot, compiler, buildlist, comp_interface, case)) + lid, caseroot, cimeroot, compiler, buildlist, comp_interface)) if not buildlist: # in case component build scripts updated the xml files, update the case object diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index 1c1acdc799ca..4b3db414ddf1 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -4,7 +4,7 @@ from CIME.XML.standard_module_setup import * from CIME.case import Case -from CIME.utils import parse_args_and_handle_standard_logging_options, setup_standard_logging_options, get_model, run_bld_cmd_ensure_logging, safe_copy +from CIME.utils import parse_args_and_handle_standard_logging_options, setup_standard_logging_options, get_model, safe_copy from CIME.build import get_standard_makefile_args import sys, os, argparse diff --git a/cime/src/drivers/mct/cime_config/buildlib_cmake b/cime/src/drivers/mct/cime_config/buildlib_cmake index 1133e66f26f5..f723bfedf27f 100755 --- a/cime/src/drivers/mct/cime_config/buildlib_cmake +++ b/cime/src/drivers/mct/cime_config/buildlib_cmake @@ -12,12 +12,12 @@ sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools")) from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case -from CIME.utils import expect, run_bld_cmd_ensure_logging +from CIME.utils import expect logger = logging.getLogger(__name__) ############################################################################### -def buildlib(bldroot, installpath, case): +def buildlib(bldroot, installpath, case): # pylint: disable=unused-argument ############################################################################### casebuild = case.get_value("CASEBUILD") caseroot = case.get_value("CASEROOT") From 7ce802cf927365e8fe70e2c77914dcfea92bf237 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 10 Jul 2019 15:18:52 -0600 Subject: [PATCH 30/48] change cmake bld dir --- cime/scripts/lib/CIME/build.py | 2 +- components/cmake/build_model.cmake | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index c115fec1a5f2..dc2a261baa55 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -154,7 +154,7 @@ def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, comp_interface, sharedpath, ninja, case): ############################################################################### cime_model = get_model() - bldroot = os.path.join(exeroot, "bld") + bldroot = os.path.join(exeroot, "cmake-bld") libroot = os.path.join(exeroot, "lib") bldlog = os.path.join(exeroot, "{}.bldlog.{}".format(cime_model, lid)) srcroot = case.get_value("SRCROOT") diff --git a/components/cmake/build_model.cmake b/components/cmake/build_model.cmake index 95ff55d677ec..828bce3672c1 100644 --- a/components/cmake/build_model.cmake +++ b/components/cmake/build_model.cmake @@ -15,9 +15,9 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) endif() if (MODEL_ARG STREQUAL "cpl") - list(APPEND INCLDIR "${EXEROOT}/bld/mpas-source/src") + list(APPEND INCLDIR "${EXEROOT}/cmake-bld/mpas-source/src") foreach(ITEM IN LISTS COMP_CLASSES) - list(APPEND INCLDIR "${EXEROOT}/bld/cmake/${ITEM}") + list(APPEND INCLDIR "${EXEROOT}/cmake-bld/cmake/${ITEM}") endforeach() endif() From 2c66234f2050b04facb35646a4f2c83e96efbd66 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 10 Jul 2019 18:34:24 -0600 Subject: [PATCH 31/48] Add helper for setting flags for indv files. Make it so users can refer to files by their position relative to E3SM/components even though the true position is relative to E3SM/components/cmake/compclass --- cime/config/e3sm/machines/Depends.gnu.cmake | 2 +- cime/config/e3sm/machines/Depends.ibm.cmake | 10 ++--- cime/config/e3sm/machines/Depends.intel.cmake | 10 ++--- .../e3sm/machines/Depends.summit.pgiacc.cmake | 2 +- .../machines/Depends.summitdev.pgiacc.cmake | 2 +- .../e3sm/machines/Depends.theta.intel.cmake | 4 +- components/cam/src/physics/cosp/Cosp.cmake | 6 +-- components/cmake/build_model.cmake | 38 ++++++++-------- components/cmake/cmake_util.cmake | 43 ++++++++++++++++++- 9 files changed, 77 insertions(+), 40 deletions(-) diff --git a/cime/config/e3sm/machines/Depends.gnu.cmake b/cime/config/e3sm/machines/Depends.gnu.cmake index 627b9085d8de..fc4d95bd139c 100644 --- a/cime/config/e3sm/machines/Depends.gnu.cmake +++ b/cime/config/e3sm/machines/Depends.gnu.cmake @@ -1 +1 @@ -set_property(SOURCE cam/src/dynamics/fv/geopk.F90 APPEND_STRING PROPERTY COMPILE_FLAGS " -fcray-pointer ") +e3sm_add_flags("cam/src/dynamics/fv/geopk.F90" "-fcray-pointer") diff --git a/cime/config/e3sm/machines/Depends.ibm.cmake b/cime/config/e3sm/machines/Depends.ibm.cmake index 5ebefbf91f75..5dec236111e2 100644 --- a/cime/config/e3sm/machines/Depends.ibm.cmake +++ b/cime/config/e3sm/machines/Depends.ibm.cmake @@ -4,11 +4,11 @@ set(SSOBJS cam/src/chemistry/mozart/mo_drydep.F90) foreach(ITEM IN LISTS SSOBJS) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -qsmallstack ") + e3sm_add_flags("${ITEM}" "-qsmallstack") endforeach() if (compile_threaded) - set_property(SOURCE share/util/shr_reprosum_mod.F90 APPEND_STRING PROPERTY COMPILE_FLAGS " -qsmp=noauto:noomp ") + e3sm_add_flags("share/util/shr_reprosum_mod.F90" "-qsmp=noauto:noomp") endif() # These routines benefit from -qnostrict without violating the bfb test @@ -37,11 +37,11 @@ set(NOINLINE if (NOT DEBUG) foreach(ITEM IN LISTS PERFOBJS) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -qnostrict ") + e3sm_add_flags("${ITEM}" "-qnostrict") endforeach() foreach(ITEM IN LISTS REDUCEOPT) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -O2 ") + e3sm_add_flags("${ITEM}" "-O2") endforeach() endif() @@ -52,5 +52,5 @@ endif() list(APPEND NOOPT_FILES cam/src/utils/buffer.F90) foreach(ITEN IN LISTS NOINLINE) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -Q! ") + e3sm_add_flags("${ITEM}" "-Q!") endforeach() diff --git a/cime/config/e3sm/machines/Depends.intel.cmake b/cime/config/e3sm/machines/Depends.intel.cmake index a4f86e63fe31..6a66db02d2a6 100644 --- a/cime/config/e3sm/machines/Depends.intel.cmake +++ b/cime/config/e3sm/machines/Depends.intel.cmake @@ -32,19 +32,19 @@ set(SHR_RANDNUM_C_OBJS if (NOT DEBUG) foreach(ITEM IN LISTS PERFOBJS) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -O3 -fp-model fast -no-prec-div ") + e3sm_add_flags("${ITEM}" "-O3 -fp-model fast -no-prec-div") endforeach() foreach(ITEM IN LISTS REDUCED_PRECISION_OBJS) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -fimf-precision=low -fp-model fast ") + e3sm_add_flags("${ITEM}" "-fimf-precision=low -fp-model fast") endforeach() foreach(ITEM IN LISTS SHR_RANDNUM_FORT_OBJS) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -O3 -fp-model fast -no-prec-div -no-prec-sqrt -qoverride-limits ") + e3sm_add_flags("${ITEM}" "-O3 -fp-model fast -no-prec-div -no-prec-sqrt -qoverride-limits") endforeach() foreach(ITEM IN LISTS SHR_RANDNUM_C_OBJS) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -O3 -fp-model fast ") + e3sm_add_flags("${ITEM}" "-O3 -fp-model fast") endforeach() -endif() \ No newline at end of file +endif() diff --git a/cime/config/e3sm/machines/Depends.summit.pgiacc.cmake b/cime/config/e3sm/machines/Depends.summit.pgiacc.cmake index 890bc4387715..de022324a614 100644 --- a/cime/config/e3sm/machines/Depends.summit.pgiacc.cmake +++ b/cime/config/e3sm/machines/Depends.summit.pgiacc.cmake @@ -1,3 +1,3 @@ foreach(ITEM IN LISTS FILES_NEED_CUDA_FLAGS) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -DUSE_OPENACC=1 -acc -ta=tesla,cc70,pinned -Minfo=accel ") + e3sm_add_flags("${ITEM}" "-DUSE_OPENACC=1 -acc -ta=tesla,cc70,pinned -Minfo=accel") endforeach() diff --git a/cime/config/e3sm/machines/Depends.summitdev.pgiacc.cmake b/cime/config/e3sm/machines/Depends.summitdev.pgiacc.cmake index e9626664baaf..48f1346a2d34 100644 --- a/cime/config/e3sm/machines/Depends.summitdev.pgiacc.cmake +++ b/cime/config/e3sm/machines/Depends.summitdev.pgiacc.cmake @@ -1,3 +1,3 @@ foreach(ITEM IN LISTS FILES_NEED_CUDA_FLAGS) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " -DUSE_OPENACC=1 -acc -ta=tesla,cc60,pinned -Minfo=accel ") + e3sm_add_flags("${ITEM}" "-DUSE_OPENACC=1 -acc -ta=tesla,cc60,pinned -Minfo=accel") endforeach() diff --git a/cime/config/e3sm/machines/Depends.theta.intel.cmake b/cime/config/e3sm/machines/Depends.theta.intel.cmake index 12a852fd20d9..49aa7a90f3dd 100644 --- a/cime/config/e3sm/machines/Depends.theta.intel.cmake +++ b/cime/config/e3sm/machines/Depends.theta.intel.cmake @@ -2,8 +2,6 @@ if (NOT DEBUG) foreach(ITEM IN LISTS PERFOBJS) - get_property(ITEM_FLAGS SOURCE ${ITEM} PROPERTY COMPILE_FLAGS) - string(REPLACE "-fp-model fast" "" ITEM_FLAGS "${ITEM_FLAGS}") - set_property(SOURCE ${ITEM} PROPERTY COMPILE_FLAGS "${ITEM_FLAGS}") + e3sm_remove_flags("${ITEM}" "-fp-model fast") endforeach() endif() diff --git a/components/cam/src/physics/cosp/Cosp.cmake b/components/cam/src/physics/cosp/Cosp.cmake index 85316dbfd220..2693bb83259d 100644 --- a/components/cam/src/physics/cosp/Cosp.cmake +++ b/components/cam/src/physics/cosp/Cosp.cmake @@ -55,13 +55,13 @@ foreach(ITEM IN LISTS COSP_SOURCES) list(FIND COSP_NOAUTO ${ITEM} ITEM_IS_NO_AUTO) if (ITEM IN_LIST COSP_FIXED) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FIXEDFLAGS}") + e3sm_add_flags("${ITEM}" "${FIXEDFLAGS}") else() - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FREEFLAGS}") + e3sm_add_flags("${ITEM}" "${FREEFLAGS}") endif() if (NOT ITEM IN_LIST COSP_NOAUTO) - set_property(SOURCE ${ITEM} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FC_AUTO_R8}") + e3sm_add_flags("${ITEM}" "${FC_AUTO_R8}") endif() endforeach() diff --git a/components/cmake/build_model.cmake b/components/cmake/build_model.cmake index 828bce3672c1..101b9644536b 100644 --- a/components/cmake/build_model.cmake +++ b/components/cmake/build_model.cmake @@ -25,14 +25,6 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) # Build & include dependency files #------------------------------------------------------------------------------- - # Get src files - # JGF: Cmake does not have a VPATH concept, so we need relative/absolute paths to source files - # Note: Using absolute paths seems to wreck CMake's ability to do a dep analysis on fortran - # sources and compile them in the right order. - # - # One additional subtley is that, when mkSrcfiles found multiple files with the same basename, - # only the one found first gets compiled. - gather_sources("${FILEPATH_DIRS}" "${CIMEROOT}") set(SOURCES ${SOURCES_RESULT}) set(GEN_F90_SOURCES ${GEN_F90_SOURCES_RESULT}) @@ -54,7 +46,7 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) set(NOOPT_FILES "cam/src/physics/rrtmg/ext/rrtmg_lw/rrtmg_lw_k_g.f90;cam/src/physics/rrtmg/ext/rrtmg_sw/rrtmg_sw_k_g.f90") if (COSP_LIBDIR) - include(${CMAKE_CURRENT_SOURCE_DIR}/cam/src/physics/cosp/Cosp.cmake) + include(${PROJECT_SOURCE_DIR}/cam/src/physics/cosp/Cosp.cmake) endif() endif() @@ -115,12 +107,12 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) foreach (SRC_FILE IN LISTS GEN_F90_SOURCES) get_filename_component(BASENAME ${SRC_FILE} NAME) add_custom_command ( - OUTPUT ${CMAKE_BINARY_DIR}/${BASENAME} + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BASENAME} COMMAND ${CIMEROOT}/src/externals/genf90/genf90.pl - ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in > ${CMAKE_BINARY_DIR}/${BASENAME} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in genf90) + ${PROJECT_SOURCE_DIR}/${SRC_FILE}.in > ${CMAKE_CURRENT_BINARY_DIR}/${BASENAME} + DEPENDS ${PROJECT_SOURCE_DIR}/${SRC_FILE}.in genf90) list(REMOVE_ITEM SOURCES ${SRC_FILE}) - list(APPEND SOURCES ${CMAKE_BINARY_DIR}/${BASENAME}) + list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${BASENAME}) endforeach () # Flags are slightly different for different fortran extensions @@ -129,11 +121,11 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) if (NOT SOURCE_FILE IN_LIST COSP_SOURCES) get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) if (SOURCE_EXT STREQUAL ".F" OR SOURCE_EXT STREQUAL ".f") - set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FIXEDFLAGS}") + e3sm_add_flags("${SOURCE_FILE}" "${FIXEDFLAGS}") elseif(SOURCE_EXT STREQUAL ".f90") - set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FREEFLAGS}") + e3sm_add_flags("${SOURCE_FILE}" "${FREEFLAGS}") elseif(SOURCE_EXT STREQUAL ".F90") - set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FREEFLAGS} ${CONTIGUOUS_FLAG}") + e3sm_add_flags("${SOURCE_FILE}" "${FREEFLAGS} ${CONTIGUOUS_FLAG}") endif() endif() endforeach() @@ -151,7 +143,7 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) # Disable optimizations on some files that would take too long to compile, expect these to all be fortran files foreach (SOURCE_FILE IN LISTS NOOPT_FILES) - set_property(SOURCE ${SOURCE_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FFLAGS_NOOPT}") + e3sm_add_flags("${SOURCE_FILE}" "${FFLAGS_NOOPT}") endforeach() #------------------------------------------------------------------------------- @@ -163,10 +155,18 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) set(MLIBS "${MLIBS} ${MPISERIAL}") endif() + foreach(ITEM IN LISTS SOURCES) + if (ITEM MATCHES "${CMAKE_BINARY_DIR}/.*") # is generated + list(APPEND REAL_SOURCES ${ITEM}) + else() + list(APPEND REAL_SOURCES "../../${ITEM}") + endif() + endforeach() + if (MODEL_ARG STREQUAL "cpl") set(TARGET_NAME "${CIME_MODEL}.exe") add_executable(${TARGET_NAME}) - target_sources(${TARGET_NAME} PRIVATE ${SOURCES}) + target_sources(${TARGET_NAME} PRIVATE ${REAL_SOURCES}) set(ALL_LIBS "${ULIBDEP} ${MCTLIBS} ${PIOLIB} ${GPTLLIB} ${SLIBS} ${MLIBS} ${F90_LDFLAGS}") separate_arguments(ALL_LIBS_LIST UNIX_COMMAND "${ALL_LIBS}") foreach(ITEM IN LISTS COMP_CLASSES) @@ -181,7 +181,7 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) else() set(TARGET_NAME ${COMP_CLASS_ARG}) add_library(${TARGET_NAME}) - target_sources(${TARGET_NAME} PRIVATE ${SOURCES}) + target_sources(${TARGET_NAME} PRIVATE ${REAL_SOURCES}) endif() # Subtle: In order for fortran dependency scanning to work, our CPPFPP/DEFS must be registered diff --git a/components/cmake/cmake_util.cmake b/components/cmake/cmake_util.cmake index e2df5da01a9c..2148a0199cdb 100644 --- a/components/cmake/cmake_util.cmake +++ b/components/cmake/cmake_util.cmake @@ -1,10 +1,18 @@ +# Gather all sources for a component +# +# Cmake does not have a VPATH concept, so we need relative/absolute paths to source files +# Note: Using absolute paths seems to wreck CMake's ability to do a dep analysis on fortran +# sources and compile them in the right order. +# +# One additional subtley is that, when mkSrcfiles found multiple files with the same basename, +# only the one found first gets compiled. We need to duplicate that behavior here. function(gather_sources FILEPATH_DIRS_ARG CIMEROOT_ARG) set(BASENAME_SET) set(SOURCES_RESULT) set(GEN_F90_SOURCES_RESULT) foreach(DIRSEARCH ${FILEPATH_DIRS_ARG}) - file(GLOB MATCHES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${DIRSEARCH}/*.[Ffc]" "${DIRSEARCH}/*.[Ff]90" "${DIRSEARCH}/*.cpp" "${DIRSEARCH}/*.F90.in") + file(GLOB MATCHES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/../.." "${DIRSEARCH}/*.[Ffc]" "${DIRSEARCH}/*.[Ff]90" "${DIRSEARCH}/*.cpp" "${DIRSEARCH}/*.F90.in") if (MATCHES) foreach (MATCH IN LISTS MATCHES) get_filename_component(BASENAME ${MATCH} NAME) @@ -33,4 +41,35 @@ function(gather_sources FILEPATH_DIRS_ARG CIMEROOT_ARG) set(SOURCES_RESULT ${SOURCES_RESULT} PARENT_SCOPE) set(GEN_F90_SOURCES_RESULT ${GEN_F90_SOURCES_RESULT} PARENT_SCOPE) -endfunction() \ No newline at end of file +endfunction() + +# Add compile flags for a file. Expects a filepath relative to E3SM/components if it +# is not a generated file. +function(e3sm_add_flags FILE_ARG FLAGS_ARG) + if (FILE_ARG MATCHES "${CMAKE_BINARY_DIR}/.*") # is generated + set(REAL_FILE ${FILE_ARG}) + else() + if (NOT EXISTS ${PROJECT_SOURCE_DIR}/${FILE_ARG}) + message(FATAL_ERROR "Trying to set flags on non-existent source: ${FILE_ARG}") + endif() + set(REAL_FILE "../../${FILE_ARG}") + endif() + set_property(SOURCE ${REAL_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FLAGS_ARG} ") +endfunction() + +# Remove compile flags for a file. Expects a filepath relative to E3SM/components if it +# is not a generated file. +function(e3sm_remove_flags FILE_ARG FLAGS_ARG) + if (FILE_ARG MATCHES "${CMAKE_BINARY_DIR}/.*") # is generated + set(REAL_FILE ${FILE_ARG}) + else() + if (NOT EXISTS ${PROJECT_SOURCE_DIR}/${FILE_ARG}) + message(FATAL_ERROR "Trying to set flags on non-existent source: ${FILE_ARG}") + endif() + set(REAL_FILE "../../${FILE_ARG}") + endif() + + get_property(ITEM_FLAGS SOURCE ${REAL_FILE} PROPERTY COMPILE_FLAGS) + string(REPLACE "${FLAGS_ARG}" "" ITEM_FLAGS "${ITEM_FLAGS}") + set_property(SOURCE ${REAL_FILE} PROPERTY COMPILE_FLAGS "${ITEM_FLAGS}") +endfunction() From 0e731f588f2d85a5eab37579fbe87718d372ba73 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 19 Jul 2019 15:50:03 -0600 Subject: [PATCH 32/48] Fix generation of cmake macros for negated string checks --- cime/scripts/lib/CIME/BuildTools/cmakemacroswriter.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cime/scripts/lib/CIME/BuildTools/cmakemacroswriter.py b/cime/scripts/lib/CIME/BuildTools/cmakemacroswriter.py index 6a42b4ef3826..89668299398b 100644 --- a/cime/scripts/lib/CIME/BuildTools/cmakemacroswriter.py +++ b/cime/scripts/lib/CIME/BuildTools/cmakemacroswriter.py @@ -101,7 +101,12 @@ def start_ifeq(self, left, right): >>> str(s.getvalue()) 'if("foo" STREQUAL "bar")\\n' """ - self.write_line('if("' + left + '" STREQUAL "' + right + '")') + if right.startswith("!"): + right = right.lstrip("!") + not_str = "NOT " + else: + not_str = "" + self.write_line('if({}"'.format(not_str) + left + '" STREQUAL "' + right + '")') self.indent_right() def end_ifeq(self): From 695715f9798ef68906572195e57d7997b82f775a Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 22 Jul 2019 14:24:16 -0700 Subject: [PATCH 33/48] Fix paths to cime files in Depends.intel.cmake --- cime/config/e3sm/machines/Depends.intel.cmake | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cime/config/e3sm/machines/Depends.intel.cmake b/cime/config/e3sm/machines/Depends.intel.cmake index 6a66db02d2a6..62fd1dfd3ba2 100644 --- a/cime/config/e3sm/machines/Depends.intel.cmake +++ b/cime/config/e3sm/machines/Depends.intel.cmake @@ -17,18 +17,18 @@ set(PERFOBJS homme/src/theta/hevi_mod.F90 cam/src/physics/cam/uwshcu.F90) -set(REDUCED_PRECISION_OBJS share/util/shr_wv_sat_mod.F90) +set(REDUCED_PRECISION_OBJS ../cime/src/share/util/shr_wv_sat_mod.F90) set(SHR_RANDNUM_FORT_OBJS - share/RandNum/src/kissvec/kissvec_mod.F90 - share/RandNum/src/mt19937/mersennetwister_mod.F90 - share/RandNum/src/dsfmt_f03/dSFMT_interface.F90 - share/RandNum/src/shr_RandNum_mod.F90) + ../cime/src/share/RandNum/src/kissvec/kissvec_mod.F90 + ../cime/src/share/RandNum/src/mt19937/mersennetwister_mod.F90 + ../cime/src/share/RandNum/src/dsfmt_f03/dSFMT_interface.F90 + ../cime/src/share/RandNum/src/shr_RandNum_mod.F90) set(SHR_RANDNUM_C_OBJS - share/RandNum/src/dsfmt_f03/dSFMT.c - share/RandNum/src/dsfmt_f03/dSFMT_utils.c - share/RandNum/src/kissvec/kissvec.c) + ../cime/src/share/RandNum/src/dsfmt_f03/dSFMT.c + ../cime/src/share/RandNum/src/dsfmt_f03/dSFMT_utils.c + ../cime/src/share/RandNum/src/kissvec/kissvec.c) if (NOT DEBUG) foreach(ITEM IN LISTS PERFOBJS) From 64a7e1954d4c87aec491df5fc7f2c251b10ed4f4 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 22 Jul 2019 14:51:32 -0700 Subject: [PATCH 34/48] Disable compiler checks that happen upon cmake launch Until Macros.cmake is included, we don't even know what compilers will be used. --- cime/scripts/lib/CIME/build.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index dc2a261baa55..7a529affb592 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -46,6 +46,9 @@ def get_standard_cmake_args(case, sharedpath, shared_lib=False): for var in _CMD_ARGS_FOR_BUILD: cmake_args += xml_to_make_variable(case, var, cmake=True) + # Disable compiler checks + cmake_args += " -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER_WORKS=1 -DCMAKE_Fortran_COMPILER_WORKS=1" + return cmake_args def xml_to_make_variable(case, varname, cmake=False): From 33bb5de7fe002ba9da9733cfbbb6be4095b0a929 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 25 Jul 2019 13:08:04 -0600 Subject: [PATCH 35/48] Fix comment --- components/cmake/common_setup.cmake | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/cmake/common_setup.cmake b/components/cmake/common_setup.cmake index 4908086cf69d..90ade4fc2f2e 100644 --- a/components/cmake/common_setup.cmake +++ b/components/cmake/common_setup.cmake @@ -13,9 +13,6 @@ if (INCROOT) set(MINCROOT ${INCROOT}) endif () -# JGF: I think SHAREDLIB paths shoudl come from build.py and not have to -# be recomputed here - if (USE_ESMF_LIB) set(ESMFDIR "esmf") else() From 48fc5ebb8c6c0fa16ec6b7e9357eaca2bfd59c5a Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 25 Jul 2019 16:09:26 -0400 Subject: [PATCH 36/48] Fix summit cxx linking --- cime/config/e3sm/machines/config_compilers.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cime/config/e3sm/machines/config_compilers.xml b/cime/config/e3sm/machines/config_compilers.xml index 637d4ee355b4..2ef6b58708b6 100644 --- a/cime/config/e3sm/machines/config_compilers.xml +++ b/cime/config/e3sm/machines/config_compilers.xml @@ -1868,6 +1868,10 @@ ntel/x86_64/2013/composer_xe_2013/composer_xe_2013_sp1.3.174/mkl/include -L$ENV{NETCDF_C_PATH}/lib -lnetcdf -L$ENV{NETCDF_FORTRAN_PATH}/lib -lnetcdff -L$ENV{ESSL_PATH}/lib64 -lessl -L$ENV{NETLIB_LAPACK_PATH}/lib -llapack -L$ENV{PNETCDF_PATH}/lib -lpnetcdf -L$ENV{HDF5_PATH}/lib -lhdf5_hl -lhdf5 + FORTRAN + + -lstdc++ + -DFORTRANUNDERSCORE -DNO_R16 -DCPRCRAY - -DDIR=NOOP + -DDIR=NOOP -s real64 @@ -113,10 +113,10 @@ for mct, etc. -fopenmp -g -Wall -Og -fbacktrace -fcheck=bounds -ffpe-trap=invalid,zero,overflow -O - -std=c99 + -std=c99 - -D CISM_GNU=ON + -D CISM_GNU=ON @@ -164,7 +164,7 @@ for mct, etc. -O - -D CISM_GNU=ON + -D CISM_GNU=ON @@ -424,12 +424,12 @@ for mct, etc. -mp -O0 -g -Ktrap=fp -Mbounds -Kieee - -Mnovect - -Mnovect - -Mnovect - -Mnovect - -Mnovect - -Mnovect + -Mnovect + -Mnovect + -Mnovect + -Mnovect + -Mnovect + -Mnovect -O0 @@ -500,14 +500,14 @@ for mct, etc. -i4 -time -Mstack_arrays -Mextend -byteswapio -Mflushz -Kieee -mp - + -O0 -g -Ktrap=fp -Mbounds -Kieee - -Mnovect - -Mnovect - -Mnovect - -Mnovect - -Mnovect - -Mnovect + -Mnovect + -Mnovect + -Mnovect + -Mnovect + -Mnovect + -Mnovect -O0 @@ -544,7 +544,7 @@ for mct, etc. /usr/bin/bash -qarch=auto -qtune=auto -qcache=auto -qsclk=micro - -qspill=6000 + -qspill=6000 -qsigtrap=xl__trcedump @@ -638,7 +638,7 @@ for mct, etc. -DLINUX - -DHAVE_NANOTIME -DBIT64 -DHAVE_VPRINTF -DHAVE_BACKTRACE -DHAVE_SLASHPROC -DHAVE_COMM_F2C -DHAVE_TIMES -DHAVE_GETTIMEOFDAY + -DHAVE_NANOTIME -DBIT64 -DHAVE_VPRINTF -DHAVE_BACKTRACE -DHAVE_SLASHPROC -DHAVE_COMM_F2C -DHAVE_TIMES -DHAVE_GETTIMEOFDAY cc CC @@ -658,7 +658,7 @@ for mct, etc. -DSYSDARWIN - -all_load + -all_load @@ -706,7 +706,7 @@ for mct, etc. - -DHAVE_NANOTIME -DBIT64 -DHAVE_SLASHPROC -DHAVE_GETTIMEOFDAY + -DHAVE_NANOTIME -DBIT64 -DHAVE_SLASHPROC -DHAVE_GETTIMEOFDAY gpfs @@ -724,7 +724,7 @@ for mct, etc. -heap-arrays - -DHAVE_SLASHPROC + -DHAVE_SLASHPROC -O2 -debug minimal -qno-opt-dynamic-align @@ -760,7 +760,7 @@ for mct, etc. /soft/climate/AlbanyTrilinos_06262017/Albany/buildintel/install - -DHAVE_SLASHPROC + -DHAVE_SLASHPROC -lstdc++ @@ -782,7 +782,7 @@ for mct, etc. /soft/climate/AlbanyTrilinos_06262017/Albany/build/install - -DHAVE_NANOTIME -DBIT64 -DHAVE_SLASHPROC -DHAVE_GETTIMEOFDAY + -DHAVE_NANOTIME -DBIT64 -DHAVE_SLASHPROC -DHAVE_GETTIMEOFDAY -lstdc++ @@ -867,12 +867,12 @@ for mct, etc. -fopenmp - -D CISM_GNU=ON + -D CISM_GNU=ON -DFORTRANUNDERSCORE -DNO_R16 - + FORTRAN @@ -884,7 +884,7 @@ for mct, etc. -O -fconvert=big-endian -ffree-line-length-none -ffixed-line-length-none -fno-range-check -fopenmp -g -Wall - + -ffixed-form @@ -898,8 +898,8 @@ for mct, etc. /software/tools/compilers/intel_2017/mkl/lib/intel64 -fopenmp - -L$NETCDF_PATH/lib -Wl,-rpath=$NETCDF_PATH/lib -lnetcdff -lnetcdf - + -L$NETCDF_PATH/lib -Wl,-rpath=$NETCDF_PATH/lib -lnetcdff -lnetcdf + mpicc mpic++ @@ -941,7 +941,7 @@ for mct, etc. "-nan" is an important flag. currently, it doesn't work for pio, it is only used for "cam" model. --> -C=all -g -O0 -v - -C=all -g -nan -O0 -v + -C=all -g -nan -O0 -v @@ -1220,7 +1220,7 @@ for mct, etc. - -DHAVE_VPRINTF -DHAVE_GETTIMEOFDAY -DHAVE_BACKTRACE + -DHAVE_VPRINTF -DHAVE_GETTIMEOFDAY -DHAVE_BACKTRACE $ENV{NETCDF_HOME} @@ -1302,7 +1302,7 @@ for mct, etc. --host=Linux - -DHAVE_PAPI + -DHAVE_PAPI -O2 @@ -1387,7 +1387,7 @@ for mct, etc. - -DHAVE_VPRINTF -DHAVE_GETTIMEOFDAY + -DHAVE_VPRINTF -DHAVE_GETTIMEOFDAY /global/software/sl-6.x86_64/modules/intel/2016.1.150/lapack/3.6.0-intel/lib $ENV{NETCDF_DIR} @@ -1398,7 +1398,7 @@ for mct, etc. - -DHAVE_VPRINTF -DHAVE_GETTIMEOFDAY + -DHAVE_VPRINTF -DHAVE_GETTIMEOFDAY /global/software/sl-6.x86_64/modules/intel/2016.1.150/lapack/3.6.0-intel/lib $ENV{NETCDF_DIR} @@ -1409,7 +1409,7 @@ for mct, etc. - -DHAVE_VPRINTF -DHAVE_GETTIMEOFDAY + -DHAVE_VPRINTF -DHAVE_GETTIMEOFDAY /global/software/sl-6.x86_64/modules/intel/2016.1.150/lapack/3.6.0-intel/lib $ENV{NETCDF_DIR} @@ -1542,7 +1542,7 @@ for mct, etc. -mkl -lstdc++ -qopenmp - -L$(NETCDF_FORTRAN_PATH)/lib64 + -L$(NETCDF_FORTRAN_PATH)/lib64 -fixed -132 @@ -1771,7 +1771,7 @@ ntel/x86_64/2013/composer_xe_2013/composer_xe_2013_sp1.3.174/mkl/include -DLINUX - -DHAVE_NANOTIME -DBIT64 -DHAVE_VPRINTF -DHAVE_BACKTRACE -DHAVE_SLASHPROC -DHAVE_COMM_F2C -DHAVE_TIMES -DHAVE_GETTIMEOFDAY + -DHAVE_NANOTIME -DBIT64 -DHAVE_VPRINTF -DHAVE_BACKTRACE -DHAVE_SLASHPROC -DHAVE_COMM_F2C -DHAVE_TIMES -DHAVE_GETTIMEOFDAY -DARCH_MIC_KNL @@ -2145,7 +2145,7 @@ ntel/x86_64/2013/composer_xe_2013/composer_xe_2013_sp1.3.174/mkl/include -O2 - -target-cpu=istanbul + -target-cpu=istanbul $SHELL{nf-config --flibs} diff --git a/cime/config/xml_schemas/config_compilers_v2.xsd b/cime/config/xml_schemas/config_compilers_v2.xsd index c1b289303cd9..6ac431de7d5c 100644 --- a/cime/config/xml_schemas/config_compilers_v2.xsd +++ b/cime/config/xml_schemas/config_compilers_v2.xsd @@ -11,6 +11,8 @@ + + @@ -53,6 +55,8 @@ + + diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index 7a529affb592..953e37832332 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -15,7 +15,7 @@ "MACH", "MPILIB", "NINST_VALUE", "OS", "PIO_VERSION", "SHAREDLIBROOT", "SMP_PRESENT", "USE_ESMF_LIB", "USE_MOAB", "CAM_CONFIG_OPTS", "COMPARE_TO_NUOPC", "HOMME_TARGET", - "OCN_SUBMODEL", "CISM_USE_TRILINOS", "USE_ALBANY", "USE_PETSC") + "OCN_SUBMODEL", "CISM_USE_TRILINOS", "USE_TRILINOS", "USE_ALBANY", "USE_PETSC") def get_standard_makefile_args(case, shared_lib=False): make_args = "CIME_MODEL={} ".format(case.get_value("MODEL")) @@ -392,8 +392,8 @@ def _build_model_thread(config_dir, compclass, compname, caseroot, libroot, bldr expect(os.path.isfile(cmd), "Could not find buildlib for {}".format(compname)) with open(file_build, "w") as fd: - stat = run_cmd("MODEL={} SMP={} {} {} {} {} " - .format(compclass, stringify_bool(smp), cmd, caseroot, libroot, bldroot), + stat = run_cmd("MODEL={} COMP_CLASS={} COMP_NAME={} SMP={} {} {} {} {} " + .format(compclass, compclass, compname, stringify_bool(smp), cmd, caseroot, libroot, bldroot), from_dir=bldroot, arg_stdout=fd, arg_stderr=subprocess.STDOUT)[0] @@ -411,6 +411,10 @@ def _build_model_thread(config_dir, compclass, compname, caseroot, libroot, bldr ############################################################################### def _create_build_metadata_for_component(config_dir, libroot, bldroot, case): ############################################################################### + """ + Ensure that crucial Filepath and CCSM_CPPDEFS files exist for this component. + In many cases, the bld/configure script will have already created these. + """ buildlib = imp.load_source("buildlib_cmake", os.path.join(config_dir, "buildlib_cmake")) buildlib.buildlib(bldroot, libroot, case) diff --git a/cime/scripts/lib/CIME/buildlib.py b/cime/scripts/lib/CIME/buildlib.py index 4b3db414ddf1..f5f54c3a835b 100644 --- a/cime/scripts/lib/CIME/buildlib.py +++ b/cime/scripts/lib/CIME/buildlib.py @@ -45,7 +45,7 @@ def build_cime_component_lib(case, compname, libroot, bldroot, use_old=True): cimeroot = case.get_value("CIMEROOT") casebuild = case.get_value("CASEBUILD") - compclass = compname[1:] + compclass = compname[1:] # This very hacky comp_interface = case.get_value("COMP_INTERFACE") confdir = os.path.join(casebuild, "{}conf".format(compname)) @@ -75,10 +75,10 @@ def build_cime_component_lib(case, compname, libroot, bldroot, use_old=True): safe_copy(os.path.join(confdir, "Filepath"), bldroot) safe_copy(os.path.join(confdir, "CCSM_cppdefs"), bldroot) - run_gmake(case, compclass, libroot, bldroot) + run_gmake(case, compclass, compname, libroot, bldroot) ############################################################################### -def run_gmake(case, compclass, libroot, bldroot, libname="", user_cppdefs=""): +def run_gmake(case, compclass, compname, libroot, bldroot, libname="", user_cppdefs=""): ############################################################################### gmake_args = get_standard_makefile_args(case) @@ -93,8 +93,8 @@ def run_gmake(case, compclass, libroot, bldroot, libname="", user_cppdefs=""): makefile = os.path.join(case.get_value("CASETOOLS"), "Makefile") - cmd = "{} complib -j {:d} MODEL={} COMPLIB={} {} -f {} -C {} " \ - .format(gmake, gmake_j, compclass, complib, gmake_args, makefile, bldroot) + cmd = "{} complib -j {:d} MODEL={} COMP_CLASS={} COMP_NAME={} COMPLIB={} {} -f {} -C {} " \ + .format(gmake, gmake_j, compclass, compclass, compname, complib, gmake_args, makefile, bldroot) if user_cppdefs: cmd = cmd + "USER_CPPDEFS='{}'".format(user_cppdefs ) diff --git a/cime/src/build_scripts/buildlib.csm_share b/cime/src/build_scripts/buildlib.csm_share index e45dbad9a97e..e6fd4a23d1b2 100755 --- a/cime/src/build_scripts/buildlib.csm_share +++ b/cime/src/build_scripts/buildlib.csm_share @@ -111,7 +111,7 @@ def buildlib(bldroot, installpath, case): copyifnewer(_file, os.path.join(installdir, "include", os.path.basename(_file))) # This runs the make command - gmake_opts = "-f {}/Makefile complib MODEL=csm_share ".format(os.path.join(caseroot,"Tools")) + gmake_opts = "-f {}/Makefile complib MODEL=csm_share COMP_NAME=csm_share ".format(os.path.join(caseroot,"Tools")) gmake_opts += "-j {} ".format(case.get_value("GMAKE_J")) gmake_opts += " COMPLIB=libcsm_share.a" gmake_opts += ' USER_CPPDEFS="{} -DTIMING" '.format(multiinst_cppdefs) diff --git a/cime/src/build_scripts/buildlib.gptl b/cime/src/build_scripts/buildlib.gptl index 21bf035e5c49..932eeadf9ae4 100755 --- a/cime/src/build_scripts/buildlib.gptl +++ b/cime/src/build_scripts/buildlib.gptl @@ -44,7 +44,7 @@ def buildlib(bldroot, installpath, case): ############################################################################### caseroot = case.get_value("CASEROOT") gptl_dir = os.path.join(case.get_value("CIMEROOT"), "src", "share", "timing") - gmake_opts = "-f {gptl}/Makefile install -C {bldroot} MACFILE={macfile} MODEL=gptl GPTL_DIR={gptl} GPTL_LIBDIR={bldroot}"\ + gmake_opts = "-f {gptl}/Makefile install -C {bldroot} MACFILE={macfile} MODEL=gptl COMP_NAME=gptl GPTL_DIR={gptl} GPTL_LIBDIR={bldroot}"\ " SHAREDPATH={install} {stdargs} "\ .format(gptl=gptl_dir, bldroot=bldroot, macfile=os.path.join(caseroot,"Macros.make"), install=installpath, stdargs=get_standard_makefile_args(case, shared_lib=True)) diff --git a/cime/src/build_scripts/buildlib.mct b/cime/src/build_scripts/buildlib.mct index ba1cd34b4a53..558a9ec01e68 100755 --- a/cime/src/build_scripts/buildlib.mct +++ b/cime/src/build_scripts/buildlib.mct @@ -55,7 +55,7 @@ def buildlib(bldroot, installpath, case): gmake_opts = "-f {} ".format(os.path.join(caseroot,"Tools","Makefile")) gmake_opts += " -C {} ".format(bldroot) gmake_opts += get_standard_makefile_args(case, shared_lib=True) - gmake_opts += "MODEL=mct {}".format(os.path.join(bldroot,"Makefile.conf")) + gmake_opts += "MODEL=mct COMP_NAME=mct {}".format(os.path.join(bldroot,"Makefile.conf")) gmake_cmd = case.get_value("GMAKE") diff --git a/cime/src/build_scripts/buildlib.mpi-serial b/cime/src/build_scripts/buildlib.mpi-serial index 7b3214e8f6c3..0ec22c38df14 100755 --- a/cime/src/build_scripts/buildlib.mpi-serial +++ b/cime/src/build_scripts/buildlib.mpi-serial @@ -52,7 +52,7 @@ def buildlib(bldroot, installpath, case): gmake_opts = "-f {} ".format(os.path.join(caseroot,"Tools","Makefile")) gmake_opts += " -C {} ".format(bldroot) gmake_opts += " {} ".format(get_standard_makefile_args(case, shared_lib=True)) - gmake_opts += "MODEL=mpi-serial {}".format(os.path.join(bldroot,"Makefile.conf")) + gmake_opts += "MODEL=mpi-serial COMP_NAME=mpi-serial {}".format(os.path.join(bldroot,"Makefile.conf")) gmake_cmd = case.get_value("GMAKE") diff --git a/cime/src/build_scripts/buildlib.pio b/cime/src/build_scripts/buildlib.pio index bab9a9f71c62..d088a197eba4 100755 --- a/cime/src/build_scripts/buildlib.pio +++ b/cime/src/build_scripts/buildlib.pio @@ -68,7 +68,7 @@ def buildlib(bldroot, installpath, case): cmake_opts = "\"-D GENF90_PATH=$CIMEROOT/src/externals/genf90 \"" stdargs = get_standard_makefile_args(case, shared_lib=True) - gmake_opts = "{pio_dir}/Makefile -C {pio_dir} CASEROOT={caseroot} MODEL={pio_model} USER_CMAKE_OPTS={cmake_opts} "\ + gmake_opts = "{pio_dir}/Makefile -C {pio_dir} CASEROOT={caseroot} MODEL={pio_model} COMP_NAME={pio_model} USER_CMAKE_OPTS={cmake_opts} "\ "PIO_LIBDIR={pio_dir} CASETOOLS={casetools} "\ " USER_CPPDEFS=-DTIMING {stdargs} -f {casetools}/Makefile"\ .format(pio_dir=pio_dir, caseroot=caseroot, pio_model=pio_model, cmake_opts=cmake_opts, diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0428855cf7aa..d6cd9c29c557 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -18,16 +18,24 @@ cmake_policy(SET CMP0057 NEW) project(E3SM C CXX Fortran) +# Include function definitions include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_util.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_mpas_model.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_model.cmake) set(BUILDCONF ${CASEROOT}/Buildconf) # Do any MPAS builds first since they manage their own flags build_mpas_models() -include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/common_setup.cmake) -include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_model.cmake) +# Set global cmake settings +set(CMAKE_MODULE_PATH ${CIMEROOT}/src/CMake) +set(CMAKE_VERBOSE_MAKEFILE TRUE) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/..) + +# Set global targets +add_custom_target(genf90 + DEPENDS ${CIMEROOT}/src/externals/genf90/genf90.pl) # Build E3SM components set(IDX 0) diff --git a/components/clm/cime_config/buildlib b/components/clm/cime_config/buildlib index da79a3603c73..4cbe6dae8326 100755 --- a/components/clm/cime_config/buildlib +++ b/components/clm/cime_config/buildlib @@ -13,7 +13,7 @@ _LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") sys.path.append(_LIBDIR) from standard_script_setup import * -from CIME.buildlib import parse_input, run_gmake +from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import run_cmd, expect from CIME.build import get_standard_makefile_args diff --git a/components/cmake/build_model.cmake b/components/cmake/build_model.cmake index 101b9644536b..14a15d3d28b7 100644 --- a/components/cmake/build_model.cmake +++ b/components/cmake/build_model.cmake @@ -1,5 +1,10 @@ -function(build_model COMP_CLASS_ARG MODEL_ARG) - set(MODELCONF_DIR "${BUILDCONF}/${MODEL_ARG}conf") +function(build_model COMP_CLASS COMP_NAME) + + # We support component-specific configuration of flags, etc, so this setup + # need to be done here. + include(${CMAKE_SOURCE_DIR}/cmake/common_setup.cmake) + + set(MODELCONF_DIR "${BUILDCONF}/${COMP_NAME}conf") # Load dependency search path. file(STRINGS ${MODELCONF_DIR}/Filepath FILEPATH_DIRS) @@ -14,7 +19,7 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) set(CPPDEFS "${CPPDEFS} ${CCSM_CPPDEFS}") endif() - if (MODEL_ARG STREQUAL "cpl") + if (COMP_NAME STREQUAL "cpl") list(APPEND INCLDIR "${EXEROOT}/cmake-bld/mpas-source/src") foreach(ITEM IN LISTS COMP_CLASSES) list(APPEND INCLDIR "${EXEROOT}/cmake-bld/cmake/${ITEM}") @@ -39,7 +44,7 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) # Cam needs some special handling for cosp and turning off opts for some files #------------------------------------------------------------------------------- - if (MODEL_ARG STREQUAL "cam") + if (COMP_NAME STREQUAL "cam") # These RRTMG files take an extraordinarily long time to compile with optimization. # Until mods are made to read the data from files, just remove optimization from # their compilation. @@ -79,7 +84,7 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) set(LNDOBJDIR "${SHAREDLIBROOT}/${SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/clm/obj") set(LNDLIBDIR "${EXEROOT}/${SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/lib") list(APPEND INCLDIR "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/include") - if (MODEL_ARG STREQUAL "clm") + if (COMP_NAME STREQUAL "clm") set(INCLUDE_DIR "${INSTALL_SHAREDPATH}/${COMP_INTERFACE}/${ESMFDIR}/include") endif() endif() @@ -163,7 +168,7 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) endif() endforeach() - if (MODEL_ARG STREQUAL "cpl") + if (COMP_NAME STREQUAL "cpl") set(TARGET_NAME "${CIME_MODEL}.exe") add_executable(${TARGET_NAME}) target_sources(${TARGET_NAME} PRIVATE ${REAL_SOURCES}) @@ -179,7 +184,7 @@ function(build_model COMP_CLASS_ARG MODEL_ARG) endforeach() set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE ${LD}) else() - set(TARGET_NAME ${COMP_CLASS_ARG}) + set(TARGET_NAME ${COMP_CLASS}) add_library(${TARGET_NAME}) target_sources(${TARGET_NAME} PRIVATE ${REAL_SOURCES}) endif() diff --git a/components/cmake/build_mpas_model.cmake b/components/cmake/build_mpas_model.cmake index eccde092fc50..ddda8db4ab4b 100644 --- a/components/cmake/build_mpas_model.cmake +++ b/components/cmake/build_mpas_model.cmake @@ -3,25 +3,25 @@ function(build_mpas_models) file(GLOB MPASCONFS "${BUILDCONF}/mpas*conf" "${BUILDCONF}/maliconf") foreach(ITEM IN LISTS MPASCONFS) get_filename_component(MPASCONF ${ITEM} NAME) - string(REPLACE "conf" "" MODEL "${MPASCONF}") + string(REPLACE "conf" "" COMP_NAME "${MPASCONF}") - if (MODEL STREQUAL "mpaso") + if (COMP_NAME STREQUAL "mpaso") list(APPEND CORES "ocean") set(COMP_CLASS "ocn") - elseif (MODEL STREQUAL "mpassi") + elseif (COMP_NAME STREQUAL "mpassi") list(APPEND CORES "seaice") set(COMP_CLASS "ice") - elseif (MODEL STREQUAL "mali") + elseif (COMP_NAME STREQUAL "mali") list(APPEND CORES "landice") set(COMP_CLASS "glc") if (USE_ALBANY) set(ALBANY True) endif() else() - message(FATAL_ERROR "Unrecognized MPAS model ${MODEL_ARG}") + message(FATAL_ERROR "Unrecognized MPAS model ${COMP_NAME}") endif() - message("Found MPAS component ${COMP_CLASS} model '${MODEL}'") + message("Found MPAS component ${COMP_CLASS} model '${COMP_NAME}'") endforeach() if (CORES) diff --git a/components/cmake/common_setup.cmake b/components/cmake/common_setup.cmake index 28ee7d89800d..79632857d622 100644 --- a/components/cmake/common_setup.cmake +++ b/components/cmake/common_setup.cmake @@ -1,10 +1,6 @@ -# This file contains configuration that is independent of the library being -# built. - -# Set global cmake settings -set(CMAKE_MODULE_PATH ${CIMEROOT}/src/CMake) -set(CMAKE_VERBOSE_MAKEFILE TRUE) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/..) +# This file is intended to be included by build_model function. Any changes +# to CMAKE variables intended to impact the CMakeLists.txt file that called +# build_model must use PARENT_SCOPE. # Add INCROOT to path for Depends and Include set(MINCROOT "") @@ -185,7 +181,7 @@ if (USE_TRILINOS) message(FATAL_ERROR "TRILINOS_PATH must be defined when USE_TRILINOS is TRUE") endif() - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${TRILINOS_PATH}) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${TRILINOS_PATH} PARENT_SCOPE) find_package(Trilinos) endif() @@ -446,21 +442,18 @@ set(MCTLIBS "${MCT_LIBDIR}/libmct.a ${MCT_LIBDIR}/libmpeu.a") set(GPTLLIB "${GPTL_LIBDIR}/libgptl.a") -add_custom_target(genf90 - DEPENDS ${CIMEROOT}/src/externals/genf90/genf90.pl) - #------------------------------------------------------------------------------ # Set key cmake vars #------------------------------------------------------------------------------ -set(CMAKE_C_COMPILER ${CC}) -set(CMAKE_CXX_COMPILER ${CXX}) -set(CMAKE_Fortran_COMPILER ${FC}) +set(CMAKE_C_COMPILER ${CC} PARENT_SCOPE) +set(CMAKE_CXX_COMPILER ${CXX} PARENT_SCOPE) +set(CMAKE_Fortran_COMPILER ${FC} PARENT_SCOPE) -set(CMAKE_Fortran_FLAGS "${FFLAGS}") -set(CMAKE_C_FLAGS "${CFLAGS}") -set(CMAKE_CXX_FLAGS "${CXXFLAGS}") +set(CMAKE_Fortran_FLAGS "${FFLAGS}" PARENT_SCOPE) +set(CMAKE_C_FLAGS "${CFLAGS}" PARENT_SCOPE) +set(CMAKE_CXX_FLAGS "${CXXFLAGS}" PARENT_SCOPE) if (LD STREQUAL "Fortran") - set(CMAKE_EXE_LINKER_FLAGS "${F90_LDFLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${F90_LDFLAGS}" PARENT_SCOPE) else() - set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}" PARENT_SCOPE) endif() From b73cd365900c55f6fbad6ebc07e00fc808d6559a Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 31 Oct 2019 15:01:32 -0600 Subject: [PATCH 39/48] MPAS' mandatory use of PIO2 should be caputured in make cmake files, not config_compilers.xml --- cime/config/e3sm/machines/config_compilers.xml | 12 +++--------- components/cmake/build_mpas_model.cmake | 1 + 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/cime/config/e3sm/machines/config_compilers.xml b/cime/config/e3sm/machines/config_compilers.xml index 91effceb21c3..2f604b5a9fe9 100644 --- a/cime/config/e3sm/machines/config_compilers.xml +++ b/cime/config/e3sm/machines/config_compilers.xml @@ -78,12 +78,6 @@ for mct, etc. compilers --> FALSE - - - -DUSE_PIO2 - -DUSE_PIO2 - -DUSE_PIO2 - @@ -787,7 +781,7 @@ for mct, etc. - -DHAVE_SLASHPROC + -DHAVE_SLASHPROC -lstdc++ @@ -1074,7 +1068,7 @@ for mct, etc. -O2 - -DHAVE_SLASHPROC + -DHAVE_SLASHPROC --host=Linux @@ -1100,7 +1094,7 @@ for mct, etc. -O2 - -DHAVE_SLASHPROC + -DHAVE_SLASHPROC -lstdc++ diff --git a/components/cmake/build_mpas_model.cmake b/components/cmake/build_mpas_model.cmake index ddda8db4ab4b..928f0e92a154 100644 --- a/components/cmake/build_mpas_model.cmake +++ b/components/cmake/build_mpas_model.cmake @@ -1,6 +1,7 @@ function(build_mpas_models) file(GLOB MPASCONFS "${BUILDCONF}/mpas*conf" "${BUILDCONF}/maliconf") + foreach(ITEM IN LISTS MPASCONFS) get_filename_component(MPASCONF ${ITEM} NAME) string(REPLACE "conf" "" COMP_NAME "${MPASCONF}") From 696e375f72ad5f91625bd127cd2d0ae7854bbc6c Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 31 Oct 2019 15:04:32 -0600 Subject: [PATCH 40/48] Add comment pertaining to MPAS --- cime/config/e3sm/machines/config_compilers.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cime/config/e3sm/machines/config_compilers.xml b/cime/config/e3sm/machines/config_compilers.xml index 2f604b5a9fe9..de54722f76a8 100644 --- a/cime/config/e3sm/machines/config_compilers.xml +++ b/cime/config/e3sm/machines/config_compilers.xml @@ -71,6 +71,12 @@ These should NOT be specified via or , because those mess up the configure step for mct, etc. +======================================================================== + MPAS +======================================================================== + +MPAS has a semi-autonomous build from core E3SM. Component-specific (mali, mpassi) +flags should be captured within MPAS CMake files. =========================== --> From ceb4a34d6ad1b89eb092c83c9ade4847268c515e Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 1 Nov 2019 12:23:55 -0600 Subject: [PATCH 41/48] Make ninja the default backend --- cime/scripts/Tools/case.build | 13 +++++----- .../CIME/SystemTests/system_tests_common.py | 8 +++--- cime/scripts/lib/CIME/build.py | 23 ++++++++++-------- externals/ninja/bin.darwin/ninja | Bin 0 -> 206588 bytes externals/ninja/bin/ninja | Bin 0 -> 204440 bytes 5 files changed, 24 insertions(+), 20 deletions(-) create mode 100755 externals/ninja/bin.darwin/ninja create mode 100755 externals/ninja/bin/ninja diff --git a/cime/scripts/Tools/case.build b/cime/scripts/Tools/case.build index 4b17dd804d61..b446d74743b5 100755 --- a/cime/scripts/Tools/case.build +++ b/cime/scripts/Tools/case.build @@ -66,8 +66,9 @@ def parse_command_line(args, description): parser.add_argument("--use-old", action="store_true", help="Use old Makefile build system (not cmake)") - parser.add_argument("--ninja", action="store_true", - help="Use ninja backed for CMake (instead of make)") + parser.add_argument("--use-gmake", action="store_true", + help="Use gmake backed for CMake (instead of ninja). " + "The gmake backend does not always correctly scan fortran dependencies") mutex_group = parser.add_mutually_exclusive_group() @@ -113,12 +114,12 @@ def parse_command_line(args, description): cleanlist = args.clean if args.clean is None or len(args.clean) else comps buildlist = None if args.build is None or len(args.build) == 0 else args.build - return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old, args.ninja + return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old, args.use_gmake ############################################################################### def _main_func(description): ############################################################################### - caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance, use_old, ninja = \ + caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance, use_old, use_gmake = \ parse_command_line(sys.argv, description) success = True @@ -143,12 +144,12 @@ def _main_func(description): raise expect(buildlist is None, "Build lists don't work with tests") - success = test.build(sharedlib_only=sharedlib_only, model_only=model_only, old_build=use_old, ninja=ninja) + success = test.build(sharedlib_only=sharedlib_only, model_only=model_only, old_build=use_old, use_gmake=use_gmake) else: success = build.case_build(caseroot, case=case, sharedlib_only=sharedlib_only, model_only=model_only, buildlist=buildlist, save_build_provenance=save_build_provenance, - use_old=use_old, ninja=ninja) + use_old=use_old, use_gmake=use_gmake) sys.exit(0 if success else 1) diff --git a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py index 5ca49218c490..f21df6656d53 100644 --- a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py +++ b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py @@ -34,7 +34,7 @@ def __init__(self, case, expected=None): self._skip_pnl = False self._cpllog = "med" if self._case.get_value("COMP_INTERFACE")=="nuopc" else "cpl" self._old_build = False - self._ninja = False + self._use_gmake = False def _init_environment(self, caseroot): """ @@ -68,7 +68,7 @@ def _resetup_case(self, phase, reset=False): self._case.case_setup(reset=True, test_mode=True) - def build(self, sharedlib_only=False, model_only=False, old_build=False, ninja=False): + def build(self, sharedlib_only=False, model_only=False, old_build=False, use_gmake=False): """ Do NOT override this method, this method is the framework that controls the build phase. build_phase is the extension point @@ -76,7 +76,7 @@ def build(self, sharedlib_only=False, model_only=False, old_build=False, ninja=F """ success = True self._old_build = old_build - self._ninja = ninja + self._use_gmake = use_gmake for phase_name, phase_bool in [(SHAREDLIB_BUILD_PHASE, not model_only), (MODEL_BUILD_PHASE, not sharedlib_only)]: if phase_bool: @@ -124,7 +124,7 @@ def build_indv(self, sharedlib_only=False, model_only=False): model = self._case.get_value('MODEL') build.case_build(self._caseroot, case=self._case, sharedlib_only=sharedlib_only, model_only=model_only, - save_build_provenance=not model=='cesm', use_old=self._old_build, ninja=self._ninja) + save_build_provenance=not model=='cesm', use_old=self._old_build, use_gmake=self._use_gmake) def clean_build(self, comps=None): if comps is None: diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index 953e37832332..7ebf8dd3effb 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -154,7 +154,7 @@ def _build_model(build_threaded, exeroot, incroot, complist, ############################################################################### def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, - comp_interface, sharedpath, ninja, case): + comp_interface, sharedpath, use_gmake, case): ############################################################################### cime_model = get_model() bldroot = os.path.join(exeroot, "cmake-bld") @@ -181,18 +181,22 @@ def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, # Call CMake cmake_args = get_standard_cmake_args(case, sharedpath) - if ninja: + cmake_env = "" + ninja_path = os.path.join(srcroot, "externals/ninja/bin") + if not use_gmake: cmake_args += " -GNinja " - cmake_cmd = "cmake {} {}/components >> {} 2>&1".format(cmake_args, srcroot, bldlog) + cmake_env += "PATH={}:$PATH ".format(ninja_path) + + cmake_cmd = "{}cmake {} {}/components >> {} 2>&1".format(cmake_env, cmake_args, srcroot, bldlog) with open(bldlog, "w") as fd: fd.write("Configuring with cmake cmd:\n{}\n\n".format(cmake_cmd)) stat = run_cmd(cmake_cmd, from_dir=bldroot)[0] # Call Make if stat == 0: - make_cmd = "{} -j {} >> {} 2>&1".format("ninja" if ninja else gmake, gmake_j, bldlog) + make_cmd = "{} -j {} >> {} 2>&1".format(gmake if use_gmake else os.path.join(ninja_path, "ninja"), gmake_j, bldlog) with open(bldlog, "a") as fd: - fd.write("\n\nBuilding with make cmd:\n{}\n\n".format(make_cmd)) + fd.write("\n\nBuilding with cmd:\n{}\n\n".format(make_cmd)) stat = run_cmd(make_cmd, from_dir=bldroot)[0] @@ -465,7 +469,7 @@ def _clean_impl(case, cleanlist, clean_all, clean_depends): ############################################################################### def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance, use_old, ninja): + save_build_provenance, use_old, use_gmake): ############################################################################### t1 = time.time() @@ -476,7 +480,6 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, logger.info("sharedlib_only is {}".format(sharedlib_only)) logger.info("model_only is {}".format(model_only)) - expect(not (use_old and ninja), "Ninja backend not supported for classic build system") expect(os.path.isdir(caseroot), "'{}' is not a valid directory".format(caseroot)) os.chdir(caseroot) @@ -589,7 +592,7 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, if not sharedlib_only: if get_model() == "e3sm" and not use_old: logs.extend(_build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, - comp_interface, sharedpath, ninja, case)) + comp_interface, sharedpath, use_gmake, case)) else: os.environ["INSTALL_SHAREDPATH"] = os.path.join(exeroot, sharedpath) # for MPAS makefile generators logs.extend(_build_model(build_threaded, exeroot, incroot, complist, @@ -634,10 +637,10 @@ def post_build(case, logs, build_complete=False, save_build_provenance=True): lock_file("env_build.xml", caseroot=case.get_value("CASEROOT")) ############################################################################### -def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True, use_old=False, ninja=False): +def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True, use_old=False, use_gmake=False): ############################################################################### functor = lambda: _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance, use_old, ninja) + save_build_provenance, use_old, use_gmake) return run_and_log_case_status(functor, "case.build", caseroot=caseroot) ############################################################################### diff --git a/externals/ninja/bin.darwin/ninja b/externals/ninja/bin.darwin/ninja new file mode 100755 index 0000000000000000000000000000000000000000..9e6d5efece00707cbeae901f31e1eb59bc6294d3 GIT binary patch literal 206588 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 z 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®e=-*xC4h)?0 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 aO7(VE@H9I8qH literal 0 HcmV?d00001 diff --git a/externals/ninja/bin/ninja b/externals/ninja/bin/ninja new file mode 100755 index 0000000000000000000000000000000000000000..fea92caafbdcdac4649f5c68d21b767a2f021c9c GIT binary patch literal 204440 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

>W2s^SJ1vzNb^@lJYMILi@k4m@Ld@G@q_jq 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 Date: Fri, 1 Nov 2019 13:29:57 -0600 Subject: [PATCH 42/48] Make sure ninja builds are verbose --- cime/scripts/lib/CIME/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index 7ebf8dd3effb..b6d9269e06be 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -194,7 +194,7 @@ def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, # Call Make if stat == 0: - make_cmd = "{} -j {} >> {} 2>&1".format(gmake if use_gmake else os.path.join(ninja_path, "ninja"), gmake_j, bldlog) + make_cmd = "{} -j {} >> {} 2>&1".format(gmake if use_gmake else "{} -v".format(os.path.join(ninja_path, "ninja")), gmake_j, bldlog) with open(bldlog, "a") as fd: fd.write("\n\nBuilding with cmd:\n{}\n\n".format(make_cmd)) From 35935f9b541a9c7e2d6534dcee306579231c822a Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 4 Nov 2019 09:45:53 -0800 Subject: [PATCH 43/48] Fixes for cori --- cime/config/e3sm/machines/Depends.intel.cmake | 21 +++++++------------ components/cmake/build_model.cmake | 7 ++++++- components/cmake/cmake_util.cmake | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cime/config/e3sm/machines/Depends.intel.cmake b/cime/config/e3sm/machines/Depends.intel.cmake index 62fd1dfd3ba2..ff1f572f50bc 100644 --- a/cime/config/e3sm/machines/Depends.intel.cmake +++ b/cime/config/e3sm/machines/Depends.intel.cmake @@ -5,30 +5,25 @@ set(PERFOBJS homme/src/share/derivative_mod_base.F90 homme/src/share/bndry_mod_base.F90 homme/src/theta-l/prim_advance_mod.F90 - homme/src/pese/prim_advance_mod.F90 - homme/src/theta/prim_advance_mod.F90 homme/src/preqx/share/prim_advance_mod.F90 homme/src/preqx/share/viscosity_preqx_base.F90 homme/src/share/viscosity_base.F90 homme/src/theta-l/viscosity_theta.F90 - homme/src/theta/viscosity_theta.F90 homme/src/theta-l/eos.F90 - homme/src/theta/eos.F90 - homme/src/theta/hevi_mod.F90 cam/src/physics/cam/uwshcu.F90) -set(REDUCED_PRECISION_OBJS ../cime/src/share/util/shr_wv_sat_mod.F90) +set(REDUCED_PRECISION_OBJS ${CIMESRC_PATH}/share/util/shr_wv_sat_mod.F90) set(SHR_RANDNUM_FORT_OBJS - ../cime/src/share/RandNum/src/kissvec/kissvec_mod.F90 - ../cime/src/share/RandNum/src/mt19937/mersennetwister_mod.F90 - ../cime/src/share/RandNum/src/dsfmt_f03/dSFMT_interface.F90 - ../cime/src/share/RandNum/src/shr_RandNum_mod.F90) + ${CIMESRC_PATH}/share/RandNum/src/kissvec/kissvec_mod.F90 + ${CIMESRC_PATH}/share/RandNum/src/mt19937/mersennetwister_mod.F90 + ${CIMESRC_PATH}/share/RandNum/src/dsfmt_f03/dSFMT_interface.F90 + ${CIMESRC_PATH}/share/RandNum/src/shr_RandNum_mod.F90) set(SHR_RANDNUM_C_OBJS - ../cime/src/share/RandNum/src/dsfmt_f03/dSFMT.c - ../cime/src/share/RandNum/src/dsfmt_f03/dSFMT_utils.c - ../cime/src/share/RandNum/src/kissvec/kissvec.c) + ${CIMESRC_PATH}/share/RandNum/src/dsfmt_f03/dSFMT.c + ${CIMESRC_PATH}/share/RandNum/src/dsfmt_f03/dSFMT_utils.c + ${CIMESRC_PATH}/share/RandNum/src/kissvec/kissvec.c) if (NOT DEBUG) foreach(ITEM IN LISTS PERFOBJS) diff --git a/components/cmake/build_model.cmake b/components/cmake/build_model.cmake index 14a15d3d28b7..aa7801a5522d 100644 --- a/components/cmake/build_model.cmake +++ b/components/cmake/build_model.cmake @@ -26,6 +26,11 @@ function(build_model COMP_CLASS COMP_NAME) endforeach() endif() + # Source files don't live in components/cmake/$COMP_CLASS. This path won't work for + # generated files. + set(SOURCE_PATH "../..") + set(CIMESRC_PATH "../cime/src") + #------------------------------------------------------------------------------- # Build & include dependency files #------------------------------------------------------------------------------- @@ -164,7 +169,7 @@ function(build_model COMP_CLASS COMP_NAME) if (ITEM MATCHES "${CMAKE_BINARY_DIR}/.*") # is generated list(APPEND REAL_SOURCES ${ITEM}) else() - list(APPEND REAL_SOURCES "../../${ITEM}") + list(APPEND REAL_SOURCES "${SOURCE_PATH}/${ITEM}") endif() endforeach() diff --git a/components/cmake/cmake_util.cmake b/components/cmake/cmake_util.cmake index 2148a0199cdb..9ce32a8a75b3 100644 --- a/components/cmake/cmake_util.cmake +++ b/components/cmake/cmake_util.cmake @@ -50,9 +50,9 @@ function(e3sm_add_flags FILE_ARG FLAGS_ARG) set(REAL_FILE ${FILE_ARG}) else() if (NOT EXISTS ${PROJECT_SOURCE_DIR}/${FILE_ARG}) - message(FATAL_ERROR "Trying to set flags on non-existent source: ${FILE_ARG}") + message(FATAL_ERROR "Trying to set flags on non-existent source: ${FILE_ARG}, looked for ${PROJECT_SOURCE_DIR}/${FILE_ARG}") endif() - set(REAL_FILE "../../${FILE_ARG}") + set(REAL_FILE "${SOURCE_PATH}/${FILE_ARG}") endif() set_property(SOURCE ${REAL_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS " ${FLAGS_ARG} ") endfunction() From 9c2eb5ec3aae8bed8d093936f89caff4e6e35a25 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Tue, 5 Nov 2019 14:12:54 -0700 Subject: [PATCH 44/48] Add dry-run capability to case.build --- cime/scripts/Tools/case.build | 11 +++-- .../CIME/SystemTests/system_tests_common.py | 7 +++- cime/scripts/lib/CIME/build.py | 41 +++++++++++++------ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/cime/scripts/Tools/case.build b/cime/scripts/Tools/case.build index b446d74743b5..f2484a3548bd 100755 --- a/cime/scripts/Tools/case.build +++ b/cime/scripts/Tools/case.build @@ -70,6 +70,9 @@ def parse_command_line(args, description): help="Use gmake backed for CMake (instead of ninja). " "The gmake backend does not always correctly scan fortran dependencies") + parser.add_argument("--dry-run", action="store_true", + help="Just print the cmake and ninja commands.") + mutex_group = parser.add_mutually_exclusive_group() # TODO mvertens: the following is hard-wired - otherwise it does not work with nuopc @@ -114,12 +117,12 @@ def parse_command_line(args, description): cleanlist = args.clean if args.clean is None or len(args.clean) else comps buildlist = None if args.build is None or len(args.build) == 0 else args.build - return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old, args.use_gmake + return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old, args.use_gmake, args.dry_run ############################################################################### def _main_func(description): ############################################################################### - caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance, use_old, use_gmake = \ + caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance, use_old, use_gmake, dry_run = \ parse_command_line(sys.argv, description) success = True @@ -144,12 +147,12 @@ def _main_func(description): raise expect(buildlist is None, "Build lists don't work with tests") - success = test.build(sharedlib_only=sharedlib_only, model_only=model_only, old_build=use_old, use_gmake=use_gmake) + success = test.build(sharedlib_only=sharedlib_only, model_only=model_only, old_build=use_old, use_gmake=use_gmake, dry_run=dry_run) else: success = build.case_build(caseroot, case=case, sharedlib_only=sharedlib_only, model_only=model_only, buildlist=buildlist, save_build_provenance=save_build_provenance, - use_old=use_old, use_gmake=use_gmake) + use_old=use_old, use_gmake=use_gmake, dry_run=dry_run) sys.exit(0 if success else 1) diff --git a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py index f21df6656d53..2f107e97de55 100644 --- a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py +++ b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py @@ -35,6 +35,7 @@ def __init__(self, case, expected=None): self._cpllog = "med" if self._case.get_value("COMP_INTERFACE")=="nuopc" else "cpl" self._old_build = False self._use_gmake = False + self._dry_run = False def _init_environment(self, caseroot): """ @@ -68,7 +69,7 @@ def _resetup_case(self, phase, reset=False): self._case.case_setup(reset=True, test_mode=True) - def build(self, sharedlib_only=False, model_only=False, old_build=False, use_gmake=False): + def build(self, sharedlib_only=False, model_only=False, old_build=False, use_gmake=False, dry_run=False): """ Do NOT override this method, this method is the framework that controls the build phase. build_phase is the extension point @@ -77,6 +78,7 @@ def build(self, sharedlib_only=False, model_only=False, old_build=False, use_gma success = True self._old_build = old_build self._use_gmake = use_gmake + self._dry_run = dry_run for phase_name, phase_bool in [(SHAREDLIB_BUILD_PHASE, not model_only), (MODEL_BUILD_PHASE, not sharedlib_only)]: if phase_bool: @@ -124,7 +126,8 @@ def build_indv(self, sharedlib_only=False, model_only=False): model = self._case.get_value('MODEL') build.case_build(self._caseroot, case=self._case, sharedlib_only=sharedlib_only, model_only=model_only, - save_build_provenance=not model=='cesm', use_old=self._old_build, use_gmake=self._use_gmake) + save_build_provenance=not model=='cesm', + use_old=self._old_build, use_gmake=self._use_gmake, dry_run=self._dry_run) def clean_build(self, comps=None): if comps is None: diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index b6d9269e06be..c7ef7f2cb3c2 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -154,7 +154,7 @@ def _build_model(build_threaded, exeroot, incroot, complist, ############################################################################### def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, - comp_interface, sharedpath, use_gmake, case): + comp_interface, sharedpath, use_gmake, dry_run, case): ############################################################################### cime_model = get_model() bldroot = os.path.join(exeroot, "cmake-bld") @@ -187,18 +187,31 @@ def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, cmake_args += " -GNinja " cmake_env += "PATH={}:$PATH ".format(ninja_path) - cmake_cmd = "{}cmake {} {}/components >> {} 2>&1".format(cmake_env, cmake_args, srcroot, bldlog) - with open(bldlog, "w") as fd: - fd.write("Configuring with cmake cmd:\n{}\n\n".format(cmake_cmd)) - stat = run_cmd(cmake_cmd, from_dir=bldroot)[0] + cmake_cmd = "{}cmake {} {}/components".format(cmake_env, cmake_args, srcroot) + stat = 0 + if dry_run: + logger.info("CMake cmd:\ncd {} && {}\n\n".format(bldroot, cmake_cmd)) + else: + with open(bldlog, "w") as fd: + fd.write("Configuring with cmake cmd:\n{}\n\n".format(cmake_cmd)) + + # Add logging before running + cmake_cmd = "{} >> {} 2>&1".format(cmake_cmd, bldlog) + stat = run_cmd(cmake_cmd, from_dir=bldroot)[0] # Call Make if stat == 0: - make_cmd = "{} -j {} >> {} 2>&1".format(gmake if use_gmake else "{} -v".format(os.path.join(ninja_path, "ninja")), gmake_j, bldlog) - with open(bldlog, "a") as fd: - fd.write("\n\nBuilding with cmd:\n{}\n\n".format(make_cmd)) + make_cmd = "{} -j {}".format(gmake if use_gmake else "{} -v".format(os.path.join(ninja_path, "ninja")), gmake_j) + if dry_run: + logger.info("Build cmd:\ncd {} && {}\n\n".format(bldroot, make_cmd)) + expect(False, "User requested dry-run only, terminating build") + else: + with open(bldlog, "a") as fd: + fd.write("\n\nBuilding with cmd:\n{}\n\n".format(make_cmd)) - stat = run_cmd(make_cmd, from_dir=bldroot)[0] + # Add logging before running + make_cmd = "{} >> {} 2>&1".format(make_cmd, bldlog) + stat = run_cmd(make_cmd, from_dir=bldroot)[0] expect(stat == 0, "BUILD FAIL: build {} failed, cat {}".format(cime_model, bldlog)) @@ -469,13 +482,15 @@ def _clean_impl(case, cleanlist, clean_all, clean_depends): ############################################################################### def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance, use_old, use_gmake): + save_build_provenance, use_old, use_gmake, dry_run): ############################################################################### t1 = time.time() expect(not (sharedlib_only and model_only), "Contradiction: both sharedlib_only and model_only") + expect(not (dry_run and not model_only), + "Dry-run is only for model builds, please build sharedlibs first") logger.info("Building case in directory {}".format(caseroot)) logger.info("sharedlib_only is {}".format(sharedlib_only)) logger.info("model_only is {}".format(model_only)) @@ -592,7 +607,7 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, if not sharedlib_only: if get_model() == "e3sm" and not use_old: logs.extend(_build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, - comp_interface, sharedpath, use_gmake, case)) + comp_interface, sharedpath, use_gmake, dry_run, case)) else: os.environ["INSTALL_SHAREDPATH"] = os.path.join(exeroot, sharedpath) # for MPAS makefile generators logs.extend(_build_model(build_threaded, exeroot, incroot, complist, @@ -637,10 +652,10 @@ def post_build(case, logs, build_complete=False, save_build_provenance=True): lock_file("env_build.xml", caseroot=case.get_value("CASEROOT")) ############################################################################### -def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True, use_old=False, use_gmake=False): +def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True, use_old=False, use_gmake=False, dry_run=False): ############################################################################### functor = lambda: _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance, use_old, use_gmake) + save_build_provenance, use_old, use_gmake, dry_run) return run_and_log_case_status(functor, "case.build", caseroot=caseroot) ############################################################################### From d87e1ce8bb13373e22828e7ec015e1150487c323 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 14 Nov 2019 16:36:44 -0700 Subject: [PATCH 45/48] e3sm no longer uses MODEL in config_compilers --- cime/config/e3sm/machines/config_compilers.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime/config/e3sm/machines/config_compilers.xml b/cime/config/e3sm/machines/config_compilers.xml index 447438df6043..0f4e54446228 100644 --- a/cime/config/e3sm/machines/config_compilers.xml +++ b/cime/config/e3sm/machines/config_compilers.xml @@ -760,7 +760,7 @@ flags should be captured within MPAS CMake files. - -DHAVE_SLASHPROC + -DHAVE_SLASHPROC --host=Linux From c24b324373facf0c263fa0d520c4e1589b94788b Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 15 Nov 2019 10:31:24 -0800 Subject: [PATCH 46/48] Forgot to push these compy fixes --- cime/scripts/Tools/case.build | 14 +++++++++++--- cime/scripts/lib/CIME/test_scheduler.py | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cime/scripts/Tools/case.build b/cime/scripts/Tools/case.build index f2484a3548bd..0c2702c02a04 100755 --- a/cime/scripts/Tools/case.build +++ b/cime/scripts/Tools/case.build @@ -66,9 +66,9 @@ def parse_command_line(args, description): parser.add_argument("--use-old", action="store_true", help="Use old Makefile build system (not cmake)") - parser.add_argument("--use-gmake", action="store_true", - help="Use gmake backed for CMake (instead of ninja). " - "The gmake backend does not always correctly scan fortran dependencies") + parser.add_argument("--use-gmake", action="store_true", + help="Use gmake backed for CMake (instead of ninja). " + "The gmake backend does not always correctly scan fortran dependencies") parser.add_argument("--dry-run", action="store_true", help="Just print the cmake and ninja commands.") @@ -117,6 +117,10 @@ def parse_command_line(args, description): cleanlist = args.clean if args.clean is None or len(args.clean) else comps buildlist = None if args.build is None or len(args.build) == 0 else args.build + if get_model() != "e3sm": + args.use_old = False + args.use_gmake = False + return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old, args.use_gmake, args.dry_run ############################################################################### @@ -129,6 +133,10 @@ def _main_func(description): with Case(caseroot, read_only=False) as case: testname = case.get_value('TESTCASE') + if get_model() == "e3sm" and case.get_value("COMPILER") == "pgi" and not use_gmake: + logging.warning("ninja CMake backend does not work with pgi, switching to gmake backend") + use_gmake = True + if cleanlist is not None or clean_all or clean_depends is not None: build.clean(case, cleanlist=cleanlist, clean_all=clean_all, clean_depends=clean_depends) elif(testname is not None): diff --git a/cime/scripts/lib/CIME/test_scheduler.py b/cime/scripts/lib/CIME/test_scheduler.py index 7f175899ca50..fa178164aeac 100644 --- a/cime/scripts/lib/CIME/test_scheduler.py +++ b/cime/scripts/lib/CIME/test_scheduler.py @@ -146,7 +146,7 @@ def __init__(self, test_names, test_data=None, self._machobj = Machines(machine=machine_name) if get_model() == "e3sm": - self._model_build_cost = (self._machobj.get_value("GMAKE_J") * 2) / 3 + 1 + self._model_build_cost = int((self._machobj.get_value("GMAKE_J") * 2) / 3) + 1 else: self._model_build_cost = 4 From 5f73364a2424fe7314f967caca1f467923eb8ff5 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Sat, 16 Nov 2019 15:06:47 -0600 Subject: [PATCH 47/48] Switch back to gmake as default backend --- cime/scripts/Tools/case.build | 23 ++++++++----------- .../CIME/SystemTests/system_tests_common.py | 8 +++---- cime/scripts/lib/CIME/build.py | 14 +++++------ 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/cime/scripts/Tools/case.build b/cime/scripts/Tools/case.build index 0c2702c02a04..6d7a55fd6604 100755 --- a/cime/scripts/Tools/case.build +++ b/cime/scripts/Tools/case.build @@ -66,9 +66,10 @@ def parse_command_line(args, description): parser.add_argument("--use-old", action="store_true", help="Use old Makefile build system (not cmake)") - parser.add_argument("--use-gmake", action="store_true", - help="Use gmake backed for CMake (instead of ninja). " - "The gmake backend does not always correctly scan fortran dependencies") + parser.add_argument("--ninja", action="store_true", + help="Use ninja backed for CMake (instead of gmake). " + "The ninja backend is better at scanning fortran dependencies but " + "seems to be less reliable across different platforms and compilers.") parser.add_argument("--dry-run", action="store_true", help="Just print the cmake and ninja commands.") @@ -118,25 +119,21 @@ def parse_command_line(args, description): buildlist = None if args.build is None or len(args.build) == 0 else args.build if get_model() != "e3sm": - args.use_old = False - args.use_gmake = False + args.use_old = False + args.ninja = False - return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old, args.use_gmake, args.dry_run + return args.caseroot, args.sharedlib_only, args.model_only, cleanlist, args.clean_all, buildlist, clean_depends, not args.skip_provenance_check, args.use_old, args.ninja, args.dry_run ############################################################################### def _main_func(description): ############################################################################### - caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance, use_old, use_gmake, dry_run = \ + caseroot, sharedlib_only, model_only, cleanlist, clean_all, buildlist,clean_depends, save_build_provenance, use_old, ninja, dry_run = \ parse_command_line(sys.argv, description) success = True with Case(caseroot, read_only=False) as case: testname = case.get_value('TESTCASE') - if get_model() == "e3sm" and case.get_value("COMPILER") == "pgi" and not use_gmake: - logging.warning("ninja CMake backend does not work with pgi, switching to gmake backend") - use_gmake = True - if cleanlist is not None or clean_all or clean_depends is not None: build.clean(case, cleanlist=cleanlist, clean_all=clean_all, clean_depends=clean_depends) elif(testname is not None): @@ -155,12 +152,12 @@ def _main_func(description): raise expect(buildlist is None, "Build lists don't work with tests") - success = test.build(sharedlib_only=sharedlib_only, model_only=model_only, old_build=use_old, use_gmake=use_gmake, dry_run=dry_run) + success = test.build(sharedlib_only=sharedlib_only, model_only=model_only, old_build=use_old, ninja=ninja, dry_run=dry_run) else: success = build.case_build(caseroot, case=case, sharedlib_only=sharedlib_only, model_only=model_only, buildlist=buildlist, save_build_provenance=save_build_provenance, - use_old=use_old, use_gmake=use_gmake, dry_run=dry_run) + use_old=use_old, ninja=ninja, dry_run=dry_run) sys.exit(0 if success else 1) diff --git a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py index 2f107e97de55..bc16819d1e59 100644 --- a/cime/scripts/lib/CIME/SystemTests/system_tests_common.py +++ b/cime/scripts/lib/CIME/SystemTests/system_tests_common.py @@ -34,7 +34,7 @@ def __init__(self, case, expected=None): self._skip_pnl = False self._cpllog = "med" if self._case.get_value("COMP_INTERFACE")=="nuopc" else "cpl" self._old_build = False - self._use_gmake = False + self._ninja = False self._dry_run = False def _init_environment(self, caseroot): @@ -69,7 +69,7 @@ def _resetup_case(self, phase, reset=False): self._case.case_setup(reset=True, test_mode=True) - def build(self, sharedlib_only=False, model_only=False, old_build=False, use_gmake=False, dry_run=False): + def build(self, sharedlib_only=False, model_only=False, old_build=False, ninja=False, dry_run=False): """ Do NOT override this method, this method is the framework that controls the build phase. build_phase is the extension point @@ -77,7 +77,7 @@ def build(self, sharedlib_only=False, model_only=False, old_build=False, use_gma """ success = True self._old_build = old_build - self._use_gmake = use_gmake + self._ninja = ninja self._dry_run = dry_run for phase_name, phase_bool in [(SHAREDLIB_BUILD_PHASE, not model_only), (MODEL_BUILD_PHASE, not sharedlib_only)]: @@ -127,7 +127,7 @@ def build_indv(self, sharedlib_only=False, model_only=False): build.case_build(self._caseroot, case=self._case, sharedlib_only=sharedlib_only, model_only=model_only, save_build_provenance=not model=='cesm', - use_old=self._old_build, use_gmake=self._use_gmake, dry_run=self._dry_run) + use_old=self._old_build, ninja=self._ninja, dry_run=self._dry_run) def clean_build(self, comps=None): if comps is None: diff --git a/cime/scripts/lib/CIME/build.py b/cime/scripts/lib/CIME/build.py index c7ef7f2cb3c2..04229c8ff1f0 100644 --- a/cime/scripts/lib/CIME/build.py +++ b/cime/scripts/lib/CIME/build.py @@ -154,7 +154,7 @@ def _build_model(build_threaded, exeroot, incroot, complist, ############################################################################### def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, - comp_interface, sharedpath, use_gmake, dry_run, case): + comp_interface, sharedpath, ninja, dry_run, case): ############################################################################### cime_model = get_model() bldroot = os.path.join(exeroot, "cmake-bld") @@ -183,7 +183,7 @@ def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, cmake_args = get_standard_cmake_args(case, sharedpath) cmake_env = "" ninja_path = os.path.join(srcroot, "externals/ninja/bin") - if not use_gmake: + if ninja: cmake_args += " -GNinja " cmake_env += "PATH={}:$PATH ".format(ninja_path) @@ -201,7 +201,7 @@ def _build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, # Call Make if stat == 0: - make_cmd = "{} -j {}".format(gmake if use_gmake else "{} -v".format(os.path.join(ninja_path, "ninja")), gmake_j) + make_cmd = "{} -j {}".format(gmake if not ninja else "{} -v".format(os.path.join(ninja_path, "ninja")), gmake_j) if dry_run: logger.info("Build cmd:\ncd {} && {}\n\n".format(bldroot, make_cmd)) expect(False, "User requested dry-run only, terminating build") @@ -482,7 +482,7 @@ def _clean_impl(case, cleanlist, clean_all, clean_depends): ############################################################################### def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance, use_old, use_gmake, dry_run): + save_build_provenance, use_old, ninja, dry_run): ############################################################################### t1 = time.time() @@ -607,7 +607,7 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, if not sharedlib_only: if get_model() == "e3sm" and not use_old: logs.extend(_build_model_cmake(exeroot, complist, lid, cimeroot, buildlist, - comp_interface, sharedpath, use_gmake, dry_run, case)) + comp_interface, sharedpath, ninja, dry_run, case)) else: os.environ["INSTALL_SHAREDPATH"] = os.path.join(exeroot, sharedpath) # for MPAS makefile generators logs.extend(_build_model(build_threaded, exeroot, incroot, complist, @@ -652,10 +652,10 @@ def post_build(case, logs, build_complete=False, save_build_provenance=True): lock_file("env_build.xml", caseroot=case.get_value("CASEROOT")) ############################################################################### -def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True, use_old=False, use_gmake=False, dry_run=False): +def case_build(caseroot, case, sharedlib_only=False, model_only=False, buildlist=None, save_build_provenance=True, use_old=False, ninja=False, dry_run=False): ############################################################################### functor = lambda: _case_build_impl(caseroot, case, sharedlib_only, model_only, buildlist, - save_build_provenance, use_old, use_gmake, dry_run) + save_build_provenance, use_old, ninja, dry_run) return run_and_log_case_status(functor, "case.build", caseroot=caseroot) ############################################################################### From 9b74244d40ba42b1d14820127a2d464462159ce0 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Sun, 17 Nov 2019 15:58:26 -0700 Subject: [PATCH 48/48] No need to set CMAKE_EXE_LINKER flags, target_link_libs already was handling that --- components/cmake/build_mpas_model.cmake | 7 ++++--- components/cmake/common_setup.cmake | 5 ----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/components/cmake/build_mpas_model.cmake b/components/cmake/build_mpas_model.cmake index 928f0e92a154..ad41b1ec1c0c 100644 --- a/components/cmake/build_mpas_model.cmake +++ b/components/cmake/build_mpas_model.cmake @@ -15,9 +15,6 @@ function(build_mpas_models) elseif (COMP_NAME STREQUAL "mali") list(APPEND CORES "landice") set(COMP_CLASS "glc") - if (USE_ALBANY) - set(ALBANY True) - endif() else() message(FATAL_ERROR "Unrecognized MPAS model ${COMP_NAME}") endif() @@ -25,6 +22,10 @@ function(build_mpas_models) message("Found MPAS component ${COMP_CLASS} model '${COMP_NAME}'") endforeach() + if (USE_ALBANY) + set(ALBANY True) + endif() + if (CORES) add_subdirectory("mpas-source/src") endif() diff --git a/components/cmake/common_setup.cmake b/components/cmake/common_setup.cmake index 8473d24d7e4e..0ddcbab4f926 100644 --- a/components/cmake/common_setup.cmake +++ b/components/cmake/common_setup.cmake @@ -457,8 +457,3 @@ set(CMAKE_Fortran_COMPILER ${FC} PARENT_SCOPE) set(CMAKE_Fortran_FLAGS "${FFLAGS}" PARENT_SCOPE) set(CMAKE_C_FLAGS "${CFLAGS}" PARENT_SCOPE) set(CMAKE_CXX_FLAGS "${CXXFLAGS}" PARENT_SCOPE) -if (LD STREQUAL "Fortran") - set(CMAKE_EXE_LINKER_FLAGS "${F90_LDFLAGS}" PARENT_SCOPE) -else() - set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}" PARENT_SCOPE) -endif()