| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- # set_default
- #
- # Define a variable to a default value if otherwise unset.
- #
- # Priority for new value is:
- # - Existing cmake value (ie set with cmake -D, or already set in CMakeLists)
- # - Value of any non-empty environment variable of the same name
- # - Default value as provided to function
- #
- function(set_default variable default_value)
- if(NOT ${variable})
- if(DEFINED ENV{${variable}} AND NOT "$ENV{${variable}}" STREQUAL "")
- set(${variable} $ENV{${variable}} PARENT_SCOPE)
- else()
- set(${variable} ${default_value} PARENT_SCOPE)
- endif()
- endif()
- endfunction()
- # spaces2list
- #
- # Take a variable whose value was space-delimited values, convert to a cmake
- # list (semicolon-delimited)
- #
- # Note: if using this for directories, keeps the issue in place that
- # directories can't contain spaces...
- #
- # TODO: look at cmake separate_arguments, which is quote-aware
- function(spaces2list variable_name)
- string(REPLACE " " ";" tmp "${${variable_name}}")
- set("${variable_name}" "${tmp}" PARENT_SCOPE)
- endfunction()
- # lines2list
- #
- # Take a variable with multiple lines of output in it, convert it
- # to a cmake list (semicolon-delimited), one line per item
- #
- function(lines2list variable_name)
- string(REGEX REPLACE "\r?\n" ";" tmp "${${variable_name}}")
- string(REGEX REPLACE ";;" ";" tmp "${tmp}")
- set("${variable_name}" "${tmp}" PARENT_SCOPE)
- endfunction()
- # move_if_different
- #
- # If 'source' has different md5sum to 'destination' (or destination
- # does not exist, move it across.
- #
- # If 'source' has the same md5sum as 'destination', delete 'source'.
- #
- # Avoids timestamp updates for re-generated files where content hasn't
- # changed.
- function(move_if_different source destination)
- set(do_copy 1)
- file(GLOB dest_exists ${destination})
- if(dest_exists)
- file(MD5 ${source} source_md5)
- file(MD5 ${destination} dest_md5)
- if(source_md5 STREQUAL dest_md5)
- set(do_copy "")
- endif()
- endif()
- if(do_copy)
- message("Moving ${source} -> ${destination}")
- file(RENAME ${source} ${destination})
- else()
- message("Not moving ${source} -> ${destination}")
- file(REMOVE ${source})
- endif()
- endfunction()
- # target_add_binary_data adds binary data into the built target,
- # by converting it to a generated source file which is then compiled
- # to a binary object as part of the build
- function(target_add_binary_data target embed_file embed_type)
- cmake_parse_arguments(_ "" "RENAME_TO" "" ${ARGN})
- idf_build_get_property(build_dir BUILD_DIR)
- idf_build_get_property(idf_path IDF_PATH)
- get_filename_component(embed_file "${embed_file}" ABSOLUTE)
- get_filename_component(name "${embed_file}" NAME)
- set(embed_srcfile "${build_dir}/${name}.S")
- set(rename_to_arg)
- if(__RENAME_TO) # use a predefined variable name
- set(rename_to_arg -D "VARIABLE_BASENAME=${__RENAME_TO}")
- endif()
- add_custom_command(OUTPUT "${embed_srcfile}"
- COMMAND "${CMAKE_COMMAND}"
- -D "DATA_FILE=${embed_file}"
- -D "SOURCE_FILE=${embed_srcfile}"
- ${rename_to_arg}
- -D "FILE_TYPE=${embed_type}"
- -P "${idf_path}/tools/cmake/scripts/data_file_embed_asm.cmake"
- MAIN_DEPENDENCY "${embed_file}"
- DEPENDS "${idf_path}/tools/cmake/scripts/data_file_embed_asm.cmake"
- WORKING_DIRECTORY "${build_dir}"
- VERBATIM)
- set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${embed_srcfile}")
- target_sources("${target}" PRIVATE "${embed_srcfile}")
- endfunction()
- macro(include_if_exists path)
- if(EXISTS "${path}")
- include("${path}")
- endif()
- endmacro()
- # Append a single line to the file specified
- # The line ending is determined by the host OS
- function(file_append_line file line)
- if(DEFINED ENV{MSYSTEM} OR CMAKE_HOST_WIN32)
- set(line_ending "\r\n")
- else() # unix
- set(line_ending "\n")
- endif()
- file(READ ${file} existing)
- string(FIND ${existing} ${line_ending} last_newline REVERSE)
- string(LENGTH ${existing} length)
- math(EXPR length "${length}-1")
- if(NOT length EQUAL last_newline) # file doesn't end with a newline
- file(APPEND "${file}" "${line_ending}")
- endif()
- file(APPEND "${file}" "${line}${line_ending}")
- endfunction()
- # Add one or more linker scripts to the target, including a link-time dependency
- #
- # Automatically adds a -L search path for the containing directory (if found),
- # and then adds -T with the filename only. This allows INCLUDE directives to be
- # used to include other linker scripts in the same directory.
- function(target_linker_script target deptype scriptfiles)
- cmake_parse_arguments(_ "" "PROCESS" "" ${ARGN})
- foreach(scriptfile ${scriptfiles})
- get_filename_component(abs_script "${scriptfile}" ABSOLUTE)
- message(STATUS "Adding linker script ${abs_script}")
- if(__PROCESS)
- get_filename_component(output "${__PROCESS}" ABSOLUTE)
- __ldgen_process_template(${abs_script} ${output})
- set(abs_script ${output})
- endif()
- get_filename_component(search_dir "${abs_script}" DIRECTORY)
- get_filename_component(scriptname "${abs_script}" NAME)
- if(deptype STREQUAL INTERFACE OR deptype STREQUAL PUBLIC)
- get_target_property(link_libraries "${target}" INTERFACE_LINK_LIBRARIES)
- else()
- get_target_property(link_libraries "${target}" LINK_LIBRARIES)
- endif()
- list(FIND "${link_libraries}" "-L ${search_dir}" found_search_dir)
- if(found_search_dir EQUAL "-1") # not already added as a search path
- target_link_libraries("${target}" "${deptype}" "-L ${search_dir}")
- endif()
- target_link_libraries("${target}" "${deptype}" "-T ${scriptname}")
- # Note: In ESP-IDF, most targets are libraries and libary LINK_DEPENDS don't propagate to
- # executable(s) the library is linked to. Attach manually to executable once it is known.
- #
- # Property INTERFACE_LINK_DEPENDS is available in CMake 3.13 which should propagate link
- # dependencies.
- if(NOT __PROCESS)
- idf_build_set_property(__LINK_DEPENDS ${abs_script} APPEND)
- endif()
- endforeach()
- endfunction()
- # Convert a CMake list to a JSON list and store it in a variable
- function(make_json_list list variable)
- string(REPLACE ";" "\", \"" result "[ \"${list}\" ]")
- set("${variable}" "${result}" PARENT_SCOPE)
- endfunction()
- # add_prefix
- #
- # Adds a prefix to each item in the specified list.
- #
- function(add_prefix var prefix)
- foreach(elm ${ARGN})
- list(APPEND newlist "${prefix}${elm}")
- endforeach()
- set(${var} "${newlist}" PARENT_SCOPE)
- endfunction()
- # fail_at_build_time
- #
- # Creates a phony target which fails the build and touches CMakeCache.txt to cause a cmake run next time.
- #
- # This is used when a missing file is required at CMake runtime, but we can't fail the build if it is not found,
- # because the "menuconfig" target may be required to fix the problem.
- #
- # We cannot use CMAKE_CONFIGURE_DEPENDS instead because it only works for files which exist at CMake runtime.
- #
- function(fail_at_build_time target_name message_line0)
- idf_build_get_property(idf_path IDF_PATH)
- set(message_lines COMMAND ${CMAKE_COMMAND} -E echo "${message_line0}")
- foreach(message_line ${ARGN})
- set(message_lines ${message_lines} COMMAND ${CMAKE_COMMAND} -E echo "${message_line}")
- endforeach()
- # Generate a timestamp file that gets included. When deleted on build, this forces CMake
- # to rerun.
- string(RANDOM filename)
- set(filename "${CMAKE_CURRENT_BINARY_DIR}/${filename}.cmake")
- file(WRITE "${filename}" "")
- include("${filename}")
- set(fail_message "Failing the build (see errors on lines above)")
- add_custom_target(${target_name} ALL
- ${message_lines}
- COMMAND ${CMAKE_COMMAND} -E remove "${filename}"
- COMMAND ${CMAKE_COMMAND} -E env FAIL_MESSAGE=${fail_message}
- ${CMAKE_COMMAND} -P ${idf_path}/tools/cmake/scripts/fail.cmake
- VERBATIM)
- endfunction()
- # fail_target
- #
- # Creates a phony target which fails when invoked. This is used when the necessary conditions
- # for a target are not met, such as configuration. Rather than ommitting the target altogether,
- # we fail execution with a helpful message.
- function(fail_target target_name message_line0)
- idf_build_get_property(idf_path IDF_PATH)
- set(message_lines COMMAND ${CMAKE_COMMAND} -E echo "${message_line0}")
- foreach(message_line ${ARGN})
- set(message_lines ${message_lines} COMMAND ${CMAKE_COMMAND} -E echo "${message_line}")
- endforeach()
- # Generate a timestamp file that gets included. When deleted on build, this forces CMake
- # to rerun.
- set(fail_message "Failed executing target (see errors on lines above)")
- add_custom_target(${target_name}
- ${message_lines}
- COMMAND ${CMAKE_COMMAND} -E env FAIL_MESSAGE=${fail_message}
- ${CMAKE_COMMAND} -P ${idf_path}/tools/cmake/scripts/fail.cmake
- VERBATIM)
- endfunction()
- function(check_exclusive_args args prefix)
- set(_args ${args})
- spaces2list(_args)
- set(only_arg 0)
- foreach(arg ${_args})
- if(${prefix}_${arg} AND only_arg)
- message(FATAL_ERROR "${args} are exclusive arguments")
- endif()
- if(${prefix}_${arg})
- set(only_arg 1)
- endif()
- endforeach()
- endfunction()
- # add_compile_options variant for C++ code only
- #
- # This adds global options, set target properties for
- # component-specific flags
- function(add_cxx_compile_options)
- foreach(option ${ARGV})
- # note: the Visual Studio Generator doesn't support this...
- add_compile_options($<$<COMPILE_LANGUAGE:CXX>:${option}>)
- endforeach()
- endfunction()
- # add_compile_options variant for C code only
- #
- # This adds global options, set target properties for
- # component-specific flags
- function(add_c_compile_options)
- foreach(option ${ARGV})
- # note: the Visual Studio Generator doesn't support this...
- add_compile_options($<$<COMPILE_LANGUAGE:C>:${option}>)
- endforeach()
- endfunction()
- # add_prebuild_library
- #
- # Add prebuilt library with support for adding dependencies on ESP-IDF components.
- function(add_prebuilt_library target_name lib_path)
- cmake_parse_arguments(_ "" "" "REQUIRES;PRIV_REQUIRES" ${ARGN})
- get_filename_component(lib_path "${lib_path}"
- ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
- add_library(${target_name} STATIC IMPORTED)
- set_property(TARGET ${target_name} PROPERTY IMPORTED_LOCATION ${lib_path})
- foreach(req ${__REQUIRES})
- idf_component_get_property(req_lib "${req}" COMPONENT_LIB)
- set_property(TARGET ${target_name} APPEND PROPERTY LINK_LIBRARIES "${req_lib}")
- set_property(TARGET ${target_name} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${req_lib}")
- endforeach()
- foreach(req ${__PRIV_REQUIRES})
- idf_component_get_property(req_lib "${req}" COMPONENT_LIB)
- set_property(TARGET ${target_name} APPEND PROPERTY LINK_LIBRARIES "${req_lib}")
- set_property(TARGET ${target_name} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "$<LINK_ONLY:${req_lib}>")
- endforeach()
- endfunction()
- # file_generate
- #
- # Utility to generate file and have the output automatically added to cleaned files.
- function(file_generate output)
- cmake_parse_arguments(_ "" "INPUT;CONTENT" "" ${ARGN})
- if(__INPUT)
- file(GENERATE OUTPUT "${output}" INPUT "${__INPUT}")
- elseif(__CONTENT)
- file(GENERATE OUTPUT "${output}" CONTENT "${__CONTENT}")
- else()
- message(FATAL_ERROR "Content to generate not specified.")
- endif()
- set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${output}")
- endfunction()
- # add_subdirectory_if_exists
- #
- # Like add_subdirectory, but only proceeds if the given source directory exists.
- function(add_subdirectory_if_exists source_dir)
- get_filename_component(abs_dir "${source_dir}"
- ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
- if(EXISTS "${abs_dir}")
- add_subdirectory("${source_dir}" ${ARGN})
- else()
- message(STATUS "Subdirectory '${abs_dir}' does not exist, skipped.")
- endif()
- endfunction()
|