kbuild_system.cmake 47.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
# Provide way for create kernel modules, and perform other actions on them
# in a way similar to standard cmake executables and libraries processing.
#
# NB: At the end of the whole configuration stage
#   kbuild_finalize_linking()
# should be executed.
#
# Should be included after:
#  find_package(Kbuild)
#
# Cached variables(ADVANCED), which affects on definitions below:
#  CROSS_COMPILE - corresponded parameter for 'make' to build kernel objects.
#  KBUILD_C_FLAGS - Additional kbuild flags for all builds
#  KBUILD_C_FLAGS{DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL} - per-configuration flags.

include(cmake_useful)

# Compute path to the auxiliary files.
get_filename_component(kbuild_this_module_dir ${CMAKE_CURRENT_LIST_FILE} PATH)
set(kbuild_aux_dir "${kbuild_this_module_dir}/kbuild_system_files")

# _declare_per_build_vars(<variable> <doc-pattern>)
#
# [INTERNAL] Per-build type definitions for given <variable>.
# 
# Create CACHE STRING variables <variable>_{DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL}
# with documentation string <doc-pattern> where %build% is replaced
# with corresponded build type description.
#
# Default value for variable <variable>_<type> is taken from <variable>_<type>_INIT.
macro(_declare_per_build_vars variable doc_pattern)
    set(_build_type)
    foreach(t
        RELEASE "release"
        DEBUG "debug"
        RELWITHDEBINFO "Release With Debug Info"
        MINSIZEREL "release minsize"
    )
        if(_build_type)
            string(REPLACE "%build%" "${t}" _docstring ${doc_pattern})
            set("${variable}_${_build_type}" "${${variable}_${_build_type}_INIT}"
                CACHE STRING "${_docstring}")
            set(_build_type)
        else(_build_type)
            set(_build_type "${t}")
        endif(_build_type)
    endforeach(t)
endmacro(_declare_per_build_vars variable doc_pattern)


# Default compiler flags.
#
# These flags are used directly when configuring 'Kbuild', so them should be
# expressed as single-string, where different flags are joinged using ' '.
set(KBUILD_C_FLAGS "" CACHE STRING
    "Compiler flags used by Kbuild system during all builds."
)

# Additional default compiler flags per build type.
set(KBUILD_C_FLAGS_DEBUG_INIT "-g")
set(KBUILD_C_FLAGS_RELWITHDEBINFO_INIT "-g")

_declare_per_build_vars(KBUILD_C_FLAGS
    "Compiler flags used by Kbuild system during %build% builds."
)
mark_as_advanced(
    KBUILD_C_FLAGS
    KBUILD_C_FLAGS_DEBUG
    KBUILD_C_FLAGS_RELEASE
    KBUILD_C_FLAGS_RELWITHDEBINFO
    KBUILD_C_FLAGS_MINSIZEREL
)


# Additional definitions which are passed directly to 'make' for
# kbuild process.
#
# Unlike to compiler flags, these ones are expressed using cmake list.
set(KBUILD_MAKE_FLAGS "" CACHE STRING
    "Make flags used by Kbuild system during all builds."
)

_declare_per_build_vars(KBUILD_MAKE_FLAGS
    "Make flags used by Kbuild system during %build% builds."
)

mark_as_advanced(
    KBUILD_MAKE_FLAGS
    KBUILD_MAKE_FLAGS_DEBUG
    KBUILD_MAKE_FLAGS_RELEASE
    KBUILD_MAKE_FLAGS_RELWITHDEBINFO
    KBUILD_MAKE_FLAGS_MINSIZEREL
)

set(CROSS_COMPILE "" CACHE STRING "Cross compilation prefix for build linux kernel objects.")
mark_as_advanced(CROSS_COMPILE)

# Property prefixed with 'KMODULE_' is readonly for outer use,
# unless explicitely noted in its description.

# Property is set for every target described kernel module.
# Concrete property's value currently has no special meaning.
define_property(TARGET PROPERTY KMODULE_TYPE
    BRIEF_DOCS "Whether given target describes kernel module."
    FULL_DOCS "Whether given target describes kernel module."
)

# Absolute filename of .ko file which is built.
# NOTE: Imported targets use
#  KMODULE_IMPORTED_MODULE_LOCATION
# property instead.
define_property(TARGET PROPERTY KMODULE_MODULE_LOCATION
    BRIEF_DOCS "Location of the built kernel module."
    FULL_DOCS "Location of the built kernel module."
)

# Name of the given module, like "ext4" or "kedr".
define_property(TARGET PROPERTY KMODULE_MODULE_NAME
    BRIEF_DOCS "Name of the kernel module."
    FULL_DOCS "Name of the kernel module."
)


# Absolute filename of Module.symvers file which is built.
# NOTE: Imported targets use
#  KMODULE_IMPORTED_SYMVERS_LOCATION
# property instead.
define_property(TARGET PROPERTY KMODULE_SYMVERS_LOCATION
    BRIEF_DOCS "Location of the symvers file of the kernel module."
    FULL_DOCS "Location of the symvers file of the kernel module."
)

# Property is "TRUE" for every target described imported kernel module,
# "FALSE" for other targets described kernel module.
define_property(TARGET PROPERTY KMODULE_IMPORTED
    BRIEF_DOCS "Whether given target describes imported kernel module."
    FULL_DOCS "Whether given target describes imported kernel module."
)

# Absolute filename of .ko file which is imported.
# Property may be set after
#  kbuild_add_module(... IMPORTED)
# for allow loading of given module or perform other actions required
# kernel module itself.
#
# Analogue for KMODULE_MODULE_LOCATION property of normal(non-exported)
# kernel module target.
define_property(TARGET PROPERTY KMODULE_IMPORTED_MODULE_LOCATION
    BRIEF_DOCS "Location of the imported kernel module."
    FULL_DOCS "Location of the imported kernel module."
)

# Absolute filename of Module.symvers file for imported kernel module.
# Property may be set after
#  kbuild_add_module(... IMPORTED)
# for allow linking with given module or perform other actions required
# its symbols.
#
# Analogue for KMODULE_MODULE_SYMVERS_LOCATION property of normal(non-exported)
# kernel module target.
define_property(TARGET PROPERTY KMODULE_IMPORTED_SYMVERS_LOCATION
    BRIEF_DOCS "Location of the symvers file for imported kernel module."
    FULL_DOCS "Location of the symvers file for imported kernel module."
)

# Helpers for simple extract some kernel module properties.

#  kbuild_get_module_location(RESULT_VAR name)
#
# Return location of the module, determined by the property
# KMODULE_MODULE_LOCATION or KMODULE_IMPORTED_MODULE_LOCATION for
# imported target. In the last case the property is checked for being set.
function(kbuild_get_module_location RESULT_VAR name)
    if(NOT TARGET ${name})
        message(FATAL_ERROR "\"${name}\" is not really a target.")
    endif(NOT TARGET ${name})
    get_property(kmodule_type TARGET ${name} PROPERTY KMODULE_TYPE)
    if(NOT kmodule_type)
        message(FATAL_ERROR "\"${name}\" is not really a target for kernel module.")
    endif(NOT kmodule_type)
    get_property(kmodule_imported TARGET ${name} PROPERTY KMODULE_IMPORTED)
    if(kmodule_imported)
        get_property(module_location TARGET ${name} PROPERTY KMODULE_IMPORTED_MODULE_LOCATION)
        if(NOT module_location)
            message(FATAL_ERROR "target \"${name}\" for imported module has no property KMODULE_IMPORTED_MODULE_LOCATION set.")
        endif(NOT module_location)
    else(kmodule_imported)
        get_property(module_location TARGET ${name} PROPERTY KMODULE_MODULE_LOCATION)
    endif(kmodule_imported)
    set(${RESULT_VAR} ${module_location} PARENT_SCOPE)
endfunction(kbuild_get_module_location RESULT_VAR module)

#  kbuild_get_symvers_location(RESULT_VAR name)
#
# Return location of the symvers file for the module, determined by the
# property KMODULE_SYMVERS_LOCATION or KMODULE_IMPORTED_SYMVERS_LOCATION
# for imported target. In the last case the property is checked for being set.
function(kbuild_get_symvers_location RESULT_VAR name)
    if(NOT TARGET ${name})
        message(FATAL_ERROR "\"${name}\" is not really a target.")
    endif(NOT TARGET ${name})
    get_property(kmodule_type TARGET ${name} PROPERTY KMODULE_TYPE)
    if(NOT kmodule_type)
        message(FATAL_ERROR "\"${name}\" is not really a target for kernel module.")
    endif(NOT kmodule_type)
    get_property(kmodule_imported TARGET ${name} PROPERTY KMODULE_IMPORTED)
    if(kmodule_imported)
        get_property(symvers_location TARGET ${name} PROPERTY KMODULE_IMPORTED_SYMVERS_LOCATION)
        if(NOT symvers_location)
            message(FATAL_ERROR "target \"${name}\" for imported module has no property KMODULE_IMPORTED_SYMVERS_LOCATION set.")
        endif(NOT symvers_location)
    else(kmodule_imported)
        get_property(symvers_location TARGET ${name} PROPERTY KMODULE_SYMVERS_LOCATION)
    endif(kmodule_imported)
    set(${RESULT_VAR} ${symvers_location} PARENT_SCOPE)
endfunction(kbuild_get_symvers_location RESULT_VAR module)

#  kbuild_add_module(<name> [EXCLUDE_FROM_ALL] [MODULE_NAME <module_name>] [<sources> ...])
#
# Build kernel module from <sources>, analogue of add_library().
#
# Source files are divided into two categories:
# -Object sources
# -Other sourses
#
# Object sources are those sources, which may be used in building kernel
# module externally.
# Follow types of object sources are supported now:
# .c: a file with the code in C language;
# .S: a file with the code in assembly language;
# .o_shipped: shipped file in binary format,
#             does not require additional preprocessing.
# 
# Other sources are treated as only prerequisite of building process.
#
#
# kbuild_add_module(<name> [MODULE_NAME <module_name>] IMPORTED)
#
# Create target, corresponded to the imported kernel module.
# In that case KMODULE_IMPORTED_* properties should be set manually if needed.
#
# In either case, if MODULE_NAME option is given, it determine name
# of the kernel module. Otherwise <name> itself is used.
function(kbuild_add_module name)
    cmake_parse_arguments(kbuild_add_module "IMPORTED;EXCLUDE_FROM_ALL" "MODULE_NAME" "" ${ARGN})
    if(kbuild_add_module_MODULE_NAME)
        set(module_name "${kbuild_add_module_MODULE_NAME}")
    else(kbuild_add_module_MODULE_NAME)
        set(module_name "${name}")
    endif(kbuild_add_module_MODULE_NAME)
    
    string(LENGTH ${module_name} module_name_len)
    if(module_name_len GREATER 55)
        # Name of the kernel module should fit into array of size (64-sizeof(unsigned long)).
        # On 64-bit systems(most restricted) this is 56.
        # Even 56 length is not good, as it is not include null character.
        # Without it, old versions of rmmod failed to unload module.
        message(SEND_ERROR "Kernel module name exceeds 55 characters: '${module_name}'")
    endif(module_name_len GREATER 55)
    
    if(kbuild_add_module_IMPORTED)
        # Creation of IMPORTED target is simple.
        add_custom_target(${name})
        set_property(TARGET ${name} PROPERTY KMODULE_TYPE "kmodule")
        set_property(TARGET ${name} PROPERTY KMODULE_IMPORTED "TRUE")
        set_property(TARGET ${name} PROPERTY KMODULE_MODULE_NAME "${module_name}")
        return()
    endif(kbuild_add_module_IMPORTED)

    if(kbuild_add_module_EXCLUDE_FROM_ALL)
        set(all_arg)
    else(kbuild_add_module_EXCLUDE_FROM_ALL)
        set(all_arg "ALL")
    endif(kbuild_add_module_EXCLUDE_FROM_ALL)
    
    # List of all source files, which are given.
    set(sources ${kbuild_add_module_UNPARSED_ARGUMENTS})

    # Sources with absolute paths
    to_abs_path(sources_abs ${sources})
    # list of files from which module building is depended
    set(depend_files)
    # Sources of "c" type, but without extension.
    # Used for clean files, and for out-of-source builds do not create
    # files in source tree.
    set(c_sources_noext_abs)
	# The sources with the code in assembly
	set(asm_sources_noext_abs)
	# Sources of "o_shipped" type, but without extension
	set(shipped_sources_noext_abs)
    # Categorize sources
    foreach(source_abs ${sources_abs})
        get_filename_component(ext ${source_abs} EXT)
        if(ext STREQUAL ".c" OR ext STREQUAL ".S" OR ext STREQUAL ".o_shipped")
			# Real sources
			# Move source into binary tree, if needed
			copy_source_to_binary_dir("${source_abs}" source_abs)
            
            get_filename_component(source_noext "${source_abs}" NAME_WE)
            get_filename_component(source_dir "${source_abs}" PATH)
            set(source_noext_abs "${source_dir}/${source_noext}")
            if(ext STREQUAL ".c")
				# c-source
				list(APPEND c_sources_noext_abs ${source_noext_abs})
			elseif(ext STREQUAL ".S")
				# asm source
				list(APPEND asm_sources_noext_abs ${source_noext_abs})
			elseif(ext STREQUAL ".o_shipped")
				# shipped-source
				list(APPEND shipped_sources_noext_abs ${source_noext_abs})
			endif(ext STREQUAL ".c")
		endif(ext STREQUAL ".c" OR ext STREQUAL ".S" OR ext STREQUAL ".o_shipped")
		# In any case, add file to depend list
        list(APPEND depend_files ${source_abs})
    endforeach(source_abs ${sources_abs})

    # Object sources relative to current binary dir
    # (for $(module)-y :=)
    set(obj_sources_noext_rel)
    foreach(obj_sources_noext_abs
            ${c_sources_noext_abs} ${asm_sources_noext_abs} ${shipped_sources_noext_abs})
        file(RELATIVE_PATH obj_source_noext_rel
            ${CMAKE_CURRENT_BINARY_DIR} ${obj_sources_noext_abs})
        list(APPEND obj_sources_noext_rel ${obj_source_noext_rel})
    endforeach(obj_sources_noext_abs)

    if(NOT obj_sources_noext_rel)
        message(FATAL_ERROR "List of object files for building kernel module ${name} is empty.")
    endif(NOT obj_sources_noext_rel)

    set(obj_sources_rel)
    # Detect, if build simple - source object name coincide with module name
    
    if(NOT obj_sources_noext_rel STREQUAL ${name})
        # Check, whether only one of source object names coincide with module name.
        # This situation is incorrect for kbuild system.
        list(FIND obj_sources_noext_rel ${name} is_objects_contain_name)
        if(is_objects_contain_name GREATER -1)
            message(FATAL_ERROR "Module should be built "
            "either from only one object with same name, "
            "or from objects with names different from the name of the module")
        endif(is_objects_contain_name GREATER -1)
        
        foreach(obj_source_noext_rel ${obj_sources_noext_rel})
            list(APPEND obj_sources_rel "${obj_source_noext_rel}.o")
        endforeach(obj_source_noext_rel ${obj_sources_noext_rel})
    endif(NOT obj_sources_noext_rel STREQUAL ${name})

    _get_directory_property_chained(ccflags KBUILD_COMPILE_DEFINITIONS " ")
    _get_directory_property_chained(include_dirs KBUILD_INCLUDE_DIRECTORIES)

    # Target for create module.
    add_custom_target(${name} ALL
        DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko"
                "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}"
    )

	# Create .cmd files for 'shipped' sources.
    # Gcc does not create them automatically for some reason.
	set(cmd_create_command)
    if(shipped_sources_noext_abs)
		foreach(shipped_source_noext_abs ${shipped_source_noext_abs})
			get_filename_component(shipped_dir ${shipped_source_noext_abs} PATH)
            get_filename_component(shipped_name ${shipped_source_noext_abs} NAME)
			list(APPEND cmd_create_command
				COMMAND printf "cmd_%s.o := cp -p %s.o_shipped %s.o\\n"
					"${shipped_source_noext_abs}"
					"${shipped_source_noext_abs}"
					"${shipped_source_noext_abs}"
					> "${shipped_dir}/.${shipped_name}.o.cmd")
		endforeach(shipped_source_noext_abs ${shipped_source_noext_abs})
	endif(shipped_sources_noext_abs)
    
    # User-defined parameters for 'make'
    set(make_flags ${KBUILD_MAKE_FLAGS})
    _get_per_build_var(make_flags_per_build KBUILD_MAKE_FLAGS)
    list(APPEND make_flags ${make_flags_per_build})
    
    # Rule for create module(and symvers file).
    add_custom_command(
        OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko"
            "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}"
        ${cmd_create_command}
        COMMAND $(MAKE) ${make_flags} ${kbuild_additional_make_flags} 
            -C ${Kbuild_BUILD_DIR} M=${CMAKE_CURRENT_BINARY_DIR} modules
# Update timestamps for targets.
# In some cases Kbuild system may decide do not update resulted files
# even in case when depencies newer.
# Updating timestamps prevent command to be executed every make call. 
        COMMAND touch "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko"
            "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}"
        DEPENDS ${depend_files}
            "${CMAKE_CURRENT_BINARY_DIR}/Kbuild"
        COMMENT "Building kernel module ${name}"
    )
    
    # Fill properties for the target.
    set_property(TARGET ${name} PROPERTY KMODULE_TYPE "kmodule")
    set_property(TARGET ${name} PROPERTY KMODULE_IMPORTED "FALSE")
    set_property(TARGET ${name} PROPERTY KMODULE_MODULE_NAME "${module_name}")

    set_property(TARGET ${name} PROPERTY KMODULE_MODULE_LOCATION
        "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko"
    )
    set_property(TARGET ${name} PROPERTY KMODULE_SYMVERS_LOCATION
        "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}"
    )
    
    # Internal properties
    set_property(TARGET ${name} PROPERTY KMODULE_BINARY_DIR
        "${CMAKE_CURRENT_BINARY_DIR}"
    )
    set_property(TARGET ${name} PROPERTY KMODULE_OBJ_SOURCES ${obj_sources_rel})
    set_property(TARGET ${name} PROPERTY KMODULE_COMPILE_FLAGS ${ccflags})
    set_property(TARGET ${name} PROPERTY KMODULE_INCLUDE_DIRECTORIES ${include_dirs})


    # Add target to the list of modules for built.
    set_property(GLOBAL APPEND PROPERTY KMODULE_TARGETS "${name}")
    
    # The rule to clean files
	_kbuild_module_clean_files(${name}
		C_SOURCE ${c_sources_noext_abs}
		ASM_SOURCE ${asm_sources_noext_abs}
		SHIPPED_SOURCE ${shipped_sources_noext_abs})
endfunction(kbuild_add_module name)

#  kbuild_include_directories(dirs ...)
#
# Add include directories for Kbuild process.
macro(kbuild_include_directories)
    set_property(DIRECTORY APPEND PROPERTY KBUILD_INCLUDE_DIRECTORIES ${ARGN})
endmacro(kbuild_include_directories)

#  kbuild_add_definitions (flags)
#
# Specify additional flags for compile kernel module.
#
# Note that multiple flags should be specified as single string,
# delimited with ' '.
function(kbuild_add_definitions flags)
    get_property(current_flags DIRECTORY PROPERTY KBUILD_COMPILE_DEFINITIONS)
    _string_join(" " current_flags "${current_flags}" "${flags}")
    set_property(DIRECTORY PROPERTY KBUILD_COMPILE_DEFINITIONS "${current_flags}")
endfunction(kbuild_add_definitions flags)

# There is no control for kbuild make flags except default values.
# Support for kbuild_add_make_definitions may be added if needed.


#  kbuild_link_module(<name> [<link> ...])
#
# Link kernel module with other modules, that allows to use symbols from
# other modules.
#
# <link> may be:
#  1) target name for other kernel module intended for build
#  2) target name for imported kernel module with
#     KMODULE_IMPORTED_SYMVERS_LOCATION property set
#  3) absolute path to symvers file of other kernel module.
#
# In any case, file-level dependency will be created for symvers file to link with.
# In the first case, also target-level dependency will be added
#
# Analogue for target_link_library().
#
# May be used only from the same directory, where module target is created.
function(kbuild_link_module name)
    # Check that @name corresponds to kernel module target for build.
    get_property(is_module TARGET ${name} PROPERTY KMODULE_TYPE SET)
    if(NOT is_module)
        message(FATAL_ERROR "kbuild_module_link: passed <name>\n\t\"${name}\"\n which is not kernel module target.")
    endif(NOT is_module)
    get_property(module_imported TARGET ${name} PROPERTY KMODULE_IMPORTED)
    if(kmodule_imported)
        message(FATAL_ERROR "Imported kernel module target \"${name}\" may not be linked.")
    endif(kmodule_imported)
    
    get_property(module_name TARGET ${name} PROPERTY KMODULE_MODULE_NAME)
    
    foreach(l ${ARGN})
        string(REGEX MATCH "/" link_is_file ${l})
        if(link_is_file)
            string(REGEX MATCH "^/" file_is_absolute ${l})
            if(NOT file_is_absolute)
                message(FATAL_ERROR "kbuild_module_link: passed filename\n\t\"${link}\"\nwhich is not absolute as <link>.")
            endif(NOT file_is_absolute)
            set(symvers_location "${l}")
            # Do not require symvers file to be already existed.
        else(link_is_file)
            if(NOT TARGET ${l})
                message(FATAL_ERROR "kbuild_module_link: passed link\n\t\"${l}\"\n which is neither an absolute path to symvers file nor a target.")
            endif(NOT TARGET ${l})
            get_property(kmodule_type TARGET ${l} PROPERTY KMODULE_TYPE)
            if(NOT kmodule_type)
                message(FATAL_ERROR "kbuild_module_link: passed target\n\t\"${l}\"\n which is not a target for kernel module as link.")
            endif(NOT kmodule_type)
            get_property(kmodule_imported TARGET ${l} PROPERTY KMODULE_IMPORTED)
            if(kmodule_imported)
                get_property(symvers_location TARGET ${l} PROPERTY KMODULE_IMPORTED_SYMVERS_LOCATION)
                if(NOT symvers_location)
                    message(FATAL_ERROR "kbuild_module_link: passed imported target\n\t\"${l}\"\n without \"KMODULE_IMPORTED_SYMVERS_LOCATION\" property set as link.")
                endif(NOT symvers_location)
            else(kmodule_imported)
                get_property(symvers_location TARGET ${l} PROPERTY KMODULE_SYMVERS_LOCATION)
                # Target dependency is added only for non-imported target.
                add_dependencies(${name} ${l})
            endif(kmodule_imported)
        endif(link_is_file)
        add_custom_command(OUTPUT
            "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko"
            "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}"
            DEPENDS ${symvers_location}
            APPEND
        )
        set_property(TARGET ${name} APPEND PROPERTY KMODULE_DEPEND_SYMVERS ${symvers_location})
    endforeach(l ${ARGN})
endfunction(kbuild_link_module name)

# kbuild_finalize_linking()
#
# Should be called after all kernel modules and their links defined.
# Usually this is the end of main CMakeLists.txt file.
function(kbuild_finalize_linking)
    _get_per_build_var(ccflags_per_build KBUILD_C_FLAGS)
    
    get_property(kmodule_targets GLOBAL PROPERTY KMODULE_TARGETS)
    foreach(m ${kmodule_targets})
        get_property(module_binary_dir TARGET ${m} PROPERTY KMODULE_BINARY_DIR)
        get_property(module_name TARGET ${m} PROPERTY KMODULE_MODULE_NAME)
        get_property(module_symvers_cmake TARGET ${m} PROPERTY KMODULE_DEPEND_SYMVERS)
        
        get_property(obj_sources TARGET ${m} PROPERTY KMODULE_OBJ_SOURCES)
        get_property(ccflags_local TARGET ${m} PROPERTY KMODULE_COMPILE_FLAGS)
        get_property(include_dirs TARGET ${m} PROPERTY KMODULE_INCLUDE_DIRECTORIES)
        
        # Combine all compiler flags together
        _string_join(" " ccflags "${KBUILD_C_FLAGS}" "${ccflags_local}")
        foreach(dir ${include_dirs})
            _string_join(" " ccflags "${ccflags}" "-I${dir}")
        endforeach(dir ${include_dirs})
        _string_join(" " ccflags "${ccflags}" "${ccflags_per_build}")
        
        string(REPLACE ";" " " module_symvers "${module_symvers_cmake}")
        
        if(obj_sources)
            set(obj_src_string "${module_name}-y := ")
            foreach(obj ${obj_sources})
                set(obj_src_string "${obj_src_string} ${obj}")
            endforeach(obj ${obj_sources})
        else(obj_sources)
            # Simple building process - module name is same as the name
            # of the only source.
            set(obj_src_string "")
        endif(obj_sources)
        # Configure kbuild file
        configure_file(${kbuild_this_module_dir}/kbuild_system_files/Kbuild.in
            ${module_binary_dir}/Kbuild
        )
    endforeach(m ${kmodule_targets})
endfunction(kbuild_finalize_linking)

# kbuild_install(TARGETS <module_name> ...
#    [[MODULE|SYMVERS]
#      DESTINATION <dir>
#      [CONFIGURATIONS [...]]
#      [COMPONENT <component>]
#    ]+)
#
# Install kernel module(s) and/or symvers file(s) into given directory.
#
# Almost all options means same as for install() cmake command.
# 'MODULE' refers to kernel module itself, SYMVERS refers symvers file.
#
# Unlike to standard install() command, there is no default destination
# directory neither for modules nor for symvers files.
# So, at least one rule should be defined, and 'DESTINATION' option
# should be set for every rule.
#
# TODO: support for 'EXPORT' mode.
function(kbuild_install type)
    if(NOT type STREQUAL "TARGETS")
        message(FATAL_ERROR "Only 'TARGETS' mode is currently supported")
    endif(NOT type STREQUAL "TARGETS")
    
    parse_install_arguments(kbuild_install
        "MODULE;SYMVERS" # Section types
        "" "DESTINATION;COMPONENT" "CONFIGURATIONS" # Section keywords classification.
        ${ARGN}
    )
    
    set(kbuild_install_TARGETS ${kbuild_install_GLOBAL_ARGUMENTS})
    if(NOT kbuild_install_TARGETS)
        message(FATAL_ERROR "No targets given for kbuild_install() command")
    endif(NOT kbuild_install_TARGETS)
    
    if(NOT kbuild_install_sections)
        message(FATAL_ERROR "There is no default destination for install kernel module components, but no section described it is given.")
    endif(NOT kbuild_install_sections)

    foreach(section_type ${kbuild_install_sections})
        if(NOT kbuild_install_${section_type}_DESTINATION)
            message(FATAL_ERROR "DESTINATION is not defined for section ${section_type}")
        endif(NOT kbuild_install_${section_type}_DESTINATION)
        # All additional arguments for given section.
        set(install_args_${section_type}
            DESTINATION "${kbuild_install_${section_type}_DESTINATION}")
        if(kbuild_install_${section_type}_CONFIGURATION)
            list(APPEND install_args_${section_type}
                CONFIGURATION "${kbuild_install_${section_type}_CONFIGURATION}"
            )
        endif(kbuild_install_${section_type}_CONFIGURATION)
        if(kbuild_install_${section_type}_COMPONENT)
            list(APPEND install_args_${section_type}
                COMPONENT "${kbuild_install_${section_type}_COMPONENT}"
            )
        endif(kbuild_install_${section_type}_COMPONENT)
        # Module installation.
        if(section_type STREQUAL "MODULE" OR section_type STREQUAL "ALL")
            # Combine locations for all modules in one list.
            set(module_locations)
            foreach(t ${kbuild_install_TARGETS})
                kbuild_get_module_location(module_location ${t})
                list(APPEND module_locations ${module_location})
            endforeach(t ${kbuild_install_TARGETS})
            # .. and install them at once.
            install(FILES ${module_locations} ${install_args_${section_type}})
        endif(section_type STREQUAL "MODULE" OR section_type STREQUAL "ALL")
        # Symvers installation.
        if(section_type STREQUAL "SYMVERS" OR section_type STREQUAL "ALL")
            # Because of renaming, symvers files should be installed separately.
            foreach(t ${kbuild_install_TARGETS})
                kbuild_get_symvers_location(symvers_location ${t})
                get_property(module_name TARGET ${t} PROPERTY KMODULE_MODULE_NAME)
                install(FILES ${symvers_location}
                    RENAME "${module_name}.symvers"
                    ${install_args_${section_type}}
                )
            endforeach(t ${kbuild_install_TARGETS})
        endif(section_type STREQUAL "SYMVERS" OR section_type STREQUAL "ALL")
    endforeach(section_type ${kbuild_install_sections})
endfunction(kbuild_install type)


# kbuild_try_compile(RESULT_VAR bindir srcfile|SOURCES src ...
#           [CMAKE_FLAGS <Flags>]
#           [KBUILD_COMPILE_DEFINITIONS flags ...]
#           [OUTPUT_VARIABLE var])
#
# Similar to try_module in simplified form, but compile srcfile as
# kernel module, instead of user space program.
#
# KBUILD_COMPILE_DEFINITIONS contains compiler definition flags for
# build kernel module.
#
# Possible CMAKE_FLAGS which has special semantic:
#  KBUILD_INCLUDE_DIRECTORIES - include directories for build kernel module
#  KBUILD_LINK_MODULE - symvers file(s) for link module with other modules.
function(kbuild_try_compile RESULT_VAR bindir srcfile)
    cmake_parse_arguments(kbuild_try_compile "" "OUTPUT_VARIABLE" "CMAKE_FLAGS;KBUILD_COMPILE_DEFINITIONS" ${ARGN})
    if(srcfile STREQUAL "SOURCES")
        set(srcfiles ${kbuild_try_compile_UNPARSED_ARGUMENTS})
    else(srcfile STREQUAL "SOURCES")
        set(srcfiles ${srcfile})
    endif(srcfile STREQUAL "SOURCES")

    # Inside try_compile project values of variables
    # CMAKE_CURRENT_BINARY_DIR and CMAKE_CURRENT_SOURCE_DIR
    # differs from ones in current project.
    #
    # So make all paths absolute before pass them into try_compile project.
    # Note, that copiing files into binary dir is nevertheless performed
    # in the try_compile project, because it bases on real current binary dir.
    to_abs_path(srcfiles_abs ${srcfiles})
    
    # Collect parameters to try_compile() function
    set(cmake_flags
        "-DSOURCES:STRING=${srcfiles_abs}" # Source file(s)
        "-DCMAKE_MODULE_PATH:PATH=${CMAKE_MODULE_PATH}" # Path for search include files.
        ${kbuild_try_compile_CMAKE_FLAGS}
    )

    # Parameters for compiler
    if(kbuild_try_compile_KBUILD_COMPILE_DEFINITIONS)
        list(APPEND cmake_flags
            "-DKBUILD_COMPILE_DEFINITIONS:STRING=${kbuild_try_compile_KBUILD_COMPILE_DEFINITIONS}"
        )
    endif(kbuild_try_compile_KBUILD_COMPILE_DEFINITIONS)

    # Other user-defined cmake flags
    if(kbuild_try_compile_CMAKE_FLAGS)
        
    endif(kbuild_try_compile_CMAKE_FLAGS)

    # Possible definition of output variable.
    if(kbuild_try_compile_OUTPUT_VARIABLE)
        set(output_variable_def "OUTPUT_VARIABLE" "output_tmp")
    else(build_try_compile_OUTPUT_VARIABLE)
        set(output_variable_def)
    endif(kbuild_try_compile_OUTPUT_VARIABLE)

    
    try_compile(result_tmp # Result variable(temporary)
        "${bindir}" # Binary directory
        "${kbuild_aux_dir}/try_compile_project" # Source directory
        "kmodule" # Project name
         CMAKE_FLAGS # Flags to CMake:
            ${cmake_flags}
            ${kbuild_try_compile_flags}
        ${output_variable_def}
    )
    
    if(kbuild_try_compile_OUTPUT_VARIABLE)
        # Set output variable for the caller
        set("${kbuild_try_compile_OUTPUT_VARIABLE}" "${output_tmp}" PARENT_SCOPE)
    endif(kbuild_try_compile_OUTPUT_VARIABLE)
    # Set result variable for the caller
    set("${RESULT_VAR}" "${result_tmp}" PARENT_SCOPE)
endfunction(kbuild_try_compile RESULT_VAR bindir srcfile)

########### Auxiliary functions for internal use #######################
# Per-directory tracking for kbuild compiler flags.
#
# Unlike to standard COMPILE_FLAGS, these flags do not include values
# set for parent directories.
# (There is no generic "fill-with-parent's values" mechanism exists
# in cmake).
#
# So, this property has a little sence for the user.
# It exists only for make effect of kbuild_add_definitions() to 
# cross "function" scope.
define_property(DIRECTORY PROPERTY KBUILD_COMPILE_FLAGS
    BRIEF_DOCS "Compiler flags used by Kbuild system added in this directory."
    FULL_DOCS "Compiler flags used by Kbuild system added in this directory."
)

# Per-directory tracking for kbuild include directories.
#
# Unlike to standard INCLUDE_DIRECTORIES, these ones do not include values
# set for parent directories.
# (There is no generic "fill-with-parent's values" mechanism exists
# in cmake).
#
# So, this property has a little sence for the user.
# It exists only for make effect of kbuild_include_directories() to 
# cross "function" scope.
define_property(DIRECTORY PROPERTY KBUILD_INCLUDE_DIRECTORIES
    BRIEF_DOCS "Include directories used by Kbuild system; added in this directory."
    FULL_DOCS "Include directories used by Kbuild system; added in this directory."
)


# Parameters below are set externally only in try_compile() for subproject,
# which include this file.
# No need to cache them as try_compile() project is not configured by the user.

# Real top-level source directory.
if(NOT KBUILD_REAL_SOURCE_DIR)
    set(KBUILD_REAL_SOURCE_DIR ${CMAKE_SOURCE_DIR})
endif(NOT KBUILD_REAL_SOURCE_DIR)
# Real top-level binary directory.
if(NOT KBUILD_REAL_BINARY_DIR)
    set(KBUILD_REAL_BINARY_DIR ${CMAKE_BINARY_DIR})
endif(NOT KBUILD_REAL_BINARY_DIR)

# These flags are passed to the 'make' when compile kernel module.
set(kbuild_additional_make_flags)
# These CMake flags will be passed to try_compile() subproject.
set(kbuild_try_compile_flags
    "-DKBUILD_REAL_SOURCE_DIR=${KBUILD_REAL_SOURCE_DIR}"
    "-DKBUILD_REAL_BINARY_DIR=${KBUILD_REAL_BINARY_DIR}"
)

# ARCH and CROSS_COMPILE are passed to submake only when non-empty.
if(ARCH)
    list(APPEND kbuild_additional_make_flags "ARCH=${ARCH}")
    list(APPEND kbuild_try_compile_flags "-DARCH=${ARCH}")
endif(ARCH)
if(CROSS_COMPILE)
    list(APPEND kbuild_additional_make_flags "CROSS_COMPILE=${CROSS_COMPILE}")
    list(APPEND kbuild_try_compile_flags "-DCROSS_COMPILE=${CROSS_COMPILE}")
endif(CROSS_COMPILE)

# List of targets created with kmodule_add_module() without
# 'IMPORTED' option.
#
# This list is traversed in kmodule_finalize_linking() for
# create 'Kbuild' files.
#
# Note, that this list does not contain all defined kernel modules,
# so property normally shouldn't be used by outer code.
define_property(GLOBAL PROPERTY KMODULE_TARGETS
    BRIEF_DOCS "List of kernel module targets configured for build"
    FULL_DOCS "List of kernel module targets configured for build"
)

# CMAKE_CURRENT_BINARY_DIR at the moment, when kbuild_add_module() is issued.
define_property(TARGET PROPERTY KMODULE_BINARY_DIR
    BRIEF_DOCS "CMAKE_CURRENT_BINARY_DIR where module is built."
    FULL_DOCS "CMAKE_CURRENT_BINARY_DIR where module is built."
)

# List of object files, used for build kernel module.
#
# List may be empty in case of simple build, when target module has same
# name as its only source.
#
# This is internal property for configure 'Kbuild' file.
define_property(TARGET PROPERTY KMODULE_OBJ_SOURCES
    BRIEF_DOCS "Object source files for build kernel module."
    FULL_DOCS "Object source files for build kernel module."
)

# Compiler flags, added with kbuild_add_definitions()
#
# Note, that KBUILD_C_FLAGS* are not included here.
#
# This is internal property for configure 'Kbuild' file.
define_property(TARGET PROPERTY KMODULE_COMPILE_FLAGS
    BRIEF_DOCS "Additional compile flags for build kernel module."
    FULL_DOCS "Additional compile flags for build kernel module."
)

# Include directories, added with kbuild_include_directories().
#
# This is internal property for configure 'Kbuild' file.
define_property(TARGET PROPERTY KMODULE_COMPILE_FLAGS
    BRIEF_DOCS "Additional compile flags for build kernel module."
    FULL_DOCS "Additional compile flags for build kernel module."
)


# List of symvers files, added by kbuild_link_module().
#
# This is internal property for configure 'Kbuild' file.
define_property(TARGET PROPERTY KMODULE_DEPEND_SYMVERS
    BRIEF_DOCS "Symvers files this module depends on."
    FULL_DOCS "Symvers files this module depends on."
)

# Constants for internal filenames.
set(_kbuild_symvers "Module.symvers")

#  copy_source_to_binary_dir(<source> <new_source_var>)
#
# Helper for the building kernel module.
#
# Make sure that given source file is inside current binary dir.
# That place is writable and has some "uniqeness" garantee for generate
# auxiliary files during build process.
#
# If <source> already inside current binary dir, do nothing and
# set <new_source_var> variable to <source> itself.
#
# Otherwise create rule for copy source into "nice" place inside
# current binary dir and set <new_source_var> pointed to that place.
function(copy_source_to_binary_dir source new_source_var)
    is_path_inside_dir(is_in_current_binary ${CMAKE_CURRENT_BINARY_DIR} "${source}")
    if(is_in_current_binary)
        # Source is already placed where we want.
        set(${new_source_var} "${source}" PARENT_SCOPE)
    else(is_in_current_binary)
        # Base directory from which count relative source path.
        # By default, it is root directory.
        set(base_dir "/")
        # Try "nicer" base directories.
        foreach(d
            ${KBUILD_REAL_BINARY_DIR}
            ${CMAKE_CURRENT_SOURCE_DIR}
            ${KBUILD_REAL_SOURCE_DIR}
            )
            is_path_inside_dir(is_in_d ${d} "${source}")
            if(is_in_d)
                set(base_dir ${d})
                break()
            endif(is_in_d)
        endforeach(d)
		# Copy source into same relativ dir, but inside current binary one.
        file(RELATIVE_PATH source_rel "${base_dir}" "${source}")
		set(new_source "${CMAKE_CURRENT_BINARY_DIR}/${source_rel}")
        get_filename_component(new_source_dir ${new_source} PATH)
        file(MAKE_DIRECTORY "${new_source_dir}")
		rule_copy_file("${new_source}" "${source}")
        # Return path to the new source.
        set(${new_source_var} "${new_source}" PARENT_SCOPE)
    endif(is_in_current_binary)
endfunction(copy_source_to_binary_dir source new_source_var)

#  _get_per_build_var(RESULT_VAR variable)
#
# Return value of per-build variable.
macro(_get_per_build_var RESULT_VAR variable)
    if(CMAKE_BUILD_TYPE)
        string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type_uppercase)
        set(${RESULT_VAR} "${${variable}_${_build_type_uppercase}}")
    else(CMAKE_BUILD_TYPE)
        set(${RESULT_VAR})
    endif(CMAKE_BUILD_TYPE)
endmacro(_get_per_build_var RESULT_VAR variable)

#  _string_join(sep RESULT_VAR str1 str2)
#
# Join strings <str1> and <str2> using <sep> as glue.
#
# Note, that precisely 2 string are joined, not a list of strings.
# This prevents automatic replacing of ';' inside strings while parsing arguments.
macro(_string_join sep RESULT_VAR str1 str2)
    if("${str1}" STREQUAL "")
        set("${RESULT_VAR}" "${str2}")
    elseif("${str2}" STREQUAL "")
        set("${RESULT_VAR}" "${str1}")
    else("${str1}" STREQUAL "")
        set("${RESULT_VAR}" "${str1}${sep}${str2}")
    endif("${str1}" STREQUAL "")
endmacro(_string_join sep RESULT_VAR str1 str2)
#  _build_get_directory_property_chained(RESULT_VAR <propert_name> [<separator>])
#
# Return list of all values for given property in the current directory
# and all parent directories.
#
# If <separator> is given, it is used as glue for join values.
# By default, cmake list separator (';') is used.
function(_get_directory_property_chained RESULT_VAR property_name)
    set(sep ";")
    foreach(arg ${ARGN})
        set(sep "${arg}")
    endforeach(arg ${ARGN})
    set(result "")
    set(d "${CMAKE_CURRENT_SOURCE_DIR}")
    while(NOT "${d}" STREQUAL "")
        get_property(p DIRECTORY "${d}" PROPERTY "${property_name}")
        # debug
        # message("Property ${property_name} for directory ${d}: '${p}'")
        _string_join("${sep}" result "${p}" "${result}")
        # message("Intermediate result: '${result}'")
        get_property(d DIRECTORY "${d}" PROPERTY PARENT_DIRECTORY)
    endwhile(NOT "${d}" STREQUAL "")
    set("${RESULT_VAR}" "${result}" PARENT_SCOPE)
endfunction(_get_directory_property_chained RESULT_VAR property_name)

#  _kbuild_module_clean_files(module_name
# 	[C_SOURCE c_source_noext_abs ...]
# 	[ASM_SOURCE asm_source_noext_abs ...]
#	[SHIPPED_SOURCE shipped_source_noext_abs ...])
#
# Tell CMake that intermediate files, created by kbuild system,
# should be cleaned with 'make clean'.
function(_kbuild_module_clean_files module_name)
    cmake_parse_arguments(kbuild_module_clean "" "" "C_SOURCE;ASM_SOURCE;SHIPPED_SOURCE" ${ARGN})
    if(kbuild_module_clean_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unparsed arguments")
    endif(kbuild_module_clean_UNPARSED_ARGUMENTS)

	# List common files (names only) for cleaning
	set(common_files_names
        ".tmp_versions" # Directory
        "modules.order"
		"Module.markers"
    )
	# List module name-depending files (extensions only) for cleaning
	set(name_files_ext
		".o"
		".mod.c"
		".mod.o"
    )
	# Same but for the files with names starting with a dot ('.').
	set(name_files_dot_ext
		".ko.cmd"
		".mod.o.cmd"
		".o.cmd"
    )
	# List source name-depending files (extensions only) for cleaning
	set(source_name_files_ext
		".o"
    )
	# Same but for the files with names starting with a dot ('.')
	set(source_name_files_dot_ext
		".o.cmd"
		".o.d" # This file is created in case of unsuccessfull build
    )
	
	# Now collect all sort of files into list
	set(files_list)

	foreach(name ${common_files_names})
		list(APPEND files_list "${CMAKE_CURRENT_BINARY_DIR}/${name}")
	endforeach(name ${common_files_names})
	
	foreach(ext ${name_files_ext})
		list(APPEND files_list
			"${CMAKE_CURRENT_BINARY_DIR}/${module_name}${ext}")
	endforeach(ext ${name_files_ext})
	
	foreach(ext ${name_files_dot_ext})
		list(APPEND files_list
			"${CMAKE_CURRENT_BINARY_DIR}/.${module_name}${ext}")
	endforeach(ext ${name_files_ext})
	
    # All the types of sources are processed in a similar way
    foreach(obj_source_noext_abs ${kbuild_module_clean_C_SOURCE}
        ${kbuild_module_clean_ASM_SOURCE} ${kbuild_module_clean_SHIPPED_SOURCE})

        get_filename_component(dir ${obj_source_noext_abs} PATH)
        get_filename_component(name ${obj_source_noext_abs} NAME)
        foreach(ext ${source_name_files_ext})
            list(APPEND files_list "${dir}/${name}${ext}")
        endforeach(ext ${source_name_files_ext})
        foreach(ext ${source_name_files_dot_ext})
            list(APPEND files_list "${dir}/.${name}${ext}")
        endforeach(ext ${source_name_files_ext})
    endforeach(obj_source_noext_abs)
	# Tell CMake that given files should be cleaned.
	set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${files_list}")
endfunction(_kbuild_module_clean_files module_name)

#  parse_install_arguments(prefix <section-type-keywords> <options> <one-value-keywords> <multiple-value-keywords> args..)
#
# Helper for parse arguments for install-like command.
#
# All arguments before the first keyword are classified as GLOBAL_ARGUMENTS
# and stored into list ${prefix}_GLOBAL_ARGUMENTS.
#
# <section-type-keywords> describe possible keywords denoting section type.
# At most one section may exist for every type.
# Special type ALL means generic section. 
#
# <options>, <one-value-keywords> and <multiple-value-keywords> describe
# all keywords inside section.
# Values corresponded to these keywords are stored under
# <prefix>_<section-type>_*.
# Note, that unlike to cmake_parse_arguments(), all arguments inside
# section definition should be either keyword or its value(s).
# Additionally, <prefix>_<section-type> is set to TRUE for every
# encountered section and <prefix>_sections contains list of such sections.
#
# If non section is currently active, the first section keyword starts
# special generic section. Definitions for this section are stored as
# for section of type ALL.
# If such section exists, it should be the only section.
#
# Function is generic, but currently is used only there.
function(parse_install_arguments prefix section_types options one_value_keywords multiple_value_keywords)
    set(all_keywords ${section_types} ${options} ${one_value_keywords} ${multiple_value_keywords})
    # Type of the currently parsed section('ALL' for ALL section).
    set(current_section_type)
    # Active section-related keyword for current section.
    set(current_section_keyword)
    # Classification for @_current_section_keyword:
    # 'OPTION', 'ONE' or 'MULTY'.
    set(current_section_keyword_type)
    
    # Clean all previous keyword values.
    set("pia_GLOBAL_ARGUMENTS")
    foreach(section_type "ALL" ${section_types})
        set(pia_${section_type} "FALSE")
        foreach(opt ${options})
            set("pia_${section_type}_${opt}" "FALSE")
        endforeach(opt ${options})
        foreach(keyword ${one_value_keywords} ${multiple_value_keywords})
            set("pia_${section_type}_${keyword}")
        endforeach(keyword ${one_value_keywords} ${multiple_value_keywords})
    endforeach(section_type "ALL" ${section_types})
    set("pia_sections")

    foreach(arg ${ARGN})
        list(FIND all_keywords ${arg} keyword_index)
        if(keyword_index EQUAL "-1")
            if(current_section_type)
                if(NOT current_section_keyword)
                    message(FATAL_ERROR "In section ${current_section_type} argument ${arg} does not belong to any keyword.")
                endif(NOT current_section_keyword)
                if(current_section_keyword_type STREQUAL "ONE")
                    set("pia_${current_section_type}_${current_section_keyword}" "${arg}")
                    set(current_section_keyword "")
                else(current_section_keyword_type STREQUAL "ONE")
                    list(APPEND "pia_${current_section_type}_${current_section_keyword}" "${arg}")
                endif(current_section_keyword_type STREQUAL "ONE")
            else(current_section_type)
                list(APPEND "pia_GLOBAL_ARGUMENTS" "${arg}")
            endif(current_section_type)
        else(keyword_index EQUAL "-1")
            if(current_section_type AND current_section_keyword AND current_section_keyword_type STREQUAL "ONE")
                message(FATAL_ERROR "Keyword ${arg} found while value for one-value-option ${current_section_keyword} expected.")
            endif(current_section_type AND current_section_keyword AND current_section_keyword_type STREQUAL "ONE")
            list(FIND section_types "${arg}" section_type_index)
            if(section_type_index EQUAL "-1")
                if(NOT current_section_type)
                    set(current_section_type "ALL")
                    set("pia_${current_section_type}" "TRUE")
                    list(APPEND "pia_sections" "${current_section_type}")
                endif(NOT current_section_type)
                list(FIND options ${arg} option_index)
                if(option_index EQUAL "-1")
                    set(current_section_keyword ${arg})
                    list(FIND one_value_keywords ${current_section_keyword} one_index)
                    if(one_index EQUAL "-1")
                        set(current_section_keyword_type "MULTY")
                    else(one_index EQUAL "-1")
                        set(current_section_keyword_type "ONE")
                    endif(one_index EQUAL "-1")
                    set("pia_${current_section_type}_${current_section_keyword}")
                else(option_index EQUAL "-1")
                    set("${prefix}_${current_section_type}_${current_section_keyword}" "TRUE")
                    set(current_section_keyword_type)
                endif(option_index EQUAL "-1")
            else(section_type_index EQUAL "-1")
                if("pia_ALL")
                    message(FATAL_ERROR "Generic section should be the only section defined")
                endif("pia_ALL")
                set(current_section_type "${arg}")
                if("pia_${current_section_type}")
                    message(FATAL_ERROR "Section ${current_section_type} is defined twice.")
                endif("pia_${current_section_type}")
                set("pia_${current_section_type}" "TRUE")
                list(APPEND "pia_sections" "${current_section_type}")
                # Current keyword is initially undefined for such section.
                set(current_section_keyword)
            endif(section_type_index EQUAL "-1")
        endif(keyword_index EQUAL "-1")
    endforeach(arg ${ARGN})

    # propagate the result variables to the caller
    set("${prefix}_GLOBAL_ARGUMENTS" ${pia_GLOBAL_ARGUMENTS} PARENT_SCOPE)
    foreach(section_type "ALL" ${section_types})
        set(${prefix}_${section_type} ${pia_${section_type}} PARENT_SCOPE)
        foreach(keyword ${options} ${one_value_keywords} ${multiple_value_keywords})
            set("${prefix}_${section_type}_${keyword}" ${pia_${section_type}_${keyword}} PARENT_SCOPE)
        endforeach(keyword ${options} ${one_value_keywords} ${multiple_value_keywords})
    endforeach(section_type "ALL" ${section_types})
    set("${prefix}_sections" ${pia_sections} PARENT_SCOPE)
endfunction(parse_install_arguments prefix section_types options one_value_keywords multiple_value_keywords)