kconfig.cmake 15 KB

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