1132 lines
47 KiB
CMake
Executable File
1132 lines
47 KiB
CMake
Executable 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)
|