From 4c9389d2c394f405ce8361ece0b6702d0df7df07 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Tue, 10 Dec 2019 13:32:16 -0700 Subject: [PATCH 1/2] Optimization/cleanup: only compile the files that are needed when static build is selected --- src/CMakeLists.txt | 69 +++++++++++++++++++++++++++++----------------- src/ccpp.F90 | 6 ++++ src/ccpp_api.F90 | 8 ++++-- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 06292032..2bef8b4e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,29 +6,40 @@ endif (NOT PROJECT) #------------------------------------------------------------------------------ # Set the sources -set(SOURCES_C - ccpp_dl.h - ccpp_dl.c - ccpp_fields_idx.h - ccpp_fields_idx.c - ccpp_utils.h - ccpp_utils.c - ccpp_xml.h - ccpp_xml.c -) -set(SOURCES_F90 - ccpp.F90 - ccpp_dl.F90 - ccpp_errors.F90 - ccpp_fcall.F90 - ccpp_fields.F90 - ccpp_strings.F90 - ccpp_scheme.F90 - ccpp_suite.F90 - ccpp_types.F90 - ccpp_xml.F90 - ccpp_api.F90 -) +if(STATIC) + set(SOURCES_C) + set(SOURCES_F90 + ccpp_types.F90 + ccpp_errors.F90 + ccpp.F90 + ccpp_api.F90 + ) +else(STATIC) + set(SOURCES_C + ccpp_dl.h + ccpp_dl.c + ccpp_fields_idx.h + ccpp_fields_idx.c + ccpp_utils.h + ccpp_utils.c + ccpp_xml.h + ccpp_xml.c + ) + set(SOURCES_F90 + ccpp.F90 + ccpp_dl.F90 + ccpp_errors.F90 + ccpp_fcall.F90 + ccpp_fields.F90 + ccpp_strings.F90 + ccpp_scheme.F90 + ccpp_suite.F90 + ccpp_types.F90 + ccpp_xml.F90 + ccpp_api.F90 + ) +endif(STATIC) + # Generate list of Fortran modules from defined sources foreach(source_f90 ${SOURCES_F90}) string(REGEX REPLACE ".F90" ".mod" module_f90 ${source_f90}) @@ -42,7 +53,13 @@ if(LIBXML2_LIB_DIR AND LIBXML2_INCLUDE_DIR) if (STATIC) list(APPEND LIBS "${LIBXML2_LIB_DIR}/libxml2.a") else (STATIC) - list(APPEND LIBS "${LIBXML2_LIB_DIR}/libxml2.so") + if(APPLE) + list(APPEND LIBS "${LIBXML2_LIB_DIR}/libxml2.dylib") + elseif(UNIX) + list(APPEND LIBS "${LIBXML2_LIB_DIR}/libxml2.so") + else (APPLE) + message (FATAL_ERROR "Unsupported platform, only Linux and MacOSX are supported at this time.") + endif(APPLE) endif (STATIC) else(LIBXML2_LIB_DIR AND LIBXML2_INCLUDE_DIR) find_package(LibXml2 REQUIRED) @@ -105,8 +122,10 @@ set(${PACKAGE}_LIB_DIRS CACHE FILEPATH "${PACKAGE} library directories") #------------------------------------------------------------------------------ -# Add the tests +# Add the tests (designed for DYNAMIC build only) +if(!STATIC) add_subdirectory(tests) +endif(!STATIC) #------------------------------------------------------------------------------ # Define the executable and what to link diff --git a/src/ccpp.F90 b/src/ccpp.F90 index 22cbad87..6bef125a 100644 --- a/src/ccpp.F90 +++ b/src/ccpp.F90 @@ -17,6 +17,10 @@ ! module ccpp +#ifdef STATIC + use :: ccpp_types, & + only: ccpp_t +#else use, intrinsic :: iso_c_binding, & only: c_ptr use :: ccpp_types, & @@ -25,12 +29,14 @@ module ccpp only: ccpp_suite_init, ccpp_suite_finalize use :: ccpp_fields, & only: ccpp_fields_init, ccpp_fields_finalize +#endif use :: ccpp_errors, & only: ccpp_error, ccpp_debug implicit none private + public :: ccpp_init, & ccpp_finalize, & ccpp_initialized diff --git a/src/ccpp_api.F90 b/src/ccpp_api.F90 index 9c338121..9fafddc7 100644 --- a/src/ccpp_api.F90 +++ b/src/ccpp_api.F90 @@ -25,11 +25,13 @@ module ccpp_api use ccpp, only: ccpp_init, & ccpp_finalize, & ccpp_initialized +#ifndef STATIC use ccpp_fcall, only: ccpp_physics_init, & ccpp_physics_run, & ccpp_physics_finalize use ccpp_fields, only: ccpp_field_add, & ccpp_field_get +#endif implicit none @@ -38,11 +40,13 @@ module ccpp_api ccpp_error, & ccpp_debug, & ccpp_init, & - ccpp_finalize, & - ccpp_physics_init, & + ccpp_finalize +#ifndef STATIC + public :: ccpp_physics_init, & ccpp_physics_run, & ccpp_physics_finalize, & ccpp_field_add, & ccpp_initialized +#endif end module ccpp_api From 10f85011c612bc3cf4e4339a45f5e54e0c5eba21 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Tue, 10 Dec 2019 13:33:00 -0700 Subject: [PATCH 2/2] Improved handling of builddir/basedir argument to ccpp_prebuild.py and metadata2html.py, improved error handling and diagnostic output for ccpp_prebuild.py --- scripts/ccpp_prebuild.py | 9 ++++++++- scripts/metadata2html.py | 8 +++++++- scripts/mkcap.py | 3 +++ scripts/mkstatic.py | 12 +++++++++--- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/scripts/ccpp_prebuild.py b/scripts/ccpp_prebuild.py index d7606289..fda3c7ba 100755 --- a/scripts/ccpp_prebuild.py +++ b/scripts/ccpp_prebuild.py @@ -30,7 +30,7 @@ parser.add_argument('--debug', action='store_true', help='enable debugging output', default=False) parser.add_argument('--static', action='store_true', help='enable a static build for a given suite definition file', default=False) parser.add_argument('--suites', action='store', help='suite definition files to use (comma-separated, for static build only, without path)', default='') -parser.add_argument('--builddir', action='store', help='relative path to CCPP build directory', required=False, default='.') +parser.add_argument('--builddir', action='store', help='relative path to CCPP build directory', required=False, default=None) # BASEDIR is the current directory where this script is executed BASEDIR = os.getcwd() @@ -71,6 +71,13 @@ def import_config(configfile, builddir): sys.path.append(configpath) ccpp_prebuild_config = importlib.import_module(configmodule) + # If the build directory for running ccpp_prebuild.py is not + # specified as command line argument, use value from config + if not builddir: + builddir = os.path.join(BASEDIR, ccpp_prebuild_config.DEFAULT_BUILD_DIR) + logging.info('Build directory not specified on command line, ' + \ + 'use "{}" from CCPP prebuild config'.format(ccpp_prebuild_config.DEFAULT_BUILD_DIR)) + # Definitions in host-model dependent CCPP prebuild config script config['variable_definition_files'] = ccpp_prebuild_config.VARIABLE_DEFINITION_FILES config['scheme_files'] = ccpp_prebuild_config.SCHEME_FILES diff --git a/scripts/metadata2html.py b/scripts/metadata2html.py index b93a8f22..148a081e 100755 --- a/scripts/metadata2html.py +++ b/scripts/metadata2html.py @@ -54,6 +54,12 @@ def import_config(configfile, logger): sys.path.append(configpath) ccpp_prebuild_config = importlib.import_module(configmodule) + # Get the base directory for running metadata2html.py from + # the default build directory value in the CCPP prebuild config + basedir = os.path.join(os.getcwd(), ccpp_prebuild_config.DEFAULT_BUILD_DIR) + logger.info('Relative path to CCPP directory from CCPP prebuild config: {}'.format( + ccpp_prebuild_config.DEFAULT_BUILD_DIR)) + config = {} # Definitions in host-model dependent CCPP prebuild config script config['variable_definition_files'] = ccpp_prebuild_config.VARIABLE_DEFINITION_FILES @@ -61,7 +67,7 @@ def import_config(configfile, logger): # Add model-independent, CCPP-internal variable definition files config['variable_definition_files'].append(CCPP_INTERNAL_VARIABLE_DEFINITON_FILE) # Output directory for converted metadata tables - config['metadata_html_output_dir'] = ccpp_prebuild_config.METADATA_HTML_OUTPUT_DIR + config['metadata_html_output_dir'] = ccpp_prebuild_config.METADATA_HTML_OUTPUT_DIR.format(build_dir=basedir) return config diff --git a/scripts/mkcap.py b/scripts/mkcap.py index a29e6228..70a13420 100755 --- a/scripts/mkcap.py +++ b/scripts/mkcap.py @@ -6,6 +6,7 @@ from __future__ import print_function import copy +import logging import os import sys import getopt @@ -184,6 +185,7 @@ def convert_to(self, units): function_name = '{0}__to__{1}'.format(string_to_python_identifier(self.units), string_to_python_identifier(units)) try: function = getattr(unit_conversion, function_name) + logging.info('Automatic unit conversion from {0} to {1} for {2} before entering {3}'.format(self.units, units, self.standard_name, self.container)) except AttributeError: raise Exception('Error, automatic unit conversion from {0} to {1} for {2} in {3} not implemented'.format(self.units, units, self.standard_name, self.container)) conversion = function() @@ -194,6 +196,7 @@ def convert_from(self, units): function_name = '{1}__to__{0}'.format(string_to_python_identifier(self.units), string_to_python_identifier(units)) try: function = getattr(unit_conversion, function_name) + logging.info('Automatic unit conversion from {0} to {1} for {2} after returning from {3}'.format(self.units, units, self.standard_name, self.container)) except AttributeError: raise Exception('Error, automatic unit conversion from {1} to {0} for {2} in {3} not implemented'.format(self.units, units, self.standard_name, self.container)) conversion = function() diff --git a/scripts/mkstatic.py b/scripts/mkstatic.py index d95c5865..7adeafa6 100755 --- a/scripts/mkstatic.py +++ b/scripts/mkstatic.py @@ -183,7 +183,7 @@ class API(object): {suite_switch} else - write({ccpp_var_name}%errmsg,'(*(a))'), 'Invalid suite ' // trim(suite_name) + write({ccpp_var_name}%errmsg,'(*(a))') 'Invalid suite ' // trim(suite_name) ierr = 1 end if @@ -303,7 +303,7 @@ def write(self): arguments=argument_list_group) group_calls += ''' else - write({ccpp_var_name}%errmsg, '(*(a))') "Group " // trim(group_name) // " not found" + write({ccpp_var_name}%errmsg, '(*(a))') 'Group ' // trim(group_name) // ' not found' ierr = 1 end if '''.format(ccpp_var_name=ccpp_var.local_name, group_name=group.name) @@ -463,6 +463,12 @@ def parse(self): tree = ET.parse(self._sdf_name) suite_xml = tree.getroot() self._name = suite_xml.get('name') + # Validate name of suite in XML tag against filename; could be moved to common.py + if not (os.path.basename(self._sdf_name) == 'suite_{}.xml'.format(self._name)): + logging.critical("Invalid suite name {0} in suite definition file {1}.".format( + self._name, self._sdf_name)) + success = False + return success # Flattened lists of all schemes and subroutines in SDF self._all_schemes_called = [] @@ -938,7 +944,7 @@ def write(self, metadata_request, metadata_define, arguments): {actions_after} '''.format(subroutine_name=subroutine_name, args=args, actions_before=actions_before.rstrip('\n'), actions_after=actions_after.rstrip('\n')) error_check = '''if ({target_name_flag}/=0) then - write({target_name_msg},'(a)') "An error occured in {subroutine_name}" + {target_name_msg} = "An error occured in {subroutine_name}: " // trim({target_name_msg}) ierr={target_name_flag} return end if