CMakeLists.txt 13.3 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")
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 database)
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 database)
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 database)
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 database)
176

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

if(LITESQL_FOUND)
  LITESQL_GENERATE_CPP("database/database.xml"
          "biboudb"
          LITESQL_GENERATED_SOURCES)

  add_library(database OBJECT src/database/database.cpp
          ${LITESQL_GENERATED_SOURCES})
197
  include_directories(database ${LITESQL_INCLUDE_DIRS})
louiz’'s avatar
louiz’ committed
198 199 200 201
  set(USE_DATABASE TRUE)
else()
  add_library(database OBJECT "")
endif()
louiz’'s avatar
louiz’ committed
202

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

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

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

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

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

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

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

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

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

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

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

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

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