Files
biboumi/CMakeLists.txt
T
louiz’ 2a637bee0a Do not install biboumi.cfg in /etc/biboumi/
Because it would overwrite the user file when installing a new version.  And
it’s basically useless anyway, because if the file doesn’t exist at all,
biboumi will write an helpful message on stderr, telling the user to create
the config file.
2017-05-21 12:02:23 +02:00

436 lines
14 KiB
CMake

cmake_minimum_required(VERSION 3.0)
project(biboumi)
set(${PROJECT_NAME}_VERSION_MAJOR 5)
set(${PROJECT_NAME}_VERSION_MINOR 0)
set(${PROJECT_NAME}_VERSION_SUFFIX "~dev")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
"Build type (Release/Debug/RelWithDebInfo/MinSizeRel)" FORCE)
endif()
#
## Find optional instrumentation libraries that will be used in debug only
#
find_library(LIBASAN NAMES asan libasan.so.3 libasan.so.2 libasan.so.1)
find_library(LIBUBSAN NAMES ubsan libubsan.so.0)
#
## Set various debug flags (instrumentation libs, coverage, …)
#
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic -Wall -Wextra -Wconversion")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage --coverage")
endif()
if(LIBASAN)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address")
endif()
if(LIBUBSAN)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=undefined")
endif()
#
## Set the software version, archive name, RPM name etc
#
set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR})
set(RPM_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR})
if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES ".+")
set(ARCHIVE_NAME ${ARCHIVE_NAME}${${PROJECT_NAME}_VERSION_SUFFIX})
set(RPM_VERSION ${RPM_VERSION}${${PROJECT_NAME}_VERSION_SUFFIX})
endif()
if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES "^~dev$")
# If we are on a dev version, append the hash of the current git HEAD to
# the version
include(FindGit)
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
execute_process(COMMAND git --git-dir=${CMAKE_SOURCE_DIR}/.git rev-parse --short HEAD
OUTPUT_VARIABLE GIT_REVISION
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(GIT_REVISION)
set(${PROJECT_NAME}_VERSION_SUFFIX "${${PROJECT_NAME}_VERSION_SUFFIX} (${GIT_REVISION})")
set(ARCHIVE_NAME ${ARCHIVE_NAME}${GIT_REVISION})
set(RPM_VERSION ${RPM_VERSION}${GIT_REVISION})
endif()
endif()
endif()
set(SOFTWARE_VERSION
${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}${${PROJECT_NAME}_VERSION_SUFFIX})
#
## The rule that generates the documentation
#
execute_process(COMMAND "date" "+%Y-%m-%d" OUTPUT_VARIABLE DOC_DATE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(MAN_PAGE ${CMAKE_CURRENT_BINARY_DIR}/doc/${PROJECT_NAME}.1)
set(DOC_PAGE ${CMAKE_CURRENT_SOURCE_DIR}/doc/${PROJECT_NAME}.1.rst)
if (NOT PANDOC_EXECUTABLE)
find_program(PANDOC_EXECUTABLE NAMES pandoc
DOC "The pandoc software, to build the man page from the rst documentation")
if(PANDOC_EXECUTABLE)
message(STATUS "Found Pandoc: ${PANDOC_EXECUTABLE}")
set(WITH_DOC true)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/)
add_custom_command(OUTPUT ${MAN_PAGE}
COMMAND ${PANDOC_EXECUTABLE} -M date="${DOC_DATE}" -s -t man ${DOC_PAGE} -o ${MAN_PAGE}
DEPENDS ${DOC_PAGE})
add_custom_target(doc ALL DEPENDS ${MAN_PAGE})
else()
message(STATUS "Pandoc not found, documentation cannot be built")
endif()
endif()
mark_as_advanced(PANDOC_EXECUTABLE)
#
## Set this search path for cmake, to find our custom search modules
#
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
find_package(ICONV REQUIRED)
find_package(LIBUUID REQUIRED)
find_package(EXPAT REQUIRED)
#
## Find all the libraries (optional or not)
#
if(WITH_LIBIDN)
find_package(LIBIDN REQUIRED)
elseif(NOT WITHOUT_LIBIDN)
find_package(LIBIDN)
endif()
if(WITH_SYSTEMD)
find_package(SYSTEMD REQUIRED)
elseif(NOT WITHOUT_SYSTEMD)
find_package(SYSTEMD)
endif()
if(WITH_BOTAN)
find_package(BOTAN REQUIRED)
elseif(NOT WITHOUT_BOTAN)
find_package(BOTAN)
endif()
if(NOT BOTAN_FOUND)
find_package(GCRYPT REQUIRED)
endif()
if(WITH_UDNS)
find_package(UDNS REQUIRED)
elseif(NOT WITHOUT_UDNS)
find_package(UDNS)
endif()
if(WITH_LITESQL)
find_package(LITESQL REQUIRED)
elseif(NOT WITHOUT_LITESQL)
find_package(LITESQL)
endif()
#
## Set all the include directories, depending on what libraries are used
#
include_directories(${EXPAT_INCLUDE_DIRS})
include_directories(${ICONV_INCLUDE_DIRS})
include_directories(${LIBUUID_INCLUDE_DIRS})
if(SYSTEMD_FOUND)
include_directories(${SYSTEMD_INCLUDE_DIRS})
endif()
if(BOTAN_FOUND)
include_directories(SYSTEM ${BOTAN_INCLUDE_DIRS})
endif()
if(UDNS_FOUND)
include_directories(${UDNS_INCLUDE_DIRS})
endif()
# To be able to include the config.h and other files generated by cmake
include_directories("${CMAKE_CURRENT_BINARY_DIR}/src/")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/src/")
include_directories("${CMAKE_CURRENT_BINARY_DIR}/")
#
## Define all the modules
#
file(GLOB source_utils
src/utils/*.[hc]pp)
add_library(utils OBJECT ${source_utils})
add_dependencies(utils litesql_generated_sources)
file(GLOB source_irc
src/irc/*.[hc]pp)
add_library(irc OBJECT ${source_irc})
add_dependencies(irc litesql_generated_sources)
file(GLOB source_xmpp
src/xmpp/*.[hc]pp)
add_library(xmpp OBJECT ${source_xmpp})
add_dependencies(xmpp litesql_generated_sources)
file(GLOB source_identd
src/identd/*.[hc]pp)
add_library(identd OBJECT ${source_identd})
file(GLOB source_bridge
src/bridge/*.[hc]pp)
add_library(bridge OBJECT ${source_bridge})
add_dependencies(bridge litesql_generated_sources)
file(GLOB source_config
src/config/*.[hc]pp)
add_library(config OBJECT ${source_config})
file(GLOB source_logger
src/logger/*.[hc]pp)
add_library(logger OBJECT ${source_logger})
file(GLOB source_network
src/network/*.[hc]pp)
add_library(network OBJECT ${source_network})
if(LITESQL_FOUND)
LITESQL_GENERATE_CPP("database/database.xml"
"biboudb"
LITESQL_GENERATED_SOURCES)
add_custom_target(litesql_generated_sources SOURCES ${LITESQL_GENERATED_SOURCES})
add_library(database OBJECT src/database/database.cpp ${LITESQL_GENERATED_SOURCES})
add_dependencies(database litesql_generated_sources)
include_directories(database ${LITESQL_INCLUDE_DIRS})
set(USE_DATABASE TRUE)
else()
add_library(database OBJECT "")
add_custom_target(litesql_generated_sources)
endif()
#
## Define the executables
#
## main
add_executable(${PROJECT_NAME} src/main.cpp
$<TARGET_OBJECTS:utils>
$<TARGET_OBJECTS:config>
$<TARGET_OBJECTS:logger>
$<TARGET_OBJECTS:network>
$<TARGET_OBJECTS:xmpp>
$<TARGET_OBJECTS:bridge>
$<TARGET_OBJECTS:irc>
$<TARGET_OBJECTS:identd>
$<TARGET_OBJECTS:database>)
## test_suite
file(GLOB source_tests
tests/*.cpp)
add_executable(test_suite ${source_tests}
$<TARGET_OBJECTS:utils>
$<TARGET_OBJECTS:config>
$<TARGET_OBJECTS:logger>
$<TARGET_OBJECTS:network>
$<TARGET_OBJECTS:xmpp>
$<TARGET_OBJECTS:bridge>
$<TARGET_OBJECTS:irc>
$<TARGET_OBJECTS:identd>
$<TARGET_OBJECTS:database>)
set_target_properties(test_suite PROPERTIES EXCLUDE_FROM_ALL TRUE)
#
## Link the executables with their libraries
#
target_link_libraries(${PROJECT_NAME}
${ICONV_LIBRARIES}
${LIBUUID_LIBRARIES}
${EXPAT_LIBRARY})
target_link_libraries(test_suite
${ICONV_LIBRARIES}
${LIBUUID_LIBRARIES}
${EXPAT_LIBRARY})
if(SYSTEMD_FOUND)
target_link_libraries(${PROJECT_NAME} ${SYSTEMD_LIBRARIES})
target_link_libraries(test_suite ${SYSTEMD_LIBRARIES})
endif()
if(BOTAN_FOUND)
target_link_libraries(${PROJECT_NAME} ${BOTAN_LIBRARIES})
target_link_libraries(test_suite ${BOTAN_LIBRARIES})
elseif(GCRYPT_FOUND)
target_link_libraries(${PROJECT_NAME} ${GCRYPT_LIBRARIES})
target_link_libraries(test_suite ${GCRYPT_LIBRARIES})
endif()
if(UDNS_FOUND)
target_link_libraries(${PROJECT_NAME} ${UDNS_LIBRARIES})
target_link_libraries(test_suite ${UDNS_LIBRARIES})
endif()
if(LIBIDN_FOUND)
target_link_libraries(${PROJECT_NAME} ${LIBIDN_LIBRARIES})
target_link_libraries(test_suite ${LIBIDN_LIBRARIES})
endif()
if(USE_DATABASE)
target_link_libraries(${PROJECT_NAME} ${LITESQL_LIBRARIES})
target_link_libraries(test_suite ${LITESQL_LIBRARIES})
endif()
# Define a __FILENAME__ macro with the relative path (from the base project directory)
# of each source file
file(GLOB_RECURSE source_all src/*.[hc]pp tests/*.[hc]pp)
foreach(file ${source_all})
file(RELATIVE_PATH shorter_file ${CMAKE_CURRENT_SOURCE_DIR} ${file})
set_property(SOURCE ${file} APPEND PROPERTY COMPILE_DEFINITIONS __FILENAME__="${shorter_file}")
endforeach()
#
## Add a rule to download the catch unit test framework
#
include(ExternalProject)
ExternalProject_Add(catch
GIT_REPOSITORY "https://lab.louiz.org/louiz/Catch.git"
PREFIX "external"
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
set_target_properties(catch PROPERTIES EXCLUDE_FROM_ALL TRUE)
ExternalProject_Get_Property(catch SOURCE_DIR)
if(NOT EXISTS ${CMAKE_SOURCE_DIR}/tests/catch.hpp)
target_include_directories(test_suite
PUBLIC "${SOURCE_DIR}/include/"
)
add_dependencies(test_suite catch)
endif()
#
## Add some custom rules to launch the tests
#
add_custom_target(check COMMAND "test_suite"
DEPENDS test_suite biboumi)
set_target_properties(check PROPERTIES EXCLUDE_FROM_ALL TRUE)
add_custom_target(e2e COMMAND "python3" "${CMAKE_CURRENT_SOURCE_DIR}/tests/end_to_end/"
DEPENDS biboumi)
set_target_properties(e2e PROPERTIES EXCLUDE_FROM_ALL TRUE)
add_custom_target(e2e_valgrind COMMAND "E2E_BIBOUMI_SUPP_DIR=${CMAKE_CURRENT_SOURCE_DIR}/tests/end_to_end/" "E2E_BIBOUMI_VALGRIND=1" "python3" "${CMAKE_CURRENT_SOURCE_DIR}/tests/end_to_end/"
DEPENDS biboumi)
if(CMAKE_BUILD_TYPE MATCHES Debug)
include(CodeCoverage)
SETUP_TARGET_FOR_COVERAGE(coverage_check
./test_suite
coverage_test_suite)
add_dependencies(coverage_check test_suite)
SETUP_TARGET_FOR_COVERAGE(coverage_e2e
python3
coverage_e2e
${CMAKE_CURRENT_SOURCE_DIR}/tests/end_to_end/)
add_dependencies(coverage_e2e biboumi)
ADD_CUSTOM_TARGET(coverage
COMMAND ${LCOV_PATH} -a coverage_e2e.info -a coverage_test_suite.info -o coverage_total.info
COMMAND ${GENHTML_PATH} -o coverage_total coverage_total.info
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()
add_custom_target(everything DEPENDS test_suite biboumi)
#
## Install target
#
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
install(FILES ${MAN_PAGE} DESTINATION share/man/man1 OPTIONAL COMPONENT documentation)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/biboumi.service DESTINATION lib/systemd/system COMPONENT init)
file(GLOB policy_files conf/*policy.txt)
install(FILES ${policy_files} DESTINATION /etc/biboumi COMPONENT configuration)
#
## Dist target
## Generate a release tarball from the git sources
#
add_custom_command(OUTPUT ${ARCHIVE_NAME}.tar.xz
COMMAND git archive --prefix=${ARCHIVE_NAME}/ --format=tar HEAD^{tree}
> ${CMAKE_CURRENT_BINARY_DIR}/${ARCHIVE_NAME}.tar
# Append this specific file that is not part of the git repo
COMMAND tar -rf ${CMAKE_CURRENT_BINARY_DIR}/${ARCHIVE_NAME}.tar -P ${SOURCE_DIR}/single_include/catch.hpp --xform 's|/.*/|${ARCHIVE_NAME}/tests/|g'
# Remove a potential existing archive
COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/${ARCHIVE_NAME}.tar.xz
# Compress the archive
COMMAND xz ${CMAKE_CURRENT_BINARY_DIR}/${ARCHIVE_NAME}.tar
COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --cyan "${ARCHIVE_NAME}.tar.xz created."
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
add_custom_target(dist
DEPENDS ${ARCHIVE_NAME}.tar.xz
DEPENDS catch)
add_custom_target(rpm
DEPENDS dist
COMMAND mkdir -p rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
COMMAND rpmbuild --define "_topdir `pwd`/rpmbuild/" --define "_sourcedir `pwd`" -ba biboumi.spec
)
#
## Set some variables that will be used in the cmake-generated files
#
set(SYSTEMD_SERVICE_TYPE_DOCSTRING "The value used as the Type= in the systemd unit file.")
set(WATCHDOG_SEC_DOCSTRING "The value used as WatchdogSec= in the systemd unit file.")
if(SYSTEMD_FOUND)
set(SYSTEMD_SERVICE_TYPE "notify" CACHE STRING ${SYSTEMD_SERVICE_TYPE_DOCSTRING})
set(WATCHDOG_SEC "20" CACHE STRING ${WATCHDOG_SEC_DOCSTRING})
else()
set(SYSTEMD_SERVICE_TYPE "simple" CACHE STRING ${SYSTEMD_SERVICE_TYPE_DOCSTRING})
set(WATCHDOG_SEC "" CACHE STRING ${WATCHDOG_SEC_DOCSTRING})
endif()
set(SERVICE_USER_DOCSTRING "The value used as the User= in the systemd unit file.")
if(NOT DEFINED SERVICE_USER)
set(SERVICE_USER "nobody" CACHE STRING ${SERVICE_USER_DOCSTRING})
endif()
set(SERVICE_GROUP_DOCSTRING "The value used as the Group= in the systemd unit file.")
if(NOT DEFINED SERVICE_GROUP)
set(SERVICE_GROUP "nobody" CACHE STRING ${SERVICE_GROUP_DOCSTRING})
endif()
# Force the format of the date output
set(ENV{LANG} "C")
execute_process(COMMAND "date" "+%a %b %d %Y" OUTPUT_VARIABLE RPM_DATE
OUTPUT_STRIP_TRAILING_WHITESPACE)
unset(ENV{LANG})
set(POLLER_DOCSTRING "Choose the poller between POLL and EPOLL (Linux-only)")
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(POLLER "EPOLL" CACHE STRING ${POLLER_DOCSTRING})
else()
set(POLLER "POLL" CACHE STRING ${POLLER_DOCSTRING})
endif()
if((NOT ${POLLER} MATCHES "POLL") AND
(NOT ${POLLER} MATCHES "EPOLL"))
message(FATAL_ERROR "POLLER must be either POLL or EPOLL")
endif()
#
## Check if we have std::get_time and put_time
#
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include <iomanip>
int main()
{ std::get_time(nullptr, \"\"); }"
HAS_GET_TIME)
mark_as_advanced(HAS_GET_TIME)
check_cxx_source_compiles("
#include <iomanip>
int main()
{ std::put_time(nullptr, \"\"); }"
HAS_PUT_TIME)
mark_as_advanced(HAS_PUT_TIME)
configure_file(unit/biboumi.service.cmake biboumi.service)
configure_file(packaging/biboumi.spec.cmake biboumi.spec)
configure_file(biboumi.h.cmake src/biboumi.h)