Commit 02844e598f7b93c7b40eeeb8da7b5b37b29980a0
1 parent
3894f4d8
Added test to library
Showing
28 changed files
with
1773 additions
and
0 deletions
.gitignore
0 → 100644
| 1 | +/build/ |
CMakeLists.txt
0 → 100644
| 1 | +cmake_minimum_required(VERSION 3.30) | ||
| 2 | +project(daemonbase VERSION 0.1 LANGUAGES CXX) | ||
| 3 | +include_guard(GLOBAL) | ||
| 4 | + | ||
| 5 | +if(EXISTS ${CMAKE_SOURCE_DIR}/cmake) | ||
| 6 | + # Use the cmake directives for compilers etc... | ||
| 7 | + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) | ||
| 8 | +else() | ||
| 9 | + message("Cmake source dir : ${CMAKE_SOURCE_DIR}") | ||
| 10 | +endif() | ||
| 11 | + | ||
| 12 | +include_directories( SYSTEM | ||
| 13 | + ${CMAKE_CURRENT_SOURCE_DIR}/include | ||
| 14 | +) | ||
| 15 | + | ||
| 16 | +include(compiler) | ||
| 17 | + | ||
| 18 | +set(SRC_LIST | ||
| 19 | + ${CMAKE_CURRENT_SOURCE_DIR}/include/daemonbase.h | ||
| 20 | + ${CMAKE_CURRENT_SOURCE_DIR}/include/daemonconfig.h | ||
| 21 | + ${CMAKE_CURRENT_SOURCE_DIR}/include/daemonlog.h | ||
| 22 | +) | ||
| 23 | + | ||
| 24 | +include(library) | ||
| 25 | +add_libraries() | ||
| 26 | + | ||
| 27 | +include(installation) | ||
| 28 | +install_component() | ||
| 29 | + | ||
| 30 | +include(packaging) | ||
| 31 | +package_component() | ||
| 32 | + | ||
| 33 | +link_directories( | ||
| 34 | + ${CMAKE_BINARY_DIR}/lib | ||
| 35 | +) | ||
| 36 | + | ||
| 37 | +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) | ||
| 38 | + | ||
| 39 | +add_subdirectory(test) | ||
| 0 | \ No newline at end of file | 40 | \ No newline at end of file |
cmake/COPYING.OSDEV
0 → 100644
| 1 | +/* **************************************************************************** | ||
| 2 | + * Copyright 2019 Open Systems Development BV * | ||
| 3 | + * * | ||
| 4 | + * Permission is hereby granted, free of charge, to any person obtaining a * | ||
| 5 | + * copy of this software and associated documentation files (the "Software"), * | ||
| 6 | + * to deal in the Software without restriction, including without limitation * | ||
| 7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * | ||
| 8 | + * and/or sell copies of the Software, and to permit persons to whom the * | ||
| 9 | + * Software is furnished to do so, subject to the following conditions: * | ||
| 10 | + * * | ||
| 11 | + * The above copyright notice and this permission notice shall be included in * | ||
| 12 | + * all copies or substantial portions of the Software. * | ||
| 13 | + * * | ||
| 14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * | ||
| 15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * | ||
| 16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * | ||
| 17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * | ||
| 18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * | ||
| 19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * | ||
| 20 | + * DEALINGS IN THE SOFTWARE. * | ||
| 21 | + * ***************************************************************************/ | ||
| 0 | \ No newline at end of file | 22 | \ No newline at end of file |
cmake/FindGMock.cmake
0 → 100644
| 1 | +#.rst: | ||
| 2 | +# FindGMock | ||
| 3 | +# --------- | ||
| 4 | +# | ||
| 5 | +# Locate the Google C++ Mocking Framework. | ||
| 6 | +# | ||
| 7 | +# Defines the following variables: | ||
| 8 | +# | ||
| 9 | +# :: | ||
| 10 | +# | ||
| 11 | +# GMOCK_FOUND - Found the Google Testing framework | ||
| 12 | +# GMOCK_INCLUDE_DIRS - Include directories | ||
| 13 | +# | ||
| 14 | +# | ||
| 15 | +# | ||
| 16 | +# Also defines the gmock source path | ||
| 17 | +# | ||
| 18 | +# :: | ||
| 19 | +# | ||
| 20 | +# GMOCK_SOURCE_DIR - directory containing the gmock sources | ||
| 21 | +# | ||
| 22 | +# | ||
| 23 | +# | ||
| 24 | +# Accepts the following variables as input: | ||
| 25 | +# | ||
| 26 | +# :: | ||
| 27 | +# | ||
| 28 | +# GMOCK_ROOT - (as a CMake or environment variable) | ||
| 29 | +# The root directory of the gmock install prefix | ||
| 30 | +# | ||
| 31 | +# | ||
| 32 | +# | ||
| 33 | +# | ||
| 34 | +# Example Usage: | ||
| 35 | +# | ||
| 36 | +# :: | ||
| 37 | +# | ||
| 38 | +# enable_testing() | ||
| 39 | +# find_package(GMock REQUIRED) | ||
| 40 | +# include_directories(${GMOCK_INCLUDE_DIRS}) | ||
| 41 | +# | ||
| 42 | +# | ||
| 43 | +# | ||
| 44 | +# :: | ||
| 45 | +# | ||
| 46 | +# add_executable(foo ${GMOCK_SOURCE_DIR}/gmock-all.cc foo.cc) | ||
| 47 | +# target_link_libraries(foo) | ||
| 48 | +# | ||
| 49 | +# | ||
| 50 | + | ||
| 51 | +find_path(GMOCK_INCLUDE_DIR gmock/gmock.h | ||
| 52 | + HINTS | ||
| 53 | + $ENV{GMOCK_ROOT}/include | ||
| 54 | + ${GMOCK_ROOT}/include | ||
| 55 | +) | ||
| 56 | +mark_as_advanced(GMOCK_INCLUDE_DIR) | ||
| 57 | + | ||
| 58 | +find_path(GMOCK_SOURCE_DIR gmock-all.cc | ||
| 59 | + HINTS | ||
| 60 | + $ENV{GMOCK_ROOT}/src/gmock | ||
| 61 | + ${GMOCK_ROOT}/src/gmock | ||
| 62 | + PATHS | ||
| 63 | + ${GMOCK_INCLUDE_DIR}/../src/gmock | ||
| 64 | +) | ||
| 65 | +mark_as_advanced(GMOCK_SOURCE_DIR) | ||
| 66 | + | ||
| 67 | +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GMock DEFAULT_MSG GMOCK_INCLUDE_DIR GMOCK_SOURCE_DIR) | ||
| 68 | + | ||
| 69 | +if(GMOCK_FOUND) | ||
| 70 | + set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR}) | ||
| 71 | +endif() | ||
| 72 | + |
cmake/FindJsoncpp.cmake
0 → 100644
| 1 | +# Locate jsoncpp | ||
| 2 | +# | ||
| 3 | +# This module defines | ||
| 4 | +# JSONCPP_FOUND, if false, do not try to link to jsoncpp | ||
| 5 | +# JSONCPP_LIBRARY, where to find jsoncpp | ||
| 6 | +# JSONCPP_INCLUDE_DIR, where to find json.h | ||
| 7 | +# | ||
| 8 | +# By default, the dynamic libraries of jsoncpp will be found. To find the static ones instead, | ||
| 9 | +# you must set the JSONCPP_STATIC_LIBRARY variable to TRUE before calling find_package(Jsoncpp ...). | ||
| 10 | +# | ||
| 11 | +# If jsoncpp is not installed in a standard path, you can use the JSONCPP_DIR CMake variable | ||
| 12 | +# to tell CMake where jsoncpp is. | ||
| 13 | + | ||
| 14 | +set(JSONCPP_FOUND 0) | ||
| 15 | + | ||
| 16 | +# attempt to find static library first if this is set | ||
| 17 | +if(JSONCPP_STATIC_LIBRARY) | ||
| 18 | + set(JSONCPP_STATIC libjsoncpp.a) | ||
| 19 | +endif() | ||
| 20 | + | ||
| 21 | +# find the jsoncpp include directory | ||
| 22 | +find_path(JSONCPP_INCLUDE_DIR json/json.h | ||
| 23 | + PATHS | ||
| 24 | + ~/Library/Frameworks/jsoncpp/include/ | ||
| 25 | + /Library/Frameworks/jsoncpp/include/ | ||
| 26 | + /usr/local/include/ | ||
| 27 | + /usr/include/ | ||
| 28 | + /sw/jsoncpp/ # Fink | ||
| 29 | + /opt/local/jsoncpp/ # DarwinPorts | ||
| 30 | + /opt/csw/jsoncpp/ # Blastwave | ||
| 31 | + /opt/jsoncpp/ | ||
| 32 | + ${JSONCPP_DIR}/include/ | ||
| 33 | + PATH_SUFFIXES jsoncpp) | ||
| 34 | + | ||
| 35 | +# find the jsoncpp library | ||
| 36 | +find_library(JSONCPP_LIBRARY | ||
| 37 | + NAMES ${JSONCPP_STATIC} jsoncpp | ||
| 38 | + PATH_SUFFIXES lib64 lib | ||
| 39 | + PATHS ~/Library/Frameworks | ||
| 40 | + /Library/Frameworks | ||
| 41 | + /usr/local | ||
| 42 | + /usr | ||
| 43 | + /sw | ||
| 44 | + /opt/local | ||
| 45 | + /opt/csw | ||
| 46 | + /opt | ||
| 47 | + ${JSONCPP_DIR}/lib) | ||
| 48 | + | ||
| 49 | +# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE if all listed variables are TRUE | ||
| 50 | +include(FindPackageHandleStandardArgs) | ||
| 51 | +FIND_PACKAGE_HANDLE_STANDARD_ARGS(JSONCPP DEFAULT_MSG JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY) | ||
| 52 | +mark_as_advanced(JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY) | ||
| 53 | +message("JSONCPP_FOUND = ${JSONCPP_FOUND}, includedir = ${JSONCPP_INCLUDE_DIR}, lib = ${JSONCPP_LIBRARY}") |
cmake/FindYamlCpp.cmake
0 → 100644
| 1 | +# Locate yaml-cpp | ||
| 2 | +# | ||
| 3 | +# This module defines | ||
| 4 | +# YAMLCPP_FOUND, if false, do not try to link to yaml-cpp | ||
| 5 | +# YAMLCPP_LIBRARY, where to find yaml-cpp | ||
| 6 | +# YAMLCPP_INCLUDE_DIR, where to find yaml.h | ||
| 7 | +# | ||
| 8 | +# By default, the dynamic libraries of yaml-cpp will be found. To find the static ones instead, | ||
| 9 | +# you must set the YAMLCPP_STATIC_LIBRARY variable to TRUE before calling find_package(YamlCpp ...). | ||
| 10 | +# | ||
| 11 | +# If yaml-cpp is not installed in a standard path, you can use the YAMLCPP_DIR CMake variable | ||
| 12 | +# to tell CMake where yaml-cpp is. | ||
| 13 | + | ||
| 14 | +# attempt to find static library first if this is set | ||
| 15 | +if(YAMLCPP_STATIC_LIBRARY) | ||
| 16 | + set(YAMLCPP_STATIC libyaml-cpp.a) | ||
| 17 | +endif() | ||
| 18 | + | ||
| 19 | +# find the yaml-cpp include directory | ||
| 20 | +find_path(YAMLCPP_INCLUDE_DIR yaml-cpp/yaml.h | ||
| 21 | + PATH_SUFFIXES include | ||
| 22 | + PATHS | ||
| 23 | + ~/Library/Frameworks/yaml-cpp/include/ | ||
| 24 | + /Library/Frameworks/yaml-cpp/include/ | ||
| 25 | + /usr/local/include/ | ||
| 26 | + /usr/include/ | ||
| 27 | + /sw/yaml-cpp/ # Fink | ||
| 28 | + /opt/local/yaml-cpp/ # DarwinPorts | ||
| 29 | + /opt/csw/yaml-cpp/ # Blastwave | ||
| 30 | + /opt/yaml-cpp/ | ||
| 31 | + ${YAMLCPP_DIR}/include/) | ||
| 32 | + | ||
| 33 | +# find the yaml-cpp library | ||
| 34 | +find_library(YAMLCPP_LIBRARY | ||
| 35 | + NAMES ${YAMLCPP_STATIC} yaml-cpp | ||
| 36 | + PATH_SUFFIXES lib64 lib | ||
| 37 | + PATHS ~/Library/Frameworks | ||
| 38 | + /Library/Frameworks | ||
| 39 | + /usr/local | ||
| 40 | + /usr | ||
| 41 | + /sw | ||
| 42 | + /opt/local | ||
| 43 | + /opt/csw | ||
| 44 | + /opt | ||
| 45 | + ${YAMLCPP_DIR}/lib) | ||
| 46 | + | ||
| 47 | +# handle the QUIETLY and REQUIRED arguments and set YAMLCPP_FOUND to TRUE if all listed variables are TRUE | ||
| 48 | +include(FindPackageHandleStandardArgs) | ||
| 49 | +FIND_PACKAGE_HANDLE_STANDARD_ARGS(YAMLCPP DEFAULT_MSG YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY) | ||
| 50 | +mark_as_advanced(YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY) |
cmake/application.cmake
0 → 100644
| 1 | +# @brief Adds an executable target and performs related actions, | ||
| 2 | +# such as verioning, binary dir and configuration. | ||
| 3 | +# @note The default binary directory is PROJECT_BINARY_DIR, but can be overridden by specifying the ${PROJECT_NAME}_CURRENT_BINARY_DIR. | ||
| 4 | +function(add_application) | ||
| 5 | + | ||
| 6 | +message( STATUS "${PROJECT_NAME} linking libraries : ${ARGN}") | ||
| 7 | + | ||
| 8 | +# Use PROJECT_BINARY_DIR by default, but override if necessary. | ||
| 9 | +set(CURRENT_PROJECT_BINARY_DIR ${PROJECT_BINARY_DIR}) | ||
| 10 | +if (${PROJECT_NAME}_CURRENT_BINARY_DIR) | ||
| 11 | + set(CURRENT_PROJECT_BINARY_DIR ${${PROJECT_NAME}_CURRENT_BINARY_DIR}) | ||
| 12 | +endif() | ||
| 13 | +message(STATUS "CURRENT_PROJECT_BINARY_DIR : ${CURRENT_PROJECT_BINARY_DIR}") | ||
| 14 | + | ||
| 15 | +include_directories(${HSOA_VERSION_INCLUDE_DIR}) | ||
| 16 | + | ||
| 17 | +add_executable( ${PROJECT_NAME} | ||
| 18 | + ${HSOA_VERSION_SRC_FILE} | ||
| 19 | + ${SRC_LIST} | ||
| 20 | +) | ||
| 21 | + | ||
| 22 | +target_link_libraries( ${PROJECT_NAME} | ||
| 23 | + ${ARGN} | ||
| 24 | +) | ||
| 25 | + | ||
| 26 | +set_target_properties( ${PROJECT_NAME} | ||
| 27 | + PROPERTIES | ||
| 28 | + VERSION ${PROJECT_VERSION} | ||
| 29 | + RUNTIME_OUTPUT_DIRECTORY ${CURRENT_PROJECT_BINARY_DIR}/bin | ||
| 30 | +) | ||
| 31 | + | ||
| 32 | +# Copy the testconfig to the build dir, so the binaries are testable from the build dir. | ||
| 33 | +# The created packages will not contain the testconfig but the production config instead. See installation.cmake. | ||
| 34 | +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/testconfig/) | ||
| 35 | + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/testconfig/" DESTINATION "${CURRENT_PROJECT_BINARY_DIR}/etc") | ||
| 36 | +endif() | ||
| 37 | + | ||
| 38 | +endfunction() |
cmake/application.post_install.inc.cmake.in
0 → 100644
| 1 | +# Make sure the mLogic group exists | ||
| 2 | +MLOGIC_GROUP=mlogic | ||
| 3 | +groupadd --force $MLOGIC_GROUP | ||
| 4 | +# Create the user | ||
| 5 | +appuserid=$(id -u @PROJECT_NAME@) | ||
| 6 | +if [ ! $appuserid ] ; then | ||
| 7 | + useradd --groups $MLOGIC_GROUP --no-create-home @PROJECT_NAME@ | ||
| 8 | +fi | ||
| 9 | +# Prevent direct login | ||
| 10 | +passwd --lock @PROJECT_NAME@ | ||
| 11 | +# Change group ownership of log folder | ||
| 12 | +chgrp $MLOGIC_GROUP @PROJCOMP_LOG_INSTALL_DIR@ | ||
| 13 | +# Change group ownership of run folder | ||
| 14 | +chgrp $MLOGIC_GROUP @PROJCOMP_RUN_INSTALL_DIR@ |
cmake/application.post_uninstall.inc.cmake.in
0 → 100644
cmake/artifacts.cmake
0 → 100644
| 1 | +# @brief Tries to find the module with find_package, and uses CMAKE_INSTALL_PREFIX (see documentation). | ||
| 2 | +# If the module can't be found, includes the directory by the specified module path. | ||
| 3 | +# @param module The name of the module on which a dependency is added | ||
| 4 | +# @param modulepath The relative path of the module wrt the current project | ||
| 5 | +# @param moduleincludepath [optional] The relative path to the include directory | ||
| 6 | +# @note Needs to be a macro because of the scope of the variables that are set by find_package. | ||
| 7 | +macro(depend_module module modulepath) | ||
| 8 | + message(STATUS "module : ${module}") | ||
| 9 | + message(STATUS "modulepath : ${modulepath}") | ||
| 10 | + | ||
| 11 | + set ( optional_macro_args ${ARGN} ) | ||
| 12 | + list ( LENGTH optional_macro_args num_optional_args ) | ||
| 13 | + if ( ${num_optional_args} GREATER 0 ) | ||
| 14 | + list ( GET optional_macro_args 0 moduleincludepath ) | ||
| 15 | + else() | ||
| 16 | + set ( moduleincludepath include ) | ||
| 17 | + endif() | ||
| 18 | + message(STATUS "moduleincludepath : ${moduleincludepath}") | ||
| 19 | + | ||
| 20 | + find_package(${module} CONFIG QUIET) | ||
| 21 | + message( STATUS "${module}_FOUND: ${${module}_FOUND}" ) | ||
| 22 | + | ||
| 23 | + string( TOUPPER ${module} MODULE_NAME_UPPER ) | ||
| 24 | + | ||
| 25 | + # check if the constructed variable name exists and if so check also the content. | ||
| 26 | + if ( NOT ${${module}_FOUND} ) | ||
| 27 | + if ( NOT TARGET ${module} ) | ||
| 28 | + message( STATUS "Adding subdirectory ${modulepath}/${module} as subdirectory ${CMAKE_CURRENT_LIST_DIR}/staging/${module}." ) | ||
| 29 | + add_subdirectory(${modulepath}/${module} staging/${module}) | ||
| 30 | + endif() | ||
| 31 | + | ||
| 32 | + set( ${MODULE_NAME_UPPER}_INCLUDE_DIR ${modulepath}/${module}/${moduleincludepath} CACHE STRING "${module} include path" FORCE ) | ||
| 33 | + set( ${MODULE_NAME_UPPER}_LIB_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "${module} library path" FORCE ) | ||
| 34 | + set( ${MODULE_NAME_UPPER}_LIB_NAME "${module}" CACHE STRING "${module} library name" FORCE ) | ||
| 35 | + endif() | ||
| 36 | + | ||
| 37 | + message( STATUS "${MODULE_NAME_UPPER}_INCLUDE_DIR: ${${MODULE_NAME_UPPER}_INCLUDE_DIR}" ) | ||
| 38 | + message( STATUS "${MODULE_NAME_UPPER}_LIB_DIR: ${${MODULE_NAME_UPPER}_LIB_DIR}" ) | ||
| 39 | + message( STATUS "${MODULE_NAME_UPPER}_LIB_NAME: ${${MODULE_NAME_UPPER}_LIB_NAME}" ) | ||
| 40 | +endmacro() |
cmake/compiler.cmake
0 → 100644
| 1 | +include(CheckCXXCompilerFlag) | ||
| 2 | + | ||
| 3 | +set(PLATFORM_RELEASE "") | ||
| 4 | +function(platformRelease) | ||
| 5 | + set(PR, "") | ||
| 6 | + execute_process(COMMAND /bin/bash -c "if [ -e /etc/redhat-release ]; then cat /etc/redhat-release | tr -d '\n'; fi" OUTPUT_VARIABLE PR) | ||
| 7 | + message(STATUS "Platform is ${PR}") | ||
| 8 | + set(PLATFORM_RELEASE "${PR}" PARENT_SCOPE) | ||
| 9 | +endfunction(platformRelease) | ||
| 10 | + | ||
| 11 | +# The target architecture (-march, -mtune) is assumed to be the architecture that was used to build gcc. | ||
| 12 | +# If cross-compilation is required, this should be specified as cmake arguments. | ||
| 13 | + | ||
| 14 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wshadow" ) | ||
| 15 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Woverloaded-virtual -Winit-self -Wuninitialized -Wunused -Wcast-qual" ) | ||
| 16 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-long-long" ) | ||
| 17 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast" ) | ||
| 18 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-type" ) | ||
| 19 | + | ||
| 20 | +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^x86_64") | ||
| 21 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-noexcept-type" ) | ||
| 22 | +endif() | ||
| 23 | + | ||
| 24 | +if(CMAKE_COMPILER_IS_GNUCC | ||
| 25 | + AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9 | ||
| 26 | + AND NOT APPLE) | ||
| 27 | + # Mac OSX doesn't seem to honour -isystem, so not for Mac. | ||
| 28 | + # Also, GCC 4.8 complains about boost | ||
| 29 | + MESSAGE(STATUS "Don't treat warnings as errors") | ||
| 30 | +else() | ||
| 31 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror" ) | ||
| 32 | +endif() | ||
| 33 | +if(BUILD_WITH_PROFILING) | ||
| 34 | + message(STATUS "Profiling enabled") | ||
| 35 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg" ) | ||
| 36 | +else() | ||
| 37 | + message(STATUS "Profiling disabled") | ||
| 38 | +endif() | ||
| 39 | + | ||
| 40 | +# Allow linking into a dynamic library | ||
| 41 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC" ) | ||
| 42 | + | ||
| 43 | +# Use RelWithDebInfo as default build type | ||
| 44 | +if (NOT CMAKE_BUILD_TYPE) | ||
| 45 | + set(CMAKE_BUILD_TYPE "RelWithDebInfo") | ||
| 46 | +endif() | ||
| 47 | +message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") | ||
| 48 | + | ||
| 49 | +if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") | ||
| 50 | + set(NOASSERTS 1) # Disable asserts as well | ||
| 51 | + # -O3 causes weird crashes on win32 so we force -O2 for release builds also for linux builds | ||
| 52 | + string(REGEX REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") | ||
| 53 | + string(REGEX REPLACE "-O3" "-O2" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") | ||
| 54 | + if(MINGW) | ||
| 55 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s") | ||
| 56 | + endif() | ||
| 57 | +else() | ||
| 58 | + # Let Qt track the use of QSharedPointer | ||
| 59 | + set(CMAKE_CXX_CFLAGS "${CMAKE_CXX_FLAGS} -DQT_SHAREDPOINTER_TRACK_POINTERS") | ||
| 60 | + # If we're debugging, remove -O2 completely | ||
| 61 | + string(REGEX REPLACE "-O2" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") | ||
| 62 | + string(REGEX REPLACE "-O2" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") | ||
| 63 | + string(REGEX REPLACE "-O2" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") | ||
| 64 | + string(REGEX REPLACE "-O2" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") | ||
| 65 | +endif() | ||
| 66 | + | ||
| 67 | +# Disable asserts with -DNOASSERTS=1 as a CMake command-line parameter | ||
| 68 | +if(NOASSERTS) | ||
| 69 | + add_definitions(-DQT_NO_DEBUG) | ||
| 70 | + add_definitions(-DNDEBUG) | ||
| 71 | + message(STATUS "Asserts have been disabled") | ||
| 72 | +endif(NOASSERTS) | ||
| 73 | + | ||
| 74 | +if(APPLE) | ||
| 75 | + # AVX instructions currently cause assembler errors, so disabling them | ||
| 76 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w -mno-avx -mmacosx-version-min=10.7 -stdlib=libc++ ") | ||
| 77 | + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w -mno-avx -mmacosx-version-min=10.7") | ||
| 78 | +endif(APPLE) | ||
| 79 | + | ||
| 80 | +if(UNIX) | ||
| 81 | + if(BUILD_WITH_COVERAGE) | ||
| 82 | + # Specifically enable coverate info, since ccache can't cache with | ||
| 83 | + # profiling enabled, seriously hurting build-times in Debug-mode | ||
| 84 | + message(STATUS "Generate coverage info") | ||
| 85 | + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") | ||
| 86 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") | ||
| 87 | + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") | ||
| 88 | + if (NOT TARGET RemoveGCDA) | ||
| 89 | + add_custom_target(RemoveGCDA ALL | ||
| 90 | + COMMAND find . -name "*.gcda" -delete | ||
| 91 | + COMMENT "Removing gcda files") | ||
| 92 | + endif(NOT TARGET RemoveGCDA) | ||
| 93 | + | ||
| 94 | + if(NOT NOASSERTS) | ||
| 95 | + add_definitions(-DQT_SHAREDPOINTER_TRACK_POINTERS) | ||
| 96 | + endif(NOT NOASSERTS) | ||
| 97 | + else() | ||
| 98 | + message(STATUS "Building without coverage info") | ||
| 99 | + endif() | ||
| 100 | +endif(UNIX) | ||
| 101 | + | ||
| 102 | +if(UNIX AND NOT APPLE) | ||
| 103 | + # needed for making qwt happy | ||
| 104 | + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lrt" ) | ||
| 105 | +endif(UNIX AND NOT APPLE) | ||
| 106 | + | ||
| 107 | +if(MINGW) | ||
| 108 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows" ) | ||
| 109 | +endif(MINGW) | ||
| 110 | + | ||
| 111 | +CHECK_CXX_COMPILER_FLAG( -fstack-protector-all result ) | ||
| 112 | +if(result) | ||
| 113 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-all") | ||
| 114 | +endif(result) | ||
| 115 | + | ||
| 116 | +CHECK_CXX_COMPILER_FLAG( -fthreadsafe-statics THREADSAFE_RESULT) | ||
| 117 | +if( NOT THREADSAFE_RESULT) | ||
| 118 | + message(FATAL_ERROR, "Compiler does not support threadsafe statics variables in methods") | ||
| 119 | +endif() | ||
| 120 | +# We use static variables in method scope, they must be threadsafe, this is on by default since gcc 4 but this flag is a check | ||
| 121 | +# If the compiler does not support this then build will fail. | ||
| 122 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fthreadsafe-statics") | ||
| 123 | + | ||
| 124 | +if(CMAKE_COMPILER_IS_GNUCXX) | ||
| 125 | + # Check on which architecture we are. ARM doesn't support mfpmath | ||
| 126 | + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^x86_64") | ||
| 127 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse" ) | ||
| 128 | + endif() | ||
| 129 | + | ||
| 130 | + MESSAGE(STATUS "Checking the c++ Standard supported by the compiler" ) | ||
| 131 | + # Check which version of c++ we can use. We drill down from c++17 to c96 | ||
| 132 | + CHECK_CXX_COMPILER_FLAG( -std=c++17 cxxresult ) | ||
| 133 | + if( NOT cxxresult ) | ||
| 134 | + CHECK_CXX_COMPILER_FLAG( -std=c++14 cxxresult ) | ||
| 135 | + if( NOT cxxresult ) | ||
| 136 | + CHECK_CXX_COMPILER_FLAG( -std=c++11 cxxresult ) | ||
| 137 | + if( NOT cxxresult ) | ||
| 138 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") | ||
| 139 | + else() | ||
| 140 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") | ||
| 141 | + endif() | ||
| 142 | + else() | ||
| 143 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") | ||
| 144 | + endif() | ||
| 145 | + else() | ||
| 146 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") | ||
| 147 | + endif() | ||
| 148 | + MESSAGE(STATUS "Compiling for ${CMAKE_CXX_FLAGS}") | ||
| 149 | + | ||
| 150 | + # -Wzero-as-null-pointer-constant is disabled for now, since the Qt 4.8.4 | ||
| 151 | + # macro's produce a bucketload of these warnings. Might be useful later on. | ||
| 152 | +# CHECK_CXX_COMPILER_FLAG( -Wzero-as-null-pointer-constant cxxresult ) | ||
| 153 | +# if(cxxresult) | ||
| 154 | +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant") | ||
| 155 | +# endif(cxxresult) | ||
| 156 | + # Leave out deprecation warnings, mostly generated by CppUnit | ||
| 157 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") | ||
| 158 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weffc++") | ||
| 159 | + | ||
| 160 | +endif(CMAKE_COMPILER_IS_GNUCXX) | ||
| 161 | + | ||
| 162 | +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") | ||
| 163 | + MESSAGE(STATUS "Enabling Clang flags") | ||
| 164 | + # We enable all warnings and disable what we don't need | ||
| 165 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything") | ||
| 166 | + # Warns if items need to be re-aligned to 4-byte boundaries. Since we use | ||
| 167 | + # booleans in our code, these warnings are all over the place. If | ||
| 168 | + # memory-usage becomes an issue, we can pack all booleans together using | ||
| 169 | + # this warning. However, it's currently not practical to eliminate them all. | ||
| 170 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-padded") | ||
| 171 | + # We use a lot of static objects, which get cleaned up at exit by their destructors. | ||
| 172 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-exit-time-destructors") | ||
| 173 | + # Static objects tend to have global constructors | ||
| 174 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-global-constructors") | ||
| 175 | + # We mix int / unsigned int a lot, so disabled it for the moment | ||
| 176 | + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-conversion") | ||
| 177 | + # Warning caused by the Qt translations | ||
| 178 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-prototypes") | ||
| 179 | + # We standardize on C++11, so don't bother us with C++98 | ||
| 180 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++98-compat -Wno-c++98-compat-pedantic") | ||
| 181 | + # We explicitly want to use the switch(){default: break;} construction | ||
| 182 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-switch-enum") | ||
| 183 | + # Q_OBJECT does an "int i = i;"... | ||
| 184 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-self-assign") | ||
| 185 | + # Compile for C++11 | ||
| 186 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") | ||
| 187 | + # Don't complain about unused arguments, since this also triggers warnings | ||
| 188 | + # about include-directories that are unused... | ||
| 189 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments") | ||
| 190 | + # Don't complain about fall-throughs in switch/case statements | ||
| 191 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-implicit-fallthrough") | ||
| 192 | + # Since "Q_ASSERT(false)" creates a not of noise, disable it when asserts are active | ||
| 193 | + if(NOT NOASSERTS) | ||
| 194 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unreachable-code") | ||
| 195 | + endif(NOT NOASSERTS) | ||
| 196 | + # There is no way to avoid this warning right now, so we disable it | ||
| 197 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-weak-template-vtables") | ||
| 198 | + # Warning caused by Qt resource files, so disabling it | ||
| 199 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-variable-declarations") | ||
| 200 | + # WORKAROUND: Somehow Qt forgets that Clang is a C++11 compiler | ||
| 201 | + ADD_DEFINITIONS("-DQ_COMPILER_INITIALIZER_LISTS") | ||
| 202 | + # Clang 3.3 doesn't know Doxygens' "\test" and "\retval" tags, so disabling | ||
| 203 | + # check for unknown tags for now | ||
| 204 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-documentation-unknown-command") | ||
| 205 | + | ||
| 206 | + if(CMAKE_CXX_COMPILER_VERSION MATCHES "3\\.4\\.2") | ||
| 207 | + message(STATUS "compiler is clang version 3.4.2") | ||
| 208 | + platformRelease() | ||
| 209 | + if("${PLATFORM_RELEASE}" MATCHES "CentOS Linux release 7\\.2\\..+") | ||
| 210 | + # Override the gnu minor version only for this specific combination of platform and clang version | ||
| 211 | + set(CMAKE_CXX_FLAGS "-U__GNUC_MINOR__ -D__GNUC_MINOR__=3 ${CMAKE_CXX_FLAGS}") | ||
| 212 | + message(STATUS "Overriding clang gnu minor version to 3 so that several libstd c++11 features like tuple can be used") | ||
| 213 | + endif("${PLATFORM_RELEASE}" MATCHES "CentOS Linux release 7\\.2\\..+") | ||
| 214 | + endif(CMAKE_CXX_COMPILER_VERSION MATCHES "3\\.4\\.2") | ||
| 215 | +endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") | ||
| 216 | + | ||
| 217 | +if(APPLE) | ||
| 218 | + set(WHOLE_ARCHIVE_ON "-all_load") | ||
| 219 | + set(WHOLE_ARCHIVE_OFF "") | ||
| 220 | +else() | ||
| 221 | + set(WHOLE_ARCHIVE_ON "-Wl,-whole-archive") | ||
| 222 | + set(WHOLE_ARCHIVE_OFF "-Wl,-no-whole-archive") | ||
| 223 | +endif() |
cmake/config.cmake.in
0 → 100644
| 1 | +@PACKAGE_INIT@ | ||
| 2 | + | ||
| 3 | +string( TOUPPER @PROJECT_NAME@ PROJECT_NAME_UPPER ) | ||
| 4 | + | ||
| 5 | +string( CONCAT MY_PACKAGE_INCLUDE_DIR ${PROJECT_NAME_UPPER} "_INCLUDE_DIR" ) | ||
| 6 | +set_and_check(${MY_PACKAGE_INCLUDE_DIR} "@PACKAGE_PROJCOMP_INCLUDE_INSTALL_DIR@") | ||
| 7 | +message( STATUS "${MY_PACKAGE_INCLUDE_DIR}: ${${MY_PACKAGE_INCLUDE_DIR}}" ) | ||
| 8 | + | ||
| 9 | +string( CONCAT MY_PACKAGE_LIB_DIR ${PROJECT_NAME_UPPER} "_LIB_DIR" ) | ||
| 10 | +set_and_check(${MY_PACKAGE_LIB_DIR} "@PACKAGE_PROJCOMP_LIB_INSTALL_DIR@") | ||
| 11 | +message( STATUS "${MY_PACKAGE_LIB_DIR}: ${${MY_PACKAGE_LIB_DIR}}" ) | ||
| 12 | + | ||
| 13 | +string( CONCAT MY_PACKAGE_CMAKE_DIR ${PROJECT_NAME_UPPER} "_CMAKE_DIR" ) | ||
| 14 | +set_and_check(${MY_PACKAGE_CMAKE_DIR} "@PACKAGE_PROJCOMP_CMAKE_INSTALL_DIR@") | ||
| 15 | +message( STATUS "${MY_PACKAGE_CMAKE_DIR}: ${${MY_PACKAGE_CMAKE_DIR}}" ) | ||
| 16 | + | ||
| 17 | +string( CONCAT MY_PACKAGE_LIB_NAME ${PROJECT_NAME_UPPER} "_LIB_NAME" ) | ||
| 18 | +set(${MY_PACKAGE_LIB_NAME} "@PROJECT_NAME@") | ||
| 19 | +message( STATUS "${MY_PACKAGE_LIB_NAME}: ${${MY_PACKAGE_LIB_NAME}}" ) | ||
| 20 | + | ||
| 21 | +check_required_components("@PROJECT_NAME@") | ||
| 22 | +#message( STATUS "@PROJECT_NAME@_FOUND: ${${@PROJECT_NAME@}_FOUND}" ) |
cmake/installation.cmake
0 → 100644
| 1 | +set( INSTALLATION_CURRENT_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR} ) | ||
| 2 | + | ||
| 3 | +# Layout | ||
| 4 | +set(USR_LOCAL_DIR "/usr/local" CACHE STRING "" FORCE) | ||
| 5 | +set(LD_SO_CONF_D_DIR "/etc/ld.so.conf.d" CACHE STRING "" FORCE) | ||
| 6 | +set(SYSTEMD_CONFIG_DIR "/etc/systemd/system" CACHE STRING "" FORCE) | ||
| 7 | +set(VAR_LOG_DIR "/var/log" CACHE STRING "" FORCE) | ||
| 8 | +set(VAR_RUN_DIR "/var/run" CACHE STRING "" FORCE) | ||
| 9 | +set(PROJCOMP_LOG_INSTALL_DIR "${VAR_LOG_DIR}/${PROJECT_NAME}") | ||
| 10 | +set(PROJCOMP_RUN_INSTALL_DIR "${VAR_RUN_DIR}/${PROJECT_NAME}") | ||
| 11 | +set(PROJCOMP_BIN_INSTALL_DIR "${PROJECT_NAME}/bin") | ||
| 12 | +set(PROJCOMP_LIB_INSTALL_DIR "lib") | ||
| 13 | +set(PROJCOMP_INCLUDE_INSTALL_DIR "${PROJECT_NAME}/include") | ||
| 14 | +set(PROJCOMP_ETC_INSTALL_DIR "${PROJECT_NAME}/etc") | ||
| 15 | +set(PROJCOMP_CMAKE_INSTALL_DIR "${PROJECT_NAME}/cmake") | ||
| 16 | +set(PROJCOMP_COMPONENT_NAME "${REPOSITORY_PACKAGE_NAME}-${PROJECT_NAME}") | ||
| 17 | +set(PROJCOMP_COMPONENT_NAME_DEVEL "${PROJCOMP_COMPONENT_NAME}-devel") | ||
| 18 | + | ||
| 19 | +# @brief Installs a library component and performs related actions. | ||
| 20 | +function(install_component) | ||
| 21 | + | ||
| 22 | +set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") | ||
| 23 | + | ||
| 24 | +# Configuration | ||
| 25 | +string(TOLOWER ${PROJECT_NAME} MODULE_NAME_LOWER) | ||
| 26 | +set(PROJECT_CONFIG "${GENERATED_DIR}/${MODULE_NAME_LOWER}-config.cmake") | ||
| 27 | + | ||
| 28 | +# Generate the cmake config file | ||
| 29 | +include(CMakePackageConfigHelpers) | ||
| 30 | +configure_package_config_file( | ||
| 31 | + "${INSTALLATION_CURRENT_CMAKE_DIR}/config.cmake.in" | ||
| 32 | + "${PROJECT_CONFIG}" | ||
| 33 | + INSTALL_DESTINATION "${PROJCOMP_CMAKE_INSTALL_DIR}" | ||
| 34 | + PATH_VARS PROJCOMP_INCLUDE_INSTALL_DIR PROJCOMP_LIB_INSTALL_DIR PROJCOMP_CMAKE_INSTALL_DIR | ||
| 35 | +) | ||
| 36 | + | ||
| 37 | +# Install license file | ||
| 38 | +if (EXISTS "${INSTALLATION_CURRENT_CMAKE_DIR}/COPYING.OSDEV") | ||
| 39 | + install( | ||
| 40 | + FILES "${INSTALLATION_CURRENT_CMAKE_DIR}/COPYING.OSDEV" | ||
| 41 | + DESTINATION ${PROJCOMP_LIB_INSTALL_DIR} | ||
| 42 | + COMPONENT "${PROJCOMP_COMPONENT_NAME}" | ||
| 43 | + ) | ||
| 44 | +endif() | ||
| 45 | + | ||
| 46 | +# Install targets | ||
| 47 | +install( | ||
| 48 | + TARGETS ${PROJECT_NAME} | ||
| 49 | + DESTINATION ${PROJCOMP_LIB_INSTALL_DIR} | ||
| 50 | + COMPONENT "${PROJCOMP_COMPONENT_NAME}" | ||
| 51 | +) | ||
| 52 | + | ||
| 53 | +# Configure and install dynamic linker runtime bindings (ld.so.conf.d file) | ||
| 54 | +configure_file( | ||
| 55 | + "${INSTALLATION_CURRENT_CMAKE_DIR}/ld.so.conf.d.cmake.in" | ||
| 56 | + "${GENERATED_DIR}/${PROJECT_NAME}.conf" | ||
| 57 | +) | ||
| 58 | +install( | ||
| 59 | + FILES "${GENERATED_DIR}/${PROJECT_NAME}.conf" | ||
| 60 | + DESTINATION ${LD_SO_CONF_D_DIR} | ||
| 61 | + COMPONENT "${PROJCOMP_COMPONENT_NAME}" | ||
| 62 | +) | ||
| 63 | + | ||
| 64 | +# Configure and set cpack post install script | ||
| 65 | +configure_file( | ||
| 66 | + "${INSTALLATION_CURRENT_CMAKE_DIR}/library.post_install.inc.cmake.in" | ||
| 67 | + "${GENERATED_DIR}/library.post_install.inc" | ||
| 68 | +) | ||
| 69 | +# Set the per-component post install script file. | ||
| 70 | +set(CPACK_RPM_${PROJCOMP_COMPONENT_NAME}_POST_INSTALL_SCRIPT_FILE "${GENERATED_DIR}/library.post_install.inc" CACHE STRING "${PROJECT_NAME} post_install script" FORCE) | ||
| 71 | + | ||
| 72 | +# Headers | ||
| 73 | +# At the moment, we anticipate the headers to be located according to either 1) or 2). | ||
| 74 | + | ||
| 75 | +# 1) Apply glob style pattern for those projects that have the header files in the root folder of the repository (such as opcua_model). | ||
| 76 | +file (GLOB PACKAGE_HEADERS "${CMAKE_CURRENT_LIST_DIR}/*.h*") | ||
| 77 | +install( | ||
| 78 | + FILES ${PACKAGE_HEADERS} | ||
| 79 | + DESTINATION ${PROJCOMP_INCLUDE_INSTALL_DIR} | ||
| 80 | + COMPONENT "${PROJCOMP_COMPONENT_NAME_DEVEL}" | ||
| 81 | +) | ||
| 82 | +# 2) Copy the include dir for those projects that have the header files in include/mlogic (such as opc_utils). | ||
| 83 | +if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/include/mlogic) | ||
| 84 | + install( | ||
| 85 | + DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/mlogic | ||
| 86 | + DESTINATION ${PROJCOMP_INCLUDE_INSTALL_DIR} | ||
| 87 | + COMPONENT "${PROJCOMP_COMPONENT_NAME_DEVEL}" | ||
| 88 | + ) | ||
| 89 | +endif() | ||
| 90 | + | ||
| 91 | +# Install cmake project config | ||
| 92 | +install( | ||
| 93 | + FILES ${PROJECT_CONFIG} | ||
| 94 | + DESTINATION ${PROJCOMP_CMAKE_INSTALL_DIR} | ||
| 95 | + COMPONENT "${PROJCOMP_COMPONENT_NAME_DEVEL}" | ||
| 96 | +) | ||
| 97 | + | ||
| 98 | +# The -devel package depends on the runtime package | ||
| 99 | +set(CPACK_RPM_${PROJCOMP_COMPONENT_NAME_DEVEL}_PACKAGE_REQUIRES "${PROJCOMP_COMPONENT_NAME} = ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}-${CURRENT_PROJECT_VERSION_RELEASENR}" CACHE STRING "${PROJCOMP_COMPONENT_NAME_DEVEL} dependency" FORCE ) | ||
| 100 | +# Clear the dependencies for the runtime package, as cpack erroneously added unexpected dependencies (hints towards the previously built package) | ||
| 101 | +set(CPACK_RPM_${PROJCOMP_COMPONENT_NAME}_PACKAGE_REQUIRES "" CACHE STRING "${PROJCOMP_COMPONENT_NAME} dependencies" FORCE ) | ||
| 102 | + | ||
| 103 | +endfunction() | ||
| 104 | + | ||
| 105 | +# @brief Installs the executable binary and related items | ||
| 106 | +# (such as systemd service files, log folder, post [un]install scripts) | ||
| 107 | +# @param INSTALL_SYSTEMD_SERVICE [optional] Boolean to indicate whether the systemd unit files must be installed. Optional. The default is ON. | ||
| 108 | +function(install_application) | ||
| 109 | + | ||
| 110 | +set ( optional_macro_args ${ARGN} ) | ||
| 111 | +list ( LENGTH optional_macro_args num_optional_args ) | ||
| 112 | +if ( ${num_optional_args} GREATER 0 ) | ||
| 113 | + list ( GET optional_macro_args 0 INSTALL_SYSTEMD_SERVICE ) | ||
| 114 | +endif() | ||
| 115 | + | ||
| 116 | +if(NOT DEFINED INSTALL_SYSTEMD_SERVICE) | ||
| 117 | + set(INSTALL_SYSTEMD_SERVICE "ON") | ||
| 118 | +endif() | ||
| 119 | + | ||
| 120 | +message(STATUS "INSTALL_SYSTEMD_SERVICE: ${INSTALL_SYSTEMD_SERVICE}") | ||
| 121 | + | ||
| 122 | +set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") | ||
| 123 | + | ||
| 124 | +# Install license file | ||
| 125 | +if (EXISTS "${INSTALLATION_CURRENT_CMAKE_DIR}/COPYING.OSDEV") | ||
| 126 | + install( | ||
| 127 | + FILES "${INSTALLATION_CURRENT_CMAKE_DIR}/COPYING.OSDEV" | ||
| 128 | + DESTINATION ${PROJCOMP_BIN_INSTALL_DIR} | ||
| 129 | + COMPONENT "${PROJCOMP_COMPONENT_NAME}" | ||
| 130 | + ) | ||
| 131 | +endif() | ||
| 132 | + | ||
| 133 | +# Install binary file | ||
| 134 | +install( | ||
| 135 | + TARGETS ${PROJECT_NAME} | ||
| 136 | + DESTINATION ${PROJCOMP_BIN_INSTALL_DIR} | ||
| 137 | + COMPONENT "${PROJCOMP_COMPONENT_NAME}" | ||
| 138 | +) | ||
| 139 | + | ||
| 140 | +# Install configuration | ||
| 141 | +if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/config/) | ||
| 142 | + install( | ||
| 143 | + DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/config/ | ||
| 144 | + DESTINATION ${PROJCOMP_ETC_INSTALL_DIR} | ||
| 145 | + COMPONENT "${PROJCOMP_COMPONENT_NAME}" | ||
| 146 | + ) | ||
| 147 | +endif() | ||
| 148 | + | ||
| 149 | +if (INSTALL_SYSTEMD_SERVICE STREQUAL "ON") | ||
| 150 | + # Configure and install systemd unit file | ||
| 151 | + configure_file( | ||
| 152 | + "${INSTALLATION_CURRENT_CMAKE_DIR}/service.cmake.in" | ||
| 153 | + "${GENERATED_DIR}/${PROJECT_NAME}.service" | ||
| 154 | + ) | ||
| 155 | + install( | ||
| 156 | + FILES "${GENERATED_DIR}/${PROJECT_NAME}.service" | ||
| 157 | + DESTINATION ${SYSTEMD_CONFIG_DIR} | ||
| 158 | + COMPONENT "${PROJCOMP_COMPONENT_NAME}" | ||
| 159 | + ) | ||
| 160 | +endif() | ||
| 161 | + | ||
| 162 | +# Install log folder | ||
| 163 | +install( | ||
| 164 | + DIRECTORY | ||
| 165 | + DESTINATION ${PROJCOMP_LOG_INSTALL_DIR} | ||
| 166 | + DIRECTORY_PERMISSIONS | ||
| 167 | + OWNER_WRITE OWNER_READ OWNER_EXECUTE | ||
| 168 | + GROUP_WRITE GROUP_READ GROUP_EXECUTE SETGID | ||
| 169 | + # No permissions for WORLD | ||
| 170 | + COMPONENT "${PROJCOMP_COMPONENT_NAME}" | ||
| 171 | +) | ||
| 172 | + | ||
| 173 | +# Install run folder | ||
| 174 | +install( | ||
| 175 | + DIRECTORY | ||
| 176 | + DESTINATION ${PROJCOMP_RUN_INSTALL_DIR} | ||
| 177 | + DIRECTORY_PERMISSIONS | ||
| 178 | + OWNER_WRITE OWNER_READ OWNER_EXECUTE | ||
| 179 | + GROUP_WRITE GROUP_READ GROUP_EXECUTE | ||
| 180 | + # No permissions for WORLD | ||
| 181 | + COMPONENT "${PROJCOMP_COMPONENT_NAME}" | ||
| 182 | +) | ||
| 183 | + | ||
| 184 | +# Configure and set cpack post install script | ||
| 185 | +configure_file( | ||
| 186 | + "${INSTALLATION_CURRENT_CMAKE_DIR}/application.post_install.inc.cmake.in" | ||
| 187 | + "${GENERATED_DIR}/application.post_install.inc" | ||
| 188 | +) | ||
| 189 | +# Set the per-component post install script file. | ||
| 190 | +set(CPACK_RPM_${PROJCOMP_COMPONENT_NAME}_POST_INSTALL_SCRIPT_FILE "${GENERATED_DIR}/application.post_install.inc" CACHE STRING "${PROJECT_NAME} post_install script" FORCE) | ||
| 191 | + | ||
| 192 | +endfunction() |
cmake/ld.so.conf.d.cmake.in
0 → 100644
| 1 | +@CMAKE_INSTALL_PREFIX@/@PROJCOMP_LIB_INSTALL_DIR@/ |
cmake/library.cmake
0 → 100644
| 1 | +# @brief Adds a single shared or static library target and performs related actions, | ||
| 2 | +# such as target properties and some packaging variables. | ||
| 3 | +# @note The default binary directory is CMAKE_BINARY_DIR, but can be overridden by specifying the ${PROJECT_NAME}_CURRENT_BINARY_DIR. | ||
| 4 | +function(add_libraries) | ||
| 5 | + | ||
| 6 | +message( STATUS "${PROJECT_NAME} linking libraries : ${ARGN}") | ||
| 7 | + | ||
| 8 | +# Use CMAKE_BINARY_DIR by default, but override if necessary. | ||
| 9 | +set(CURRENT_PROJECT_BINARY_DIR ${CMAKE_BINARY_DIR}) | ||
| 10 | +if (${PROJECT_NAME}_CURRENT_BINARY_DIR) | ||
| 11 | + set(CURRENT_PROJECT_BINARY_DIR ${${PROJECT_NAME}_CURRENT_BINARY_DIR}) | ||
| 12 | +endif() | ||
| 13 | +message(STATUS "CURRENT_PROJECT_BINARY_DIR : ${CURRENT_PROJECT_BINARY_DIR}") | ||
| 14 | + | ||
| 15 | +if( ${BUILD_STATIC} ) | ||
| 16 | + if(${BUILD_STATIC} STREQUAL "ON") | ||
| 17 | + set(SHARED_OR_STATIC "STATIC") | ||
| 18 | + else() | ||
| 19 | + set(SHARED_OR_STATIC "SHARED") | ||
| 20 | + endif() | ||
| 21 | +else() | ||
| 22 | + set(SHARED_OR_STATIC "SHARED") | ||
| 23 | +endif() | ||
| 24 | + | ||
| 25 | +add_library( ${PROJECT_NAME} ${SHARED_OR_STATIC} | ||
| 26 | + ${SRC_LIST} | ||
| 27 | +) | ||
| 28 | + | ||
| 29 | +target_link_libraries( ${PROJECT_NAME} | ||
| 30 | + ${ARGN} | ||
| 31 | +) | ||
| 32 | + | ||
| 33 | +set_target_properties( ${PROJECT_NAME} | ||
| 34 | + PROPERTIES | ||
| 35 | + VERSION ${PROJECT_VERSION} | ||
| 36 | + SOVERSION ${PROJECT_VERSION_MAJOR} | ||
| 37 | + LIBRARY_OUTPUT_DIRECTORY ${CURRENT_PROJECT_BINARY_DIR}/lib | ||
| 38 | + ARCHIVE_OUTPUT_DIRECTORY ${CURRENT_PROJECT_BINARY_DIR}/lib | ||
| 39 | +) | ||
| 40 | + | ||
| 41 | +endfunction() |
cmake/library.post_install.inc.cmake.in
0 → 100644
| 1 | +# Update the dynamic linker runtime bindings. | ||
| 2 | +VAR1="/sbin/ldconfig" | ||
| 3 | +VAR2=`which ldconfig` | ||
| 4 | + | ||
| 5 | +if [ -e $VAR1 ]; then | ||
| 6 | + $VAR1 | ||
| 7 | +elif [ ! -z $VAR2 ]; then | ||
| 8 | + $VAR2 | ||
| 9 | +else | ||
| 10 | + VAR3=`find / -name ldconfig -type f` | ||
| 11 | + if [ -e $VAR3 ]; then | ||
| 12 | + $VAR3 | ||
| 13 | + else | ||
| 14 | + echo "ldconfig not found!!!" | ||
| 15 | + fi | ||
| 16 | +fi |
cmake/packaging.cmake
0 → 100644
| 1 | +set( PACKAGING_CURRENT_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR} ) | ||
| 2 | + | ||
| 3 | +# @brief Creates component packages. Can be executed by calling "make package". | ||
| 4 | +function(package_component) | ||
| 5 | + | ||
| 6 | +# Determine build architecture | ||
| 7 | +execute_process( | ||
| 8 | + COMMAND uname -m | ||
| 9 | + COMMAND tr -d '\n' | ||
| 10 | + OUTPUT_VARIABLE ARCHITECTURE | ||
| 11 | +) | ||
| 12 | + | ||
| 13 | +# Set package name | ||
| 14 | +# Known issue: Due to the way cpack works (only evaluated once), the PROJECT_NAME will be the last package to | ||
| 15 | +# call this function. We worked around this by including packaging.cmake only from 1 location in the repository. | ||
| 16 | +# However, in a superbuild (i.e. from an mlogic parent directory building all repositories at once), | ||
| 17 | +# this will yield an erroneous package name (usually datacollector, as that is the last project to be evaluated). | ||
| 18 | +# In order to prevent dynamic package names caused by different build directories, | ||
| 19 | +# The package name is set to a fixed value. The actual name of the rpm and package will be determined by | ||
| 20 | +# other variable values such as the component name and version, leading to uniquely identifiable packages. | ||
| 21 | +set(CPACK_PACKAGE_NAME osdev) | ||
| 22 | + | ||
| 23 | +# Set package version numbers | ||
| 24 | +set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") | ||
| 25 | +set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") | ||
| 26 | +set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") | ||
| 27 | +# The release number is not part of CPACK_PACKAGE_VERSION and is dealt with seperately (see below) | ||
| 28 | +set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") | ||
| 29 | +message( STATUS "Packaging ${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION} for ${ARCHITECTURE}.") | ||
| 30 | + | ||
| 31 | +set(CPACK_PACKAGE_RELEASE "1") | ||
| 32 | +if (CURRENT_PROJECT_VERSION_RELEASENR) | ||
| 33 | + set(CPACK_PACKAGE_RELEASE ${CURRENT_PROJECT_VERSION_RELEASENR}) | ||
| 34 | +endif() | ||
| 35 | + | ||
| 36 | +# Build CPack driven installer packages | ||
| 37 | +include(InstallRequiredSystemLibraries) | ||
| 38 | + | ||
| 39 | +# This doesn't seem to work, only the specific archive variables (_RPM_, _DEB_) seem to work | ||
| 40 | +#set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) | ||
| 41 | +set(CPACK_COMPONENTS_IGNORE_GROUPS 1) | ||
| 42 | +# Enable the line below if the repository being built has only 1 target that's installed | ||
| 43 | +# (No longer necessary, as we now have at least 2 components: runtime and development components.) | ||
| 44 | +#set(CPACK_COMPONENTS_ALL ${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_NAME}-devel) | ||
| 45 | + | ||
| 46 | +# Enable DESTDIR and copy CMAKE_INSTALL_PREFIX, which requires disabling rpm relocatability | ||
| 47 | +set(CPACK_SET_DESTDIR 1) | ||
| 48 | +set(CPACK_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) | ||
| 49 | +set(CPACK_PACKAGE_RELOCATABLE OFF) | ||
| 50 | + | ||
| 51 | +# Set package metadata | ||
| 52 | +if (EXISTS "${PACKAGING_CURRENT_CMAKE_DIR}/../../../COPYING.OSDEV") | ||
| 53 | + set(CPACK_RESOURCE_FILE_LICENSE "${PACKAGING_CURRENT_CMAKE_DIR}/../../../COPYING.OSDEV") | ||
| 54 | +endif() | ||
| 55 | +if (EXISTS "${PACKAGING_CURRENT_CMAKE_DIR}/../../../README.md") | ||
| 56 | + set(CPACK_RESOURCE_FILE_README "${PACKAGING_CURRENT_CMAKE_DIR}/../../../README.md") | ||
| 57 | +endif() | ||
| 58 | +set(CPACK_SYSTEM_NAME "${ARCHITECTURE}") | ||
| 59 | +set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.${CURRENT_PROJECT_VERSION_LETTER}-${CPACK_PACKAGE_RELEASE}.${ARCHITECTURE}") | ||
| 60 | + | ||
| 61 | +# RPM specific fields | ||
| 62 | +set(CPACK_RPM_PACKAGE_ARCHITECTURE "${ARCHITECTURE}") | ||
| 63 | +set(CPACK_RPM_COMPONENT_INSTALL ON) | ||
| 64 | +set(CPACK_RPM_PACKAGE_GROUP "${CPACK_PACKAGE_NAME}-${REPOSITORY_PACKAGE_NAME}") | ||
| 65 | +# Unfortunately, CPACK_RPM_PACKAGE_RELEASE isn't inherited from CPACK_PACKAGE_RELEASE automatically. | ||
| 66 | +set(CPACK_RPM_PACKAGE_RELEASE ${CPACK_PACKAGE_RELEASE}) | ||
| 67 | +set(CPACK_RPM_PACKAGE_VENDOR ${CURRENT_PROJECT_MANUFACTURER_CODE}) | ||
| 68 | +set(CPACK_RPM_PACKAGE_SUMMARY "${CPACK_PACKAGE_NAME} package") | ||
| 69 | +set(CPACK_RPM_PACKAGE_DESCRIPTION "${CPACK_RPM_PACKAGE_SUMMARY}") | ||
| 70 | +set(CPACK_RPM_PACKAGE_LICENSE "${CURRENT_PROJECT_MANUFACTURER_CODE}") | ||
| 71 | + | ||
| 72 | +# Select CPack generators | ||
| 73 | +set(CPACK_GENERATOR "RPM") | ||
| 74 | + | ||
| 75 | +# Exclude certain system directories from the rpm | ||
| 76 | +set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr;/etc;/etc/systemd;/var;${USR_LOCAL_DIR};${LD_SO_CONF_D_DIR};${SYSTEMD_CONFIG_DIR};${VAR_LOG_DIR};${VAR_RUN_DIR}) | ||
| 77 | + | ||
| 78 | +# This line should come last | ||
| 79 | +include(CPack) | ||
| 80 | + | ||
| 81 | +endfunction(package_component) |
cmake/projectheader.cmake
0 → 100644
| 1 | +# @brief Defines the project name, version and binary dir. | ||
| 2 | +# @param CURRENT_PROJECT_NAME The name of the project to define. | ||
| 3 | +# @param CURRENT_PROJECT_BINARY_DIR [optional] Override for the default project binary dir (PROJECT_BINARY_DIR for executables, CMAKE_BINARY_DIR for libraries). | ||
| 4 | +macro ( project_header CURRENT_PROJECT_NAME ) | ||
| 5 | + | ||
| 6 | +# Determine the version and fill the following variables : | ||
| 7 | +# SOVERSION : The tag from the git-repository. Not necessarily a number-only string. | ||
| 8 | +find_package(Git QUIET) | ||
| 9 | + | ||
| 10 | +if(GIT_FOUND) | ||
| 11 | + if( EXISTS "${PROJECT_SOURCE_DIR}/.git") | ||
| 12 | + execute_process(COMMAND ${GIT_EXECUTABLE} describe --abbrev=0 --tags | ||
| 13 | + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} | ||
| 14 | + OUTPUT_VARIABLE CURRENT_PROJECT_VERSION | ||
| 15 | + OUTPUT_STRIP_TRAILING_WHITESPACE | ||
| 16 | + RESULT_VARIABLE GIT_SUBMOD_RESULT) | ||
| 17 | + | ||
| 18 | + # Exit code will be 128 if no tags are present | ||
| 19 | + if( ${GIT_SUBMOD_RESULT} EQUAL 128 ) | ||
| 20 | + set(CURRENT_PROJECT_VERSION "0.0.1") | ||
| 21 | + endif() | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + message( STATUS "================================================================" ) | ||
| 26 | + message( STATUS "Found the following tag : ${CURRENT_PROJECT_VERSION}") | ||
| 27 | + message( STATUS "================================================================" ) | ||
| 28 | + else() | ||
| 29 | + message( STATUS ".git directory does not exists..") | ||
| 30 | + message( STATUS "Project directory : ${PROJECT_SOURCE_DIR}") | ||
| 31 | + endif() | ||
| 32 | +else() | ||
| 33 | + message( STATUS "git-command not found....") | ||
| 34 | + message( FATAL "Unable to determine the version of the software.") | ||
| 35 | +endif() | ||
| 36 | + | ||
| 37 | + | ||
| 38 | +message( STATUS "" ) | ||
| 39 | +message( STATUS "================================================================" ) | ||
| 40 | +message( STATUS "Creating Makefile of ${CURRENT_PROJECT_NAME}" ) | ||
| 41 | +message( STATUS "================================================================" ) | ||
| 42 | +message( STATUS "CURRENT_PROJECT_VERSION: ${CURRENT_PROJECT_VERSION}" ) | ||
| 43 | + | ||
| 44 | +set(SOVERSION "${CURRENT_PROJECT_VERSION}") | ||
| 45 | +set(VERSION "${CURRENT_PROJECT_VERSION}") | ||
| 46 | + | ||
| 47 | +project(${CURRENT_PROJECT_NAME} VERSION ${CURRENT_PROJECT_VERSION}) | ||
| 48 | +set_property(GLOBAL PROPERTY GLOBAL_DEPENDS_NO_CYCLES 1) | ||
| 49 | + | ||
| 50 | +set ( optional_macro_args ${ARGN} ) | ||
| 51 | +list ( LENGTH optional_macro_args num_optional_args ) | ||
| 52 | +if ( ${num_optional_args} GREATER 0 ) | ||
| 53 | + # Set project binary dir override to the specified value | ||
| 54 | + list ( GET optional_macro_args 0 CURRENT_PROJECT_BINARY_DIR ) | ||
| 55 | + set ( ${PROJECT_NAME}_CURRENT_BINARY_DIR ${CURRENT_PROJECT_BINARY_DIR} CACHE STRING "${PROJECT_NAME} binary dir" FORCE ) | ||
| 56 | +endif() | ||
| 57 | + | ||
| 58 | +endmacro() |
cmake/qtmoc.cmake
0 → 100644
| 1 | +# @brief Creates the qt5 mocs for the specified header files. | ||
| 2 | +# @param SRC_LIST The current source list of the project, to which to add the created moc files. | ||
| 3 | +# @param MOC_LIST The list of header files for which to create qt5 mocs. | ||
| 4 | +macro(create_mocs SRC_LIST MOC_LIST) | ||
| 5 | + | ||
| 6 | +message( STATUS "${PROJECT_NAME} Creating mocs for: ${ARGN}") | ||
| 7 | + | ||
| 8 | +set( MOCABLE_LIST | ||
| 9 | + ${ARGN} | ||
| 10 | +) | ||
| 11 | + | ||
| 12 | +# Empty the MOC_LIST variable | ||
| 13 | +set( ${MOC_LIST} | ||
| 14 | +) | ||
| 15 | + | ||
| 16 | +# Create the MOC_LIST | ||
| 17 | +QT6_WRAP_CPP( ${MOC_LIST} ${MOCABLE_LIST} ) | ||
| 18 | + | ||
| 19 | +# Append SRC_LIST with MOC_LIST | ||
| 20 | +list ( APPEND SRC_LIST | ||
| 21 | + ${${MOC_LIST}} | ||
| 22 | +) | ||
| 23 | + | ||
| 24 | +message( STATUS "${PROJECT_NAME} MOC_LIST: ${${MOC_LIST}}") | ||
| 25 | +message( STATUS "${PROJECT_NAME} SRC_LIST: ${${SRC_LIST}}") | ||
| 26 | + | ||
| 27 | +set_source_files_properties( | ||
| 28 | + ${${MOC_LIST}} | ||
| 29 | + PROPERTIES | ||
| 30 | + COMPILE_FLAGS -Wno-undefined-reinterpret-cast | ||
| 31 | +) | ||
| 32 | + | ||
| 33 | +endmacro() |
cmake/qtuic.cmake
0 → 100644
| 1 | +# @brief Creates the qt5 ui_ headers for the specified designer files. | ||
| 2 | +# @param SRC_LIST The current source list of the project, to which to add the created moc files. | ||
| 3 | +# @param UIC_LIST The list of designer files for which to create qt5 headers. | ||
| 4 | +macro(create_ui SRC_LIST UIC_LIST) | ||
| 5 | + | ||
| 6 | +message( STATUS "${PROJECT_NAME} Creating headers for: ${ARGN}") | ||
| 7 | + | ||
| 8 | +set( UICABLE_LIST | ||
| 9 | + ${ARGN} | ||
| 10 | +) | ||
| 11 | + | ||
| 12 | +# Empty the UIC_LIST variable | ||
| 13 | +set( ${UIC_LIST} | ||
| 14 | +) | ||
| 15 | + | ||
| 16 | +# Create the UIC_LIST | ||
| 17 | +QT5_WRAP_UI( ${UIC_LIST} ${UICABLE_LIST} ) | ||
| 18 | + | ||
| 19 | +# Append SRC_LIST with UIC_LIST | ||
| 20 | +list ( APPEND SRC_LIST | ||
| 21 | + ${${UIC_LIST}} | ||
| 22 | +) | ||
| 23 | + | ||
| 24 | +# Avoid warnings by including a generated header file. | ||
| 25 | +include_directories( ${SYSTEMORNOT} | ||
| 26 | + ${CMAKE_CURRENT_BINARY_DIR} | ||
| 27 | + ${CMAKE_SOURCE_DIR} | ||
| 28 | +) | ||
| 29 | + | ||
| 30 | +message( STATUS "${PROJECT_NAME} UIC_LIST: ${${UIC_LIST}}") | ||
| 31 | +message( STATUS "${PROJECT_NAME} SRC_LIST: ${${SRC_LIST}}") | ||
| 32 | + | ||
| 33 | +set_source_files_properties( | ||
| 34 | + ${${UIC_LIST}} | ||
| 35 | + PROPERTIES | ||
| 36 | + COMPILE_FLAGS -Wno-undefined-reinterpret-cast | ||
| 37 | +) | ||
| 38 | + | ||
| 39 | +endmacro() |
cmake/service.cmake.in
0 → 100644
cmake/sync.sh
0 → 100755
| 1 | +#!/bin/bash | ||
| 2 | + | ||
| 3 | +# $1: cmake-file-filename | ||
| 4 | +function sync-file() | ||
| 5 | +{ | ||
| 6 | + echo ---------- Syncing $1 started | ||
| 7 | + | ||
| 8 | + cp -f ../../mlogic_support/cmake/$1 $1 | ||
| 9 | + if [ $? -ne 0 ] ; then | ||
| 10 | + echo ---------- Syncing $1 failed | ||
| 11 | + return 1 | ||
| 12 | + fi | ||
| 13 | + | ||
| 14 | + echo ---------- Syncing $1 finished | ||
| 15 | +} | ||
| 16 | + | ||
| 17 | +# We don't copy installation.cmake, because the includes files are in the src folder. | ||
| 18 | +# datacollector is different in this respect from the other repositories. | ||
| 19 | +MLOGIC_CMAKE_FILES="artifacts.cmake | ||
| 20 | +compiler.cmake | ||
| 21 | +config.cmake.in | ||
| 22 | +FindGMock.cmake | ||
| 23 | +library.cmake | ||
| 24 | +packaging.cmake | ||
| 25 | +projectheader.cmake | ||
| 26 | +qtmoc.cmake" | ||
| 27 | + | ||
| 28 | +# Process the cmake files | ||
| 29 | +cd $(dirname $(readlink -f $0)) || exit 1 | ||
| 30 | +for cmake_file in ${MLOGIC_CMAKE_FILES} | ||
| 31 | +do | ||
| 32 | + sync-file ${cmake_file} | ||
| 33 | +done |
cmake/targetprops.cmake
0 → 100644
include/daemonbase.h
0 → 100644
| 1 | +/* **************************************************************************** | ||
| 2 | + * Copyright 2019 Open Systems Development BV * | ||
| 3 | + * * | ||
| 4 | + * Permission is hereby granted, free of charge, to any person obtaining a * | ||
| 5 | + * copy of this software and associated documentation files (the "Software"), * | ||
| 6 | + * to deal in the Software without restriction, including without limitation * | ||
| 7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * | ||
| 8 | + * and/or sell copies of the Software, and to permit persons to whom the * | ||
| 9 | + * Software is furnished to do so, subject to the following conditions: * | ||
| 10 | + * * | ||
| 11 | + * The above copyright notice and this permission notice shall be included in * | ||
| 12 | + * all copies or substantial portions of the Software. * | ||
| 13 | + * * | ||
| 14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * | ||
| 15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * | ||
| 16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * | ||
| 17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * | ||
| 18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * | ||
| 19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * | ||
| 20 | + * DEALINGS IN THE SOFTWARE. * | ||
| 21 | + * ****************************************************************************/ | ||
| 22 | +#pragma once | ||
| 23 | + | ||
| 24 | +#include <cstdlib> | ||
| 25 | +#include <iostream> | ||
| 26 | +#include <sys/types.h> | ||
| 27 | +#include <unistd.h> | ||
| 28 | +#include <cerrno> | ||
| 29 | +#include <cstring> | ||
| 30 | +#include <string> | ||
| 31 | +#include <csignal> | ||
| 32 | +#include <sys/stat.h> | ||
| 33 | +#include <stdexcept> | ||
| 34 | +#include <chrono> | ||
| 35 | +#include <thread> | ||
| 36 | +#include <atomic> | ||
| 37 | +#include <condition_variable> | ||
| 38 | + | ||
| 39 | +#include "daemonlog.h" | ||
| 40 | +#include "daemonconfig.h" | ||
| 41 | + | ||
| 42 | +namespace osdev::components::daemon | ||
| 43 | +{ | ||
| 44 | +class DaemonBase | ||
| 45 | +{ | ||
| 46 | +private: | ||
| 47 | + static DaemonBase *instance; | ||
| 48 | + | ||
| 49 | +public: | ||
| 50 | + /** | ||
| 51 | + * Construct a new daemon process. | ||
| 52 | + * @note: only one daemon per application is possible. | ||
| 53 | + * @param name: name of daemon process | ||
| 54 | + * @param cwd: daemon current working directory, root "/" directory by default. | ||
| 55 | + * @param update_duration: duration to sleep before waking up the on_update() callback every time, deafult 10 seconds. | ||
| 56 | + */ | ||
| 57 | + DaemonBase(const std::string &name, | ||
| 58 | + const std::string &cwd = "/", | ||
| 59 | + const std::chrono::high_resolution_clock::duration &update_duration = std::chrono::seconds(10)) | ||
| 60 | + : m_name(name) | ||
| 61 | + , m_cwd(cwd) | ||
| 62 | + , m_update_duration(update_duration) | ||
| 63 | + , m_is_running(false) | ||
| 64 | + , m_exit_code(EXIT_SUCCESS) | ||
| 65 | + { | ||
| 66 | + if (instance) | ||
| 67 | + { | ||
| 68 | + daemonlog::error("Only one daemon instance is possible."); | ||
| 69 | + std::exit(EXIT_FAILURE); | ||
| 70 | + } | ||
| 71 | + instance = this; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + DaemonBase() | ||
| 75 | + : m_name("<unknown_daemon>") | ||
| 76 | + , m_cwd("/") | ||
| 77 | + , m_update_duration(std::chrono::seconds(10)) | ||
| 78 | + , m_is_running(false) | ||
| 79 | + { | ||
| 80 | + if(instance) | ||
| 81 | + { | ||
| 82 | + daemonlog::error("Only one daemon instance is possible."); | ||
| 83 | + std::exit(EXIT_FAILURE); | ||
| 84 | + } | ||
| 85 | + instance = this; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + void run(int argc, char *argv[]) | ||
| 89 | + { | ||
| 90 | + if (m_is_running.load()) | ||
| 91 | + { | ||
| 92 | + daemonlog::error("Daemon '" + m_name + "' is already running."); | ||
| 93 | + return; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + // Get config file path from cmd args passed by ExecStart=/usr/bin/my_daemon --config /etc/my_daemon/my_daemon.conf | ||
| 97 | + // since we need it for a reload./ | ||
| 98 | + for (std::int32_t i = 0; i < argc; i++) | ||
| 99 | + { | ||
| 100 | + if (!std::strcmp(argv[i], "--config")) | ||
| 101 | + { | ||
| 102 | + if (i + 1 < argc) | ||
| 103 | + { | ||
| 104 | + m_config_file = argv[i + 1]; | ||
| 105 | + } | ||
| 106 | + else | ||
| 107 | + { | ||
| 108 | + daemonlog::error("Missing config file. Did ytou forget to specify a config file in your .serve file's ExecStart ?"); | ||
| 109 | + } | ||
| 110 | + break; | ||
| 111 | + } | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + // daemonize this program by forking the parent process. | ||
| 115 | + daemonize(); | ||
| 116 | + | ||
| 117 | + // Mark as running (better to have it before on_start() as a user may call stop() inside on_start()). | ||
| 118 | + m_is_running = true; | ||
| 119 | + on_start(daemonconfig::from_file(m_config_file)); | ||
| 120 | + while (m_is_running.load()) | ||
| 121 | + { | ||
| 122 | + on_update(); | ||
| 123 | + | ||
| 124 | + // On long sleeps, if we want to exit we need a condition_variable to wake up the thread from sleep to carry on exiting. | ||
| 125 | + std::unique_lock<std::mutex> lock(m_mutex); | ||
| 126 | + m_update_cv.wait_for(lock, m_update_duration, [this]() | ||
| 127 | + { | ||
| 128 | + return !m_is_running.load(); | ||
| 129 | + }); | ||
| 130 | + } | ||
| 131 | + on_stop(); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + void stop(std::int32_t code = EXIT_SUCCESS) | ||
| 135 | + { | ||
| 136 | + m_exit_code = code; | ||
| 137 | + m_is_running.store(false); | ||
| 138 | + m_update_cv.notify_all(); | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + virtual ~DaemonBase() | ||
| 142 | + { | ||
| 143 | + daemonlog::shutdown(); | ||
| 144 | + // Terminate the child process when the daemon completes (loop stopped) | ||
| 145 | + // @note that calling std::exit() inside the run function will not call DTor, | ||
| 146 | + std::exit(m_exit_code); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + // Getters & Setters | ||
| 150 | + void set_update_duration(const std::chrono::high_resolution_clock::duration &duration) noexcept | ||
| 151 | + { m_update_duration = duration; } | ||
| 152 | + | ||
| 153 | + const std::chrono::high_resolution_clock::duration& get_update_duration() const noexcept | ||
| 154 | + { return m_update_duration; } | ||
| 155 | + | ||
| 156 | + void set_name(const std::string &daemon_name) noexcept | ||
| 157 | + { m_name = daemon_name; } | ||
| 158 | + | ||
| 159 | + const std::string& get_name() const noexcept | ||
| 160 | + { return m_name; } | ||
| 161 | + | ||
| 162 | + void set_cwd(const std::string ¤t_working_dir) noexcept | ||
| 163 | + { | ||
| 164 | + // Change the current working directory to a directory guaranteed to exist, provided by the user. | ||
| 165 | + if (chdir(current_working_dir.c_str()) < 0) | ||
| 166 | + { | ||
| 167 | + daemonlog::error("Could not change current working directory to'" | ||
| 168 | + + current_working_dir + "': " | ||
| 169 | + + std::string(std::strerror(errno))); | ||
| 170 | + return; | ||
| 171 | + } | ||
| 172 | + m_cwd = current_working_dir; | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + const std::string& get_cwd() const noexcept { return m_cwd; } | ||
| 176 | + | ||
| 177 | + pid_t get_pid() const noexcept { return m_pid; } | ||
| 178 | + pid_t get_sid() const noexcept { return m_sid; } | ||
| 179 | + | ||
| 180 | +protected: // Callbacks | ||
| 181 | + /** | ||
| 182 | + * @brief Called once on daemon starts | ||
| 183 | + * @scenarios: | ||
| 184 | + * - when system starts | ||
| 185 | + * - when you run `$ systemctl start your_daemon` manually | ||
| 186 | + * @param cfg: Installed daemon config file | ||
| 187 | + * Initialize your code here... | ||
| 188 | + */ | ||
| 189 | + virtual void on_start(const daemonconfig &cfg) = 0; | ||
| 190 | + | ||
| 191 | + /** | ||
| 192 | + * @brief Called every DURATION which was set by set_update_duration(DURATION). | ||
| 193 | + * Update your code here... | ||
| 194 | + */ | ||
| 195 | + virtual void on_update() = 0; | ||
| 196 | + | ||
| 197 | + /** | ||
| 198 | + * @brief Called once before daemon is about to exit. | ||
| 199 | + * @scenarios: | ||
| 200 | + * - when you call stop(ewxit_code) | ||
| 201 | + * - when you run `$ systemctl stop your_daemon` manually | ||
| 202 | + * - when the system kills your daemon for some reason | ||
| 203 | + * Cleanup your code here... | ||
| 204 | + */ | ||
| 205 | + virtual void on_stop() = 0; | ||
| 206 | + | ||
| 207 | + /** | ||
| 208 | + * @brief Called once when daemon's config or service files are updated. | ||
| 209 | + * @scenarios: | ||
| 210 | + * - when you run `$systemctl daemon-reload` after you have changed your .conf or .service files | ||
| 211 | + * (after reinstalling your daemon with `$ sudo make install` for example) | ||
| 212 | + * Reinitialize your code here... | ||
| 213 | + */ | ||
| 214 | + virtual void on_reload(const daemonconfig &cfg) = 0; | ||
| 215 | + | ||
| 216 | +private: | ||
| 217 | + static void signal_handler(std::int32_t sig) | ||
| 218 | + { | ||
| 219 | + daemonlog::info("Signal " + std::to_string(sig) + " received."); | ||
| 220 | + | ||
| 221 | + switch(sig) | ||
| 222 | + { | ||
| 223 | + // daemon.service handler : ExecStop=/bin/kill -s SIGTERM $MAINPID | ||
| 224 | + // When daemon is stopped, system sends SIGTERM first. | ||
| 225 | + // If daemon didn't respond during 90 seconds, it will send a SIGKILL signal | ||
| 226 | + case SIGTERM: | ||
| 227 | + case SIGKILL: | ||
| 228 | + { | ||
| 229 | + instance->stop(); | ||
| 230 | + break; | ||
| 231 | + } | ||
| 232 | + // daemon.service handler : ExecReload=/bin/kill -S SIGHUB $MAINPID | ||
| 233 | + // When a daemon is reloaded due updates in .service or .conf, system sends SIGHUP signal. | ||
| 234 | + case SIGHUP: | ||
| 235 | + { | ||
| 236 | + instance->on_reload(daemonconfig::from_file(instance->m_config_file)); | ||
| 237 | + break; | ||
| 238 | + } | ||
| 239 | + default: | ||
| 240 | + { | ||
| 241 | + break; | ||
| 242 | + } | ||
| 243 | + } | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + /** | ||
| 247 | + * @brief Daemonize this program | ||
| 248 | + * @note: It is also possible to use glibc function daemon() | ||
| 249 | + * at this point, but it is useful to customize your daemon. | ||
| 250 | + * Like for example handle signals, set working directory... | ||
| 251 | + */ | ||
| 252 | + void daemonize() | ||
| 253 | + { | ||
| 254 | + // Fork off the parent process (https://linux.die.net/man/3/fork) | ||
| 255 | + m_pid = fork(); | ||
| 256 | + // Success: The parent process continues with a PID > 0 | ||
| 257 | + if (m_pid > 0) | ||
| 258 | + { | ||
| 259 | + std::exit(EXIT_SUCCESS); | ||
| 260 | + } | ||
| 261 | + else if (m_pid < 0) | ||
| 262 | + { | ||
| 263 | + // An error occurred. A process ID lower than 0 indicates a failure in either process | ||
| 264 | + std::exit(EXIT_FAILURE); | ||
| 265 | + } | ||
| 266 | + // The parent process has now terminated, and the forked child process will continue | ||
| 267 | + // (the pid of the child process was 0) | ||
| 268 | + | ||
| 269 | + // Since the child process is a daemon, the unask needs to be set so files and logs can be written | ||
| 270 | + umask(0); | ||
| 271 | + | ||
| 272 | + // Initialize syslog for this daemon, here it's a good place to do so. | ||
| 273 | + daemonlog::init(m_name); | ||
| 274 | + | ||
| 275 | + // On success: The child process becomes session leader. Generate a session ID for the child process. | ||
| 276 | + m_sid = setsid(); | ||
| 277 | + if (m_sid < 0) | ||
| 278 | + { | ||
| 279 | + daemonlog::error("Could not set SID to child process: " + std::string(std::strerror(errno))); | ||
| 280 | + std::exit(EXIT_FAILURE); | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + // Ignore the Child terminated or stopped signal. | ||
| 284 | + std::signal(SIGCHLD, SIG_IGN); | ||
| 285 | + | ||
| 286 | + // Set signal handlers to detect daemon interrupt, restart.. | ||
| 287 | + std::signal(SIGHUP, signal_handler); | ||
| 288 | + | ||
| 289 | + // When a sudo systemctl stop my_daemon is ran, by default, a SIGTERM is sent, | ||
| 290 | + // followed by 90 seconds of waiting followed by a SIGKILL | ||
| 291 | + std::signal(SIGTERM, signal_handler); | ||
| 292 | + std::signal(SIGKILL, signal_handler); | ||
| 293 | + | ||
| 294 | + // Change the current working directory to a directory guaranteed to exist, procided by the user | ||
| 295 | + if (chdir(m_cwd.c_str()) < 0) | ||
| 296 | + { | ||
| 297 | + daemonlog::error("Could not change current working directory to `" + m_cwd + "': " + std::string(std::strerror(errno))); | ||
| 298 | + std::exit(EXIT_FAILURE); | ||
| 299 | + } | ||
| 300 | + | ||
| 301 | + // A daemon cannot use the terminal, so close standard file descriptors for security reasons | ||
| 302 | + close(STDIN_FILENO); | ||
| 303 | + close(STDOUT_FILENO); | ||
| 304 | + close(STDERR_FILENO); | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + // Member variables | ||
| 308 | + pid_t m_pid; | ||
| 309 | + pid_t m_sid; | ||
| 310 | + std::string m_config_file; | ||
| 311 | + std::string m_name; | ||
| 312 | + std::string m_cwd; | ||
| 313 | + std::chrono::high_resolution_clock::duration m_update_duration; | ||
| 314 | + std::atomic<bool> m_is_running; | ||
| 315 | + std::condition_variable m_update_cv; | ||
| 316 | + std::mutex m_mutex; | ||
| 317 | + std::int32_t m_exit_code; | ||
| 318 | + | ||
| 319 | +}; | ||
| 320 | + | ||
| 321 | +DaemonBase* DaemonBase::instance = nullptr; | ||
| 322 | + | ||
| 323 | +} /* End namespace osdev::components::daemon */ | ||
| 0 | \ No newline at end of file | 324 | \ No newline at end of file |
include/daemonconfig.h
0 → 100644
| 1 | +/* **************************************************************************** | ||
| 2 | + * Copyright 2019 Open Systems Development BV * | ||
| 3 | + * * | ||
| 4 | + * Permission is hereby granted, free of charge, to any person obtaining a * | ||
| 5 | + * copy of this software and associated documentation files (the "Software"), * | ||
| 6 | + * to deal in the Software without restriction, including without limitation * | ||
| 7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * | ||
| 8 | + * and/or sell copies of the Software, and to permit persons to whom the * | ||
| 9 | + * Software is furnished to do so, subject to the following conditions: * | ||
| 10 | + * * | ||
| 11 | + * The above copyright notice and this permission notice shall be included in * | ||
| 12 | + * all copies or substantial portions of the Software. * | ||
| 13 | + * * | ||
| 14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * | ||
| 15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * | ||
| 16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * | ||
| 17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * | ||
| 18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * | ||
| 19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * | ||
| 20 | + * DEALINGS IN THE SOFTWARE. * | ||
| 21 | + * ****************************************************************************/ | ||
| 22 | +#pragma once | ||
| 23 | + | ||
| 24 | +#include <fstream> | ||
| 25 | +#include <cstring> | ||
| 26 | +#include <string> | ||
| 27 | +#include <vector> | ||
| 28 | +#include <sstream> | ||
| 29 | +#include <iostream> | ||
| 30 | +#include <algorithm> | ||
| 31 | +#include <map> | ||
| 32 | + | ||
| 33 | +#include "daemonlog.h" | ||
| 34 | + | ||
| 35 | +// TODO: Do a better config parsing. | ||
| 36 | +namespace osdev::components::daemon | ||
| 37 | +{ | ||
| 38 | + struct daemonconfig | ||
| 39 | + { | ||
| 40 | + std::map<std::string, std::string> values; | ||
| 41 | + | ||
| 42 | + std::string get(const std::string &key) const | ||
| 43 | + { | ||
| 44 | + auto it = values.find(key); | ||
| 45 | + if (it != values.end()) | ||
| 46 | + { | ||
| 47 | + return it->second; | ||
| 48 | + } | ||
| 49 | + return ""; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + static daemonconfig from_file(const std::string &filename) | ||
| 53 | + { | ||
| 54 | + daemonconfig cfg; | ||
| 55 | + if (filename.empty()) | ||
| 56 | + { | ||
| 57 | + return cfg; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + auto split = [](const std::string &str, char delim) | ||
| 61 | + { | ||
| 62 | + std::vector<std::string> parts; | ||
| 63 | + std::stringstream oss(str); | ||
| 64 | + std::string part; | ||
| 65 | + while (std::getline(oss, part, delim)) | ||
| 66 | + { | ||
| 67 | + parts.push_back(part); | ||
| 68 | + } | ||
| 69 | + return parts; | ||
| 70 | + }; | ||
| 71 | + | ||
| 72 | + auto trim = [](std::string &s) | ||
| 73 | + { | ||
| 74 | + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch){ return !std::isspace(ch);})); | ||
| 75 | + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch){return !std::isspace(ch);}).base(), s.end()); | ||
| 76 | + }; | ||
| 77 | + | ||
| 78 | + std::ifstream ifs{filename}; | ||
| 79 | + std::string line; | ||
| 80 | + | ||
| 81 | + while(std::getline(ifs, line)) | ||
| 82 | + { | ||
| 83 | + trim(line); | ||
| 84 | + if (line.empty()) // skip empty lines | ||
| 85 | + { | ||
| 86 | + continue; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + if (line[0] == '#') // skip comments | ||
| 90 | + { | ||
| 91 | + continue; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + auto parts = split(line, '='); | ||
| 95 | + std::string key = parts[0]; | ||
| 96 | + std::string value = parts[1]; | ||
| 97 | + trim(key); | ||
| 98 | + trim(value); | ||
| 99 | + cfg.values[key] = value; | ||
| 100 | + } | ||
| 101 | + ifs.close(); | ||
| 102 | + return cfg; | ||
| 103 | + } | ||
| 104 | + }; | ||
| 105 | +} | ||
| 0 | \ No newline at end of file | 106 | \ No newline at end of file |
include/daemonlog.h
0 → 100644
| 1 | +/* **************************************************************************** | ||
| 2 | + * Copyright 2019 Open Systems Development BV * | ||
| 3 | + * * | ||
| 4 | + * Permission is hereby granted, free of charge, to any person obtaining a * | ||
| 5 | + * copy of this software and associated documentation files (the "Software"), * | ||
| 6 | + * to deal in the Software without restriction, including without limitation * | ||
| 7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * | ||
| 8 | + * and/or sell copies of the Software, and to permit persons to whom the * | ||
| 9 | + * Software is furnished to do so, subject to the following conditions: * | ||
| 10 | + * * | ||
| 11 | + * The above copyright notice and this permission notice shall be included in * | ||
| 12 | + * all copies or substantial portions of the Software. * | ||
| 13 | + * * | ||
| 14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * | ||
| 15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * | ||
| 16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * | ||
| 17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * | ||
| 18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * | ||
| 19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * | ||
| 20 | + * DEALINGS IN THE SOFTWARE. * | ||
| 21 | + * ****************************************************************************/ | ||
| 22 | +#pragma once | ||
| 23 | + | ||
| 24 | +#include <sys/syslog.h> | ||
| 25 | +#include <syslog.h> | ||
| 26 | +#include <cstdio> | ||
| 27 | +#include <string> | ||
| 28 | + | ||
| 29 | +namespace osdev::components::daemon { | ||
| 30 | + | ||
| 31 | +class daemonlog | ||
| 32 | +{ | ||
| 33 | +public: | ||
| 34 | + /** | ||
| 35 | + * Initialize the logger | ||
| 36 | + * @param daemon_name | ||
| 37 | + */ | ||
| 38 | + static void init(const std::string &daemon_name) | ||
| 39 | + { | ||
| 40 | + // m_daemon_name = daemon_name; | ||
| 41 | + openlog(daemon_name.c_str(), LOG_PID, LOG_DAEMON); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * main logger with priority LOG_X | ||
| 46 | + * @param message | ||
| 47 | + * @param priority | ||
| 48 | + */ | ||
| 49 | + static void log(const std::string &message, std::int32_t priority) | ||
| 50 | + { | ||
| 51 | + syslog(priority, "%s", message.c_str()); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * debug-level messages | ||
| 56 | + * @param message | ||
| 57 | + */ | ||
| 58 | + static void debug(const std::string &message) | ||
| 59 | + { | ||
| 60 | + log(message, LOG_DEBUG); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * informational | ||
| 65 | + * @param message | ||
| 66 | + */ | ||
| 67 | + static void info(const std::string &message) | ||
| 68 | + { | ||
| 69 | + log(message, LOG_INFO); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + /** | ||
| 73 | + * normal but significant condition | ||
| 74 | + * @param message | ||
| 75 | + */ | ||
| 76 | + static void notice(const std::string &message) | ||
| 77 | + { | ||
| 78 | + log(message, LOG_NOTICE); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + /** | ||
| 82 | + * Warning conditions | ||
| 83 | + * @param message | ||
| 84 | + */ | ||
| 85 | + static void warning(const std::string &message) | ||
| 86 | + { | ||
| 87 | + log(message, LOG_WARNING); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * error conditions | ||
| 92 | + * @param message | ||
| 93 | + */ | ||
| 94 | + static void error(const std::string &message) | ||
| 95 | + { | ||
| 96 | + log(message, LOG_ERR); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + /** | ||
| 100 | + * critical conditions | ||
| 101 | + * @param message | ||
| 102 | + */ | ||
| 103 | + static void critical(const std::string &message) | ||
| 104 | + { | ||
| 105 | + log(message, LOG_CRIT); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + /** | ||
| 109 | + * action must be taken immediately | ||
| 110 | + * @param message | ||
| 111 | + */ | ||
| 112 | + static void alert(const std::string &message) | ||
| 113 | + { | ||
| 114 | + log(message, LOG_ALERT); | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + /** | ||
| 118 | + * system is unusable | ||
| 119 | + * @param message | ||
| 120 | + */ | ||
| 121 | + static void emergency(const std::string &message) | ||
| 122 | + { | ||
| 123 | + log(message, LOG_EMERG); | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + /** | ||
| 127 | + * shutdown the logger | ||
| 128 | + */ | ||
| 129 | + static void shutdown() | ||
| 130 | + { | ||
| 131 | + closelog(); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | +private: | ||
| 135 | + static std::string priority_str(std::int32_t priority) | ||
| 136 | + { | ||
| 137 | + switch(priority) | ||
| 138 | + { | ||
| 139 | + case LOG_EMERG: return "emergency"; | ||
| 140 | + case LOG_ALERT: return "alert"; | ||
| 141 | + case LOG_CRIT: return "critical"; | ||
| 142 | + case LOG_ERR: return "error"; | ||
| 143 | + case LOG_WARNING: return "warning"; | ||
| 144 | + case LOG_NOTICE: return "notice"; | ||
| 145 | + case LOG_INFO: return "info"; | ||
| 146 | + case LOG_DEBUG: return "debug"; | ||
| 147 | + default: return "unknown_priority"; | ||
| 148 | + } | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + std::string m_daemon_name; | ||
| 152 | + | ||
| 153 | +}; | ||
| 154 | + | ||
| 155 | +// std::string osdev::components::daemon::m_daemon_name{}; | ||
| 156 | + | ||
| 157 | +} | ||
| 0 | \ No newline at end of file | 158 | \ No newline at end of file |
test/CMakeLists.txt
0 → 100644
| 1 | +# | ||
| 2 | +# Don't call this file directly from cmake. | ||
| 3 | +# TRhis file is included from the upper directory. | ||
| 4 | +# | ||
| 5 | +# Build rules for the daemon library | ||
| 6 | + | ||
| 7 | +add_executable(MyExampleDaemon | ||
| 8 | + MyDaemonExample.cpp | ||
| 9 | +) | ||
| 10 | + | ||
| 11 | +target_include_directories(MyExampleDaemon PRIVATE | ||
| 12 | + ${CMAKE_CURRENT_SOURCE_DIR} | ||
| 13 | + ../include | ||
| 14 | +) | ||
| 15 | + | ||
| 16 | +target_link_libraries(MyExampleDaemon PRIVATE | ||
| 17 | + daemonbase | ||
| 18 | +) | ||
| 0 | \ No newline at end of file | 19 | \ No newline at end of file |
test/MyDaemonExample.cpp
0 → 100644
| 1 | +/* **************************************************************************** | ||
| 2 | + * Copyright 2019 Open Systems Development BV * | ||
| 3 | + * * | ||
| 4 | + * Permission is hereby granted, free of charge, to any person obtaining a * | ||
| 5 | + * copy of this software and associated documentation files (the "Software"), * | ||
| 6 | + * to deal in the Software without restriction, including without limitation * | ||
| 7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * | ||
| 8 | + * and/or sell copies of the Software, and to permit persons to whom the * | ||
| 9 | + * Software is furnished to do so, subject to the following conditions: * | ||
| 10 | + * * | ||
| 11 | + * The above copyright notice and this permission notice shall be included in * | ||
| 12 | + * all copies or substantial portions of the Software. * | ||
| 13 | + * * | ||
| 14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * | ||
| 15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * | ||
| 16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * | ||
| 17 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * | ||
| 18 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * | ||
| 19 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * | ||
| 20 | + * DEALINGS IN THE SOFTWARE. * | ||
| 21 | + * ****************************************************************************/ | ||
| 22 | +#include "daemonbase.h" | ||
| 23 | +#include <cstdlib> | ||
| 24 | + | ||
| 25 | +using namespace osdev::components::daemon; | ||
| 26 | +using namespace std::chrono_literals; | ||
| 27 | + | ||
| 28 | +class MyExampleDaemon : public DaemonBase | ||
| 29 | +{ | ||
| 30 | +public: | ||
| 31 | + void on_start(const daemonconfig &config) override | ||
| 32 | + { | ||
| 33 | + /// Called once after daemon starts automatically with system startup | ||
| 34 | + /// or when you manually call `$ system,ctl start MyExampleDaemon` | ||
| 35 | + | ||
| 36 | + /// Initialize your code here... | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + daemonlog::info("MyExampleDaemon::on_start(): MyExampleDaemon version: " + config.get("version") + " started successfully!"); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + void on_update() override | ||
| 44 | + { | ||
| 45 | + /// Called every DURATION set in set_update_duration()... | ||
| 46 | + | ||
| 47 | + /// Update your code here | ||
| 48 | + | ||
| 49 | + daemonlog::info("MyExampleDaemon::on_update()"); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + void on_stop() override | ||
| 53 | + { | ||
| 54 | + /// Called once before daemon is about to exit with system shutdown or when you manually call `$ systemctl stop MyExampleDaemon` | ||
| 55 | + /// Cleanup your code here... | ||
| 56 | + | ||
| 57 | + daemonlog::info("MyExampleDaemon::on_stop()"); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + void on_reload(const daemonconfig &cfg) override | ||
| 61 | + { | ||
| 62 | + /// Called once after your daemon's config fil is updated then reloaded with `$ systemctl reload MyExampleDaemon` | ||
| 63 | + /// Handle your config updates here... | ||
| 64 | + | ||
| 65 | + daemonlog::info("MyExampleDaemon::on_reload(): new daemon version from updated config: " + cfg.get("version")); | ||
| 66 | + } | ||
| 67 | +}; | ||
| 68 | + | ||
| 69 | + | ||
| 70 | +int main(int argc, char *argv[]) | ||
| 71 | +{ | ||
| 72 | + MyExampleDaemon oDaemon; // Create the daemon instance. | ||
| 73 | + | ||
| 74 | + oDaemon.set_name("MyAweSomeExampleDaemon"); // Set daemon name to identify logs in syslog | ||
| 75 | + oDaemon.set_update_duration(3s); // Set duration to sleep before triggering the on_update callback 3 seconds. | ||
| 76 | + oDaemon.set_cwd("/root"); // set daemon's current working directory to roots home-folder | ||
| 77 | + oDaemon.run(argc, argv); // run the daemon | ||
| 78 | + | ||
| 79 | + return(EXIT_SUCCESS); // Close the main process now the child process is running. | ||
| 80 | +} | ||
| 0 | \ No newline at end of file | 81 | \ No newline at end of file |