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 9)
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 14 15 16 17 18
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
        message(FATAL_ERROR "GCC version must be at least 5.0.")
    endif()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
        message(FATAL_ERROR "Clang version must be at least 3.4.")
    endif()
endif()

19 20 21 22 23
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
24 25 26
#
## Find optional instrumentation libraries that will be used in debug only
#
27
find_library(LIBASAN NAMES asan libasan.so.4 libasan.so.3 libasan.so.2 libasan.so.1)
28 29
find_library(LIBUBSAN NAMES ubsan libubsan.so.0)

louiz’'s avatar
louiz’ committed
30 31 32
#
## Set various debug flags (instrumentation libs, coverage, …)
#
louiz’'s avatar
louiz’ committed
33
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic -Wall -Wextra -Wconversion -fvisibility=hidden -fvisibility-inlines-hidden")
34 35 36
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage --coverage")
endif()
37 38 39 40 41 42 43
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()

44
#
louiz’'s avatar
louiz’ committed
45
## Set the software version, archive name, RPM name etc
46
#
louiz’'s avatar
louiz’ committed
47
set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR})
48 49
set(RPM_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR})

louiz’'s avatar
louiz’ committed
50
if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES ".+")
51
  set(ARCHIVE_NAME ${ARCHIVE_NAME}${${PROJECT_NAME}_VERSION_SUFFIX})
52
  set(RPM_VERSION ${RPM_VERSION}${${PROJECT_NAME}_VERSION_SUFFIX})
louiz’'s avatar
louiz’ committed
53 54 55
endif()

if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES "^~dev$")
56 57 58
  # 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
59
  if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
60 61 62 63 64
    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})")
65
      set(ARCHIVE_NAME ${ARCHIVE_NAME}${GIT_REVISION})
66
      set(RPM_VERSION ${RPM_VERSION}${GIT_REVISION})
67 68 69 70
    endif()
  endif()
endif()

71
set(SOFTWARE_VERSION
72 73
  ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}${${PROJECT_NAME}_VERSION_SUFFIX})

74
#
louiz’'s avatar
louiz’ committed
75
## The rule that generates the documentation
76
#
77
add_custom_target(html COMMAND make html BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}
78
                  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc)
79 80 81
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)
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
if(WITH_UDNS)
  find_package(UDNS REQUIRED)
elseif(NOT WITHOUT_UDNS)
  find_package(UDNS)
endif()

louiz’'s avatar
louiz’ committed
122 123 124 125
if(WITH_SQLITE3)
  find_package(SQLITE3 REQUIRED)
elseif(NOT WITHOUT_SQLITE3)
  find_package(SQLITE3)
louiz’'s avatar
louiz’ committed
126 127
endif()

louiz’'s avatar
louiz’ committed
128 129 130 131 132 133
if(WITH_POSTGRESQL)
  find_package(PQ REQUIRED)
elseif(NOT WITHOUT_POSTGRESQL)
  find_package(PQ)
endif()

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

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

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

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

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

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

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

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

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

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

199 200 201 202 203 204
  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
205 206
  set(USE_DATABASE TRUE)
endif()
louiz’'s avatar
louiz’ committed
207

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

## 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>
221
        $<TARGET_OBJECTS:identd>)
louiz’'s avatar
louiz’ committed
222 223

## test_suite
louiz’'s avatar
louiz’ committed
224 225
file(GLOB source_tests
  tests/*.cpp)
louiz’'s avatar
louiz’ committed
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>
234
        $<TARGET_OBJECTS:identd>)
235
set_target_properties(test_suite PROPERTIES EXCLUDE_FROM_ALL TRUE)
236
if(USE_DATABASE)
237 238
  target_sources(${PROJECT_NAME} PRIVATE $<TARGET_OBJECTS:database>)
  target_sources(test_suite      PRIVATE $<TARGET_OBJECTS:database>)
239
endif()
240

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

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

#
## Add some custom rules to launch the tests
#
louiz’'s avatar
louiz’ committed
314
add_custom_target(check COMMAND "test_suite"
315
  DEPENDS test_suite)
316 317
add_custom_target(check_junit COMMAND test_suite -r junit -o check_result.xml
  DEPENDS test_suite)
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
    ./test_suite
328
    coverage_test_suite
329
    "-o;check_result.xml;-r;junit")
330 331
  add_dependencies(coverage_check test_suite)

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

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

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

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

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

louiz’'s avatar
louiz’ committed
383 384 385
#
## Set some variables that will be used in the cmake-generated files
#
386 387
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.")
388
set(WATCHDOG_SEC "" CACHE STRING ${WATCHDOG_SEC_DOCSTRING})
389
if(SYSTEMD_FOUND)
390
  set(SYSTEMD_SERVICE_TYPE "notify" CACHE STRING ${SYSTEMD_SERVICE_TYPE_DOCSTRING})
391
else()
392
  set(SYSTEMD_SERVICE_TYPE "simple" CACHE STRING ${SYSTEMD_SERVICE_TYPE_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)