# # Copyright(c) 2006 to 2018 ADLINK Technology Limited and others # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License v. 2.0 which is available at # http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License # v. 1.0 which is available at # http://www.eclipse.org/org/documents/edl-v10.php. # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # include(CheckCSourceCompiles) include(CheckLibraryExists) include(GenerateDummyExportHeader) # Lightweight IP stack can be used on non-embedded targets too, but the # runtime must be instructed to use it instead of the native stack. Of course # for embedded targets there is no "native" stack and the runtime module must # always be instructed to use an "alternative" stack. option(WITH_LWIP "Use lightweight IP stack" OFF) option(WITH_DNS "Enable domain name lookups" ON) option(WITH_FREERTOS "Build for FreeRTOS" OFF) function(check_runtime_feature SOURCE_FILE) get_target_property(_defs ddsrt INTERFACE_COMPILE_DEFINITIONS) foreach(_def ${_defs}) set(_strdefs "${_strdefs} -D${_def}") endforeach() # Generate dummy export header required by feature tests. generate_dummy_export_header( ddsrt BASE_NAME dds EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/cmake/include/dds/export.h") set(_strincs "${CMAKE_CURRENT_BINARY_DIR}/cmake/include") get_target_property(_incs ddsrt INTERFACE_INCLUDE_DIRECTORIES) foreach(_inc ${_incs}) set(_strincs "${_strincs};${_inc}") endforeach() if(_strincs) set(_strincs "-DINCLUDE_DIRECTORIES:STRING=${_strincs}") endif() set(expr "cmake_([_a-zA-Z0-9]+)=([_a-zA-Z0-9]+)") try_compile( foo "${CMAKE_BINARY_DIR}" SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE}" CMAKE_FLAGS "${_strincs}" COMPILE_DEFINITIONS "${_strdefs}" OUTPUT_VARIABLE output) string(REGEX MATCHALL "${expr}" matches "${output}") foreach(match ${matches}) string(REGEX REPLACE "${expr}" "\\1" option "${match}") string(REGEX REPLACE "${expr}" "\\2" value "${match}") set(${option} ${value} PARENT_SCOPE) endforeach() endfunction() if(WITH_FREERTOS) set(system_name freertos) elseif(APPLE) set(system_name darwin) elseif(ANDROID) # FIXME: Not correct, but will do for the short-term. A better way would be # fallback to linux, and then posix. set(system_name linux) else() string(TOLOWER ${CMAKE_SYSTEM_NAME} system_name) endif() # A better choice is to use a so-called object library for ddsrt, but it was # not possible to use target_link_libraries with object libraries until CMake # 3.12. At the time of this writing most long-term stable distributions still # ship an older version, so an interface library with public sources is used # as a workaround for now. add_library(ddsrt INTERFACE) foreach(opt WITH_LWIP WITH_DNS WITH_FREERTOS) if(${opt}) target_compile_definitions(ddsrt INTERFACE DDSRT_${opt}=1) else() target_compile_definitions(ddsrt INTERFACE DDSRT_${opt}=0) endif() endforeach() target_include_directories( ddsrt INTERFACE "$" "$") # Generate version header. configure_file("include/dds/version.h.in" "include/dds/version.h") target_sources( ddsrt INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/include/dds/version.h") if(WIN32) configure_file("include/getopt.h.in" "include/getopt.h" COPYONLY) list(APPEND headers "${CMAKE_CURRENT_BINARY_DIR}/include/getopt.h") list(APPEND sources "${CMAKE_CURRENT_SOURCE_DIR}/src/getopt.c") endif() set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include") set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/src") list(APPEND headers "${include_path}/dds/ddsrt/avl.h" "${include_path}/dds/ddsrt/fibheap.h" "${include_path}/dds/ddsrt/hopscotch.h" "${include_path}/dds/ddsrt/thread_pool.h" "${include_path}/dds/ddsrt/log.h" "${include_path}/dds/ddsrt/retcode.h" "${include_path}/dds/ddsrt/attributes.h" "${include_path}/dds/ddsrt/endian.h" "${include_path}/dds/ddsrt/arch.h" "${include_path}/dds/ddsrt/misc.h" "${include_path}/dds/ddsrt/mh3.h" "${include_path}/dds/ddsrt/io.h" "${include_path}/dds/ddsrt/process.h" "${include_path}/dds/ddsrt/strtod.h" "${include_path}/dds/ddsrt/strtol.h" "${include_path}/dds/ddsrt/types.h" "${include_path}/dds/ddsrt/countargs.h" "${include_path}/dds/ddsrt/static_assert.h" "${include_path}/dds/ddsrt/circlist.h") list(APPEND sources "${source_path}/bswap.c" "${source_path}/io.c" "${source_path}/log.c" "${source_path}/retcode.c" "${source_path}/strtod.c" "${source_path}/strtol.c" "${source_path}/mh3.c" "${source_path}/avl.c" "${source_path}/expand_envvars.c" "${source_path}/fibheap.c" "${source_path}/hopscotch.c" "${source_path}/thread_pool.c" "${source_path}/xmlparser.c" "${source_path}/circlist.c") # Not every target offers the same set of features. For embedded targets the # set of features may even be different between builds. e.g. a FreeRTOS build # could use the lightweight IP stack, but later change to FreeRTOS+TCP. # # Most features and target specific settings can be determined at compile time # by a combination of pre-defined macros. However, some features require input # from the build system. e.g. that the target operating system is FreeRTOS or # that the network stack to be used is lwIP as opposed to the target native # network stack. In order to mix-and-match various compilers, architectures, # operating systems, etc input from the build system is required. foreach(feature atomics cdtors environ heap ifaddrs random rusage sockets string sync threads time md5 process netstat) if(EXISTS "${include_path}/dds/ddsrt/${feature}.h") list(APPEND headers "${include_path}/dds/ddsrt/${feature}.h") file(GLOB_RECURSE files CONFIGURE_DEPENDS "${include_path}/dds/ddsrt/${feature}/*.h") list(APPEND headers ${files}) # Do not add any sources if a feature is not offered by the target. The # headers will define any macros needed by the source code by combining # build system exports and pre-defined macros. To determine if a certain # feature is offered by the target and whether or not to compile any # source files, that information must be made available to CMake. # # Tests that export the required information can be written in # cmake/${feature}.c. A test consists of a source file that includes the # required header files and results in a specifically crafted compiler # error that is picked up by CMake. By default, if a file named after the # feature does not exist in cmake, the feature is expected to be # implemented for all targets. string(TOUPPER "${feature}" feature_uc) set(HAVE_${feature_uc} TRUE) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${feature}.c") check_runtime_feature("cmake/${feature}.c") endif() if(HAVE_${feature_uc}) # Code that is more-or-less the same for all targets can placed in # src/.c. An example would be ddsrt_freeifaddrs. if(EXISTS "${source_path}/${feature}.c") list(APPEND sources "${source_path}/${feature}.c") endif() set(system_exists FALSE) # Headers that must remain private but are required by other runtime # source files must be located in src//dds/ddsrt. if(IS_DIRECTORY "${source_path}/${feature}/include") file(GLOB_RECURSE files CONFIGURE_DEPENDS "${source_path}/${feature}/include/*.h") list(APPEND headers ${files}) target_include_directories( ddsrt INTERFACE "$") endif() # Allow custom implementations for a feature. e.g. lwip as opposed to # windows or posix. set(_system_name "${system_name}") if(NOT HAVE_${feature_uc} MATCHES "[tT][rR][uU][eE]") set(_system_name "${HAVE_${feature_uc}}") endif() foreach(system ${_system_name} posix) if(IS_DIRECTORY "${source_path}/${feature}/${system}") file(GLOB_RECURSE files CONFIGURE_DEPENDS "${source_path}/${feature}/${system}/*.c") list(APPEND sources ${files}) set(system_exists TRUE) endif() # Break as soon a system-specific headers or sources are found. if(system_exists) break() endif() endforeach() else() message(STATUS "Feature ${feature} disabled") endif() else() message(FATAL_ERROR "Feature ${feature} does not exist") endif() endforeach() target_sources(ddsrt INTERFACE ${sources} ${headers}) set(HAVE_MULTI_PROCESS ${HAVE_MULTI_PROCESS} PARENT_SCOPE) if(NOT WITH_FREERTOS) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) find_package(Threads REQUIRED) target_link_libraries(ddsrt INTERFACE Threads::Threads) endif() if(WIN32) target_link_libraries(ddsrt INTERFACE ws2_32 iphlpapi bcrypt) elseif(UNIX) check_library_exists(c clock_gettime "" HAVE_CLOCK_GETTIME) if(NOT HAVE_CLOCK_GETTIME) # Before glibc 2.17, clock_gettime was in librt. check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME_RT) if(HAVE_CLOCK_GETTIME_RT) set(HAVE_CLOCK_GETTIME TRUE) target_link_libraries(ddsrt INTERFACE rt) endif() endif() if(NOT HAVE_CLOCK_GETTIME) message(FATAL_ERROR "clock_gettime is not available") endif() endif() if(${CMAKE_C_COMPILER_ID} STREQUAL "SunPro") target_link_libraries(ddsrt INTERFACE socket nsl) endif() if(BUILD_TESTING) add_subdirectory(tests) endif() install( DIRECTORY "include/" ${CMAKE_CURRENT_BINARY_DIR}/include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" COMPONENT dev FILES_MATCHING PATTERN "*.h")