############################################################################
# Copyright (c) 2016, Johan Mabille, Sylvain Corlay, Martin Renou #
# Copyright (c) 2016, QuantStack #
# #
# Distributed under the terms of the BSD 3-Clause License. #
# #
# The full license is in the file LICENSE, distributed with this software. #
############################################################################
cmake_minimum_required(VERSION 3.8)
project(xeus)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
set(XEUS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(XEUS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(XEUS_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test)
# Versionning
# ===========
# Project version
file(STRINGS "${XEUS_INCLUDE_DIR}/xeus/xeus.hpp" xeus_version_defines
REGEX "#define XEUS_VERSION_(MAJOR|MINOR|PATCH)")
foreach(ver ${xeus_version_defines})
if(ver MATCHES "#define XEUS_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$")
set(XEUS_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
endif()
endforeach()
set(XEUS_VERSION
${XEUS_VERSION_MAJOR}.${XEUS_VERSION_MINOR}.${XEUS_VERSION_PATCH})
message(STATUS "xeus version: v${XEUS_VERSION}")
# Binary version
# See the following URL for explanations about the binary versionning
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
file(STRINGS "${XEUS_INCLUDE_DIR}/xeus/xeus.hpp" xeus_version_defines
REGEX "#define XEUS_BINARY_(CURRENT|REVISION|AGE)")
foreach(ver ${xeus_version_defines})
if(ver MATCHES "#define XEUS_BINARY_(CURRENT|REVISION|AGE) +([^ ]+)$")
set(XEUS_BINARY_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
endif()
endforeach()
set(XEUS_BINARY_VERSION
${XEUS_BINARY_CURRENT}.${XEUS_BINARY_REVISION}.${XEUS_BINARY_AGE})
message(STATUS "xeus binary version: v${XEUS_BINARY_VERSION}")
# Build options
# =============
# Compilation options
option(XEUS_DISABLE_ARCH_NATIVE "disable -march=native flag" OFF)
option(XEUS_BUILD_SHARED_LIBS "Build xeus shared library." ON)
option(XEUS_BUILD_STATIC_LIBS "Build xeus static library (default if BUILD_SHARED_LIBS is OFF)." ON)
option(XEUS_STATIC_DEPENDENCIES "link statically with xeus dependencies" OFF)
# Test options
option(XEUS_BUILD_TESTS "xeus test suite" OFF)
option(XEUS_DOWNLOAD_GTEST "build gtest from downloaded sources" OFF)
# Static build configuration
# ==========================
if (XEUS_STATIC_DEPENDENCIES)
set(CPPZMQ_TARGET_NAME cppzmq-static)
set(OPENSSL_USE_STATIC_LIBS ON CACHE BOOL "Linking statically with OpenSSL")
else()
set(CPPZMQ_TARGET_NAME cppzmq)
set(OPENSSL_USE_STATIC_LIBS OFF CACHE BOOL "Not linking statically with OpenSSL")
endif()
# Dependencies
# ============
set(nlohmann_json_REQUIRED_VERSION 3.2.0)
set(xtl_REQUIRED_VERSION 0.5)
set(cppzmq_REQUIRED_VERSION 4.4.1)
set(zeromq_REQUIRED_VERSION 4.3.2)
if (NOT TARGET nlohmann_json)
find_package(nlohmann_json ${nlohmann_json_REQUIRED_VERSION} REQUIRED)
endif ()
if (NOT TARGET xtl)
find_package(xtl ${xtl_REQUIRED_VERSION} REQUIRED)
endif ()
if (NOT TARGET cppzmq AND NOT TARGET cppzmq-static)
find_package(cppzmq ${cppzmq_REQUIRED_VERSION} REQUIRED)
endif ()
if (NOT TARGET libzmq AND NOT TARGET libzmq-static)
if (WIN32)
find_package(zeromq ${zeromq_REQUIRED_VERSION} REQUIRED)
else ()
find_package(zeromq ${zeromq_REQUIRED_VERSION} QUIET)
if (NOT ZeroMQ_FOUND)
message(STATUS "CMake libzmq package not found, trying again with pkg-config")
find_package(PkgConfig)
pkg_check_modules(ZeroMQ libzmq>=${zeromq_REQUIRED_VERSION} REQUIRED)
set(ZeroMQ_VERSION ${PC_LIBZMQ_VERSION})
find_library(ZeroMQ_LIBRARY NAMES libzmq.so libzmq.dylib libzmq.dll
PATHS ${PC_LIBZMQ_LIBDIR} ${PC_LIBZMQ_LIBRARY_DIRS})
find_library(ZeroMQ_STATIC_LIBRARY NAMES libzmq-static.a libzmq.a libzmq.dll.a
PATHS ${PC_LIBZMQ_LIBDIR} ${PC_LIBZMQ_LIBRARY_DIRS})
message(STATUS "STATIC_LIBRARY" {ZeroMQ_LIBRARY})
message(STATUS "STATIC_STATIC_LIBRARY" {ZeroMQ_STATIC_LIBRARY})
endif ()
endif ()
endif ()
if (NOT DEFINED OPENSSL_LIBRARY)
set(OPENSSL_ROOT_DIR ${CMAKE_INSTALL_PREFIX})
find_package(OpenSSL REQUIRED)
endif ()
# Source files
# ============
set(XEUS_HEADERS
${XEUS_INCLUDE_DIR}/xeus/xauthentication.hpp
${XEUS_INCLUDE_DIR}/xeus/xcomm.hpp
${XEUS_INCLUDE_DIR}/xeus/xcontrol_messenger.hpp
${XEUS_INCLUDE_DIR}/xeus/xdap_tcp_client.hpp
${XEUS_INCLUDE_DIR}/xeus/xdebugger.hpp
${XEUS_INCLUDE_DIR}/xeus/xdebugger_base.hpp
${XEUS_INCLUDE_DIR}/xeus/xeus.hpp
${XEUS_INCLUDE_DIR}/xeus/xguid.hpp
${XEUS_INCLUDE_DIR}/xeus/xhistory_manager.hpp
${XEUS_INCLUDE_DIR}/xeus/xinput.hpp
${XEUS_INCLUDE_DIR}/xeus/xinterpreter.hpp
${XEUS_INCLUDE_DIR}/xeus/xjson.hpp
${XEUS_INCLUDE_DIR}/xeus/xkernel.hpp
${XEUS_INCLUDE_DIR}/xeus/xkernel_configuration.hpp
${XEUS_INCLUDE_DIR}/xeus/xlogger.hpp
${XEUS_INCLUDE_DIR}/xeus/xmessage.hpp
${XEUS_INCLUDE_DIR}/xeus/xmiddleware.hpp
${XEUS_INCLUDE_DIR}/xeus/xserver.hpp
${XEUS_INCLUDE_DIR}/xeus/xserver_control_main.hpp
${XEUS_INCLUDE_DIR}/xeus/xserver_shell_main.hpp
${XEUS_INCLUDE_DIR}/xeus/xserver_zmq.hpp
${XEUS_INCLUDE_DIR}/xeus/xserver_zmq_split.hpp
${XEUS_INCLUDE_DIR}/xeus/xsystem.hpp
)
set(XEUS_SOURCES
${XEUS_SOURCE_DIR}/xauthentication.cpp
${XEUS_SOURCE_DIR}/xcomm.cpp
${XEUS_SOURCE_DIR}/xcontrol.hpp
${XEUS_SOURCE_DIR}/xcontrol.cpp
${XEUS_SOURCE_DIR}/xcontrol_messenger.cpp
${XEUS_SOURCE_DIR}/xdap_tcp_client.cpp
${XEUS_SOURCE_DIR}/xdebugger.cpp
${XEUS_SOURCE_DIR}/xdebugger_base.cpp
${XEUS_SOURCE_DIR}/xguid.cpp
${XEUS_SOURCE_DIR}/xheartbeat.cpp
${XEUS_SOURCE_DIR}/xheartbeat.hpp
${XEUS_SOURCE_DIR}/xhistory_manager.cpp
${XEUS_SOURCE_DIR}/xinput.cpp
${XEUS_SOURCE_DIR}/xin_memory_history_manager.hpp
${XEUS_SOURCE_DIR}/xin_memory_history_manager.cpp
${XEUS_SOURCE_DIR}/xinterpreter.cpp
${XEUS_SOURCE_DIR}/xkernel.cpp
${XEUS_SOURCE_DIR}/xkernel_configuration.cpp
${XEUS_SOURCE_DIR}/xkernel_core.cpp
${XEUS_SOURCE_DIR}/xkernel_core.hpp
${XEUS_SOURCE_DIR}/xlogger.cpp
${XEUS_SOURCE_DIR}/xlogger_impl.hpp
${XEUS_SOURCE_DIR}/xlogger_impl.cpp
${XEUS_SOURCE_DIR}/xmessage.cpp
${XEUS_SOURCE_DIR}/xmock_interpreter.cpp
${XEUS_SOURCE_DIR}/xmock_interpreter.hpp
${XEUS_SOURCE_DIR}/xmiddleware.cpp
${XEUS_SOURCE_DIR}/xpublisher.cpp
${XEUS_SOURCE_DIR}/xpublisher.hpp
${XEUS_SOURCE_DIR}/xserver.cpp
${XEUS_SOURCE_DIR}/xserver_control_main.cpp
${XEUS_SOURCE_DIR}/xserver_shell_main.cpp
${XEUS_SOURCE_DIR}/xserver_zmq.cpp
${XEUS_SOURCE_DIR}/xserver_zmq_split.cpp
${XEUS_SOURCE_DIR}/xshell.hpp
${XEUS_SOURCE_DIR}/xshell.cpp
${XEUS_SOURCE_DIR}/xstring_utils.hpp
${XEUS_SOURCE_DIR}/xsystem.cpp
${XEUS_SOURCE_DIR}/xtrivial_messenger.hpp
${XEUS_SOURCE_DIR}/xtrivial_messenger.cpp
${XEUS_SOURCE_DIR}/xzmq_messenger.hpp
${XEUS_SOURCE_DIR}/xzmq_messenger.cpp
)
# Targets and link
# ================
include(CheckCXXCompilerFlag)
string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
if (NOT APPLE)
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
endif ()
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib; ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
if (XEUS_STATIC_DEPENDENCIES AND NOT MSVC AND NOT APPLE)
# Explicitly finds and links with libsodium.a
# because it is not exported as a dependency by
# the static build of libzmq. Remove this when
# it is fixed upstream.
set(sodium_USE_STATIC_LIBS ON)
find_package(sodium REQUIRED)
endif ()
macro(xeus_create_target target_name linkage output_name)
string(TOUPPER "${linkage}" linkage_upper)
if (NOT ${linkage_upper} MATCHES "^(SHARED|STATIC)$")
message(FATAL_ERROR "Invalid library linkage: ${linkage}")
endif ()
# Output
# ======
add_library(${target_name} ${linkage_upper} ${XEUS_SOURCES} ${XEUS_HEADERS})
if (APPLE)
set_target_properties(
${target_name} PROPERTIES
MACOSX_RPATH ON
)
else ()
set_target_properties(
${target_name} PROPERTIES
BUILD_WITH_INSTALL_RPATH 1
)
endif ()
target_include_directories(
${target_name}
PUBLIC $<BUILD_INTERFACE:${XEUS_INCLUDE_DIR}>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(
${target_name}
PUBLIC ${CPPZMQ_TARGET_NAME}
PUBLIC nlohmann_json::nlohmann_json
PUBLIC xtl
)
target_link_libraries(${target_name} PUBLIC OpenSSL::Crypto)
if (NOT MSVC)
if (APPLE)
target_link_libraries(${target_name} PUBLIC "-framework CoreFoundation")
else ()
if (XEUS_STATIC_DEPENDENCIES)
find_path(LIBUUID_INCLUDE_DIR uuid.h PATH_SUFFIXES uuid)
find_library(LIBUUID_LIBRARY libuuid.a)
target_include_directories(${target_name} PRIVATE ${LIBUUID_INCLUDE_DIR})
target_link_libraries(${target_name} PUBLIC ${LIBUUID_LIBRARY})
target_link_libraries(${target_name} PUBLIC ${sodium_LIBRARY_RELEASE})
else ()
find_package(LibUUID REQUIRED)
target_link_libraries(${target_name} PUBLIC LibUUID::LibUUID)
endif ()
endif ()
endif ()
set_target_properties(
${target_name}
PROPERTIES
PUBLIC_HEADER "${XEUS_HEADERS}"
COMPILE_DEFINITIONS "XEUS_EXPORTS"
PREFIX ""
VERSION ${XEUS_BINARY_VERSION}
SOVERSION ${XEUS_BINARY_CURRENT}
OUTPUT_NAME "lib${output_name}"
)
# Compilation flags
# =================
target_compile_features(${target_name} PRIVATE cxx_std_11)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR
CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR
CMAKE_CXX_COMPILER_ID MATCHES "Intel")
target_compile_options(${target_name} PUBLIC -Wunused-parameter -Wextra -Wreorder)
if (NOT XEUS_DISABLE_ARCH_NATIVE)
target_compile_options(${target_name} PUBLIC -march=native)
endif ()
# Enable link time optimization and set the default symbol
# visibility to hidden (very important to obtain small binaries)
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
# Check for Link Time Optimization support
# (GCC/Clang)
CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
if (HAS_LTO_FLAG)
target_compile_options(${target_name} PUBLIC -flto)
endif ()
# Avoids removing symbols from the static library
CHECK_CXX_COMPILER_FLAG("-ffat-lto-objects" HAS_FATLTO_FLAG)
if (${linkage_upper} MATCHES "STATIC" AND HAS_FATLTO_FLAG)
message(STATUS "ENABLE FAT LTO OBJECTS")
target_compile_options(${target_name} PUBLIC -ffat-lto-objects)
endif ()
# Intel equivalent to LTO is called IPO
if (CMAKE_CXX_COMPILER_ID MATCHES "Intel")
CHECK_CXX_COMPILER_FLAG("-ipo" HAS_IPO_FLAG)
if (HAS_IPO_FLAG)
target_compile_options(${target_name} PUBLIC -ipo)
endif ()
endif ()
endif ()
message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
endif()
if (${linkage_upper} STREQUAL "STATIC")
target_compile_definitions(${target_name} PUBLIC XEUS_STATIC_LIB)
endif ()
if (MSVC)
target_compile_definitions(${target_name} PUBLIC -DNOMINMAX)
target_compile_options(${target_name} PUBLIC /DGUID_WINDOWS /MP /bigobj)
target_compile_options(${target_name} PUBLIC /wd4251 /wd4996)
elseif (APPLE)
target_compile_definitions(${target_name} PUBLIC -DGUID_CFUUID)
else ()
target_compile_definitions(${target_name} PUBLIC -DGUID_LIBUUID)
endif ()
if (XEUS_STATIC_DEPENDENCIES AND CMAKE_DL_LIBS)
target_link_libraries(${target_name} PRIVATE ${CMAKE_DL_LIBS} util rt)
endif ()
endmacro()
set(xeus_targets "")
if (XEUS_BUILD_SHARED_LIBS)
xeus_create_target(xeus SHARED xeus)
if(CMAKE_TARGET_SYSTEM MATCHES "Linux" AND OPENSSL_USE_STATIC_LIBS)
# Do not reexport OpenSSL symbols from xeus, for libraries
# Prevents conflicts with other versions of OpenSSL
# loaded in the same process namespace, which can cause
# crashes if the versions are not compatible.
set_target_properties(xeus PROPERTIES LINK_FLAGS "-Wl,--exclude-libs,libcrypto.a")
endif()
list(APPEND xeus_targets xeus)
endif ()
if (XEUS_BUILD_STATIC_LIBS)
# On Windows, a static library should use a different output name
# to avoid the conflict with the import library of a shared one.
if (CMAKE_HOST_WIN32)
xeus_create_target(xeus-static STATIC xeus-static)
else ()
xeus_create_target(xeus-static STATIC xeus)
endif ()
list(APPEND xeus_targets xeus-static)
endif ()
# Tests
# =====
# We need to control from outside whether we enable testing or not. We cannot
# rely on BUILD_TESTING since it doe snot exist until CTest is included.
include(CTest)
if(XEUS_DOWNLOAD_GTEST OR GTEST_SRC_DIR OR XEUS_BUILD_TESTS)
set(BUILD_TESTING ON)
message(STATUS "tests enabled")
else ()
set(BUILD_TESTING OFF)
message(STATUS "tests disabled")
endif()
if(BUILD_TESTING)
add_subdirectory(test)
endif()
# Installation
# ============
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
set(XEUS_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for xeusConfig.cmake")
install(TARGETS ${xeus_targets}
EXPORT ${PROJECT_NAME}-targets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xeus)
# Makes the project importable from the build directory
export(EXPORT ${PROJECT_NAME}-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake")
# Configure 'xeusConfig.cmake' for a build tree
set(XEUS_CONFIG_CODE "####### Expanded from \@XEUS_CONFIG_CODE\@ #######\n")
set(XEUS_CONFIG_CODE "${XEUS_CONFIG_CODE}set(CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/cmake;\${CMAKE_MODULE_PATH}\")\n")
set(XEUS_CONFIG_CODE "${XEUS_CONFIG_CODE}##################################################")
configure_package_config_file(${PROJECT_NAME}Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION ${PROJECT_BINARY_DIR})
# Configure 'xeusConfig.cmake' for an install tree
set(XEUS_CONFIG_CODE "")
configure_package_config_file(${PROJECT_NAME}Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION ${XEUS_CMAKECONFIG_INSTALL_DIR})
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
VERSION ${XEUS_VERSION}
COMPATIBILITY AnyNewerVersion)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindLibUUID.cmake
DESTINATION ${XEUS_CMAKECONFIG_INSTALL_DIR})
install(EXPORT ${PROJECT_NAME}-targets
FILE ${PROJECT_NAME}Targets.cmake
DESTINATION ${XEUS_CMAKECONFIG_INSTALL_DIR})