Commit a7734a3a authored by Raphael Defosseux's avatar Raphael Defosseux

chore(build): refactoring for build installation scripts and CI python scripts

parent 93af65f0
[submodule "src/oai-cn5g-common-src"]
path = src/oai-cn5g-common-src
url = https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-common-src.git
[submodule "ci-scripts/common"]
path = ci-scripts/common
url = https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-common-ci.git
[submodule "build/common-build"]
path = build/common-build
url = https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-common-build.git
# 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)
# - 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
)
# - 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)
# - 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)
# - Try to find the CHECK libraries
# Once done this will define
#
# CHECK_FOUND - system has check
# CHECK_INCLUDE_DIR - the check include directory
# CHECK_LIBRARIES - check library
#
# This configuration file for finding libcheck is originally from
# the opensync project. The originally was downloaded from here:
# opensync.org/browser/branches/3rd-party-cmake-modules/modules/FindCheck.cmake
#
# Copyright (c) 2007 Daniel Gollub <dgollub@suse.de>
# Copyright (c) 2007 Bjoern Ricks <b.ricks@fh-osnabrueck.de>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
INCLUDE( FindPkgConfig )
# Take care about check.pc settings
PKG_SEARCH_MODULE( CHECK check )
# Look for CHECK include dir and libraries
IF( NOT CHECK_FOUND )
IF ( CHECK_INSTALL_DIR )
MESSAGE ( STATUS "Using override CHECK_INSTALL_DIR to find check" )
SET ( CHECK_INCLUDE_DIR "${CHECK_INSTALL_DIR}/include" )
SET ( CHECK_INCLUDE_DIRS "${CHECK_INCLUDE_DIR}" )
FIND_LIBRARY( CHECK_LIBRARY NAMES check PATHS "${CHECK_INSTALL_DIR}/lib" )
FIND_LIBRARY( COMPAT_LIBRARY NAMES compat PATHS "${CHECK_INSTALL_DIR}/lib" )
SET ( CHECK_LIBRARIES "${CHECK_LIBRARY}" "${COMPAT_LIBRARY}" )
ELSE ( CHECK_INSTALL_DIR )
FIND_PATH( CHECK_INCLUDE_DIR check.h )
FIND_LIBRARY( CHECK_LIBRARIES NAMES check )
ENDIF ( CHECK_INSTALL_DIR )
IF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
SET( CHECK_FOUND 1 )
IF ( NOT Check_FIND_QUIETLY )
MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" )
ENDIF ( NOT Check_FIND_QUIETLY )
ELSE ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
IF ( Check_FIND_REQUIRED )
MESSAGE( FATAL_ERROR "Could NOT find CHECK" )
ELSE ( Check_FIND_REQUIRED )
IF ( NOT Check_FIND_QUIETLY )
MESSAGE( STATUS "Could NOT find CHECK" )
ENDIF ( NOT Check_FIND_QUIETLY )
ENDIF ( Check_FIND_REQUIRED )
ENDIF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
ENDIF( NOT CHECK_FOUND )
# Hide advanced variables from CMake GUIs
MARK_AS_ADVANCED( CHECK_INCLUDE_DIR CHECK_LIBRARIES )
# Find Libevent
# http://monkey.org/~provos/libevent/
#
# Once done, this will define:
#
# Event_FOUND - system has Event
# Event_INCLUDE_DIRS - the Event include directories
# Event_LIBRARIES - link these to use Event
#
if (EVENT_INCLUDE_DIR AND EVENT_LIBRARY)
# Already in cache, be silent
set(EVENT_FIND_QUIETLY TRUE)
endif (EVENT_INCLUDE_DIR AND EVENT_LIBRARY)
find_path(EVENT_INCLUDE_DIR event.h
PATHS /usr/include
PATH_SUFFIXES event
)
find_library(EVENT_LIBRARY
NAMES event
PATHS /usr/lib /usr/local/lib
)
set(EVENT_LIBRARIES ${EVENT_LIBRARY} )
add_definitions(-DLIBNET_LIL_ENDIAN)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(EVENT
DEFAULT_MSG
EVENT_INCLUDE_DIR
EVENT_LIBRARIES
)
mark_as_advanced(EVENT_INCLUDE_DIR EVENT_LIBRARY)
# - 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 )
GET_FILENAME_COMPONENT(FREEDIAMETER_PATH ${FREEDIAMETER_LIBRARY} PATH)
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)
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)
# FindGCCXML
# ----------
find_program(GCCXML
NAMES gccxml
PATHS "/usr/bin"
"usr/local/bin"
)
mark_as_advanced(GCCXML)
# - 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 )
# - 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)
# - 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
)
# - 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
# 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)
# - 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
)
# 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)
# - 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 )
# - 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 )
# Updated FindThreads.cmake that supports pthread-win32
# Downloaded from http://www.vtk.org/Bug/bug_view_advanced_page.php?bug_id=6399
# - This module determines the thread library of the system.
#
# The following variables are set
# CMAKE_THREAD_LIBS_INIT - the thread library
# CMAKE_USE_SPROC_INIT - are we using sproc?
# CMAKE_USE_WIN32_THREADS_INIT - using WIN32 threads?
# CMAKE_USE_PTHREADS_INIT - are we using pthreads
# CMAKE_HP_PTHREADS_INIT - are we using hp pthreads
#
# If use of pthreads-win32 is desired, the following variables
# can be set.
#
# THREADS_USE_PTHREADS_WIN32 -
# Setting this to true searches for the pthreads-win32
# port (since CMake 2.8.0)
#
# THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME
# C = no exceptions (default)
# (NOTE: This is the default scheme on most POSIX thread
# implementations and what you should probably be using)
# CE = C++ Exception Handling
# SE = Structure Exception Handling (MSVC only)
# (NOTE: Changing this option from the default may affect
# the portability of your application. See pthreads-win32
# documentation for more details.)
#
#======================================================
# Example usage where threading library
# is provided by the system:
#
# find_package(Threads REQUIRED)
# add_executable(foo foo.cc)
# target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT})
#
# Example usage if pthreads-win32 is desired on Windows
# or a system provided thread library:
#
# set(THREADS_USE_PTHREADS_WIN32 true)
# find_package(Threads REQUIRED)
# include_directories(${THREADS_PTHREADS_INCLUDE_DIR})
#
# add_executable(foo foo.cc)
# target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT})
#
INCLUDE (CheckIncludeFiles)
INCLUDE (CheckLibraryExists)
SET(Threads_FOUND FALSE)
IF(WIN32 AND NOT CYGWIN AND THREADS_USE_PTHREADS_WIN32)
SET(_Threads_ptwin32 true)
ENDIF()
# Do we have sproc?
IF(CMAKE_SYSTEM MATCHES IRIX)
CHECK_INCLUDE_FILES("sys/types.h;sys/prctl.h" CMAKE_HAVE_SPROC_H)
ENDIF()
IF(CMAKE_HAVE_SPROC_H)
# We have sproc
SET(CMAKE_USE_SPROC_INIT 1)
ELSEIF(_Threads_ptwin32)
IF(NOT DEFINED THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME)
# Assign the default scheme
SET(THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME "C")
ELSE()
# Validate the scheme specified by the user
IF(NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "C" AND
NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "CE" AND
NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE")
MESSAGE(FATAL_ERROR "See documentation for FindPthreads.cmake, only C, CE, and SE modes are allowed")
ENDIF()
IF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE")
MESSAGE(FATAL_ERROR "Structured Exception Handling is only allowed for MSVC")
ENDIF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE")
ENDIF()
FIND_PATH(THREADS_PTHREADS_INCLUDE_DIR pthread.h)
# Determine the library filename
IF(MSVC)
SET(_Threads_pthreads_libname
pthreadV${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2)
ELSEIF(MINGW)
SET(_Threads_pthreads_libname
pthreadG${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2)
ELSE()
MESSAGE(FATAL_ERROR "This should never happen")
ENDIF()
# Use the include path to help find the library if possible
SET(_Threads_lib_paths "")
IF(THREADS_PTHREADS_INCLUDE_DIR)
GET_FILENAME_COMPONENT(_Threads_root_dir
${THREADS_PTHREADS_INCLUDE_DIR} PATH)
SET(_Threads_lib_paths ${_Threads_root_dir}/lib)
ENDIF()
FIND_LIBRARY(THREADS_PTHREADS_WIN32_LIBRARY
NAMES ${_Threads_pthreads_libname}
PATHS ${_Threads_lib_paths}
DOC "The Portable Threads Library for Win32"
NO_SYSTEM_PATH
)
IF(THREADS_PTHREADS_INCLUDE_DIR AND THREADS_PTHREADS_WIN32_LIBRARY)
MARK_AS_ADVANCED(THREADS_PTHREADS_INCLUDE_DIR)
SET(CMAKE_THREAD_LIBS_INIT ${THREADS_PTHREADS_WIN32_LIBRARY})
SET(CMAKE_HAVE_THREADS_LIBRARY 1)
SET(Threads_FOUND TRUE)
ENDIF()
MARK_AS_ADVANCED(THREADS_PTHREADS_WIN32_LIBRARY)
ELSE()
# Do we have pthreads?
CHECK_INCLUDE_FILES("pthread.h" CMAKE_HAVE_PTHREAD_H)
IF(CMAKE_HAVE_PTHREAD_H)
#
# We have pthread.h
# Let's check for the library now.
#
SET(CMAKE_HAVE_THREADS_LIBRARY)
IF(NOT THREADS_HAVE_PTHREAD_ARG)
# Do we have -lpthreads
CHECK_LIBRARY_EXISTS(pthreads pthread_create "" CMAKE_HAVE_PTHREADS_CREATE)
IF(CMAKE_HAVE_PTHREADS_CREATE)
SET(CMAKE_THREAD_LIBS_INIT "-lpthreads")
SET(CMAKE_HAVE_THREADS_LIBRARY 1)
SET(Threads_FOUND TRUE)
ENDIF()
# Ok, how about -lpthread
CHECK_LIBRARY_EXISTS(pthread pthread_create "" CMAKE_HAVE_PTHREAD_CREATE)
IF(CMAKE_HAVE_PTHREAD_CREATE)
SET(CMAKE_THREAD_LIBS_INIT "-lpthread")
SET(Threads_FOUND TRUE)
SET(CMAKE_HAVE_THREADS_LIBRARY 1)
ENDIF()
IF(CMAKE_SYSTEM MATCHES "SunOS.*")
# On sun also check for -lthread
CHECK_LIBRARY_EXISTS(thread thr_create "" CMAKE_HAVE_THR_CREATE)
IF(CMAKE_HAVE_THR_CREATE)
SET(CMAKE_THREAD_LIBS_INIT "-lthread")
SET(CMAKE_HAVE_THREADS_LIBRARY 1)
SET(Threads_FOUND TRUE)
ENDIF()
ENDIF(CMAKE_SYSTEM MATCHES "SunOS.*")
ENDIF(NOT THREADS_HAVE_PTHREAD_ARG)
IF(NOT CMAKE_HAVE_THREADS_LIBRARY)
# If we did not found -lpthread, -lpthread, or -lthread, look for -pthread
IF("THREADS_HAVE_PTHREAD_ARG" MATCHES "^THREADS_HAVE_PTHREAD_ARG")
MESSAGE(STATUS "Check if compiler accepts -pthread")
TRY_RUN(THREADS_PTHREAD_ARG THREADS_HAVE_PTHREAD_ARG
${CMAKE_BINARY_DIR}
${CMAKE_ROOT}/Modules/CheckForPthreads.c
CMAKE_FLAGS -DLINK_LIBRARIES:STRING=-pthread
COMPILE_OUTPUT_VARIABLE OUTPUT)
IF(THREADS_HAVE_PTHREAD_ARG)
IF(THREADS_PTHREAD_ARG MATCHES "^2$")
SET(Threads_FOUND TRUE)
MESSAGE(STATUS "Check if compiler accepts -pthread - yes")
ELSE()
MESSAGE(STATUS "Check if compiler accepts -pthread - no")
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if compiler accepts -pthread returned ${THREADS_PTHREAD_ARG} instead of 2. The compiler had the following output:\n${OUTPUT}\n\n")
ENDIF()
ELSE()
MESSAGE(STATUS "Check if compiler accepts -pthread - no")
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if compiler accepts -pthread failed with the following output:\n${OUTPUT}\n\n")
ENDIF()
ENDIF("THREADS_HAVE_PTHREAD_ARG" MATCHES "^THREADS_HAVE_PTHREAD_ARG")
IF(THREADS_HAVE_PTHREAD_ARG)
SET(Threads_FOUND TRUE)
SET(CMAKE_THREAD_LIBS_INIT "-pthread")
ENDIF()
ENDIF(NOT CMAKE_HAVE_THREADS_LIBRARY)
ENDIF(CMAKE_HAVE_PTHREAD_H)
ENDIF()
IF(CMAKE_THREAD_LIBS_INIT)
SET(CMAKE_USE_PTHREADS_INIT 1)
SET(Threads_FOUND TRUE)
ENDIF()
IF(CMAKE_SYSTEM MATCHES "Windows"
AND NOT THREADS_USE_PTHREADS_WIN32)
SET(CMAKE_USE_WIN32_THREADS_INIT 1)
SET(Threads_FOUND TRUE)
ENDIF()
IF(CMAKE_USE_PTHREADS_INIT)
IF(CMAKE_SYSTEM MATCHES "HP-UX-*")
# Use libcma if it exists and can be used. It provides more
# symbols than the plain pthread library. CMA threads
# have actually been deprecated:
# http://docs.hp.com/en/B3920-90091/ch12s03.html#d0e11395
# http://docs.hp.com/en/947/d8.html
# but we need to maintain compatibility here.
# The CMAKE_HP_PTHREADS setting actually indicates whether CMA threads
# are available.
CHECK_LIBRARY_EXISTS(cma pthread_attr_create "" CMAKE_HAVE_HP_CMA)
IF(CMAKE_HAVE_HP_CMA)
SET(CMAKE_THREAD_LIBS_INIT "-lcma")
SET(CMAKE_HP_PTHREADS_INIT 1)
SET(Threads_FOUND TRUE)
ENDIF(CMAKE_HAVE_HP_CMA)
SET(CMAKE_USE_PTHREADS_INIT 1)
ENDIF()
IF(CMAKE_SYSTEM MATCHES "OSF1-V*")
SET(CMAKE_USE_PTHREADS_INIT 0)
SET(CMAKE_THREAD_LIBS_INIT )
ENDIF()
IF(CMAKE_SYSTEM MATCHES "CYGWIN_NT*")
SET(CMAKE_USE_PTHREADS_INIT 1)
SET(Threads_FOUND TRUE)
SET(CMAKE_THREAD_LIBS_INIT )
SET(CMAKE_USE_WIN32_THREADS_INIT 0)
ENDIF()
ENDIF(CMAKE_USE_PTHREADS_INIT)
INCLUDE(FindPackageHandleStandardArgs)
IF(_Threads_ptwin32)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG
THREADS_PTHREADS_WIN32_LIBRARY THREADS_PTHREADS_INCLUDE_DIR)
ELSE()
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG Threads_FOUND)
ENDIF()
src=${dir}
obj-m += ${name}.o
${name}-y += ${objs}
ccflags-y += ${module_cc_opt}
# 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
# 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)
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)
############################################################################
# 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)
common-build @ a28192ec
Subproject commit a28192ecfcb85d39ea9c39792e3b0fae2422a340
################################################################################
# Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The OpenAirInterface Software Alliance licenses this file to You under
# the OAI Public License, Version 1.1 (the "License"); you may not use this file
# except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.openairinterface.org/?page_id=698
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#-------------------------------------------------------------------------------
# For more information about the OpenAirInterface (OAI) Software Alliance:
# contact@openairinterface.org
################################################################################
# file build_helper
# brief
# author Laurent Thomas, Lionel GAUTHIER
#
#######################################
#SUPPORTED_DISTRO="Ubuntu 18.04, CentOS 7, RHEL 7"
SUPPORTED_DISTRO="Ubuntu 18.04,20.04,22.04, RHEL8"
if [ ! -f /etc/os-release ]; then
echo_fatal "No /etc/os-release file found. You're likely on an unsupported distro."
fi
OS_DISTRO=$(grep "^ID=" /etc/os-release | sed "s/ID=//" | sed "s/\"//g")
OS_RELEASE=$(grep "^VERSION_ID=" /etc/os-release | sed "s/VERSION_ID=//" | sed "s/\"//g")
case "$OS_DISTRO" in
fedora) OS_BASEDISTRO="fedora"; INSTALLER="dnf"; CMAKE="cmake" ;;
rhel) OS_BASEDISTRO="fedora"; INSTALLER="yum"; CMAKE="cmake" ;;
centos) OS_BASEDISTRO="fedora"; INSTALLER="yum"; CMAKE="cmake3" ;;
debian) OS_BASEDISTRO="debian"; INSTALLER="apt-get"; CMAKE="cmake" ;;
ubuntu) OS_BASEDISTRO="debian"; INSTALLER="apt-get"; CMAKE="cmake" ;;
esac
IS_CONTAINER=`egrep -c "docker|kubepods|podman|buildah|libpod" /proc/self/cgroup || true`
IS_DOCKERBUILD=${IS_DOCKERFILE:-0}
if [ $IS_CONTAINER -eq 0 ] && [ $IS_DOCKERBUILD -eq 0 ]
then
SUDO='sudo -S -E'
else
SUDO=''
IS_CONTAINER=1
fi
###############################
## echo and family
###############################
black='\E[30m'
red='\E[31m'
green='\E[32m'
yellow='\E[33m'
blue='\E[1;34m'
magenta='\E[35m'
cyan='\E[36m'
white='\E[37m'
reset_color='\E[00m'
COLORIZE=1
#-------------------------------------------------------------------------------
cecho() {
# Color-echo
# arg1 = message
# arg2 = color
local default_msg="No Message."
message=${1:-$default_msg}
color=${2:-$green}
[ "$COLORIZE" = "1" ] && message="$color$message$reset_color"
echo -e "$message"
return
}
echo_error() { cecho "$*" $red ;}
echo_fatal() { cecho "$*" $red; exit -1 ;}
echo_warning() { cecho "$*" $yellow ;}
echo_success() { cecho "$*" $green ;}
echo_info() { cecho "$*" $blue ;}
#-------------------------------------------------------------------------------
# From https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash
# arg1 is a dotted (or not) version number (ex 4.10.6.56-ubunutu)
# arg2 is a dotted (or not) version number (ex 4.10.6.56-ubunutu)
# return 0 if $1 lower or equal $2, else 1
version_le() {
[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
}
# From https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash
version_lt() {
[ "$1" = "$2" ] && return 1 || version_le $1 $2
}
# From https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash
version_ge() {
[ "$1" = "`echo -e "$1\n$2" | sort -V | tail -n1`" ]
}
# From https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash
version_gt() {
[ "$1" = "$2" ] && return 1 || version_ge $1 $2
}
########################
# distribution helpers #
########################
#-------------------------------------------------------------------------------
# This function return a string to identify the distribution we are running
# If we can't check the distribution, it returns "Unknown"
# This function return always true as exit code by design
# Examples:
# ubuntu18.04
# debian8.5
get_distribution_release() {
if [[ ! -z "$OS_DISTRO$OS_RELEASE" ]]; then
echo -n "$OS_DISTRO$OS_RELEASE"
else
echo -n Unknown
fi
}
check_supported_distribution() {
local distribution=$(get_distribution_release)
case "$distribution" in
"ubuntu18.04") return 0 ;;
"ubuntu20.04") return 0 ;;
"ubuntu22.04") return 0 ;;
"rhel8") return 0 ;;
"rhel8.2") return 0 ;;
"rhel8.3") return 0 ;;
"rhel8.4") return 0 ;;
"rhel8.5") return 0 ;;
"rhel8.6") return 0 ;;
"rhel8.7") return 0 ;;
esac
return 1
}
###########################
# Cleaners
###########################
#-------------------------------------------------------------------------------
clean_kernel() {
$SUDO modprobe ip_tables
$SUDO modprobe x_tables
$SUDO iptables -P INPUT ACCEPT
$SUDO iptables -F INPUT
$SUDO iptables -P OUTPUT ACCEPT
$SUDO iptables -F OUTPUT
$SUDO iptables -P FORWARD ACCEPT
$SUDO iptables -F FORWARD
$SUDO iptables -t nat -F
$SUDO iptables -t mangle -F
$SUDO iptables -t filter -F
$SUDO iptables -t raw -F
echo_info "Flushed iptables"
}
#-------------------------------------------------------------------------------
disable_ipv6() {
if [ $IS_CONTAINER -eq 0 ]
then
$SUDO sysctl -w net.ipv6.conf.all.disable_ipv6=1
fi
}
#-------------------------------------------------------------------------------
# Compare two versions of software. Returns true if $version is greater than $req_version
# arg1 = version
# arg2 = req_version
#
function version_gt() {
test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1";
}
###################################
# Compilers
###################################
# From https://stackoverflow.com/a/20473191
# test if a list include item
# arg1 is list, ex "item1 item2 ..."
# arg2 is item
function list_include_item {
local list="$1"
local item="$2"
if [[ $list =~ (^|[[:space:]])"$item"($|[[:space:]]) ]] ; then
# yes, list include item
result=0
else
result=1
fi
return $result
}
# arg 1 Build directory OPENAIR_DIR/build/?/build
# arg 2 Executable target name
# arg 3 Executable name (no path)
# arg 4 Verbose (1 or 0)
compilations() {
echo_info "Compilation log for $3 is here: $dlog/$2.txt"
cd $OPENAIRCN_DIR/build/$1/build
if [ "a$4" == "a1" ]; then
set -o pipefail
{
rm -f $3
make $make_args $2
} | tee $dlog/$2.txt
else
{
rm -f $3
make $make_args $2
} > $dlog/$2.txt 2>&1
fi
if [ $? == 0 -a -s $3 ] ; then
echo_success "$2 compiled"
return 0
else
echo_error "$2 compilation failed"
return 1
fi
}
###################################
# make test
###################################
# arg 1 Build directory OPENAIRCN_DIR/build/?/build
# arg 2 Executable target name
# arg 3 Executable name (no path)
# arg 4 Verbose (1 or 0)
make_test() {
echo_success "unit tests start"
cd $OPENAIRCN_DIR/build/$1/build
if [ "a$4" == "a1" ]; then
{
make test ARGS="-V"
} | tee $dlog/$2_test.txt
else
{
make test
} > $dlog/$2_test.txt 2>&1
fi
echo_success "unit tests end"
}
#-------------------------------------------------------------------------------
# arg1 is package name
test_install_package() {
# usage: test_install_package package_name
if [ $# -eq 1 ]; then
dpkg -s "$1" > /dev/null 2>&1 && {
echo "$1 is installed."
} || {
echo "$1 is not installed."
$SUDO apt-get install --force-yes $1
}
fi
}
#-------------------------------------------------------------------------------
update_package_db() {
if [ ! -f /tmp/no_more_update_package_db ]; then
$SUDO $INSTALLER update
[[ $? -ne 0 ]] && return $?
touch /tmp/no_more_update_package_db
[[ $? -ne 0 ]] && return $?
else
let elapsed_time=$(expr `date +%s` - `stat -c %Y /tmp/no_more_update_package_db`)
if [ $elapsed_time -gt 3600 ]; then
$SUDO $INSTALLER update
[[ $? -ne 0 ]] && return $?
touch /tmp/no_more_update_package_db
[[ $? -ne 0 ]] && return $?
fi
fi
return 0
}
#-------------------------------------------------------------------------------
check_enable_epel_repos() {
# on Enterprise Linuxes, ensure EPEL repos are installed
# (provides: libidn2-devel, vconfig, iperf, phpMyAdmin, dkms, ...)
if [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]]; then
if rpm -q epel-release > /dev/null; then
echo "EPEL repos already present. Good."
else
echo "EPEL repos not present. Installing them."
wget --tries=4 --retry-connrefused --wait=8 \
https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
$SUDO $INSTALLER install $OPTION epel-release-latest-7.noarch.rpm
rm -f epel-release-latest-7.noarch.rpm
fi
fi
}
################################
# set_openair_env
###############################
#-------------------------------------------------------------------------------
set_openair_env(){
fullpath=`readlink -f $BASH_SOURCE`
[ -f "/.$fullpath" ] || fullpath=`readlink -f $PWD/$fullpath`
openair_path=${fullpath%/build/*}
openair_path=${openair_path%/scripts/*}
openair_path=${openair_path%/src/nas/*}
openair_path=${openair_path%/src/s6a/*}
export OPENAIRCN_DIR=$openair_path
}
################################################################################
# Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The OpenAirInterface Software Alliance licenses this file to You under
# the OAI Public License, Version 1.1 (the "License"); you may not use this file
# except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.openairinterface.org/?page_id=698
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#-------------------------------------------------------------------------------
# For more information about the OpenAirInterface (OAI) Software Alliance:
# contact@openairinterface.org
################################################################################
# file build_helper.libconfig
# brief
# author Lionel GAUTHIER
#
#######################################
SCRIPT=$(readlink -f ${BASH_SOURCE})
THIS_SCRIPT_PATH=`dirname $SCRIPT`
source $THIS_SCRIPT_PATH/build_helper
#-------------------------------------------------------------------------------
# Motivation: seems libconfig++ need to be compiled with same application C++ compiler,
# otherwise you encounter strange linker errors. (ubuntu 16.04)
#arg1 is force (0 or 1) (no interactive script)
#arg2 is debug (0 or 1) (install debug libraries)
install_libconfig_from_source(){
if [ $1 -eq 0 ]; then
OPTION=""
read -p "Do you want to install libconfig (github)? <y/N> " prompt
else
prompt='y'
OPTION="-y"
fi
if [ $2 -eq 0 ]; then
debug=0
else
debug=1
fi
if [[ $prompt =~ [yY](es)* ]]
then
if [[ "$OS_DISTRO" == "ubuntu" ]]; then
PACKAGE_LIST="\
autoconf \
automake \
bison \
build-essential \
flex \
gcc \
libtool"
elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then
PACKAGE_LIST="\
autoconf \
automake \
bison \
patch \
flex \
gcc \
libtool \
textinfo"
else
echo_fatal "$OS_DISTRO is not a supported distribution."
fi
$SUDO $INSTALLER install $OPTION $PACKAGE_LIST
pushd /tmp
$SUDO rm -rf /tmp/libconfig
git clone https://github.com/hyperrealm/libconfig.git
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
cd libconfig
autoreconf -fi
./configure
ret=$?;[[ $ret -ne 0 ]] && return $ret
make -j `nproc` > /tmp/log_compile_config 2>&1
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
$SUDO make install
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
popd
fi
return 0
}
......@@ -29,341 +29,13 @@
################################
SCRIPT=$(readlink -f ${BASH_SOURCE})
THIS_SCRIPT_PATH=`dirname $SCRIPT`
source $THIS_SCRIPT_PATH/build_helper
#-------------------------------------------------------------------------------
#arg1 is force (0 or 1) (no interactive script)
#arg2 is debug (0 or 1) (install debug libraries)
install_spdlog_from_git() {
echo "Starting to install spdlog"
if [ $1 -eq 0 ]; then
read -p "Do you want to install spdlog ? <y/N> " prompt
OPTION=""
else
prompt='y'
OPTION="-y"
fi
if [ $2 -eq 0 ]; then
debug=0
else
debug=1
fi
if [[ $prompt =~ [yY](es)* ]]
then
GIT_URL=https://github.com/gabime/spdlog.git
echo "Install spdlog from $GIT_URL"
pushd $OPENAIRCN_DIR/build/ext
echo "Downloading spdlog"
if [[ $OPTION =~ -[yY](es)* ]]
then
$SUDO rm -rf spdlog
fi
git clone $GIT_URL
cd spdlog && git checkout v1.11.0
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
mkdir _build && cd _build
$CMAKE -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DSPDLOG_FMT_EXTERNAL=ON -DSPDLOG_BUILD_SHARED=ON ..
make
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
$SUDO make install
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
popd
rm -Rf $OPENAIRCN_DIR/build/ext/spdlog/_build
fi
echo "spdlog installation complete"
return 0
}
#-------------------------------------------------------------------------------
#arg1 is force (0 or 1) (no interactive script)
#arg2 is debug (0 or 1) (install debug libraries)
install_fmt_from_git() {
echo "Starting to install fmt"
if [ $1 -eq 0 ]; then
read -p "Do you want to install fmt? <y/N> " prompt
OPTION=""
else
prompt='y'
OPTION="-y"
fi
if [ $2 -eq 0 ]; then
debug=0
else
debug=1
fi
if [[ $prompt =~ [yY](es)* ]]
then
GIT_URL=https://github.com/fmtlib/fmt/
echo "Install fmt from $GIT_URL"
pushd $OPENAIRCN_DIR/build/ext
echo "Downloading fmt"
if [[ $OPTION =~ -[yY](es)* ]]
then
$SUDO rm -rf fmt
fi
git clone $GIT_URL
cd fmt && git checkout 9.0.0
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
mkdir _build && cd _build
$CMAKE -G "Unix Makefiles" -DFMT_TEST=OFF -DBUILD_SHARED_LIBS=TRUE ..
make
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
$SUDO make install
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
popd
rm -Rf $OPENAIRCN_DIR/build/ext/fmt/_build
fi
echo "fmt installation complete"
return 0
}
#-------------------------------------------------------------------------------
#arg1 is force (0 or 1) (no interactive script)
#arg2 is debug (0 or 1) (install debug libraries)
install_pistache_from_git() {
echo "Starting to install pistache"
if [ $1 -eq 0 ]; then
read -p "Do you want to install Pistache ? <y/N> " prompt
OPTION="-y"
else
prompt='y'
OPTION="-y"
fi
if [ $2 -eq 0 ]; then
debug=0
else
debug=1
fi
if [[ $prompt =~ [yY](es)* ]]
then
GIT_URL=https://github.com/oktal/pistache.git
echo "Install Pistache from $GIT_URL"
pushd $OPENAIRCN_DIR/build/ext
echo "Downloading Pistache"
if [[ $OPTION =~ -[yY](es)* ]]
then
$SUDO rm -rf pistache
fi
git clone $GIT_URL
cd pistache && git checkout e18ed9baeb2145af6f9ea41246cf48054ffd9907
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
mkdir _build && cd _build
$CMAKE -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release \
-DPISTACHE_BUILD_EXAMPLES=false \
-DPISTACHE_BUILD_TESTS=false \
-DPISTACHE_BUILD_DOCS=false \
..
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
make -j $(nproc)
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
$SUDO make install
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
popd
rm -Rf $OPENAIRCN_DIR/build/ext/pistache/_build
fi
echo "pistache installation complete"
return 0
}
#-------------------------------------------------------------------------------
#arg1 is force (0 or 1) (no interactive script)
#arg2 is debug (0 or 1) (install debug libraries)
install_nlohmann_from_git() {
echo "Starting to install Nlohmann Json"
if [ $1 -eq 0 ]; then
read -p "Do you want to install Nlohmann Json ? <y/N> " prompt
OPTION=""
else
prompt='y'
OPTION="-y"
fi
if [ $2 -eq 0 ]; then
debug=0
else
debug=1
fi
if [[ $prompt =~ [yY](es)* ]]
then
GIT_URL=https://github.com/nlohmann/json.git
echo "Install Nlohmann Json from $GIT_URL"
pushd $OPENAIRCN_DIR/build/ext
echo "Downloading Nlohmann"
if [[ $OPTION =~ -[yY](es)* ]]
then
$SUDO rm -rf json
fi
git clone $GIT_URL
cd json && git checkout -f v3.10.3
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
mkdir _build && cd _build
$CMAKE -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DJSON_BuildTests=OFF ..
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
make
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
$SUDO make install
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
popd
rm -Rf $OPENAIRCN_DIR/build/ext/json/_build
fi
echo "Nlohmann Json installation complete"
return 0
}
#-------------------------------------------------------------------------------
#arg1 is force (0 or 1) (no interactive script)
#arg2 is debug (0 or 1) (install debug libraries)
install_nghttp2_from_git() {
echo "Starting to install nghttp2"
if [ $1 -eq 0 ]; then
read -p "Do you want to install nghttp2 ? <y/N> " prompt
OPTION=""
else
prompt='y'
OPTION="-y"
fi
if [ $2 -eq 0 ]; then
debug=0
else
debug=1
fi
if [[ $prompt =~ [yY](es)* ]]
then
if [[ $OS_DISTRO == "ubuntu" ]]; then
PACKAGE_LIST="\
g++ \
$CMAKE \
binutils \
autoconf \
automake \
autotools-dev \
libtool \
pkg-config \
zlib1g-dev \
libcunit1-dev \
libssl-dev \
libxml2-dev libev-dev libevent-dev libjansson-dev libc-ares-dev \
libjemalloc-dev libsystemd-dev python3-dev python-setuptools"
elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then
PACKAGE_LIST="\
gcc-c++ \
binutils-devel \
autoconf \
automake \
$CMAKE \
make \
libtool \
pkg-config \
zlib-devel \
CUnit-devel \
openssl-devel \
libxml2-devel libev-devel libevent-devel jansson-devel c-ares-devel \
jemalloc-devel systemd-devel python3-Cython python3-devel python3-setuptools"
else
echo_fatal "$OS_DISTRO is not a supported distribution."
fi
echo "Install build tools"
$SUDO $INSTALLER install $OPTION $PACKAGE_LIST
ret=$?;[[ $ret -ne 0 ]] && return $ret
GIT_URL=https://github.com/nghttp2/nghttp2.git
echo "Install nghttp2 from $GIT_URL"
pushd $OPENAIRCN_DIR/build/ext
echo "Downloading nghttp2"
if [[ $OPTION =~ [yY](es)* ]]
then
$SUDO rm -rf nghttp2
fi
git clone $GIT_URL
cd nghttp2
git checkout 43ba3125932c1d56addaeded2b7f62637af255cd
git submodule update --init
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
autoreconf -i
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
automake
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
autoconf
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
./configure --enable-asio-lib --enable-lib-only
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
make -j $(nproc)
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
$SUDO make install
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
$SUDO ldconfig
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
git clean -x -d -ff .
popd
fi
echo "nghttp2 installation complete"
return 0
}
#-------------------------------------------------------------------------------
#arg1 is force (0 or 1) (no interactive script)
#arg2 is debug (0 or 1) (install debug libraries)
install_libyaml_cpp_from_git() {
# For Ubuntu 2x and RHEL we should install from repo.
echo "Starting to install libyaml_cpp"
if [ $1 -eq 0 ]; then
read -p "Do you want to install yaml_cpp ? <y/N> " prompt
OPTION=""
else
prompt='y'
OPTION="-y"
fi
if [ $2 -eq 0 ]; then
debug=0
else
debug=1
fi
if [[ $prompt =~ [yY](es)* ]]
then
GIT_URL=https://github.com/jbeder/yaml-cpp.git
echo "Install yaml-cpp from $GIT_URL"
pushd $OPENAIRCN_DIR/build/ext
echo "Downloading yaml-cpp"
if [[ $OPTION =~ -[yY](es)* ]]
then
$SUDO rm -rf yaml-cpp
fi
git clone $GIT_URL
cd yaml-cpp && git checkout master
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
mkdir _build && cd _build
$CMAKE -G "Unix Makefiles" -DYAML_BUILD_SHARED_LIBS=on -DYAML_CPP_BUILD_TESTS=off ..
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
make
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
$SUDO make install
ret=$?;[[ $ret -ne 0 ]] && popd && return $ret
popd
rm -Rf $OPENAIRCN_DIR/build/ext/yaml-cpp/_build
fi
echo "yaml-cpp installation complete"
return 0
}
source $THIS_SCRIPT_PATH/../common-build/installation/build_helper
source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.fmt
source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.spdlog
source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.pistache
source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.nlohmann
source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.nghttp2
source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.yamlcpp
#-------------------------------------------------------------------------------
#arg1 is force (0 or 1) (no interactive script)
......
......@@ -27,12 +27,28 @@
#
set -o pipefail
THIS_SCRIPT_PATH=$(dirname $(readlink -f $0))
## initialize git submodules
pushd ${THIS_SCRIPT_PATH}/../..
if [ -d .git ] && [ -f .gitmodules ]; then
echo "Synchronizing the Git Sub-Modules"
git submodule status | while read -r line ; do
moduleName=`echo $line | awk '{print $2}'`
gitReference=`echo $line | awk '{print $3}'`
if [[ -z "$gitReference" ]]; then
echo "$moduleName looks empty!"
git submodule update --init --recursive $moduleName
fi
done
git submodule --quiet foreach 'echo "${path} is synchronized or in edition"'
fi
popd
INSTALL_DIR=/usr/local/bin
################################
# include helper functions
################################
THIS_SCRIPT_PATH=$(dirname $(readlink -f $0))
source $THIS_SCRIPT_PATH/build_helper.smf
......
......@@ -227,7 +227,8 @@ pipeline {
// It's a different agent from main one.
prepareWorkspaceMergeCase()
// Moving to focal and cppcheck 1.90 and a dockerfile approach
sh 'docker build --target smf-cppcheck --tag smf-cppcheck:test --file ci-scripts/docker/Dockerfile.ci.cppcheck . > archives/cppcheck_install.log 2>&1'
sh 'sed -i -e "s@nfName@smf@" ci-scripts/common/docker/Dockerfile.ci.cppcheck'
sh 'docker build --target smf-cppcheck --tag smf-cppcheck:test --file ci-scripts/common/docker/Dockerfile.ci.cppcheck . > archives/cppcheck_install.log 2>&1'
sh 'docker run --name smf-ci-cppcheck --entrypoint /bin/true smf-cppcheck:test'
sh 'docker cp smf-ci-cppcheck:/home/cppcheck.xml archives'
sh 'docker cp smf-ci-cppcheck:/home/cppcheck_build.log archives'
......@@ -263,10 +264,11 @@ pipeline {
gitlabCommitStatus(name: "Code Formatting Checker") {
// It's a different agent from main one.
prepareWorkspaceMergeCase()
sh 'sed -i -e "s@nfName@smf@" ci-scripts/common/docker/Dockerfile.ci.clang-format'
if ("MERGE".equals(env.gitlabActionType)) {
sh 'docker build --target smf-clang-format-check --tag smf-clang-format-check:test --file ci-scripts/docker/Dockerfile.ci.clang-format --build-arg MERGE_REQUEST_CHECK=True --build-arg SOURCE_BRANCH=' + env.gitlabSourceBranch + ' --build-arg TARGET_BRANCH=' + env.gitlabTargetBranch + ' . > archives/clang_format_install.log 2>&1'
sh 'docker build --target smf-clang-format-check --tag smf-clang-format-check:test --file ci-scripts/common/docker/Dockerfile.ci.clang-format --build-arg MERGE_REQUEST_CHECK=True --build-arg SOURCE_BRANCH=' + env.gitlabSourceBranch + ' --build-arg TARGET_BRANCH=' + env.gitlabTargetBranch + ' . > archives/clang_format_install.log 2>&1'
} else {
sh 'docker build --target smf-clang-format-check --tag smf-clang-format-check:test --file ci-scripts/docker/Dockerfile.ci.clang-format . > archives/clang_format_install.log 2>&1'
sh 'docker build --target smf-clang-format-check --tag smf-clang-format-check:test --file ci-scripts/common/docker/Dockerfile.ci.clang-format . > archives/clang_format_install.log 2>&1'
}
sh 'docker run --name smf-ci-clang-format --entrypoint /bin/true smf-clang-format-check:test'
sh 'docker cp smf-ci-clang-format:/home/src/oai_rules_result.txt src'
......@@ -316,8 +318,7 @@ pipeline {
if (localStatus.resultIsBetterOrEqualTo('SUCCESS')) {
echo "Tutorials Test Job is OK"
} else {
echo "Tutorials Test Job is KO"
sh "ci-scripts/fail.sh"
error "Tutorials Test Job is KO"
}
}
}
......@@ -346,8 +347,7 @@ pipeline {
if (localStatus.resultIsBetterOrEqualTo('SUCCESS')) {
echo "Test Job with COTS-UE is OK"
} else {
echo "Test Job with COTS-UE is is KO"
sh "ci-scripts/fail.sh"
error "Test Job with COTS-UE is is KO"
}
}
}
......@@ -376,8 +376,7 @@ pipeline {
if (localStatus.resultIsBetterOrEqualTo('SUCCESS')) {
echo "Load Testing is OK"
} else {
echo "Load Testing is is KO"
sh "ci-scripts/fail.sh"
error "Load Testing is is KO"
}
}
}
......@@ -407,8 +406,7 @@ pipeline {
if (localStatus.resultIsBetterOrEqualTo('SUCCESS')) {
echo "NGAP-Tester is OK"
} else {
echo "NGAP-Tester is is KO"
sh "ci-scripts/fail.sh"
error "NGAP-Tester is is KO"
}
}
}
......@@ -430,21 +428,23 @@ pipeline {
// Temporary Images from Merge-Request Runs are kept in local private registry
stage ('Pushing Image to Official Registry') {
steps {
script {
// Only in case of push to target branch!
if ("PUSH".equals(env.gitlabActionType)) {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.DockerHubCredentials}", usernameVariable: 'DH_Username', passwordVariable: 'DH_Password']
]) {
sh "echo ${DH_Password} | docker login --username ${DH_Username} --password-stdin"
lock(ubuntuBuildResource) {
script {
// Only in case of push to target branch!
if ("PUSH".equals(env.gitlabActionType)) {
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.DockerHubCredentials}", usernameVariable: 'DH_Username', passwordVariable: 'DH_Password']
]) {
sh "echo ${DH_Password} | docker login --username ${DH_Username} --password-stdin"
}
sh "docker login -u oaicicd -p oaicicd ${PrivateRegistryURL}"
sh "docker pull ${PrivateRegistryURL}/oai-smf:${smf_tag}"
sh "docker image tag ${PrivateRegistryURL}/oai-smf:${smf_tag} ${DH_Account}/oai-smf:develop"
sh "docker push ${DH_Account}/oai-smf:develop"
sh "docker rmi ${DH_Account}/oai-smf:develop ${PrivateRegistryURL}/oai-smf:${smf_tag}"
sh "docker logout ${PrivateRegistryURL}"
sh "docker logout"
}
sh "docker login -u oaicicd -p oaicicd ${PrivateRegistryURL}"
sh "docker pull ${PrivateRegistryURL}/oai-smf:${smf_tag}"
sh "docker image tag ${PrivateRegistryURL}/oai-smf:${smf_tag} ${DH_Account}/oai-smf:develop"
sh "docker push ${DH_Account}/oai-smf:develop"
sh "docker rmi ${DH_Account}/oai-smf:develop ${PrivateRegistryURL}/oai-smf:${smf_tag}"
sh "docker logout ${PrivateRegistryURL}"
sh "docker logout"
}
}
}
......@@ -479,9 +479,9 @@ pipeline {
// Generating the HTML report(s)
if ("MERGE".equals(env.gitlabActionType)) {
sh "python3 ci-scripts/generateHtmlReport.py --job_name=${JOB_NAME} --job_id=${BUILD_ID} --job_url=${BUILD_URL} --git_url=${GIT_URL} --git_src_branch=${env.gitlabSourceBranch} --git_src_commit=${env.gitlabMergeRequestLastCommit} --git_pull_request=True --git_target_branch=${env.gitlabTargetBranch} --git_target_commit=${GIT_COMMIT}"
sh "./ci-scripts/generateHtmlReport.py --job-name ${JOB_NAME} --build-id ${BUILD_ID} --build-url ${BUILD_URL} --git-url ${GIT_URL} --git-src-branch ${env.gitlabSourceBranch} --git-src-commit ${env.gitlabMergeRequestLastCommit} --git-merge-request --git-dst-branch ${env.gitlabTargetBranch} --git-dst-commit ${GIT_COMMIT}"
} else {
sh "python3 ci-scripts/generateHtmlReport.py --job_name=${JOB_NAME} --job_id=${BUILD_ID} --job_url=${BUILD_URL} --git_url=${GIT_URL} --git_src_branch=${GIT_BRANCH} --git_src_commit=${GIT_COMMIT}"
sh "./ci-scripts/generateHtmlReport.py --job-name ${JOB_NAME} --build-id ${BUILD_ID} --build-url ${BUILD_URL} --git-url ${GIT_URL} --git-src-branch ${GIT_BRANCH} --git-src-commit ${GIT_COMMIT}"
}
listOfFiles = sh returnStdout: true, script: 'ls test_results*.html'
String[] htmlFiles = listOfFiles.split("\\n")
......@@ -517,6 +517,8 @@ OAI CI Team''',
def prepareWorkspaceMergeCase () {
sh "git clean -x -d -f > /dev/null 2>&1"
sh "git submodule foreach --recursive 'git clean -x -d -ff' > /dev/null 2>&1"
sh "git submodule deinit --force --all > /dev/null 2>&1"
if ("MERGE".equals(env.gitlabActionType)) {
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${env.gitlabSourceBranch} --src-commit ${env.gitlabMergeRequestLastCommit} --target-branch ${env.gitlabTargetBranch} --target-commit ${GIT_COMMIT}"
}
......
common @ 2dbfb4cf
Subproject commit 2dbfb4cfb675d03858f066358802320d99953d9f
#/*
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements. See the NOTICE file distributed with
# * this work for additional information regarding copyright ownership.
# * The OpenAirInterface Software Alliance licenses this file to You under
# * the OAI Public License, Version 1.1 (the "License"); you may not use this file
# * except in compliance with the License.
# * You may obtain a copy of the License at
# *
# * http://www.openairinterface.org/?page_id=698
# *
# * Unless required by applicable law or agreed to in writing, software
# * distributed under the License is distributed on an "AS IS" BASIS,
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# * See the License for the specific language governing permissions and
# * limitations under the License.
# *-------------------------------------------------------------------------------
# * For more information about the OpenAirInterface (OAI) Software Alliance:
# * contact@openairinterface.org
# */
#---------------------------------------------------------------------
import os
import re
import sys
class smfConfigGen():
def __init__(self):
self.kind = ''
self.sbi_name = ''
self.sbi_port = '80'
self.sbi_http2_port = '9090'
self.sbi_api_version = 'v1'
self.n4_name = ''
self.amf_ip_addr = ''
self.amf_port = '80'
self.amf_api_version = 'v1'
self.udm_ip_addr = ''
self.udm_port = '80'
self.udm_api_version = 'v2'
# self.nrf_ip_addr = ''
# self.nrf_port = '80'
# self.nrf_api_version = 'v1'
self.upf_ip_addr = ''
self.apn = 'carrier.com'
self.dns1_ip = '192.168.18.129'
self.dns2_ip = '8.8.4.4'
self.fromDockerFile = False
def GenerateSmfConfigurer(self):
smfFile = open('./smf-cfg.sh', 'w')
smfFile.write('#!/bin/bash\n')
smfFile.write('\n')
if self.fromDockerFile:
smfFile.write('cd /openair-smf\n')
else:
smfFile.write('cd /home\n')
smfFile.write('\n')
smfFile.write('INSTANCE=1\n')
if self.fromDockerFile:
smfFile.write('PREFIX=\'/openair-smf/etc\'\n')
else:
smfFile.write('PREFIX=\'/usr/local/etc/oai\'\n')
smfFile.write('\n')
smfFile.write('MY_APN=\'' + self.apn + '\'\n')
smfFile.write('MY_PRIMARY_DNS=\'' + self.dns1_ip + '\'\n')
smfFile.write('MY_SECONDARY_DNS=\'' + self.dns2_ip + '\'\n')
smfFile.write('\n')
if not self.fromDockerFile:
smfFile.write('mkdir -p $PREFIX\n')
smfFile.write('cp etc/spgw_c.conf $PREFIX\n')
smfFile.write('\n')
smfFile.write('declare -A SMF_CONF\n')
smfFile.write('\n')
smfFile.write('SMF_CONF[@INSTANCE@]=$INSTANCE\n')
smfFile.write('SMF_CONF[@PID_DIRECTORY@]=\'/var/run\'\n')
smfFile.write('SMF_CONF[@SMF_INTERFACE_NAME_FOR_N4@]=\'' + self.n4_name + '\'\n')
smfFile.write('SMF_CONF[@SMF_INTERFACE_NAME_FOR_SBI@]=\'' + self.sbi_name + '\'\n')
smfFile.write('SMF_CONF[@SMF_INTERFACE_PORT_FOR_SBI@]=' + self.sbi_port + '\n')
smfFile.write('SMF_CONF[@SMF_INTERFACE_HTTP2_PORT_FOR_SBI@]=' + self.sbi_http2_port + '\n')
smfFile.write('SMF_CONF[@SMF_API_VERSION@]=\'' + self.sbi_api_version + '\'\n')
smfFile.write('SMF_CONF[@DEFAULT_DNS_IPV4_ADDRESS@]=$MY_PRIMARY_DNS\n')
smfFile.write('SMF_CONF[@DEFAULT_DNS_SEC_IPV4_ADDRESS@]=$MY_SECONDARY_DNS\n')
#smfFile.write('SMF_CONF[@DEFAULT_APN@]=$MY_APN\n')
smfFile.write('SMF_CONF[@AMF_IPV4_ADDRESS@]=\'' + self.amf_ip_addr + '\'\n')
smfFile.write('SMF_CONF[@AMF_PORT@]=' + self.amf_port + '\n')
smfFile.write('SMF_CONF[@AMF_API_VERSION@]=\'' + self.amf_api_version + '\'\n')
smfFile.write('SMF_CONF[@UDM_IPV4_ADDRESS@]=\'' + self.udm_ip_addr + '\'\n')
smfFile.write('SMF_CONF[@UDM_PORT@]=' + self.udm_port + '\n')
smfFile.write('SMF_CONF[@UDM_API_VERSION@]=\'' + self.udm_api_version + '\'\n')
# smfFile.write('SMF_CONF[@NRF_IPV4_ADDRESS@]=\'' + self.nrf_ip_addr + '\'\n')
# smfFile.write('SMF_CONF[@NRF_PORT@]=' + self.nrf_port + '\n')
# smfFile.write('SMF_CONF[@NRF_API_VERSION@]=\'' + self.nrf_api_version + '\'\n')
smfFile.write('SMF_CONF[@UPF_IPV4_ADDRESS@]=\'' + self.upf_ip_addr + '\'\n')
smfFile.write('\n')
smfFile.write('for K in "${!SMF_CONF[@]}"; do \n')
smfFile.write(' egrep -lRZ "$K" $PREFIX | xargs -0 -l sed -i -e "s|$K|${SMF_CONF[$K]}|g"\n')
smfFile.write('done\n')
smfFile.write('\n')
smfFile.write('exit 0\n')
smfFile.close()
#-----------------------------------------------------------
# Usage()
#-----------------------------------------------------------
def Usage():
print('----------------------------------------------------------------------------------------------------------------------')
print('generateConfigFiles.py')
print(' Prepare a bash script to be run in the workspace where SMF is being built.')
print(' That bash script will copy configuration template files and adapt to your configuration.')
print('----------------------------------------------------------------------------------------------------------------------')
print('Usage: python3 generateConfigFiles.py [options]')
print(' --help Show this help.')
print('---------------------------------------------------------------------------------------------------- SMF Options -----')
print(' --kind=SMF')
print(' --sbi=[SMF SBI Interface Name]')
print(' --n4=[SMF N4 Interface Name]')
print(' --amf_ip_addr=[AMF IP Address]')
print(' --udm_ip_addr=[UDM IP Address]')
# print(' --nrf_ip_addr=[NRF IP Address]')
print(' --upf_ip_addr=[UPF IP Address]')
print(' --from_docker_file')
print('---------------------------------------------------------------------------------------------- SMF Not Mandatory -----')
print(' --apn=[Access Point Name]')
print(' --dns1_ip=[First DNS IP address]')
print(' --dns2_ip=[Second DNS IP address]')
argvs = sys.argv
argc = len(argvs)
cwd = os.getcwd()
mySmfCfg = smfConfigGen()
while len(argvs) > 1:
myArgv = argvs.pop(1)
if re.match('^\-\-help$', myArgv, re.IGNORECASE):
Usage()
sys.exit(0)
elif re.match('^\-\-kind=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-kind=(.+)$', myArgv, re.IGNORECASE)
mySmfCfg.kind = matchReg.group(1)
elif re.match('^\-\-sbi=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-sbi=(.+)$', myArgv, re.IGNORECASE)
mySmfCfg.sbi_name = matchReg.group(1)
elif re.match('^\-\-n4=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-n4=(.+)$', myArgv, re.IGNORECASE)
mySmfCfg.n4_name = matchReg.group(1)
elif re.match('^\-\-amf_ip_addr=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-amf_ip_addr=(.+)$', myArgv, re.IGNORECASE)
mySmfCfg.amf_ip_addr = matchReg.group(1)
elif re.match('^\-\-udm_ip_addr=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-udm_ip_addr=(.+)$', myArgv, re.IGNORECASE)
mySmfCfg.udm_ip_addr = matchReg.group(1)
# elif re.match('^\-\-nrf_ip_addr=(.+)$', myArgv, re.IGNORECASE):
# matchReg = re.match('^\-\-nrf_ip_addr=(.+)$', myArgv, re.IGNORECASE)
# mySmfCfg.nrf_ip_addr = matchReg.group(1)
elif re.match('^\-\-upf_ip_addr=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-upf_ip_addr=(.+)$', myArgv, re.IGNORECASE)
mySmfCfg.upf_ip_addr = matchReg.group(1)
elif re.match('^\-\-apn=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-apn=(.+)$', myArgv, re.IGNORECASE)
mySmfCfg.apn = matchReg.group(1)
elif re.match('^\-\-dns1_ip=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-dns1_ip=(.+)$', myArgv, re.IGNORECASE)
mySmfCfg.dns1_ip = matchReg.group(1)
elif re.match('^\-\-dns2_ip=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-dns2_ip=(.+)$', myArgv, re.IGNORECASE)
mySmfCfg.dns2_ip = matchReg.group(1)
elif re.match('^\-\-from_docker_file', myArgv, re.IGNORECASE):
mySmfCfg.fromDockerFile = True
else:
Usage()
sys.exit('Invalid Parameter: ' + myArgv)
if mySmfCfg.kind == '':
Usage()
sys.exit('missing kind parameter')
if mySmfCfg.kind == 'SMF':
if mySmfCfg.sbi_name == '':
Usage()
sys.exit('missing S11 Interface Name on SMF container')
elif mySmfCfg.n4_name == '':
Usage()
sys.exit('missing N4 Interface Name on SMF container')
elif mySmfCfg.amf_ip_addr == '':
Usage()
sys.exit('missing AMF IP address')
elif mySmfCfg.udm_ip_addr == '':
Usage()
sys.exit('missing UDM IP address')
# elif mySmfCfg.nrf_ip_addr == '':
# Usage()
# sys.exit('missing NRF IP address')
elif mySmfCfg.upf_ip_addr == '':
Usage()
sys.exit('missing UPF IP address')
else:
mySmfCfg.GenerateSmfConfigurer()
sys.exit(0)
else:
Usage()
sys.exit('invalid kind parameter')
#/*
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements. See the NOTICE file distributed with
# * this work for additional information regarding copyright ownership.
# * The OpenAirInterface Software Alliance licenses this file to You under
# * the OAI Public License, Version 1.1 (the "License"); you may not use this file
# * except in compliance with the License.
# * You may obtain a copy of the License at
# *
# * http://www.openairinterface.org/?page_id=698
# *
# * Unless required by applicable law or agreed to in writing, software
# * distributed under the License is distributed on an "AS IS" BASIS,
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# * See the License for the specific language governing permissions and
# * limitations under the License.
# *-------------------------------------------------------------------------------
# * For more information about the OpenAirInterface (OAI) Software Alliance:
# * contact@openairinterface.org
# */
#---------------------------------------------------------------------
import glob
#!/usr/bin/env python3
"""
Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The OpenAirInterface Software Alliance licenses this file to You under
the OAI Public License, Version 1.1 (the "License"); you may not use this file
except in compliance with the License.
You may obtain a copy of the License at
http://www.openairinterface.org/?page_id=698
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
------------------------------------------------------------------------------
For more information about the OpenAirInterface (OAI) Software Alliance:
contact@openairinterface.org
---------------------------------------------------------------------
"""
#import argparse
import os
import re
import sys
import subprocess
class HtmlReport():
def __init__(self):
self.job_name = ''
self.job_id = ''
self.job_url = ''
self.job_start_time = 'TEMPLATE_TIME'
self.git_url = ''
self.git_src_branch = ''
self.git_src_commit = ''
self.git_src_commit_msg = None
self.git_pull_request = False
self.git_target_branch = ''
self.git_target_commit = ''
self.nb_warnings = 0
self.warning_rows = ''
def generate(self):
cwd = os.getcwd()
self.file = open(cwd + '/test_results_oai_smf.html', 'w')
self.generateHeader()
self.coding_formatting_log()
self.analyze_sca_log()
self.buildSummaryHeader()
self.initialGitSetup()
self.installLibsPackagesRow()
self.buildCompileRows()
self.copyToTargetImage()
self.copyConfToolsToTargetImage()
self.imageSizeRow()
self.buildSummaryFooter()
self.testSummaryHeader()
self.testSummaryFooter()
self.generateFooter()
self.file.close()
def generateHeader(self):
# HTML Header
self.file.write('<!DOCTYPE html>\n')
self.file.write('<html class="no-js" lang="en-US">\n')
self.file.write('<head>\n')
self.file.write(' <meta name="viewport" content="width=device-width, initial-scale=1">\n')
self.file.write(' <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">\n')
self.file.write(' <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>\n')
self.file.write(' <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>\n')
self.file.write(' <title>OAI Core Network Test Results for ' + self.job_name + ' job build #' + self.job_id + '</title>\n')
self.file.write('</head>\n')
self.file.write('<body><div class="container">\n')
self.file.write(' <table width = "100%" style="border-collapse: collapse; border: none;">\n')
self.file.write(' <tr style="border-collapse: collapse; border: none;">\n')
self.file.write(' <td style="border-collapse: collapse; border: none;">\n')
self.file.write(' <a href="http://www.openairinterface.org/">\n')
self.file.write(' <img src="http://www.openairinterface.org/wp-content/uploads/2016/03/cropped-oai_final_logo2.png" alt="" border="none" height=50 width=150>\n')
self.file.write(' </img>\n')
self.file.write(' </a>\n')
self.file.write(' </td>\n')
self.file.write(' <td style="border-collapse: collapse; border: none; vertical-align: center;">\n')
self.file.write(' <b><font size = "6">Job Summary -- Job: ' + self.job_name + ' -- Build-ID: <a href="' + self.job_url + '">' + self.job_id + '</a></font></b>\n')
self.file.write(' </td>\n')
self.file.write(' </tr>\n')
self.file.write(' </table>\n')
self.file.write(' <br>\n')
# Build Info Summary
buildSummary = ''
buildSummary += ' <table class="table-bordered" width = "80%" align = "center" border = "1">\n'
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-time"></span> Build Start Time</td>\n'
#date_formatted = re.sub('\..*', '', self.created)
buildSummary += ' <td>' + self.job_start_time + '</td>\n'
buildSummary += ' </tr>\n'
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-wrench"></span> Build Trigger</td>\n'
if self.git_pull_request:
buildSummary += ' <td>Pull Request</td>\n'
else:
buildSummary += ' <td>Push Event</td>\n'
buildSummary += ' </tr>\n'
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-cloud-upload"></span> GIT Repository</td>\n'
buildSummary += ' <td><a href="' + self.git_url + '">' + self.git_url + '</a></td>\n'
buildSummary += ' </tr>\n'
if self.git_pull_request:
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-log-out"></span> Source Branch</td>\n'
buildSummary += ' <td><a href="TEMPLATE_MERGE_REQUEST_LINK">TEMPLATE_MERGE_REQUEST_LINK</a></td>\n'
buildSummary += ' </tr>\n'
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-header"></span> Merge Request Title</td>\n'
buildSummary += ' <td>TEMPLATE_MERGE_REQUEST_TEMPLATE</td>\n'
buildSummary += ' </tr>\n'
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-log-out"></span> Source Branch</td>\n'
buildSummary += ' <td>' + self.git_src_branch + '</td>\n'
buildSummary += ' </tr>\n'
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tag"></span> Source Commit ID</td>\n'
buildSummary += ' <td>' + self.git_src_commit + '</td>\n'
buildSummary += ' </tr>\n'
if (self.git_src_commit_msg is not None):
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-comment"></span> Source Commit Message</td>\n'
buildSummary += ' <td>' + self.git_src_commit_msg + '</td>\n'
buildSummary += ' </tr>\n'
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-log-in"></span> Target Branch</td>\n'
buildSummary += ' <td>' + self.git_target_branch + '</td>\n'
buildSummary += ' </tr>\n'
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tag"></span> Target Commit ID</td>\n'
buildSummary += ' <td>' + self.git_target_commit + '</td>\n'
buildSummary += ' </tr>\n'
else:
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tree-deciduous"></span> Branch</td>\n'
buildSummary += ' <td>' + self.git_src_branch + '</td>\n'
buildSummary += ' </tr>\n'
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tag"></span> Commit ID</td>\n'
buildSummary += ' <td>' + self.git_src_commit + '</td>\n'
buildSummary += ' </tr>\n'
if (self.git_src_commit_msg is not None):
buildSummary += ' <tr>\n'
buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-comment"></span> Commit Message</td>\n'
buildSummary += ' <td>' + self.git_src_commit_msg + '</td>\n'
buildSummary += ' </tr>\n'
buildSummary += ' </table>\n'
buildSummary += ' <br>\n'
self.file.write(buildSummary)
cwd = os.getcwd()
for reportFile in glob.glob('./*results_oai_*.html'):
if reportFile == './test_results_oai_smf.html':
continue
newEpcReport = open(cwd + '/' + str(reportFile) + '.new', 'w')
buildSummaryDone = True
with open(cwd + '/' + str(reportFile), 'r') as originalEpcReport:
for line in originalEpcReport:
result = re.search('Deployment Summary', line)
if (result is not None) and buildSummaryDone:
newEpcReport.write(buildSummary)
buildSummaryDone = False
newEpcReport.write(line)
originalEpcReport.close()
newEpcReport.close()
os.rename(cwd + '/' + str(reportFile) + '.new', cwd + '/' + str(reportFile))
def generateFooter(self):
self.file.write(' <div class="well well-lg">End of Build Report -- Copyright <span class="glyphicon glyphicon-copyright-mark"></span> 2020 <a href="http://www.openairinterface.org/">OpenAirInterface</a>. All Rights Reserved.</div>\n')
self.file.write('</div></body>\n')
self.file.write('</html>\n')
def coding_formatting_log(self):
cwd = os.getcwd()
self.file.write(' <h2>OAI Coding / Formatting Guidelines Check</h2>\n')
if os.path.isfile(cwd + '/src/oai_rules_result.txt'):
cmd = 'grep NB_FILES_FAILING_CHECK ' + cwd + '/src/oai_rules_result.txt | sed -e "s#NB_FILES_FAILING_CHECK=##"'
nb_fail = subprocess.check_output(cmd, shell=True, universal_newlines=True)
cmd = 'grep NB_FILES_CHECKED ' + cwd + '/src/oai_rules_result.txt | sed -e "s#NB_FILES_CHECKED=##"'
nb_total = subprocess.check_output(cmd, shell=True, universal_newlines=True)
if int(nb_fail.strip()) == 0:
self.file.write(' <div class="alert alert-success">\n')
if self.git_pull_request:
self.file.write(' <strong>All modified files in Pull-Request follow OAI rules. <span class="glyphicon glyphicon-ok-circle"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n')
else:
self.file.write(' <strong>All files in repository follow OAI rules. <span class="glyphicon glyphicon-ok-circle"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n')
self.file.write(' </div>\n')
else:
self.file.write(' <div class="alert alert-danger">\n')
if self.git_pull_request:
self.file.write(' <strong>' + nb_fail.strip() + ' modified files in Pull-Request DO NOT follow OAI rules. <span class="glyphicon glyphicon-warning-sign"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n')
else:
self.file.write(' <strong>' + nb_fail.strip() + ' files in repository DO NOT follow OAI rules. <span class="glyphicon glyphicon-warning-sign"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n')
self.file.write(' </div>\n')
if os.path.isfile(cwd + '/src/oai_rules_result_list.txt'):
self.file.write(' <button data-toggle="collapse" data-target="#oai-formatting-details">More details on formatting check</button>\n')
self.file.write(' <div id="oai-formatting-details" class="collapse">\n')
self.file.write(' <p>Please apply the following command to this(ese) file(s): </p>\n')
self.file.write(' <p style="margin-left: 30px"><strong><code>cd src && clang-format -i filename(s)</code></strong></p>\n')
self.file.write(' <table class="table-bordered" width = "60%" align = "center" border = 1>\n')
self.file.write(' <tr><th bgcolor = "lightcyan" >Filename</th></tr>\n')
with open(cwd + '/src/oai_rules_result_list.txt', 'r') as filelist:
for line in filelist:
self.file.write(' <tr><td>' + line.strip() + '</td></tr>\n')
filelist.close()
self.file.write(' </table>\n')
self.file.write(' </div>\n')
else:
self.file.write(' <div class="alert alert-danger">\n')
self.file.write(' <strong>Was NOT performed (with CLANG-FORMAT tool). <span class="glyphicon glyphicon-ban-circle"></span></strong>\n')
self.file.write(' </div>\n')
self.file.write(' <br>\n')
def analyze_sca_log(self):
cwd = os.getcwd()
if os.path.isfile(cwd + '/archives/cppcheck_build.log'):
self.file.write(' <h2>Static Code Analysis</h2>\n')
if os.path.isfile(cwd + '/archives/cppcheck.xml'):
nb_errors = 0
nb_warnings = 0
nb_uninitvar = 0
nb_uninitStructMember = 0
nb_memleak = 0
nb_doubleFree = 0
nb_resourceLeak = 0
nb_nullPointer = 0
nb_arrayIndexOutOfBounds = 0
nb_bufferAccessOutOfBounds = 0
nb_unknownEvaluationOrder = 0
with open(cwd + '/archives/cppcheck.xml', 'r') as xmlfile:
for line in xmlfile:
result = re.search('severity="warning"', line)
if result is not None:
nb_warnings += 1
result = re.search('severity="error"', line)
if result is not None:
nb_errors += 1
result = re.search('uninitvar', line)
if result is not None:
nb_uninitvar += 1
result = re.search('uninitStructMember', line)
if result is not None:
nb_uninitStructMember += 1
result = re.search('memleak', line)
if result is not None:
nb_memleak += 1
result = re.search('doubleFree', line)
if result is not None:
nb_doubleFree += 1
result = re.search('resourceLeak', line)
if result is not None:
nb_resourceLeak += 1
result = re.search('nullPointer', line)
if result is not None:
nb_nullPointer += 1
result = re.search('arrayIndexOutOfBounds', line)
if result is not None:
nb_arrayIndexOutOfBounds += 1
result = re.search('bufferAccessOutOfBounds', line)
if result is not None:
nb_bufferAccessOutOfBounds += 1
result = re.search('unknownEvaluationOrder', line)
if result is not None:
nb_unknownEvaluationOrder += 1
xmlfile.close()
if (nb_errors == 0) and (nb_warnings == 0):
self.file.write(' <div class="alert alert-success">\n')
self.file.write(' <strong>CPPCHECK found NO error and NO warning <span class="glyphicon glyphicon-ok-circle"></span></strong>\n')
self.file.write(' </div>\n')
elif (nb_errors == 0):
self.file.write(' <div class="alert alert-warning">\n')
self.file.write(' <strong>CPPCHECK found NO error and ' + str(nb_warnings) + ' warnings <span class="glyphicon glyphicon-warning-sign"></span></strong>\n')
self.file.write(' </div>\n')
else:
self.file.write(' <div class="alert alert-danger">\n')
self.file.write(' <strong>CPPCHECK found ' + str(nb_errors) + ' errors and ' + str(nb_warnings) + ' warnings <span class="glyphicon glyphicon-ban-circle"></span></strong>\n')
self.file.write(' </div>\n')
if (nb_errors > 0) or (nb_warnings > 0):
self.file.write(' <button data-toggle="collapse" data-target="#oai-cppcheck-details">More details on CPPCHECK results</button>\n')
self.file.write(' <div id="oai-cppcheck-details" class="collapse">\n')
self.file.write(' <br>\n')
self.file.write(' <table class="table-bordered" width = "80%" align = "center" border = "1">\n')
self.file.write(' <tr bgcolor = "#33CCFF" >\n')
self.file.write(' <th>Error / Warning Type</th>\n')
self.file.write(' <th>Nb Errors</th>\n')
self.file.write(' <th>Nb Warnings</th>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Uninitialized variable</td>\n')
self.file.write(' <td>' + str(nb_uninitvar) + '</td>\n')
self.file.write(' <td>N/A</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Uninitialized struct member</td>\n')
self.file.write(' <td>' + str(nb_uninitStructMember) + '</td>\n')
self.file.write(' <td>N/A</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Memory leak</td>\n')
self.file.write(' <td>' + str(nb_memleak) + '</td>\n')
self.file.write(' <td>N/A</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Memory is freed twice</td>\n')
self.file.write(' <td>' + str(nb_doubleFree) + '</td>\n')
self.file.write(' <td>N/A</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Resource leak</td>\n')
self.file.write(' <td>' + str(nb_resourceLeak) + '</td>\n')
self.file.write(' <td>N/A</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Possible null pointer dereference</td>\n')
self.file.write(' <td>' + str(nb_nullPointer) + '</td>\n')
self.file.write(' <td>N/A</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Array access out of bounds</td>\n')
self.file.write(' <td>' + str(nb_arrayIndexOutOfBounds) + '</td>\n')
self.file.write(' <td>N/A</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Buffer is accessed out of bounds</td>\n')
self.file.write(' <td>' + str(nb_bufferAccessOutOfBounds) + '</td>\n')
self.file.write(' <td>N/A</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Expression depends on order of evaluation of side effects</td>\n')
self.file.write(' <td>' + str(nb_unknownEvaluationOrder) + '</td>\n')
self.file.write(' <td>N/A</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.file.write(' <td>Others</td>\n')
nb_others = nb_uninitvar + nb_uninitStructMember + nb_memleak + nb_doubleFree + nb_resourceLeak + nb_nullPointer + nb_arrayIndexOutOfBounds + nb_arrayIndexOutOfBounds + nb_bufferAccessOutOfBounds + nb_unknownEvaluationOrder
nb_others = nb_errors - nb_others
self.file.write(' <td>' + str(nb_others) + '</td>\n')
self.file.write(' <td>' + str(nb_warnings) + '</td>\n')
self.file.write(' </tr>\n')
self.file.write(' <tr bgcolor = "#33CCFF" >\n')
self.file.write(' <th>Total</th>\n')
self.file.write(' <th>' + str(nb_errors) + '</th>\n')
self.file.write(' <th>' + str(nb_warnings) + '</th>\n')
self.file.write(' </tr>\n')
self.file.write(' </table>\n')
self.file.write(' <br>\n')
self.file.write(' <p>Full details in artifact (cppcheck.xml) </p>\n')
self.file.write(' <p style="margin-left: 30px">Graphical Interface tool : <strong><code>cppcheck-gui -l cppcheck.xml</code></strong></p>\n')
self.file.write(' <br>\n')
self.file.write(' </div>\n')
else:
self.file.write(' <div class="alert alert-danger">\n')
self.file.write(' <strong>Was NOT performed (with CPPCHECK tool). <span class="glyphicon glyphicon-ban-circle"></span></strong>\n')
self.file.write(' </div>\n')
def buildSummaryHeader(self):
self.file.write(' <h2>Docker / Podman Image Build Summary</h2>\n')
self.file.write(' <table class="table-bordered" width = "100%" align = "center" border = "1">\n')
self.file.write(' <tr bgcolor="#33CCFF" >\n')
self.file.write(' <th>Stage Name</th>\n')
self.file.write(' <th>Image Kind</th>\n')
self.file.write(' <th>OAI SMF <font color="Gold">Ubuntu18</font> Image</th>\n')
self.file.write(' <th>OAI SMF <font color="Gold">RHEL8</font> Image</th>\n')
self.file.write(' </tr>\n')
def buildSummaryFooter(self):
self.file.write(' </table>\n')
self.file.write(' <br>\n')
if self.nb_warnings > 0:
self.file.write(' <h3>Compilation Warnings Details</h3>\n')
self.file.write(' <button data-toggle="collapse" data-target="#oai-compilation-details">Details for Compilation Errors and Warnings </button>\n')
self.file.write(' <div id="oai-compilation-details" class="collapse">\n')
self.file.write(' <table class="table-bordered">\n')
self.file.write(' <tr bgcolor = "#33CCFF" >\n')
self.file.write(' <th>File</th>\n')
self.file.write(' <th>Line Number</th>\n')
self.file.write(' <th>Status</th>\n')
self.file.write(' <th>Message</th>\n')
self.file.write(self.warning_rows)
self.file.write(' </tr>\n')
self.file.write(' </table>\n')
self.file.write(' </div>\n')
def testBuildSummaryHeader(self):
self.file.write(' <h2>Test Images Build Summary</h2>\n')
self.file.write(' <table class="table-bordered" width = "100%" align = "center" border = "1">\n')
self.file.write(' <tr bgcolor="#33CCFF" >\n')
self.file.write(' <th>Stage Name</th>\n')
self.file.write(' <th>Test AMF Server</th>\n')
self.file.write(' <th>Test AMF Client</th>\n')
self.file.write(' <th>Test UDM Server</th>\n')
self.file.write(' </tr>\n')
def testBuildSummaryFooter(self):
self.file.write(' </table>\n')
self.file.write(' <br>\n')
def initialGitSetup(self):
self.file.write(' <tr>\n')
self.file.write(' <td bgcolor="lightcyan" >Initial Git Setup</td>\n')
self.analyze_docker_build_git_part('SMF')
self.file.write(' </tr>\n')
def analyze_docker_build_git_part(self, nfType):
if nfType != 'SMF':
self.file.write(' <td>N/A</td>\n')
self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n')
return
self.file.write(' <td>Builder Image</td>\n')
cwd = os.getcwd()
variants = ['docker', 'podman']
for variant in variants:
logFileName = 'smf_' + variant + '_image_build.log'
if os.path.isfile(cwd + '/archives/' + logFileName):
status = False
section_start_pattern = 'git config --global http'
section_end_pattern = 'WORKDIR /openair-smf/build/scripts'
section_status = False
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
result = re.search(section_start_pattern, line)
if result is not None:
section_status = True
result = re.search(section_end_pattern, line)
if result is not None:
section_status = False
status = True
logfile.close()
if status:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
cell_msg += 'OK:\n'
cell_msg += ' -- All Git Operations went successfully</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO::\n'
cell_msg += ' -- Some Git Operations went WRONG</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
self.file.write(cell_msg)
def installLibsPackagesRow(self):
self.file.write(' <tr>\n')
self.file.write(' <td bgcolor="lightcyan" >SW libs and packages Installation</td>\n')
self.analyze_install_log('SMF')
self.file.write(' </tr>\n')
def analyze_install_log(self, nfType):
if nfType != 'SMF':
self.file.write(' <td>N/A</td>\n')
self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n')
return
self.file.write(' <td>Builder Image</td>\n')
cwd = os.getcwd()
variants = ['docker', 'podman']
for variant in variants:
logFileName = 'smf_' + variant + '_image_build.log'
if os.path.isfile(cwd + '/archives/' + logFileName):
status = False
section_start_pattern = 'build_smf --install-deps --force'
section_end_pattern = 'build_smf --clean --Verbose --build-type Release --jobs'
section_status = False
package_install = False
spdlog_build_start = False
spdlog_build_status = False
pistache_build_start = False
pistache_build_status = False
json_build_start = False
json_build_status = False
nghttp2_build_start = False
nghttp2_build_status = False
base_image = False
build_stage_id = 'NotAcorrectBuildStageId'
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
# old method
result = re.search('FROM oai-smf-base:latest', line)
if result is not None:
base_image = True
# new method --> buildx may cache this stage
result = re.search('^#([0-9]+).* RUN ./build_smf --install-deps', line)
if result is not None:
build_stage_id = result.group(1)
result = re.search(f'^#{build_stage_id} CACHED', line)
if result is not None:
base_image = True
result = re.search(section_start_pattern, line)
if result is not None:
section_status = True
result = re.search(section_end_pattern, line)
if result is not None:
section_status = False
if section_status:
result = re.search('SMF deps installation successful', line)
if result is not None:
status = True
result = re.search('distro libs installation complete', line)
if result is not None:
package_install = True
result = re.search('Starting to install spdlog', line)
if result is not None:
spdlog_build_start = True
result = re.search('spdlog installation complete', line)
if result is not None and spdlog_build_start:
spdlog_build_status = True
result = re.search('Starting to install pistache', line)
if result is not None:
pistache_build_start = True
result = re.search('pistache installation complete', line)
if result is not None and pistache_build_start:
pistache_build_status = True
result = re.search('Starting to install Nlohmann Json', line)
if result is not None:
json_build_start = True
result = re.search('Nlohmann Json installation complete', line)
if result is not None and json_build_start:
json_build_status = True
result = re.search('Starting to install nghttp2', line)
if result is not None:
nghttp2_build_start = True
result = re.search('nghttp2 installation complete', line)
if result is not None and nghttp2_build_start:
nghttp2_build_status = True
logfile.close()
if base_image:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
cell_msg += 'N/A:\n'
elif status:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
cell_msg += 'OK:\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO:\n'
cell_msg += ' -- build_smf --install-deps --force\n'
if base_image:
cell_msg += ' ** Packages Installation: N/A\n'
elif package_install:
cell_msg += ' ** Packages Installation: OK\n'
else:
cell_msg += ' ** Packages Installation: KO\n'
if base_image:
cell_msg += ' ** spdlog Installation: N/A\n'
elif spdlog_build_status:
cell_msg += ' ** spdlog Installation: OK\n'
else:
cell_msg += ' ** spdlog Installation: KO\n'
if base_image:
cell_msg += ' ** pistache Installation: N/A\n'
elif pistache_build_status:
cell_msg += ' ** pistache Installation: OK\n'
else:
cell_msg += ' ** pistache Installation: KO\n'
if base_image:
cell_msg += ' ** Nlohmann Json Installation: N/A\n'
elif json_build_status:
cell_msg += ' ** Nlohmann Json Installation: OK\n'
else:
cell_msg += ' ** Nlohmann Json Installation: KO\n'
if base_image:
cell_msg += ' ** nghttp2-asio Installation: N/A\n'
elif nghttp2_build_status:
cell_msg += ' ** nghttp2-asio Installation: OK\n'
else:
cell_msg += ' ** nghttp2-asio Installation: KO\n'
cell_msg += '</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
self.file.write(cell_msg)
def buildCompileRows(self):
self.file.write(' <tr>\n')
self.file.write(' <td rowspan=2 bgcolor="lightcyan" >cNF Compile / Build</td>\n')
self.analyze_build_log('SMF', True)
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.analyze_compile_log('SMF', True)
self.file.write(' </tr>\n')
def analyze_build_log(self, nfType, imageKind):
if nfType != 'SMF':
if imageKind:
self.file.write(' <td>N/A</td>\n')
self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n')
return
if imageKind:
self.file.write(' <td>Builder Image</td>\n')
cwd = os.getcwd()
variants = ['docker', 'podman']
for variant in variants:
logFileName = 'smf_' + variant + '_image_build.log'
if os.path.isfile(cwd + '/archives/' + logFileName):
status = False
if nfType == 'SMF':
section_start_pattern = 'build_smf --clean --Verbose --build-type Release --jobs'
section_end_pattern = 'FROM .* as oai-smf$'
pass_pattern = 'smf installed'
section_status = False
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
result = re.search(section_start_pattern, line)
if result is not None:
section_status = True
result = re.search(section_end_pattern, line)
if result is not None:
section_status = False
if section_status:
result = re.search(pass_pattern, line)
if result is not None:
status = True
logfile.close()
if status:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
cell_msg += 'OK:\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO:\n'
if nfType != 'SMF':
cell_msg += ' -- cd ' + path_pattern + '\n'
cell_msg += ' -- ' + section_start_pattern + '</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
self.file.write(cell_msg)
def analyze_compile_log(self, nfType, imageKind):
if nfType != 'SMF':
if imageKind:
self.file.write(' <td>N/A</td>\n')
self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n')
return
from common.python.pipeline_args_parse import (
_parse_args,
)
if imageKind:
self.file.write(' <td>Builder Image</td>\n')
from common.python.generate_html import (
generate_header,
generate_footer,
generate_git_info,
)
cwd = os.getcwd()
variants = ['docker', 'podman']
for variant in variants:
logFileName = 'smf_' + variant + '_image_build.log'
nb_errors = 0
nb_warnings = 0
if os.path.isfile(cwd + '/archives/' + logFileName):
if nfType == 'SMF':
section_start_pattern = 'build_smf --clean --Verbose --build-type Release --jobs'
section_end_pattern = 'FROM .* as oai-smf$'
section_status = False
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
result = re.search(section_start_pattern, line)
if result is not None:
section_status = True
result = re.search(section_end_pattern, line)
if result is not None:
section_status = False
if section_status:
result = re.search('error:', line)
if result is not None:
nb_errors += 1
result = re.search('warning:', line)
if result is not None:
nb_warnings += 1
if nfType == 'SMF':
correctLine = re.sub("^.*/openair-smf","/openair-smf",line.strip())
wordsList = correctLine.split(None,2)
filename = re.sub(":[0-9]*:[0-9]*:","", wordsList[0])
linenumber = re.sub(filename + ':',"", wordsList[0])
linenumber = re.sub(':[0-9]*:',"", linenumber)
error_warning_status = re.sub(':',"", wordsList[1])
error_warning_msg = re.sub('^.*' + error_warning_status + ':', '', correctLine)
self.warning_rows += '<tr><td>' + filename + '</td><td>' + linenumber + '</td><td>' + error_warning_status + '</td><td>' + error_warning_msg + '</td></tr>\n'
logfile.close()
if nb_warnings == 0 and nb_errors == 0:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
elif nb_warnings < 20 and nb_errors == 0:
cell_msg = ' <td bgcolor="Orange"><pre style="border:none; background-color:Orange"><b>'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
if nb_errors > 0:
cell_msg += str(nb_errors) + ' errors found in compile log\n'
cell_msg += str(nb_warnings) + ' warnings found in compile log</b></pre></td>\n'
if nfType == 'SMF':
self.nb_warnings = nb_warnings
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
from common.python.code_format_checker import (
coding_formatting_log_check,
)
self.file.write(cell_msg)
from common.python.static_code_analysis import (
analyze_sca_log_check,
)
def copyToTargetImage(self):
self.file.write(' <tr>\n')
self.file.write(' <td bgcolor="lightcyan" >SW libs Installation / Copy from Builder</td>\n')
self.analyze_copy_log('SMF')
self.file.write(' </tr>\n')
from common.python.building_report import (
build_summary,
)
def analyze_copy_log(self, nfType):
if nfType != 'SMF':
self.file.write(' <td>N/A</td>\n')
self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n')
return
REPORT_NAME = 'test_results_oai_smf.html'
self.file.write(' <td>Target Image</td>\n')
cwd = os.getcwd()
variants = ['docker', 'podman']
for variant in variants:
logFileName = 'smf_' + variant + '_image_build.log'
if os.path.isfile(cwd + '/archives/' + logFileName):
section_start_pattern = 'COPY --from=oai-smf-builder */openair-smf/build/smf/build/oai_smf'
section_end_pattern = 'WORKDIR /openair-smf/etc'
section_status = False
status = False
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
result = re.search(section_start_pattern, line)
if result is not None:
section_status = True
result = re.search(section_end_pattern, line)
if result is not None:
section_status = False
status = True
logfile.close()
if status:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
cell_msg += 'OK:\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO:\n'
cell_msg += '</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
self.file.write(cell_msg)
def copyConfToolsToTargetImage(self):
self.file.write(' <tr>\n')
self.file.write(' <td bgcolor="lightcyan" >Copy Template Conf / Tools from Builder</td>\n')
self.analyze_copy_conf_tool_log('SMF')
self.file.write(' </tr>\n')
def analyze_copy_conf_tool_log(self, nfType):
if nfType != 'SMF':
self.file.write(' <td>N/A</td>\n')
self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n')
return
self.file.write(' <td>Target Image</td>\n')
cwd = os.getcwd()
variants = ['docker', 'podman']
for variant in variants:
logFileName = 'smf_' + variant + '_image_build.log'
if os.path.isfile(cwd + '/archives/' + logFileName):
section_start_pattern = 'WORKDIR /openair-smf/etc'
if variant == 'docker':
section_end_pattern = 'naming to docker.io/library/oai-smf:'
else:
section_end_pattern = 'COMMIT oai-smf:'
section_status = False
status = False
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
result = re.search(section_start_pattern, line)
if result is not None:
section_status = True
result = re.search(section_end_pattern, line)
if result is not None:
section_status = False
status = True
logfile.close()
if status:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
cell_msg += 'OK:\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO:\n'
cell_msg += '</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
self.file.write(cell_msg)
def imageSizeRow(self):
self.file.write(' <tr>\n')
self.file.write(' <td bgcolor="lightcyan" >Image Size</td>\n')
self.analyze_image_size_log('SMF', True)
self.file.write(' </tr>\n')
def analyze_image_size_log(self, nfType, imageKind):
if nfType != 'SMF':
if imageKind:
self.file.write(' <td>N/A</td>\n')
self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n')
return
if imageKind:
self.file.write(' <td>Target Image</td>\n')
cwd = os.getcwd()
variants = ['docker', 'podman']
for variant in variants:
logFileName = 'smf_' + variant + '_image_build.log'
if os.path.isfile(cwd + '/archives/' + logFileName):
if nfType == 'SMF':
if variant == 'docker':
section_start_pattern = 'naming to docker.io/library/oai-smf:'
section_end_pattern = 'OAI-SMF DOCKER IMAGE BUILD'
else:
section_start_pattern = 'COMMIT oai-smf:'
section_end_pattern = 'OAI-SMF PODMAN RHEL8 IMAGE BUILD'
section_status = False
status = False
imageTag = 'notAcorrectTagForTheMoment'
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
result = re.search(f'{section_start_pattern}([0-9a-zA-Z\-\_\.]+)', line)
if result is not None:
section_status = True
imageTag = result.group(1)
result = re.search(section_end_pattern, line)
if result is not None:
section_status = False
if section_status:
if nfType == 'SMF':
result = re.search(f'oai-smf *{imageTag}', line)
if result is not None and not status:
result = re.search('ago *([0-9A-Z ]+)', line)
if result is not None:
size = result.group(1)
if variant == 'docker':
size = re.sub('MB', ' MB', size)
status = True
logfile.close()
if status:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>'
cell_msg += 'OK: ' + size + '\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO:\n'
cell_msg += '</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>'
cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n'
self.file.write(cell_msg)
def testBuildCompileRows(self):
self.file.write(' <tr>\n')
self.file.write(' <td rowspan=2 bgcolor="lightcyan" >cNF Compile / Build</td>\n')
self.analyze_build_log('AMF-Server', False)
self.analyze_build_log('AMF-Client', False)
self.analyze_build_log('UDM-Server', False)
self.file.write(' </tr>\n')
self.file.write(' <tr>\n')
self.analyze_compile_log('AMF-Server', False)
self.analyze_compile_log('AMF-Client', False)
self.analyze_compile_log('UDM-Server', False)
self.file.write(' </tr>\n')
def testImageSizeRow(self):
self.file.write(' <tr>\n')
self.file.write(' <td bgcolor="lightcyan" >Image Size</td>\n')
self.analyze_image_size_log('AMF-Server', False)
self.analyze_image_size_log('AMF-Client', False)
self.analyze_image_size_log('UDM-Server', False)
self.file.write(' </tr>\n')
def sanityCheckSummaryHeader(self):
self.file.write(' <h2>Sanity Check Deployment Summary</h2>\n')
self.file.write(' <table class="table-bordered" width = "100%" align = "center" border = "1">\n')
self.file.write(' <tr bgcolor="#33CCFF" >\n')
self.file.write(' <th>Stage Name</th>\n')
self.file.write(' <th>OAI SMF cNF</th>\n')
self.file.write(' <th>OAI SPGWU (as UPF) cNF</th>\n')
self.file.write(' <th>Test AMF-Server</th>\n')
self.file.write(' <th>Test UDM-Server</th>\n')
self.file.write(' <th>Test AMF-Client</th>\n')
self.file.write(' </tr>\n')
def sanityCheckSummaryFooter(self):
self.file.write(' </table>\n')
self.file.write(' <br>\n')
def sanityCheckDeployRow(self):
self.file.write(' <tr>\n')
self.file.write(' <td bgcolor="lightcyan" >Container Start</td>\n')
cwd = os.getcwd()
if os.path.isfile(cwd + '/archives/amf_server_config.log') and os.path.isfile(cwd + '/archives/udm_server_config.log') and os.path.isfile(cwd + '/archives/amf_client_config.log'):
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>OK</b></pre></td>\n'
for x in range(0, 5):
self.file.write(cell_msg)
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>KO?</b></pre></td>\n'
for x in range(0, 5):
self.file.write(cell_msg)
self.file.write(' </tr>\n')
def sanityCheckTestRow(self):
self.file.write(' <tr>\n')
self.file.write(' <td bgcolor="lightcyan" >Local Test</td>\n')
cwd = os.getcwd()
if os.path.isfile(cwd + '/archives/smf_check_run.log'):
nb_sm_req_from_amf = 0
nb_pdu_create_smf_req = 0
nb_encode_pdu_establish_accept = 0
nb_pdu_session_pending = 0
nb_pdu_session_ue_establish_req = 0
nb_pdu_status_active = 0
with open(cwd + '/archives/smf_check_run.log', 'r') as logfile:
for line in logfile:
result = re.search('Received a SM context create request from AMF', line)
if result is not None:
nb_sm_req_from_amf += 1
result = re.search('PDU Session Create SM Context Request', line)
if result is not None:
nb_pdu_create_smf_req += 1
result = re.search('Encode PDU Session Establishment Accept', line)
if result is not None:
nb_encode_pdu_establish_accept += 1
result = re.search('Set PDU Session Status to PDU_SESSION_ESTABLISHMENT_PENDING', line)
if result is not None:
nb_pdu_session_pending += 1
result = re.search('PDU_SESSION_ESTABLISHMENT_UE_REQUESTED', line)
if result is not None:
nb_pdu_session_ue_establish_req += 1
result = re.search('Set PDU Session Status to PDU_SESSION_ACTIVE', line)
if result is not None:
nb_pdu_status_active += 1
logfile.close()
if nb_sm_req_from_amf > 0 and nb_pdu_create_smf_req > 0 and nb_encode_pdu_establish_accept > 0 and nb_pdu_session_pending > 0 and nb_pdu_session_ue_establish_req > 0 and nb_pdu_status_active > 0:
cell_msg = ' <td colspan = "5" bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>OK:\n'
else:
cell_msg = ' <td colspan = "5" bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>KO:\n'
if nb_sm_req_from_amf > 0:
cell_msg += ' -- Received a SM context create request from AMF : OK\n'
else:
cell_msg += ' -- Received a SM context create request from AMF : KO\n'
if nb_pdu_create_smf_req > 0:
cell_msg += ' -- PDU Session Create SM Context Request : OK\n'
else:
cell_msg += ' -- PDU Session Create SM Context Request : KO\n'
if nb_encode_pdu_establish_accept > 0:
cell_msg += ' -- Encode PDU Session Establishment Accept : OK\n'
else:
cell_msg += ' -- Encode PDU Session Establishment Accept : KO\n'
if nb_pdu_session_pending > 0:
cell_msg += ' -- PDU Session Status to PDU_SESSION_ESTABLISHMENT_PENDING : OK\n'
else:
cell_msg += ' -- PDU Session Status to PDU_SESSION_ESTABLISHMENT_PENDING : KO\n'
if nb_pdu_session_ue_establish_req > 0:
cell_msg += ' -- PDU_SESSION_ESTABLISHMENT_UE_REQUESTED : OK\n'
else:
cell_msg += ' -- PDU_SESSION_ESTABLISHMENT_UE_REQUESTED : KO\n'
if nb_pdu_status_active > 0:
cell_msg += ' -- Set PDU Session Status to PDU_SESSION_ACTIVE : OK\n'
else:
cell_msg += ' -- Set PDU Session Status to PDU_SESSION_ACTIVE : KO\n'
cell_msg += '</b></pre></td>\n'
else:
cell_msg = ' <td colspan = "5" bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>KO?</b></pre></td>\n'
self.file.write(cell_msg)
self.file.write(' </tr>\n')
def sanityCheckConfigRow(self):
self.file.write(' <tr>\n')
self.file.write(' <td bgcolor="lightcyan" >Container Config</td>\n')
cwd = os.getcwd()
if os.path.isfile(cwd + '/archives/smf_config.log'):
cmd = 'grep -c OK ' + cwd + '/archives/smf_config.log'
try:
is_ok = subprocess.check_output(cmd, shell=True, universal_newlines=True)
except:
is_ok = '0'
if int(is_ok.strip()) == 0:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>KO?</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>OK</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>KO?</b></pre></td>\n'
self.file.write(cell_msg)
if os.path.isfile(cwd + '/archives/spgwu_config.log'):
cmd = 'grep -c OK ' + cwd + '/archives/spgwu_config.log'
try:
is_ok = subprocess.check_output(cmd, shell=True, universal_newlines=True)
except:
is_ok = '0'
if int(is_ok.strip()) == 0:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>KO?</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>OK</b></pre></td>\n'
else:
cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>KO?</b></pre></td>\n'
self.file.write(cell_msg)
cell_msg = ' <td bgcolor="LightGray"><pre style="border:none; background-color:LightGray">N/A</pre></td>\n'
for x in range(0, 3):
self.file.write(cell_msg)
self.file.write(' </tr>\n')
def testSummaryHeader(self):
self.file.write(' <h2>Test Summary</h2>\n')
self.file.write(' <div class="alert alert-warning">\n')
self.file.write(' <strong>Not performed yet. <span class="glyphicon glyphicon-warning-sign"></span></strong>\n')
self.file.write(' </div>\n')
def testSummaryFooter(self):
self.file.write(' <br>\n')
def Usage():
print('----------------------------------------------------------------------------------------------------------------------')
print('generateHtmlReport.py')
print(' Generate an HTML report for the Jenkins pipeline on openair-smf.')
print('----------------------------------------------------------------------------------------------------------------------')
print('Usage: python3 generateHtmlReport.py [options]')
print(' --help Show this help.')
print('---------------------------------------------------------------------------------------------- Mandatory Options -----')
print(' --job_name=[Jenkins Job name]')
print(' --job_id=[Jenkins Job Build ID]')
print(' --job_url=[Jenkins Job Build URL]')
print(' --git_url=[Git Repository URL]')
print(' --git_src_branch=[Git Source Branch Name]')
print(' --git_src_commit=[Git Source Commit SHA-ONE]')
print('----------------------------------------------------------------------------------------------- Optional Options -----')
print(' --git_pull_request=True')
print(' --git_target_branch=[Git Target Branch Name]')
print(' --git_target_commit=[Git Target Commit SHA-ONE]')
#--------------------------------------------------------------------------------------------------------
#
# Start of main
#
#--------------------------------------------------------------------------------------------------------
argvs = sys.argv
argc = len(argvs)
HTML = HtmlReport()
while len(argvs) > 1:
myArgv = argvs.pop(1)
if re.match('^\-\-help$', myArgv, re.IGNORECASE):
Usage()
sys.exit(0)
elif re.match('^\-\-job_name=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-job_name=(.+)$', myArgv, re.IGNORECASE)
HTML.job_name = matchReg.group(1)
elif re.match('^\-\-job_id=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-job_id=(.+)$', myArgv, re.IGNORECASE)
HTML.job_id = matchReg.group(1)
elif re.match('^\-\-job_url=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-job_url=(.+)$', myArgv, re.IGNORECASE)
HTML.job_url = matchReg.group(1)
elif re.match('^\-\-git_url=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-git_url=(.+)$', myArgv, re.IGNORECASE)
HTML.git_url = matchReg.group(1)
elif re.match('^\-\-git_src_branch=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-git_src_branch=(.+)$', myArgv, re.IGNORECASE)
HTML.git_src_branch = matchReg.group(1)
elif re.match('^\-\-git_src_commit=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-git_src_commit=(.+)$', myArgv, re.IGNORECASE)
HTML.git_src_commit = matchReg.group(1)
elif re.match('^\-\-git_src_commit_msg=(.+)$', myArgv, re.IGNORECASE):
# Not Mandatory
matchReg = re.match('^\-\-git_src_commit_msg=(.+)$', myArgv, re.IGNORECASE)
HTML.git_src_commit_msg = matchReg.group(1)
elif re.match('^\-\-git_pull_request=(.+)$', myArgv, re.IGNORECASE):
# Can be silent: would be false!
matchReg = re.match('^\-\-git_pull_request=(.+)$', myArgv, re.IGNORECASE)
if matchReg.group(1) == 'true' or matchReg.group(1) == 'True':
HTML.git_pull_request = True
elif re.match('^\-\-git_target_branch=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-git_target_branch=(.+)$', myArgv, re.IGNORECASE)
HTML.git_target_branch = matchReg.group(1)
elif re.match('^\-\-git_target_commit=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-git_target_commit=(.+)$', myArgv, re.IGNORECASE)
HTML.git_target_commit = matchReg.group(1)
else:
sys.exit('Invalid Parameter: ' + myArgv)
if HTML.job_name == '' or HTML.job_id == '' or HTML.job_url == '':
sys.exit('Missing Parameter in job description')
if HTML.git_url == '' or HTML.git_src_branch == '' or HTML.git_src_commit == '':
sys.exit('Missing Parameter in Git Repository description')
if HTML.git_pull_request:
if HTML.git_target_commit == '' or HTML.git_target_branch == '':
sys.exit('Missing Parameter in Git Pull Request Repository description')
HTML.generate()
class HtmlReport():
def __init__(self):
pass
def generate(self, args):
cwd = os.getcwd()
with open(os.path.join(cwd, REPORT_NAME), 'w') as wfile:
wfile.write(generate_header(args))
wfile.write(generate_git_info(args))
wfile.write(build_summary(args, 'smf', '18', '8'))
wfile.write(coding_formatting_log_check(args))
wfile.write(analyze_sca_log_check())
wfile.write(generate_footer())
def appendToTestReports(self, args):
gitInfo = generate_git_info(args)
cwd = os.getcwd()
for reportFile in os.listdir(cwd):
if reportFile.endswith('.html') and re.search('results_oai_cn5g_', reportFile) is not None:
newFile = ''
gitInfoAppended = False
with open(os.path.join(cwd, reportFile), 'r') as rfile:
for line in rfile:
if re.search('<h2>', line) is not None and not gitInfoAppended:
gitInfoAppended = True
newFile += gitInfo
newFile += line
with open(os.path.join(cwd, reportFile), 'w') as wfile:
wfile.write(newFile)
if __name__ == '__main__':
# Parse the arguments
args = _parse_args()
# Generate report
HTML = HtmlReport()
HTML.generate(args)
HTML.appendToTestReports(args)
#/*
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements. See the NOTICE file distributed with
# * this work for additional information regarding copyright ownership.
# * The OpenAirInterface Software Alliance licenses this file to You under
# * the OAI Public License, Version 1.1 (the "License"); you may not use this file
# * except in compliance with the License.
# * You may obtain a copy of the License at
# *
# * http://www.openairinterface.org/?page_id=698
# *
# * Unless required by applicable law or agreed to in writing, software
# * distributed under the License is distributed on an "AS IS" BASIS,
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# * See the License for the specific language governing permissions and
# * limitations under the License.
# *-------------------------------------------------------------------------------
# * For more information about the OpenAirInterface (OAI) Software Alliance:
# * contact@openairinterface.org
# */
#---------------------------------------------------------------------
import os
import re
import sys
import subprocess
class verifySanityCheckDeployment():
def __init__(self):
self.job_name = ''
self.smf_pdu_check = False
def checkLogs(self):
if self.smf_pdu_check:
smf_status = self.analyze_pdu_scenario_log('SMF')
if not smf_status:
sys.exit('Local Test went wrong')
else:
print ('Local Test is OK')
return
smf_status = self.analyze_check_run_log('SMF')
spgwu_status = self.analyze_check_run_log('SPGW-U')
if not smf_status:
print ('SMF did not deploy properly')
if not spgwu_status:
print ('SPGW-U did not deploy properly')
if not smf_status or not spgwu_status:
sys.exit('Sanity Check Deployment went wrong')
else:
print ('Sanity Check Deployment is OK')
def analyze_pdu_scenario_log(self, nfType):
if nfType != 'SMF':
return False
logFileName = nfType.lower().replace('-','') + '_check_run.log'
cwd = os.getcwd()
status = False
if os.path.isfile(cwd + '/archives/' + logFileName):
myCmd = 'iconv -f ISO-8859-1 -t UTF-8//TRANSLIT ' + cwd + '/archives/' + logFileName + ' -o ' + cwd + '/archives/' + logFileName + '.conv'
subprocess.run(myCmd, shell=True)
myCmd = 'mv ' + cwd + '/archives/' + logFileName + '.conv ' + cwd + '/archives/' + logFileName
subprocess.run(myCmd, shell=True)
nb_sm_req_from_amf = 0
nb_pdu_create_smf_req = 0
nb_encode_pdu_establish_accept = 0
nb_pdu_session_pending = 0
nb_pdu_session_ue_establish_req = 0
nb_pdu_status_active = 0
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
result = re.search('Received a SM context create request from AMF', line)
if result is not None:
nb_sm_req_from_amf += 1
result = re.search('PDU Session Create SM Context Request', line)
if result is not None:
nb_pdu_create_smf_req += 1
result = re.search('Encode PDU Session Establishment Accept', line)
if result is not None:
nb_encode_pdu_establish_accept += 1
result = re.search('Set PDU Session Status to PDU_SESSION_ESTABLISHMENT_PENDING', line)
if result is not None:
nb_pdu_session_pending += 1
result = re.search('PDU_SESSION_ESTABLISHMENT_UE_REQUESTED', line)
if result is not None:
nb_pdu_session_ue_establish_req += 1
result = re.search('Set PDU Session Status to PDU_SESSION_ACTIVE', line)
if result is not None:
nb_pdu_status_active += 1
logfile.close()
if nb_sm_req_from_amf > 0 and nb_pdu_create_smf_req > 0 and nb_encode_pdu_establish_accept > 0 and nb_pdu_session_pending > 0 and nb_pdu_session_ue_establish_req > 0 and nb_pdu_status_active > 0:
status = True
return status
def analyze_check_run_log(self, nfType):
logFileName = nfType.lower().replace('-','') + '_check_run.log'
cwd = os.getcwd()
status = False
if os.path.isfile(cwd + '/archives/' + logFileName):
myCmd = 'iconv -f ISO-8859-1 -t UTF-8//TRANSLIT ' + cwd + '/archives/' + logFileName + ' -o ' + cwd + '/archives/' + logFileName + '.conv'
subprocess.run(myCmd, shell=True)
myCmd = 'mv ' + cwd + '/archives/' + logFileName + '.conv ' + cwd + '/archives/' + logFileName
subprocess.run(myCmd, shell=True)
nb_pfcp_hb_proc = 0
nb_sx_hb_resp = 0
nb_sx_hb_req = 0
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
if nfType == 'SPGW-U':
result = re.search('PFCP HEARTBEAT PROCEDURE', line)
if result is not None:
nb_pfcp_hb_proc += 1
result = re.search('SX HEARTBEAT RESPONSE', line)
if result is not None:
nb_sx_hb_resp += 1
result = re.search('SX HEARTBEAT REQUEST', line)
if result is not None:
nb_sx_hb_req += 1
if nfType == 'SMF':
result = re.search('PFCP HEARTBEAT PROCEDURE', line)
if result is not None:
nb_pfcp_hb_proc += 1
result = re.search('Sending HEARTBEAT_REQUEST', line)
if result is not None:
nb_sx_hb_resp += 1
result = re.search('Sending HEARTBEAT_RESPONSE', line)
if result is not None:
nb_sx_hb_req += 1
logfile.close()
if nfType == 'SMF':
if nb_pfcp_hb_proc > 0:
status = True
if nfType == 'SPGW-U':
if nb_pfcp_hb_proc > 0 and nb_sx_hb_resp > 0 and nb_sx_hb_req > 0:
status = True
return status
def Usage():
print('----------------------------------------------------------------------------------------------------------------------')
print('verifySanityCheckDeployment.py')
print(' Verify the Sanity Check Deployment in the pipeline.')
print('----------------------------------------------------------------------------------------------------------------------')
print('Usage: python3 verifySanityCheckDeployment.py [options]')
print(' --help Show this help.')
print('---------------------------------------------------------------------------------------------- Mandatory Options -----')
print(' --job_name=[Jenkins Job name]')
print(' --job_id=[Jenkins Job Build ID]')
print(' --smf_pdu_check')
#--------------------------------------------------------------------------------------------------------
#
# Start of main
#
#--------------------------------------------------------------------------------------------------------
argvs = sys.argv
argc = len(argvs)
vscd = verifySanityCheckDeployment()
while len(argvs) > 1:
myArgv = argvs.pop(1)
if re.match('^\-\-help$', myArgv, re.IGNORECASE):
Usage()
sys.exit(0)
elif re.match('^\-\-job_name=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-job_name=(.+)$', myArgv, re.IGNORECASE)
vscd.job_name = matchReg.group(1)
elif re.match('^\-\-job_id=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-job_id=(.+)$', myArgv, re.IGNORECASE)
vscd.job_id = matchReg.group(1)
elif re.match('^\-\-smf_pdu_check', myArgv, re.IGNORECASE):
vscd.smf_pdu_check = True
else:
sys.exit('Invalid Parameter: ' + myArgv)
if vscd.job_name == '' or vscd.job_id == '':
sys.exit('Missing Parameter in job description')
vscd.checkLogs()
......@@ -65,21 +65,22 @@ RUN git config --global https.postBuffer 123289600 && \
# Copying source code
WORKDIR /openair-smf
COPY ./build/scripts /openair-smf/build/scripts
COPY ./build/common-build /openair-smf/build/common-build
COPY ./build/smf/CMakeLists.txt /openair-smf/build/smf/CMakeLists.txt
COPY ./build/cmake_modules /openair-smf/cmake_modules
# Installing all the needed libraries/packages to build and run SMF
WORKDIR /openair-smf/build/scripts
RUN ./build_smf --install-deps --force
COPY . /openair-smf
# Building SMF
WORKDIR /openair-smf/build/scripts
COPY . /openair-smf
RUN ldconfig && \
./build_smf --clean --Verbose --build-type Release --jobs && \
ldd /openair-smf/build/smf/build/smf && \
mv /openair-smf/build/smf/build/smf /openair-smf/build/smf/build/oai_smf && \
sed -i -e "s@nf-root-folder@smf@" -e "s@nf-config-file@smf.conf@" \
../common-build/docker-scripts/entrypoint.py && \
# Remove entitlements and Subscription Manager configs
rm -rf /etc/pki/entitlement && \
rm -rf /etc/rhsm
......
......@@ -50,8 +50,8 @@ RUN git config --global https.postBuffer 123289600 && \
# Copying source code
WORKDIR /openair-smf
COPY ./build/scripts /openair-smf/build/scripts
COPY ./build/common-build /openair-smf/build/common-build
COPY ./build/smf/CMakeLists.txt /openair-smf/build/smf/CMakeLists.txt
COPY ./build/cmake_modules /openair-smf/cmake_modules
# Installing all the needed libraries/packages to build and run SMF
WORKDIR /openair-smf/build/scripts
......@@ -68,7 +68,9 @@ WORKDIR /openair-smf/build/scripts
RUN ldconfig && \
./build_smf --clean --Verbose --build-type Release --jobs && \
ldd /openair-smf/build/smf/build/smf && \
mv /openair-smf/build/smf/build/smf /openair-smf/build/smf/build/oai_smf
mv /openair-smf/build/smf/build/smf /openair-smf/build/smf/build/oai_smf && \
sed -i -e "s@nf-root-folder@smf@" -e "s@nf-config-file@smf.conf@" \
../common-build/docker-scripts/entrypoint.py
#---------------------------------------------------------------------
# TARGET IMAGE
......@@ -116,7 +118,7 @@ RUN apt-get update && \
WORKDIR /openair-smf/bin
COPY --from=oai-smf-builder \
/openair-smf/build/smf/build/oai_smf \
/openair-smf/scripts/entrypoint.py \
/openair-smf/build/common-build/docker-scripts/entrypoint.py \
/openair-smf/scripts/healthcheck.sh \
./
......
......@@ -220,7 +220,7 @@ add_definitions("-DPACKAGE_BUGREPORT=\"openaircn-user@lists.eurecom.fr\"")
# Include CMake modules to find other library
###############################################################################
set(CMAKE_MODULE_PATH "${OPENAIRCN_DIR}/build/cmake_modules" "${CMAKE_MODULE_PATH}")
set(CMAKE_MODULE_PATH "${OPENAIRCN_DIR}/build/common-build/cmake_modules" "${CMAKE_MODULE_PATH}")
include(FindPkgConfig)
###############################################################################
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment