kconfig.cmake 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. include(ExternalProject)
  2. function(__kconfig_init)
  3. idf_build_get_property(idf_path IDF_PATH)
  4. if(CMAKE_HOST_WIN32)
  5. # Prefer a prebuilt mconf-idf on Windows
  6. if(DEFINED ENV{MSYSTEM})
  7. find_program(WINPTY winpty)
  8. else()
  9. unset(WINPTY CACHE) # in case previous CMake run was in a tty and this one is not
  10. endif()
  11. unset(MCONF CACHE) # needed when MSYS and CMD is intermixed (cache could contain an incompatible path)
  12. find_program(MCONF mconf-idf)
  13. # Fall back to the old binary which was called 'mconf' not 'mconf-idf'
  14. if(NOT MCONF)
  15. find_program(MCONF mconf)
  16. if(MCONF)
  17. message(WARNING "Falling back to mconf binary '${MCONF}' not mconf-idf. "
  18. "This is probably because an old version of IDF mconf is installed and this is fine. "
  19. "However if there are config problems please check the Getting Started guide for your platform.")
  20. endif()
  21. endif()
  22. if(NOT MCONF)
  23. find_program(NATIVE_GCC gcc)
  24. if(NOT NATIVE_GCC)
  25. message(FATAL_ERROR
  26. "Windows requires a prebuilt mconf-idf for your platform "
  27. "on the PATH, or an MSYS2 version of gcc on the PATH to build mconf-idf. "
  28. "Consult the setup docs for ESP-IDF on Windows.")
  29. endif()
  30. else()
  31. execute_process(COMMAND "${MCONF}" -v
  32. RESULT_VARIABLE mconf_res
  33. OUTPUT_VARIABLE mconf_out
  34. ERROR_VARIABLE mconf_err)
  35. if(${mconf_res})
  36. message(WARNING "Failed to detect version of mconf-idf. Return code was ${mconf_res}.")
  37. else()
  38. string(STRIP "${mconf_out}" mconf_out)
  39. set(mconf_expected_ver "mconf-v4.6.0.0-idf-20190628-win32")
  40. if(NOT ${mconf_out} STREQUAL "mconf-idf version ${mconf_expected_ver}")
  41. message(WARNING "Unexpected ${mconf_out}. Expected ${mconf_expected_ver}. "
  42. "Please check the ESP-IDF Getting Started guide for version "
  43. "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH} "
  44. "to correct this issue")
  45. else()
  46. message(STATUS "${mconf_out}") # prints: mconf-idf version ....
  47. endif()
  48. endif()
  49. if(WINPTY)
  50. set(MCONF "\"${WINPTY}\" \"${MCONF}\"")
  51. endif()
  52. endif()
  53. endif()
  54. if(NOT MCONF)
  55. # Use the existing Makefile to build mconf (out of tree) when needed
  56. #
  57. set(MCONF ${CMAKE_BINARY_DIR}/kconfig_bin/mconf-idf)
  58. set(src_path ${idf_path}/tools/kconfig)
  59. # note: we preemptively remove any build files from the src dir
  60. # as we're building out of tree, but don't want build system to
  61. # #include any from there that were previously build with/for make
  62. externalproject_add(mconf-idf
  63. SOURCE_DIR ${src_path}
  64. CONFIGURE_COMMAND ""
  65. BINARY_DIR "${CMAKE_BINARY_DIR}/kconfig_bin"
  66. BUILD_COMMAND rm -f ${src_path}/zconf.lex.c ${src_path}/zconf.hash.c
  67. COMMAND make -f ${src_path}/Makefile mconf-idf
  68. BUILD_BYPRODUCTS ${MCONF}
  69. INSTALL_COMMAND ""
  70. EXCLUDE_FROM_ALL 1
  71. )
  72. file(GLOB mconf_srcfiles ${src_path}/*.c)
  73. list(REMOVE_ITEM mconf_srcfiles "${src_path}/zconf.lex.c" "${src_path}/zconf.hash.c")
  74. externalproject_add_stepdependencies(mconf-idf build
  75. ${mconf_srcfiles}
  76. ${src_path}/Makefile
  77. ${CMAKE_CURRENT_LIST_FILE})
  78. unset(mconf_srcfiles)
  79. unset(src_path)
  80. set(menuconfig_depends DEPENDS mconf-idf)
  81. endif()
  82. idf_build_set_property(__MCONF ${MCONF})
  83. idf_build_set_property(__MENUCONFIG_DEPENDS "${menuconfig_depends}")
  84. idf_build_get_property(idf_path IDF_PATH)
  85. idf_build_set_property(__ROOT_KCONFIG ${idf_path}/Kconfig)
  86. idf_build_set_property(__ROOT_SDKCONFIG_RENAME ${idf_path}/sdkconfig.rename)
  87. idf_build_set_property(__OUTPUT_SDKCONFIG 1)
  88. endfunction()
  89. #
  90. # Initialize Kconfig-related properties for components.
  91. # This function assumes that all basic properties of the components have been
  92. # set prior to calling it.
  93. #
  94. function(__kconfig_component_init component_target)
  95. __component_get_property(component_dir ${component_target} COMPONENT_DIR)
  96. file(GLOB kconfig "${component_dir}/Kconfig")
  97. __component_set_property(${component_target} KCONFIG "${kconfig}")
  98. file(GLOB kconfig "${component_dir}/Kconfig.projbuild")
  99. __component_set_property(${component_target} KCONFIG_PROJBUILD "${kconfig}")
  100. file(GLOB sdkconfig_rename "${component_dir}/sdkconfig.rename")
  101. __component_set_property(${component_target} SDKCONFIG_RENAME "${sdkconfig_rename}")
  102. endfunction()
  103. #
  104. # Generate the config files and create config related targets and configure
  105. # dependencies.
  106. #
  107. function(__kconfig_generate_config sdkconfig sdkconfig_defaults)
  108. # List all Kconfig and Kconfig.projbuild in known components
  109. idf_build_get_property(component_targets __COMPONENT_TARGETS)
  110. idf_build_get_property(build_component_targets __BUILD_COMPONENT_TARGETS)
  111. foreach(component_target ${component_targets})
  112. if(component_target IN_LIST build_component_targets)
  113. __component_get_property(kconfig ${component_target} KCONFIG)
  114. __component_get_property(kconfig_projbuild ${component_target} KCONFIG_PROJBUILD)
  115. __component_get_property(sdkconfig_rename ${component_target} SDKCONFIG_RENAME)
  116. if(kconfig)
  117. list(APPEND kconfigs ${kconfig})
  118. endif()
  119. if(kconfig_projbuild)
  120. list(APPEND kconfig_projbuilds ${kconfig_projbuild})
  121. endif()
  122. if(sdkconfig_rename)
  123. list(APPEND sdkconfig_renames ${sdkconfig_rename})
  124. endif()
  125. endif()
  126. endforeach()
  127. # Store the list version of kconfigs and kconfig_projbuilds
  128. idf_build_set_property(KCONFIGS "${kconfigs}")
  129. idf_build_set_property(KCONFIG_PROJBUILDS "${kconfig_projbuilds}")
  130. idf_build_get_property(idf_target IDF_TARGET)
  131. idf_build_get_property(idf_path IDF_PATH)
  132. string(REPLACE ";" " " kconfigs "${kconfigs}")
  133. string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}")
  134. string(REPLACE ";" " " sdkconfig_renames "${sdkconfig_renames}")
  135. # Place config-related environment arguments into config.env file
  136. # to work around command line length limits for execute_process
  137. # on Windows & CMake < 3.11
  138. set(config_env_path "${CMAKE_CURRENT_BINARY_DIR}/config.env")
  139. configure_file("${idf_path}/tools/kconfig_new/config.env.in" ${config_env_path})
  140. idf_build_set_property(CONFIG_ENV_PATH ${config_env_path})
  141. if(sdkconfig_defaults)
  142. set(defaults_arg --defaults "${sdkconfig_defaults}")
  143. endif()
  144. if(EXISTS "${sdkconfig_defaults}.${idf_target}")
  145. list(APPEND defaults_arg --defaults "${sdkconfig_defaults}.${idf_target}")
  146. endif()
  147. idf_build_get_property(root_kconfig __ROOT_KCONFIG)
  148. idf_build_get_property(root_sdkconfig_rename __ROOT_SDKCONFIG_RENAME)
  149. idf_build_get_property(python PYTHON)
  150. set(confgen_basecommand
  151. ${python} ${idf_path}/tools/kconfig_new/confgen.py
  152. --kconfig ${root_kconfig}
  153. --sdkconfig-rename ${root_sdkconfig_rename}
  154. --config ${sdkconfig}
  155. ${defaults_arg}
  156. --env-file ${config_env_path})
  157. idf_build_get_property(build_dir BUILD_DIR)
  158. set(config_dir ${build_dir}/config)
  159. file(MAKE_DIRECTORY "${config_dir}")
  160. # Generate the config outputs
  161. set(sdkconfig_cmake ${config_dir}/sdkconfig.cmake)
  162. set(sdkconfig_header ${config_dir}/sdkconfig.h)
  163. set(sdkconfig_json ${config_dir}/sdkconfig.json)
  164. set(sdkconfig_json_menus ${config_dir}/kconfig_menus.json)
  165. idf_build_get_property(output_sdkconfig __OUTPUT_SDKCONFIG)
  166. if(output_sdkconfig)
  167. execute_process(
  168. COMMAND ${confgen_basecommand}
  169. --output header ${sdkconfig_header}
  170. --output cmake ${sdkconfig_cmake}
  171. --output json ${sdkconfig_json}
  172. --output json_menus ${sdkconfig_json_menus}
  173. --output config ${sdkconfig}
  174. RESULT_VARIABLE config_result)
  175. else()
  176. execute_process(
  177. COMMAND ${confgen_basecommand}
  178. --output header ${sdkconfig_header}
  179. --output cmake ${sdkconfig_cmake}
  180. --output json ${sdkconfig_json}
  181. --output json_menus ${sdkconfig_json_menus}
  182. RESULT_VARIABLE config_result)
  183. endif()
  184. if(config_result)
  185. message(FATAL_ERROR "Failed to run confgen.py (${confgen_basecommand}). Error ${config_result}")
  186. endif()
  187. # Add the generated config header to build specifications.
  188. idf_build_set_property(INCLUDE_DIRECTORIES ${config_dir} APPEND)
  189. # When sdkconfig file changes in the future, trigger a cmake run
  190. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sdkconfig}")
  191. # Ditto if either of the generated files are missing/modified (this is a bit irritating as it means
  192. # you can't edit these manually without them being regenerated, but I don't know of a better way...)
  193. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sdkconfig_header}")
  194. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sdkconfig_cmake}")
  195. # Or if the config generation tool changes
  196. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${idf_path}/tools/kconfig_new/confgen.py")
  197. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${idf_path}/tools/kconfig_new/kconfiglib.py")
  198. set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY
  199. ADDITIONAL_MAKE_CLEAN_FILES "${sdkconfig_header}" "${sdkconfig_cmake}")
  200. idf_build_set_property(SDKCONFIG_HEADER ${sdkconfig_header})
  201. idf_build_set_property(SDKCONFIG_JSON ${sdkconfig_json})
  202. idf_build_set_property(SDKCONFIG_CMAKE ${sdkconfig_cmake})
  203. idf_build_set_property(SDKCONFIG_JSON_MENUS ${sdkconfig_json_menus})
  204. idf_build_set_property(CONFIG_DIR ${config_dir})
  205. idf_build_get_property(menuconfig_depends __MENUCONFIG_DEPENDS)
  206. idf_build_get_property(mconf __MCONF)
  207. # Generate the menuconfig target (uses C-based mconf-idf tool, either prebuilt or via mconf-idf target above)
  208. add_custom_target(menuconfig
  209. ${menuconfig_depends}
  210. # create any missing config file, with defaults if necessary
  211. COMMAND ${confgen_basecommand}
  212. --env "IDF_TARGET=${idf_target}"
  213. --dont-write-deprecated
  214. --output config ${sdkconfig}
  215. COMMAND ${CMAKE_COMMAND} -E env
  216. "COMPONENT_KCONFIGS=${kconfigs}"
  217. "COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}"
  218. "IDF_CMAKE=y"
  219. "KCONFIG_CONFIG=${sdkconfig}"
  220. "IDF_TARGET=${idf_target}"
  221. ${mconf} ${root_kconfig}
  222. # VERBATIM cannot be used here because it cannot handle ${mconf}="winpty mconf-idf" and the escaping must be
  223. # done manually
  224. USES_TERMINAL
  225. # additional run of confgen esures that the deprecated options will be inserted into sdkconfig (for backward
  226. # compatibility)
  227. COMMAND ${confgen_basecommand} --env "IDF_TARGET=${idf_target}" --output config ${sdkconfig}
  228. )
  229. # Custom target to run confserver.py from the build tool
  230. add_custom_target(confserver
  231. COMMAND ${PYTHON} ${IDF_PATH}/tools/kconfig_new/confserver.py
  232. --env-file ${config_env_path}
  233. --kconfig ${IDF_PATH}/Kconfig
  234. --sdkconfig-rename ${root_sdkconfig_rename}
  235. --config ${sdkconfig}
  236. VERBATIM
  237. USES_TERMINAL)
  238. endfunction()