# This file is part of P^nMPI.
#
# Copyright (c)
#  2008-2019 Lawrence Livermore National Laboratories, United States of America
#  2011-2016 ZIH, Technische Universitaet Dresden, Federal Republic of Germany
#  2013-2019 RWTH Aachen University, Federal Republic of Germany
#
#
# P^nMPI is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation version 2.1 dated February 1999.
#
# P^nMPI is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with P^nMPI; if not, write to the
#
#   Free Software Foundation, Inc.
#   51 Franklin St, Fifth Floor
#   Boston, MA 02110, USA
#
#
# Written by Martin Schulz, schulzm@llnl.gov.
#
# LLNL-CODE-402774

include(CheckFortranMPIFunctionExists)
include(CheckMPIFunctionExists)
include(easylib)


# Feature checks.
#
# Some functionality of PnMPI is dependent on the features of the used MPI
# library. However, as most of the functions are just wrapped calls generated by
# wrap, just the initializations functions of the MPI-2 standard need to be
# checked.
check_mpi_function_exists(MPI_Init_thread HAVE_MPI_INIT_THREAD_C)
if (ENABLE_FORTRAN)
  check_fortran_mpi_function_exists(MPI_INIT_THREAD
    HAVE_MPI_INIT_THREAD_Fortran)
endif ()

# If C11 was found, add the C11 compiler flags, so C11 thread local storage can
# be used by PnMPI. Separate flags for the subdirectories are not required, as
# setting this variable will set it for the subdirectories, too.
if (C11_FOUND)
  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C11_FLAGS}")
endif ()


# Include common include directories.
#
# Instead of including the same directories in the recursive directories, the
# common ones will be included before recursing for sharing.
include_directories(
  ${PROJECT_BINARY_DIR}
  ${CMAKE_CURRENT_BINARY_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}
  ${MPI_C_INCLUDE_PATH}
)

# Recurse into subdirectories.
#
# This has to be done BEFORE adding the PnMPI libraries, because for adding
# PnMPI with its object libraries, the easylib functions need to know about the
# available object libraries. Otherwise the compilation of PnMPI will result in
# errors, as easylib would select the static object library for the shared PnMPI
# library.

# Sources for the PnMPI libraries used by all libraries.
#
# Note: The apple linker does not support reordering of constructors, so files
#       containing a constructor must be listed in the order they should be
#       executed.
set(PNMPI_LIB_SOURCES
  initialize.c
  finalize.c

  core.c
  wrapper.c
  print_banner.c
)


add_subdirectory(compiler)
add_subdirectory(debug)
add_subdirectory(modules)
add_subdirectory(service)
add_subdirectory(wrapper)

# Install and manage the public and private header files of the PnMPI sources.
# This has to be done to use the same headers for the PnMPI sources and the API
# without getting conflicts about the used paths. Otherwise you'd have to take
# care about file locations after installation, especially if you use the
# headers over multiple directories.
#
# Some headers will be generated by wrap, so the internal function
# pnmpi_add_header can't be used and the files will be installed manually.
add_wrapped_file("header/pnmpi/private/pmpi.h" pmpi.h.w -s)
add_wrapped_file("header/pnmpi/newstack.h" newstack.h.w -w)
add_wrapped_file("header/pnmpi/xmpi.h" xmpi.h.w -w)

install(FILES
          "${PNMPI_HEADER_DIR}/pnmpi/newstack.h"
          "${PNMPI_HEADER_DIR}/pnmpi/xmpi.h"
        DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/pnmpi")

pnmpi_add_private_header(config.h.in config.h)
pnmpi_add_private_header(force_link.h)
pnmpi_add_private_header(initialization.h)


add_wrapped_file(wrapper.h   wrapper.h.w -w)
add_wrapped_file(wrapper_c.c wrapper_c.c.w -w)

set(PNMPI_ADDITIONAL_FILES "")
if (ENABLE_FORTRAN)
  set(PNMPI_ADDITIONAL_FILES "${CMAKE_CURRENT_BINARY_DIR}/wrapper_cf.c")
  add_wrapped_file(wrapper_cf.c wrapper_c.c.w -f -w)
endif ()


# Add a new target for all generated files. This can be referenced as dependency
# for other targets, if they use any of the generated files.
add_custom_target(generate DEPENDS
  ${PNMPI_HEADER_DIR}/pnmpi/private/pmpi.h
  ${PNMPI_HEADER_DIR}/pnmpi/newstack.h
  ${PNMPI_HEADER_DIR}/pnmpi/xmpi.h
  ${CMAKE_CURRENT_BINARY_DIR}/wrapper_c.c
  ${CMAKE_CURRENT_BINARY_DIR}/wrapper.h
  ${PNMPI_ADDITIONAL_FILES})


# Add linkage to adept utils if we have it
if (PnMPI_USE_adept_utils)
  include_directories(BEFORE ${adept_utils_INCLUDE_PATH} ${adept-utils_INCLUDE_DIRS})
endif()




# PnMPI shared library
easy_add_library(pnmpi SHARED ${PNMPI_LIB_SOURCES})
add_dependencies(pnmpi generate pnmpi_debug_pmpi)
add_coverage(pnmpi)
add_sanitizers(pnmpi)
target_link_libraries(pnmpi
  ${MPI_C_LIBRARIES}
  -ldl)

set_target_properties(pnmpi PROPERTIES VERSION
  ${PNMPI_VERSION_MAJOR}.${PNMPI_VERSION_MINOR}.${PNMPI_VERSION_PATCH}
  SOVERSION ${PNMPI_VERSION_MAJOR})

 if(APPLE)
    get_target_property(TEMP_FLAG pnmpi LINK_FLAGS)
    string(TOUPPER "${TEMP_FLAG}" TEMP_CAPITAL_FLAG)
    if(${TEMP_CAPITAL_FLAG} STREQUAL "TEMP_FLAG-NOTFOUND")
      set(TEMP_FLAG "")
    endif()
    set (TEMP_FLAG "${TEMP_FLAG} -undefined dynamic_lookup")
    set_target_properties(pnmpi PROPERTIES LINK_FLAGS ${TEMP_FLAG})
  endif()

# PnMPI static library (same output name as shared lib)
easy_add_library(pnmpi_static STATIC ${PNMPI_LIB_SOURCES} force_link.c)
add_dependencies(pnmpi_static generate pnmpi_debug_pmpi)
set_target_properties(pnmpi_static PROPERTIES OUTPUT_NAME pnmpi)

#copy header files to include directory in binary dir
install(FILES pnmpi.h pnmpimod.h DESTINATION include)
install(TARGETS pnmpi_static pnmpi EXPORT pnmpi-libs DESTINATION lib)

#
# Fortran support (If Fortran was enabled)
#
if (CMAKE_Fortran_COMPILER_WORKS)
  if(NOT HAVE_MPI_F_STATUS_SIZE)
    list(APPEND PNMPI_LIB_SOURCES ${Wrap_EXTRA_SOURCE})
  endif()

  # PnMPI fortran shared library
  easy_add_library(pnmpif SHARED ${PNMPI_LIB_SOURCES})
  add_coverage(pnmpif)
  add_sanitizers(pnmpif)
  add_dependencies(pnmpif generate pnmpi_debug_pmpi)
  target_link_libraries(pnmpif
    ${MPI_Fortran_LIBRARIES}
    -ldl)
  if(MPI_Fortran_F77_HEADER_DIR)
    target_include_directories(pnmpif PUBLIC ${MPI_Fortran_F77_HEADER_DIR})
  endif()

  set_target_properties(pnmpif PROPERTIES VERSION
    ${PNMPI_VERSION_MAJOR}.${PNMPI_VERSION_MINOR}.${PNMPI_VERSION_PATCH}
    SOVERSION ${PNMPI_VERSION_MAJOR})

  if(CMAKE_Fortran_COMPILER_WORKS)
    get_target_property(TEMP_FLAG pnmpif COMPILE_FLAGS)
    string(TOUPPER "${TEMP_FLAG}" TEMP_CAPITAL_FLAG)
    if(${TEMP_CAPITAL_FLAG} STREQUAL "TEMP_FLAG-NOTFOUND")
      set(TEMP_FLAG "")
    endif()
    set(TEMP_FLAG "${TEMP_FLAG} -DCOMPILE_FOR_FORTRAN")
    set_target_properties(pnmpif PROPERTIES COMPILE_FLAGS ${TEMP_FLAG})
  endif()
  if(APPLE)
    get_target_property(TEMP_FLAG pnmpif LINK_FLAGS)
    string(TOUPPER "${TEMP_FLAG}" TEMP_CAPITAL_FLAG)
    if(${TEMP_CAPITAL_FLAG} STREQUAL "TEMP_FLAG-NOTFOUND")
      set(TEMP_FLAG "")
    endif()
    set(TEMP_FLAG "${TEMP_FLAG} -undefined dynamic_lookup")
    set_target_properties(pnmpif PROPERTIES LINK_FLAGS ${TEMP_FLAG})
  endif()

  # PnMPI fortran static lib
  easy_add_library(pnmpif_static STATIC ${PNMPI_LIB_SOURCES} force_link.c)
  add_dependencies(pnmpif_static generate pnmpi_debug_pmpi)
  set_target_properties(pnmpif_static PROPERTIES OUTPUT_NAME   pnmpif)
  set_target_properties(pnmpif_static PROPERTIES COMPILE_FLAGS "-DCOMPILE_FOR_FORTRAN")

  #Install pnmpi core for Fortran with reasonable file permissions
  install(TARGETS pnmpif pnmpif_static EXPORT pnmpi-libs DESTINATION lib)
endif()

# file to export pnmpi-libs
install(
  EXPORT pnmpi-libs
  DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/PnMPI
)
