From 915f93d2381578ab43decea04d05bf23cc956603 Mon Sep 17 00:00:00 2001 From: Anthony Islas <128631809+islas@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:57:27 -0700 Subject: [PATCH] CMake compilation flags as categorical properties (#2088) TYPE: enhancement KEYWORDS: cmake, compilation, flags SOURCE: internal DESCRIPTION OF CHANGES: Problem: In preparation for alternative core selection, there is a broader range of flags that must be set and controlled throughout the project. This includes being able to set flags on a per-source basis to override certain flags that are normally applied wholly to all source within a CMake target. An example of this is disabling double precision on an individual file when that option is being used. Solution: Categorizing the flags first allows for easy application and selection of particular sets of flags for the multiple libraries and binaries created. Second, for the core library, using pseudo-inherited CMake properties between targets and source files allows for granular control of these flag categories. --- CMakeLists.txt | 348 +++++++++++++++++---------- arch/configure_reader.py | 3 +- cmake/c_preproc.cmake | 5 +- cmake/target_source_properties.cmake | 142 +++++++++++ cmake/template/arch_config.cmake | 21 +- frame/CMakeLists.txt | 2 +- 6 files changed, 378 insertions(+), 143 deletions(-) create mode 100644 cmake/target_source_properties.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 07a80586ba..3cd0264b72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,12 +26,15 @@ list( APPEND CMAKE_C_PREPROCESSOR_FLAGS -P -nostdinc -traditional ) include( CMakePackageConfigHelpers ) include( CheckIPOSupported ) + +# WRF helper scripts include( c_preproc ) include( m4_preproc ) include( target_copy ) include( confcheck ) include( gitinfo ) include( printOption ) +include( target_source_properties ) include( wrf_case_setup ) include( wrf_get_version ) @@ -311,6 +314,51 @@ if ( ${USE_IPO} ) endif() endif() + +################################################################################ +## +## Create our flags / defines properties and variables to carry our information +## +################################################################################ +define_target_source_properties( + PROPERTIES + COMPILE_OPTIONS_OPTIMIZATION # Control of optimization flags + COMPILE_OPTIONS_CONFCHECK # Originate from system configuration checks + COMPILE_OPTIONS_OPTIONS # Derived from options + COMPILE_OPTIONS_Fortran_PRECISION # Fortran floating point precision control + COMPILE_OPTIONS_Fortran_LINE_LENGTH # Fortran line length for compilers that need it + COMPILE_OPTIONS_DIAGNOSTICS # Extra flags for diagnostics + COMPILE_OPTIONS_SUPPRESS_ERRORS # EXPLICITLY suppress errors, USE SPARINGLY!!! + COMPILE_OPTIONS_SUPPRESS_WARNINGS # Suppress warnings, try to fix before they become errs + COMPILE_OPTIONS_STANZA # Any remaining flags imported via stanza + + COMPILE_DEFINITIONS_CONFCHECK # Originate from system configuration checks + COMPILE_DEFINITIONS_OPTIONS # Anything that is derived from options + COMPILE_DEFINITIONS_STANZA # Any remaining defines imported via stanza + ) + +# These will be the cumulative set for quicker reference +set( PROJECT_COMPILE_OPTIONS "" ) +set( PROJECT_COMPILE_DEFINITIONS "" ) + +# Recreate these as project variables so that they may be re-used generically +set( PROJECT_COMPILE_OPTIONS_OPTIMIZATION "" ) +set( PROJECT_COMPILE_OPTIONS_CONFCHECK "" ) +set( PROJECT_COMPILE_OPTIONS_OPTIONS "" ) +set( PROJECT_COMPILE_OPTIONS_Fortran_PRECISION "" ) +set( PROJECT_COMPILE_OPTIONS_Fortran_LINE_LENGTH "" ) +set( PROJECT_COMPILE_OPTIONS_DIAGNOSTICS "" ) +set( PROJECT_COMPILE_OPTIONS_SUPPRESS_ERRORS "" ) +set( PROJECT_COMPILE_OPTIONS_SUPPRESS_WARNINGS "" ) +set( PROJECT_COMPILE_OPTIONS_STANZA "" ) +set( PROJECT_COMPILE_DEFINITIONS_CONFCHECK "" ) +set( PROJECT_COMPILE_DEFINITIONS_OPTIONS "" ) +set( PROJECT_COMPILE_DEFINITIONS_STANZA ${WRF_ARCH_LOCAL} ) + +# Make these imported variables easier to use in genexp +separate_arguments( WRF_FCOPTIM ) +separate_arguments( WRF_FCNOOPT ) + ################################################################################ ## ## Now find packages that cross-compilation is potentially handled @@ -330,19 +378,19 @@ if ( ${USE_MPI} ) # It still technically finds MPI but the output is nonintuitive # saying things like hdf5 or pthread find_package( MPI REQUIRED COMPONENTS Fortran C ) - list( APPEND PROJECT_COMPILE_DEFINITIONS + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS USE_MPI=1 DM_PARALLEL ) if ( DEFINED WRF_MPI_Fortran_FLAGS AND NOT "${WRF_MPI_Fortran_FLAGS}" STREQUAL "" ) - list( APPEND PROJECT_COMPILE_OPTIONS + list( APPEND PROJECT_COMPILE_OPTIONS_OPTIONS $<$:${WRF_MPI_Fortran_FLAGS}> ) endif() if ( DEFINED WRF_MPI_C_FLAGS AND NOT "${WRF_MPI_C_FLAGS}" STREQUAL "" ) - list( APPEND PROJECT_COMPILE_OPTIONS + list( APPEND PROJECT_COMPILE_OPTIONS_OPTIONS $<$:${WRF_MPI_C_FLAGS}> ) endif() @@ -373,7 +421,7 @@ if ( ${USE_MPI} ) set( USE_RSL_LITE ON ) # We know NONE is the zero index so compare against that elseif( ${CURRENT_NESTING_IDX} GREATER 0 ) - list( APPEND PROJECT_COMPILE_DEFINITIONS + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS DM_PARALLEL STUBMPI ) @@ -382,7 +430,7 @@ endif() if ( ${USE_OPENMP} ) find_package( OpenMP REQUIRED COMPONENTS Fortran C ) - list( APPEND PROJECT_COMPILE_DEFINITIONS + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS USE_OPENMP=1 SM_PARALLEL ) @@ -525,44 +573,18 @@ add_subdirectory( confcheck ) ## ################################################################################ -# https://stackoverflow.com/a/47927921 -# Define compile options to be inherited for directories -define_property( - SOURCE - PROPERTY COMPILE_FLAGS - INHERITED - BRIEF_DOCS "brief-doc" - FULL_DOCS "full-doc" - ) - -define_property( - DIRECTORY - PROPERTY COMPILE_FLAGS - INHERITED - BRIEF_DOCS "brief-doc" - FULL_DOCS "full-doc" - ) - # Get current build type flags and put them in there if ( "${CMAKE_BUILD_TYPE}" STREQUAL "Release" ) - set_directory_properties( - PROPERTIES - COMPILE_FLAGS - $<$:${WRF_FCOPTIM}> - ) + set( PROJECT_COMPILE_OPTIONS_OPTIMIZATION $<$:${WRF_FCOPTIM}> ) # else() # # Assume no optimization -# set_directory_properties( -# PROPERTIES -# COMPILE_FLAGS -# $<$:${WRF_FCNOOPT}> -# ) +# set( PROJECT_COMPILE_OPTIONS_OPTIMIZATION $<$:${WRF_FCNOOPT}> ) endif() # This is really ugly but such is the cost of supporting many ways to say the same thing # https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html -list( APPEND PROJECT_COMPILE_OPTIONS +list( APPEND PROJECT_COMPILE_OPTIONS_Fortran_PRECISION # Use "" and ; specifically to evaluate correctly # "$<$:>" #@ Absoft Fortran # "$<$:>" #@ Analog VisualDSP++ @@ -602,7 +624,9 @@ list( APPEND PROJECT_COMPILE_OPTIONS # "$<$:>" #@ IBM LLVM-based Compiler # Todo find how to handle default selection or add new compiler IDs # unknown how to add support for sxf90 + ) +list( APPEND PROJECT_COMPILE_OPTIONS_Fortran_LINE_LENGTH # line lengths "$<$:-ffree-line-length-none>" #@ GNU Compiler Collection ) @@ -613,24 +637,23 @@ list( APPEND PROJECT_COMPILE_OPTIONS # message( STATUS "Set Fortran_COMPILER_ID to : ${Fortran_COMPILER_ID}" ) -# Whole project flags -list( APPEND PROJECT_COMPILE_OPTIONS - # $<$:-cpp> +list( APPEND PROJECT_COMPILE_OPTIONS_SUPPRESS_WARNINGS # Use "" and ; specifically to evaluate correctly "$<$:-diag-disable;6843>" + ) + +list( APPEND PROJECT_COMPILE_OPTIONS_SUPPRESS_ERRORS $<$,$>:-fallow-argument-mismatch> $<$,$>:-fallow-invalid-boz> $<$,$>:-ffree-line-length-none> - - # $,$:-diag-disable;6843> ) if ( ${PROFILE_COMPILATION} ) message( STATUS "Attemping to add compilation profiling..." ) - list( APPEND PROJECT_COMPILE_OPTIONS $<$:-ftime-report> ) + list( APPEND PROJECT_COMPILE_OPTIONS_DIAGNOSTICS $<$:-ftime-report> ) endif() -list( APPEND PROJECT_COMPILE_DEFINITIONS +list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS MAX_DOMAINS_F=${MAX_DOMAINS_F} CONFIG_BUF_LEN=${CONFIG_BUF_LEN} MAX_HISTORY=${MAX_HISTORY} @@ -645,7 +668,7 @@ list( APPEND PROJECT_COMPILE_DEFINITIONS NETCDF #!TODO Change this to a confcheck - NONSTANDARD_SYSTEM_SUBR + # NONSTANDARD_SYSTEM_SUBR # For now let this come from stanza EM_CORE=${EM_CORE} @@ -656,56 +679,56 @@ list( APPEND PROJECT_COMPILE_DEFINITIONS # in code since cmake cannot handle basically any others :( # https://gitlab.kitware.com/cmake/cmake/-/issues/17398 if ( ${ENABLE_CHEM} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_CHEM=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_CHEM=1 ) if ( ${ENABLE_KPP} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_KPP=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_KPP=1 ) endif() endif() if ( ${ENABLE_CHEM} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS BUILD_CHEM=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS BUILD_CHEM=1 ) endif() if ( ${ENABLE_CMAQ} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_CMAQ=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_CMAQ=1 ) endif() if ( ${ENABLE_DFI_RADAR} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_DFI_RADAR=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_DFI_RADAR=1 ) endif() if ( ${ENABLE_TITAN} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_TITAN=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_TITAN=1 ) endif() if ( ${ENABLE_MARS} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_MARS=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_MARS=1 ) endif() if ( ${ENABLE_VENUS} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_VENUS=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_VENUS=1 ) endif() if ( ${ENABLE_HYDRO} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_HYDRO=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_HYDRO=1 ) endif() # Because once again we need two defines to control one thing if ( ${ENABLE_CTSM} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_USE_CTSM ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_USE_CTSM ) else() #!TODO there are some files that rely on this being 1, but that is never set by the legacy make system - list( APPEND PROJECT_COMPILE_DEFINITIONS WRF_USE_CLM ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRF_USE_CLM ) endif() # If force classic or no nc-4 support enable classic if ( ${FORCE_NETCDF_CLASSIC} OR ( NOT ${netCDF_HAS_NC4} ) ) - list( APPEND PROJECT_COMPILE_DEFINITIONS NETCDF_classic=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS NETCDF_classic=1 ) endif() if ( ${WRFIO_NCD_NO_LARGE_FILE_SUPPORT} OR ( NOT ${netCDF_LARGE_FILE_SUPPORT} ) ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRFIO_NCD_NO_LARGE_FILE_SUPPORT=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRFIO_NCD_NO_LARGE_FILE_SUPPORT=1 ) endif() # May need a check for WRFIO_ncdpar_LARGE_FILE_SUPPORT # Now set the opposite in different defines, because why not :) if ( ( NOT ${FORCE_NETCDF_CLASSIC} ) AND ${netCDF_HAS_NC4} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS USE_NETCDF4_FEATURES=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS USE_NETCDF4_FEATURES=1 ) endif() if ( ( NOT ${WRFIO_NCD_NO_LARGE_FILE_SUPPORT} ) AND ${netCDF_LARGE_FILE_SUPPORT} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRFIO_NCD_LARGE_FILE_SUPPORT=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRFIO_NCD_LARGE_FILE_SUPPORT=1 ) endif() # Could simplify logic to just check if RPC is available but to be explicit @@ -713,136 +736,165 @@ endif() # not enable terran or not rpc_found do # not ( enable terrain and rpc_found ) # if ( NOT ( ${ENABLE_TERRAIN} AND ${RPC_FOUND} ) ) # this is wrong, needs fixing -# list( APPEND PROJECT_COMPILE_DEFINITIONS LANDREAD_STUB ) +# list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS LANDREAD_STUB ) # endif() if ( ${ENABLE_TERRAIN} AND ${MOVE_NESTS} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS TERRAIN_AND_LANDUSE ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS TERRAIN_AND_LANDUSE ) else () - list( APPEND PROJECT_COMPILE_DEFINITIONS LANDREAD_STUB ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS LANDREAD_STUB ) endif() if ( ${USE_ALLOCATABLES} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS USE_ALLOCATABLES ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS USE_ALLOCATABLES ) endif() if ( ${wrfmodel} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS wrfmodel ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS wrfmodel ) endif() if ( ${GRIB1} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS GRIB1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS GRIB1 ) endif() if ( ${INTIO} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS INTIO ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS INTIO ) endif() if ( ${KEEP_INT_AROUND} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS KEEP_INT_AROUND ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS KEEP_INT_AROUND ) endif() if ( ${LIMIT_ARGS} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS LIMIT_ARGS ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS LIMIT_ARGS ) endif() if ( ${BUILD_RRTMG_FAST} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS BUILD_RRTMG_FAST=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS BUILD_RRTMG_FAST=1 ) else() - list( APPEND PROJECT_COMPILE_DEFINITIONS BUILD_RRTMG_FAST=0 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS BUILD_RRTMG_FAST=0 ) endif() if ( ${BUILD_RRTMK} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS BUILD_RRTMK=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS BUILD_RRTMK=1 ) else() - list( APPEND PROJECT_COMPILE_DEFINITIONS BUILD_RRTMK=0 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS BUILD_RRTMK=0 ) endif() if ( ${BUILD_SBM_FAST} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS BUILD_SBM_FAST=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS BUILD_SBM_FAST=1 ) else() - list( APPEND PROJECT_COMPILE_DEFINITIONS BUILD_SBM_FAST=0 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS BUILD_SBM_FAST=0 ) endif() if ( ${SHOW_ALL_VARS_USED} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS SHOW_ALL_VARS_USED=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS SHOW_ALL_VARS_USED=1 ) else() - list( APPEND PROJECT_COMPILE_DEFINITIONS SHOW_ALL_VARS_USED=0 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS SHOW_ALL_VARS_USED=0 ) endif() if ( ${NMM_CORE} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS NMM_CORE=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS NMM_CORE=1 ) else() - list( APPEND PROJECT_COMPILE_DEFINITIONS NMM_CORE=0 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS NMM_CORE=0 ) endif() if ( "${WRF_CORE}" STREQUAL "PLUS" ) - list( APPEND PROJECT_COMPILE_DEFINITIONS WRFPLUS=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRFPLUS=1 ) else() - list( APPEND PROJECT_COMPILE_DEFINITIONS WRFPLUS=0 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS WRFPLUS=0 ) endif() if ( "${WRF_CORE}" STREQUAL "DA_CORE" OR "${WRF_CORE}" STREQUAL "DA_4D_VAR" ) - list( APPEND PROJECT_COMPILE_DEFINITIONS DA_CORE=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS DA_CORE=1 ) else() - list( APPEND PROJECT_COMPILE_DEFINITIONS DA_CORE=0 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS DA_CORE=0 ) endif() # DFI_RADAR=$ # Nesting options if ( ${MOVE_NESTS} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS MOVE_NESTS ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS MOVE_NESTS ) endif() if ( "${WRF_NESTING}" STREQUAL "VORTEX" ) - list( APPEND PROJECT_COMPILE_DEFINITIONS VORTEX_CENTER ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_OPTIONS VORTEX_CENTER ) endif() # Configuration checks if ( NOT ${Fortran_2003_IEEE} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS NO_IEEE_MODULE ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_CONFCHECK NO_IEEE_MODULE ) endif() if ( NOT ${Fortran_2003_ISO_C} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS NO_ISO_C_SUPPORT ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_CONFCHECK NO_ISO_C_SUPPORT ) endif() # If flush fails, check if we can fall back to fflush, and if not no support if ( NOT ${Fortran_2003_FLUSH} ) if ( "${Fortran_2003_FFLUSH}" ) - list( APPEND PROJECT_COMPILE_DEFINITIONS USE_FFLUSH ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_CONFCHECK USE_FFLUSH ) else() - list( APPEND PROJECT_COMPILE_DEFINITIONS NO_FLUSH_SUPPORT ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_CONFCHECK NO_FLUSH_SUPPORT ) endif() endif() if ( NOT ${Fortran_2003_GAMMA} ) - list( APPEND PROJECT_COMPILE_DEFINITIONS NO_GAMMA_SUPPORT ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_CONFCHECK NO_GAMMA_SUPPORT ) endif() #!TODO Leaving as is in WRF for now but investigate why we don't do this # https://stackoverflow.com/a/1035713 # If fseeko64 succeeds, use that, else check if we can fall back to fseeko, and if not just use fseek if ( "${FSEEKO64}" OR "${FSEEKO}" ) - list( APPEND PROJECT_COMPILE_DEFINITIONS _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE=1 ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_CONFCHECK _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE=1 ) if ( "${FSEEKO64}" ) - list( APPEND PROJECT_COMPILE_DEFINITIONS FSEEKO64_OK ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_CONFCHECK FSEEKO64_OK ) elseif( "${FSEEKO}" ) - list( APPEND PROJECT_COMPILE_DEFINITIONS FSEEKO_OK ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_CONFCHECK FSEEKO_OK ) endif() else() - list( APPEND PROJECT_COMPILE_DEFINITIONS FSEEK_OK ) + list( APPEND PROJECT_COMPILE_DEFINITIONS_CONFCHECK FSEEK_OK ) endif() # I don't believe these are used anymore... # $<$:MPI2_SUPPORT=$> # $<$:MPI2_THREAD_SUPPORT=$> +# Accumulate option and definitions +list( APPEND PROJECT_COMPILE_OPTIONS + ${PROJECT_COMPILE_OPTIONS_OPTIMIZATION} + ${PROJECT_COMPILE_OPTIONS_CONFCHECK} + ${PROJECT_COMPILE_OPTIONS_OPTIONS} + ${PROJECT_COMPILE_OPTIONS_Fortran_PRECISION} + ${PROJECT_COMPILE_OPTIONS_Fortran_LINE_LENGTH} + ${PROJECT_COMPILE_OPTIONS_DIAGNOSTICS} + ${PROJECT_COMPILE_OPTIONS_SUPPRESS_ERRORS} + ${PROJECT_COMPILE_OPTIONS_SUPPRESS_WARNINGS} + ${PROJECT_COMPILE_OPTIONS_STANZA} + ) +list( APPEND PROJECT_COMPILE_DEFINITIONS + ${PROJECT_COMPILE_DEFINITIONS_CONFCHECK} + ${PROJECT_COMPILE_DEFINITIONS_OPTIONS} + ${PROJECT_COMPILE_DEFINITIONS_STANZA} + ) + +################################################################################ +## +## DO NOT modify PROJECT_COMPILE_* beyond this point +## +################################################################################ + + # Make core target add_library( ${PROJECT_NAME}_Core STATIC ) -target_compile_options( - ${PROJECT_NAME}_Core - PRIVATE - ${PROJECT_COMPILE_OPTIONS} - ) - +set_target_properties( + ${PROJECT_NAME}_Core + PROPERTIES + COMPILE_OPTIONS_OPTIMIZATION "${PROJECT_COMPILE_OPTIONS_OPTIMIZATION}" + COMPILE_OPTIONS_CONFCHECK "${PROJECT_COMPILE_OPTIONS_CONFCHECK}" + COMPILE_OPTIONS_OPTIONS "${PROJECT_COMPILE_OPTIONS_OPTIONS}" + COMPILE_OPTIONS_Fortran_PRECISION "${PROJECT_COMPILE_OPTIONS_Fortran_PRECISION}" + COMPILE_OPTIONS_Fortran_LINE_LENGTH "${PROJECT_COMPILE_OPTIONS_Fortran_LINE_LENGTH}" + COMPILE_OPTIONS_DIAGNOSTICS "${PROJECT_COMPILE_OPTIONS_DIAGNOSTICS}" + COMPILE_OPTIONS_SUPPRESS_ERRORS "${PROJECT_COMPILE_OPTIONS_SUPPRESS_ERRORS}" + COMPILE_OPTIONS_SUPPRESS_WARNINGS "${PROJECT_COMPILE_OPTIONS_SUPPRESS_WARNINGS}" + COMPILE_OPTIONS_STANZA "${PROJECT_COMPILE_OPTIONS_STANZA}" + # We do not use compile definitions for CMake's lack of source file accounting + ) -target_compile_definitions( - ${PROJECT_NAME}_Core - PRIVATE - ${PROJECT_COMPILE_DEFINITIONS} - ) +# Do NOT apply these options or defines just yet, allow files to be added and set their own properties # Supplemental to core, or rather should be, some stuff in external is legitimately part of WRF and others # are source code from truly external repositories - albeit old versions @@ -855,6 +907,68 @@ add_dependencies( # So many things depend on this that I'm adding a dep here registry_code ) + +# Add directly to core +add_subdirectory( phys ) +add_subdirectory( share ) +add_subdirectory( frame ) +add_subdirectory( inc ) + +if ( ${WRF_CHEM} ) + add_subdirectory( chem ) +endif() + +if ( ${ENABLE_HYDRO} ) + add_subdirectory( hydro ) +endif() + +add_subdirectory( dyn_em ) + + +add_subdirectory( main ) + +################################################################################ +# Add subdirectory with case info +################################################################################ +if ( ${CURRENT_WRF_CORE_IDX} GREATER_EQUAL ${START_DA_IDX} ) + message( STATUS "DA or PLUS build, WRF_CASE selection ignored" ) +else() + add_subdirectory( test/${WRF_CASE_FOLDER} ) +endif() + + + +################################################################################ +## +## DO NOT add sources beyond this point +## +################################################################################ + +# gather compile info and apply +apply_target_source_properties( + TARGETS ${PROJECT_NAME}_Core + PROPERTIES + COMPILE_OPTIONS_OPTIMIZATION + COMPILE_OPTIONS_CONFCHECK + COMPILE_OPTIONS_OPTIONS + COMPILE_OPTIONS_Fortran_PRECISION + COMPILE_OPTIONS_Fortran_LINE_LENGTH + COMPILE_OPTIONS_DIAGNOSTICS + COMPILE_OPTIONS_SUPPRESS_ERRORS + COMPILE_OPTIONS_SUPPRESS_WARNINGS + COMPILE_OPTIONS_STANZA + AS_PROPERTY COMPILE_OPTIONS + ) + +target_compile_definitions( + ${PROJECT_NAME}_Core + PRIVATE + ${PROJECT_COMPILE_DEFINITIONS_CONFCHECK} + ${PROJECT_COMPILE_DEFINITIONS_OPTIONS} + ${PROJECT_COMPILE_DEFINITIONS_STANZA} + ) + + target_include_directories( ${PROJECT_NAME}_Core PUBLIC @@ -911,34 +1025,6 @@ target_include_directories( ${pnetCDF_INCLUDE_DIRS} ) -# Add directly to core -add_subdirectory( phys ) -add_subdirectory( share ) -add_subdirectory( frame ) -add_subdirectory( inc ) - -if ( ${WRF_CHEM} ) - add_subdirectory( chem ) -endif() - -if ( ${ENABLE_HYDRO} ) - add_subdirectory( hydro ) -endif() - -add_subdirectory( dyn_em ) - - -add_subdirectory( main ) - -################################################################################ -# Add subdirectory with case info -################################################################################ -if ( ${CURRENT_WRF_CORE_IDX} GREATER_EQUAL ${START_DA_IDX} ) - message( STATUS "DA or PLUS build, WRF_CASE selection ignored" ) -else() - add_subdirectory( test/${WRF_CASE_FOLDER} ) -endif() - # Configure core set_target_properties( ${PROJECT_NAME}_Core @@ -949,6 +1035,8 @@ set_target_properties( EXPORT_PROPERTIES Fortran_MODULE_DIRECTORY ) +target_link_options( ${PROJECT_NAME}_Core PRIVATE ${WRF_LINK_FLAGS} ) + target_link_libraries( ${PROJECT_NAME}_Core PUBLIC diff --git a/arch/configure_reader.py b/arch/configure_reader.py index 98f758e0b8..c52d776af7 100755 --- a/arch/configure_reader.py +++ b/arch/configure_reader.py @@ -504,6 +504,7 @@ def generateCMakeToolChainFile( cmakeToolChainTemplate, output, stanza, optionsD configStanza = cmakeToolChainTemplateLines.format( ARCH_LOCAL=stanza.kvPairs_["ARCH_LOCAL"], + LDFLAGS_LOCAL=stanza.kvPairs_["LDFLAGS_LOCAL"], BYTESWAPIO=stanza.kvPairs_["BYTESWAPIO"], CFLAGS_LOCAL=stanza.kvPairs_["CFLAGS_LOCAL"], DM_CC=stanza.kvPairs_["DM_CC"], @@ -587,4 +588,4 @@ def projectSpecificOptions( options, stanzaCfg ) : return additionalOptions if __name__ == '__main__' : - main() \ No newline at end of file + main() diff --git a/cmake/c_preproc.cmake b/cmake/c_preproc.cmake index 4de0a1e7a1..0d0dd751ef 100644 --- a/cmake/c_preproc.cmake +++ b/cmake/c_preproc.cmake @@ -117,9 +117,12 @@ macro( wrf_expand_definitions ) else() list( APPEND WRF_EXP_DEFS -D${WRF_EXP_DEF} ) endif() + else() + # Just add it normally + list( APPEND WRF_EXP_DEFS ${WRF_EXP_DEF} ) endif() endforeach() set( ${WRF_EXP_RESULT_VAR} ${WRF_EXP_DEFS} ) -endmacro() \ No newline at end of file +endmacro() diff --git a/cmake/target_source_properties.cmake b/cmake/target_source_properties.cmake new file mode 100644 index 0000000000..64bd47379b --- /dev/null +++ b/cmake/target_source_properties.cmake @@ -0,0 +1,142 @@ +# +# These two functions together allow greater control of propagating flags within +# a target on a per-source basis with the ability to "inherit" those properties +# from the target if not set. This allows a target to defing its own flags, but +# then if a file needs different settings those can be directly overridden without +# relying on compiler-specific flag order precedence. Additionally this allows a +# project to organize grouping of flags within a target +# +# Note that for compile defines on source files they are not used in the autogen +# dependency scanning. See : +# https://gitlab.kitware.com/cmake/cmake/-/issues/22519 +# and +# https://gitlab.kitware.com/cmake/cmake/-/blob/master/Source/cmDependsFortran.cxx#L84 +# functions cmDependsFortran::cmDependsFortran() and cmDependsFortran::WriteDependencies() +# +# The solution is to either use Ninja or preprocess the files (what Ninja internally does) +# This is probably the way to go as well since CMake native preprocessor directive +# parsing is... subpar and simplified : +# https://gitlab.kitware.com/cmake/cmake/-/issues/17398 +# +# Alternatively, set critical flags at the target level +# + + + +# +# A simple function to create properties for targets and sources quickly +# +function( define_target_source_properties ) + set( options ) + set( oneValueArgs ) + set( multiValueArgs PROPERTIES ) + + cmake_parse_arguments( + FUNC_PROP + "${options}" "${oneValueArgs}" "${multiValueArgs}" + ${ARGN} + ) + + foreach( PROPERTY ${FUNC_PROP_PROPERTIES} ) + define_property( + SOURCE + PROPERTY ${PROPERTY} + # INHERITED # they will be "inherited" via target to source + ) + + define_property( + TARGET + PROPERTY ${PROPERTY} + # INHERITED # they will be "inherited" via target to source + ) + endforeach() +endfunction() + + +# +# The bulk of the functionality exists in this function. It will loop over each +# provided target, gathering sources and their respective properties listed, using +# the target's property if not defined for this source else nothing, and finally +# applies it to that source. +# +function( apply_target_source_properties ) + set( options DISCARD_PREVIOUS DEBUG ) + set( oneValueArgs AS_PROPERTY ) + set( multiValueArgs TARGETS PROPERTIES ) + + cmake_parse_arguments( + FUNC_PROP + "${options}" "${oneValueArgs}" "${multiValueArgs}" + ${ARGN} + ) + + foreach( TARGET ${FUNC_PROP_TARGETS} ) + # get target sources + get_target_property( TARGET_SOURCES ${TARGET} SOURCES ) + + # get default "inherited" value from target + foreach( PROPERTY ${FUNC_PROP_PROPERTIES} ) + get_target_property( TARGET_PROPERTY_${PROPERTY} ${TARGET} ${PROPERTY} ) + if ( "${TARGET_PROPERTY_${PROPERTY}}" STREQUAL "TARGET_PROPERTY_${PROPERTY}-NOTFOUND" ) + # unset it + set( TARGET_PROPERTY_${PROPERTY} ) + endif() + endforeach() + + foreach( SOURCE ${TARGET_SOURCES} ) + + # We need to accumulate properties since a call to set property will + # override what was there before + set( SOURCE_PROPERTY_ALL ) + + foreach( PROPERTY ${FUNC_PROP_PROPERTIES} ) + # first try source + get_source_file_property( + SOURCE_PROPERTY_${PROPERTY} + ${SOURCE} + TARGET_DIRECTORY ${TARGET} + ${PROPERTY} + ) + if ( "${SOURCE_PROPERTY_${PROPERTY}}" STREQUAL "NOTFOUND" ) + # use target + set( SOURCE_PROPERTY_${PROPERTY} ${TARGET_PROPERTY_${PROPERTY}} ) + endif() + + # Now apply these as prop + if ( NOT "${SOURCE_PROPERTY_${PROPERTY}}" STREQUAL "" ) + if ( ${FUNC_PROP_DEBUG} ) + message( STATUS "DEBUG : Adding '${SOURCE_PROPERTY_${PROPERTY}}' as SOURCE_PROPERTY_${PROPERTY}") + endif() + list( APPEND SOURCE_PROPERTY_ALL ${SOURCE_PROPERTY_${PROPERTY}} ) + endif() + endforeach() # properties + + # Apply properties to source + if ( NOT "${SOURCE_PROPERTY_ALL}" STREQUAL "" ) + if ( NOT ${FUNC_PROP_DISCARD_PREVIOUS} ) + # get old value and append + get_source_file_property( + SOURCE_PROPERTY_ORIG + ${SOURCE} + TARGET_DIRECTORY ${TARGET} + ${FUNC_PROP_AS_PROPERTY} + ) + if ( "${SOURCE_PROPERTY_ORIG}" STREQUAL "NOTFOUND" ) + set( SOURCE_PROPERTY_ORIG ) + endif() + endif() + + if ( ${FUNC_PROP_DEBUG} ) + message( STATUS "DEBUG : ${FUNC_PROP_AS_PROPERTY} being set to '${SOURCE_PROPERTY_ORIG} ${SOURCE_PROPERTY_ALL}'") + endif() + + set_source_files_properties( + ${SOURCE} + TARGET_DIRECTORY ${TARGET} + PROPERTIES + ${FUNC_PROP_AS_PROPERTY} "${SOURCE_PROPERTY_ORIG};${SOURCE_PROPERTY_ALL}" + ) + endif() + endforeach() # sources + endforeach() # targets +endfunction() diff --git a/cmake/template/arch_config.cmake b/cmake/template/arch_config.cmake index 42cba60287..0a655a4e32 100644 --- a/cmake/template/arch_config.cmake +++ b/cmake/template/arch_config.cmake @@ -15,15 +15,16 @@ set( CMAKE_Fortran_FLAGS_INIT "{SFC_FLAGS} {FCBASEOPTS} {BYTESWAPIO}" ) set( CMAKE_C_FLAGS_INIT "{SCC_FLAGS} {CFLAGS_LOCAL}" ) # https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_CONFIG_INIT.html -set( CMAKE_Fortran_FLAGS_DEBUG_INIT "{FCDEBUG}" ) -set( CMAKE_Fortran_FLAGS_RELEASE_INIT "" ) -set( CMAKE_C_FLAGS_DEBUG_INIT "" ) -set( CMAKE_C_FLAGS_RELEASE_INIT "" ) +set( CMAKE_Fortran_FLAGS_Debug_INIT "{FCDEBUG}" ) +set( CMAKE_Fortran_FLAGS_Release_INIT "" ) +set( CMAKE_C_FLAGS_Debug_INIT "" ) +set( CMAKE_C_FLAGS_Release_INIT "" ) # Project specifics now -set( WRF_MPI_Fortran_FLAGS "{DM_FC_FLAGS}" ) -set( WRF_MPI_C_FLAGS "{DM_CC_FLAGS}" ) -set( WRF_ARCH_LOCAL "{ARCH_LOCAL}" ) -set( WRF_M4_FLAGS "{M4_FLAGS}" ) -set( WRF_FCOPTIM "{FCOPTIM}" ) -set( WRF_FCNOOPT "{FCNOOPT}" ) \ No newline at end of file +set( WRF_MPI_Fortran_FLAGS "{DM_FC_FLAGS}" ) +set( WRF_MPI_C_FLAGS "{DM_CC_FLAGS}" ) +set( WRF_ARCH_LOCAL "{ARCH_LOCAL}" ) +set( WRF_M4_FLAGS "{M4_FLAGS}" ) +set( WRF_FCOPTIM "{FCOPTIM}" ) +set( WRF_FCNOOPT "{FCNOOPT}" ) +set( WRF_LINK_FLAGS "{LDFLAGS_LOCAL}" ) diff --git a/frame/CMakeLists.txt b/frame/CMakeLists.txt index 85264c7d5f..4543c4694e 100644 --- a/frame/CMakeLists.txt +++ b/frame/CMakeLists.txt @@ -156,7 +156,7 @@ target_sources( set_source_files_properties( ${nl_dyn_source} PROPERTIES - COMPILE_FLAGS + COMPILE_OPTIONS_OPTIMIZATION $<$:${WRF_FCNOOPT}> )