CMakeLists.txt 13.7 KB
Newer Older
1
cmake_minimum_required(VERSION 3.0)
2 3 4

project(biboumi)

louiz’'s avatar
louiz’ committed
5
set(${PROJECT_NAME}_VERSION_MAJOR 5)
6
set(${PROJECT_NAME}_VERSION_MINOR 0)
louiz’'s avatar
louiz’ committed
7
set(${PROJECT_NAME}_VERSION_SUFFIX "~dev")
8

louiz’'s avatar
louiz’ committed
9 10 11
#
## Find optional instrumentation libraries that will be used in debug only
#
12 13 14
find_library(LIBASAN NAMES asan libasan.so.3 libasan.so.2 libasan.so.1)
find_library(LIBUBSAN NAMES ubsan libubsan.so.0)

louiz’'s avatar
louiz’ committed
15 16 17
#
## Set various debug flags (instrumentation libs, coverage, …)
#
louiz’'s avatar
louiz’ committed
18
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic -Wall -Wextra -Wconversion")
19 20 21
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage --coverage")
endif()
22 23 24 25 26 27 28
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()

29
#
louiz’'s avatar
louiz’ committed
30
## Set the software version, archive name, RPM name etc
31
#
louiz’'s avatar
louiz’ committed
32
set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR})
33 34
set(RPM_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR})

louiz’'s avatar
louiz’ committed
35
if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES ".+")
36
  set(ARCHIVE_NAME ${ARCHIVE_NAME}${${PROJECT_NAME}_VERSION_SUFFIX})
37
  set(RPM_VERSION ${RPM_VERSION}${${PROJECT_NAME}_VERSION_SUFFIX})
louiz’'s avatar
louiz’ committed
38 39 40
endif()

if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES "^~dev$")
41 42 43
  # If we are on a dev version, append the hash of the current git HEAD to
  # the version
  include(FindGit)
louiz’'s avatar
louiz’ committed
44
  if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
45 46 47 48 49
    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})")
50
      set(ARCHIVE_NAME ${ARCHIVE_NAME}${GIT_REVISION})
51
      set(RPM_VERSION ${RPM_VERSION}${GIT_REVISION})
52 53 54 55
    endif()
  endif()
endif()

56
set(SOFTWARE_VERSION
57 58
  ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}${${PROJECT_NAME}_VERSION_SUFFIX})

59
#
louiz’'s avatar
louiz’ committed
60
## The rule that generates the documentation
61
#
62 63
execute_process(COMMAND "date" "+%Y-%m-%d" OUTPUT_VARIABLE DOC_DATE
                OUTPUT_STRIP_TRAILING_WHITESPACE)
64
set(MAN_PAGE ${CMAKE_CURRENT_BINARY_DIR}/doc/${PROJECT_NAME}.1)
65
set(DOC_PAGE ${CMAKE_CURRENT_SOURCE_DIR}/doc/${PROJECT_NAME}.1.rst)
66 67 68 69 70 71 72 73 74 75 76 77 78 79
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()
80
endif()
81
mark_as_advanced(PANDOC_EXECUTABLE)
82

louiz’'s avatar
louiz’ committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
#
## 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)
98 99
endif()

louiz’'s avatar
louiz’ committed
100 101 102 103 104
if(WITH_SYSTEMD)
  find_package(SYSTEMD REQUIRED)
elseif(NOT WITHOUT_SYSTEMD)
  find_package(SYSTEMD)
endif()
105

louiz’'s avatar
louiz’ committed
106 107 108 109
if(WITH_BOTAN)
  find_package(BOTAN REQUIRED)
elseif(NOT WITHOUT_BOTAN)
  find_package(BOTAN)
110 111
endif()

louiz’'s avatar
louiz’ committed
112 113 114
if(NOT BOTAN_FOUND)
  find_package(GCRYPT REQUIRED)
endif()
115

louiz’'s avatar
louiz’ committed
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
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})
134 135 136 137 138 139
if(SYSTEMD_FOUND)
  include_directories(${SYSTEMD_INCLUDE_DIRS})
endif()
if(BOTAN_FOUND)
  include_directories(SYSTEM ${BOTAN_INCLUDE_DIRS})
endif()
louiz’'s avatar
louiz’ committed
140 141
if(UDNS_FOUND)
  include_directories(${UDNS_INCLUDE_DIRS})
142
endif()
143

louiz’'s avatar
louiz’ committed
144 145 146 147
# 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}/")
148

149
#
louiz’'s avatar
louiz’ committed
150
## Define all the modules
151
#
louiz’'s avatar
louiz’ committed
152 153 154 155

file(GLOB source_utils
        src/utils/*.[hc]pp)
add_library(utils OBJECT ${source_utils})
156
add_dependencies(utils litesql_generated_sources)
louiz’'s avatar
louiz’ committed
157

158
file(GLOB source_irc
louiz’'s avatar
louiz’ committed
159 160
        src/irc/*.[hc]pp)
add_library(irc OBJECT ${source_irc})
161
add_dependencies(irc litesql_generated_sources)
162

163
file(GLOB source_xmpp
louiz’'s avatar
louiz’ committed
164 165
        src/xmpp/*.[hc]pp)
add_library(xmpp OBJECT ${source_xmpp})
166
add_dependencies(xmpp litesql_generated_sources)
167

louiz’'s avatar
louiz’ committed
168
file(GLOB source_identd
louiz’'s avatar
louiz’ committed
169 170
        src/identd/*.[hc]pp)
add_library(identd OBJECT ${source_identd})
louiz’'s avatar
louiz’ committed
171

172
file(GLOB source_bridge
louiz’'s avatar
louiz’ committed
173 174
        src/bridge/*.[hc]pp)
add_library(bridge OBJECT ${source_bridge})
175
add_dependencies(bridge litesql_generated_sources)
176

louiz’'s avatar
louiz’ committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
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)
193 194 195 196
  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)
louiz’'s avatar
louiz’ committed
197

198
  include_directories(database ${LITESQL_INCLUDE_DIRS})
louiz’'s avatar
louiz’ committed
199 200 201
  set(USE_DATABASE TRUE)
else()
  add_library(database OBJECT "")
202
  add_custom_target(litesql_generated_sources)
louiz’'s avatar
louiz’ committed
203
endif()
louiz’'s avatar
louiz’ committed
204

205
#
louiz’'s avatar
louiz’ committed
206
## Define the executables
207
#
louiz’'s avatar
louiz’ committed
208 209 210 211 212 213 214 215 216 217 218 219 220 221

## 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
louiz’'s avatar
louiz’ committed
222 223
file(GLOB source_tests
  tests/*.cpp)
louiz’'s avatar
louiz’ committed
224 225 226 227 228 229 230 231 232 233
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>)
234
set_target_properties(test_suite PROPERTIES EXCLUDE_FROM_ALL TRUE)
235

louiz’'s avatar
louiz’ committed
236 237 238
#
## Link the executables with their libraries
#
239
target_link_libraries(${PROJECT_NAME}
240
        ${ICONV_LIBRARIES}
241
        ${LIBUUID_LIBRARIES}
242
        ${EXPAT_LIBRARY})
243
target_link_libraries(test_suite
244
        ${ICONV_LIBRARIES}
245
        ${LIBUUID_LIBRARIES}
246
        ${EXPAT_LIBRARY})
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
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()
266
if(USE_DATABASE)
267 268
  target_link_libraries(${PROJECT_NAME} ${LITESQL_LIBRARIES})
  target_link_libraries(test_suite ${LITESQL_LIBRARIES})
269
endif()
270

271 272 273 274 275 276 277 278
# 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()

louiz’'s avatar
louiz’ committed
279 280 281
#
## Add a rule to download the catch unit test framework
#
louiz’'s avatar
louiz’ committed
282 283
include(ExternalProject)
ExternalProject_Add(catch
284
  GIT_REPOSITORY "https://lab.louiz.org/louiz/Catch.git"
louiz’'s avatar
louiz’ committed
285 286 287 288 289
  PREFIX "external"
  UPDATE_COMMAND ""
  CONFIGURE_COMMAND ""
  BUILD_COMMAND ""
  INSTALL_COMMAND ""
290
  )
291
set_target_properties(catch PROPERTIES EXCLUDE_FROM_ALL TRUE)
louiz’'s avatar
louiz’ committed
292
ExternalProject_Get_Property(catch SOURCE_DIR)
293 294 295 296 297 298
if(NOT EXISTS ${CMAKE_SOURCE_DIR}/tests/catch.hpp)
  target_include_directories(test_suite
    PUBLIC "${SOURCE_DIR}/include/"
    )
  add_dependencies(test_suite catch)
endif()
louiz’'s avatar
louiz’ committed
299 300 301 302

#
## Add some custom rules to launch the tests
#
louiz’'s avatar
louiz’ committed
303
add_custom_target(check COMMAND "test_suite"
304
  DEPENDS test_suite biboumi)
305
set_target_properties(check PROPERTIES EXCLUDE_FROM_ALL TRUE)
306 307
add_custom_target(e2e COMMAND "python3" "${CMAKE_CURRENT_SOURCE_DIR}/tests/end_to_end/"
  DEPENDS biboumi)
308
set_target_properties(e2e PROPERTIES EXCLUDE_FROM_ALL TRUE)
louiz’'s avatar
louiz’ committed
309 310
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)
louiz’'s avatar
louiz’ committed
311
if(CMAKE_BUILD_TYPE MATCHES Debug)
312
  include(CodeCoverage)
313
  SETUP_TARGET_FOR_COVERAGE(coverage_check
314 315 316 317
    ./test_suite
    coverage_test_suite)
  add_dependencies(coverage_check test_suite)

318
  SETUP_TARGET_FOR_COVERAGE(coverage_e2e
319
    python3
320
    coverage_e2e
321 322
    ${CMAKE_CURRENT_SOURCE_DIR}/tests/end_to_end/)
  add_dependencies(coverage_e2e biboumi)
323 324 325 326 327 328 329 330

  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}
    )
331
endif()
332
add_custom_target(everything DEPENDS test_suite biboumi)
louiz’'s avatar
louiz’ committed
333

louiz’'s avatar
louiz’ committed
334 335 336
#
## Install target
#
337 338
install(TARGETS ${PROJECT_NAME} RUNTIME                     DESTINATION bin)
install(FILES   ${MAN_PAGE}                                 DESTINATION share/man/man1         OPTIONAL COMPONENT documentation)
339
install(FILES   ${CMAKE_CURRENT_BINARY_DIR}/biboumi.service DESTINATION lib/systemd/system     COMPONENT init)
340
install(FILES   conf/biboumi.cfg                            DESTINATION /etc/biboumi           COMPONENT configuration)
341 342
file(GLOB policy_files conf/*policy.txt)
install(FILES   ${policy_files}                             DESTINATION /etc/biboumi           COMPONENT configuration)
louiz’'s avatar
louiz’ committed
343 344 345 346 347

#
## Dist target
## Generate a release tarball from the git sources
#
348
add_custom_command(OUTPUT ${ARCHIVE_NAME}.tar.xz
349
  COMMAND git archive --prefix=${ARCHIVE_NAME}/ --format=tar HEAD^{tree}
350 351 352 353 354 355 356
          > ${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
357
  COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --cyan "${ARCHIVE_NAME}.tar.xz created."
358 359
  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  )
360 361 362
add_custom_target(dist
  DEPENDS ${ARCHIVE_NAME}.tar.xz
  DEPENDS catch)
363 364

add_custom_target(rpm
365
  DEPENDS dist
366 367 368
  COMMAND mkdir -p rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
  COMMAND rpmbuild --define "_topdir `pwd`/rpmbuild/" --define "_sourcedir `pwd`" -ba biboumi.spec
  )
369

louiz’'s avatar
louiz’ committed
370 371 372
#
## Set some variables that will be used in the cmake-generated files
#
373 374
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.")
375
if(SYSTEMD_FOUND)
376 377
  set(SYSTEMD_SERVICE_TYPE "notify" CACHE STRING ${SYSTEMD_SERVICE_TYPE_DOCSTRING})
  set(WATCHDOG_SEC "20" CACHE STRING ${WATCHDOG_SEC_DOCSTRING})
378
else()
379 380
  set(SYSTEMD_SERVICE_TYPE "simple" CACHE STRING ${SYSTEMD_SERVICE_TYPE_DOCSTRING})
  set(WATCHDOG_SEC "" CACHE STRING ${WATCHDOG_SEC_DOCSTRING})
381
endif()
382
set(SERVICE_USER_DOCSTRING "The value used as the User= in the systemd unit file.")
383
if(NOT DEFINED SERVICE_USER)
384
  set(SERVICE_USER "nobody" CACHE STRING ${SERVICE_USER_DOCSTRING})
385
endif()
386
set(SERVICE_GROUP_DOCSTRING "The value used as the Group= in the systemd unit file.")
387
if(NOT DEFINED SERVICE_GROUP)
388
  set(SERVICE_GROUP "nobody" CACHE STRING ${SERVICE_GROUP_DOCSTRING})
389
endif()
390

louiz’'s avatar
louiz’ committed
391
# Force the format of the date output
392
set(ENV{LANG} "C")
393 394
execute_process(COMMAND "date" "+%a %b %d %Y" OUTPUT_VARIABLE RPM_DATE
                OUTPUT_STRIP_TRAILING_WHITESPACE)
395
unset(ENV{LANG})
396

louiz’'s avatar
louiz’ committed
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
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)
430
configure_file(packaging/biboumi.spec.cmake biboumi.spec)
louiz’'s avatar
louiz’ committed
431
configure_file(biboumi.h.cmake src/biboumi.h)