diff --git a/.VERSION b/.VERSION new file mode 100644 index 000000000..6ff366451 --- /dev/null +++ b/.VERSION @@ -0,0 +1,13 @@ +$Format:%d%n%n$ +# Fall back version, probably last release: +1.9.3 + +# OpenCoarrays version file. This project uses semantic +# versioning. For details see http://semver.org +# +# Release archive created from commit: +# $Format:%H %d$ +# $Format:Created on %ci by %cN, and$ +# $Format:signed by %GS using %GK.$ +# $Format:Signature status: %G?$ +$Format:%GG$ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..caa9633a4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,743 @@ +cmake_minimum_required(VERSION 3.2) + +# Set the type/configuration of build to perform +set ( CMAKE_CONFIGURATION_TYPES "Debug" "Release" "MinSizeRel" "RelWithDebInfo" "CodeCoverage" ) +set ( CMAKE_BUILD_TYPE "Release" + CACHE STRING "Select which configuration to build." ) +set_property ( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_CONFIGURATION_TYPES} ) + +# Add option and check environment to determine if developer tests should be run +if($ENV{OPENCOARRAYS_DEVELOPER}) + option(CAF_RUN_DEVELOPER_TESTS "Run tests intended only for developers" ON) +else() + option(CAF_RUN_DEVELOPER_TESTS "Run tests intended only for developers" OFF) +endif() +mark_as_advanced(CAF_RUN_DEVELOPER_TESTS) + +if( NOT DEFINED ENV{OPENCOARRAYS_DEVELOPER}) + set ( ENV{OPENCOARRAYS_DEVELOPER} FALSE ) +endif() + +# Name project and specify source languages +# Parse version from .VERSION file so that more info can be added and easier to get from scripts +file(STRINGS ".VERSION" first_line + LIMIT_COUNT 1 + ) + +string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" + OpenCoarraysVersion "${first_line}") + +if((NOT (OpenCoarraysVersion MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")) AND (EXISTS "${CMAKE_SOURCE_DIR}/.git")) + message( STATUS "Build from git repository detected") + find_package(Git) + if(GIT_FOUND) + execute_process(COMMAND "${GIT_EXECUTABLE}" describe --abbrev=0 + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE git_status + OUTPUT_VARIABLE git_output + OUTPUT_STRIP_TRAILING_WHITESPACE) + if((git_status STREQUAL "0") AND (git_output MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")) + set(OpenCoarraysVersion "${git_output}") + endif() + execute_process(COMMAND "${GIT_EXECUTABLE}" describe --always + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE git_status + OUTPUT_VARIABLE full_git_describe + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT (git_status STREQUAL "0")) + set(full_git_describe NOTFOUND) + endif() + # Create a source distribution target using git archive + # e.g., `make dist` will package a release using current git state + add_custom_target(dist # OUTPUT "${CMAKE_BINARY_DIR}/${_OC_stem_name}.tar.gz" + COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/makeDist.cmake" "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" + COMMENT "Creating source release asset, ${_OC_stem_name}.tar.gz, from ${git_full_describe} using the `git archive` command." + VERBATIM) + else() + message( WARNING "Could not find git executable!") + endif() +endif() + +if(NOT (OpenCoarraysVersion MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")) + message( WARNING "Could not extract version from git, falling back on .VERSION, line 3.") + file(STRINGS ".VERSION" OpenCoarraysVersion + REGEX "[0-9]+\\.[0-9]+\\.[0-9]+" + ) +endif() + +if(NOT full_git_describe) + set(full_git_describe ${OpenCoarraysVersion}) +endif() + +project(opencoarrays VERSION "${OpenCoarraysVersion}" LANGUAGES C Fortran) +message( STATUS "Building OpenCoarrays version: ${full_git_describe}" ) +set(OpenCoarrays_dist_string "OpenCoarrays-${full_git_describe}") + +#Print an error message on an attempt to build inside the source directory tree: +if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") + message(FATAL_ERROR "ERROR! " + "CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}" + " == CMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}" + "\nThis archive does not support in-source builds:\n" + "You must now delete the CMakeCache.txt file and the CMakeFiles/ directory under " + "the 'src' source directory or you will not be able to configure correctly!" + "\nYou must now run something like:\n" + " $ rm -r CMakeCache.txt CMakeFiles/" + "\n" + "Please create a directory outside the opencoarrays source tree and build under that outside directory " + "in a manner such as\n" + " $ mkdir build-opencarrays\n" + " $ cd build-opencoarrays\n" + " $ CC=gcc FC=gfortran cmake -DBUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/path/to/install/dir /path/to/opencoarrays/src/dir \n" + "\nsubstituting the appropriate syntax for your shell (the above line assumes the bash shell)." + ) +endif() + +#Report untested Fortran compiler unless explicitly directed to build all examples. +if ("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU" ) + set(gfortran_compiler true) + set ( CMAKE_C_FLAGS_CODECOVERAGE "-fprofile-arcs -ftest-coverage -O0" + CACHE STRING "Code coverage C compiler flags") + set ( CMAKE_Fortran_FLAGS_CODECOVERAGE "-fprofile-arcs -ftest-coverage -O0" + CACHE STRING "Code coverage Fortran compiler flags") +else() + message(WARNING + "\n" + "Attempting to build with untested Fortran compiler: ${CMAKE_Fortran_COMPILER_ID}. " + "Please report any failures to opencoarrays@googlegroups.com\n\n" + ) +endif() + +#----------------------------------------------------------------- +# Set CMAKE_Fortran_COMPILER_VERSION if CMake doesn't do it for us +#----------------------------------------------------------------- +if ( NOT CMAKE_Fortran_COMPILER_VERSION ) + if ( NOT (CMAKE_VERSION VERSION_LESS 3.3.1) ) + message( AUTHOR_WARNING + "CMake ${CMAKE_VERSION} should know about Fortran compiler versions but is missing CMAKE_Fortran_COMPILER_VERSION variable." + ) + endif() + # No CMAKE_Fortran_COMPILER_VERSION set, build our own + # Try extracting it directly from ISO_FORTRAN_ENV's compiler_version + # Write program for introspection + file( WRITE "${CMAKE_BINARY_DIR}/get_compiler_ver.f90" + "program main + use iso_fortran_env, only: compiler_version, output_unit + write(output_unit,'(a)') compiler_version() +end program" + ) + try_run( PROG_RAN COMPILE_SUCCESS + "${CMAKE_BINARY_DIR}" "${CMAKE_BINARY_DIR}/get_compiler_ver.f90" + RUN_OUTPUT_VARIABLE VER_STRING + ) + if ( COMPILE_SUCCESS ) + string( REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" + DETECTED_VER "${VER_STRING}" + ) + message( STATUS "Detected Fortran compiler as ${VER_STRING}" ) + message( STATUS "Extracted version number: ${DETECTED_VER}" ) + endif() + if( ( NOT COMPILE_SUCCESS ) OR ( NOT DETECTED_VER ) ) + message( WARNING "Could not reliably detect Fortran compiler version. We'll infer it from +the C compiler if it matches the Fortran compiler ID." ) + endif() + if( "${CMAKE_C_COMPILER_ID}" MATCHES "${CMAKE_Fortran_COMPILER_ID}" ) + set( DETECTED_VER "${CMAKE_C_COMPILER_VERSION}" ) + else() + message( FATAL_ERROR "Exhausted all possible means of detecting the Fortran compiler version, cannot proceed!" ) + endif() + set( CMAKE_Fortran_COMPILER_VERSION "${DETECTED_VER}" ) +endif() + + # We have populated CMAKE_Fortran_COMPILER_VERSION if it was missing + if(gfortran_compiler AND (CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER 5.0.0)) + set(opencoarrays_aware_compiler true) + add_definitions(-DPREFIX_NAME=_gfortran_caf_) + else() + set(opencoarrays_aware_compiler false) + add_definitions(-DPREFIX_NAME=_caf_extensions_) + endif() + if(gfortran_compiler AND (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 5.4.0)) + # GCC patch to fix issue accepted for 5.4 release + # See https://github.com/sourceryinstitute/opencoarrays/issues/28 and + # https://groups.google.com/forum/#!msg/opencoarrays/RZOwwYTqG80/46S9eL696dgJ + message( STATUS "Disabling optimization flags due to GCC < 5.4 bug") + set(CMAKE_Fortran_FLAGS_RELEASE -O0 + CACHE STRING "Flags used by the compiler during release builds." FORCE) + set(CMAKE_Fortran_FLAGS_RELWITHDEBINFO "-g -DNDEBUG -O0" + CACHE STRING "Flags used by the compiler during release builds with debug info" FORCE) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -O0") + endif() + if ( gfortran_compiler AND ( NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 7.0.0 ) ) + add_definitions(-DGCC_GE_7) # Tell library to build against GFortran 7.x bindings b/c we might be using clang for C + endif() + if ( gfortran_compiler AND ( NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 8.0.0 ) ) + add_definitions(-DGCC_GE_8) # Tell library to build against GFortran 8.x bindings w/ descriptor change + endif() + +if(gfortran_compiler) + set(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "-fcoarray=single -ffree-form") +endif() +include(CheckFortranSourceCompiles) +CHECK_Fortran_SOURCE_COMPILES(" + program main + implicit none + integer :: i + i = this_image() + end program +" Check_Simple_Coarray_Fortran_Source_Compiles) +if(gfortran_compiler) + set (CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) + unset(OLD_REQUIRED_FLAGS) +endif() + + +#---------------------------------------------------------------------------- +# Find MPI and set some flags so that FC and CC can point to gfortran and gcc +#---------------------------------------------------------------------------- + +# If the user passes FC=mpifort etc. check and prefer that location +get_filename_component( FTN_COMPILER_NAME "${CMAKE_Fortran_COMPILER}" + NAME ) +get_filename_component( C_COMPILER_NAME "${CMAKE_C_COMPILER}" + NAME ) +get_filename_component( FTN_COMPILER_DIR "${CMAKE_Fortran_COMPILER}" + REALPATH ) +get_filename_component( C_COMPILER_DIR "${CMAKE_C_COMPILER}" + REALPATH ) + +if (FTN_COMPILER_NAME MATCHES "^[mM][pP][iI]") + set (MPI_Fortran_COMPILER "${CMAKE_Fortran_COMPILER}") +endif() +if (C_COMPILER_NAME MATCHES "^[mM][pP][iI]") + set (MPI_C_COMPILER "${CMAKE_C_COMPILER}") +endif() + +find_package( MPI ) + +if ( (NOT MPI_C_FOUND) OR (NOT MPI_Fortran_FOUND) OR (NOT MPIEXEC)) + # Get default install location of MPICH from install.sh + execute_process( COMMAND "./install.sh" -P mpich + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE DEFAULT_MPICH_INSTALL_LOC + OUTPUT_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + find_program (MY_MPI_EXEC NAMES mpirun mpiexec lamexec srun + PATHS "${DEFAULT_MPICH_INSTALL_LOC}" ENV PATH + HINTS "${FTN_COMPILER_DIR}" "${C_COMPILER_DIR}" + PATH_SUFFIXES bin) + set ( MPI_HOME "${MPI_HOME}" "${MY_MPI_EXEC}" "${MY_MPI_EXEC}/.." ) + find_package( MPI REQUIRED ) +endif() +list(REMOVE_DUPLICATES MPI_Fortran_INCLUDE_PATH) + +# Test for consistent MPI environment +if (NOT MPIEXEC) + message ( ERROR "CMake failed to find `mpiexec` or similar. If building with `./install.sh` please +report this bug to the OpenCoarrays developers at +https://github.com/sourceryinstitute/opencoarrays/issues, otherwise point CMake +to the desired MPI runtime.") +endif() + +get_filename_component(MPIEXEC_RELATIVE_LOC "${MPIEXEC}" + PROGRAM) +get_filename_component(MPIEXEC_ABS_LOC "${MPIEXEC_RELATIVE_LOC}" + REALPATH) +get_filename_component(MPIEXEC_DIR "${MPIEXEC_ABS_LOC}" + DIRECTORY) + +get_filename_component(MPICC_RELATIVE_LOC "${MPI_C_COMPILER}" + PROGRAM) +get_filename_component(MPICC_ABS_LOC "${MPICC_RELATIVE_LOC}" + REALPATH) +get_filename_component(MPICC_DIR "${MPICC_ABS_LOC}" + DIRECTORY) + +get_filename_component(MPIFC_RELATIVE_LOC "${MPI_Fortran_COMPILER}" + PROGRAM) +get_filename_component(MPIFC_ABS_LOC "${MPIFC_RELATIVE_LOC}" + REALPATH) +get_filename_component(MPIFC_DIR "${MPIFC_ABS_LOC}" + DIRECTORY) + +if ((MPIEXEC_DIR STREQUAL MPICC_DIR) AND (MPIEXEC_DIR STREQUAL MPIFC_DIR)) + message ( STATUS "MPI runtime and compile time environments appear to be consistent") +else() + message ( WARNING "MPIEXEC is in \"${MPIEXEC_DIR},\" +which differs from the location of MPICC and/or MPIFC which are in +\"${MPICC_DIR}\" and \"${MPIFC_DIR},\" respectively. +This is likely indicative of a problem. If building with `./install.sh` please report +this to the OpenCoarrays developers by filing a new issue at: +https://github.com/sourceryinstitute/OpenCoarrays/issues/new") +endif() + +#----------------------------------------------- +# Work around bug #317 present on fedora systems +#----------------------------------------------- +if( (MPI_C_LINK_FLAGS MATCHES "noexecstack") OR (MPI_Fortran_LINK_FLAGS MATCHES "noexecstack") ) + message ( WARNING +"The `noexecstack` linker flag was found in the MPI__LINK_FLAGS variable. This is +known to cause segmentation faults for some Fortran codes. See, e.g., +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71729 or +https://github.com/sourceryinstitute/OpenCoarrays/issues/317. + +`noexecstack` is being replaced with `execstack`" + ) + string(REPLACE "noexecstack" + "execstack" MPI_C_LINK_FLAGS_FIXED ${MPI_C_LINK_FLAGS}) + string(REPLACE "noexecstack" + "execstack" MPI_Fortran_LINK_FLAGS_FIXED ${MPI_Fortran_LINK_FLAGS}) + set(MPI_C_LINK_FLAGS "${MPI_C_LINK_FLAGS_FIXED}" CACHE STRING + "MPI C linking flags" FORCE) + set(MPI_Fortran_LINK_FLAGS "${MPI_Fortran_LINK_FLAGS_FIXED}" CACHE STRING + "MPI Fortran linking flags" FORCE) +endif() + +#-------------------------------------------------------- +# Make sure a simple "hello world" C mpi program compiles +#-------------------------------------------------------- +set(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) +set(CMAKE_REQUIRED_FLAGS ${MPI_C_COMPILE_FLAGS} ${MPI_C_LINK_FLAGS}) +set(OLD_INCLUDES ${CMAKE_REQUIRED_INCLUDES}) +set(CMAKE_REQUIRED_INCLUDES ${MPI_C_INCLUDE_PATH}) +set(OLD_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) +set(CMAKE_REQUIRED_LIBRARIES ${MPI_C_LIBRARIES}) +include (CheckCSourceCompiles) +CHECK_C_SOURCE_COMPILES(" +#include +#include +int main(int argc, char** argv) { + MPI_Init(NULL, NULL); + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + char processor_name[MPI_MAX_PROCESSOR_NAME]; + int name_len; + MPI_Get_processor_name(processor_name, &name_len); + printf('Hello world from processor %s, rank %d out of %d processors', + processor_name, world_rank, world_size); + MPI_Finalize(); +}" +MPI_C_COMPILES) +set(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) +set(CMAKE_REQUIRED_INCLUDES ${OLD_INCLUDES}) +set(CMAKE_REQUIRED_LIBRARIES ${OLD_LIBRARIES}) +unset(OLD_REQUIRED_FLAGS) +unset(OLD_INCLUDES) +unset(OLD_LIBRARIES) + +if (NOT MPI_C_COMPILES) + message(FATAL_ERROR "MPI_C is missing! " + "Try setting MPI_C_COMPILER to the appropriate C compiler wrapper script and reconfigure. " + "i.e., `cmake -DMPI_C_COMPILER=/path/to/mpicc ..` or set it by editing the cache using " + "cmake-gui or ccmake." + ) +endif() + +#-------------------------------------------------------------- +# Make sure a simple "hello world" Fortran mpi program compiles +# Try using mpi.mod first then fall back on includ 'mpif.h' +#-------------------------------------------------------------- +set(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) +set(CMAKE_REQUIRED_FLAGS "-ffree-form" ${MPI_Fortran_COMPILE_FLAGS} ${MPI_Fortran_LINK_FLAGS}) +set(OLD_INCLUDES ${CMAKE_REQUIRED_INCLUDES}) +set(CMAKE_REQUIRED_INCLUDES ${MPI_Fortran_INCLUDE_PATH}) +set(OLD_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) +set(CMAKE_REQUIRED_LIBRARIES ${MPI_Fortran_LIBRARIES}) +include (CheckFortranSourceCompiles) +CHECK_Fortran_SOURCE_COMPILES(" +program mpi_hello +use mpi +implicit none +integer :: ierr, mpi_world_size, mpi_world_rank, res_len +character*(MPI_MAX_PROCESSOR_NAME) :: proc +call mpi_init(ierr) +call mpi_comm_size(MPI_COMM_WORLD,mpi_world_size,ierr) +call mpi_comm_rank(MPI_COMM_WORLD,mpi_world_rank,ierr) +call mpi_get_processor_name(proc,res_len,ierr) +write(*,*) 'Hello from processor ', trim(proc), ' rank ', mpi_world_rank, ' out of ', mpi_world_size, '.' +call mpi_finalize(ierr) +end program +" +MPI_Fortran_MODULE_COMPILES) +set(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) +set(CMAKE_REQUIRED_INCLUDES ${OLD_INCLUDES}) +set(CMAKE_REQUIRED_LIBRARIES ${OLD_LIBRARIES}) +unset(OLD_REQUIRED_FLAGS) +unset(OLD_INCLUDES) +unset(OLD_LIBRARIES) + +#-------------------------------- +# If that failed try using mpif.h +#-------------------------------- +set(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) +set(CMAKE_REQUIRED_FLAGS "-ffree-form" ${MPI_Fortran_COMPILE_FLAGS} ${MPI_Fortran_LINK_FLAGS}) +set(OLD_INCLUDES ${CMAKE_REQUIRED_INCLUDES}) +set(CMAKE_REQUIRED_INCLUDES ${MPI_Fortran_INCLUDE_PATH}) +set(OLD_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) +set(CMAKE_REQUIRED_LIBRARIES ${MPI_Fortran_LIBRARIES}) +include (CheckFortranSourceCompiles) +CHECK_Fortran_SOURCE_COMPILES(" +program mpi_hello +implicit none +include 'mpif.h' +integer :: ierr, mpi_world_size, mpi_world_rank, res_len +character*(MPI_MAX_PROCESSOR_NAME) :: proc +call mpi_init(ierr) +call mpi_comm_size(MPI_COMM_WORLD,mpi_world_size,ierr) +call mpi_comm_rank(MPI_COMM_WORLD,mpi_world_rank,ierr) +call mpi_get_processor_name(proc,res_len,ierr) +write(*,*) 'Hello from processor ', trim(proc), ' rank ', mpi_world_rank, ' out of ', mpi_world_size, '.' +call mpi_finalize(ierr) +end program +" + MPI_Fortran_INCLUDE_COMPILES) +set(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) +set(CMAKE_REQUIRED_INCLUDES ${OLD_INCLUDES}) +set(CMAKE_REQUIRED_LIBRARIES ${OLD_LIBRARIES}) +unset(OLD_REQUIRED_FLAGS) +unset(OLD_INCLUDES) +unset(OLD_LIBRARIES) + +if ( (NOT MPI_Fortran_MODULE_COMPILES) AND (NOT MPI_Fortran_INCLUDE_COMPILES) ) + message ( WARNING "It appears that the Fortran MPI compiler is not working. " + "For OpenCoarrays Aware compilers, this may be irrelavent: " + " The src/extensions/opencoarrays.F90 module will be disabled, but it is " + " possible that the build will succeed, despite this fishy circumstance." + ) +endif() + +if ( MPI_Fortran_MODULE_COMPILES ) + add_definitions(-DMPI_WORKING_MODULE) +else() + message ( WARNING "It appears that MPI was built with a different Fortran compiler. " + "It is possible that this may cause unpredictable behavior. The build will continue " + "using `mpif.h` BUT please report any suspicious behavior to the OpenCoarrays " + "developers." + ) +endif() + +#---------------- +# Setup MPI flags +#---------------- +set(CMAKE_C_COMPILE_FLAGS ${CMAKE_C_COMPILE_FLAGS} ${MPI_C_COMPILE_FLAGS}) +set(CMAKE_C_LINK_FLAGS ${CMAKE_C_LINK_FLAGS} ${MPI_C_LINK_FLAGS}) +set(CMAKE_Fortran_COMPILE_FLAGS ${CMAKE_Fortran_COMPILE_FLAGS} ${MPI_Fortran_COMPILE_FLAGS}) +set(CMAKE_Fortran_LINK_FLAGS ${CMAKE_Fortran_LINK_FLAGS} ${MPI_Fortran_LINK_FLAGS}) +include_directories(BEFORE ${MPI_C_INCLUDE_PATH} ${MPI_Fortran_INCLUDE_PATH}) + +#--------------------------------------------------- +# Use standardized GNU install directory conventions +#--------------------------------------------------- +include(GNUInstallDirs) +set(mod_dir_tail "${OpenCoarrays_dist_string}_${CMAKE_Fortran_COMPILER_ID}-${CMAKE_Fortran_COMPILER_VERSION}") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/${OpenCoarrays_dist_string}-tests") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +#----------------- +# Install manpages +#----------------- +install(FILES "${CMAKE_SOURCE_DIR}/doc/man/man1/caf.1" "${CMAKE_SOURCE_DIR}/doc/man/man1/cafrun.1" + DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + COMPONENT documentation) + +#--------------------------------------------------- +# Define macro for compiling with caf wrapper script +#--------------------------------------------------- +function(caf_compile_executable target main_depend) + foreach(includedir IN LISTS MPI_Fortran_INCLUDE_PATH) + set(includes ${includes} -I ${includedir}) + endforeach() + string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) + separate_arguments(config_Fortran_flags UNIX_COMMAND "${CMAKE_Fortran_FLAGS_${build_type}}") + get_directory_property( DirDefs DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS ) + set(localDefs "") + foreach(d ${DirDefs}) + list(APPEND localDefs "-D${d}") + endforeach() + add_custom_command(OUTPUT "${target}" + COMMAND "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/caf" ${includes} ${localDefs} ${config_Fortran_flags} -o "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target}" "${CMAKE_CURRENT_SOURCE_DIR}/${main_depend}" ${ARGN} + DEPENDS "${main_depend}" ${ARGN} caf_mpi_static + VERBATIM + ) + add_custom_target("build_${target}" ALL + DEPENDS "${target}") +endfunction(caf_compile_executable) + +enable_testing() + +#-------------------------------------------------------- +# Setup shellcheck if present for testing/linting scripts +#-------------------------------------------------------- +find_program(SHELLCHECK_EXE shellcheck + DOC "Path to shellcheck executable for linting scripts" + ) +if (CAF_RUN_DEVELOPER_TESTS OR $ENV{OPENCOARRAYS_DEVELOPER}) + if(NOT SHELLCHECK_EXE) + message( AUTHOR_WARNING "OpenCoarrays developers should install shellcheck to test/lint all shell scripts. + See https://github.com/koalaman/shellcheck#installing for info on obtaining shellcheck.") + endif() +endif() + +function(lint_script script_dir script_name) + if (SHELLCHECK_EXE) + add_test(NAME "shellcheck:${script_name}" + COMMAND ${SHELLCHECK_EXE} -x "${script_dir}/${script_name}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") + elseif (CAF_RUN_DEVELOPER_TESTS OR $ENV{OPENCOARRAYS_DEVELOPER}) + message( AUTHOR_WARNING "test: shellcheck:${script_name} not run because shellcheck not installed." ) + endif() +endfunction() + +#----------------------------------------------- +# Setup script style testing & enforcement macro +#----------------------------------------------- + +find_program(style_pl style.pl "${CMAKE_SOURCE_DIR}/developer-scripts/") +function(check_script_style script_full_path) + if(style_pl) + add_test(NAME "style:${script_full_path}" + COMMAND "${style_pl}" "${script_full_path}") + endif() +endfunction() + +#------------------------------------------------------------------------------ +# Add custom properties on targets for controling number of images during tests +#------------------------------------------------------------------------------ +define_property(TARGET + PROPERTY MIN_IMAGES + BRIEF_DOCS "Minimum allowable images for the test " + FULL_DOCS "Property to mark executable targets run as tests that they require at least images to run" + ) + +define_property(TARGET + PROPERTY POWER_2_IMGS + BRIEF_DOCS "True if test must be run with a power of 2 images (T/F)" + FULL_DOCS "Property to mark executable targets run as tests that they require 2^n images." + ) + + +#------------------------------- +# Recurse into the src directory +#------------------------------- +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/src) + +add_subdirectory(src) + +#----------------------------------------------------- +# Publicize installed location to other CMake projects +#----------------------------------------------------- +install(EXPORT OpenCoarraysTargets + NAMESPACE + OpenCoarrays:: + DESTINATION + "${CMAKE_INSTALL_LIBDIR}/cmake/opencoarrays" +) +include(CMakePackageConfigHelpers) # standard CMake module +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/OpenCoarraysConfigVersion.cmake" + VERSION "${opencoarrays_VERSION}" + COMPATIBILITY AnyNewerVersion +) +configure_file("${CMAKE_SOURCE_DIR}/cmake/pkg/OpenCoarraysConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/OpenCoarraysConfig.cmake" @ONLY) + +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/OpenCoarraysConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/OpenCoarraysConfigVersion.cmake" + DESTINATION + "${CMAKE_INSTALL_LIBDIR}/cmake/opencoarrays" +) + +add_library(OpenCoarrays INTERFACE) +target_compile_options(OpenCoarrays INTERFACE -fcoarray=lib) +target_link_libraries(OpenCoarrays INTERFACE caf_mpi) + +#------------------------------------------ +# Add portable unistall command to makefile +#------------------------------------------ +# Adapted from the CMake Wiki FAQ +configure_file ( "${CMAKE_SOURCE_DIR}/cmake/uninstall.cmake.in" "${CMAKE_BINARY_DIR}/uninstall.cmake" + @ONLY) + +add_custom_target ( uninstall + COMMAND ${CMAKE_COMMAND} -P "${CMAKE_BINARY_DIR}/uninstall.cmake" ) + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure) +# See JSON-Fortran's CMakeLists.txt file to find out how to get the check target to depend +# on the test executables + +#--------------------------------------------------------------------------------------- +# Define macro for adding CAF tests, and ensuring proper flags are passed to MPI runtime +#--------------------------------------------------------------------------------------- + +# Determine if we're using Open MPI +execute_process(COMMAND ${MPIEXEC} --version + OUTPUT_VARIABLE mpi_version_out) +if (mpi_version_out MATCHES "[Oo]pen[ -][Mm][Pp][Ii]") + message( STATUS "OpenMPI detected") + set ( openmpi true ) +endif () + +include( ProcessorCount ) +ProcessorCount(N_CPU) +function(add_caf_test name num_caf_img test_target) + # Function to add MPI tests. + if(TARGET ${test_target}) + get_target_property(min_test_imgs ${test_target} MIN_IMAGES) + elseif(TARGET build_${test_target}) + get_target_property(min_test_imgs build_${test_target} MIN_IMAGES) + endif() + if(min_test_imgs) + if(num_caf_img LESS min_test_imgs) + message( FATAL_ERROR "Test ${name} requires ${min_test_imgs} but was only given ${num_caf_images}" ) + endif() + endif() + if ( ((N_CPU LESS num_caf_img) OR (N_CPU EQUAL 0)) ) + message(STATUS "Test ${name} is oversubscribed: ${num_caf_img} CAF images requested with ${N_CPU} system processor available.") + if ( openmpi ) + if (min_test_imgs) + set( num_caf_img ${min_test_imgs} ) + elseif ( N_CPU LESS 2 ) + set( num_caf_img 2 ) + endif() + set (test_parameters --oversubscribe) + message( STATUS "Open-MPI back end detected, passing --oversubscribe for oversubscribed test, ${name}, with ${num_caf_img} ranks/images." ) + endif() + endif() + set(test_parameters -np ${num_caf_img} ${test_parameters}) + add_test(NAME ${name} COMMAND "bash" "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/cafrun" ${test_parameters} "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test_target}") + set_property(TEST ${name} PROPERTY PASS_REGULAR_EXPRESSION "Test passed.") +endfunction(add_caf_test) + +#-------------- +# Add OCA tests +#-------------- + +if(opencoarrays_aware_compiler) + if (CAF_RUN_DEVELOPER_TESTS OR $ENV{OPENCOARRAYS_DEVELOPER}) + message ( STATUS "Running Developer tests is enabled." ) + endif() + # Unit tests targeting each libcaf_mpi function, argument, and branch of code + add_caf_test(initialize_mpi 2 initialize_mpi) + add_caf_test(register 2 register) + add_caf_test(register_vector 2 register_vector) + add_caf_test(register_alloc_vector 2 register_alloc_vector) + add_caf_test(allocate_as_barrier 2 allocate_as_barrier) + add_caf_test(allocate_as_barrier_proc 8 allocate_as_barrier_proc) + if (gfortran_compiler AND (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 7.0.0) OR (CAF_RUN_DEVELOPER_TESTS OR $ENV{OPENCOARRAYS_DEVELOPER})) + message( STATUS "Allocatable components of coarray derived types only supported in GFortran >= 7 with OpenCoarrays > 1.8.4" ) + message( STATUS "(but full support not anticipated until OpenCoarrays 2.0 release)" ) + if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 7.0.0) + message( AUTHOR_WARNING "Allocatable components of coarray derived type developer tests enabled, despite lack of support in GFortran < 7\n These tests should fail." ) + endif() + add_caf_test(register_alloc_comp_1 2 register_alloc_comp_1) + add_caf_test(register_alloc_comp_2 2 register_alloc_comp_2) + add_caf_test(register_alloc_comp_3 2 register_alloc_comp_3) + add_caf_test(async_comp_alloc 6 async_comp_alloc) + add_caf_test(async_comp_alloc_2 2 async_comp_alloc_2) + add_caf_test(comp_allocated_1 2 comp_allocated_1) + add_caf_test(comp_allocated_2 2 comp_allocated_2) + endif() + add_caf_test(get_array 2 get_array) + add_caf_test(get_self 2 get_self) + add_caf_test(send_array 2 send_array) + add_caf_test(get_with_offset_1d 2 get_with_offset_1d) + add_caf_test(whole_get_array 2 whole_get_array) + add_caf_test(strided_get 2 strided_get) + add_caf_test(strided_sendget 3 strided_sendget) + add_caf_test(co_sum 4 co_sum_test) + add_caf_test(co_broadcast 4 co_broadcast_test) + add_caf_test(co_min 4 co_min_test) + add_caf_test(co_max 4 co_max_test) + add_caf_test(syncall 8 syncall) + add_caf_test(syncimages 8 syncimages) + add_caf_test(syncimages2 8 syncimages2) + add_caf_test(duplicate_syncimages 8 duplicate_syncimages) + add_caf_test(co_reduce 4 co_reduce_test) + add_caf_test(co_reduce_res_im 4 co_reduce_res_im) + add_caf_test(co_reduce_string 4 co_reduce_string) + add_caf_test(syncimages_status 8 syncimages_status) + add_caf_test(sync_ring_abort_np3 3 sync_image_ring_abort_on_stopped_image) + add_caf_test(sync_ring_abort_np7 7 sync_image_ring_abort_on_stopped_image) + add_caf_test(simpleatomics 8 atomics) + # possible logic error in the following test +# add_caf_test(increment_my_neighbor 32 increment_my_neighbor) + + # Integration tests verifying the use of libcaf_mpi in applications + add_caf_test(hello_multiverse 2 hello_multiverse) + add_caf_test(coarray_burgers_pde 2 coarray_burgers_pde) + add_caf_test(co_heat 2 co_heat) + add_caf_test(asynchronous_hello_world 3 asynchronous_hello_world) + + # Regression tests based on reported issues + if((gfortran_compiler AND (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 7.0.0)) OR (CAF_RUN_DEVELOPER_TESTS OR $ENV{OPENCOARRAYS_DEVELOPER})) + if( CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 7.0.0 ) + message( AUTHOR_WARNING "Developer tests requested and GFortran < 7: test source-alloc-no-sync may fail" ) + endif() + # GFortran PR 78505 only fixed on trunk/gcc 7, issue #243 + add_caf_test(source-alloc-no-sync 8 source-alloc-sync) + endif() + + # Open GCC 7 regressions + if ((CAF_RUN_DEVELOPER_TESTS OR $ENV{OPENCOARRAYS_DEVELOPER}) OR (gfortran_compiler AND (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 7.0.0))) + add_caf_test(convert-before-put 3 convert-before-put) + add_caf_test(put-alloc-comp 2 issue-422-send) + add_caf_test(get-put-alloc-comp 3 issue-422-send-get) + endif() + + add_caf_test(allocatable_p2p_event_post 4 allocatable_p2p_event_post) + # Fixed GCC 7 regressions, should run on GCC 6 and 7 + add_caf_test(static_event_post_issue_293 3 static_event_post_issue_293) + + # These co_reduce (#172, fixed by PR #332, addl discussion in PR + # #331) tests are for bugs not regressions. Should be fixed in all + # version of GCC, I beleive + add_caf_test(co_reduce-factorial 4 co_reduce-factorial) + add_caf_test(co_reduce-factorial-int8 4 co_reduce-factorial-int8) + add_caf_test(co_reduce-factorial-int64 4 co_reduce-factorial-int64) + + # IMAGE FAIL tests + if(NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 7.0.0) + add_caf_test(image_status_test_1 4 image_status_test_1) + if(CAF_ENABLE_FAILED_IMAGES) + if ((NOT DEFINED ENV{TRAVIS}) OR (CAF_RUN_DEVELOPER_TESTS OR $ENV{OPENCOARRAYS_DEVELOPER})) + add_caf_test(image_fail_test_1 4 image_fail_test_1) + set_property(TEST image_fail_test_1 PROPERTY FAIL_REGULAR_EXPRESSION "Test failed.") + # No other way to check that image_fail_test_1 passes. + add_caf_test(image_fail_and_sync_test_1 4 image_fail_and_sync_test_1) + add_caf_test(image_fail_and_sync_test_2 4 image_fail_and_sync_test_2) + + add_caf_test(image_fail_and_sync_test_3 4 image_fail_and_sync_test_3) + add_caf_test(image_fail_and_status_test_1 4 image_fail_and_status_test_1) + add_caf_test(image_fail_and_failed_images_test_1 4 image_fail_and_failed_images_test_1) + add_caf_test(image_fail_and_stopped_images_test_1 4 image_fail_and_stopped_images_test_1) + add_caf_test(image_fail_and_get_test_1 4 image_fail_and_get_test_1) + endif() + endif() + endif() +else() + add_test(co_sum_extension test-co_sum-extension.sh) + set_property(TEST co_sum_extension PROPERTY PASS_REGULAR_EXPRESSION "Test passed.") + + add_test(co_broadcast_extension test-co_broadcast-extension.sh) + set_property(TEST co_broadcast_extension PROPERTY PASS_REGULAR_EXPRESSION "Test passed.") + + add_test(co_min_extension test-co_min-extension.sh) + set_property(TEST co_min_extension PROPERTY PASS_REGULAR_EXPRESSION "Test passed.") + + add_test(co_max_extension test-co_max-extension.sh) + set_property(TEST co_max_extension PROPERTY PASS_REGULAR_EXPRESSION "Test passed.") + + add_test(co_reduce_extension test-co_reduce-extension.sh) + set_property(TEST co_reduce_extension PROPERTY PASS_REGULAR_EXPRESSION "Test passed.") +endif() + +include(cmake/AddInstallationScriptTest.cmake ) +add_installation_script_test(installation-scripts.sh src/tests/installation/)