CMakeLists.txt 13.8 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 8)
6
set(${PROJECT_NAME}_VERSION_MINOR 0)
louiz’'s avatar
louiz’ committed
7
set(${PROJECT_NAME}_VERSION_SUFFIX "~dev")
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
find_library(LIBASAN NAMES asan libasan.so.4 libasan.so.3 libasan.so.2 libasan.so.1)
18 19
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
endif()

louiz’'s avatar
louiz’ committed
133 134 135 136 137 138
if(WITH_POSTGRESQL)
  find_package(PQ REQUIRED)
elseif(NOT WITHOUT_POSTGRESQL)
  find_package(PQ)
endif()

louiz’'s avatar
louiz’ committed
139 140 141 142 143 144
#
## 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})
145 146 147 148 149 150
if(SYSTEMD_FOUND)
  include_directories(${SYSTEMD_INCLUDE_DIRS})
endif()
if(BOTAN_FOUND)
  include_directories(SYSTEM ${BOTAN_INCLUDE_DIRS})
endif()
louiz’'s avatar
louiz’ committed
151 152
if(UDNS_FOUND)
  include_directories(${UDNS_INCLUDE_DIRS})
153
endif()
154

louiz’'s avatar
louiz’ committed
155 156 157 158
# 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}/")
159

160
#
louiz’'s avatar
louiz’ committed
161
## Define all the modules
162
#
louiz’'s avatar
louiz’ committed
163 164 165 166 167

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

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

172
file(GLOB source_xmpp
louiz’'s avatar
louiz’ committed
173 174
        src/xmpp/*.[hc]pp)
add_library(xmpp OBJECT ${source_xmpp})
175

louiz’'s avatar
louiz’ committed
176
file(GLOB source_identd
louiz’'s avatar
louiz’ committed
177 178
        src/identd/*.[hc]pp)
add_library(identd OBJECT ${source_identd})
louiz’'s avatar
louiz’ committed
179

180
file(GLOB source_bridge
louiz’'s avatar
louiz’ committed
181 182
        src/bridge/*.[hc]pp)
add_library(bridge OBJECT ${source_bridge})
183

louiz’'s avatar
louiz’ committed
184 185 186 187 188 189 190 191 192 193 194 195
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})

196 197 198
option(DEBUG_SQL_QUERIES
       "If set to true, every SQL statement executed will be logged and timed"
       OFF)
199
if(SQLITE3_FOUND OR PQ_FOUND)
louiz’'s avatar
louiz’ committed
200 201 202
  file(GLOB source_database
          src/database/*.[hc]pp)
  add_library(database OBJECT ${source_database})
203

204 205 206 207 208 209
  if(SQLITE3_FOUND)
    include_directories(database ${SQLITE3_INCLUDE_DIRS})
  endif()
  if(PQ_FOUND)
    include_directories(database ${PQ_INCLUDE_DIRS})
  endif()
louiz’'s avatar
louiz’ committed
210 211 212 213
  set(USE_DATABASE TRUE)
else()
  add_library(database OBJECT "")
endif()
louiz’'s avatar
louiz’ committed
214

215
#
louiz’'s avatar
louiz’ committed
216
## Define the executables
217
#
louiz’'s avatar
louiz’ committed
218 219 220 221 222 223 224 225 226 227 228 229 230 231

## 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
232 233
file(GLOB source_tests
  tests/*.cpp)
louiz’'s avatar
louiz’ committed
234 235 236 237 238 239 240 241 242 243
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>)
244
set_target_properties(test_suite PROPERTIES EXCLUDE_FROM_ALL TRUE)
245

louiz’'s avatar
louiz’ committed
246 247 248
#
## Link the executables with their libraries
#
249
target_link_libraries(${PROJECT_NAME}
250
        ${ICONV_LIBRARIES}
251
        ${LIBUUID_LIBRARIES}
252
        ${EXPAT_LIBRARY})
253
target_link_libraries(test_suite
254
        ${ICONV_LIBRARIES}
255
        ${LIBUUID_LIBRARIES}
256
        ${EXPAT_LIBRARY})
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
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()
276
if(USE_DATABASE)
277 278 279 280 281 282 283 284
  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()
285
endif()
286

287 288 289 290 291 292 293 294
# 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
295 296 297
#
## Add a rule to download the catch unit test framework
#
louiz’'s avatar
louiz’ committed
298 299
include(ExternalProject)
ExternalProject_Add(catch
300
  GIT_REPOSITORY "https://lab.louiz.org/louiz/Catch.git"
louiz’'s avatar
louiz’ committed
301 302 303 304 305
  PREFIX "external"
  UPDATE_COMMAND ""
  CONFIGURE_COMMAND ""
  BUILD_COMMAND ""
  INSTALL_COMMAND ""
306
  )
307
set_target_properties(catch PROPERTIES EXCLUDE_FROM_ALL TRUE)
louiz’'s avatar
louiz’ committed
308
ExternalProject_Get_Property(catch SOURCE_DIR)
309 310 311 312 313 314
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
315 316 317 318

#
## Add some custom rules to launch the tests
#
louiz’'s avatar
louiz’ committed
319
add_custom_target(check COMMAND "test_suite"
320
  DEPENDS test_suite biboumi)
321
set_target_properties(check PROPERTIES EXCLUDE_FROM_ALL TRUE)
322 323
add_custom_target(e2e COMMAND "python3" "${CMAKE_CURRENT_SOURCE_DIR}/tests/end_to_end/"
  DEPENDS biboumi)
324
set_target_properties(e2e PROPERTIES EXCLUDE_FROM_ALL TRUE)
louiz’'s avatar
louiz’ committed
325 326
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
327
if(CMAKE_BUILD_TYPE MATCHES Debug)
328
  include(CodeCoverage)
329
  SETUP_TARGET_FOR_COVERAGE(coverage_check
330 331 332 333
    ./test_suite
    coverage_test_suite)
  add_dependencies(coverage_check test_suite)

334
  SETUP_TARGET_FOR_COVERAGE(coverage_e2e
335
    python3
336
    coverage_e2e
337 338
    ${CMAKE_CURRENT_SOURCE_DIR}/tests/end_to_end/)
  add_dependencies(coverage_e2e biboumi)
339 340 341 342 343 344 345 346

  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}
    )
347
endif()
348
add_custom_target(everything DEPENDS test_suite biboumi)
louiz’'s avatar
louiz’ committed
349

louiz’'s avatar
louiz’ committed
350 351 352
#
## Install target
#
353 354
install(TARGETS ${PROJECT_NAME} RUNTIME                     DESTINATION bin)
install(FILES   ${MAN_PAGE}                                 DESTINATION share/man/man1         OPTIONAL COMPONENT documentation)
355
install(FILES   ${CMAKE_CURRENT_BINARY_DIR}/biboumi.service DESTINATION lib/systemd/system     COMPONENT init)
356 357
file(GLOB policy_files conf/*policy.txt)
install(FILES   ${policy_files}                             DESTINATION /etc/biboumi           COMPONENT configuration)
louiz’'s avatar
louiz’ committed
358 359 360 361 362

#
## Dist target
## Generate a release tarball from the git sources
#
363
add_custom_command(OUTPUT ${ARCHIVE_NAME}.tar.xz
364
  COMMAND git archive --prefix=${ARCHIVE_NAME}/ --format=tar HEAD^{tree}
365 366 367 368 369 370 371
          > ${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
372
  COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --cyan "${ARCHIVE_NAME}.tar.xz created."
373 374
  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  )
375 376 377
add_custom_target(dist
  DEPENDS ${ARCHIVE_NAME}.tar.xz
  DEPENDS catch)
378 379

add_custom_target(rpm
380
  DEPENDS dist
381 382 383
  COMMAND mkdir -p rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
  COMMAND rpmbuild --define "_topdir `pwd`/rpmbuild/" --define "_sourcedir `pwd`" -ba biboumi.spec
  )
384

louiz’'s avatar
louiz’ committed
385 386 387
#
## Set some variables that will be used in the cmake-generated files
#
388 389
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.")
390
if(SYSTEMD_FOUND)
391 392
  set(SYSTEMD_SERVICE_TYPE "notify" CACHE STRING ${SYSTEMD_SERVICE_TYPE_DOCSTRING})
  set(WATCHDOG_SEC "20" CACHE STRING ${WATCHDOG_SEC_DOCSTRING})
393
else()
394 395
  set(SYSTEMD_SERVICE_TYPE "simple" CACHE STRING ${SYSTEMD_SERVICE_TYPE_DOCSTRING})
  set(WATCHDOG_SEC "" CACHE STRING ${WATCHDOG_SEC_DOCSTRING})
396
endif()
397
set(SERVICE_USER_DOCSTRING "The value used as the User= in the systemd unit file.")
398
if(NOT DEFINED SERVICE_USER)
399
  set(SERVICE_USER "nobody" CACHE STRING ${SERVICE_USER_DOCSTRING})
400
endif()
401
set(SERVICE_GROUP_DOCSTRING "The value used as the Group= in the systemd unit file.")
402
if(NOT DEFINED SERVICE_GROUP)
403
  set(SERVICE_GROUP "nobody" CACHE STRING ${SERVICE_GROUP_DOCSTRING})
404
endif()
405

louiz’'s avatar
louiz’ committed
406
# Force the format of the date output
407
set(ENV{LANG} "C")
408 409
execute_process(COMMAND "date" "+%a %b %d %Y" OUTPUT_VARIABLE RPM_DATE
                OUTPUT_STRIP_TRAILING_WHITESPACE)
410
unset(ENV{LANG})
411

louiz’'s avatar
louiz’ committed
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
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)
445
configure_file(packaging/biboumi.spec.cmake biboumi.spec)
446
configure_file(src/biboumi.h.cmake src/biboumi.h)