diff --git a/components/bootloader/subproject/CMakeLists.txt b/components/bootloader/subproject/CMakeLists.txt index ab7b5aaa6..1931392d5 100644 --- a/components/bootloader/subproject/CMakeLists.txt +++ b/components/bootloader/subproject/CMakeLists.txt @@ -1,24 +1,21 @@ cmake_minimum_required(VERSION 3.5) set(CMAKE_TOOLCHAIN_FILE $ENV{IDF_PATH}/toolchain.cmake) -project(idf_bootloader ASM C CXX) + +if(NOT SDKCONFIG) + message(FATAL_ERROR "Bootloader subproject expects the SDKCONFIG variable to be passed in by the parent build process.") +endif() + +project(bootloader ASM C CXX) set(COMPONENTS bootloader esptool_py esp32 soc bootloader_support log spi_flash micro-ecc soc) - set(BOOTLOADER_BUILD 1) set(IS_BOOTLOADER_BUILD 1) # deprecated, use BOOTLOADER_BUILD add_definitions(-DBOOTLOADER_BUILD=1) -if(NOT SDKCONFIG) - message(FATAL_ERROR "Bootloader subproject expects the SDKCONFIG variable to be passed in by the app build process.") -endif() - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) - -add_executable(bootloader.elf - main/bootloader_start.c +set(MAIN_SRCS main/bootloader_start.c main/flash_qio_mode.c) -target_link_libraries(bootloader.elf ${COMPONENT_LIBRARIES}) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) target_link_libraries(bootloader.elf "-L ${CMAKE_CURRENT_SOURCE_DIR}/main") target_link_libraries(bootloader.elf "-T esp32.bootloader.ld") diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake new file mode 100644 index 000000000..52fc289ee --- /dev/null +++ b/components/esptool_py/project_include.cmake @@ -0,0 +1,48 @@ +# Set some global esptool.py variables +set(ESPTOOLPY "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/esptool/esptool.py" --chip esp32) +set(ESPSECUREPY "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py") + +set(ESPPORT $ENV{ESPPORT}) +if(NOT ESPPORT) + set(ESPPORT ${CONFIG_ESPTOOLPY_PORT}) +endif() + +set(ESPBAUD $ENV{ESPPORT}) +if(NOT ESPBAUD) + set(ESPPORT ${CONFIG_ESPTOOLPY_PORT}) +endif() + +set(ESPFLASHMODE ${CONFIG_ESPTOOLPY_FLASHMODE}) +set(ESPFLASHFREQ ${CONFIG_ESPTOOLPY_FLASHFREQ}) +set(ESPFLASHSIZE ${CONFIG_ESPTOOLPY_FLASHSIZE}) + +set(ESPTOOLPY_SERIAL "${ESPTOOLPY}" --port "${ESPPORT}" --baud ${ESPBAUD}) + +if(CONFIG_ESPTOOLPY_FLASHSIZE_DETECT) + set(flashsize_arg detect) +else() + set(flashsize_arg ${ESPFLASHSIZE}) +endif() + +set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS --flash_mode ${ESPFLASHMODE} --flash_freq ${ESPFLASHFREQ} --flash_size ${ESPFLASHSIZE}) + +set(ESPTOOLPY_WRITE_FLASH_OPTIONS --flash_mode ${ESPFLASHMODE} --flash_freq ${ESPFLASHFREQ} --flash_size ${flashsize_Arg}) + +set(ESPTOOLPY_WRITE_FLASH ${ESPTOOLPY_SERIAL} write_flash ${ESPTOOLPY_WRITE_FLASH_OPTIONS}) + +# +# Add 'binary' target - generates with elf2image +# +add_custom_command(OUTPUT "${PROJECT_NAME}.bin" + COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} -o "${PROJECT_NAME}.bin" "${PROJECT_NAME}.elf" + DEPENDS ${PROJECT_NAME}.elf + VERBATIM + ) +add_custom_target(binary ALL DEPENDS "${PROJECT_NAME}.bin") + +# +# Add 'flash' target - not all build systems can run this directly +# +add_custom_target(flash DEPENDS binary partition_table bootloader_subproject) +# TODO: this target should call "idftool" not esptool directly, so it can +# override things (port, baud, etc) at runtime not configure time diff --git a/components/partition_table/CMakeLists.txt b/components/partition_table/CMakeLists.txt index b8a17b13a..f39408806 100644 --- a/components/partition_table/CMakeLists.txt +++ b/components/partition_table/CMakeLists.txt @@ -20,27 +20,34 @@ else() set(final_partition_target "build_partition_table") endif() -add_custom_target(build_partition_table ALL - "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" -q - ${partition_csv} ${unsigned_partition_bin} - BYPRODUCTS ${unsigned_partition_bin} - DEPENDS ${partition_csv} "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" - VERBATIM) +if(CONFIG_PARTITION_TABLE_MD5) + set(md5_opt --disable-md5sum) +endif() + +if(CONFIG_ESPTOOLPY_FLASHSIZE) + set(flashsize_opt --flash-size ${CONFIG_ESPTOOLPY_FLASHSIZE}) +endif() + +add_custom_command(OUTPUT "${unsigned_partition_bin}" + COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" -q ${md5_opt} ${flashsize_opt} + ${partition_csv} ${unsigned_partition_bin} + DEPENDS ${partition_csv} "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" + VERBATIM) # Add signing steps if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) get_filename_component(secure_boot_signing_key "${CONFIG_SECURE_BOOT_SIGNING_KEY}" ABSOLUTE BASE_DIR "${PROJECT_PATH}") - add_custom_target(signpartition_table ALL - "${PYTHON}" "${ESPSECUREPY}" sign_data --keyfile "${secure_boot_signing_key}" -o "${final_partition_bin}" "${unsigned_partition_bin}" - BYPRODUCTS "${final_partition_bin}" + add_custom_command(OUTPUT "${final_partition_bin}" + COMMAND "${PYTHON}" "${ESPSECUREPY}" sign_data --keyfile "${secure_boot_signing_key}" -o "${final_partition_bin}" "${unsigned_partition_bin}" DEPENDS "${unsigned_partition_bin}" VERBATIM) endif() -# Use global properties ESPTOOL_WRITE_FLASH_ARGS & FLASH_DEPENDS to pass this info to the esptool component for flashing -set_property(GLOBAL APPEND_STRING PROPERTY ESPTOOL_WRITE_FLASH_ARGS "${final_partition_bin} ${partition_table_offset} ") -set_property(GLOBAL APPEND PROPERTY FLASH_DEPENDS "${final_partition_target}") +add_custom_target(partition_table ALL DEPENDS "${final_partition_bin}") + +# Use global properties ESPTOOL_WRITE_FLASH_ARGS to pass this info to build hte list of esptool write arguments for flashing +set_property(GLOBAL APPEND_STRING PROPERTY ESPTOOL_WRITE_FLASH_ARGS "${partition_table_offset} ${final_partition_bin} ") register_config_only_component() diff --git a/examples/get-started/hello_world/CMakeLists.txt b/examples/get-started/hello_world/CMakeLists.txt index 4e66c5efd..4ae205fa2 100644 --- a/examples/get-started/hello_world/CMakeLists.txt +++ b/examples/get-started/hello_world/CMakeLists.txt @@ -1,12 +1,10 @@ -# The following four lines of boilerplate have to be in your project's CMakeLists +# The following five lines of boilerplate have to be in your project's CMakeLists # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) set(CMAKE_TOOLCHAIN_FILE $ENV{IDF_PATH}/toolchain.cmake) -project(idf_project ASM C CXX) + +project(hello-world ASM C CXX) + +set(MAIN_SRCS main/hello_world_main.c) include($ENV{IDF_PATH}/tools/cmake/project.cmake) - -add_executable(hello_world.elf - main/hello_world_main.c) - -target_link_libraries(hello_world.elf ${COMPONENT_LIBRARIES}) diff --git a/tools/cmake/components.cmake b/tools/cmake/components.cmake index 9930a44eb..8e2b85775 100644 --- a/tools/cmake/components.cmake +++ b/tools/cmake/components.cmake @@ -76,6 +76,15 @@ function(register_component) endforeach() endif() + # add public includes from other components when building this component + if(COMPONENT_SRCS OR embed_binaries) + add_library(${component} STATIC ${COMPONENT_SRCS}) + set(include_type PUBLIC) + else() + add_library(${component} INTERFACE) # header-only component + set(include_type INTERFACE) + endif() + # binaries to embed directly in library spaces2list(COMPONENT_EMBED_FILES) spaces2list(COMPONENT_EMBED_TXTFILES) @@ -88,20 +97,13 @@ function(register_component) target_add_binary_data("${component}" "${embed_data}" "${embed_type}") endforeach() - # add public includes from other components when building this component - if(COMPONENT_SRCS OR embed_binaries) - add_library(${component} STATIC ${COMPONENT_SRCS} ${embed_binaries}) - set(include_type PUBLIC) - else() - add_library(${component} INTERFACE) # header-only component - set(include_type INTERFACE) - endif(COMPONENT_SRCS OR embed_binaries) - + # add public includes foreach(include_dir ${COMPONENT_ADD_INCLUDEDIRS}) get_filename_component(include_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir}) target_include_directories(${component} ${include_type} ${include_dir}) endforeach() + # add private includes foreach(include_dir ${COMPONENT_PRIV_INCLUDEDIRS}) if (${include_type} STREQUAL INTERFACE) message(FATAL_ERROR "Component ${component} can't have no source files and COMPONENT_PRIV_INCLUDEDIRS set.") @@ -123,10 +125,10 @@ function(components_finish_registration) # each component should see the include directories of each other # # (we can't do this until all components are registered, because if(TARGET ...) won't work - foreach(a ${COMPONENTS}) + foreach(a ${COMPONENTS} ${CMAKE_PROJECT_NAME}.elf) if (TARGET ${a}) get_target_property(a_type ${a} TYPE) - if (${a_type} STREQUAL STATIC_LIBRARY) + if (${a_type} STREQUAL STATIC_LIBRARY OR ${a_type} STREQUAL EXECUTABLE) foreach(b ${COMPONENTS}) if (TARGET ${b} AND NOT ${a} STREQUAL ${b}) # Add all public compile options from b in a @@ -138,15 +140,14 @@ function(components_finish_registration) $) endif() endforeach(b) - endif(${a_type} STREQUAL STATIC_LIBRARY) + endif(${a_type} STREQUAL STATIC_LIBRARY OR ${a_type} STREQUAL EXECUTABLE) - set(COMPONENT_LIBRARIES "${COMPONENT_LIBRARIES};${a}") + if (${a_type} MATCHES .+_LIBRARY) + set(COMPONENT_LIBRARIES "${COMPONENT_LIBRARIES};${a}") + endif() endif() endforeach() - # set COMPONENT_LIBRARIES in top-level scope - set(COMPONENT_LIBRARIES "${COMPONENT_LIBRARIES}" PARENT_SCOPE) - # Embedded binary & text files spaces2list(COMPONENT_EMBED_FILES) foreach(embed_src ${COMPONENT_EMBED_FILES}) @@ -157,4 +158,6 @@ function(components_finish_registration) target_add_binary_data(${component} "${embed_src}" TEXT) endforeach() + target_link_libraries(${CMAKE_PROJECT_NAME}.elf ${COMPONENT_LIBRARIES}) + endfunction(components_finish_registration) diff --git a/tools/cmake/idf_functions.cmake b/tools/cmake/idf_functions.cmake index a9100b7db..d7f9bb235 100644 --- a/tools/cmake/idf_functions.cmake +++ b/tools/cmake/idf_functions.cmake @@ -3,6 +3,7 @@ include(crosstool_version_check) macro(idf_set_global_variables) + # Note that CONFIG_xxx is not available when this function is called set_default(EXTRA_COMPONENT_DIRS "") @@ -18,6 +19,9 @@ macro(idf_set_global_variables) spaces2list(COMPONENTS) + # Tell cmake to drop executables in the top-level build dir + set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}") + endmacro() # Add all the IDF global compiler & preprocessor options @@ -76,27 +80,18 @@ function(idf_set_global_compiler_options) endfunction(idf_set_global_compiler_options) -# Override add_executable to add IDF-specific -# linker flags & map file to all built executables -function(add_executable target) - get_filename_component(basename ${target} NAME_WE) - set(mapfile "${basename}.map") - - _add_executable(${ARGV}) - - target_link_libraries(${target} "-Wl,--gc-sections -Wl,--cref -Wl,--Map=${mapfile} -Wl,--start-group") - - set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${mapfile}") -endfunction(add_executable) - # Verify the IDF environment is configured correctly (environment, toolchain, etc) function(idf_verify_environment) + if(NOT CMAKE_PROJECT_NAME) + message(FATAL_ERROR "Project top-level CMakeLists.txt file must call project() before including project.cmake") + endif() + # Check toolchain is configured properly in cmake if(NOT ( ${CMAKE_SYSTEM_NAME} STREQUAL "Generic" AND ${CMAKE_C_COMPILER} MATCHES xtensa)) - message(FATAL_ERROR "The parent project CMakeLists.txt file needs to set CMAKE_TOOLCHAIN_FILE " - "before including this file. " + message(FATAL_ERROR "Project top-level CMakeLists.txt file needs to set CMAKE_TOOLCHAIN_FILE " + "before including project.cmake.\n" "Update CMakeLists.txt to match the template project and delete CMakeCache.txt before " "re-running cmake.") endif() @@ -108,3 +103,28 @@ function(idf_verify_environment) crosstool_version_check("1.22.0-80-g6c4433a") endfunction() + +# idf_add_executable +# +# Calls add_executable to add the final project executable +# Adds .map & .bin file targets +# Sets up flash-related targets +function(idf_add_executable) + set(exe_target ${PROJECT_NAME}.elf) + + spaces2list(${MAIN_SRCS}) + add_executable(${exe_target} "${MAIN_SRCS}") + + add_map_file(${exe_target}) +endfunction(idf_add_executable) + + +# add_map_file +# +# Set linker args for 'exe_target' to generate a linker Map file +function(add_map_file exe_target) + get_filename_component(basename ${exe_target} NAME_WE) + set(mapfile "${basename}.map") + target_link_libraries(${exe_target} "-Wl,--gc-sections -Wl,--cref -Wl,--Map=${mapfile} -Wl,--start-group") + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${mapfile}") +endfunction(add_map_file) diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index f45d7166d..a37d6fd0c 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -50,17 +50,31 @@ add_definitions(-DIDF_VER=\"${GIT_REVISION}\") git_submodule_check("${IDF_PATH}") +# Include any top-level project_include.cmake files from components +foreach(component ${COMPONENT_PATHS}) + include_if_exists("${component}/project_include.cmake") +endforeach() + # -# Add components to the build +# Add each component to the build as a library # foreach(component ${COMPONENT_PATHS}) get_filename_component(component_name ${component} NAME) add_subdirectory(${component} ${component_name}) endforeach() +# +# Add the app executable to the build (has name of PROJECT.elf) +# +idf_add_executable() + +# +# Finish component registration (add cross-dependencies, make +# executable dependent on all components.) +# components_finish_registration() -# Load the targets for the bootloader subproject +# Define the external target to build the bootloader subproject if(NOT BOOTLOADER_BUILD) include(bootloader_subproject) endif() diff --git a/tools/cmake/utilities.cmake b/tools/cmake/utilities.cmake index f7ffcabb0..045b88497 100644 --- a/tools/cmake/utilities.cmake +++ b/tools/cmake/utilities.cmake @@ -102,7 +102,7 @@ endfunction() # to a binary object as part of the build function(target_add_binary_data target embed_file embed_type) - get_filename_component(embed_file "${embed_file}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + get_filename_component(embed_file "${embed_file}" ABSOLUTE) get_filename_component(name "${embed_file}" NAME) set(embed_srcfile "${CMAKE_BINARY_DIR}/${name}.c") @@ -121,3 +121,8 @@ function(target_add_binary_data target embed_file embed_type) target_sources("${target}" PRIVATE "${embed_srcfile}") endfunction() +macro(include_if_exists path) + if(EXISTS "${path}") + include("${path}") + endif() +endmacro(include_if_exists)