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