cmake_minimum_required(VERSION 2.8.12.2...3.15 FATAL_ERROR) # Setup cmake policies. foreach(policy CMP0012 CMP0013 CMP0014 CMP0022 # CMake 2.8.12 CMP0025 # CMake 3.0 CMP0053 # CMake 3.1 CMP0054 # CMake 3.1 CMP0074 # CMake 3.12 CMP0075 # CMake 3.12 CMP0083 # CMake 3.14 CMP0093 # CMake 3.15 CMP0167 # CMake 3.30 ) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() # Set a consistent MACOSX_RPATH default across all CMake versions. # When CMake 2.8.12 is required, change this default to 1. # When CMake 3.0.0 is required, remove this block (see CMP0042). if(NOT DEFINED CMAKE_MACOSX_RPATH) set(CMAKE_MACOSX_RPATH 0) endif() project(MERCURY C) #------------------------------------------------------------------------------ # Setup install and output Directories #------------------------------------------------------------------------------ if(NOT MERCURY_INSTALL_BIN_DIR) set(MERCURY_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/bin) endif() if(NOT MERCURY_INSTALL_LIB_DIR) set(MERCURY_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib) endif() if(NOT MERCURY_INSTALL_INCLUDE_DIR) # Interface include will default to prefix/include set(MERCURY_INSTALL_INTERFACE include) set(MERCURY_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_PREFIX}/include) else() set(MERCURY_INSTALL_INTERFACE ${MERCURY_INSTALL_INCLUDE_DIR}) endif() if(NOT MERCURY_INSTALL_DATA_DIR) set(MERCURY_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/share) endif() # Setting this ensures that "make install" will leave rpaths to external # libraries intact on "make install". This ensures that one can install a # version of Mercury on the build machine without any issues. If this not # desired, simply specify CMAKE_INSTALL_RPATH_USE_LINK_PATH when configuring # Mercury and "make install" will strip all rpaths, which is default behavior. if(NOT CMAKE_INSTALL_RPATH_USE_LINK_PATH) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif() #------------------------------------------------------------------------------ # Set module path #------------------------------------------------------------------------------ set(MERCURY_CMAKE_MODULE_PATH "${MERCURY_SOURCE_DIR}/CMake") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MERCURY_CMAKE_MODULE_PATH}) #------------------------------------------------------------------------------ # Version information #------------------------------------------------------------------------------ include(${MERCURY_CMAKE_MODULE_PATH}/Git/Git.cmake) include(MercuryDetermineVersion) # Hard-coded version variables are read-in from a separate file. This makes it # easier to have a script to update version numbers automatically. file(STRINGS version.txt version_txt) extract_version_components("${version_txt}" "${PROJECT_NAME}") determine_version(${MERCURY_SOURCE_DIR} ${GIT_EXECUTABLE} "${PROJECT_NAME}") set(MERCURY_PACKAGE "mercury") set(MERCURY_PACKAGE_NAME "Mercury") set(MERCURY_PACKAGE_DESCRIPTION "RPC for High-Performance Computing") set(MERCURY_PACKAGE_URL "http://mercury-hpc.github.io/") set(MERCURY_PACKAGE_VENDOR "Argonne National Laboratory / The HDF Group") message(STATUS "Configuring ${MERCURY_PACKAGE} v${MERCURY_VERSION_FULL}") #------------------------------------------------------------------------------ # Setup CMake Environment #------------------------------------------------------------------------------ if(APPLE AND NOT MERCURY_EXTERNALLY_CONFIGURED) # We are doing a unix-style install i.e. everything will be installed in # CMAKE_INSTALL_PREFIX/bin and CMAKE_INSTALL_PREFIX/lib etc. as on other unix # platforms. We still need to setup CMAKE_INSTALL_NAME_DIR correctly so that # the binaries point to appropriate location for the libraries. # 1. Make CMAKE_INSTALL_PREFIX publicly accessible, if it was hidden in # previous pass get_property(is_internal CACHE CMAKE_INSTALL_PREFIX PROPERTY TYPE) if(is_internal STREQUAL "INTERNAL") set(CMAKE_INSTALL_PREFIX ${CACHED_CMAKE_INSTALL_PREFIX} CACHE PATH "Install prefix" FORCE) else() set(CMAKE_INSTALL_PREFIX ${CACHED_CMAKE_INSTALL_PREFIX} CACHE PATH "Install prefix") endif() unset(MACOSX_APP_INSTALL_PREFIX CACHE) mark_as_advanced( CMAKE_OSX_ARCHITECTURES CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT ) endif() #------------------------------------------------------------------------------ if(NOT MERCURY_EXTERNALLY_CONFIGURED) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin CACHE PATH "Single Directory for all Executables." ) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin CACHE PATH "Single Directory for all Libraries" ) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin CACHE PATH "Single Directory for all static libraries." ) endif() #------------------------------------------------------------------------------ # Disallow in-source build #------------------------------------------------------------------------------ if(NOT CMAKE_IN_SOURCE_BUILD AND "${MERCURY_SOURCE_DIR}" STREQUAL "${MERCURY_BINARY_DIR}") message(FATAL_ERROR "Mercury requires an out of source Build. " "Please create a separate binary directory and run CMake there.") endif() #------------------------------------------------------------------------------ # Set a default build type if none was specified #------------------------------------------------------------------------------ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.") set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo" "Asan" "Tsan" "Ubsan") endif() if(NOT CMAKE_C_FLAGS AND CMAKE_COMPILER_IS_GNUCC) message(STATUS "GCC detected, setting additional flags") set(CMAKE_C_FLAGS "-Wall -Wextra -Winline -Wcast-qual -std=gnu99 -Wshadow" CACHE STRING "Flags used by the compiler during all build types." FORCE) endif() # Detect Asan/Tsan/Ubsan compiler flags include(CheckAsan) include(CheckTsan) include(CheckUbsan) #----------------------------------------------------------------------------- # Targets built within this project are exported at Install time for use # by other projects. #----------------------------------------------------------------------------- if(NOT MERCURY_EXPORTED_TARGETS) set(MERCURY_EXPORTED_TARGETS "${MERCURY_PACKAGE}-targets") endif() #------------------------------------------------------------------------------ # Choose static or shared libraries. #------------------------------------------------------------------------------ option(BUILD_SHARED_LIBS "Build with shared libraries." OFF) if(BUILD_SHARED_LIBS) set(HG_BUILD_SHARED_LIBS 1) set(MERCURY_LIBTYPE SHARED) else() set(HG_BUILD_SHARED_LIBS 0) set(MERCURY_LIBTYPE STATIC) endif() #------------------------------------------------------------------------------ # Enable debug output. #------------------------------------------------------------------------------ option(MERCURY_ENABLE_DEBUG "Enable debug statements." OFF) if(MERCURY_ENABLE_DEBUG) set(HG_HAS_DEBUG 1) # Always enable counters if debug is turned ON set(MERCURY_ENABLE_COUNTERS "ON" CACHE BOOL "Enable diagnostics counters (enabled with debug)." FORCE) else() set(HG_HAS_DEBUG 0) endif() #------------------------------------------------------------------------------ # Enable diagnostics counters separately from debug. #------------------------------------------------------------------------------ option(MERCURY_ENABLE_COUNTERS "Enable diagnostics counters." OFF) if(MERCURY_ENABLE_COUNTERS) set(HG_HAS_DIAG 1) else() set(HG_HAS_DIAG 0) endif() #------------------------------------------------------------------------------- if(${CMAKE_VERSION} VERSION_GREATER 3.14) include(CheckPIESupported) check_pie_supported(OUTPUT_VARIABLE output LANGUAGES C) if(BUILD_SHARED_LIBS AND NOT CMAKE_C_LINK_PIE_SUPPORTED) message(WARNING "PIE is not supported at link time: ${output}.\n" "PIE link options will not be passed to linker.") endif() endif() function(mercury_set_exe_options exetarget var_prefix) set_target_properties(${exetarget} PROPERTIES POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} INSTALL_RPATH ${${var_prefix}_INSTALL_LIB_DIR} INSTALL_NAME_DIR ${${var_prefix}_INSTALL_LIB_DIR} ) endfunction() #------------------------------------------------------------------------------- function(mercury_set_lib_options libtarget libname libtype var_prefix) if(${libtype} MATCHES "SHARED" OR ${libtype} MATCHES "MODULE") if(WIN32 AND NOT MINGW) set(LIB_RELEASE_NAME "${libname}") set(LIB_DEBUG_NAME "${libname}_D") else() set(LIB_RELEASE_NAME "${libname}") set(LIB_DEBUG_NAME "${libname}_debug") endif() else() if(WIN32 AND NOT MINGW) set(LIB_RELEASE_NAME "lib${libname}") set(LIB_DEBUG_NAME "lib${libname}_D") else() # if the generator supports configuration types or if the CMAKE_BUILD_TYPE has a value if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) set(LIB_RELEASE_NAME "${libname}") set(LIB_DEBUG_NAME "${libname}_debug") else() set(LIB_RELEASE_NAME "lib${libname}") set(LIB_DEBUG_NAME "lib${libname}_debug") endif() endif() endif() set_target_properties(${libtarget} PROPERTIES OUTPUT_NAME_DEBUG ${LIB_DEBUG_NAME} OUTPUT_NAME_RELEASE ${LIB_RELEASE_NAME} OUTPUT_NAME_MINSIZEREL ${LIB_RELEASE_NAME} OUTPUT_NAME_RELWITHDEBINFO ${LIB_RELEASE_NAME} OUTPUT_NAME_ASAN ${LIB_DEBUG_NAME} OUTPUT_NAME_TSAN ${LIB_DEBUG_NAME} OUTPUT_NAME_UBSAN ${LIB_DEBUG_NAME} ) if(${libtype} MATCHES "SHARED") set_target_properties(${libtarget} PROPERTIES INSTALL_RPATH ${${var_prefix}_INSTALL_LIB_DIR} INSTALL_NAME_DIR ${${var_prefix}_INSTALL_LIB_DIR} VERSION ${${var_prefix}_VERSION}.${${var_prefix}_VERSION_PATCH} SOVERSION ${${var_prefix}_VERSION_MAJOR} ) endif() if(MSVC) target_compile_definitions(${libtarget} PRIVATE -D_CRT_SECURE_NO_WARNINGS) endif() #----- Use MSVC Naming conventions for Shared Libraries if(MINGW AND ${libtype} MATCHES "SHARED") set_target_properties(${libtarget} PROPERTIES IMPORT_SUFFIX ".lib" IMPORT_PREFIX "" PREFIX "" ) endif() endfunction() #----------------------------------------------------------------------------- function(mercury_get_pc_lib_name output_var lib_target) if(CMAKE_BUILD_TYPE) string(TOLOWER ${CMAKE_BUILD_TYPE} lower_cmake_build_type) endif() if(lower_cmake_build_type MATCHES "debug") get_target_property(${output_var} ${lib_target} OUTPUT_NAME_DEBUG) else() get_target_property(${output_var} ${lib_target} OUTPUT_NAME_RELEASE) endif() set(${output_var} "${${output_var}}" PARENT_SCOPE) endfunction() #----------------------------------------------------------------------------- function(mercury_get_pc_inc_deps output_var inc_deps) foreach(inc_dep ${inc_deps}) set(${output_var} "${${output_var}} -I${inc_dep}") endforeach() set(${output_var} "${${output_var}}" PARENT_SCOPE) endfunction() #----------------------------------------------------------------------------- function(mercury_get_pc_lib_deps output_var lib_deps) # Need to generate -llib if not already passed foreach(lib_dep ${lib_deps}) # get library name get_filename_component(lib_name ${lib_dep} NAME_WE) if(lib_name MATCHES "^-l" OR lib_name MATCHES "-pthread") # lib_name found is -lxxx set(deps_list ${deps_list} ${lib_name}) else() # lib_name is /path/to/lib so get library path and name get_filename_component(lib_path ${lib_dep} PATH) if(lib_path) set(deps_list ${deps_list} -L${lib_path}) endif() string(REGEX REPLACE "^lib" "" lib_name ${lib_name}) set(deps_list ${deps_list} "-l${lib_name}") endif() endforeach() if(deps_list) list(REMOVE_DUPLICATES deps_list) string(REPLACE ";" " " ${output_var} "${deps_list}") endif() set(${output_var} "${${output_var}}" PARENT_SCOPE) endfunction() #----------------------------------------------------------------------------- # Avoid explicitly including system include paths set(MERCURY_SYSTEM_INCLUDE_PATH ${CMAKE_SYSTEM_INCLUDE_PATH} ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}) function(mercury_clean_include_path path_list) if(${path_list}) foreach(item ${MERCURY_SYSTEM_INCLUDE_PATH}) list(REMOVE_ITEM ${path_list} ${item}) endforeach() endif() set(${path_list} "${${path_list}}" PARENT_SCOPE) endfunction() set(MERCURY_SYSTEM_LIBRARY_PATH ${CMAKE_SYSTEM_LIBRARY_PATH} ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}) function(mercury_clean_library_path path_list) if(${path_list}) foreach(item ${MERCURY_SYSTEM_LIBRARY_PATH}) list(REMOVE_ITEM ${path_list} ${item}) endforeach() endif() set(${path_list} "${${path_list}}" PARENT_SCOPE) endfunction() #----------------------------------------------------------------------------- # Coverage #----------------------------------------------------------------------------- if(NOT MERCURY_EXTERNALLY_CONFIGURED) option(MERCURY_ENABLE_COVERAGE "Enable coverage." OFF) if(MERCURY_ENABLE_COVERAGE) set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage" CACHE STRING "Flags to the coverage program that CTest uses to perform coverage inspection" ) mark_as_advanced(COVERAGE_FLAGS) endif() macro(set_coverage_flags target) set_target_properties(${target} PROPERTIES COMPILE_FLAGS ${COVERAGE_FLAGS} LINK_FLAGS ${COVERAGE_FLAGS} ) endmacro() endif() #----------------------------------------------------------------------------- # Source #----------------------------------------------------------------------------- add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src) #----------------------------------------------------------------------------- # Util #----------------------------------------------------------------------------- add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/util) #----------------------------------------------------------------------------- # Build doxygen documentation. #----------------------------------------------------------------------------- option(BUILD_DOCUMENTATION "Build documentation." OFF) if(BUILD_DOCUMENTATION) add_subdirectory(Documentation/Doxygen) endif() #----------------------------------------------------------------------------- # Examples #----------------------------------------------------------------------------- option(BUILD_EXAMPLES "Build examples." OFF) if(BUILD_EXAMPLES) # Make sure MERCURY_USE_BOOST_PP is turned ON for examples. set(MERCURY_USE_BOOST_PP "ON" CACHE BOOL "Use BOOST preprocessor macros." FORCE) # BuildExamples.cmake builds the examples as a separate project. This ensures # that examples can be built by themselves as well as avoiding pollution of # the target space with targets (and other things) from examples. include(${CMAKE_CURRENT_SOURCE_DIR}/Examples/BuildExamples.cmake) endif() #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- option(BUILD_TESTING "Build testing." OFF) if(NOT MERCURY_EXTERNALLY_CONFIGURED AND BUILD_TESTING) enable_testing() include(CTest) add_subdirectory(Testing) endif() #----------------------------------------------------------------------------- # Configure the config.cmake file for the build directory #----------------------------------------------------------------------------- set(MERCURY_CONFIG_INSTALLED FALSE) configure_file( ${MERCURY_SOURCE_DIR}/CMake/${MERCURY_PACKAGE}-config.cmake.in ${MERCURY_BINARY_DIR}/${MERCURY_PACKAGE}-config.cmake @ONLY ) #----------------------------------------------------------------------------- # Configure the config.cmake file for the install directory #----------------------------------------------------------------------------- set(MERCURY_CONFIG_INSTALLED TRUE) configure_file( ${MERCURY_SOURCE_DIR}/CMake/${MERCURY_PACKAGE}-config.cmake.in ${MERCURY_BINARY_DIR}/CMakeFiles/${MERCURY_PACKAGE}-config.cmake @ONLY ) install( FILES ${MERCURY_BINARY_DIR}/CMakeFiles/${MERCURY_PACKAGE}-config.cmake DESTINATION ${MERCURY_INSTALL_DATA_DIR}/cmake/${MERCURY_PACKAGE} ) #----------------------------------------------------------------------------- # Configure the config-version .cmake file for the install directory #----------------------------------------------------------------------------- configure_file( ${MERCURY_SOURCE_DIR}/CMake/${MERCURY_PACKAGE}-config-version.cmake.in ${MERCURY_BINARY_DIR}/CMakeFiles/${MERCURY_PACKAGE}-config-version.cmake @ONLY ) install( FILES ${MERCURY_BINARY_DIR}/CMakeFiles/${MERCURY_PACKAGE}-config-version.cmake DESTINATION ${MERCURY_INSTALL_DATA_DIR}/cmake/${MERCURY_PACKAGE} ) #----------------------------------------------------------------------------- # CPack #----------------------------------------------------------------------------- if(NOT MERCURY_EXTERNALLY_CONFIGURED) set(CPACK_GENERATOR "TBZ2") set(CPACK_PACKAGE_DESCRIPTION_FILE ${MERCURY_SOURCE_DIR}/README.md) set(CPACK_RESOURCE_FILE_LICENSE ${MERCURY_SOURCE_DIR}/LICENSE.txt) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${MERCURY_PACKAGE_DESCRIPTION}) set(CPACK_PACKAGE_NAME ${MERCURY_PACKAGE_NAME}) set(CPACK_PACKAGE_VENDOR ${MERCURY_PACKAGE_VENDOR}) set(CPACK_PACKAGE_VERSION_MAJOR ${MERCURY_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${MERCURY_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${MERCURY_VERSION_PATCH}) set(CPACK_SOURCE_GENERATOR "TBZ2") set(CPACK_SOURCE_PACKAGE_FILE_NAME ${MERCURY_PACKAGE}-${MERCURY_VERSION_FULL}) set(CPACK_SOURCE_IGNORE_FILES # Files specific to version control "/\\\\.git/" "/\\\\.git$" "/\\\\.gitattributes$" "/\\\\.github/" "/\\\\.gitignore$" "/\\\\.gitmodules$" # IDE files "/\\\\.vscode/" # Build "/build/" # Temporary files "\\\\.swp$" "\\\\.#" "/#" "~$" ) set(CPACK_SOURCE_STRIP_FILES "") include(CPack) endif()