Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not merge yet: Portable CMake project #154

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 136 additions & 28 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,25 @@ set(libROM_CMAKE_PATH ${CMAKE_SOURCE_DIR}/cmake)
set(libROM_CMAKE_MODULE_PATH ${libROM_CMAKE_PATH}/modules)
list(APPEND CMAKE_MODULE_PATH ${libROM_CMAKE_MODULE_PATH})

option(USE_MFEM "Build libROM with MFEM" OFF)
option(MFEM_USE_GSLIB "Build libROM with MFEM using GSLIB" OFF)
option(BUILD_STATIC "Build libROM as a static library" OFF)
# Load libROM CMake utilities.
include(libROMCmakeUtilities)

# Get some version-related names
string(TOUPPER "${PROJECT_NAME}" PROJECT_NAME_UC)
librom_version_to_int(${${PROJECT_NAME}_VERSION} ${PROJECT_NAME_UC}_VERSION)
set(${PROJECT_NAME_UC}_VERSION_STRING ${${PROJECT_NAME}_VERSION})
if (EXISTS ${PROJECT_SOURCE_DIR}/.git)
execute_process(
COMMAND git describe --all --long --abbrev=40 --dirty --always
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
OUTPUT_VARIABLE ${PROJECT_NAME_UC}_GIT_STRING
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
if (NOT ${PROJECT_NAME_UC}_GIT_STRING)
set(${PROJECT_NAME_UC}_GIT_STRING "(unknown)")
endif()

option(LIBROM_USE_MFEM "Build libROM with MFEM" OFF)
option(ENABLE_EXAMPLES "Build examples and regression tests" ON)

## Set a bunch of variables to generate a configure header
Expand Down Expand Up @@ -111,14 +127,18 @@ find_package(Doxygen 1.8.5)

find_package(GTest 1.6.0)

if (USE_MFEM)
find_library(MFEM mfem "${CMAKE_SOURCE_DIR}/dependencies/mfem" "${MFEM_DIR}/lib")
find_library(HYPRE HYPRE "${CMAKE_SOURCE_DIR}/dependencies/hypre/src/hypre/lib" "${HYPRE_DIR}/lib")
find_library(PARMETIS parmetis "${CMAKE_SOURCE_DIR}/dependencies/parmetis-4.0.3/build/lib/libparmetis" "${PARMETIS_DIR}/lib")
find_library(METIS metis "${CMAKE_SOURCE_DIR}/dependencies/parmetis-4.0.3/build/lib/libmetis" "${METIS_DIR}/lib")
find_path(MFEM_INCLUDES mfem.hpp "${CMAKE_SOURCE_DIR}/dependencies/mfem" "${MFEM_DIR}/include")
find_path(HYPRE_INCLUDES HYPRE.h "${CMAKE_SOURCE_DIR}/dependencies/hypre/src/hypre/include" "${HYPRE_DIR}/include")
find_path(PARMETIS_INCLUDES metis.h "${CMAKE_SOURCE_DIR}/dependencies/parmetis-4.0.3/metis/include" "${PARMETIS_DIR}/metis/include")
set(DEPS HDF5::HDF5 BLAS::BLAS LAPACK::LAPACK
MPI::MPI_C MPI::MPI_CXX MPI::MPI_Fortran ZLIB::ZLIB)

if (LIBROM_USE_MFEM)
find_package(MFEM 4.5.0 REQUIRED)
if (NOT ${MFEM_USE_MPI})
message(FATAL_ERROR, "MFEM does not have MPI support")
endif()
if (NOT ${MFEM_USE_MUMPS})
message(FATAL_ERROR, "MFEM does not have MUMPS support")
endif()
list(APPEND DEPS MFEM::mfem)
endif()

add_subdirectory(lib)
Expand All @@ -128,7 +148,7 @@ add_subdirectory(lib)
target_compile_features(ROM PRIVATE cxx_std_11)

if (ENABLE_EXAMPLES)
if (USE_MFEM)
if (LIBROM_USE_MFEM)
set(examples
poisson_global_rom
poisson_local_rom_greedy
Expand Down Expand Up @@ -171,11 +191,9 @@ if (ENABLE_EXAMPLES)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/examples/${example_dir})
add_executable(${name} examples/${example_dir}/${name}.cpp)

target_link_libraries(${name}
PRIVATE ROM ${MPI_C_LINK_FLAGS} ${MPI_C_LIBRARIES} MPI::MPI_C ${MPI_FORTRAN_LINK_FLAGS} ${MPI_FORTRAN_LIBRARIES} MPI::MPI_Fortran)
target_link_libraries(${name} PRIVATE ROM)
target_include_directories(${name}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${MPI_C_INCLUDE_DIRS})
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/lib)
target_compile_features(${name} PRIVATE cxx_std_11)
endforeach() # IN LISTS examples
file(COPY examples/data DESTINATION ${CMAKE_BINARY_DIR}/examples)
Expand All @@ -190,11 +208,9 @@ if (ENABLE_EXAMPLES)
foreach(name IN LISTS misc_example_names)
add_executable(${name} examples/misc/${name}.cpp)

target_link_libraries(${name}
PRIVATE ROM ${MPI_C_LINK_FLAGS} ${MPI_C_LIBRARIES} MPI::MPI_C ${MPI_FORTRAN_LINK_FLAGS} ${MPI_FORTRAN_LIBRARIES} MPI::MPI_Fortran)
target_link_libraries(${name} PRIVATE ROM)
target_include_directories(${name}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${MPI_C_INCLUDE_DIRS})
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/lib)
target_compile_features(${name} PRIVATE cxx_std_11)
endforeach(name) # IN LISTS misc_exmaple_names

Expand All @@ -212,11 +228,9 @@ if (ENABLE_EXAMPLES)
foreach(name IN LISTS regression_test_names)
add_executable(${name} tests/${name}.cpp)

target_link_libraries(${name}
PRIVATE ROM ${MPI_C_LINK_FLAGS} ${MPI_C_LIBRARIES} MPI::MPI_C ${MPI_FORTRAN_LINK_FLAGS} ${MPI_FORTRAN_LIBRARIES} MPI::MPI_Fortran)
target_link_libraries(${name} PRIVATE ROM)
target_include_directories(${name}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${MPI_C_INCLUDE_DIRS})
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/lib)
target_compile_features(${name} PRIVATE cxx_std_11)
endforeach(name) # IN LISTS regression_test_names
endif(ENABLE_EXAMPLES)
Expand All @@ -237,11 +251,9 @@ if(GTEST_FOUND)
GreedyCustomSampler)
foreach(stem IN LISTS unit_test_stems)
add_executable(test_${stem} tests/test_${stem}.cpp)
target_link_libraries(test_${stem} PRIVATE ROM
${MPI_C_LINK_FLAGS} ${MPI_C_LIBRARIES} MPI::MPI_C ${MPI_FORTRAN_LINK_FLAGS} ${MPI_FORTRAN_LIBRARIES} MPI::MPI_Fortran GTest::GTest)
target_link_libraries(test_${stem} PRIVATE ROM ${DEPS} GTest::GTest)
target_include_directories(test_${stem}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${MPI_C_INCLUDE_DIRS})
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/lib)
target_compile_features(test_${stem} PRIVATE cxx_std_11)
target_compile_definitions(test_${stem} PRIVATE CAROM_HAS_GTEST)
endforeach(stem) # IN LISTS unit_test_stems
Expand Down Expand Up @@ -270,3 +282,99 @@ if(DOXYGEN_FOUND)
add_dependencies(doxygen_tagfile documentation)

endif(DOXYGEN_FOUND)

#-------------------------------------------------------------------------------
# Installation
#-------------------------------------------------------------------------------

message(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")
set(INSTALL_INCLUDE_DIR include
CACHE PATH "Relative path for installing header files.")
set(INSTALL_LIB_DIR lib
CACHE PATH "Relative path for installing the library.")
set(INSTALL_CMAKE_DIR lib/cmake/librom
CACHE PATH "Relative path for installing cmake config files.")

# The "INSTALL_INTERFACE" folder shall be
# $<INSTALL_INTERFACE:${INSTALL_INCLUDE_DIR} after fixing
# https://github.com/LLNL/libROM/issues/156
target_include_directories(ROM
INTERFACE
$<INSTALL_INTERFACE:${INSTALL_INCLUDE_DIR}/librom>)

set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Development)

# Install the library
install(TARGETS ROM
EXPORT libROMTargets
DESTINATION ${INSTALL_LIB_DIR})

# Install the headers
foreach(Header librom.h FCMangle.h)
install(FILES ${CMAKE_SOURCE_DIR}/lib/${Header}
DESTINATION ${INSTALL_INCLUDE_DIR}/librom/)
endforeach()
install(FILES ${PROJECT_BINARY_DIR}/lib/CAROM_config.h
DESTINATION ${INSTALL_INCLUDE_DIR}/librom/)

foreach(Folder algo hyperreduction linalg utils)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/${Folder}
DESTINATION ${INSTALL_INCLUDE_DIR}/librom/
FILES_MATCHING PATTERN "*.h")
endforeach()

if (LIBROM_USE_MFEM)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib/mfem
DESTINATION ${INSTALL_INCLUDE_DIR}/librom/
FILES_MATCHING PATTERN "*.hpp")
endif()

# Package the whole thing up nicely
include(CMakePackageConfigHelpers)

# Add all targets to the build-tree export set
export(TARGETS ROM
FILE "${PROJECT_BINARY_DIR}/libROMTargets.cmake")

# Export the package for use from the build-tree (this registers the build-tree
# with the CMake user package registry.)
# TODO: How do we register the install-tree? Replacing the build-tree?
export(PACKAGE ${PROJECT_NAME})

# This is the build-tree version
set(INCLUDE_INSTALL_DIRS ${PROJECT_BINARY_DIR})
set(LIB_INSTALL_DIR ${PROJECT_BINARY_DIR})
configure_package_config_file(cmake/libROMConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/libROMConfig.cmake
INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
PATH_VARS INCLUDE_INSTALL_DIRS LIB_INSTALL_DIR)

# This is the version that will be installed
set(INCLUDE_INSTALL_DIRS ${INSTALL_INCLUDE_DIR})
set(LIB_INSTALL_DIR ${INSTALL_LIB_DIR})
configure_package_config_file(cmake/libROMConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libROMConfig.cmake
INSTALL_DESTINATION ${INSTALL_CMAKE_DIR}
PATH_VARS INCLUDE_INSTALL_DIRS LIB_INSTALL_DIR)

# Write the version file (same for build and install tree)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/libROMConfigVersion.cmake
VERSION ${${PROJECT_NAME}_VERSION}
COMPATIBILITY SameMajorVersion )

# Install the config files
install(FILES
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libROMConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/libROMConfigVersion.cmake
DESTINATION ${INSTALL_CMAKE_DIR})

# Install the export set for use with the install-tree
install(EXPORT libROMTargets
NAMESPACE libROM::
DESTINATION ${INSTALL_CMAKE_DIR})

# Install the modules directory, so it can be used to find the dependencies
install(DIRECTORY config/cmake/modules
DESTINATION ${INSTALL_CMAKE_DIR}
FILES_MATCHING PATTERN "*.cmake")
48 changes: 48 additions & 0 deletions cmake/libROMConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the libROM library. For more information and source code
# availability visit https://mfem.org.
#
# libROM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.

include(CMakeFindDependencyMacro)
include(${CMAKE_CURRENT_LIST_DIR}/libROMConfigVersion.cmake)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/modules)

set(libROM_VERSION ${PACKAGE_VERSION})

# MPI needs to link against MPI::C MPI::CXX or MPI::Fortran
enable_language(C)
enable_language(CXX)
enable_language(Fortran)
find_dependency(MPI)
find_dependency(HDF5)
find_dependency(BLAS)
find_dependency(LAPACK)
find_dependency(ZLIB)

set(LIBROM_USE_MFEM @LIBROM_USE_MFEM@)
if(LIBROM_USE_MFEM)
find_dependency(MFEM)
endif()

@PACKAGE_INIT@

set(libROM_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIRS@")
foreach (dir ${libROM_INCLUDE_DIRS})
set_and_check(libROM_INCLUDE_DIR "${dir}")
endforeach (dir "${libROM_INCLUDE_DIRS}")

set_and_check(libROM_LIBRARY_DIR "@PACKAGE_LIB_INSTALL_DIR@")

check_required_components(libROM)

if (NOT TARGET librom)
include(${CMAKE_CURRENT_LIST_DIR}/libROMTargets.cmake)
endif (NOT TARGET librom)

set(libROM_LIBRARIES librom)
34 changes: 34 additions & 0 deletions cmake/modules/libROMCmakeUtilities.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.

# Function that converts a version string of the form 'major[.minor[.patch]]' to
# the integer ((major * 100) + minor) * 100 + patch.
function(librom_version_to_int VersionString VersionIntVar)
if ("${VersionString}" MATCHES "^([0-9]+)(.*)$")
set(Major "${CMAKE_MATCH_1}")
set(MinorPatchString "${CMAKE_MATCH_2}")
else()
set(Major 0)
endif()
if ("${MinorPatchString}" MATCHES "^\\.([0-9]+)(.*)$")
set(Minor "${CMAKE_MATCH_1}")
set(PatchString "${CMAKE_MATCH_2}")
else()
set(Minor 0)
endif()
if ("${PatchString}" MATCHES "^\\.([0-9]+)(.*)$")
set(Patch "${CMAKE_MATCH_1}")
else()
set(Patch 0)
endif()
math(EXPR VersionInt "(${Major}*100+${Minor})*100+${Patch}")
set(${VersionIntVar} ${VersionInt} PARENT_SCOPE)
endfunction()
45 changes: 9 additions & 36 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ FortranCInterface_HEADER(${CMAKE_CURRENT_SOURCE_DIR}/FCMangle.h
MACRO_NAMESPACE "CAROM_FC_")

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CAROM_config.h.in
${CMAKE_CURRENT_SOURCE_DIR}/CAROM_config.h @ONLY)
${CMAKE_CURRENT_BINARY_DIR}/CAROM_config.h @ONLY)

# While it is tempting to use file globbing here, file globbing is
# considered a "modern CMake anti-pattern" because "CMake is not a
Expand Down Expand Up @@ -64,7 +64,7 @@ list(APPEND source_files
linalg/Options.h
librom.h)

if (USE_MFEM)
if (LIBROM_USE_MFEM)
list(APPEND source_files
mfem/PointwiseSnapshot.hpp
mfem/PointwiseSnapshot.cpp
Expand All @@ -77,28 +77,9 @@ endif()
list(APPEND source_files
linalg/scalapack_c_wrapper.c
linalg/scalapack_f_wrapper.f90)
if (BUILD_STATIC)
add_library(ROM ${source_files})
else()
add_library(ROM SHARED ${source_files})
endif()

# If MKL libraries not found, search for reference ScaLAPACK. If MKL
# libraries found, search for MKL ScaLAPACK; if MKL ScaLAPACK not
# found, search for reference ScaLAPACK. It seems that only
if (BLAS_LIBRARIES MATCHES ".*mkl.*")
find_package(MKL COMPONENTS BLACS ScaLAPACK)
if (NOT MKL_ScaLAPACK_FOUND)
find_package(ScaLAPACK REQUIRED)
target_link_libraries(ROM PUBLIC ${ScaLAPACK_LIBRARIES})
else()
target_link_libraries(ROM PUBLIC ${MKL_ScaLAPACK_LIBRARY} ${MKL_BLACS_LIBRARY} ${MKL_LIBRARIES})
target_include_directories(ROM PUBLIC ${MKL_INCLUDE_DIRS})
endif()
else() # BLAS or LAPACK isn't MKL
find_package(ScaLAPACK REQUIRED)
target_link_libraries(ROM PUBLIC ${ScaLAPACK_LIBRARIES})
endif()
# The type of library can be set by means of BUILD_SHARED_LIBS CMake global
# variable
add_library(ROM ${source_files})

# PUBLIC dependencies are transitive; these dependencies are used in
# the API headers *and* in their implementations
Expand All @@ -114,17 +95,9 @@ endif()
# (i.e., "MPI_C_LINK_FLAGS, MPI_C_LIBRARIES) is probably redundant,
# but is done here to ease a potential rollback to CMake 2.8 or CMake
# 3.0.
target_link_libraries(ROM
PUBLIC ${MPI_C_LINK_FLAGS} ${MPI_C_LIBRARIES} MPI::MPI_C ${MPI_FORTRAN_LINK_FLAGS} ${MPI_FORTRAN_LIBRARIES} MPI::MPI_Fortran ${HDF5_LIBRARIES}
${LAPACK_LIBRARIES} ${BLAS_LIBRARIES} ${MFEM} ${HYPRE} ${PARMETIS} ${METIS}
PRIVATE ${ZLIB_LIBRARIES} ZLIB::ZLIB)
target_link_libraries(ROM PUBLIC ${DEPS})

target_include_directories(ROM PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${MFEM_INCLUDES}
${HYPRE_INCLUDES}
${PARMETIS_INCLUDES}
${HDF5_C_INCLUDE_DIRS}
${MPI_C_INCLUDE_DIRS}
${MFEM_C_INCLUDE_DIRS}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)