CMakeLists.txt 13.7 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
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
if(SQLITE3_FOUND OR PQ_FOUND)
louiz’'s avatar
louiz’ committed
197 198 199
  file(GLOB source_database
          src/database/*.[hc]pp)
  add_library(database OBJECT ${source_database})
200

201 202 203 204 205 206
  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
207 208 209 210
  set(USE_DATABASE TRUE)
else()
  add_library(database OBJECT "")
endif()
louiz’'s avatar
louiz’ committed
211

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

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

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

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

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

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

  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}
    )
344
endif()
345
add_custom_target(everything DEPENDS test_suite biboumi)
louiz’'s avatar
louiz’ committed
346

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

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

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

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

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

louiz’'s avatar
louiz’ committed
409 410 411 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
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)
442
configure_file(packaging/biboumi.spec.cmake biboumi.spec)
443
configure_file(src/biboumi.h.cmake src/biboumi.h)