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

project(biboumi)

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

9 10 11 12 13
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
      "Build type (Release/Debug/RelWithDebInfo/MinSizeRel)" FORCE)
endif()

louiz’'s avatar
louiz’ committed
14 15 16
#
## Find optional instrumentation libraries that will be used in debug only
#
17 18 19
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
20 21 22
#
## Set various debug flags (instrumentation libs, coverage, …)
#
23
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic -Wall -Wextra -Wconversion -fvisibility=hidden -fvisibility-inlines-hidden")
24 25 26
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage --coverage")
endif()
27 28 29 30 31 32 33
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()

34
#
louiz’'s avatar
louiz’ committed
35
## Set the software version, archive name, RPM name etc
36
#
louiz’'s avatar
louiz’ committed
37
set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR})
38 39
set(RPM_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR})

louiz’'s avatar
louiz’ committed
40
if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES ".+")
41
  set(ARCHIVE_NAME ${ARCHIVE_NAME}${${PROJECT_NAME}_VERSION_SUFFIX})
42
  set(RPM_VERSION ${RPM_VERSION}${${PROJECT_NAME}_VERSION_SUFFIX})
louiz’'s avatar
louiz’ committed
43 44 45
endif()

if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES "^~dev$")
46 47 48
  # 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
49
  if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
50 51 52 53 54
    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})")
55
      set(ARCHIVE_NAME ${ARCHIVE_NAME}${GIT_REVISION})
56
      set(RPM_VERSION ${RPM_VERSION}${GIT_REVISION})
57 58 59 60
    endif()
  endif()
endif()

61
set(SOFTWARE_VERSION
62 63
  ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}${${PROJECT_NAME}_VERSION_SUFFIX})

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

louiz’'s avatar
louiz’ committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
#
## 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)
103 104
endif()

louiz’'s avatar
louiz’ committed
105 106 107 108 109
if(WITH_SYSTEMD)
  find_package(SYSTEMD REQUIRED)
elseif(NOT WITHOUT_SYSTEMD)
  find_package(SYSTEMD)
endif()
110

louiz’'s avatar
louiz’ committed
111 112 113 114
if(WITH_BOTAN)
  find_package(BOTAN REQUIRED)
elseif(NOT WITHOUT_BOTAN)
  find_package(BOTAN)
115 116
endif()

louiz’'s avatar
louiz’ committed
117 118 119
if(NOT BOTAN_FOUND)
  find_package(GCRYPT REQUIRED)
endif()
120

louiz’'s avatar
louiz’ committed
121 122 123 124 125 126
if(WITH_UDNS)
  find_package(UDNS REQUIRED)
elseif(NOT WITHOUT_UDNS)
  find_package(UDNS)
endif()

louiz’'s avatar
louiz’ committed
127 128 129 130
if(WITH_SQLITE3)
  find_package(SQLITE3 REQUIRED)
elseif(NOT WITHOUT_SQLITE3)
  find_package(SQLITE3)
louiz’'s avatar
louiz’ committed
131 132 133 134 135 136 137 138
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})
139 140 141 142 143 144
if(SYSTEMD_FOUND)
  include_directories(${SYSTEMD_INCLUDE_DIRS})
endif()
if(BOTAN_FOUND)
  include_directories(SYSTEM ${BOTAN_INCLUDE_DIRS})
endif()
louiz’'s avatar
louiz’ committed
145 146
if(UDNS_FOUND)
  include_directories(${UDNS_INCLUDE_DIRS})
147
endif()
148

louiz’'s avatar
louiz’ committed
149 150 151 152
# 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}/")
153

154
#
louiz’'s avatar
louiz’ committed
155
## Define all the modules
156
#
louiz’'s avatar
louiz’ committed
157 158 159 160 161

file(GLOB source_utils
        src/utils/*.[hc]pp)
add_library(utils OBJECT ${source_utils})

162
file(GLOB source_irc
louiz’'s avatar
louiz’ committed
163 164
        src/irc/*.[hc]pp)
add_library(irc OBJECT ${source_irc})
165

166
file(GLOB source_xmpp
louiz’'s avatar
louiz’ committed
167 168
        src/xmpp/*.[hc]pp)
add_library(xmpp OBJECT ${source_xmpp})
169

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

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

louiz’'s avatar
louiz’ committed
178 179 180 181 182 183 184 185 186 187 188 189
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})

louiz’'s avatar
louiz’ committed
190 191 192 193
if(SQLITE3_FOUND)
  file(GLOB source_database
          src/database/*.[hc]pp)
  add_library(database OBJECT ${source_database})
194

louiz’'s avatar
louiz’ committed
195
  include_directories(database ${SQLITE3_INCLUDE_DIRS})
louiz’'s avatar
louiz’ committed
196 197 198 199
  set(USE_DATABASE TRUE)
else()
  add_library(database OBJECT "")
endif()
louiz’'s avatar
louiz’ committed
200

201
#
louiz’'s avatar
louiz’ committed
202
## Define the executables
203
#
louiz’'s avatar
louiz’ committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217

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

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

267 268 269 270 271 272 273 274
# 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
275 276 277
#
## Add a rule to download the catch unit test framework
#
louiz’'s avatar
louiz’ committed
278 279
include(ExternalProject)
ExternalProject_Add(catch
280
  GIT_REPOSITORY "https://lab.louiz.org/louiz/Catch.git"
louiz’'s avatar
louiz’ committed
281 282 283 284 285
  PREFIX "external"
  UPDATE_COMMAND ""
  CONFIGURE_COMMAND ""
  BUILD_COMMAND ""
  INSTALL_COMMAND ""
286
  )
287
set_target_properties(catch PROPERTIES EXCLUDE_FROM_ALL TRUE)
louiz’'s avatar
louiz’ committed
288
ExternalProject_Get_Property(catch SOURCE_DIR)
289 290 291 292 293 294
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
295 296 297 298

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

314
  SETUP_TARGET_FOR_COVERAGE(coverage_e2e
315
    python3
316
    coverage_e2e
317 318
    ${CMAKE_CURRENT_SOURCE_DIR}/tests/end_to_end/)
  add_dependencies(coverage_e2e biboumi)
319 320 321 322 323 324 325 326

  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}
    )
327
endif()
328
add_custom_target(everything DEPENDS test_suite biboumi)
louiz’'s avatar
louiz’ committed
329

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

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

add_custom_target(rpm
360
  DEPENDS dist
361 362 363
  COMMAND mkdir -p rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
  COMMAND rpmbuild --define "_topdir `pwd`/rpmbuild/" --define "_sourcedir `pwd`" -ba biboumi.spec
  )
364

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

louiz’'s avatar
louiz’ committed
386
# Force the format of the date output
387
set(ENV{LANG} "C")
388 389
execute_process(COMMAND "date" "+%a %b %d %Y" OUTPUT_VARIABLE RPM_DATE
                OUTPUT_STRIP_TRAILING_WHITESPACE)
390
unset(ENV{LANG})
391

louiz’'s avatar
louiz’ committed
392 393 394 395 396 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
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)
425
configure_file(packaging/biboumi.spec.cmake biboumi.spec)
426
configure_file(src/biboumi.h.cmake src/biboumi.h)