utilities.cmake 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. # set_default
  2. #
  3. # Define a variable to a default value if otherwise unset.
  4. #
  5. # Priority for new value is:
  6. # - Existing cmake value (ie set with cmake -D, or already set in CMakeLists)
  7. # - Value of any non-empty environment variable of the same name
  8. # - Default value as provided to function
  9. #
  10. function(set_default variable default_value)
  11. if(NOT ${variable})
  12. if(DEFINED ENV{${variable}} AND NOT "$ENV{${variable}}" STREQUAL "")
  13. set(${variable} $ENV{${variable}} PARENT_SCOPE)
  14. else()
  15. set(${variable} ${default_value} PARENT_SCOPE)
  16. endif()
  17. endif()
  18. endfunction()
  19. # spaces2list
  20. #
  21. # Take a variable whose value was space-delimited values, convert to a cmake
  22. # list (semicolon-delimited)
  23. #
  24. # Note: if using this for directories, keeps the issue in place that
  25. # directories can't contain spaces...
  26. #
  27. # TODO: look at cmake separate_arguments, which is quote-aware
  28. function(spaces2list variable_name)
  29. string(REPLACE " " ";" tmp "${${variable_name}}")
  30. set("${variable_name}" "${tmp}" PARENT_SCOPE)
  31. endfunction()
  32. # lines2list
  33. #
  34. # Take a variable with multiple lines of output in it, convert it
  35. # to a cmake list (semicolon-delimited), one line per item
  36. #
  37. function(lines2list variable_name)
  38. string(REGEX REPLACE "\r?\n" ";" tmp "${${variable_name}}")
  39. string(REGEX REPLACE ";;" ";" tmp "${tmp}")
  40. set("${variable_name}" "${tmp}" PARENT_SCOPE)
  41. endfunction()
  42. # move_if_different
  43. #
  44. # If 'source' has different md5sum to 'destination' (or destination
  45. # does not exist, move it across.
  46. #
  47. # If 'source' has the same md5sum as 'destination', delete 'source'.
  48. #
  49. # Avoids timestamp updates for re-generated files where content hasn't
  50. # changed.
  51. function(move_if_different source destination)
  52. set(do_copy 1)
  53. file(GLOB dest_exists ${destination})
  54. if(dest_exists)
  55. file(MD5 ${source} source_md5)
  56. file(MD5 ${destination} dest_md5)
  57. if(source_md5 STREQUAL dest_md5)
  58. set(do_copy "")
  59. endif()
  60. endif()
  61. if(do_copy)
  62. message("Moving ${source} -> ${destination}")
  63. file(RENAME ${source} ${destination})
  64. else()
  65. message("Not moving ${source} -> ${destination}")
  66. file(REMOVE ${source})
  67. endif()
  68. endfunction()
  69. # add_compile_options variant for C++ code only
  70. #
  71. # This adds global options, set target properties for
  72. # component-specific flags
  73. function(add_cxx_compile_options)
  74. foreach(option ${ARGV})
  75. # note: the Visual Studio Generator doesn't support this...
  76. add_compile_options($<$<COMPILE_LANGUAGE:CXX>:${option}>)
  77. endforeach()
  78. endfunction()
  79. # add_compile_options variant for C code only
  80. #
  81. # This adds global options, set target properties for
  82. # component-specific flags
  83. function(add_c_compile_options)
  84. foreach(option ${ARGV})
  85. # note: the Visual Studio Generator doesn't support this...
  86. add_compile_options($<$<COMPILE_LANGUAGE:C>:${option}>)
  87. endforeach()
  88. endfunction()
  89. # target_add_binary_data adds binary data into the built target,
  90. # by converting it to a generated source file which is then compiled
  91. # to a binary object as part of the build
  92. function(target_add_binary_data target embed_file embed_type)
  93. get_filename_component(embed_file "${embed_file}" ABSOLUTE)
  94. get_filename_component(name "${embed_file}" NAME)
  95. set(embed_srcfile "${IDF_BUILD_ARTIFACTS_DIR}/${name}.S")
  96. add_custom_command(OUTPUT "${embed_srcfile}"
  97. COMMAND "${CMAKE_COMMAND}"
  98. -D "DATA_FILE=${embed_file}"
  99. -D "SOURCE_FILE=${embed_srcfile}"
  100. -D "FILE_TYPE=${embed_type}"
  101. -P "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake"
  102. MAIN_DEPENDENCY "${embed_file}"
  103. DEPENDS "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake"
  104. WORKING_DIRECTORY "${IDF_BUILD_ARTIFACTS_DIR}"
  105. VERBATIM)
  106. set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${embed_srcfile}")
  107. target_sources("${target}" PRIVATE "${embed_srcfile}")
  108. endfunction()
  109. macro(include_if_exists path)
  110. if(EXISTS "${path}")
  111. include("${path}")
  112. endif()
  113. endmacro()
  114. # Append a single line to the file specified
  115. # The line ending is determined by the host OS
  116. function(file_append_line file line)
  117. if(DEFINED ENV{MSYSTEM} OR CMAKE_HOST_WIN32)
  118. set(line_ending "\r\n")
  119. else() # unix
  120. set(line_ending "\n")
  121. endif()
  122. file(READ ${file} existing)
  123. string(FIND ${existing} ${line_ending} last_newline REVERSE)
  124. string(LENGTH ${existing} length)
  125. math(EXPR length "${length}-1")
  126. if(NOT length EQUAL last_newline) # file doesn't end with a newline
  127. file(APPEND "${file}" "${line_ending}")
  128. endif()
  129. file(APPEND "${file}" "${line}${line_ending}")
  130. endfunction()
  131. # Add one or more linker scripts to the target, including a link-time dependency
  132. #
  133. # Automatically adds a -L search path for the containing directory (if found),
  134. # and then adds -T with the filename only. This allows INCLUDE directives to be
  135. # used to include other linker scripts in the same directory.
  136. function(target_linker_script target)
  137. foreach(scriptfile ${ARGN})
  138. get_filename_component(abs_script "${scriptfile}" ABSOLUTE)
  139. message(STATUS "Adding linker script ${abs_script}")
  140. get_filename_component(search_dir "${abs_script}" DIRECTORY)
  141. get_filename_component(scriptname "${abs_script}" NAME)
  142. get_target_property(link_libraries "${target}" LINK_LIBRARIES)
  143. list(FIND "${link_libraries}" "-L ${search_dir}" found_search_dir)
  144. if(found_search_dir EQUAL "-1") # not already added as a search path
  145. target_link_libraries("${target}" "-L ${search_dir}")
  146. endif()
  147. target_link_libraries("${target}" "-T ${scriptname}")
  148. # Note: In ESP-IDF, most targets are libraries and libary LINK_DEPENDS don't propagate to
  149. # executable(s) the library is linked to. This is done manually in components.cmake.
  150. set_property(TARGET "${target}" APPEND PROPERTY LINK_DEPENDS "${abs_script}")
  151. endforeach()
  152. endfunction()
  153. # Convert a CMake list to a JSON list and store it in a variable
  154. function(make_json_list list variable)
  155. string(REPLACE ";" "\", \"" result "[ \"${list}\" ]")
  156. set("${variable}" "${result}" PARENT_SCOPE)
  157. endfunction()
  158. # add_prefix
  159. #
  160. # Adds a prefix to each item in the specified list.
  161. #
  162. function(add_prefix var prefix)
  163. foreach(elm ${ARGN})
  164. list(APPEND newlist "${prefix}${elm}")
  165. endforeach()
  166. set(${var} "${newlist}" PARENT_SCOPE)
  167. endfunction()
  168. # fail_at_build_time
  169. #
  170. # Creates a phony target which fails the build and touches CMakeCache.txt to cause a cmake run next time.
  171. #
  172. # This is used when a missing file is required at CMake runtime, but we can't fail the build if it is not found,
  173. # because the "menuconfig" target may be required to fix the problem.
  174. #
  175. # We cannot use CMAKE_CONFIGURE_DEPENDS instead because it only works for files which exist at CMake runtime.
  176. #
  177. function(fail_at_build_time target_name message_line0)
  178. set(message_lines COMMAND ${CMAKE_COMMAND} -E echo "${message_line0}")
  179. foreach(message_line ${ARGN})
  180. set(message_lines ${message_lines} COMMAND ${CMAKE_COMMAND} -E echo "${message_line}")
  181. endforeach()
  182. add_custom_target(${target_name} ALL
  183. ${message_lines}
  184. COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt"
  185. COMMAND ${CMAKE_COMMAND} -P ${IDF_PATH}/tools/cmake/scripts/fail.cmake
  186. VERBATIM)
  187. endfunction()