Some packagers use ctest by default to run tests. This is a small easy-win to add to biboumi. In addition some distros don't use /etc as their configuration path, and have to patch this out (see guix and nix), so this is also an easy fix.
434 lines
13 KiB
CMake
434 lines
13 KiB
CMake
cmake_minimum_required(VERSION 3.5)
|
|
|
|
project(biboumi)
|
|
|
|
set(${PROJECT_NAME}_VERSION_MAJOR 10)
|
|
set(${PROJECT_NAME}_VERSION_MINOR 0)
|
|
set(${PROJECT_NAME}_VERSION_SUFFIX "~dev")
|
|
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11.2)
|
|
message(FATAL_ERROR "GCC version must be at least 11.2.")
|
|
endif()
|
|
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14)
|
|
message(FATAL_ERROR "Clang version must be at least 14.")
|
|
endif()
|
|
endif()
|
|
|
|
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.8 libasan.so.4 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++20 -pedantic -Wall -Wextra -Wconversion -fvisibility=hidden -fvisibility-inlines-hidden")
|
|
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
|
|
#
|
|
add_custom_target(html COMMAND make html BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc)
|
|
add_custom_target(man COMMAND make man BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc)
|
|
add_custom_target(doc DEPENDS html man)
|
|
|
|
#
|
|
## 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_SQLITE3)
|
|
find_package(SQLITE3 REQUIRED)
|
|
elseif(NOT WITHOUT_SQLITE3)
|
|
find_package(SQLITE3)
|
|
endif()
|
|
|
|
if(WITH_POSTGRESQL)
|
|
find_package(PQ REQUIRED)
|
|
elseif(NOT WITHOUT_POSTGRESQL)
|
|
find_package(PQ)
|
|
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})
|
|
|
|
file(GLOB source_irc
|
|
src/irc/*.[hc]pp)
|
|
add_library(irc OBJECT ${source_irc})
|
|
|
|
file(GLOB source_xmpp
|
|
src/xmpp/*.[hc]pp)
|
|
add_library(xmpp OBJECT ${source_xmpp})
|
|
|
|
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})
|
|
|
|
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})
|
|
|
|
option(DEBUG_SQL_QUERIES
|
|
"If set to true, every SQL statement executed will be logged and timed"
|
|
OFF)
|
|
if(SQLITE3_FOUND OR PQ_FOUND)
|
|
file(GLOB source_database
|
|
src/database/*.[hc]pp)
|
|
add_library(database OBJECT ${source_database})
|
|
|
|
if(SQLITE3_FOUND)
|
|
include_directories(database ${SQLITE3_INCLUDE_DIRS})
|
|
endif()
|
|
if(PQ_FOUND)
|
|
include_directories(database ${PQ_INCLUDE_DIRS})
|
|
endif()
|
|
set(USE_DATABASE TRUE)
|
|
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>)
|
|
|
|
## 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>)
|
|
set_target_properties(test_suite PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
|
if(USE_DATABASE)
|
|
target_sources(${PROJECT_NAME} PRIVATE $<TARGET_OBJECTS:database>)
|
|
target_sources(test_suite PRIVATE $<TARGET_OBJECTS:database>)
|
|
endif()
|
|
|
|
#
|
|
## 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)
|
|
if(SQLITE3_FOUND)
|
|
target_link_libraries(${PROJECT_NAME} ${SQLITE3_LIBRARIES})
|
|
target_link_libraries(test_suite ${SQLITE3_LIBRARIES})
|
|
endif()
|
|
if(PQ_FOUND)
|
|
target_link_libraries(${PROJECT_NAME} ${PQ_LIBRARIES})
|
|
target_link_libraries(test_suite ${PQ_LIBRARIES})
|
|
endif()
|
|
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()
|
|
|
|
#
|
|
## Catch unit test framework
|
|
#
|
|
find_package(Catch2)
|
|
if(Catch2_FOUND)
|
|
target_link_libraries(test_suite Catch2::Catch2WithMain)
|
|
include(CTest)
|
|
include(Catch)
|
|
catch_discover_tests(test_suite)
|
|
endif()
|
|
|
|
#
|
|
## Add some custom rules to launch the tests
|
|
#
|
|
add_custom_target(check COMMAND "test_suite"
|
|
DEPENDS test_suite)
|
|
add_custom_target(check_junit COMMAND test_suite -r junit -o check_result.xml
|
|
DEPENDS test_suite)
|
|
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
|
|
"-o;check_result.xml;-r;junit")
|
|
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 ${CMAKE_CURRENT_BINARY_DIR}/man/biboumi.1 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.")
|
|
set(WATCHDOG_SEC "" CACHE STRING ${WATCHDOG_SEC_DOCSTRING})
|
|
if(SYSTEMD_FOUND)
|
|
set(SYSTEMD_SERVICE_TYPE "notify" CACHE STRING ${SYSTEMD_SERVICE_TYPE_DOCSTRING})
|
|
else()
|
|
set(SYSTEMD_SERVICE_TYPE "simple" CACHE STRING ${SYSTEMD_SERVICE_TYPE_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(src/biboumi.h.cmake src/biboumi.h)
|