# Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved. # SPDX-License-Identifier: MIT # SPDX-License-Identifier: Apache-2.0 ######################################################## # Table of contents ######################################################## # 1. Amlogic-aware extensions # 1.1. aml_* # 1.2. aml_library_* # 1.2.1 aml_interface_library_* # 1.3. generate_inc_* # 1.4. board_* # 1.5. Misc. # 2. Kconfig-aware extensions # 2.1 *_if_kconfig # 2.2 Misc # 3. CMake-generic extensions # 3.1. *_ifdef # 3.2. *_ifndef # 3.3. *_option compiler compatibility checks # 3.4. Debugging CMake # 3.5. File system management ######################################################## # 1. Amlogic-aware extensions ######################################################## # 1.1. aml_* # # The following methods are for modifying the CMake library[0] called # "aml". aml is a catch-all CMake library for source files that # can be built purely with the include paths, defines, and other # compiler flags that all aml source files use. # [0] https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html # # Example usage: # aml_sources( # random_esp32.c # utils.c # ) # # Is short for: # target_sources(aml PRIVATE # ${CMAKE_CURRENT_SOURCE_DIR}/random_esp32.c # ${CMAKE_CURRENT_SOURCE_DIR}/utils.c # ) # https://cmake.org/cmake/help/latest/command/target_sources.html function(aml_sources) foreach(arg ${ARGV}) if(IS_ABSOLUTE ${arg}) set(path ${arg}) else() set(path ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) endif() if(IS_DIRECTORY ${path}) message(FATAL_ERROR "aml_sources() was called on a directory") endif() target_sources(${TARGET_NAME} PRIVATE ${path}) endforeach() endfunction() # https://cmake.org/cmake/help/latest/command/target_include_directories.html function(aml_include_directories) foreach(arg ${ARGV}) if(IS_ABSOLUTE ${arg}) set(path ${arg}) else() set(path ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) endif() target_include_directories(aml_interface INTERFACE ${path}) endforeach() endfunction() # https://cmake.org/cmake/help/latest/command/target_include_directories.html function(aml_system_include_directories) foreach(arg ${ARGV}) if(IS_ABSOLUTE ${arg}) set(path ${arg}) else() set(path ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) endif() target_include_directories(aml_interface SYSTEM INTERFACE ${path}) endforeach() endfunction() # https://cmake.org/cmake/help/latest/command/target_compile_definitions.html function(aml_compile_definitions) target_compile_definitions(aml_interface INTERFACE ${ARGV}) endfunction() # https://cmake.org/cmake/help/latest/command/target_compile_options.html function(aml_compile_options) target_compile_options(aml_interface INTERFACE ${ARGV}) endfunction() # https://cmake.org/cmake/help/latest/command/target_link_libraries.html function(aml_link_libraries) set(COLLECT_LINK_LIBRARIES ${CURRENT_LIBRARY} ${COLLECT_LINK_LIBRARIES} CACHE INTERNAL "") # target_link_libraries(${TARGET_NAME} ${CURRENT_LIBRARY}) endfunction() function(aml_link_libraries_with_name lib_name) set(COLLECT_LINK_LIBRARIES ${lib_name} ${COLLECT_LINK_LIBRARIES} CACHE INTERNAL "") # target_link_libraries(${TARGET_NAME} ${CURRENT_LIBRARY}) endfunction() function(aml_link_cpp_libraries_with_name lib_name) set(COLLECT_LINK_LIBRARIES ${lib_name} ${COLLECT_LINK_LIBRARIES} CACHE INTERNAL "") set(COLLECT_IS_CPP_LIBRARIES "1" CACHE INTERNAL "") endfunction() function(aml_link_interfaces) target_link_libraries(${TARGET_NAME} ${CURRENT_INTERFACE}) endfunction() # See this file section 3.1. target_cc_option function(aml_cc_option) foreach(arg ${ARGV}) target_cc_option(aml_interface INTERFACE ${arg}) endforeach() endfunction() function(aml_cc_option_fallback option1 option2) target_cc_option_fallback(aml_interface INTERFACE ${option1} ${option2}) endfunction() function(aml_ld_options) target_ld_options(aml_interface INTERFACE ${ARGV}) endfunction() # Getter functions for extracting build information from # aml_interface. Returning lists, and strings is supported, as is # requesting specific categories of build information (defines, # includes, options). # # The naming convention follows: # aml_get_${build_information}_for_lang${format}(lang x [SKIP_PREFIX]) # Where # the argument 'x' is written with the result # and # ${build_information} can be one of # - include_directories # -I directories # - system_include_directories # -isystem directories # - compile_definitions # -D'efines # - compile_options # misc. compiler flags # and # ${format} can be # - the empty string '', signifying that it should be returned as a list # - _as_string signifying that it should be returned as a string # and # ${lang} can be one of # - C # - CXX # - ASM # # SKIP_PREFIX # # By default the result will be returned ready to be passed directly # to a compiler, e.g. prefixed with -D, or -I, but it is possible to # omit this prefix by specifying 'SKIP_PREFIX' . This option has no # effect for 'compile_options'. # # e.g. # aml_get_include_directories_for_lang(ASM x) # writes "-Isome_dir;-Isome/other/dir" to x function(aml_get_include_directories_for_lang_as_string lang i) aml_get_include_directories_for_lang(${lang} list_of_flags ${ARGN}) convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) set(${i} ${str_of_flags} PARENT_SCOPE) endfunction() function(aml_get_system_include_directories_for_lang_as_string lang i) aml_get_system_include_directories_for_lang(${lang} list_of_flags ${ARGN}) convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) set(${i} ${str_of_flags} PARENT_SCOPE) endfunction() function(aml_get_compile_definitions_for_lang_as_string lang i) aml_get_compile_definitions_for_lang(${lang} list_of_flags ${ARGN}) convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) set(${i} ${str_of_flags} PARENT_SCOPE) endfunction() function(aml_get_compile_options_for_lang_as_string lang i) aml_get_compile_options_for_lang(${lang} list_of_flags) convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) set(${i} ${str_of_flags} PARENT_SCOPE) endfunction() function(aml_get_include_directories_for_lang lang i) get_property_and_add_prefix(flags aml_interface INTERFACE_INCLUDE_DIRECTORIES "-I" ${ARGN} ) process_flags(${lang} flags output_list) set(${i} ${output_list} PARENT_SCOPE) endfunction() function(aml_get_system_include_directories_for_lang lang i) get_property_and_add_prefix(flags aml_interface INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "-isystem" ${ARGN} ) process_flags(${lang} flags output_list) set(${i} ${output_list} PARENT_SCOPE) endfunction() function(aml_get_compile_definitions_for_lang lang i) get_property_and_add_prefix(flags aml_interface INTERFACE_COMPILE_DEFINITIONS "-D" ${ARGN} ) process_flags(${lang} flags output_list) set(${i} ${output_list} PARENT_SCOPE) endfunction() function(aml_get_compile_options_for_lang lang i) get_property(flags TARGET aml_interface PROPERTY INTERFACE_COMPILE_OPTIONS) process_flags(${lang} flags output_list) set(${i} ${output_list} PARENT_SCOPE) endfunction() # This function writes a dict to it's output parameter # 'return_dict'. The dict has information about the parsed arguments, # # Usage: # aml_get_parse_args(foo ${ARGN}) # print(foo_STRIP_PREFIX) # foo_STRIP_PREFIX might be set to 1 function(aml_get_parse_args return_dict) foreach(x ${ARGN}) if(x STREQUAL STRIP_PREFIX) set(${return_dict}_STRIP_PREFIX 1 PARENT_SCOPE) endif() endforeach() endfunction() function(process_flags lang input output) # The flags might contains compile language generator expressions that # look like this: # $<$:-fno-exceptions> # # Flags that don't specify a language like this apply to all # languages. # # See COMPILE_LANGUAGE in # https://cmake.org/cmake/help/v3.3/manual/cmake-generator-expressions.7.html # # To deal with this, we apply a regex to extract the flag and also # to find out if the language matches. # # If this doesn't work out we might need to ban the use of # COMPILE_LANGUAGE and instead partition C, CXX, and ASM into # different libraries set(languages C CXX ASM) set(tmp_list "") foreach(flag ${${input}}) set(is_compile_lang_generator_expression 0) foreach(l ${languages}) if(flag MATCHES ":([^>]+)>") set(is_compile_lang_generator_expression 1) if(${l} STREQUAL ${lang}) list(APPEND tmp_list ${CMAKE_MATCH_1}) break() endif() endif() endforeach() if(NOT is_compile_lang_generator_expression) list(APPEND tmp_list ${flag}) endif() endforeach() set(${output} ${tmp_list} PARENT_SCOPE) endfunction() function(convert_list_of_flags_to_string_of_flags ptr_list_of_flags string_of_flags) # Convert the list to a string so we can do string replace # operations on it and replace the ";" list separators with a # whitespace so the flags are spaced out string(REPLACE ";" " " locally_scoped_string_of_flags "${${ptr_list_of_flags}}") # Set the output variable in the parent scope set(${string_of_flags} ${locally_scoped_string_of_flags} PARENT_SCOPE) endfunction() macro(get_property_and_add_prefix result target property prefix) aml_get_parse_args(args ${ARGN}) if(args_STRIP_PREFIX) set(maybe_prefix "") else() set(maybe_prefix ${prefix}) endif() get_property(target_property TARGET ${target} PROPERTY ${property}) foreach(x ${target_property}) list(APPEND ${result} ${maybe_prefix}${x}) endforeach() endmacro() # 1.2 aml_library_* # # Amlogic libraries use CMake's library concept and a set of # assumptions about how aml code is organized to cut down on # boilerplate code. # # A Amlogic library can be constructed by the function aml_library # or aml_library_named. The constructors create a CMake library # with a name accessible through the variable CURRENT_LIBRARY. # # The variable CURRENT_LIBRARY should seldomly be needed since # the aml libraries have methods that modify the libraries. These # methods have the signature: aml_library_ # # The methods are wrappers around the CMake target_* functions. See # https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for # documentation on the underlying target_* functions. # # The methods modify the CMake target_* API to reduce boilerplate; # PRIVATE is assumed # The target is assumed to be CURRENT_LIBRARY # # When a flag that is given through the aml_* API conflicts with # the aml_library_* API then precedence will be given to the # aml_library_* API. In other words, local configuration overrides # global configuration. # Constructor with a directory-inferred name macro(aml_library) aml_library_get_current_dir_lib_name(lib_name) aml_library_named(${lib_name}) endmacro() # Constructor with an explicitly given name. macro(aml_library_named name) # This is a macro because we need add_library() to be executed # within the scope of the caller. set(CURRENT_LIBRARY ${name}) add_library(${name} STATIC "") aml_append_cmake_library(${name}) target_link_libraries(${name} PUBLIC aml_interface) endmacro() macro(redefine_file_macro) get_target_property(source_files "${CURRENT_LIBRARY}" SOURCES) foreach(sourcefile ${source_files}) get_property(defs SOURCE "${sourcefile}" PROPERTY COMPILE_DEFINITIONS) get_filename_component(filepath "${sourcefile}" ABSOLUTE) string(REPLACE ${PROJECT_SOURCE_DIR}/ "" relpath ${filepath}) list(APPEND defs "__FILE__=\"${relpath}\"") set_property(SOURCE "${sourcefile}" PROPERTY COMPILE_DEFINITIONS ${defs}) endforeach() endmacro() macro(aml_add_library) STRING( REGEX REPLACE ".*/(.*)/.*" "\\1" LAYER ${CMAKE_CURRENT_SOURCE_DIR} ) STRING( REGEX REPLACE ".*/(.*)" "\\1" MODULE ${CMAKE_CURRENT_SOURCE_DIR} ) if(LAYER STREQUAL ARCH AND MODULE STREQUAL PRODUCT) STRING( REGEX REPLACE ".*/(.*)/.*/.*" "\\1" LAYER ${CMAKE_CURRENT_SOURCE_DIR} ) STRING( REGEX REPLACE ".*/(.*)/.*" "\\1" MODULE ${CMAKE_CURRENT_SOURCE_DIR} ) endif() set(CURRENT_LIBRARY_TYPE STATIC) set(CURRENT_LIBRARY ${LAYER}__${MODULE}) message(STATUS "@@${CURRENT_LIBRARY_TYPE}: ${CURRENT_LIBRARY}") add_library(${CURRENT_LIBRARY} ${CURRENT_LIBRARY_TYPE} "") set_target_properties(${CURRENT_LIBRARY} PROPERTIES LIBRARY_BASE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) endmacro() macro(aml_add_library_spec CURRENT_LIBRARY CURRENT_LIBRARY_TYPE) add_library(${CURRENT_LIBRARY} ${CURRENT_LIBRARY_TYPE} "") set_target_properties(${CURRENT_LIBRARY} PROPERTIES LIBRARY_BASE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) endmacro() macro(aml_add_interface) STRING( REGEX REPLACE ".*/(.*)/.*" "\\1" LAYER ${CMAKE_CURRENT_SOURCE_DIR} ) STRING( REGEX REPLACE ".*/(.*)" "\\1" MODULE ${CMAKE_CURRENT_SOURCE_DIR} ) set(CURRENT_INTERFACE_TYPE INTERFACE) set(CURRENT_INTERFACE ${LAYER}__${MODULE}) message(STATUS "@@${CURRENT_INTERFACE_TYPE}: ${CURRENT_INTERFACE}") add_library(${CURRENT_INTERFACE} ${CURRENT_INTERFACE_TYPE}) endmacro() function(aml_link_interface interface) target_link_libraries(${interface} INTERFACE aml_interface) endfunction() # # aml_library versions of normal CMake target_ functions # function(aml_library_sources source) #remove the base dir if the source is a full path string(REPLACE "${CMAKE_CURRENT_LIST_DIR}/" "" source ${source}) #calculate the obj output full path set(FILE_NAME "${source}.obj") get_target_property(LIBRARY_BASE_PATH ${CURRENT_LIBRARY} LIBRARY_BASE_PATH) string(REPLACE ${LIBRARY_BASE_PATH} "${LIBRARY_BASE_PATH}/CMakeFiles/${CURRENT_LIBRARY}.dir" OBJ_OUTPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) string(REPLACE ${PROJECT_SOURCE_DIR} "${PROJECT_SOURCE_DIR}/output/$ENV{ARCH}-$ENV{BOARD}-$ENV{PRODUCT}/$ENV{KERNEL}/obj" OBJ_OUTPUT_DIR ${OBJ_OUTPUT_DIR}) set(OBJ_OUTPUT_PATH "${OBJ_OUTPUT_DIR}/${FILE_NAME}") #collect the obj output full path to COLLECT_LINK_OBJS set(COLLECT_LINK_OBJS ${OBJ_OUTPUT_PATH} ${COLLECT_LINK_OBJS} CACHE INTERNAL "") FOREACH(PART_PATH ${ARGN}) string(REPLACE "${CMAKE_CURRENT_LIST_DIR}/" "" PART_PATH ${PART_PATH}) set(FILE_NAME "${PART_PATH}.obj") set(OBJ_OUTPUT_PATH "${OBJ_OUTPUT_DIR}/${FILE_NAME}") #if the obj is exist in collection,ignore it string(FIND "${COLLECT_LINK_OBJS}" "${OBJ_OUTPUT_PATH}" ret) if(${ret} STREQUAL "-1") set(COLLECT_LINK_OBJS ${OBJ_OUTPUT_PATH} ${COLLECT_LINK_OBJS} CACHE INTERNAL "") endif() ENDFOREACH(PART_PATH) target_sources(${CURRENT_LIBRARY} PRIVATE ${source} ${ARGN}) endfunction() function(aml_library_include_directories) target_include_directories(${CURRENT_LIBRARY} PUBLIC ${ARGN}) endfunction() function(aml_library_include_directories_ifdef feature_toggle) if(${${feature_toggle}}) target_include_directories(${CURRENT_LIBRARY} PUBLIC ${ARGN}) endif() endfunction() function(aml_interface_include_directories) target_include_directories(${CURRENT_INTERFACE} INTERFACE ${ARGN}) endfunction() function(aml_library_link_libraries item) target_link_libraries(${CURRENT_LIBRARY} PUBLIC ${item} ${ARGN}) endfunction() function(aml_interface_link_interfaces item) target_link_libraries(${CURRENT_INTERFACE} INTERFACE ${item} ${ARGN}) endfunction() function(aml_library_compile_definitions item) target_compile_definitions(${CURRENT_LIBRARY} PRIVATE ${item} ${ARGN}) endfunction() function(aml_library_compile_options item) # The compiler is relied upon for sane behaviour when flags are in # conflict. Compilers generally give precedence to flags given late # on the command line. So to ensure that aml_library_* flags are # placed late on the command line we create a dummy interface # library and link with it to obtain the flags. # # Linking with a dummy interface library will place flags later on # the command line than the the flags from aml_interface because # aml_interface will be the first interface library that flags # are taken from. string(MD5 uniqueness ${item}) set(lib_name options_interface_lib_${uniqueness}) if (TARGET ${lib_name}) # ${item} already added, ignoring duplicate just like CMake does return() endif() add_library( ${lib_name} INTERFACE) target_compile_options(${lib_name} INTERFACE ${item} ${ARGN}) target_link_libraries(${CURRENT_LIBRARY} PRIVATE ${lib_name}) endfunction() function(aml_library_cc_option) foreach(option ${ARGV}) string(MAKE_C_IDENTIFIER check${option} check) aml_check_compiler_flag(C ${option} ${check}) if(${check}) aml_library_compile_options(${option}) endif() endforeach() endfunction() # 1.2.1 aml_interface_library_* # 1.3 generate_inc_* # 1.4. board_* # 1.5. Misc. ######################################################## # 2. Kconfig-aware extensions ######################################################## # # Kconfig is a configuration language developed for the Linux # kernel. The below functions integrate CMake with Kconfig. # # 2.1 *_if_kconfig # # Functions for conditionally including directories and source files # that have matching KConfig values. # # aml_library_sources_if_kconfig(fft.c) # is the same as # aml_library_sources_ifdef(CONFIG_FFT fft.c) # # add_subdirectory_if_kconfig(serial) # is the same as # add_subdirectory_ifdef(CONFIG_SERIAL serial) function(add_subdirectory_if_kconfig dir) string(TOUPPER config_${dir} UPPER_CASE_CONFIG) add_subdirectory_ifdef(${UPPER_CASE_CONFIG} ${dir}) endfunction() function(target_sources_if_kconfig target scope item) get_filename_component(item_basename ${item} NAME_WE) string(TOUPPER CONFIG_${item_basename} UPPER_CASE_CONFIG) target_sources_ifdef(${UPPER_CASE_CONFIG} ${target} ${scope} ${item}) endfunction() function(aml_library_sources_if_kconfig item) get_filename_component(item_basename ${item} NAME_WE) string(TOUPPER CONFIG_${item_basename} UPPER_CASE_CONFIG) aml_library_sources_ifdef(${UPPER_CASE_CONFIG} ${item}) endfunction() function(aml_sources_if_kconfig item) get_filename_component(item_basename ${item} NAME_WE) string(TOUPPER CONFIG_${item_basename} UPPER_CASE_CONFIG) aml_sources_ifdef(${UPPER_CASE_CONFIG} ${item}) endfunction() # 2.2 Misc # # Parse a KConfig fragment (typically with extension .config) and # introduce all the symbols that are prefixed with 'prefix' into the # CMake namespace function(import_kconfig prefix kconfig_fragment) # Parse the lines prefixed with 'prefix' in ${kconfig_fragment} file( STRINGS ${kconfig_fragment} DOT_CONFIG_LIST REGEX "^${prefix}" ENCODING "UTF-8" ) foreach (CONFIG ${DOT_CONFIG_LIST}) # CONFIG could look like: CONFIG_NET_BUF=y # Match the first part, the variable name string(REGEX MATCH "[^=]+" CONF_VARIABLE_NAME ${CONFIG}) # Match the second part, variable value string(REGEX MATCH "=(.+$)" CONF_VARIABLE_VALUE ${CONFIG}) # The variable name match we just did included the '=' symbol. To just get the # part on the RHS we use match group 1 set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1}) if("${CONF_VARIABLE_VALUE}" MATCHES "^\"(.*)\"$") # Is surrounded by quotes set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1}) endif() set("${CONF_VARIABLE_NAME}" "${CONF_VARIABLE_VALUE}" PARENT_SCOPE) endforeach() endfunction() ######################################################## # 3. CMake-generic extensions ######################################################## # # These functions extend the CMake API in a way that is not particular # to Amlogic. Primarily they work around limitations in the CMake # language to allow cleaner build scripts. # 3.1. *_ifdef # # Functions for conditionally executing CMake functions with oneliners # e.g. # # if(CONFIG_FFT) # aml_library_source( # fft_32.c # fft_utils.c # ) # endif() # # Becomes # # aml_source_ifdef( # CONFIG_FFT # fft_32.c # fft_utils.c # ) # # More Generally # "_ifdef(CONDITION args)" # Becomes # """ # if(CONDITION) # (args) # endif() # """ # # ifdef functions are added on an as-need basis. See # https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for # a list of available functions. function(add_subdirectory_ifdef feature_toggle dir) if(${${feature_toggle}}) add_subdirectory(${dir}) endif() endfunction() function(target_sources_ifdef feature_toggle target scope item) if(${${feature_toggle}}) target_sources(${target} ${scope} ${item} ${ARGN}) endif() endfunction() function(target_compile_definitions_ifdef feature_toggle target scope item) if(${${feature_toggle}}) target_compile_definitions(${target} ${scope} ${item} ${ARGN}) endif() endfunction() function(target_include_directories_ifdef feature_toggle target scope item) if(${${feature_toggle}}) target_include_directories(${target} ${scope} ${item} ${ARGN}) endif() endfunction() function(target_link_libraries_ifdef feature_toggle target item) if(${${feature_toggle}}) target_link_libraries(${target} ${item} ${ARGN}) endif() endfunction() function(add_compile_option_ifdef feature_toggle option) if(${${feature_toggle}}) add_compile_options(${option}) endif() endfunction() function(target_compile_option_ifdef feature_toggle target scope option) if(${feature_toggle}) target_compile_options(${target} ${scope} ${option}) endif() endfunction() function(target_cc_option_ifdef feature_toggle target scope option) if(${feature_toggle}) target_cc_option(${target} ${scope} ${option}) endif() endfunction() function(aml_library_sources_ifdef feature_toggle source) if(${${feature_toggle}}) aml_library_sources(${source} ${ARGN}) endif() endfunction() function(aml_sources_ifdef feature_toggle) if(${${feature_toggle}}) aml_sources(${ARGN}) endif() endfunction() function(aml_sources_ifndef feature_toggle) if(NOT ${feature_toggle}) aml_sources(${ARGN}) endif() endfunction() function(aml_cc_option_ifdef feature_toggle) if(${${feature_toggle}}) aml_cc_option(${ARGN}) endif() endfunction() function(aml_ld_option_ifdef feature_toggle) if(${${feature_toggle}}) aml_ld_options(${ARGN}) endif() endfunction() function(aml_link_libraries_ifdef feature_toggle) if(${${feature_toggle}}) aml_link_libraries(${ARGN}) endif() endfunction() function(aml_compile_options_ifdef feature_toggle) if(${${feature_toggle}}) aml_compile_options(${ARGN}) endif() endfunction() function(aml_compile_definitions_ifdef feature_toggle) if(${${feature_toggle}}) aml_compile_definitions(${ARGN}) endif() endfunction() function(aml_include_directories_ifdef feature_toggle) if(${${feature_toggle}}) aml_include_directories(${ARGN}) endif() endfunction() function(aml_library_compile_definitions_ifdef feature_toggle item) if(${${feature_toggle}}) aml_library_compile_definitions(${item} ${ARGN}) endif() endfunction() function(aml_library_compile_options_ifdef feature_toggle item) if(${${feature_toggle}}) aml_library_compile_options(${item} ${ARGN}) endif() endfunction() function(aml_link_interface_ifdef feature_toggle interface) if(${${feature_toggle}}) target_link_libraries(${interface} INTERFACE aml_interface) endif() endfunction() function(aml_library_link_libraries_ifdef feature_toggle item) if(${${feature_toggle}}) aml_library_link_libraries(${item}) endif() endfunction() macro(list_append_ifdef feature_toggle list) if(${${feature_toggle}}) list(APPEND ${list} ${ARGN}) endif() endmacro() # 3.4. Debugging CMake # Usage: # print(BOARD) # # will print: "BOARD: nrf52_pca10040" function(print arg) message(STATUS "${arg}: ${${arg}}") endfunction() # will cause a FATAL_ERROR and print an error message if the first # expression is false macro(assert test comment) if(NOT ${test}) message(FATAL_ERROR "Assertion failed: ${comment}") endif() endmacro() # Usage: # assert_not(FLASH_SCRIPT "FLASH_SCRIPT has been removed; use BOARD_FLASH_RUNNER") # # will cause a FATAL_ERROR and print an errorm essage if the first # espression is true macro(assert_not test comment) if(${test}) message(FATAL_ERROR "Assertion failed: ${comment}") endif() endmacro() # Usage: # assert_exists(CMAKE_READELF) # # will cause a FATAL_ERROR if there is no file or directory behind the # variable macro(assert_exists var) if(NOT EXISTS ${${var}}) message(FATAL_ERROR "No such file or directory: ${var}: '${${var}}'") endif() endmacro() # 3.5. extend files management function(compiler_generate_binary_output TARGET) add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_OBJCOPY_COMPILER} ARGS -O binary $ $/$ENV{KERNEL}.bin) endfunction() function(compiler_generate_lst_output TARGET) #Generate disassembly file intermix source code #llvm-objdump -S will warning can't find source file which in the prebuilt library, #then use 2>/dev/null to ignore standard error output add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_OBJDUMP_COMPILER} ARGS -S $ > $/$ENV{KERNEL}.lst 2>/dev/null) endfunction() function(generate_module_info_output TARGET) set(map_file_path ${PROJECT_SOURCE_DIR}/output/$ENV{ARCH}-$ENV{BOARD}-$ENV{PRODUCT}/$ENV{KERNEL}/${TARGET_NAME}.map) add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND COMPILER=$ENV{COMPILER} ARCH=$ENV{ARCH} ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/map_analyzer_$ENV{COMPILER}.py --combine ${map_file_path} > $/$ENV{KERNEL}_module_info.txt) endfunction()