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.
436 lines
14 KiB
CMake
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)
|