diff --git a/cmake_targets/hss_build/CMakeLists.txt b/cmake_targets/hss_build/CMakeLists.txt index e3bdf928212d82cf3440491f9939263656d7dd4e..afbc672027d4732bef9b79b8ec8ce2a2e37a940a 100755 --- a/cmake_targets/hss_build/CMakeLists.txt +++ b/cmake_targets/hss_build/CMakeLists.txt @@ -49,7 +49,7 @@ set(OPENAIRHSS_DIR ${OPENAIRCN_DIR}/OPENAIRHSS) set(OPENAIR_BIN_DIR ${OPENAIR_TARGETS}/bin) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${OPENAIR_TARGETS}/CMAKE/MODULES/") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${OPENAIR_CMAKE_SCRIPTS}/MODULES") include(cmake_useful) macro(add_option name val helpstr) diff --git a/cmake_targets/tools/MODULES/CMakeParseArguments.cmake b/cmake_targets/tools/MODULES/CMakeParseArguments.cmake new file mode 100644 index 0000000000000000000000000000000000000000..ab53b112fa201468a9aa7a41546263336c285683 --- /dev/null +++ b/cmake_targets/tools/MODULES/CMakeParseArguments.cmake @@ -0,0 +1,66 @@ +# Analogue for standard CMake module with same name, appeared in CMake 2.8.3. +# +# Used for compatibility with older versions of cmake. + +function(cmake_parse_arguments prefix options one_value_keywords multi_value_keywords) + set(all_keywords ${options} ${one_value_keywords} ${multi_value_keywords}) + # Clear variables before parsing. + foreach(arg ${one_value_keywords} ${multie_value_keywords}) + set(cpa_${arg}) + endforeach() + + foreach(arg ${options}) + set(cpa_${arg} FALSE) + endforeach() + + set(cpa_UNPARSED_ARGUMENTS) + + set(current_keyword) + # Classification for current_keyword: + # 'ONE' or 'MULTY'. + set(current_keyword_type) + + # now iterate over all arguments and fill the result variables + foreach(arg ${ARGN}) + list(FIND all_keywords ${arg} keyword_index) + + if(keyword_index EQUAL -1) + if(current_keyword) + if(current_keyword_type STREQUAL "ONE") + set(cpa_${current_keyword} ${arg}) + set(current_keyword) + else(current_keyword_type STREQUAL "ONE") + list(APPEND cpa_${current_keyword} ${arg}) + endif(current_keyword_type STREQUAL "ONE") + else(current_keyword) + list(APPEND cpa_UNPARSED_ARGUMENTS ${arg}) + endif(current_keyword) + else(keyword_index EQUAL -1) + if(current_keyword AND current_keyword_type STREQUAL "ONE") + message(SEND_ERROR "Value is expected for one-value-keyword ${current_keyword}") + endif(current_keyword AND current_keyword_type STREQUAL "ONE") + list(FIND options ${arg} option_index) + if(option_index EQUAL -1) + set(current_keyword ${arg}) + list(FIND one_value_keywords ${arg} one_value_index) + if(one_value_index EQUAL -1) + set(current_keyword_type "MULTI") + else(one_value_index EQUAL -1) + set(current_keyword_type "ONE") + endif(one_value_index EQUAL -1) + else(option_index EQUAL -1) + set(current_keyword) + set(cpa_${arg} TRUE) + endif(option_index EQUAL -1) + endif(keyword_index EQUAL -1) + endforeach(arg ${ARGN}) + + if(current_keyword AND current_keyword_type STREQUAL "ONE") + message(SEND_ERROR "Value is expected for one-value-keyword ${current_keyword}") + endif(current_keyword AND current_keyword_type STREQUAL "ONE") + + # propagate the result variables to the caller: + foreach(keyword ${all_keywords} UNPARSED_ARGUMENTS) + set(${prefix}_${keyword} ${cpa_${keyword}} PARENT_SCOPE) + endforeach(keyword ${all_keywords}) +endfunction(cmake_parse_arguments prefix options one_value_keywords multi_value_keywords) diff --git a/cmake_targets/tools/MODULES/CMakeUserFindMySQL.cmake b/cmake_targets/tools/MODULES/CMakeUserFindMySQL.cmake new file mode 100644 index 0000000000000000000000000000000000000000..1b5de7e3ac5fd1332d03e4f0bfe5f48f506a9c0f --- /dev/null +++ b/cmake_targets/tools/MODULES/CMakeUserFindMySQL.cmake @@ -0,0 +1,48 @@ +# - Find mysqlclient +# Find the native MySQL includes and library +# +# MYSQL_INCLUDE_DIR - where to find mysql.h, etc. +# MYSQL_LIBRARIES - List of libraries when using MySQL. +# MYSQL_FOUND - True if MySQL found. + +IF (MYSQL_INCLUDE_DIR) + # Already in cache, be silent + SET(MYSQL_FIND_QUIETLY TRUE) +ENDIF (MYSQL_INCLUDE_DIR) + +FIND_PATH(MYSQL_INCLUDE_DIR mysql.h + /usr/local/include/mysql + /usr/include/mysql +) + +SET(MYSQL_NAMES mysqlclient mysqlclient_r) +FIND_LIBRARY(MYSQL_LIBRARY + NAMES ${MYSQL_NAMES} + PATHS /usr/lib /usr/local/lib + PATH_SUFFIXES mysql +) + +IF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY) + SET(MYSQL_FOUND TRUE) + SET( MYSQL_LIBRARIES ${MYSQL_LIBRARY} ) +ELSE (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY) + SET(MYSQL_FOUND FALSE) + SET( MYSQL_LIBRARIES ) +ENDIF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY) + +IF (MYSQL_FOUND) + IF (NOT MYSQL_FIND_QUIETLY) + MESSAGE(STATUS "Found MySQL: ${MYSQL_LIBRARY}") + ENDIF (NOT MYSQL_FIND_QUIETLY) +ELSE (MYSQL_FOUND) + IF (MYSQL_FIND_REQUIRED) + MESSAGE(STATUS "Looked for MySQL libraries named ${MYSQL_NAMES}.") + MESSAGE(FATAL_ERROR "Could NOT find MySQL library") + ENDIF (MYSQL_FIND_REQUIRED) +ENDIF (MYSQL_FOUND) + +MARK_AS_ADVANCED( + MYSQL_LIBRARY + MYSQL_INCLUDE_DIR + ) + diff --git a/cmake_targets/tools/MODULES/CMakeUserUseBison.cmake b/cmake_targets/tools/MODULES/CMakeUserUseBison.cmake new file mode 100644 index 0000000000000000000000000000000000000000..5295a1ba392abd0a38e2703e29d97790d7703ce2 --- /dev/null +++ b/cmake_targets/tools/MODULES/CMakeUserUseBison.cmake @@ -0,0 +1,71 @@ +# - Look for GNU Bison, the parser generator +# Based off a news post from Andy Cedilnik at Kitware +# Defines the following: +# BISON_EXECUTABLE - path to the bison executable +# BISON_FILE - parse a file with bison +# BISON_PREFIX_OUTPUTS - Set to true to make BISON_FILE produce prefixed +# symbols in the generated output based on filename. +# So for ${filename}.y, you'll get ${filename}parse(), etc. +# instead of yyparse(). +# BISON_GENERATE_DEFINES - Set to true to make BISON_FILE output the matching +# .h file for a .c file. You want this if you're using +# flex. + +IF(NOT DEFINED BISON_PREFIX_OUTPUTS) + SET(BISON_PREFIX_OUTPUTS FALSE) +ENDIF(NOT DEFINED BISON_PREFIX_OUTPUTS) + +IF(NOT DEFINED BISON_GENERATE_DEFINES) + SET(BISON_GENERATE_DEFINES FALSE) +ENDIF(NOT DEFINED BISON_GENERATE_DEFINES) + +IF(NOT BISON_EXECUTABLE) + MESSAGE(STATUS "Looking for bison") + FIND_PROGRAM(BISON_EXECUTABLE bison) + IF(BISON_EXECUTABLE) + MESSAGE(STATUS "Looking for bison -- ${BISON_EXECUTABLE}") + ENDIF(BISON_EXECUTABLE) +ENDIF(NOT BISON_EXECUTABLE) + +IF(BISON_EXECUTABLE) + MACRO(BISON_FILE FILENAME) + GET_FILENAME_COMPONENT(PATH "${FILENAME}" PATH) + IF("${PATH}" STREQUAL "") + SET(PATH_OPT "") + ELSE("${PATH}" STREQUAL "") + SET(PATH_OPT "/${PATH}") + ENDIF("${PATH}" STREQUAL "") + GET_FILENAME_COMPONENT(HEAD "${FILENAME}" NAME_WE) + IF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") + FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") + ENDIF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") + IF(BISON_PREFIX_OUTPUTS) + SET(PREFIX "${HEAD}") + ELSE(BISON_PREFIX_OUTPUTS) + SET(PREFIX "yy") + ENDIF(BISON_PREFIX_OUTPUTS) + SET(OUTFILE "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/${HEAD}.tab.c") + IF(BISON_GENERATE_DEFINES) + SET(HEADER "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/${HEAD}.tab.h") + ADD_CUSTOM_COMMAND( + OUTPUT "${OUTFILE}" "${HEADER}" + COMMAND "${BISON_EXECUTABLE}" + ARGS "--name-prefix=${PREFIX}" + "--defines" + "--output-file=${OUTFILE}" + "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}") + SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" "${HEADER}" PROPERTIES GENERATED TRUE) + SET_SOURCE_FILES_PROPERTIES("${HEADER}" PROPERTIES HEADER_FILE_ONLY TRUE) + ELSE(BISON_GENERATE_DEFINES) + ADD_CUSTOM_COMMAND( + OUTPUT "${OUTFILE}" + COMMAND "${BISON_EXECUTABLE}" + ARGS "--name-prefix=${PREFIX}" + "--output-file=${OUTFILE}" + "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}") + SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" PROPERTIES GENERATED TRUE) + ENDIF(BISON_GENERATE_DEFINES) + ENDMACRO(BISON_FILE) +ENDIF(BISON_EXECUTABLE) diff --git a/cmake_targets/tools/MODULES/CMakeUserUseFlex.cmake b/cmake_targets/tools/MODULES/CMakeUserUseFlex.cmake new file mode 100644 index 0000000000000000000000000000000000000000..09a3e71e6d8d353752b3ad7978d5fedaa19b6138 --- /dev/null +++ b/cmake_targets/tools/MODULES/CMakeUserUseFlex.cmake @@ -0,0 +1,46 @@ +# - Look for GNU flex, the lexer generator. +# Defines the following: +# FLEX_EXECUTABLE - path to the flex executable +# FLEX_FILE - parse a file with flex +# FLEX_PREFIX_OUTPUTS - Set to true to make FLEX_FILE produce outputs of +# lex.${filename}.c, not lex.yy.c . Passes -P to flex. + +IF(NOT DEFINED FLEX_PREFIX_OUTPUTS) + SET(FLEX_PREFIX_OUTPUTS FALSE) +ENDIF(NOT DEFINED FLEX_PREFIX_OUTPUTS) + +IF(NOT FLEX_EXECUTABLE) + MESSAGE(STATUS "Looking for flex") + FIND_PROGRAM(FLEX_EXECUTABLE flex) + IF(FLEX_EXECUTABLE) + MESSAGE(STATUS "Looking for flex -- ${FLEX_EXECUTABLE}") + ENDIF(FLEX_EXECUTABLE) +ENDIF(NOT FLEX_EXECUTABLE) + +IF(FLEX_EXECUTABLE) + MACRO(FLEX_FILE FILENAME) + GET_FILENAME_COMPONENT(PATH "${FILENAME}" PATH) + IF("${PATH}" STREQUAL "") + SET(PATH_OPT "") + ELSE("${PATH}" STREQUAL "") + SET(PATH_OPT "/${PATH}") + ENDIF("${PATH}" STREQUAL "") + IF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") + FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") + ENDIF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") + IF(FLEX_PREFIX_OUTPUTS) + GET_FILENAME_COMPONENT(PREFIX "${FILENAME}" NAME_WE) + ELSE(FLEX_PREFIX_OUTPUTS) + SET(PREFIX "yy") + ENDIF(FLEX_PREFIX_OUTPUTS) + SET(OUTFILE "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/lex.${PREFIX}.c") + ADD_CUSTOM_COMMAND( + OUTPUT "${OUTFILE}" + COMMAND "${FLEX_EXECUTABLE}" + ARGS "--prefix=${PREFIX}" + "--outfile=${OUTFILE}" + "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}") + SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" PROPERTIES GENERATED TRUE) + ENDMACRO(FLEX_FILE) +ENDIF(FLEX_EXECUTABLE) diff --git a/cmake_targets/tools/MODULES/FindFreeDiameter.cmake b/cmake_targets/tools/MODULES/FindFreeDiameter.cmake new file mode 100644 index 0000000000000000000000000000000000000000..6351ff2ce36fe054a9ff9bacc538379f9b56d654 --- /dev/null +++ b/cmake_targets/tools/MODULES/FindFreeDiameter.cmake @@ -0,0 +1,88 @@ +# - Find freediameter +# Find the native FreeDiameter includes and libraries +# +# FREEDIAMETER_FOUND - True if FreeDiameter found. +# FREEDIAMETER_INCLUDE_DIR - where to find gnutls.h, etc. +# FREEDIAMETER_LIBRARIES - List of libraries when using gnutls. +# FREEDIAMETER_HSS_S6A_ENABLED - true if FreeDiameter enabled for S6A interface + + +if (FREEDIAMETER_INCLUDE_DIR AND FREEDIAMETER_LIBRARIES) + set(FREEDIAMETER_FIND_QUIETLY TRUE) +endif (FREEDIAMETER_INCLUDE_DIR AND FREEDIAMETER_LIBRARIES) + +# Include dir +find_path(FREEDIAMETER_INCLUDE_DIR + NAMES + freeDiameter/freeDiameter-host.h + freeDiameter/libfdcore.h + freeDiameter/libfdproto.h +) + +# Library +find_library(FREEDIAMETER_LIBRARY + NAMES fdcore +) + +# handle the QUIETLY and REQUIRED arguments and set FREEDIAMETER_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FREEDIAMETER DEFAULT_MSG FREEDIAMETER_LIBRARY FREEDIAMETER_INCLUDE_DIR) + +IF(FREEDIAMETER_FOUND) + SET( FREEDIAMETER_LIBRARIES ${FREEDIAMETER_LIBRARY} ) +ELSE(FREEDIAMETER_FOUND) + SET( FREEDIAMETER_LIBRARIES ) +ENDIF(FREEDIAMETER_FOUND) + +find_library(FREEDIAMETER_LIBRARY2 + NAMES fdproto +) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FREEDIAMETER2 DEFAULT_MSG FREEDIAMETER_LIBRARY2 FREEDIAMETER_INCLUDE_DIR) +IF(FREEDIAMETER2_FOUND) + SET( FREEDIAMETER_LIBRARIES ${FREEDIAMETER_LIBRARIES} ${FREEDIAMETER_LIBRARY2} ) +ELSE(FREEDIAMETER2_FOUND) + SET( FREEDIAMETER_LIBRARIES ) +ENDIF(FREEDIAMETER2_FOUND) + + +# Lastly make it so that the FREEDIAMETER_LIBRARY and FREEDIAMETER_INCLUDE_DIR variables +# only show up under the advanced options in the gui cmake applications. +MARK_AS_ADVANCED( FREEDIAMETER_LIBRARY FREEDIAMETER_INCLUDE_DIR ) + +# Now check if the library is patched for OPENAIR HSS S6A. +IF(FREEDIAMETER_FOUND) + IF( FREEDIAMETER_INCLUDE_DIR ) + # Extract FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR from freeDiameter-host.h + # Read the whole file: + # + FILE(READ "${FREEDIAMETER_INCLUDE_DIR}/freeDiameter/freeDiameter-host.h" _freeDiameter_HOST_H_CONTENTS) + + STRING(REGEX REPLACE ".*#define FD_PROJECT_VERSION_MAJOR ([0-9]+).*" "\\1" FD_PROJECT_VERSION_MAJOR "${_freeDiameter_HOST_H_CONTENTS}") + STRING(REGEX REPLACE ".*#define FD_PROJECT_VERSION_MINOR ([0-9]+).*" "\\1" FD_PROJECT_VERSION_MINOR "${_freeDiameter_HOST_H_CONTENTS}") + + IF(FD_PROJECT_VERSION_MAJOR GREATER 0) + MATH(EXPR FREEDIAMETER_VERSION_VALUE "${FD_PROJECT_VERSION_MAJOR} * 100 + ${FD_PROJECT_VERSION_MINOR} * 10") + SET(FREEDIAMETER_VERSION "${FREEDIAMETER_VERSION_VALUE}" CACHE INTERNAL "Freediameter release version") + MESSAGE(STATUS "freeDiameter version found ${FREEDIAMETER_VERSION}") + ENDIF(FD_PROJECT_VERSION_MAJOR GREATER 0) + ENDIF( FREEDIAMETER_INCLUDE_DIR ) + IF( NOT( "${FREEDIAMETER_VERSION_TEST_FOR}" STREQUAL "${FREEDIAMETER_LIBRARIES}" )) + INCLUDE (CheckLibraryExists) + MESSAGE(STATUS "Checking freeDiameter patched for S6A") + UNSET(FREEDIAMETER_HSS_S6A_ENABLED) + UNSET(FREEDIAMETER_HSS_S6A_ENABLED CACHE) + UNSET(DICT_S6A_FOUND) + UNSET(DICT_S6A_FOUND CACHE) + + GET_FILENAME_COMPONENT(FREEDIAMETER_PATH ${FREEDIAMETER_LIBRARY} PATH) + FIND_FILE(DICT_S6A_FOUND NAMES dict_s6a.fdx PATHS ${FREEDIAMETER_PATH} ${FREEDIAMETER_PATH}/freeDiameter) + IF(DICT_S6A_FOUND) + SET( FREEDIAMETER_HSS_S6A_ENABLED TRUE CACHE INTERNAL "dict_s6a.fdx Found") + ELSE(DICT_S6A_FOUND) + SET( FREEDIAMETER_HSS_S6A_ENABLED FALSE CACHE INTERNAL "dict_s6a.fdx not Found") + ENDIF(DICT_S6A_FOUND) + SET( FREEDIAMETER_VERSION_TEST_FOR ${FREEDIAMETER_LIBRARIES} CACHE INTERNAL "Version the test was made against" ) + ENDIF (NOT( "${FREEDIAMETER_VERSION_TEST_FOR}" STREQUAL "${FREEDIAMETER_LIBRARIES}" )) +ENDIF(FREEDIAMETER_FOUND) + diff --git a/cmake_targets/tools/MODULES/FindGCCXML.cmake b/cmake_targets/tools/MODULES/FindGCCXML.cmake new file mode 100644 index 0000000000000000000000000000000000000000..6a4daa084d81b7b10a4dd8882775984d9e70e30e --- /dev/null +++ b/cmake_targets/tools/MODULES/FindGCCXML.cmake @@ -0,0 +1,8 @@ +# FindGCCXML +# ---------- +find_program(GCCXML +NAMES gccxml +PATHS "/usr/bin" +"usr/local/bin" +) +mark_as_advanced(GCCXML) diff --git a/cmake_targets/tools/MODULES/FindGcrypt.cmake b/cmake_targets/tools/MODULES/FindGcrypt.cmake new file mode 100644 index 0000000000000000000000000000000000000000..fd4517dafbe67dc6ed47c6b3da1a4cccb3f2fdf1 --- /dev/null +++ b/cmake_targets/tools/MODULES/FindGcrypt.cmake @@ -0,0 +1,36 @@ +# - Find gnutls +# Find the native GCRYPT includes and library +# +# GCRYPT_FOUND - True if gnutls found. +# GCRYPT_INCLUDE_DIR - where to find gnutls.h, etc. +# GCRYPT_LIBRARIES - List of libraries when using gnutls. + +if (GCRYPT_INCLUDE_DIR AND GCRYPT_LIBRARIES) + set(GCRYPT_FIND_QUIETLY TRUE) +endif (GCRYPT_INCLUDE_DIR AND GCRYPT_LIBRARIES) + +# Include dir +find_path(GCRYPT_INCLUDE_DIR + NAMES + gcrypt.h +) + +# Library +find_library(GCRYPT_LIBRARY + NAMES gcrypt +) + +# handle the QUIETLY and REQUIRED arguments and set GCRYPT_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GCRYPT DEFAULT_MSG GCRYPT_LIBRARY GCRYPT_INCLUDE_DIR) + +IF(GCRYPT_FOUND) + SET( GCRYPT_LIBRARIES ${GCRYPT_LIBRARY} ) +ELSE(GCRYPT_FOUND) + SET( GCRYPT_LIBRARIES ) +ENDIF(GCRYPT_FOUND) + +# Lastly make it so that the GCRYPT_LIBRARY and GCRYPT_INCLUDE_DIR variables +# only show up under the advanced options in the gui cmake applications. +MARK_AS_ADVANCED( GCRYPT_LIBRARY GCRYPT_INCLUDE_DIR ) diff --git a/cmake_targets/tools/MODULES/FindGnuTLS.cmake b/cmake_targets/tools/MODULES/FindGnuTLS.cmake new file mode 100644 index 0000000000000000000000000000000000000000..19c4fffae6f2b85b1d672ecfbb46f3ec3bd4a970 --- /dev/null +++ b/cmake_targets/tools/MODULES/FindGnuTLS.cmake @@ -0,0 +1,64 @@ +# - Find gnutls +# Find the native GNUTLS includes and library +# +# GNUTLS_FOUND - True if gnutls found. +# GNUTLS_INCLUDE_DIR - where to find gnutls.h, etc. +# GNUTLS_LIBRARIES - List of libraries when using gnutls. +# GNUTLS_VERSION_210 - true if GnuTLS version is >= 2.10.0 (does not require additional separate gcrypt initialization) +# GNUTLS_VERSION_212 - true if GnuTLS version is >= 2.12.0 (supports gnutls_transport_set_vec_push_function) +# GNUTLS_VERSION_300 - true if GnuTLS version is >= 3.00.0 (x509 verification functions changed) +# GNUTLS_VERSION_310 - true if GnuTLS version is >= 3.01.0 (stabilization branch with new APIs) + +if (GNUTLS_INCLUDE_DIR AND GNUTLS_LIBRARIES) + set(GNUTLS_FIND_QUIETLY TRUE) +endif (GNUTLS_INCLUDE_DIR AND GNUTLS_LIBRARIES) + +# Include dir +find_path(GNUTLS_INCLUDE_DIR + NAMES + gnutls.h + gnutls/gnutls.h +) + +# Library +find_library(GNUTLS_LIBRARY + NAMES gnutls +) + +# handle the QUIETLY and REQUIRED arguments and set GNUTLS_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNUTLS DEFAULT_MSG GNUTLS_LIBRARY GNUTLS_INCLUDE_DIR) + +IF(GNUTLS_FOUND) + SET( GNUTLS_LIBRARIES ${GNUTLS_LIBRARY} ) +ELSE(GNUTLS_FOUND) + SET( GNUTLS_LIBRARIES ) +ENDIF(GNUTLS_FOUND) + +# Lastly make it so that the GNUTLS_LIBRARY and GNUTLS_INCLUDE_DIR variables +# only show up under the advanced options in the gui cmake applications. +MARK_AS_ADVANCED( GNUTLS_LIBRARY GNUTLS_INCLUDE_DIR ) + +# Now check if the library is recent. gnutls_hash was added in 2.10.0. +# Also test library is even more recent. gnutls_x509_trust_list_verify_crt was added in 3.00.0. +IF(GNUTLS_FOUND) + IF( NOT( "${GNUTLS_VERSION_TEST_FOR}" STREQUAL "${GNUTLS_LIBRARY}" )) + INCLUDE (CheckLibraryExists) + MESSAGE(STATUS "Checking GNUTLS version") + UNSET(GNUTLS_VERSION_210) + UNSET(GNUTLS_VERSION_210 CACHE) + UNSET(GNUTLS_VERSION_212) + UNSET(GNUTLS_VERSION_212 CACHE) + UNSET(GNUTLS_VERSION_300) + UNSET(GNUTLS_VERSION_300 CACHE) + UNSET(GNUTLS_VERSION_310) + UNSET(GNUTLS_VERSION_310 CACHE) + GET_FILENAME_COMPONENT(GNUTLS_PATH ${GNUTLS_LIBRARY} PATH) + CHECK_LIBRARY_EXISTS(gnutls gnutls_hash ${GNUTLS_PATH} GNUTLS_VERSION_210) + CHECK_LIBRARY_EXISTS(gnutls gnutls_transport_set_vec_push_function ${GNUTLS_PATH} GNUTLS_VERSION_212) + CHECK_LIBRARY_EXISTS(gnutls gnutls_x509_trust_list_verify_crt ${GNUTLS_PATH} GNUTLS_VERSION_300) + CHECK_LIBRARY_EXISTS(gnutls gnutls_handshake_set_timeout ${GNUTLS_PATH} GNUTLS_VERSION_310) + SET( GNUTLS_VERSION_TEST_FOR ${GNUTLS_LIBRARY} CACHE INTERNAL "Version the test was made against" ) + ENDIF (NOT( "${GNUTLS_VERSION_TEST_FOR}" STREQUAL "${GNUTLS_LIBRARY}" )) +ENDIF(GNUTLS_FOUND) diff --git a/cmake_targets/tools/MODULES/FindKbuild.cmake b/cmake_targets/tools/MODULES/FindKbuild.cmake new file mode 100644 index 0000000000000000000000000000000000000000..08accb8551fd63a61544713fd4e9b3dc937a1f9b --- /dev/null +++ b/cmake_targets/tools/MODULES/FindKbuild.cmake @@ -0,0 +1,105 @@ +# - Support for building kernel modules + +# This module defines several variables which may be used when build +# kernel modules. +# +# The following variables are set here: +# Kbuild_VERSION_STRING - kernel version. +# Kbuild_ARCH - architecture. +# Kbuild_BUILD_DIR - directory for build kernel and/or its components. +# Kbuild_VERSION_{MAJOR|MINOR|TWEAK} - kernel version components +# Kbuild_VERSION_STRING_CLASSIC - classic representation of version, +# where parts are delimited by dots. +# +# Cache variables which affect on this package: +# CMAKE_SYSTEM_VERSION - change Kbuild_VERSION_STRING +# Also, setting CMAKE_SYSTEM_VERSION will be interpreted by cmake as crosscompile. +# +# Cache variables(ADVANCED) which affect on this package: +# ARCH - if not empty, change Kbuild_ARCH +# KBUILD_DIR - change Kbuild_BUILD_DIR + +set(Kbuild_VERSION_STRING ${CMAKE_SYSTEM_VERSION}) + +# Form classic version view. +string(REGEX MATCH "([0-9]+)\\.([0-9]+)[.-]([0-9]+)" + _kernel_version_match + "${Kbuild_VERSION_STRING}" +) + +if(NOT _kernel_version_match) + message(FATAL_ERROR "Kernel version has unexpected format: ${Kbuild_VERSION_STRING}") +endif(NOT _kernel_version_match) + +set(Kbuild_VERSION_MAJOR ${CMAKE_MATCH_1}) +set(Kbuild_VERSION_MINOR ${CMAKE_MATCH_2}) +set(Kbuild_VERSION_TWEAK ${CMAKE_MATCH_3}) +# Version string for compare +set(Kbuild_VERSION_STRING_CLASSIC "${Kbuild_VERSION_MAJOR}.${Kbuild_VERSION_MINOR}.${Kbuild_VERSION_TWEAK}") + +set(KBUILD_DIR "/lib/modules/${Kbuild_VERSION_STRING}/build" CACHE PATH + "Directory for build linux kernel and/or its components." +) +mark_as_advanced(KBUILD_DIR) + +set(Kbuild_BUILD_DIR "${KBUILD_DIR}") + +set(ARCH "" CACHE STRING + "Architecture for build linux kernel components for, empty string means autodetect." +) +mark_as_advanced(ARCH) + +if(NOT ARCH) + # Autodetect arch. + execute_process(COMMAND uname -m + RESULT_VARIABLE uname_m_result + OUTPUT_VARIABLE ARCH_DEFAULT + ) + if(NOT uname_m_result EQUAL 0) + message("'uname -m' failed:") + message("${ARCH_DEFAULT}") + message(FATAL_ERROR "Failed to determine system architecture.") + endif(NOT uname_m_result EQUAL 0) + + string(REGEX REPLACE "\n$" "" ARCH_DEFAULT "${ARCH_DEFAULT}") + + # Pairs of pattern-replace for postprocess architecture string from + # 'uname -m'. + # Taken from ./Makefile of the kernel build. + set(_kbuild_arch_replacers + "i.86" "x86" + "x86_64" "x86" + "sun4u" "sparc64" + "arm.*" "arm" + "sa110" "arm" + "s390x" "s390" + "parisc64" "parisc" + "ppc.*" "powerpc" + "mips.*" "mips" + "sh[234].*" "sh" + "aarch64.*" "arm64" + ) + + set(_current_pattern) + foreach(p ${_kbuild_arch_replacers}) + if(_current_pattern) + string(REGEX REPLACE "${_current_pattern}" "${p}" ARCH_DEFAULT "${ARCH_DEFAULT}") + set(_current_pattern) + else(_current_pattern) + set(_current_pattern "${p}") + endif(_current_pattern) + endforeach(p ${_kbuild_arch_replacers}) + + set(Kbuild_ARCH "${ARCH_DEFAULT}") +else(NOT ARCH) + # User-provided value is used. + set(Kbuild_ARCH "${ARCH}") +endif(NOT ARCH) + + + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Kbuild + REQUIRED_VARS Kbuild_BUILD_DIR + VERSION_VAR KBuild_VERSION_STRING_CLASSIC +) diff --git a/cmake_targets/tools/MODULES/FindLibXml2.cmake b/cmake_targets/tools/MODULES/FindLibXml2.cmake new file mode 100644 index 0000000000000000000000000000000000000000..e18dc2e921b8f49d103cf3ce9547ee0885d50dd7 --- /dev/null +++ b/cmake_targets/tools/MODULES/FindLibXml2.cmake @@ -0,0 +1,53 @@ +# - Try to find the LibXml2 xml processing library +# Once done this will define +# +# LIBXML2_FOUND - System has LibXml2 +# LIBXML2_INCLUDE_DIR - The LibXml2 include directory +# LIBXML2_LIBRARIES - The libraries needed to use LibXml2 +# LIBXML2_DEFINITIONS - Compiler switches required for using LibXml2 +# LIBXML2_XMLLINT_EXECUTABLE - The XML checking tool xmllint coming with LibXml2 + +#============================================================================= +# Copyright 2006-2009 Kitware, Inc. +# Copyright 2006 Alexander Neundorf <neundorf@kde.org> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +# License text for the above reference.) + +# use pkg-config to get the directories and then use these values +# in the FIND_PATH() and FIND_LIBRARY() calls +FIND_PACKAGE(PkgConfig) +PKG_CHECK_MODULES(PC_LIBXML libxml-2.0) +SET(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER}) + +FIND_PATH(LIBXML2_INCLUDE_DIR NAMES libxml/xpath.h + HINTS + ${PC_LIBXML_INCLUDEDIR} + ${PC_LIBXML_INCLUDE_DIRS} + PATH_SUFFIXES libxml2 + ) + +FIND_LIBRARY(LIBXML2_LIBRARIES NAMES xml2 libxml2 + HINTS + ${PC_LIBXML_LIBDIR} + ${PC_LIBXML_LIBRARY_DIRS} + ) + +FIND_PROGRAM(LIBXML2_XMLLINT_EXECUTABLE xmllint) +# for backwards compat. with KDE 4.0.x: +SET(XMLLINT_EXECUTABLE "${LIBXML2_XMLLINT_EXECUTABLE}") + +# handle the QUIETLY and REQUIRED arguments and set LIBXML2_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARIES LIBXML2_INCLUDE_DIR) + +MARK_AS_ADVANCED(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARIES LIBXML2_XMLLINT_EXECUTABLE) + diff --git a/cmake_targets/tools/MODULES/FindMySQL.cmake b/cmake_targets/tools/MODULES/FindMySQL.cmake new file mode 100644 index 0000000000000000000000000000000000000000..668f8a434dcf642651d9dcd321874a6c2eb70e53 --- /dev/null +++ b/cmake_targets/tools/MODULES/FindMySQL.cmake @@ -0,0 +1,55 @@ +# - Find mysqlclient +# +# -*- cmake -*- +# +# Find the native MySQL includes and library +# +# MySQL_INCLUDE_DIR - where to find mysql.h, etc. +# MySQL_LIBRARIES - List of libraries when using MySQL. +# MySQL_FOUND - True if MySQL found. + +IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) + # Already in cache, be silent + SET(MySQL_FIND_QUIETLY TRUE) +ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) + +# Include dir +FIND_PATH(MySQL_INCLUDE_DIR + NAMES mysql.h + PATH_SUFFIXES mysql +) + +# Library +#SET(MySQL_NAMES mysqlclient mysqlclient_r) +SET(MySQL_NAMES mysqlclient) +FIND_LIBRARY(MySQL_LIBRARY + NAMES ${MySQL_NAMES} + PATHS /usr/lib /usr/local/lib + PATH_SUFFIXES mysql +) + +IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) + SET(MySQL_FOUND TRUE) + SET( MySQL_LIBRARIES ${MySQL_LIBRARY} ) +ELSE (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) + SET(MySQL_FOUND FALSE) + SET( MySQL_LIBRARIES ) +ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) + + +IF (MySQL_FOUND) + IF (NOT MySQL_FIND_QUIETLY) + MESSAGE(STATUS "Found MySQL: ${MySQL_LIBRARY}") + ENDIF (NOT MySQL_FIND_QUIETLY) +ELSE (MySQL_FOUND) + IF (MySQL_FIND_REQUIRED) + MESSAGE(STATUS "Looked for MySQL libraries named ${MySQL_NAMES}.") + MESSAGE(FATAL_ERROR "Could NOT find MySQL library") + ENDIF (MySQL_FIND_REQUIRED) +ENDIF (MySQL_FOUND) + +MARK_AS_ADVANCED( + MySQL_LIBRARY + MySQL_INCLUDE_DIR + ) + diff --git a/cmake_targets/tools/MODULES/FindNettle.cmake b/cmake_targets/tools/MODULES/FindNettle.cmake new file mode 100644 index 0000000000000000000000000000000000000000..4602e749970dce10a47173299b35a018707aa413 --- /dev/null +++ b/cmake_targets/tools/MODULES/FindNettle.cmake @@ -0,0 +1,22 @@ +# Find the native Nettle includes, library, and flags +# +# NETTLE_INCLUDE_DIR - where to find nettle.h, etc. +# NETTLE_LIBRARIES - List of libraries when using Nettle. +# NETTLE_FOUND - True if Nettle found. +IF (NETTLE_INCLUDE_DIR) +# Already in cache, be silent + SET(NETTLE_FIND_QUIETLY TRUE) +ENDIF (NETTLE_INCLUDE_DIR) +FIND_PATH(NETTLE_INCLUDE_DIR nettle/nettle-meta.h) +SET(NETTLE_NAMES nettle) +FIND_LIBRARY(NETTLE_LIBRARY NAMES ${NETTLE_NAMES} ) +# handle the QUIETLY and REQUIRED arguments and set NETTLE_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(NETTLE DEFAULT_MSG NETTLE_LIBRARY NETTLE_INCLUDE_DIR) +IF(NETTLE_FOUND) + SET(NETTLE_LIBRARIES ${NETTLE_LIBRARY}) +ELSE(NETTLE_FOUND) + SET(NETTLE_LIBRARIES ) +ENDIF(NETTLE_FOUND) +MARK_AS_ADVANCED(NETTLE_LIBRARY NETTLE_INCLUDE_DIR) diff --git a/cmake_targets/tools/MODULES/FindPostgreSQL.cmake b/cmake_targets/tools/MODULES/FindPostgreSQL.cmake new file mode 100644 index 0000000000000000000000000000000000000000..a639a262b0ae365aa7e433680cf1a3bbb017719d --- /dev/null +++ b/cmake_targets/tools/MODULES/FindPostgreSQL.cmake @@ -0,0 +1,36 @@ +# - Find PostgreSQL library +# +# This module defines: +# POSTGRESQL_FOUND - True if the package is found +# POSTGRESQL_INCLUDE_DIR - containing libpq-fe.h +# POSTGRESQL_LIBRARIES - Libraries to link to use PQ functions. + +if (POSTGRESQL_INCLUDE_DIR AND POSTGRESQL_LIBRARIES) + set(POSTGRESQL_FIND_QUIETLY TRUE) +endif (POSTGRESQL_INCLUDE_DIR AND POSTGRESQL_LIBRARIES) + +# Include dir +find_path(POSTGRESQL_INCLUDE_DIR + NAMES libpq-fe.h + PATH_SUFFIXES pgsql postgresql +) + +# Library +find_library(POSTGRESQL_LIBRARY + NAMES pq +) + +# handle the QUIETLY and REQUIRED arguments and set POSTGRESQL_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(POSTGRESQL DEFAULT_MSG POSTGRESQL_LIBRARY POSTGRESQL_INCLUDE_DIR) + +IF(POSTGRESQL_FOUND) + SET( POSTGRESQL_LIBRARIES ${POSTGRESQL_LIBRARY} ) +ELSE(POSTGRESQL_FOUND) + SET( POSTGRESQL_LIBRARIES ) +ENDIF(POSTGRESQL_FOUND) + +# Lastly make it so that the POSTGRESQL_LIBRARY and POSTGRESQL_INCLUDE_DIR variables +# only show up under the advanced options in the gui cmake applications. +MARK_AS_ADVANCED( POSTGRESQL_LIBRARY POSTGRESQL_INCLUDE_DIR ) diff --git a/cmake_targets/tools/MODULES/FindSCTP.cmake b/cmake_targets/tools/MODULES/FindSCTP.cmake new file mode 100644 index 0000000000000000000000000000000000000000..de8e878a995963a6b1d4dfcfec2f4a69aeeaa942 --- /dev/null +++ b/cmake_targets/tools/MODULES/FindSCTP.cmake @@ -0,0 +1,46 @@ +# - Try to find SCTP library and headers +# Once done, this will define +# +# SCTP_FOUND - system has SCTP +# SCTP_INCLUDE_DIR - the SCTP include directories +# SCTP_LIBRARIES - link these to use SCTP + +if (SCTP_INCLUDE_DIR AND SCTP_LIBRARIES) + set(SCTP_FIND_QUIETLY TRUE) +endif (SCTP_INCLUDE_DIR AND SCTP_LIBRARIES) + +# Include dir +find_path(SCTP_INCLUDE_DIR + NAMES netinet/sctp.h +) + +# Library +find_library(SCTP_LIBRARY + NAMES sctp +) + +# Set the include dir variables and the libraries and let libfind_process do the rest. +# NOTE: Singular variables for this library, plural for libraries this this lib depends on. +#set(SCTP_PROCESS_INCLUDES SCTP_INCLUDE_DIR) +#set(SCTP_PROCESS_LIBS SCTP_LIBRARY) +#libfind_process(SCTP) + + +# handle the QUIETLY and REQUIRED arguments and set SCTP_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SCTP DEFAULT_MSG SCTP_LIBRARY SCTP_INCLUDE_DIR) + +# If we successfully found the sctp library then add the library to the +# SCTP_LIBRARIES cmake variable otherwise set SCTP_LIBRARIES to nothing. +IF(SCTP_FOUND) + SET( SCTP_LIBRARIES ${SCTP_LIBRARY} ) +ELSE(SCTP_FOUND) + SET( SCTP_LIBRARIES ) +ENDIF(SCTP_FOUND) + + +# Lastly make it so that the SCTP_LIBRARY and SCTP_INCLUDE_DIR variables +# only show up under the advanced options in the gui cmake applications. +MARK_AS_ADVANCED( SCTP_LIBRARY SCTP_INCLUDE_DIR ) + diff --git a/cmake_targets/tools/MODULES/Kbuild.cmake b/cmake_targets/tools/MODULES/Kbuild.cmake new file mode 100644 index 0000000000000000000000000000000000000000..7403cd04df670a6fbb720d9221365a95a90f4d78 --- /dev/null +++ b/cmake_targets/tools/MODULES/Kbuild.cmake @@ -0,0 +1,4 @@ +src=${dir} +obj-m += ${name}.o +${name}-y += ${objs} +ccflags-y += ${module_cc_opt} diff --git a/cmake_targets/tools/MODULES/cmake_useful.cmake b/cmake_targets/tools/MODULES/cmake_useful.cmake new file mode 100644 index 0000000000000000000000000000000000000000..af6bbb56c7c1c3ae3a84cc6684072c2533daea18 --- /dev/null +++ b/cmake_targets/tools/MODULES/cmake_useful.cmake @@ -0,0 +1,229 @@ +# Create rule for obtain one file by copying another one +function(rule_copy_file target_file source_file) + add_custom_command(OUTPUT ${target_file} + COMMAND cp -p ${source_file} ${target_file} + DEPENDS ${source_file} + ) +endfunction(rule_copy_file target_file source_file) + +# rule_copy_source([source_dir] file ...) +# +# Create rule for obtain file(s) in binary tree by copiing it from source tree. +# +# Files are given relative to ${source_dir}, if it is set, or +# relative to ${CMAKE_CURRENT_SOURCE_DIR}. +# +# Files will be copied into ${CMAKE_CURRENT_BINARY_DIR} with same +# relative paths. +# +# ${source_dir} should be absolute path(that is, starts from '/'). +# Otherwise first argument is treated as first file to copy. +function(rule_copy_source file) + string(REGEX MATCH "^/" is_abs_path ${file}) + if(is_abs_path) + set(source_dir ${file}) + set(files ${ARGN}) + else(is_abs_path) + set(source_dir ${CMAKE_CURRENT_SOURCE_DIR}) + set(files ${file} ${ARGN}) + endif(is_abs_path) + + foreach(file_real ${files}) + rule_copy_file("${CMAKE_CURRENT_BINARY_DIR}/${file_real}" + ${source_dir}/${file_real}) + endforeach(file_real ${files}) +endfunction(rule_copy_source file) + +# to_abs_path(output_var path [...]) +# +# Convert relative path of file to absolute path: +# use path in source tree, if file already exist there. +# otherwise use path in binary tree. +# If initial path already absolute, return it. +function(to_abs_path output_var) + set(result) + foreach(path ${ARGN}) + string(REGEX MATCH "^/" _is_abs_path ${path}) + if(_is_abs_path) + list(APPEND result ${path}) + else(_is_abs_path) + file(GLOB to_abs_path_file + "${CMAKE_CURRENT_SOURCE_DIR}/${path}" + ) + if(NOT to_abs_path_file) + set (to_abs_path_file "${CMAKE_CURRENT_BINARY_DIR}/${path}") + endif(NOT to_abs_path_file) + list(APPEND result ${to_abs_path_file}) + endif(_is_abs_path) + endforeach(path ${ARGN}) + set("${output_var}" ${result} PARENT_SCOPE) +endfunction(to_abs_path output_var path) + +# is_path_inside_dir(output_var dir path) +# +# Set output_var to true if path is absolute path inside given directory. +# NOTE: Path should be absolute. +macro(is_path_inside_dir output_var dir path) + file(RELATIVE_PATH _rel_path ${dir} ${path}) + string(REGEX MATCH "^\\.\\." _is_not_inside_dir ${_rel_path}) + if(_is_not_inside_dir) + set(${output_var} "FALSE") + else(_is_not_inside_dir) + set(${output_var} "TRUE") + endif(_is_not_inside_dir) +endmacro(is_path_inside_dir output_var dir path) + + +# Write given content to the file. +# +# If file is already exists and its content is same as written one, file +# is not rewritten, so its write timestamp remains unchanged. +function(file_update filename content) + if(EXISTS "${filename}") + file(READ "${filename}" old_content) + if(old_content STREQUAL "${content}") + return() + endif(old_content STREQUAL "${content}") + endif(EXISTS "${filename}") + # File doesn't exists or its content differ. + file(WRITE "${filename}" "${content}") +endfunction(file_update filename content) + + +# Write given content to the file in APPEND mode. +# +# For append we use position variable <pos> which should be initialized +# to 0 for every new build process and which is updated every time when +# this function is called. +# If file is already exists and its content at given <pos> is same as +# written one, file is not rewritten, so its write timestamp remains unchanged. +# +# Note, that file will not be rewritten if new build process issues less +# APPEND actions than one which create file. +# But similar problem exists for file_update() and even for built-in +# configure_file() command: file will not be removed if new build process +# do not call configure_file() for it. +function(file_update_append filename content POS) + set(pos "${${POS}}") + string(LENGTH "${content}" len) + # Update output variable first. + # This allows to use return() when need not to do anything + math(EXPR pos_new "${pos}+${len}") + set(${POS} "${pos_new}" PARENT_SCOPE) + if(EXISTS "${filename}") + file(READ "${filename}" old_content LIMIT "${len}" OFFSET "${pos}") + if(old_content STREQUAL "${content}") + return() + elseif(old_content STREQUAL "") + file(APPEND "${filename}" "${content}") + return() + endif(old_content STREQUAL "${content}") + else(EXISTS "${filename}") + if(NOT pos EQUAL 0) + message(FATAL_ERROR "Appending to non-zero position to non-existent file.") + endif(NOT pos EQUAL 0) + endif(EXISTS "${filename}") + # File doesn't exists or its content differ. + if(NOT pos EQUAL 0) + file(READ "${filename}" prefix LIMIT "${pos}") + else(NOT pos EQUAL 0) + set(prefix) + endif(NOT pos EQUAL 0) + file(WRITE "${filename}" "${prefix}${content}") +endfunction(file_update_append filename content POS) + + +# Common mechanism for output status message +# when checking different aspects. +# +# Normal using: +# +# check_begin("Checking <...>") +# if(NOT <check-already-has-been-done>) +# check_try() # Here message is printed +# # Perform check(try_compile(), etc.) +# endif(NOT <check-already-has-been-done>) +# check_end("<check-result>") # Here message is printed with result. + +# Should be called (unconditionally) when new cheking is issued. +# Note, that given @status_msg is not printed at that step. +function(check_begin status_msg) + set(_check_status_msg ${status_msg} PARENT_SCOPE) + set(_check_has_tries PARENT_SCOPE) +endfunction(check_begin status_msg) + +# Should be called before every real checking, that is which is not come +# from cache variables comparision. +# +# First call of that function is trigger printing of @status_msg, +# passed to check_begin(). +function(check_try) + if(NOT _check_has_tries) + message(STATUS "${_check_status_msg}") + set(_check_has_tries "1" PARENT_SCOPE) + endif(NOT _check_has_tries) +endfunction(check_try) + +# Should be called when cheking is end, and @result_msg should be short +# description of check result. +# If any check_try() has been issued before, +# "@status_msg - @result_msg" +# will be printed. +# Otherwise, +# "@status_msg - [cached] @result_msg" +# will be printed, at it will be the only message for that check. +function(check_end result_msg) + if(NOT _check_has_tries) + message(STATUS "${_check_status_msg} [cached] - ${result_msg}") + else(NOT _check_has_tries) + message(STATUS "${_check_status_msg} - ${result_msg}") + endif(NOT _check_has_tries) + set(_check_status_msg PARENT_SCOPE) + set(_check_has_tries PARENT_SCOPE) +endfunction(check_end result_msg) + +# set_bool_string(var true_string false_string value [CACHE ... | PARENT_SCOPE]) +# +# Set variable to one of two string according to true property of some value. +# +# If 'value' is true-evaluated, 'var' will be set to 'true_string', +# otherwise to 'var' will be set to 'false_string'. +# Like standard set(), macro accept CACHE and PARENT_SCOPE modifiers. +# +# Useful for form meaningful value for cache variables, contained result +# of some operation. +# Also may be used for form message for check_end(). +macro(set_bool_string var true_string false_string value) + # Macro parameters are not a variables, so them cannot be tested + # using 'if(value)'. + # Usage 'if(${value})' leads to warnings since 2.6.4 when ${val} + # is boolean constant + # (because until 2.6.4 'if(value)' always dereference val). + # So copy 'value' to local variable for test it. + set(_set_bool_string_value ${value}) + if(_set_bool_string_value) + set(${var} "${true_string}" ${ARGN}) + else() + set(${var} "${false_string}" ${ARGN}) + endif() +endmacro(set_bool_string) + +# set_zero_string(var true_string false_string value [CACHE ... | PARENT_SCOPE]) +# +# Set variable to one of two string according to zero property of some value. +# +# If 'value' is '0' (presizely), 'var' will be set to 'zero_string', +# otherwise to 'var' will be set to 'nonzero_string'. +# Like standard set(), macro accept CACHE and PARENT_SCOPE modifiers. +# +# Useful for form meaningful value for cache variables, contained result +# of execute_process(). +# Also may be used for form message for check_end(). +macro(set_zero_string var zero_string nonzero_string value) + set(_set_zero_string_value ${value}) + if(_set_zero_string_value EQUAL "0") + set(${var} ${zero_string} ${ARGN}) + else() + set(${var} ${nonzero_string} ${ARGN}) + endif() +endmacro(set_zero_string) \ No newline at end of file diff --git a/cmake_targets/tools/MODULES/kbuild_system.cmake b/cmake_targets/tools/MODULES/kbuild_system.cmake new file mode 100644 index 0000000000000000000000000000000000000000..42a1a2d42b4a8723709641fb33879a8ddf5a56d5 --- /dev/null +++ b/cmake_targets/tools/MODULES/kbuild_system.cmake @@ -0,0 +1,1131 @@ +# Provide way for create kernel modules, and perform other actions on them +# in a way similar to standard cmake executables and libraries processing. +# +# NB: At the end of the whole configuration stage +# kbuild_finalize_linking() +# should be executed. +# +# Should be included after: +# find_package(Kbuild) +# +# Cached variables(ADVANCED), which affects on definitions below: +# CROSS_COMPILE - corresponded parameter for 'make' to build kernel objects. +# KBUILD_C_FLAGS - Additional kbuild flags for all builds +# KBUILD_C_FLAGS{DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL} - per-configuration flags. + +include(cmake_useful) + +# Compute path to the auxiliary files. +get_filename_component(kbuild_this_module_dir ${CMAKE_CURRENT_LIST_FILE} PATH) +set(kbuild_aux_dir "${kbuild_this_module_dir}/kbuild_system_files") + +# _declare_per_build_vars(<variable> <doc-pattern>) +# +# [INTERNAL] Per-build type definitions for given <variable>. +# +# Create CACHE STRING variables <variable>_{DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL} +# with documentation string <doc-pattern> where %build% is replaced +# with corresponded build type description. +# +# Default value for variable <variable>_<type> is taken from <variable>_<type>_INIT. +macro(_declare_per_build_vars variable doc_pattern) + set(_build_type) + foreach(t + RELEASE "release" + DEBUG "debug" + RELWITHDEBINFO "Release With Debug Info" + MINSIZEREL "release minsize" + ) + if(_build_type) + string(REPLACE "%build%" "${t}" _docstring ${doc_pattern}) + set("${variable}_${_build_type}" "${${variable}_${_build_type}_INIT}" + CACHE STRING "${_docstring}") + set(_build_type) + else(_build_type) + set(_build_type "${t}") + endif(_build_type) + endforeach(t) +endmacro(_declare_per_build_vars variable doc_pattern) + + +# Default compiler flags. +# +# These flags are used directly when configuring 'Kbuild', so them should be +# expressed as single-string, where different flags are joinged using ' '. +set(KBUILD_C_FLAGS "" CACHE STRING + "Compiler flags used by Kbuild system during all builds." +) + +# Additional default compiler flags per build type. +set(KBUILD_C_FLAGS_DEBUG_INIT "-g") +set(KBUILD_C_FLAGS_RELWITHDEBINFO_INIT "-g") + +_declare_per_build_vars(KBUILD_C_FLAGS + "Compiler flags used by Kbuild system during %build% builds." +) +mark_as_advanced( + KBUILD_C_FLAGS + KBUILD_C_FLAGS_DEBUG + KBUILD_C_FLAGS_RELEASE + KBUILD_C_FLAGS_RELWITHDEBINFO + KBUILD_C_FLAGS_MINSIZEREL +) + + +# Additional definitions which are passed directly to 'make' for +# kbuild process. +# +# Unlike to compiler flags, these ones are expressed using cmake list. +set(KBUILD_MAKE_FLAGS "" CACHE STRING + "Make flags used by Kbuild system during all builds." +) + +_declare_per_build_vars(KBUILD_MAKE_FLAGS + "Make flags used by Kbuild system during %build% builds." +) + +mark_as_advanced( + KBUILD_MAKE_FLAGS + KBUILD_MAKE_FLAGS_DEBUG + KBUILD_MAKE_FLAGS_RELEASE + KBUILD_MAKE_FLAGS_RELWITHDEBINFO + KBUILD_MAKE_FLAGS_MINSIZEREL +) + +set(CROSS_COMPILE "" CACHE STRING "Cross compilation prefix for build linux kernel objects.") +mark_as_advanced(CROSS_COMPILE) + +# Property prefixed with 'KMODULE_' is readonly for outer use, +# unless explicitely noted in its description. + +# Property is set for every target described kernel module. +# Concrete property's value currently has no special meaning. +define_property(TARGET PROPERTY KMODULE_TYPE + BRIEF_DOCS "Whether given target describes kernel module." + FULL_DOCS "Whether given target describes kernel module." +) + +# Absolute filename of .ko file which is built. +# NOTE: Imported targets use +# KMODULE_IMPORTED_MODULE_LOCATION +# property instead. +define_property(TARGET PROPERTY KMODULE_MODULE_LOCATION + BRIEF_DOCS "Location of the built kernel module." + FULL_DOCS "Location of the built kernel module." +) + +# Name of the given module, like "ext4" or "kedr". +define_property(TARGET PROPERTY KMODULE_MODULE_NAME + BRIEF_DOCS "Name of the kernel module." + FULL_DOCS "Name of the kernel module." +) + + +# Absolute filename of Module.symvers file which is built. +# NOTE: Imported targets use +# KMODULE_IMPORTED_SYMVERS_LOCATION +# property instead. +define_property(TARGET PROPERTY KMODULE_SYMVERS_LOCATION + BRIEF_DOCS "Location of the symvers file of the kernel module." + FULL_DOCS "Location of the symvers file of the kernel module." +) + +# Property is "TRUE" for every target described imported kernel module, +# "FALSE" for other targets described kernel module. +define_property(TARGET PROPERTY KMODULE_IMPORTED + BRIEF_DOCS "Whether given target describes imported kernel module." + FULL_DOCS "Whether given target describes imported kernel module." +) + +# Absolute filename of .ko file which is imported. +# Property may be set after +# kbuild_add_module(... IMPORTED) +# for allow loading of given module or perform other actions required +# kernel module itself. +# +# Analogue for KMODULE_MODULE_LOCATION property of normal(non-exported) +# kernel module target. +define_property(TARGET PROPERTY KMODULE_IMPORTED_MODULE_LOCATION + BRIEF_DOCS "Location of the imported kernel module." + FULL_DOCS "Location of the imported kernel module." +) + +# Absolute filename of Module.symvers file for imported kernel module. +# Property may be set after +# kbuild_add_module(... IMPORTED) +# for allow linking with given module or perform other actions required +# its symbols. +# +# Analogue for KMODULE_MODULE_SYMVERS_LOCATION property of normal(non-exported) +# kernel module target. +define_property(TARGET PROPERTY KMODULE_IMPORTED_SYMVERS_LOCATION + BRIEF_DOCS "Location of the symvers file for imported kernel module." + FULL_DOCS "Location of the symvers file for imported kernel module." +) + +# Helpers for simple extract some kernel module properties. + +# kbuild_get_module_location(RESULT_VAR name) +# +# Return location of the module, determined by the property +# KMODULE_MODULE_LOCATION or KMODULE_IMPORTED_MODULE_LOCATION for +# imported target. In the last case the property is checked for being set. +function(kbuild_get_module_location RESULT_VAR name) + if(NOT TARGET ${name}) + message(FATAL_ERROR "\"${name}\" is not really a target.") + endif(NOT TARGET ${name}) + get_property(kmodule_type TARGET ${name} PROPERTY KMODULE_TYPE) + if(NOT kmodule_type) + message(FATAL_ERROR "\"${name}\" is not really a target for kernel module.") + endif(NOT kmodule_type) + get_property(kmodule_imported TARGET ${name} PROPERTY KMODULE_IMPORTED) + if(kmodule_imported) + get_property(module_location TARGET ${name} PROPERTY KMODULE_IMPORTED_MODULE_LOCATION) + if(NOT module_location) + message(FATAL_ERROR "target \"${name}\" for imported module has no property KMODULE_IMPORTED_MODULE_LOCATION set.") + endif(NOT module_location) + else(kmodule_imported) + get_property(module_location TARGET ${name} PROPERTY KMODULE_MODULE_LOCATION) + endif(kmodule_imported) + set(${RESULT_VAR} ${module_location} PARENT_SCOPE) +endfunction(kbuild_get_module_location RESULT_VAR module) + +# kbuild_get_symvers_location(RESULT_VAR name) +# +# Return location of the symvers file for the module, determined by the +# property KMODULE_SYMVERS_LOCATION or KMODULE_IMPORTED_SYMVERS_LOCATION +# for imported target. In the last case the property is checked for being set. +function(kbuild_get_symvers_location RESULT_VAR name) + if(NOT TARGET ${name}) + message(FATAL_ERROR "\"${name}\" is not really a target.") + endif(NOT TARGET ${name}) + get_property(kmodule_type TARGET ${name} PROPERTY KMODULE_TYPE) + if(NOT kmodule_type) + message(FATAL_ERROR "\"${name}\" is not really a target for kernel module.") + endif(NOT kmodule_type) + get_property(kmodule_imported TARGET ${name} PROPERTY KMODULE_IMPORTED) + if(kmodule_imported) + get_property(symvers_location TARGET ${name} PROPERTY KMODULE_IMPORTED_SYMVERS_LOCATION) + if(NOT symvers_location) + message(FATAL_ERROR "target \"${name}\" for imported module has no property KMODULE_IMPORTED_SYMVERS_LOCATION set.") + endif(NOT symvers_location) + else(kmodule_imported) + get_property(symvers_location TARGET ${name} PROPERTY KMODULE_SYMVERS_LOCATION) + endif(kmodule_imported) + set(${RESULT_VAR} ${symvers_location} PARENT_SCOPE) +endfunction(kbuild_get_symvers_location RESULT_VAR module) + +# kbuild_add_module(<name> [EXCLUDE_FROM_ALL] [MODULE_NAME <module_name>] [<sources> ...]) +# +# Build kernel module from <sources>, analogue of add_library(). +# +# Source files are divided into two categories: +# -Object sources +# -Other sourses +# +# Object sources are those sources, which may be used in building kernel +# module externally. +# Follow types of object sources are supported now: +# .c: a file with the code in C language; +# .S: a file with the code in assembly language; +# .o_shipped: shipped file in binary format, +# does not require additional preprocessing. +# +# Other sources are treated as only prerequisite of building process. +# +# +# kbuild_add_module(<name> [MODULE_NAME <module_name>] IMPORTED) +# +# Create target, corresponded to the imported kernel module. +# In that case KMODULE_IMPORTED_* properties should be set manually if needed. +# +# In either case, if MODULE_NAME option is given, it determine name +# of the kernel module. Otherwise <name> itself is used. +function(kbuild_add_module name) + cmake_parse_arguments(kbuild_add_module "IMPORTED;EXCLUDE_FROM_ALL" "MODULE_NAME" "" ${ARGN}) + if(kbuild_add_module_MODULE_NAME) + set(module_name "${kbuild_add_module_MODULE_NAME}") + else(kbuild_add_module_MODULE_NAME) + set(module_name "${name}") + endif(kbuild_add_module_MODULE_NAME) + + string(LENGTH ${module_name} module_name_len) + if(module_name_len GREATER 55) + # Name of the kernel module should fit into array of size (64-sizeof(unsigned long)). + # On 64-bit systems(most restricted) this is 56. + # Even 56 length is not good, as it is not include null character. + # Without it, old versions of rmmod failed to unload module. + message(SEND_ERROR "Kernel module name exceeds 55 characters: '${module_name}'") + endif(module_name_len GREATER 55) + + if(kbuild_add_module_IMPORTED) + # Creation of IMPORTED target is simple. + add_custom_target(${name}) + set_property(TARGET ${name} PROPERTY KMODULE_TYPE "kmodule") + set_property(TARGET ${name} PROPERTY KMODULE_IMPORTED "TRUE") + set_property(TARGET ${name} PROPERTY KMODULE_MODULE_NAME "${module_name}") + return() + endif(kbuild_add_module_IMPORTED) + + if(kbuild_add_module_EXCLUDE_FROM_ALL) + set(all_arg) + else(kbuild_add_module_EXCLUDE_FROM_ALL) + set(all_arg "ALL") + endif(kbuild_add_module_EXCLUDE_FROM_ALL) + + # List of all source files, which are given. + set(sources ${kbuild_add_module_UNPARSED_ARGUMENTS}) + + # Sources with absolute paths + to_abs_path(sources_abs ${sources}) + # list of files from which module building is depended + set(depend_files) + # Sources of "c" type, but without extension. + # Used for clean files, and for out-of-source builds do not create + # files in source tree. + set(c_sources_noext_abs) + # The sources with the code in assembly + set(asm_sources_noext_abs) + # Sources of "o_shipped" type, but without extension + set(shipped_sources_noext_abs) + # Categorize sources + foreach(source_abs ${sources_abs}) + get_filename_component(ext ${source_abs} EXT) + if(ext STREQUAL ".c" OR ext STREQUAL ".S" OR ext STREQUAL ".o_shipped") + # Real sources + # Move source into binary tree, if needed + copy_source_to_binary_dir("${source_abs}" source_abs) + + get_filename_component(source_noext "${source_abs}" NAME_WE) + get_filename_component(source_dir "${source_abs}" PATH) + set(source_noext_abs "${source_dir}/${source_noext}") + if(ext STREQUAL ".c") + # c-source + list(APPEND c_sources_noext_abs ${source_noext_abs}) + elseif(ext STREQUAL ".S") + # asm source + list(APPEND asm_sources_noext_abs ${source_noext_abs}) + elseif(ext STREQUAL ".o_shipped") + # shipped-source + list(APPEND shipped_sources_noext_abs ${source_noext_abs}) + endif(ext STREQUAL ".c") + endif(ext STREQUAL ".c" OR ext STREQUAL ".S" OR ext STREQUAL ".o_shipped") + # In any case, add file to depend list + list(APPEND depend_files ${source_abs}) + endforeach(source_abs ${sources_abs}) + + # Object sources relative to current binary dir + # (for $(module)-y :=) + set(obj_sources_noext_rel) + foreach(obj_sources_noext_abs + ${c_sources_noext_abs} ${asm_sources_noext_abs} ${shipped_sources_noext_abs}) + file(RELATIVE_PATH obj_source_noext_rel + ${CMAKE_CURRENT_BINARY_DIR} ${obj_sources_noext_abs}) + list(APPEND obj_sources_noext_rel ${obj_source_noext_rel}) + endforeach(obj_sources_noext_abs) + + if(NOT obj_sources_noext_rel) + message(FATAL_ERROR "List of object files for building kernel module ${name} is empty.") + endif(NOT obj_sources_noext_rel) + + set(obj_sources_rel) + # Detect, if build simple - source object name coincide with module name + + if(NOT obj_sources_noext_rel STREQUAL ${name}) + # Check, whether only one of source object names coincide with module name. + # This situation is incorrect for kbuild system. + list(FIND obj_sources_noext_rel ${name} is_objects_contain_name) + if(is_objects_contain_name GREATER -1) + message(FATAL_ERROR "Module should be built " + "either from only one object with same name, " + "or from objects with names different from the name of the module") + endif(is_objects_contain_name GREATER -1) + + foreach(obj_source_noext_rel ${obj_sources_noext_rel}) + list(APPEND obj_sources_rel "${obj_source_noext_rel}.o") + endforeach(obj_source_noext_rel ${obj_sources_noext_rel}) + endif(NOT obj_sources_noext_rel STREQUAL ${name}) + + _get_directory_property_chained(ccflags KBUILD_COMPILE_DEFINITIONS " ") + _get_directory_property_chained(include_dirs KBUILD_INCLUDE_DIRECTORIES) + + # Target for create module. + add_custom_target(${name} ALL + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" + "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" + ) + + # Create .cmd files for 'shipped' sources. + # Gcc does not create them automatically for some reason. + set(cmd_create_command) + if(shipped_sources_noext_abs) + foreach(shipped_source_noext_abs ${shipped_source_noext_abs}) + get_filename_component(shipped_dir ${shipped_source_noext_abs} PATH) + get_filename_component(shipped_name ${shipped_source_noext_abs} NAME) + list(APPEND cmd_create_command + COMMAND printf "cmd_%s.o := cp -p %s.o_shipped %s.o\\n" + "${shipped_source_noext_abs}" + "${shipped_source_noext_abs}" + "${shipped_source_noext_abs}" + > "${shipped_dir}/.${shipped_name}.o.cmd") + endforeach(shipped_source_noext_abs ${shipped_source_noext_abs}) + endif(shipped_sources_noext_abs) + + # User-defined parameters for 'make' + set(make_flags ${KBUILD_MAKE_FLAGS}) + _get_per_build_var(make_flags_per_build KBUILD_MAKE_FLAGS) + list(APPEND make_flags ${make_flags_per_build}) + + # Rule for create module(and symvers file). + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" + "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" + ${cmd_create_command} + COMMAND $(MAKE) ${make_flags} ${kbuild_additional_make_flags} + -C ${Kbuild_BUILD_DIR} M=${CMAKE_CURRENT_BINARY_DIR} modules +# Update timestamps for targets. +# In some cases Kbuild system may decide do not update resulted files +# even in case when depencies newer. +# Updating timestamps prevent command to be executed every make call. + COMMAND touch "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" + "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" + DEPENDS ${depend_files} + "${CMAKE_CURRENT_BINARY_DIR}/Kbuild" + COMMENT "Building kernel module ${name}" + ) + + # Fill properties for the target. + set_property(TARGET ${name} PROPERTY KMODULE_TYPE "kmodule") + set_property(TARGET ${name} PROPERTY KMODULE_IMPORTED "FALSE") + set_property(TARGET ${name} PROPERTY KMODULE_MODULE_NAME "${module_name}") + + set_property(TARGET ${name} PROPERTY KMODULE_MODULE_LOCATION + "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" + ) + set_property(TARGET ${name} PROPERTY KMODULE_SYMVERS_LOCATION + "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" + ) + + # Internal properties + set_property(TARGET ${name} PROPERTY KMODULE_BINARY_DIR + "${CMAKE_CURRENT_BINARY_DIR}" + ) + set_property(TARGET ${name} PROPERTY KMODULE_OBJ_SOURCES ${obj_sources_rel}) + set_property(TARGET ${name} PROPERTY KMODULE_COMPILE_FLAGS ${ccflags}) + set_property(TARGET ${name} PROPERTY KMODULE_INCLUDE_DIRECTORIES ${include_dirs}) + + + # Add target to the list of modules for built. + set_property(GLOBAL APPEND PROPERTY KMODULE_TARGETS "${name}") + + # The rule to clean files + _kbuild_module_clean_files(${name} + C_SOURCE ${c_sources_noext_abs} + ASM_SOURCE ${asm_sources_noext_abs} + SHIPPED_SOURCE ${shipped_sources_noext_abs}) +endfunction(kbuild_add_module name) + +# kbuild_include_directories(dirs ...) +# +# Add include directories for Kbuild process. +macro(kbuild_include_directories) + set_property(DIRECTORY APPEND PROPERTY KBUILD_INCLUDE_DIRECTORIES ${ARGN}) +endmacro(kbuild_include_directories) + +# kbuild_add_definitions (flags) +# +# Specify additional flags for compile kernel module. +# +# Note that multiple flags should be specified as single string, +# delimited with ' '. +function(kbuild_add_definitions flags) + get_property(current_flags DIRECTORY PROPERTY KBUILD_COMPILE_DEFINITIONS) + _string_join(" " current_flags "${current_flags}" "${flags}") + set_property(DIRECTORY PROPERTY KBUILD_COMPILE_DEFINITIONS "${current_flags}") +endfunction(kbuild_add_definitions flags) + +# There is no control for kbuild make flags except default values. +# Support for kbuild_add_make_definitions may be added if needed. + + +# kbuild_link_module(<name> [<link> ...]) +# +# Link kernel module with other modules, that allows to use symbols from +# other modules. +# +# <link> may be: +# 1) target name for other kernel module intended for build +# 2) target name for imported kernel module with +# KMODULE_IMPORTED_SYMVERS_LOCATION property set +# 3) absolute path to symvers file of other kernel module. +# +# In any case, file-level dependency will be created for symvers file to link with. +# In the first case, also target-level dependency will be added +# +# Analogue for target_link_library(). +# +# May be used only from the same directory, where module target is created. +function(kbuild_link_module name) + # Check that @name corresponds to kernel module target for build. + get_property(is_module TARGET ${name} PROPERTY KMODULE_TYPE SET) + if(NOT is_module) + message(FATAL_ERROR "kbuild_module_link: passed <name>\n\t\"${name}\"\n which is not kernel module target.") + endif(NOT is_module) + get_property(module_imported TARGET ${name} PROPERTY KMODULE_IMPORTED) + if(kmodule_imported) + message(FATAL_ERROR "Imported kernel module target \"${name}\" may not be linked.") + endif(kmodule_imported) + + get_property(module_name TARGET ${name} PROPERTY KMODULE_MODULE_NAME) + + foreach(l ${ARGN}) + string(REGEX MATCH "/" link_is_file ${l}) + if(link_is_file) + string(REGEX MATCH "^/" file_is_absolute ${l}) + if(NOT file_is_absolute) + message(FATAL_ERROR "kbuild_module_link: passed filename\n\t\"${link}\"\nwhich is not absolute as <link>.") + endif(NOT file_is_absolute) + set(symvers_location "${l}") + # Do not require symvers file to be already existed. + else(link_is_file) + if(NOT TARGET ${l}) + message(FATAL_ERROR "kbuild_module_link: passed link\n\t\"${l}\"\n which is neither an absolute path to symvers file nor a target.") + endif(NOT TARGET ${l}) + get_property(kmodule_type TARGET ${l} PROPERTY KMODULE_TYPE) + if(NOT kmodule_type) + message(FATAL_ERROR "kbuild_module_link: passed target\n\t\"${l}\"\n which is not a target for kernel module as link.") + endif(NOT kmodule_type) + get_property(kmodule_imported TARGET ${l} PROPERTY KMODULE_IMPORTED) + if(kmodule_imported) + get_property(symvers_location TARGET ${l} PROPERTY KMODULE_IMPORTED_SYMVERS_LOCATION) + if(NOT symvers_location) + message(FATAL_ERROR "kbuild_module_link: passed imported target\n\t\"${l}\"\n without \"KMODULE_IMPORTED_SYMVERS_LOCATION\" property set as link.") + endif(NOT symvers_location) + else(kmodule_imported) + get_property(symvers_location TARGET ${l} PROPERTY KMODULE_SYMVERS_LOCATION) + # Target dependency is added only for non-imported target. + add_dependencies(${name} ${l}) + endif(kmodule_imported) + endif(link_is_file) + add_custom_command(OUTPUT + "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" + "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" + DEPENDS ${symvers_location} + APPEND + ) + set_property(TARGET ${name} APPEND PROPERTY KMODULE_DEPEND_SYMVERS ${symvers_location}) + endforeach(l ${ARGN}) +endfunction(kbuild_link_module name) + +# kbuild_finalize_linking() +# +# Should be called after all kernel modules and their links defined. +# Usually this is the end of main CMakeLists.txt file. +function(kbuild_finalize_linking) + _get_per_build_var(ccflags_per_build KBUILD_C_FLAGS) + + get_property(kmodule_targets GLOBAL PROPERTY KMODULE_TARGETS) + foreach(m ${kmodule_targets}) + get_property(module_binary_dir TARGET ${m} PROPERTY KMODULE_BINARY_DIR) + get_property(module_name TARGET ${m} PROPERTY KMODULE_MODULE_NAME) + get_property(module_symvers_cmake TARGET ${m} PROPERTY KMODULE_DEPEND_SYMVERS) + + get_property(obj_sources TARGET ${m} PROPERTY KMODULE_OBJ_SOURCES) + get_property(ccflags_local TARGET ${m} PROPERTY KMODULE_COMPILE_FLAGS) + get_property(include_dirs TARGET ${m} PROPERTY KMODULE_INCLUDE_DIRECTORIES) + + # Combine all compiler flags together + _string_join(" " ccflags "${KBUILD_C_FLAGS}" "${ccflags_local}") + foreach(dir ${include_dirs}) + _string_join(" " ccflags "${ccflags}" "-I${dir}") + endforeach(dir ${include_dirs}) + _string_join(" " ccflags "${ccflags}" "${ccflags_per_build}") + + string(REPLACE ";" " " module_symvers "${module_symvers_cmake}") + + if(obj_sources) + set(obj_src_string "${module_name}-y := ") + foreach(obj ${obj_sources}) + set(obj_src_string "${obj_src_string} ${obj}") + endforeach(obj ${obj_sources}) + else(obj_sources) + # Simple building process - module name is same as the name + # of the only source. + set(obj_src_string "") + endif(obj_sources) + # Configure kbuild file + configure_file(${kbuild_this_module_dir}/kbuild_system_files/Kbuild.in + ${module_binary_dir}/Kbuild + ) + endforeach(m ${kmodule_targets}) +endfunction(kbuild_finalize_linking) + +# kbuild_install(TARGETS <module_name> ... +# [[MODULE|SYMVERS] +# DESTINATION <dir> +# [CONFIGURATIONS [...]] +# [COMPONENT <component>] +# ]+) +# +# Install kernel module(s) and/or symvers file(s) into given directory. +# +# Almost all options means same as for install() cmake command. +# 'MODULE' refers to kernel module itself, SYMVERS refers symvers file. +# +# Unlike to standard install() command, there is no default destination +# directory neither for modules nor for symvers files. +# So, at least one rule should be defined, and 'DESTINATION' option +# should be set for every rule. +# +# TODO: support for 'EXPORT' mode. +function(kbuild_install type) + if(NOT type STREQUAL "TARGETS") + message(FATAL_ERROR "Only 'TARGETS' mode is currently supported") + endif(NOT type STREQUAL "TARGETS") + + parse_install_arguments(kbuild_install + "MODULE;SYMVERS" # Section types + "" "DESTINATION;COMPONENT" "CONFIGURATIONS" # Section keywords classification. + ${ARGN} + ) + + set(kbuild_install_TARGETS ${kbuild_install_GLOBAL_ARGUMENTS}) + if(NOT kbuild_install_TARGETS) + message(FATAL_ERROR "No targets given for kbuild_install() command") + endif(NOT kbuild_install_TARGETS) + + if(NOT kbuild_install_sections) + message(FATAL_ERROR "There is no default destination for install kernel module components, but no section described it is given.") + endif(NOT kbuild_install_sections) + + foreach(section_type ${kbuild_install_sections}) + if(NOT kbuild_install_${section_type}_DESTINATION) + message(FATAL_ERROR "DESTINATION is not defined for section ${section_type}") + endif(NOT kbuild_install_${section_type}_DESTINATION) + # All additional arguments for given section. + set(install_args_${section_type} + DESTINATION "${kbuild_install_${section_type}_DESTINATION}") + if(kbuild_install_${section_type}_CONFIGURATION) + list(APPEND install_args_${section_type} + CONFIGURATION "${kbuild_install_${section_type}_CONFIGURATION}" + ) + endif(kbuild_install_${section_type}_CONFIGURATION) + if(kbuild_install_${section_type}_COMPONENT) + list(APPEND install_args_${section_type} + COMPONENT "${kbuild_install_${section_type}_COMPONENT}" + ) + endif(kbuild_install_${section_type}_COMPONENT) + # Module installation. + if(section_type STREQUAL "MODULE" OR section_type STREQUAL "ALL") + # Combine locations for all modules in one list. + set(module_locations) + foreach(t ${kbuild_install_TARGETS}) + kbuild_get_module_location(module_location ${t}) + list(APPEND module_locations ${module_location}) + endforeach(t ${kbuild_install_TARGETS}) + # .. and install them at once. + install(FILES ${module_locations} ${install_args_${section_type}}) + endif(section_type STREQUAL "MODULE" OR section_type STREQUAL "ALL") + # Symvers installation. + if(section_type STREQUAL "SYMVERS" OR section_type STREQUAL "ALL") + # Because of renaming, symvers files should be installed separately. + foreach(t ${kbuild_install_TARGETS}) + kbuild_get_symvers_location(symvers_location ${t}) + get_property(module_name TARGET ${t} PROPERTY KMODULE_MODULE_NAME) + install(FILES ${symvers_location} + RENAME "${module_name}.symvers" + ${install_args_${section_type}} + ) + endforeach(t ${kbuild_install_TARGETS}) + endif(section_type STREQUAL "SYMVERS" OR section_type STREQUAL "ALL") + endforeach(section_type ${kbuild_install_sections}) +endfunction(kbuild_install type) + + +# kbuild_try_compile(RESULT_VAR bindir srcfile|SOURCES src ... +# [CMAKE_FLAGS <Flags>] +# [KBUILD_COMPILE_DEFINITIONS flags ...] +# [OUTPUT_VARIABLE var]) +# +# Similar to try_module in simplified form, but compile srcfile as +# kernel module, instead of user space program. +# +# KBUILD_COMPILE_DEFINITIONS contains compiler definition flags for +# build kernel module. +# +# Possible CMAKE_FLAGS which has special semantic: +# KBUILD_INCLUDE_DIRECTORIES - include directories for build kernel module +# KBUILD_LINK_MODULE - symvers file(s) for link module with other modules. +function(kbuild_try_compile RESULT_VAR bindir srcfile) + cmake_parse_arguments(kbuild_try_compile "" "OUTPUT_VARIABLE" "CMAKE_FLAGS;KBUILD_COMPILE_DEFINITIONS" ${ARGN}) + if(srcfile STREQUAL "SOURCES") + set(srcfiles ${kbuild_try_compile_UNPARSED_ARGUMENTS}) + else(srcfile STREQUAL "SOURCES") + set(srcfiles ${srcfile}) + endif(srcfile STREQUAL "SOURCES") + + # Inside try_compile project values of variables + # CMAKE_CURRENT_BINARY_DIR and CMAKE_CURRENT_SOURCE_DIR + # differs from ones in current project. + # + # So make all paths absolute before pass them into try_compile project. + # Note, that copiing files into binary dir is nevertheless performed + # in the try_compile project, because it bases on real current binary dir. + to_abs_path(srcfiles_abs ${srcfiles}) + + # Collect parameters to try_compile() function + set(cmake_flags + "-DSOURCES:STRING=${srcfiles_abs}" # Source file(s) + "-DCMAKE_MODULE_PATH:PATH=${CMAKE_MODULE_PATH}" # Path for search include files. + ${kbuild_try_compile_CMAKE_FLAGS} + ) + + # Parameters for compiler + if(kbuild_try_compile_KBUILD_COMPILE_DEFINITIONS) + list(APPEND cmake_flags + "-DKBUILD_COMPILE_DEFINITIONS:STRING=${kbuild_try_compile_KBUILD_COMPILE_DEFINITIONS}" + ) + endif(kbuild_try_compile_KBUILD_COMPILE_DEFINITIONS) + + # Other user-defined cmake flags + if(kbuild_try_compile_CMAKE_FLAGS) + + endif(kbuild_try_compile_CMAKE_FLAGS) + + # Possible definition of output variable. + if(kbuild_try_compile_OUTPUT_VARIABLE) + set(output_variable_def "OUTPUT_VARIABLE" "output_tmp") + else(build_try_compile_OUTPUT_VARIABLE) + set(output_variable_def) + endif(kbuild_try_compile_OUTPUT_VARIABLE) + + + try_compile(result_tmp # Result variable(temporary) + "${bindir}" # Binary directory + "${kbuild_aux_dir}/try_compile_project" # Source directory + "kmodule" # Project name + CMAKE_FLAGS # Flags to CMake: + ${cmake_flags} + ${kbuild_try_compile_flags} + ${output_variable_def} + ) + + if(kbuild_try_compile_OUTPUT_VARIABLE) + # Set output variable for the caller + set("${kbuild_try_compile_OUTPUT_VARIABLE}" "${output_tmp}" PARENT_SCOPE) + endif(kbuild_try_compile_OUTPUT_VARIABLE) + # Set result variable for the caller + set("${RESULT_VAR}" "${result_tmp}" PARENT_SCOPE) +endfunction(kbuild_try_compile RESULT_VAR bindir srcfile) + +########### Auxiliary functions for internal use ####################### +# Per-directory tracking for kbuild compiler flags. +# +# Unlike to standard COMPILE_FLAGS, these flags do not include values +# set for parent directories. +# (There is no generic "fill-with-parent's values" mechanism exists +# in cmake). +# +# So, this property has a little sence for the user. +# It exists only for make effect of kbuild_add_definitions() to +# cross "function" scope. +define_property(DIRECTORY PROPERTY KBUILD_COMPILE_FLAGS + BRIEF_DOCS "Compiler flags used by Kbuild system added in this directory." + FULL_DOCS "Compiler flags used by Kbuild system added in this directory." +) + +# Per-directory tracking for kbuild include directories. +# +# Unlike to standard INCLUDE_DIRECTORIES, these ones do not include values +# set for parent directories. +# (There is no generic "fill-with-parent's values" mechanism exists +# in cmake). +# +# So, this property has a little sence for the user. +# It exists only for make effect of kbuild_include_directories() to +# cross "function" scope. +define_property(DIRECTORY PROPERTY KBUILD_INCLUDE_DIRECTORIES + BRIEF_DOCS "Include directories used by Kbuild system; added in this directory." + FULL_DOCS "Include directories used by Kbuild system; added in this directory." +) + + +# Parameters below are set externally only in try_compile() for subproject, +# which include this file. +# No need to cache them as try_compile() project is not configured by the user. + +# Real top-level source directory. +if(NOT KBUILD_REAL_SOURCE_DIR) + set(KBUILD_REAL_SOURCE_DIR ${CMAKE_SOURCE_DIR}) +endif(NOT KBUILD_REAL_SOURCE_DIR) +# Real top-level binary directory. +if(NOT KBUILD_REAL_BINARY_DIR) + set(KBUILD_REAL_BINARY_DIR ${CMAKE_BINARY_DIR}) +endif(NOT KBUILD_REAL_BINARY_DIR) + +# These flags are passed to the 'make' when compile kernel module. +set(kbuild_additional_make_flags) +# These CMake flags will be passed to try_compile() subproject. +set(kbuild_try_compile_flags + "-DKBUILD_REAL_SOURCE_DIR=${KBUILD_REAL_SOURCE_DIR}" + "-DKBUILD_REAL_BINARY_DIR=${KBUILD_REAL_BINARY_DIR}" +) + +# ARCH and CROSS_COMPILE are passed to submake only when non-empty. +if(ARCH) + list(APPEND kbuild_additional_make_flags "ARCH=${ARCH}") + list(APPEND kbuild_try_compile_flags "-DARCH=${ARCH}") +endif(ARCH) +if(CROSS_COMPILE) + list(APPEND kbuild_additional_make_flags "CROSS_COMPILE=${CROSS_COMPILE}") + list(APPEND kbuild_try_compile_flags "-DCROSS_COMPILE=${CROSS_COMPILE}") +endif(CROSS_COMPILE) + +# List of targets created with kmodule_add_module() without +# 'IMPORTED' option. +# +# This list is traversed in kmodule_finalize_linking() for +# create 'Kbuild' files. +# +# Note, that this list does not contain all defined kernel modules, +# so property normally shouldn't be used by outer code. +define_property(GLOBAL PROPERTY KMODULE_TARGETS + BRIEF_DOCS "List of kernel module targets configured for build" + FULL_DOCS "List of kernel module targets configured for build" +) + +# CMAKE_CURRENT_BINARY_DIR at the moment, when kbuild_add_module() is issued. +define_property(TARGET PROPERTY KMODULE_BINARY_DIR + BRIEF_DOCS "CMAKE_CURRENT_BINARY_DIR where module is built." + FULL_DOCS "CMAKE_CURRENT_BINARY_DIR where module is built." +) + +# List of object files, used for build kernel module. +# +# List may be empty in case of simple build, when target module has same +# name as its only source. +# +# This is internal property for configure 'Kbuild' file. +define_property(TARGET PROPERTY KMODULE_OBJ_SOURCES + BRIEF_DOCS "Object source files for build kernel module." + FULL_DOCS "Object source files for build kernel module." +) + +# Compiler flags, added with kbuild_add_definitions() +# +# Note, that KBUILD_C_FLAGS* are not included here. +# +# This is internal property for configure 'Kbuild' file. +define_property(TARGET PROPERTY KMODULE_COMPILE_FLAGS + BRIEF_DOCS "Additional compile flags for build kernel module." + FULL_DOCS "Additional compile flags for build kernel module." +) + +# Include directories, added with kbuild_include_directories(). +# +# This is internal property for configure 'Kbuild' file. +define_property(TARGET PROPERTY KMODULE_COMPILE_FLAGS + BRIEF_DOCS "Additional compile flags for build kernel module." + FULL_DOCS "Additional compile flags for build kernel module." +) + + +# List of symvers files, added by kbuild_link_module(). +# +# This is internal property for configure 'Kbuild' file. +define_property(TARGET PROPERTY KMODULE_DEPEND_SYMVERS + BRIEF_DOCS "Symvers files this module depends on." + FULL_DOCS "Symvers files this module depends on." +) + +# Constants for internal filenames. +set(_kbuild_symvers "Module.symvers") + +# copy_source_to_binary_dir(<source> <new_source_var>) +# +# Helper for the building kernel module. +# +# Make sure that given source file is inside current binary dir. +# That place is writable and has some "uniqeness" garantee for generate +# auxiliary files during build process. +# +# If <source> already inside current binary dir, do nothing and +# set <new_source_var> variable to <source> itself. +# +# Otherwise create rule for copy source into "nice" place inside +# current binary dir and set <new_source_var> pointed to that place. +function(copy_source_to_binary_dir source new_source_var) + is_path_inside_dir(is_in_current_binary ${CMAKE_CURRENT_BINARY_DIR} "${source}") + if(is_in_current_binary) + # Source is already placed where we want. + set(${new_source_var} "${source}" PARENT_SCOPE) + else(is_in_current_binary) + # Base directory from which count relative source path. + # By default, it is root directory. + set(base_dir "/") + # Try "nicer" base directories. + foreach(d + ${KBUILD_REAL_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${KBUILD_REAL_SOURCE_DIR} + ) + is_path_inside_dir(is_in_d ${d} "${source}") + if(is_in_d) + set(base_dir ${d}) + break() + endif(is_in_d) + endforeach(d) + # Copy source into same relativ dir, but inside current binary one. + file(RELATIVE_PATH source_rel "${base_dir}" "${source}") + set(new_source "${CMAKE_CURRENT_BINARY_DIR}/${source_rel}") + get_filename_component(new_source_dir ${new_source} PATH) + file(MAKE_DIRECTORY "${new_source_dir}") + rule_copy_file("${new_source}" "${source}") + # Return path to the new source. + set(${new_source_var} "${new_source}" PARENT_SCOPE) + endif(is_in_current_binary) +endfunction(copy_source_to_binary_dir source new_source_var) + +# _get_per_build_var(RESULT_VAR variable) +# +# Return value of per-build variable. +macro(_get_per_build_var RESULT_VAR variable) + if(CMAKE_BUILD_TYPE) + string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type_uppercase) + set(${RESULT_VAR} "${${variable}_${_build_type_uppercase}}") + else(CMAKE_BUILD_TYPE) + set(${RESULT_VAR}) + endif(CMAKE_BUILD_TYPE) +endmacro(_get_per_build_var RESULT_VAR variable) + +# _string_join(sep RESULT_VAR str1 str2) +# +# Join strings <str1> and <str2> using <sep> as glue. +# +# Note, that precisely 2 string are joined, not a list of strings. +# This prevents automatic replacing of ';' inside strings while parsing arguments. +macro(_string_join sep RESULT_VAR str1 str2) + if("${str1}" STREQUAL "") + set("${RESULT_VAR}" "${str2}") + elseif("${str2}" STREQUAL "") + set("${RESULT_VAR}" "${str1}") + else("${str1}" STREQUAL "") + set("${RESULT_VAR}" "${str1}${sep}${str2}") + endif("${str1}" STREQUAL "") +endmacro(_string_join sep RESULT_VAR str1 str2) +# _build_get_directory_property_chained(RESULT_VAR <propert_name> [<separator>]) +# +# Return list of all values for given property in the current directory +# and all parent directories. +# +# If <separator> is given, it is used as glue for join values. +# By default, cmake list separator (';') is used. +function(_get_directory_property_chained RESULT_VAR property_name) + set(sep ";") + foreach(arg ${ARGN}) + set(sep "${arg}") + endforeach(arg ${ARGN}) + set(result "") + set(d "${CMAKE_CURRENT_SOURCE_DIR}") + while(NOT "${d}" STREQUAL "") + get_property(p DIRECTORY "${d}" PROPERTY "${property_name}") + # debug + # message("Property ${property_name} for directory ${d}: '${p}'") + _string_join("${sep}" result "${p}" "${result}") + # message("Intermediate result: '${result}'") + get_property(d DIRECTORY "${d}" PROPERTY PARENT_DIRECTORY) + endwhile(NOT "${d}" STREQUAL "") + set("${RESULT_VAR}" "${result}" PARENT_SCOPE) +endfunction(_get_directory_property_chained RESULT_VAR property_name) + +# _kbuild_module_clean_files(module_name +# [C_SOURCE c_source_noext_abs ...] +# [ASM_SOURCE asm_source_noext_abs ...] +# [SHIPPED_SOURCE shipped_source_noext_abs ...]) +# +# Tell CMake that intermediate files, created by kbuild system, +# should be cleaned with 'make clean'. +function(_kbuild_module_clean_files module_name) + cmake_parse_arguments(kbuild_module_clean "" "" "C_SOURCE;ASM_SOURCE;SHIPPED_SOURCE" ${ARGN}) + if(kbuild_module_clean_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unparsed arguments") + endif(kbuild_module_clean_UNPARSED_ARGUMENTS) + + # List common files (names only) for cleaning + set(common_files_names + ".tmp_versions" # Directory + "modules.order" + "Module.markers" + ) + # List module name-depending files (extensions only) for cleaning + set(name_files_ext + ".o" + ".mod.c" + ".mod.o" + ) + # Same but for the files with names starting with a dot ('.'). + set(name_files_dot_ext + ".ko.cmd" + ".mod.o.cmd" + ".o.cmd" + ) + # List source name-depending files (extensions only) for cleaning + set(source_name_files_ext + ".o" + ) + # Same but for the files with names starting with a dot ('.') + set(source_name_files_dot_ext + ".o.cmd" + ".o.d" # This file is created in case of unsuccessfull build + ) + + # Now collect all sort of files into list + set(files_list) + + foreach(name ${common_files_names}) + list(APPEND files_list "${CMAKE_CURRENT_BINARY_DIR}/${name}") + endforeach(name ${common_files_names}) + + foreach(ext ${name_files_ext}) + list(APPEND files_list + "${CMAKE_CURRENT_BINARY_DIR}/${module_name}${ext}") + endforeach(ext ${name_files_ext}) + + foreach(ext ${name_files_dot_ext}) + list(APPEND files_list + "${CMAKE_CURRENT_BINARY_DIR}/.${module_name}${ext}") + endforeach(ext ${name_files_ext}) + + # All the types of sources are processed in a similar way + foreach(obj_source_noext_abs ${kbuild_module_clean_C_SOURCE} + ${kbuild_module_clean_ASM_SOURCE} ${kbuild_module_clean_SHIPPED_SOURCE}) + + get_filename_component(dir ${obj_source_noext_abs} PATH) + get_filename_component(name ${obj_source_noext_abs} NAME) + foreach(ext ${source_name_files_ext}) + list(APPEND files_list "${dir}/${name}${ext}") + endforeach(ext ${source_name_files_ext}) + foreach(ext ${source_name_files_dot_ext}) + list(APPEND files_list "${dir}/.${name}${ext}") + endforeach(ext ${source_name_files_ext}) + endforeach(obj_source_noext_abs) + # Tell CMake that given files should be cleaned. + set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${files_list}") +endfunction(_kbuild_module_clean_files module_name) + +# parse_install_arguments(prefix <section-type-keywords> <options> <one-value-keywords> <multiple-value-keywords> args..) +# +# Helper for parse arguments for install-like command. +# +# All arguments before the first keyword are classified as GLOBAL_ARGUMENTS +# and stored into list ${prefix}_GLOBAL_ARGUMENTS. +# +# <section-type-keywords> describe possible keywords denoting section type. +# At most one section may exist for every type. +# Special type ALL means generic section. +# +# <options>, <one-value-keywords> and <multiple-value-keywords> describe +# all keywords inside section. +# Values corresponded to these keywords are stored under +# <prefix>_<section-type>_*. +# Note, that unlike to cmake_parse_arguments(), all arguments inside +# section definition should be either keyword or its value(s). +# Additionally, <prefix>_<section-type> is set to TRUE for every +# encountered section and <prefix>_sections contains list of such sections. +# +# If non section is currently active, the first section keyword starts +# special generic section. Definitions for this section are stored as +# for section of type ALL. +# If such section exists, it should be the only section. +# +# Function is generic, but currently is used only there. +function(parse_install_arguments prefix section_types options one_value_keywords multiple_value_keywords) + set(all_keywords ${section_types} ${options} ${one_value_keywords} ${multiple_value_keywords}) + # Type of the currently parsed section('ALL' for ALL section). + set(current_section_type) + # Active section-related keyword for current section. + set(current_section_keyword) + # Classification for @_current_section_keyword: + # 'OPTION', 'ONE' or 'MULTY'. + set(current_section_keyword_type) + + # Clean all previous keyword values. + set("pia_GLOBAL_ARGUMENTS") + foreach(section_type "ALL" ${section_types}) + set(pia_${section_type} "FALSE") + foreach(opt ${options}) + set("pia_${section_type}_${opt}" "FALSE") + endforeach(opt ${options}) + foreach(keyword ${one_value_keywords} ${multiple_value_keywords}) + set("pia_${section_type}_${keyword}") + endforeach(keyword ${one_value_keywords} ${multiple_value_keywords}) + endforeach(section_type "ALL" ${section_types}) + set("pia_sections") + + foreach(arg ${ARGN}) + list(FIND all_keywords ${arg} keyword_index) + if(keyword_index EQUAL "-1") + if(current_section_type) + if(NOT current_section_keyword) + message(FATAL_ERROR "In section ${current_section_type} argument ${arg} does not belong to any keyword.") + endif(NOT current_section_keyword) + if(current_section_keyword_type STREQUAL "ONE") + set("pia_${current_section_type}_${current_section_keyword}" "${arg}") + set(current_section_keyword "") + else(current_section_keyword_type STREQUAL "ONE") + list(APPEND "pia_${current_section_type}_${current_section_keyword}" "${arg}") + endif(current_section_keyword_type STREQUAL "ONE") + else(current_section_type) + list(APPEND "pia_GLOBAL_ARGUMENTS" "${arg}") + endif(current_section_type) + else(keyword_index EQUAL "-1") + if(current_section_type AND current_section_keyword AND current_section_keyword_type STREQUAL "ONE") + message(FATAL_ERROR "Keyword ${arg} found while value for one-value-option ${current_section_keyword} expected.") + endif(current_section_type AND current_section_keyword AND current_section_keyword_type STREQUAL "ONE") + list(FIND section_types "${arg}" section_type_index) + if(section_type_index EQUAL "-1") + if(NOT current_section_type) + set(current_section_type "ALL") + set("pia_${current_section_type}" "TRUE") + list(APPEND "pia_sections" "${current_section_type}") + endif(NOT current_section_type) + list(FIND options ${arg} option_index) + if(option_index EQUAL "-1") + set(current_section_keyword ${arg}) + list(FIND one_value_keywords ${current_section_keyword} one_index) + if(one_index EQUAL "-1") + set(current_section_keyword_type "MULTY") + else(one_index EQUAL "-1") + set(current_section_keyword_type "ONE") + endif(one_index EQUAL "-1") + set("pia_${current_section_type}_${current_section_keyword}") + else(option_index EQUAL "-1") + set("${prefix}_${current_section_type}_${current_section_keyword}" "TRUE") + set(current_section_keyword_type) + endif(option_index EQUAL "-1") + else(section_type_index EQUAL "-1") + if("pia_ALL") + message(FATAL_ERROR "Generic section should be the only section defined") + endif("pia_ALL") + set(current_section_type "${arg}") + if("pia_${current_section_type}") + message(FATAL_ERROR "Section ${current_section_type} is defined twice.") + endif("pia_${current_section_type}") + set("pia_${current_section_type}" "TRUE") + list(APPEND "pia_sections" "${current_section_type}") + # Current keyword is initially undefined for such section. + set(current_section_keyword) + endif(section_type_index EQUAL "-1") + endif(keyword_index EQUAL "-1") + endforeach(arg ${ARGN}) + + # propagate the result variables to the caller + set("${prefix}_GLOBAL_ARGUMENTS" ${pia_GLOBAL_ARGUMENTS} PARENT_SCOPE) + foreach(section_type "ALL" ${section_types}) + set(${prefix}_${section_type} ${pia_${section_type}} PARENT_SCOPE) + foreach(keyword ${options} ${one_value_keywords} ${multiple_value_keywords}) + set("${prefix}_${section_type}_${keyword}" ${pia_${section_type}_${keyword}} PARENT_SCOPE) + endforeach(keyword ${options} ${one_value_keywords} ${multiple_value_keywords}) + endforeach(section_type "ALL" ${section_types}) + set("${prefix}_sections" ${pia_sections} PARENT_SCOPE) +endfunction(parse_install_arguments prefix section_types options one_value_keywords multiple_value_keywords) diff --git a/cmake_targets/tools/MODULES/kmodule.cmake b/cmake_targets/tools/MODULES/kmodule.cmake new file mode 100644 index 0000000000000000000000000000000000000000..2912ac115a76015096586a84070a7c48cacd15a7 --- /dev/null +++ b/cmake_targets/tools/MODULES/kmodule.cmake @@ -0,0 +1,539 @@ +set(kmodule_this_module_dir "${CMAKE_SOURCE_DIR}/cmake/modules/") +set(kmodule_test_sources_dir "${CMAKE_SOURCE_DIR}/cmake/kmodule_sources") + +set(kmodule_function_map_file "") +if (CMAKE_CROSSCOMPILING) + if (KEDR_SYSTEM_MAP_FILE) + set (kmodule_function_map_file "${KEDR_SYSTEM_MAP_FILE}") + else (KEDR_SYSTEM_MAP_FILE) +# KEDR_SYSTEM_MAP_FILE is not specified, construct the default path +# to the symbol map file. + set (kmodule_function_map_file + "${KEDR_ROOT_DIR}/boot/System.map-${KBUILD_VERSION_STRING}" + ) + endif (KEDR_SYSTEM_MAP_FILE) +endif (CMAKE_CROSSCOMPILING) + +# List of unreliable functions, that is, the functions that may be +# be exported and mentioned in System.map but still cannot be used +# because no header provides their declarations. +set(unreliable_functions_list + "__kmalloc_node" + "kmem_cache_alloc_node" + "kmem_cache_alloc_node_notrace" + "kmem_cache_alloc_node_trace" +) + +# kmodule_is_function_exist(function_name RESULT_VAR) +# Verify, whether given function exist in the kernel space on the current system. +# RESULT_VAR is TRUE, if function_name exist in the kernel space, FALSE otherwise. +# RESULT_VAR is cached. + +function(kmodule_is_function_exist function_name RESULT_VAR) + check_begin("Looking for ${function_name} in the kernel") + if(NOT DEFINED ${RESULT_VAR}) + check_try() + execute_process( + COMMAND sh "${kmodule_this_module_dir}/kmodule_files/scripts/lookup_kernel_function.sh" + ${function_name} ${kmodule_function_map_file} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE kmodule_is_function_exist_result + OUTPUT_QUIET) + + if (kmodule_is_function_exist_result EQUAL 0) + list(FIND unreliable_functions_list ${function_name} unreliable_function_index) + if(unreliable_function_index GREATER -1) + # Additional verification for unreliable function + kbuild_try_compile(kmodule_function_is_exist_reliable + "${CMAKE_BINARY_DIR}/check_unreliable_functions/${function_name}" + "${kmodule_test_sources_dir}/check_unreliable_functions/${function_name}.c" + ) + if(NOT kmodule_function_is_exist_reliable) + set(kmodule_is_function_exist_result 1) + endif(NOT kmodule_function_is_exist_reliable) + endif(unreliable_function_index GREATER -1) + endif(kmodule_is_function_exist_result EQUAL 0) + + if (kmodule_is_function_exist_result EQUAL 0) + set(${RESULT_VAR} "TRUE" CACHE INTERNAL "Does ${function_name} exist in the kernel?") + elseif(kmodule_is_function_exist_result EQUAL 1) + set(${RESULT_VAR} "FALSE" CACHE INTERNAL "Does ${function_name} exist in the kernel?") + else(kmodule_is_function_exist_result EQUAL 0) + message(FATAL_ERROR +"Cannot determine whether function '${function_name}' exists in the kernel" + ) + endif(kmodule_is_function_exist_result EQUAL 0) + endif(NOT DEFINED ${RESULT_VAR}) + set_bool_string(check_result "found" "not found" ${${RESULT_VAR}}) + check_end(${check_result}) +endfunction(kmodule_is_function_exist function_name RESULT_VAR) + +# Creates the list of functions that actually exist on the +# current system. +# +# kmodule_configure_kernel_functions(output_list +# {[REQUIRED | OPTIONAL] {func | ONE_OF_LIST}} ...) +# +# ONE_OF_LIST := ONE_OF_BEGIN {func ...} ONE_OF_END +# +# There are 2 modes of function lookup: +# OPTIONAL - if the function doesn't exist, it is silently ignored. +# REQUIRED - if the function doesn't exist, FATAL_ERROR message is printed. +# +# Initial mode is REQUIRED, and it can be changed at any time by REQUIRED +# and OPTIONAL keywords. +# +# ONE_OF_BEGIN/ONE_OF_END determine a section for which no more than one +# function among all listed there should exist. FATAL_ERROR message is +# printed otherwise. When mode is REQUIRED, precisely one function must +# exist. +# Inside this section other keywords must not be used (even another +# ONE_OF_BEGIN). + +function(kmodule_configure_kernel_functions output_list) + set(kmodule_configure_kernel_functions_mode "REQUIRED") + set(kmodule_configure_kernel_functions_one_of_section "FALSE") + set(output_list_tmp) + set(${output_list}) + foreach(arg ${ARGN}) + if(arg STREQUAL "REQUIRED" OR arg STREQUAL "OPTIONAL") + if(kmodule_configure_kernel_functions_one_of_section) + message(FATAL_ERROR +"Inside ONE_OF_BEGIN/ONE_OF_END section, other keywords are not allowed." + ) + endif(kmodule_configure_kernel_functions_one_of_section) + set(kmodule_configure_kernel_functions_mode ${arg}) + elseif(arg STREQUAL "ONE_OF_BEGIN") + if(kmodule_configure_kernel_functions_one_of_section) + message(FATAL_ERROR "Nested ONE_OF_BEGIN/ONE_OF_END sections are not allowed.") + endif(kmodule_configure_kernel_functions_one_of_section) + set(kmodule_configure_kernel_functions_one_of_section "TRUE") + set(kmodule_configure_kernel_functions_one_of_section_function) + elseif(arg STREQUAL "ONE_OF_END") + if(NOT kmodule_configure_kernel_functions_one_of_section) + message(FATAL_ERROR "ONE_OF_END without ONE_OF_BEGIN is not allowed.") + endif(NOT kmodule_configure_kernel_functions_one_of_section) + if(kmodule_configure_kernel_functions_one_of_section_function) + list(APPEND output_list_tmp ${kmodule_configure_kernel_functions_one_of_section_function}) + else(kmodule_configure_kernel_functions_one_of_section_function) + if(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED") + message(FATAL_ERROR +"None of the functions listed in ONE_OF section exist in the kernel but it is required." + ) + endif(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED") + endif(kmodule_configure_kernel_functions_one_of_section_function) + set(kmodule_configure_kernel_functions_one_of_section "FALSE") + else(arg STREQUAL "REQUIRED" OR arg STREQUAL "OPTIONAL") + set(kmodule_func_varname _KMODULE_IS_${arg}_EXIST) + kedr_find_function(${arg} ${kmodule_func_varname}) + if(kmodule_configure_kernel_functions_one_of_section) + if(${kmodule_func_varname}) + if(kmodule_configure_kernel_functions_one_of_section_function) + message(FATAL_ERROR "Two functions from ONE_OF sections exist in the kernel.") + else(kmodule_configure_kernel_functions_one_of_section_function) + set(kmodule_configure_kernel_functions_one_of_section_function ${arg}) + endif(kmodule_configure_kernel_functions_one_of_section_function) + endif(${kmodule_func_varname}) + else(kmodule_configure_kernel_functions_one_of_section) + if(${kmodule_func_varname}) + list(APPEND output_list_tmp ${arg}) + else(${kmodule_func_varname}) + if(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED") + message(FATAL_ERROR "Function ${arg} is not found in the kernel but it is required.") + endif(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED") + endif(${kmodule_func_varname}) + endif(kmodule_configure_kernel_functions_one_of_section) + endif(arg STREQUAL "REQUIRED" OR arg STREQUAL "OPTIONAL") + endforeach(arg ${ARGN}) + if(kmodule_configure_kernel_functions_one_of_section) + message(FATAL_ERROR "Found ONE_OF_BEGIN without ONE_OF_END") + endif(kmodule_configure_kernel_functions_one_of_section) + set(${output_list} ${output_list_tmp} PARENT_SCOPE) +endfunction(kmodule_configure_kernel_functions output_list) + +############################################################################ +# Utility macros to check for particular features. If the particular feature +# is supported, the macros will set the corresponding variable to TRUE, +# otherwise - to FALSE (the name of variable is mentioned in the comments +# for the macro). +############################################################################ + +# Check if the system has everything necessary to build at least simple +# kernel modules. +# The macro sets variable 'MODULE_BUILD_SUPPORTED'. +macro(check_module_build) + check_begin("Checking if kernel modules can be built on this system") + if (NOT MODULE_BUILD_SUPPORTED) + check_try() + kbuild_try_compile(module_build_supported_impl + "${CMAKE_BINARY_DIR}/check_module_build" + "${kmodule_test_sources_dir}/check_module_build/module.c" + ) + set_bool_string(MODULE_BUILD_SUPPORTED "yes" "no" ${module_build_supported_impl} + CACHE INTERNAL "Can kernel modules be built on this system?" + ) + endif (NOT MODULE_BUILD_SUPPORTED) + + check_end("${MODULE_BUILD_SUPPORTED}") + + if (NOT MODULE_BUILD_SUPPORTED) + message(FATAL_ERROR +"There are problems with building kernel modules on this system. " +"Please check that the appropriate kernel headers and build tools " +"are installed." + ) + endif (NOT MODULE_BUILD_SUPPORTED) +endmacro(check_module_build) + +# Check if reliable stack trace information can be obtained. +# This is the case, for example, if the kernel is compiled with support +# for frame pointers and/or stack unwind on. +# The macro sets variable 'STACK_TRACE_RELIABLE'. +macro(check_stack_trace) + check_begin("Checking if stack trace information is reliable") + if (NOT DEFINED STACK_TRACE_RELIABLE) + check_try() + kbuild_try_compile(stack_trace_reliable_impl + "${CMAKE_BINARY_DIR}/check_stack_trace" + "${kmodule_test_sources_dir}/check_stack_trace/module.c" + ) + set_bool_string(STACK_TRACE_RELIABLE "yes" "no" ${stack_trace_reliable_impl} + CACHE INTERNAL "Are stack traces reliable on this system?") + endif (NOT DEFINED STACK_TRACE_RELIABLE) + check_end("${STACK_TRACE_RELIABLE}") + + if (NOT STACK_TRACE_RELIABLE) + message ("\n[WARNING]\n" + "It looks like reliable stack traces cannot be obtained on this system.\n" + "The output of KEDR-based tools like LeakCheck will be less detailed\n" + "(each stack trace shown will contain only one frame).\n" + "If this is not acceptable, you could rebuild the kernel with\n" + "CONFIG_FRAME_POINTER or CONFIG_STACK_UNWIND (if available) set to \"y\"\n" + "and then reconfigure and rebuild KEDR.\n") + endif (NOT STACK_TRACE_RELIABLE) +endmacro(check_stack_trace) + +# Check whether ring buffer is implemented by the kernel. +# Set cache variable RING_BUFFER_IMPLEMENTED according to this checking. +function(check_ring_buffer) + check_begin("Checking if ring buffer is implemented in the kernel") + + if (NOT DEFINED RING_BUFFER_IMPLEMENTED) + check_try() + kbuild_try_compile(ring_buffer_implemented_impl + "${CMAKE_BINARY_DIR}/check_ring_buffer" + "${kmodule_test_sources_dir}/check_ring_buffer/module.c" + ) + + set_bool_string(RING_BUFFER_IMPLEMENTED "yes" "no" "${ring_buffer_implemented_impl}" + CACHE INTERNAL "Whether ring buffer is implemented in the kernel" + ) + endif (NOT DEFINED RING_BUFFER_IMPLEMENTED) + check_end(${RING_BUFFER_IMPLEMENTED}) + + if (NOT RING_BUFFER_IMPLEMENTED) + message("\n[WARNING]\nRing buffer is not supported by the system.\n" + "The tracing facilities as well as call monitoring plugins will not be built.\n" + "If this is not acceptable, you could rebuild the kernel with\n" + "CONFIG_RING_BUFFER set to \"y\" and then reconfigure and rebuild KEDR.\n") + endif (NOT RING_BUFFER_IMPLEMENTED) +endfunction(check_ring_buffer) + +# Check which memory allocator is used by the kernel. +# Set KERNEL_MEMORY_ALLOCATOR to 'slab', 'slub', 'slob' or 'other'. +# +# Some functions in that allocators may have same names, but different signatures. +function(check_allocator) + check_begin("Checking which memory allocator is used by the kernel") + if(NOT DEFINED KERNEL_MEMORY_ALLOCATOR) + check_try() + # Use local variable for detect allocator, + # Cache one will be set at the end + set(allocator "") + if(allocator STREQUAL "") + kbuild_try_compile(is_allocator_slab + "${CMAKE_BINARY_DIR}/check_allocator_slab" + "${kmodule_test_sources_dir}/check_allocator/module.c" + KBUILD_COMPILE_DEFINITIONS "-DIS_ALLOCATOR_SLAB" + ) + if (is_allocator_slab) + set(allocator "slab") + endif (is_allocator_slab) + endif(allocator STREQUAL "") + + if(allocator STREQUAL "") + kbuild_try_compile(is_allocator_slub + "${CMAKE_BINARY_DIR}/check_allocator_slub" + "${kmodule_test_sources_dir}/check_allocator/module.c" + KBUILD_COMPILE_DEFINITIONS "-DIS_ALLOCATOR_SLUB" + ) + if (is_allocator_slub) + set(allocator "slub") + endif (is_allocator_slub) + endif(allocator STREQUAL "") + + if(allocator STREQUAL "") + kbuild_try_compile(is_allocator_slob + "${CMAKE_BINARY_DIR}/check_allocator_slob" + "${kmodule_test_sources_dir}/check_allocator/module.c" + KBUILD_COMPILE_DEFINITIONS "-DIS_ALLOCATOR_SLOB" + ) + if (is_allocator_slob) + set(allocator "slob") + endif (is_allocator_slub) + endif(allocator STREQUAL "") + + if(allocator STREQUAL "") + set(allocator "other") + endif(allocator STREQUAL "") + + set(KERNEL_MEMORY_ALLOCATOR "${allocator}" CACHE INTERNAL + "Memory allocator which is used by the kernel" + ) + endif (NOT DEFINED KERNEL_MEMORY_ALLOCATOR) + check_end("${KERNEL_MEMORY_ALLOCATOR}") +endfunction(check_allocator) + +# Check if 'kfree_rcu' is available in the kernel (it is likely to be +# a macro or an inline). If it is available, we should handle it as +# 'free' in LeakCheck. As KEDR cannot normally intercept kfree_rcu() +# itself, it needs to intercept call_rcu/call_rcu_sched and check their +# arguments. +# The macro sets variable 'HAVE_KFREE_RCU'. +macro(check_kfree_rcu) + check_begin("Checking if kfree_rcu() is available") + + if (NOT DEFINED HAVE_KFREE_RCU) + check_try() + kbuild_try_compile(have_kfree_rcu_impl + "${CMAKE_BINARY_DIR}/check_kfree_rcu" + "${kmodule_test_sources_dir}/check_kfree_rcu/module.c" + ) + + set_bool_string(HAVE_KFREE_RCU "yes" "no" ${have_kfree_rcu_impl} + CACHE INTERNAL "Is kfree_rcu() available?" + ) + endif () + check_end("${HAVE_KFREE_RCU}") +endmacro(check_kfree_rcu) +############################################################################ + +# Check if posix_acl_from_xattr() accepts struct user_namespace as the +# first argument. +# The macro sets variable 'POSIX_ACL_XATTR_HAS_USER_NS'. +macro(check_xattr_user_ns) + check_begin("Checking if posix_acl_from_xattr() has struct user_namespace * argument") + if (NOT DEFINED POSIX_ACL_XATTR_HAS_USER_NS) + check_try() + kbuild_try_compile(have_xattr_user_ns_impl + "${CMAKE_BINARY_DIR}/check_xattr_user_ns" + "${kmodule_test_sources_dir}/check_xattr_user_ns/module.c" + ) + + set_bool_string(POSIX_ACL_XATTR_HAS_USER_NS "yes" "no" ${have_xattr_user_ns_impl} + CACHE INTERNAL "Does posix_acl_from_xattr() have struct user_namespace argument?" + ) + endif () + check_end("${POSIX_ACL_XATTR_HAS_USER_NS}") +endmacro(check_xattr_user_ns) +############################################################################ + +# Check if hlist_for_each_entry*() macros accept only 'type *pos' argument +# rather than both 'type *tpos' and 'hlist_node *pos' as the loop cursors. +# The macro sets variable 'HLIST_FOR_EACH_ENTRY_POS_ONLY'. +macro(check_hlist_for_each_entry) + check_begin("Checking the signatures of hlist_for_each_entry*() macros") + if (NOT DEFINED HLIST_FOR_EACH_ENTRY_POS_ONLY) + check_try() + kbuild_try_compile(pos_only_impl + "${CMAKE_BINARY_DIR}/check_hlist_for_each_entry" + "${kmodule_test_sources_dir}/check_hlist_for_each_entry/module.c" + ) + set_bool_string(HLIST_FOR_EACH_ENTRY_POS_ONLY "yes" "no" ${pos_only_impl} + CACHE INTERNAL + "Do hlist_for_each_entry*() macros have only 'type *pos' to use as a loop cursor?" + ) + endif () + set_bool_string(check_result "do not use additional loop cursor" "use additional loop cursor" + ${HLIST_FOR_EACH_ENTRY_POS_ONLY}) + check_end(${check_result}) +endmacro(check_hlist_for_each_entry) +############################################################################ + +# Check if 'random32' is available in the kernel. +# The macro sets variable 'KEDR_HAVE_RANDOM32'. +macro(check_random32) + check_begin("Checking if random32() is available") + if (NOT DEFINED KEDR_HAVE_RANDOM32) + check_try() + kbuild_try_compile(have_random32_impl + "${CMAKE_BINARY_DIR}/check_random32" + "${kmodule_test_sources_dir}/check_random32/module.c" + ) + set_bool_string(KEDR_HAVE_RANDOM32 "yes" "no" "${have_random32_impl}" + CACHE INTERNAL "Is random32() available?" + ) + endif () + check_end("${KEDR_HAVE_RANDOM32}") +endmacro(check_random32) +############################################################################ + +# The payload modules should call kedr_find_function() for each kernel +# function they would like to process. If the function is not known +# to KEDR (absent from the "function database", see "functions/" directory), +# kedr_find_function() issues a fatal error. +# +# 'func_name' is the name of the function, +# 'found_var' is the name of the output variable (the variable will evaluate +# as "true" if found, as "false" otherwise). +function (kedr_find_function func_name found_var) + if (NOT DEFINED KEDR_DATA_FILE_${func_name}) + message(FATAL_ERROR "Unsupported function: ${func_name}") + endif (NOT DEFINED KEDR_DATA_FILE_${func_name}) + + # OK, known function. + kmodule_is_function_exist(${func_name} ${found_var}) + if (${found_var}) + # Mark the function as used by at least one payload module. + # This can be used when preparing the tests for call interception. + # The actual value does not matter, it only matters that this + # variable is defined. + set(KEDR_FUNC_USED_${func_name} "yes" CACHE INTERNAL + "Is kernel function ${func_name} used by any payload module?") + set(${found_var} "${${found_var}}" PARENT_SCOPE) + else () + set(${found_var} "NO" PARENT_SCOPE) + endif (${found_var}) +endfunction (kedr_find_function func_name found_var) + +# Returns (in ${path_var}) the path to the .data file for the function +# ${func_name}. The function must be present in the system and +# kedr_find_function() must be called for it before kedr_get_data_for_func(). +function (kedr_get_data_for_func func_name path_var) + if (NOT DEFINED KEDR_FUNC_USED_${func_name}) + message(FATAL_ERROR +"Attempt to lookup data for a function that is not marked as used: " + "${func_name}") + endif (NOT DEFINED KEDR_FUNC_USED_${func_name}) + + set(${path_var} "${KEDR_DATA_FILE_${func_name}}" PARENT_SCOPE) +endfunction (kedr_get_data_for_func func_name path_var) + +# kedr_get_header_data_list(list_var func1 [func2 func3 ...]) +# Get the list of paths to the 'header.data' files for the given functions. +# The functions must be present in the system and # kedr_find_function() +# must be called for each of them before kedr_get_header_data_list() is +# called. +# The resulting list is returned in ${list_var}. It will contain at least +# one item. It will not contain duplicates. +function (kedr_get_header_data_list list_var) + set(hdata_list) + foreach (func ${ARGN}) + if (NOT DEFINED KEDR_FUNC_USED_${func}) + message(FATAL_ERROR +"Attempt to lookup header data for a function that is not marked as used: " + "${func}") + endif (NOT DEFINED KEDR_FUNC_USED_${func}) + list(APPEND hdata_list "${KEDR_HEADER_DATA_FILE_${func}}") + endforeach () + list(REMOVE_DUPLICATES hdata_list) + + list(LENGTH hdata_list hdata_list_len) + if (NOT hdata_list_len) + message(FATAL_ERROR + "kedr_get_header_data_list(): BUG: the output list is empty.") + endif (NOT hdata_list_len) + + set(${list_var} ${hdata_list} PARENT_SCOPE) +endfunction (kedr_get_header_data_list list_var) + +# kedr_create_header_rules( +# header_impl_file header_data_file func1 [func2 ...]) +# Create the rules to generate ${header_impl_file} from +# ${header_data_file} and the specific header files for the given +# functions. +function(kedr_create_header_rules header_impl_file header_data_file + functions) + set(hlist_data) + kedr_get_header_data_list(hlist_data ${functions} ${ARGN}) + to_abs_path(hdata_files_abs ${header_data_file} ${hlist_data}) + add_custom_command(OUTPUT ${header_impl_file} + COMMAND cat ${hdata_files_abs} > ${header_impl_file} + DEPENDS ${hdata_files_abs} + ) +endfunction(kedr_create_header_rules header_impl_file header_data_file + functions) + +# kedr_create_data_rules(func) +# Create the rules to generate ${func}_impl.data from +# ${func}.data (contains processing instructions specific to the current +# payload) and the .data file from "func_db" (contains function signature). +function(kedr_create_data_rules func) + set(func_db_data_file) + kedr_get_data_for_func(${func} func_db_data_file) + + set(func_proc_data_file) + to_abs_path(func_proc_data_file ${func}.data) + + add_custom_command(OUTPUT "${func}_impl.data" + COMMAND printf "\"[group]\\n\"" > "${func}_impl.data" + COMMAND grep -E -v '\\[group\\]' + "${func_db_data_file}" >> "${func}_impl.data" + COMMAND printf "\"\\n\"" >> "${func}_impl.data" + COMMAND grep -E -v '\\[group\\]' + "${func_proc_data_file}" >> "${func}_impl.data" + DEPENDS + "${func_proc_data_file}" + "${func_db_data_file}" + ) +endfunction(kedr_create_data_rules func) + +# kedr_create_payload_module(module_name payload_data_file template_dir) +# Create the rules to build a payload module with the given name. +# 'payload_data_file' defines how the kernel functions are to be processed +# by this payload module. +# 'template_dir' - path to the direcotry containing the templates to be used +# to prepare the source code of the module from 'payload_data_file'. +function(kedr_create_payload_module module_name payload_data_file + template_dir) + + # Rules to build the module + kbuild_add_module(${module_name} + "payload.c" + "functions_support.c" + ) + kbuild_link_module(${module_name} kedr) + + # Rules to obtain the source files of the module + kedr_generate("payload.c" ${payload_data_file} "${template_dir}") + kedr_generate("functions_support.c" ${payload_data_file} "${KEDR_GEN_TEMPLATES_DIR}/functions_support.c") +endfunction(kedr_create_payload_module module_name payload_data_file + template_dir) + +# kedr_create_payload_data(payload_data_file func1 [func2 ...]) +# Create .data files and the header data files for the functions and prepare +# the main .data file (${payload_data_file}) for the payload module. +function(kedr_create_payload_data header_data_file payload_data_file + functions) + set(header_impl_file "header_impl.data") + set(functions_data) + + foreach(func ${functions} ${ARGN}) + list(APPEND functions_data "${func}_impl.data") + kedr_create_data_rules(${func}) + endforeach(func ${functions} ${ARGN}) + + kedr_create_header_rules(${header_impl_file} ${header_data_file} + ${functions} ${ARGN}) + + to_abs_path(payload_data_file_abs ${payload_data_file}) + to_abs_path(source_files_abs ${header_impl_file} ${functions_data}) + + set(payload_data_file_abs "${CMAKE_CURRENT_BINARY_DIR}/${payload_data_file}") + add_custom_command(OUTPUT ${payload_data_file_abs} + COMMAND cat ${source_files_abs} > ${payload_data_file_abs} + DEPENDS ${source_files_abs} + ) +endfunction(kedr_create_payload_data header_data_file payload_data_file + functions) +############################################################################ diff --git a/cmake_targets/tools/MODULES/path_prefixes.cmake b/cmake_targets/tools/MODULES/path_prefixes.cmake new file mode 100644 index 0000000000000000000000000000000000000000..7deaec0fed39adaffc61355ac93237cedcd9023d --- /dev/null +++ b/cmake_targets/tools/MODULES/path_prefixes.cmake @@ -0,0 +1,264 @@ +# Declare variables for path prefixes for different types of files. +# NB: depends on 'multi_kernel' and 'uninstall_target'. + +# fill_install_prefixes(<project_name> <project_prefix> +# [BASE_INSTALL_PREFIX <base_install_prefix>] +# [KERNEL] +# ) +# +# Setup variables <project_prefix>_* to the install prefixes for +# different project components. +# Precisely, variables with next sufficies are set: +# INSTALL_PREFIX_EXEC - executables +# INSTALL_PREFIX_READONLY - readonly files +# INSTALL_PREFIX_GLOBAL_CONF - global configuration files +# INSTALL_PREFIX_PREFIX_LIB - libraries +# INSTALL_INCLUDE_DIR - include directory(for flags to compiler) +# INSTALL_PREFIX_INCLUDE - include files +# INSTALL_PREFIX_TEMP_SESSION - temporary files(exists until system restarts) +# INSTALL_PREFIX_TEMP - temporary files(preserved even when system restats) +# INSTALL_PREFIX_STATE - files which describe current state of the project. +# INSTALL_PREFIX_CACHE - cache files +# INSTALL_PREFIX_VAR - other modifiable files +# INSTALL_PREFIX_DOC - documentation files +# INSTALL_PREFIX_EXAMPLES - documentation files +# +# With 'KERNEL' option enabled paths for kernel-related files also set: +# INSTALL_KINCLUDE_DIR - directory for include when build kernel components +# INSTALL_PREFIX_KINCLUDE - include files for the kernel. +# +# Additionally, with 'KERNEL' option enabled, several variables are set to +# paths, which contains "%kernel%" pattern. +# These paths are intended for kernel-dependent files; for make paths +# complete one should replace "%kernel%" substring with version of the +# kernel. +# Next kernel-dependend paths are set(sufficies only): +# KERNEL_INSTALL_PREFIX_KMODULE - directory for install kernel modules +# KERNEL_INSTALL_PREFIX_KSYMVERS - directory for install kernel modules' symvers files. +# KERNEL_INSTALL_INCLUDE_KERNEL_DIR - include directory with kernel-dependent headers. +# KERNEL_INSTALL_PREFIX_INCLUDE_KERNEL - include files, which depends from kernel. +# +# Iff option 'COMMON_INSTALL_PREFIX' is given, all paths above are +# calculated using <base_install_prefix> as base prefix. +# Otherwise, CMAKE_INSTALL_PREFIX is used for that purpose. +# +# Additionally, +# INSTALL_TYPE +# variable(suffix) is set to one of: +# - "GLOBAL_OPT" - install into "/opt", +# - "GLOBAL" - global installation except one into "/opt", +# - "LOCAL" - local installation. +function(fill_install_prefixes project_name project_prefix) + cmake_parse_arguments(fip "KERNEL" "BASE_INSTALL_PREFIX" "" ${ARGN}) + if(fip_UNPARSED_ARGUMENTS) + list(GET fip_UNPARSED_ARGUMENTS 0 exceeded_arg) + message(SEND_ERROR "Exceeded argument: ${exceeded_arg}") + endif(fip_UNPARSED_ARGUMENTS) + if(NOT fip_BASE_INSTALL_PREFIX) + set(fip_BASE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + endif(NOT fip_BASE_INSTALL_PREFIX) + + # Follow conventions about paths listed in + # devel-docs/general/path_conventions.txt + # in kedr-devel package. + + # Determine type of installation + if(fip_BASE_INSTALL_PREFIX MATCHES "^/opt") + set(fip_INSTALL_TYPE "GLOBAL_OPT") + elseif(fip_BASE_INSTALL_PREFIX MATCHES "^/usr" + OR fip_BASE_INSTALL_PREFIX STREQUAL "/" + ) + set(fip_INSTALL_TYPE "GLOBAL") + else() + set(fip_INSTALL_TYPE "LOCAL") + endif() + + # 1 + if(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + set(fip_INSTALL_PREFIX_EXEC "/opt/${project_name}/bin") + else(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + set(fip_INSTALL_PREFIX_EXEC "${fip_BASE_INSTALL_PREFIX}/bin") + endif(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + # 2 + set(fip_INSTALL_PREFIX_EXEC_AUX + "${fip_BASE_INSTALL_PREFIX}/lib/${project_name}" + ) + # 3 + set(fip_INSTALL_PREFIX_READONLY + "${fip_BASE_INSTALL_PREFIX}/share/${project_name}" + ) + # 4 + set(fip_INSTALL_PREFIX_MANPAGE + "${fip_BASE_INSTALL_PREFIX}/share/man" + ) + # 5 + if(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + set(fip_INSTALL_PREFIX_GLOBAL_CONF "/etc/opt/${project_name}") + elseif(fip_INSTALL_TYPE STREQUAL "GLOBAL") + set(fip_INSTALL_PREFIX_GLOBAL_CONF "/etc/${project_name}") + else(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + set(fip_INSTALL_PREFIX_GLOBAL_CONF + "${fip_BASE_INSTALL_PREFIX}/etc/${project_name}" + ) + endif(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + # 6 + set(fip_INSTALL_PREFIX_LIB "${fip_BASE_INSTALL_PREFIX}/lib") + # 7 + set(fip_INSTALL_PREFIX_LIB_AUX + "${fip_BASE_INSTALL_PREFIX}/lib/${project_name}" + ) + # 8 + set(fip_INSTALL_INCLUDE_DIR "${fip_BASE_INSTALL_PREFIX}/include") + + set(fip_INSTALL_PREFIX_INCLUDE + "${fip_INSTALL_INCLUDE_DIR}/${project_name}" + ) + # 9 + set(fip_INSTALL_PREFIX_TEMP_SESSION "/tmp/${project_name}") + # 10 + if(fip_INSTALL_TYPE MATCHES "GLOBAL") + set(fip_INSTALL_PREFIX_TEMP "/var/tmp/${project_name}") + else(fip_INSTALL_TYPE MATCHES "GLOBAL") + set(fip_INSTALL_PREFIX_TEMP + "${fip_BASE_INSTALL_PREFIX}/var/tmp/${project_name}" + ) + endif(fip_INSTALL_TYPE MATCHES "GLOBAL") + # 11 + if(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + set(fip_INSTALL_PREFIX_STATE + "/var/opt/${project_name}/lib/${project_name}" + ) + elseif(fip_INSTALL_TYPE STREQUAL "GLOBAL") + set(fip_INSTALL_PREFIX_STATE "/var/lib/${project_name}") + else(fip_INSTALL_TYPE STREQUAL "GLOBAL") + set(fip_INSTALL_PREFIX_STATE + "${fip_BASE_INSTALL_PREFIX}/var/lib/${project_name}" + ) + endif(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + # 12 + if(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + set(fip_INSTALL_PREFIX_CACHE + "/var/opt/${project_name}/cache/${project_name}" + ) + elseif(fip_INSTALL_TYPE STREQUAL "GLOBAL") + set(fip_INSTALL_PREFIX_CACHE "/var/cache/${project_name}") + else(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + set(fip_INSTALL_PREFIX_CACHE + "${fip_BASE_INSTALL_PREFIX}/var/cache/${project_name}" + ) + endif(fip_INSTALL_TYPE STREQUAL "GLOBAL_OPT") + # 13 + if(fip_INSTALL_TYPE MATCHES "GLOBAL") + set(fip_INSTALL_PREFIX_VAR "/var/opt/${project_name}") + else(fip_INSTALL_TYPE MATCHES "GLOBAL") + set(fip_INSTALL_PREFIX_VAR + "${fip_BASE_INSTALL_PREFIX}/var/${project_name}" + ) + endif(fip_INSTALL_TYPE MATCHES "GLOBAL") + # 14 + set(fip_INSTALL_PREFIX_DOC + "${fip_BASE_INSTALL_PREFIX}/share/doc/${project_name}" + ) + + # Set derivative install path and prefixes + + # additional, 4 + set(fip_INSTALL_PREFIX_EXAMPLES + "${fip_INSTALL_PREFIX_READONLY}/examples") + + # Export symbols to the outer scope + foreach(suffix + INSTALL_TYPE + INSTALL_PREFIX_EXEC + INSTALL_PREFIX_EXEC_AUX + INSTALL_PREFIX_READONLY + INSTALL_PREFIX_MANPAGE + INSTALL_PREFIX_GLOBAL_CONF + INSTALL_PREFIX_LIB + INSTALL_PREFIX_LIB_AUX + INSTALL_INCLUDE_DIR + INSTALL_PREFIX_INCLUDE + INSTALL_PREFIX_TEMP_SESSION + INSTALL_PREFIX_TEMP + INSTALL_PREFIX_STATE + INSTALL_PREFIX_CACHE + INSTALL_PREFIX_VAR + INSTALL_PREFIX_DOC + INSTALL_PREFIX_EXAMPLES + ) + set(${project_prefix}_${suffix} "${fip_${suffix}}" PARENT_SCOPE) + endforeach(suffix) + + if(fip_KERNEL) + # Set derivative install path and prefixes + # additional, 1 + if(fip_INSTALL_TYPE MATCHES GLOBAL) + set(fip_KERNEL_INSTALL_PREFIX_KMODULE + "/lib/modules/%kernel%/extra" + ) + else(fip_INSTALL_TYPE MATCHES GLOBAL) + set(fip_KERNEL_INSTALL_PREFIX_KMODULE + "${fip_INSTALL_PREFIX_LIB}/modules/%kernel%/extra" + ) + endif(fip_INSTALL_TYPE MATCHES GLOBAL) + + # additional, 2 + set(fip_KERNEL_INSTALL_PREFIX_KSYMVERS + "${fip_INSTALL_PREFIX_LIB}/modules/%kernel%/symvers" + ) + # additional, 3 + set(fip_INSTALL_KINCLUDE_DIR "${fip_INSTALL_INCLUDE_DIR}") + set(fip_INSTALL_PREFIX_KINCLUDE "${fip_INSTALL_PREFIX_INCLUDE}") + + # Kernel include files, which depends from kernel version. + # This prefix is not listed in path conventions. + set(fip_KERNEL_INSTALL_INCLUDE_KERNEL_DIR + "${fip_BASE_INSTALL_PREFIX}/include-kernel/%kernel%" + ) + + set(fip_KERNEL_INSTALL_PREFIX_INCLUDE_KERNEL + "${fip_KERNEL_INSTALL_INCLUDE_KERNEL_DIR}/${project_name}-kernel" + ) + + # Export symbols to the outer scope + foreach(suffix + KERNEL_INSTALL_PREFIX_KMODULE + KERNEL_INSTALL_PREFIX_KSYMVERS + INSTALL_KINCLUDE_DIR + INSTALL_PREFIX_KINCLUDE + KERNEL_INSTALL_INCLUDE_KERNEL_DIR + KERNEL_INSTALL_PREFIX_INCLUDE_KERNEL + ) + set(${project_prefix}_${suffix} "${fip_${suffix}}" PARENT_SCOPE) + endforeach(suffix) + endif(fip_KERNEL) +endfunction(fill_install_prefixes project_name project_prefix) + + +######################################################################## +# Kernel-dependent paths. +# +# Some deliverables may depends on linux kernel. +# +# For make "one user installation for several kernels" paradigm works, +# installation directory for that deliverables should include +# kernel-version part(like "3.10.2-generic"). +# +# So, components installed by user installation can determine at runtime, +# which kernel-dependent deliverable should be used on currently loaded system. +# They do selection using 'uname -r' request. +# +# For define variables represented kernel-dependent directories, +# we use strings containing "%kernel%" stem. + +# kernel_path(kernel_version RESULT_VARIABLE pattern ...) +# +# Form concrete path representation from kernel-dependent pattern(s). +# Replace occurence of %kernel% in pattern(s) with given @kernel_version string. +# Result is stored in the RESULT_VARIABLE. +# +# @kernel_version may be concrete version of the kernel, +# or variable reference in some language. +macro(kernel_path kernel_version RESULT_VARIABLE pattern) + string(REPLACE "%kernel%" "${kernel_version}" ${RESULT_VARIABLE} ${pattern} ${ARGN}) +endmacro(kernel_path kernel_version RESULT_VARIABLE pattern)