1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
|
cmake_minimum_required(VERSION 3.5...3.28.1)
project(libnetconf2 C)
# include custom Modules
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/")
include(GNUInstallDirs)
include(CheckFunctionExists)
include(CheckCSourceCompiles)
include(CheckIncludeFile)
include(UseCompat)
include(ABICheck)
include(SourceFormat)
include(GenDoc)
include(GenCoverage)
if(POLICY CMP0075)
cmake_policy(SET CMP0075 NEW)
endif()
# set default build type if not specified by user
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
# see https://github.com/CESNET/libyang/pull/1692 for why CMAKE_C_FLAGS_<type> are not used directly
# normalize build type string
string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_UPPER)
if ("${BUILD_TYPE_UPPER}" STREQUAL "RELEASE")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE)
set(CMAKE_C_FLAGS "-DNDEBUG -O2 ${CMAKE_C_FLAGS}")
elseif("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build Type" FORCE)
set(CMAKE_C_FLAGS "-g -O0 ${CMAKE_C_FLAGS}")
elseif("${BUILD_TYPE_UPPER}" STREQUAL "RELWITHDEBINFO")
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Build Type" FORCE)
elseif("${BUILD_TYPE_UPPER}" STREQUAL "RELWITHDEBUG")
set(CMAKE_BUILD_TYPE "RelWithDebug" CACHE STRING "Build Type" FORCE)
elseif("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
set(CMAKE_BUILD_TYPE "ABICheck" CACHE STRING "Build Type" FORCE)
set(CMAKE_C_FLAGS "-g -Og ${CMAKE_C_FLAGS}")
elseif("${BUILD_TYPE_UPPER}" STREQUAL "DOCONLY")
set(CMAKE_BUILD_TYPE "DocOnly" CACHE STRING "Build Type" FORCE)
endif()
#
# variables
#
set(LIBNETCONF2_DESCRIPTION "NETCONF server and client library in C.")
# osx specific
set(CMAKE_MACOSX_RPATH TRUE)
# Version of the project
# Generic version of not only the library. Major version is reserved for really big changes of the project,
# minor version changes with added functionality (new tool, functionality of the tool or library, ...) and
# micro version is changed with a set of small changes or bugfixes anywhere in the project.
set(LIBNETCONF2_MAJOR_VERSION 4)
set(LIBNETCONF2_MINOR_VERSION 2)
set(LIBNETCONF2_MICRO_VERSION 4)
set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION}.${LIBNETCONF2_MICRO_VERSION})
# Version of the library
# Major version is changed with every backward non-compatible API/ABI change in the library, minor version changes
# with backward compatible change and micro version is connected with any internal change of the library.
set(LIBNETCONF2_MAJOR_SOVERSION 5)
set(LIBNETCONF2_MINOR_SOVERSION 2)
set(LIBNETCONF2_MICRO_SOVERSION 4)
set(LIBNETCONF2_SOVERSION_FULL ${LIBNETCONF2_MAJOR_SOVERSION}.${LIBNETCONF2_MINOR_SOVERSION}.${LIBNETCONF2_MICRO_SOVERSION})
set(LIBNETCONF2_SOVERSION ${LIBNETCONF2_MAJOR_SOVERSION})
# Version of libyang library that this project depends on
set(LIBYANG_DEP_VERSION 4.2.0)
set(LIBYANG_DEP_SOVERSION 4.2.0)
set(LIBYANG_DEP_SOVERSION_MAJOR 4)
# global C flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fvisibility=hidden -std=c99")
#
# options
#
if(("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG") OR ("${BUILD_TYPE_UPPER}" STREQUAL "RELWITHDEBINFO"))
option(ENABLE_TESTS "Build tests" ON)
option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" ON)
else()
option(ENABLE_TESTS "Build tests" OFF)
option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
endif()
option(ENABLE_EXAMPLES "Build examples" ON)
option(ENABLE_COVERAGE "Build code coverage report from tests" OFF)
option(ENABLE_SSH_TLS "Enable NETCONF over SSH and TLS support (via libssh and OpenSSL)" ON)
option(ENABLE_DNSSEC "Enable support for SSHFP retrieval using DNSSEC for SSH (requires OpenSSL and libval)" OFF)
option(ENABLE_PAM "Detect and use PAM" ON)
option(ENABLE_COMMON_TARGETS "Define common custom target names such as 'doc' or 'uninstall', may cause conflicts when using add_subdirectory() to build this project" ON)
option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON)
set(READ_INACTIVE_TIMEOUT 20 CACHE STRING "Maximum number of seconds waiting for new data once some data have arrived")
set(READ_ACTIVE_TIMEOUT 300 CACHE STRING "Maximum number of seconds for receiving a full message")
set(MAX_PSPOLL_THREAD_COUNT 6 CACHE STRING "Maximum number of threads that could simultaneously access a ps_poll structure")
set(TIMEOUT_STEP 100 CACHE STRING "Number of microseconds tasks are repeated until timeout elapses")
set(YANG_MODULE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/yang/modules/libnetconf2" CACHE STRING "Directory where to copy the YANG modules to")
set(CLIENT_SEARCH_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/yang/modules" CACHE STRING "Default NC client YANG module search directory")
#
# sources
#
set(libsrc
src/io.c
src/log.c
src/messages_client.c
src/messages_server.c
src/session.c
src/session_client.c
src/session_server.c
src/server_config.c
src/server_config_util.c
src/proxy_unix.c)
if(ENABLE_SSH_TLS)
list(APPEND libsrc
src/session_client_ssh.c
src/session_server_ssh.c
src/server_config_util_ssh.c
src/session_client_tls.c
src/session_server_tls.c
src/server_config_util_tls.c)
set(SSH_TLS_MACRO "#ifndef NC_ENABLED_SSH_TLS\n#define NC_ENABLED_SSH_TLS\n#endif")
endif()
set(headers
src/log.h
src/netconf.h
src/session.h
src/messages_client.h
src/messages_server.h
src/session_client.h
src/session_client_ch.h
src/session_server.h
src/session_server_ch.h
src/server_config.h
src/proxy_unix.h)
# files to generate doxygen from
set(doxy_files
doc/libnetconf.doc
src/log.h
src/netconf.h
src/session.h
src/messages_client.h
src/messages_server.h
src/session_client.h
src/session_client_ch.h
src/session_server.h
src/session_server_ch.h
src/server_config.h
src/proxy_unix.h)
# source files to be covered by the 'format' target
set(format_sources
compat/*.c
compat/*.h*
examples/*.c
examples/*.h*
src/*.c
src/*.h
tests/*.c)
#
# checks
#
if(ENABLE_DNSSEC AND NOT ENABLE_SSH_TLS)
message(WARNING "DNSSEC SSHFP retrieval cannot be used without SSH support.")
set(ENABLE_DNSSEC OFF)
endif()
if(ENABLE_VALGRIND_TESTS)
find_program(VALGRIND_FOUND valgrind)
if(NOT VALGRIND_FOUND)
message(WARNING "valgrind executable not found! Disabling memory leaks tests.")
set(ENABLE_VALGRIND_TESTS OFF)
else()
set(ENABLE_TESTS ON)
endif()
endif()
if(ENABLE_TESTS)
find_package(CMocka 1.0.1)
if(NOT CMOCKA_FOUND)
message(STATUS "Disabling tests because of missing CMocka")
set(ENABLE_TESTS OFF)
endif()
endif()
if(ENABLE_COVERAGE)
gen_coverage_enable(${ENABLE_TESTS})
endif()
if ("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
source_format_enable(0.77)
endif()
if("${BUILD_TYPE_UPPER}" STREQUAL "DOCONLY")
gen_doc("${doxy_files}" ${LIBNETCONF2_VERSION} ${LIBNETCONF2_DESCRIPTION} "")
return()
endif()
#
# targets
#
# use compat
use_compat()
# netconf2 sourceless target - need it for linking libs, but the required sources will be added later
add_library(netconf2)
# set the shared library version
set_target_properties(netconf2 PROPERTIES VERSION ${LIBNETCONF2_SOVERSION_FULL} SOVERSION ${LIBNETCONF2_SOVERSION})
# include repository files with highest priority
include_directories(${PROJECT_BINARY_DIR}/src)
include_directories(${PROJECT_BINARY_DIR}/include)
# dependencies - pthread
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
target_link_libraries(netconf2 ${CMAKE_THREAD_LIBS_INIT})
# check availability for some pthread functions
set(CMAKE_REQUIRED_LIBRARIES pthread)
check_function_exists(pthread_rwlockattr_setkind_np HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP)
# header file compatibility
check_include_file("shadow.h" HAVE_SHADOW)
check_include_file("termios.h" HAVE_TERMIOS)
if(ENABLE_SSH_TLS)
# dependencies - mbedTLS (higher preference) or OpenSSL
find_package(MbedTLS 3.5.0)
if (MBEDTLS_FOUND)
# dependencies - mbedtls
set(HAVE_MBEDTLS TRUE)
list(APPEND libsrc src/session_mbedtls.c)
include_directories(${MBEDTLS_INCLUDE_DIRS})
target_link_libraries(netconf2 ${MBEDTLS_LIBRARIES})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_LIBRARIES})
else()
# dependencies - openssl
find_package(OpenSSL 3.0.0 REQUIRED)
list(APPEND libsrc src/session_openssl.c)
include_directories(${OPENSSL_INCLUDE_DIR})
target_link_libraries(netconf2 ${OPENSSL_LIBRARIES})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
endif()
# dependencies - libssh
find_package(LibSSH 0.9.5 REQUIRED)
target_link_libraries(netconf2 ${LIBSSH_LIBRARIES})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBSSH_LIBRARIES})
include_directories(${LIBSSH_INCLUDE_DIRS})
# dependencies - libcurl
find_package(CURL 7.30.0 REQUIRED)
if(TARGET CURL::libcurl)
target_link_libraries(netconf2 CURL::libcurl)
else()
target_link_libraries(netconf2 ${CURL_LIBRARIES})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARY})
include_directories(${CURL_INCLUDE_DIRS})
endif()
# crypt (if not found, assume no library needs to be linked)
if(${CMAKE_SYSTEM_NAME} MATCHES "QNX")
set(LIBCRYPT login)
else()
set(LIBCRYPT crypt)
endif()
check_library_exists(${LIBCRYPT} crypt "" HAVE_CRYPT)
if(HAVE_CRYPT)
target_link_libraries(netconf2 ${LIBCRYPT})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBCRYPT})
endif()
# libpam
if(ENABLE_PAM)
find_package(LibPAM)
endif()
if(LibPAM_FOUND)
set(HAVE_LIBPAM TRUE)
target_link_libraries(netconf2 ${LIBPAM_LIBRARIES})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBPAM_LIBRARIES})
include_directories(${LIBPAM_INCLUDE_DIRS})
message(STATUS "SSH Keyboard Interactive system method: Linux PAM")
elseif(HAVE_SHADOW)
message(STATUS "SSH Keyboard Interactive system method: local users")
else()
message(WARNING "SSH Keyboard Interactive system method: disabled")
endif()
# set compiler flag
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_SSH_TLS")
endif()
# dependencies - libval
if(ENABLE_DNSSEC)
find_package(LibVAL REQUIRED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_DNSSEC")
target_link_libraries(netconf2 ${LIBVAL_LIBRARIES})
include_directories(${LIBVAL_INCLUDE_DIRS})
endif()
# dependencies - libyang
find_package(LibYANG ${LIBYANG_DEP_SOVERSION} REQUIRED)
target_link_libraries(netconf2 ${LIBYANG_LIBRARIES})
include_directories(${LIBYANG_INCLUDE_DIRS})
# set sources
target_sources(netconf2 PRIVATE ${libsrc} ${compatsrc})
# generate config file
configure_file("${PROJECT_SOURCE_DIR}/src/config.h.in" "${PROJECT_BINARY_DIR}/src/config.h" ESCAPE_QUOTES @ONLY)
# generate and copy public header files
configure_file("${PROJECT_SOURCE_DIR}/nc_client.h.in" "${PROJECT_BINARY_DIR}/include/nc_client.h")
configure_file("${PROJECT_SOURCE_DIR}/nc_server.h.in" "${PROJECT_BINARY_DIR}/include/nc_server.h")
configure_file("${PROJECT_SOURCE_DIR}/nc_version.h.in" "${PROJECT_BINARY_DIR}/include/nc_version.h")
file(COPY ${headers} DESTINATION "${PROJECT_BINARY_DIR}/include/libnetconf2")
# install YANG modules
install(DIRECTORY "${PROJECT_SOURCE_DIR}/modules/" DESTINATION ${YANG_MODULE_DIR} FILES_MATCHING PATTERN "*.yang")
# install library
install(TARGETS netconf2 DESTINATION ${CMAKE_INSTALL_LIBDIR})
# install headers
install(FILES ${PROJECT_BINARY_DIR}/include/nc_client.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES ${PROJECT_BINARY_DIR}/include/nc_server.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES ${PROJECT_BINARY_DIR}/include/nc_version.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(DIRECTORY ${PROJECT_BINARY_DIR}/include/libnetconf2 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
# install pkg-config file
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
configure_file("libnetconf2.pc.in" "libnetconf2.pc" @ONLY)
install(FILES "${PROJECT_BINARY_DIR}/libnetconf2.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
# check that pkg-config includes the used path
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable pc_path pkg-config RESULT_VARIABLE RETURN OUTPUT_VARIABLE PC_PATH ERROR_QUIET)
if(RETURN EQUAL 0)
string(REGEX MATCH "${CMAKE_INSTALL_LIBDIR}/pkgconfig" SUBSTR "${PC_PATH}")
string(LENGTH "${SUBSTR}" SUBSTR_LEN)
if(SUBSTR_LEN EQUAL 0)
message(WARNING "pkg-config will not detect the new package after installation, adjust PKG_CONFIG_PATH using \"export PKG_CONFIG_PATH=\${PKG_CONFIG_PATH}:${CMAKE_INSTALL_LIBDIR}/pkgconfig\".")
endif()
endif()
endif()
# examples
if(ENABLE_EXAMPLES)
if(NOT ENABLE_SSH_TLS)
message(WARNING "Examples will not be compiled because SSH and TLS are disabled.")
else()
add_subdirectory(examples)
endif()
endif()
# tests
if(ENABLE_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
# create coverage target for generating coverage reports
gen_coverage("test_.*" "test_.*_valgrind")
# generate doxygen documentation for libnetconf2 API
if(ENABLE_COMMON_TARGETS)
gen_doc("${doxy_files}" ${LIBNETCONF2_VERSION} ${LIBNETCONF2_DESCRIPTION} "")
endif()
# generate API/ABI report
if ("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
lib_abi_check(netconf2 "${headers}" ${LIBNETCONF2_SOVERSION_FULL} 8ea8545008b715385c1fe8ccaabe48f3cc9f8e1c)
endif()
# source files to be covered by the 'format' target and a test with 'format-check' target
source_format(${format_sources})
# clean cmake cache
if(ENABLE_COMMON_TARGETS)
add_custom_target(cleancache
COMMAND make clean
COMMAND find . -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} +
COMMAND rm -rf Makefile Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif()
# uninstall
if(ENABLE_COMMON_TARGETS)
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake")
endif()
|