From 37d30c7a6e758ee103ae5da9736533086e4581d8 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 11 Nov 2018 15:36:10 +0800 Subject: [PATCH 1/5] cmake: separate app from idf lib project mbedtls: import mbedtls using unmodified cmake file --- .gitignore | 3 + CMakeLists.txt | 153 +++++++++ components/app_trace/CMakeLists.txt | 2 +- components/app_update/CMakeLists.txt | 9 +- components/app_update/project_include.cmake | 2 +- components/bootloader/project_include.cmake | 8 +- .../bootloader/subproject/CMakeLists.txt | 12 +- components/bt/CMakeLists.txt | 4 +- components/coap/CMakeLists.txt | 2 +- components/cxx/CMakeLists.txt | 6 +- components/esp32/CMakeLists.txt | 65 ++-- components/esp32/test/CMakeLists.txt | 2 +- components/esptool_py/CMakeLists.txt | 25 +- components/esptool_py/flash_app_args.in | 2 +- components/esptool_py/flash_project_args.in | 2 +- components/esptool_py/flasher_args.json.in | 4 +- components/esptool_py/project_include.cmake | 34 +- components/freertos/CMakeLists.txt | 2 +- components/heap/test/CMakeLists.txt | 2 +- components/mbedtls/CMakeLists.txt | 2 +- components/newlib/CMakeLists.txt | 6 +- components/nvs_flash/test_nvs_host/Makefile | 8 +- components/partition_table/CMakeLists.txt | 26 +- components/partition_table/gen_esp32part.py | 11 + .../partition_table/project_include.cmake | 7 +- components/ulp/component_ulp_common.cmake | 8 +- components/unity/CMakeLists.txt | 2 +- .../subscribe_publish/main/CMakeLists.txt | 12 +- .../aws_iot/thing_shadow/main/CMakeLists.txt | 12 +- tools/cmake/component_utils.cmake | 6 + tools/cmake/components.cmake | 101 +++--- tools/cmake/idf_functions.cmake | 325 +++++++++--------- tools/cmake/kconfig.cmake | 131 ++++--- tools/cmake/ldgen.cmake | 6 +- tools/cmake/project.cmake | 252 ++++++-------- tools/cmake/project_description.json.in | 12 +- tools/cmake/scripts/expand_requirements.cmake | 18 +- tools/cmake/targets.cmake | 3 +- tools/cmake/utilities.cmake | 4 +- 39 files changed, 700 insertions(+), 591 deletions(-) create mode 100644 CMakeLists.txt diff --git a/.gitignore b/.gitignore index 478852216..51decdb5f 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,6 @@ test_multi_heap_host # Results for the checking of the Python coding style flake8_output.txt + +# ESP-IDF library +build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..226a67d5e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,153 @@ +cmake_minimum_required(VERSION 3.5) +project(esp-idf C CXX ASM) + +if(NOT IDF_PATH) + set(IDF_PATH ${CMAKE_CURRENT_LIST_DIR}) +endif() + +include(tools/cmake/idf_functions.cmake) + +# +# Set variables that control the build configuration and the build itself +# +idf_set_variables() + +kconfig_set_variables() + +# +# Generate a component dependencies file, enumerating components to be included in the build +# as well as their dependencies. +# +execute_process(COMMAND "${CMAKE_COMMAND}" + -D "COMPONENTS=${IDF_COMPONENTS}" + -D "COMPONENT_REQUIRES_COMMON=${IDF_COMPONENT_REQUIRES_COMMON}" + -D "EXCLUDE_COMPONENTS=${IDF_EXCLUDE_COMPONENTS}" + -D "TEST_COMPONENTS=${IDF_TEST_COMPONENTS}" + -D "TEST_EXCLUDE_COMPONENTS=${IDF_TEST_EXCLUDE_COMPONENTS}" + -D "BUILD_TESTS=${IDF_BUILD_TESTS}" + -D "DEPENDENCIES_FILE=${CMAKE_BINARY_DIR}/component_depends.cmake" + -D "COMPONENT_DIRS=${IDF_COMPONENT_DIRS}" + -D "BOOTLOADER_BUILD=${BOOTLOADER_BUILD}" + -D "IDF_TARGET=${IDF_TARGET}" + -D "IDF_PATH=${IDF_PATH}" + -D "DEBUG=${DEBUG}" + -P "${IDF_PATH}/tools/cmake/scripts/expand_requirements.cmake" + WORKING_DIRECTORY "${PROJECT_PATH}") +include("${CMAKE_BINARY_DIR}/component_depends.cmake") + +# +# We now have the following component-related variables: +# +# IDF_COMPONENTS is the list of initial components set by the user +# (or empty to include all components in the build). +# BUILD_COMPONENTS is the list of components to include in the build. +# BUILD_COMPONENT_PATHS is the paths to all of these components, obtained from the component dependencies file. +# +# Print the list of found components and test components +# +string(REPLACE ";" " " BUILD_COMPONENTS_SPACES "${BUILD_COMPONENTS}") +message(STATUS "Component names: ${BUILD_COMPONENTS_SPACES}") +unset(BUILD_COMPONENTS_SPACES) +message(STATUS "Component paths: ${BUILD_COMPONENT_PATHS}") + +# Print list of test components +if(TESTS_ALL EQUAL 1 OR TEST_COMPONENTS) + string(REPLACE ";" " " BUILD_TEST_COMPONENTS_SPACES "${BUILD_TEST_COMPONENTS}") + message(STATUS "Test component names: ${BUILD_TEST_COMPONENTS_SPACES}") + unset(BUILD_TEST_COMPONENTS_SPACES) + message(STATUS "Test component paths: ${BUILD_TEST_COMPONENT_PATHS}") +endif() + +# Generate project configuration +kconfig_process_config() + +# Include sdkconfig.cmake so rest of the build knows the configuration +include(${SDKCONFIG_CMAKE}) + +# Verify the environment is configured correctly +idf_verify_environment() + +# Check git revision (may trigger reruns of cmake) +## sets IDF_VER to IDF git revision +idf_get_git_revision() + +# Check that the targets set in cache, sdkconfig, and in environment all match +idf_check_config_target() + +## if project uses git, retrieve revision +git_describe(PROJECT_VER "${CMAKE_CURRENT_SOURCE_DIR}") + +# Add some idf-wide definitions +idf_set_global_compile_options() + +# generate compile_commands.json (needs to come after project) +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) + +# +# Setup variables for linker script generation +# +ldgen_set_variables() + +# Include any top-level project_include.cmake files from components +foreach(component ${BUILD_COMPONENT_PATHS}) + set(COMPONENT_PATH "${component}") + include_if_exists("${component}/project_include.cmake") + unset(COMPONENT_PATH) +endforeach() + +# +# Add each component to the build as a library +# +foreach(COMPONENT_PATH ${BUILD_COMPONENT_PATHS}) + get_filename_component(COMPONENT_NAME ${COMPONENT_PATH} NAME) + + list(FIND BUILD_TEST_COMPONENT_PATHS ${COMPONENT_PATH} idx) + + if(NOT idx EQUAL -1) + list(GET BUILD_TEST_COMPONENTS ${idx} test_component) + set(COMPONENT_NAME ${test_component}) + endif() + + component_get_target(COMPONENT_TARGET ${COMPONENT_NAME}) + + add_subdirectory(${COMPONENT_PATH} ${COMPONENT_NAME}) +endforeach() +unset(COMPONENT_NAME) +unset(COMPONENT_PATH) + +# each component should see the include directories of its requirements +# +# (we can't do this until all components are registered and targets exist in cmake, as we have +# a circular requirements graph...) +foreach(component ${BUILD_COMPONENTS}) + component_get_target(component_target ${component}) + if(TARGET ${component_target}) + get_component_requirements(${component} deps priv_deps) + + list(APPEND priv_deps ${IDF_COMPONENT_REQUIRES_COMMON}) + + foreach(dep ${deps}) + component_get_target(dep_target ${dep}) + add_component_dependencies(${component_target} ${dep_target} PUBLIC) + endforeach() + + foreach(dep ${priv_deps}) + component_get_target(dep_target ${dep}) + add_component_dependencies(${component_target} ${dep_target} PRIVATE) + endforeach() + endif() +endforeach() + +if(IDF_BUILD_ARTIFACTS) + # Write project description JSON file + make_json_list("${BUILD_COMPONENTS}" build_components_json) + make_json_list("${BUILD_COMPONENT_PATHS}" build_component_paths_json) + configure_file("${IDF_PATH}/tools/cmake/project_description.json.in" + "${IDF_BUILD_ARTIFACTS_DIR}/project_description.json") + unset(build_components_json) + unset(build_component_paths_json) +endif() + +set(BUILD_COMPONENTS ${BUILD_COMPONENTS} PARENT_SCOPE) + +ldgen_add_dependencies() diff --git a/components/app_trace/CMakeLists.txt b/components/app_trace/CMakeLists.txt index ffd609509..bc8d7b847 100644 --- a/components/app_trace/CMakeLists.txt +++ b/components/app_trace/CMakeLists.txt @@ -26,4 +26,4 @@ register_component() # for gcov component_compile_options("-fno-profile-arcs" "-fno-test-coverage") -target_link_libraries(app_trace gcov) +target_link_libraries(${COMPONENT_TARGET} gcov) diff --git a/components/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index ef2684a2c..8eac36935 100644 --- a/components/app_update/CMakeLists.txt +++ b/components/app_update/CMakeLists.txt @@ -7,11 +7,12 @@ set(COMPONENT_PRIV_REQUIRES bootloader_support) register_component() # Add custom target for generating empty otadata partition for flashing -if(${OTADATA_PARTITION_OFFSET}) - add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/${BLANK_OTADATA_FILE}" +if(OTADATA_PARTITION_OFFSET AND IDF_BUILD_ARTIFACTS) + add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/${BLANK_OTADATA_FILE}" COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/gen_empty_partition.py - --size ${OTADATA_PARTITION_SIZE} "${PROJECT_BINARY_DIR}/${BLANK_OTADATA_FILE}") + --size ${OTADATA_PARTITION_SIZE} "${IDF_BUILD_ARTIFACTS_DIR}/${BLANK_OTADATA_FILE}") + + add_custom_target(blank_ota_data ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/${BLANK_OTADATA_FILE}") - add_custom_target(blank_ota_data ALL DEPENDS "${PROJECT_BINARY_DIR}/${BLANK_OTADATA_FILE}") add_dependencies(flash blank_ota_data) endif() diff --git a/components/app_update/project_include.cmake b/components/app_update/project_include.cmake index 70b896f05..8d959bd7c 100644 --- a/components/app_update/project_include.cmake +++ b/components/app_update/project_include.cmake @@ -3,6 +3,6 @@ # partition table # (NB: because of component dependency, we know partition_table # project_include.cmake has already been included.) -if(${OTADATA_PARTITION_OFFSET}) +if(OTADATA_PARTITION_OFFSET AND IDF_BUILD_ARTIFACTS) set(BLANK_OTADATA_FILE "ota_data_initial.bin") endif() diff --git a/components/bootloader/project_include.cmake b/components/bootloader/project_include.cmake index d997510e9..e08c18f7d 100644 --- a/components/bootloader/project_include.cmake +++ b/components/bootloader/project_include.cmake @@ -2,7 +2,7 @@ if(BOOTLOADER_BUILD) set(main_project_path "${CMAKE_BINARY_DIR}/../..") else() - set(main_project_path "${PROJECT_PATH}") + set(main_project_path "${IDF_PROJECT_PATH}") endif() get_filename_component(secure_boot_signing_key @@ -19,15 +19,15 @@ else() add_custom_target(gen_secure_boot_signing_key) endif() -if(BOOTLOADER_BUILD) - return() # don't keep recursing! +if(BOOTLOADER_BUILD OR NOT IDF_BUILD_ARTIFACTS) + return() # don't keep recursing, generate on project builds endif() # Glue to build the bootloader subproject binary as an external # cmake project under this one # # -set(bootloader_build_dir "${CMAKE_BINARY_DIR}/bootloader") +set(bootloader_build_dir "${IDF_BUILD_ARTIFACTS_DIR}/bootloader") set(bootloader_binary_files "${bootloader_build_dir}/bootloader.elf" "${bootloader_build_dir}/bootloader.bin" diff --git a/components/bootloader/subproject/CMakeLists.txt b/components/bootloader/subproject/CMakeLists.txt index 2d75c0a4d..da4560434 100644 --- a/components/bootloader/subproject/CMakeLists.txt +++ b/components/bootloader/subproject/CMakeLists.txt @@ -21,8 +21,16 @@ project(bootloader) target_linker_script(bootloader.elf "main/esp32.bootloader.ld" - "main/esp32.bootloader.rom.ld") -# Imported from esp32 component + "main/esp32.bootloader.rom.ld" +) + +# as cmake won't attach linker args to a header-only library, attach +# linker args directly to the bootloader.elf +set(ESP32_BOOTLOADER_LINKER_SCRIPTS + "../../esp32/ld/esp32.rom.ld" + "../../esp32/ld/esp32.rom.spiram_incompatible_fns.ld" + "../../esp32/ld/esp32.peripherals.ld") + target_linker_script(bootloader.elf ${ESP32_BOOTLOADER_LINKER_SCRIPTS}) target_link_libraries(bootloader.elf gcc) diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index df32f9f94..07b469fe6 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -281,6 +281,6 @@ if(CONFIG_BT_ENABLED) component_compile_options(-Wno-implicit-fallthrough -Wno-unused-const-variable) endif() - target_link_libraries(bt "-L${CMAKE_CURRENT_LIST_DIR}/lib") - target_link_libraries(bt btdm_app) + target_link_libraries(${COMPONENT_TARGET} "-L${CMAKE_CURRENT_LIST_DIR}/lib") + target_link_libraries(${COMPONENT_TARGET} btdm_app) endif() diff --git a/components/coap/CMakeLists.txt b/components/coap/CMakeLists.txt index a7800e64f..01cd61e68 100644 --- a/components/coap/CMakeLists.txt +++ b/components/coap/CMakeLists.txt @@ -24,7 +24,7 @@ register_component() # Needed for coap headers in public builds, also. # # TODO: find a way to move this to a port header -target_compile_definitions(coap PUBLIC WITH_POSIX) +target_compile_definitions(${COMPONENT_TARGET} PUBLIC WITH_POSIX) set_source_files_properties( libcoap/src/debug.c diff --git a/components/cxx/CMakeLists.txt b/components/cxx/CMakeLists.txt index 29ee8016e..236bd5cf7 100644 --- a/components/cxx/CMakeLists.txt +++ b/components/cxx/CMakeLists.txt @@ -3,10 +3,10 @@ set(COMPONENT_SRCS "cxx_exception_stubs.cpp" set(COMPONENT_REQUIRES) register_component() -target_link_libraries(cxx stdc++) +target_link_libraries(${COMPONENT_TARGET} stdc++) -target_link_libraries(cxx "-u __cxa_guard_dummy") +target_link_libraries(${COMPONENT_TARGET} "-u __cxa_guard_dummy") if(NOT CONFIG_CXX_EXCEPTIONS) - target_link_libraries(cxx "-u __cxx_fatal_exception") + target_link_libraries(${COMPONENT_TARGET} "-u __cxx_fatal_exception") endif() diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index ae69d7575..d77aeb410 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -3,19 +3,9 @@ require_idf_targets(esp32) if(BOOTLOADER_BUILD) # For bootloader, all we need from esp32 is headers set(COMPONENT_ADD_INCLUDEDIRS include) - set(COMPONENT_REQUIRES ${COMPONENTS}) + set(COMPONENT_REQUIRES ${IDF_COMPONENTS}) set(COMPONENT_SRCS ) - register_component(esp32) - - # as cmake won't attach linker args to a header-only library, attach - # linker args directly to the bootloader.elf - set(ESP32_BOOTLOADER_LINKER_SCRIPTS - "${CMAKE_CURRENT_SOURCE_DIR}/ld/esp32.rom.ld" - "${CMAKE_CURRENT_SOURCE_DIR}/ld/esp32.rom.spiram_incompatible_fns.ld" - "${CMAKE_CURRENT_SOURCE_DIR}/ld/esp32.peripherals.ld" - PARENT_SCOPE - ) - + register_component() else() # Regular app build @@ -75,29 +65,31 @@ else() register_component() - target_link_libraries(esp32 "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib") + target_link_libraries(${COMPONENT_TARGET} "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib") if(NOT CONFIG_NO_BLOBS) - target_link_libraries(esp32 coexist core espnow mesh net80211 phy pp rtc smartconfig wpa2 wpa wps) + target_link_libraries(${COMPONENT_TARGET} coexist core espnow mesh net80211 phy pp rtc smartconfig wpa2 wpa wps) endif() - target_linker_script(esp32 "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") + target_linker_script(${COMPONENT_TARGET} "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") if(CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY) # This has to be linked before esp32.common.ld - target_linker_script(esp32 "ld/esp32.extram.bss.ld") + target_linker_script(${COMPONENT_TARGET} "ld/esp32.extram.bss.ld") endif() - # Process the template file through the linker script generation mechanism, and use the output for linking the - # final binary - set(esp32_common_script "${CMAKE_CURRENT_BINARY_DIR}/esp32.common.ld") - set(esp32_common_template "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.common.ld.in") + if(IDF_PROJECT_EXECUTABLE) + # Process the template file through the linker script generation mechanism, and use the output for linking the + # final binary + set(esp32_common_script "${CMAKE_CURRENT_BINARY_DIR}/esp32.common.ld") + set(esp32_common_template "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.common.ld.in") - ldgen_process_template(${esp32_common_template} ${esp32_common_script}) + ldgen_process_template(${esp32_common_template} ${esp32_common_script}) - target_link_libraries(esp32 "-T ${esp32_common_script}") + target_link_libraries(${COMPONENT_TARGET} "-T ${esp32_common_script}") + + set_property(TARGET ${IDF_PROJECT_EXECUTABLE} APPEND PROPERTY LINK_DEPENDS ${esp32_common_script}) + endif() - set_property(TARGET ${PROJECT_NAME}.elf APPEND PROPERTY LINK_DEPENDS ${esp32_common_script}) - - target_linker_script(esp32 + target_linker_script(${COMPONENT_TARGET} "ld/esp32.rom.ld" "ld/esp32.peripherals.ld" "ld/esp32.rom.libgcc.ld" @@ -106,25 +98,25 @@ else() if(CONFIG_SPIRAM_CACHE_WORKAROUND) add_compile_options(-mfix-esp32-psram-cache-issue) else() - target_linker_script(esp32 "ld/esp32.rom.spiram_incompatible_fns.ld") + target_linker_script(${COMPONENT_TARGET} "ld/esp32.rom.spiram_incompatible_fns.ld") endif() if(CONFIG_NEWLIB_NANO_FORMAT) - target_linker_script(esp32 "ld/esp32.rom.nanofmt.ld") + target_linker_script(${COMPONENT_TARGET} "ld/esp32.rom.nanofmt.ld") endif() if(NOT CONFIG_SPI_FLASH_ROM_DRIVER_PATCH) - target_linker_script(esp32 "ld/esp32.rom.spiflash.ld") + target_linker_script(${COMPONENT_TARGET} "ld/esp32.rom.spiflash.ld") endif() - target_link_libraries(esp32 "${CMAKE_CURRENT_SOURCE_DIR}/libhal.a") - target_link_libraries(esp32 gcc) - target_link_libraries(esp32 "-u call_user_start_cpu0") + target_link_libraries(${COMPONENT_TARGET} "${CMAKE_CURRENT_SOURCE_DIR}/libhal.a") + target_link_libraries(${COMPONENT_TARGET} gcc) + target_link_libraries(${COMPONENT_TARGET} "-u call_user_start_cpu0") #ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the #linker will ignore panic_highint_hdl.S as it has no other files depending on any #symbols in it. - target_link_libraries(esp32 "-u ld_include_panic_highint_hdl") + target_link_libraries(${COMPONENT_TARGET} "-u ld_include_panic_highint_hdl") # Preprocess esp32.ld linker script to include configuration, becomes esp32_out.ld set(LD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ld) @@ -136,10 +128,10 @@ else() VERBATIM) add_custom_target(esp32_linker_script DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld) - add_dependencies(esp32 esp32_linker_script) + add_dependencies(${COMPONENT_TARGET} esp32_linker_script) - if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) - set(PHY_INIT_DATA_BIN phy_init_data.bin) + if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION AND IDF_BUILD_ARTIFACTS) + set(PHY_INIT_DATA_BIN ${IDF_BUILD_ARTIFACTS_DIR}/${PHY_PARTITION_BIN_FILE}) # To get the phy_init_data.bin file, compile phy_init_data.h as a C file and then objcopy # the object file to a raw binary @@ -147,14 +139,13 @@ else() OUTPUT ${PHY_INIT_DATA_BIN} DEPENDS ${CMAKE_CURRENT_LIST_DIR}/phy_init_data.h COMMAND ${CMAKE_C_COMPILER} -x c -c - -I ${CMAKE_CURRENT_LIST_DIR} -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${CMAKE_BINARY_DIR} + -I ${CMAKE_CURRENT_LIST_DIR} -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${IDF_BUILD_ARTIFACTS_DIR} -o phy_init_data.obj ${CMAKE_CURRENT_LIST_DIR}/phy_init_data.h COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${PHY_INIT_DATA_BIN} ) add_custom_target(phy_init_data ALL DEPENDS ${PHY_INIT_DATA_BIN}) add_dependencies(flash phy_init_data) - endif() # Enable dynamic esp_timer overflow value if building unit tests diff --git a/components/esp32/test/CMakeLists.txt b/components/esp32/test/CMakeLists.txt index a56e6d2bb..939b386a5 100644 --- a/components/esp32/test/CMakeLists.txt +++ b/components/esp32/test/CMakeLists.txt @@ -27,4 +27,4 @@ add_definitions(-DWIFI_CRYPTO_MD5=\"${WIFI_CRYPTO_MD5}\") add_custom_target(esp32_test_logo DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h") -add_dependencies(${COMPONENT_NAME} esp32_test_logo) +add_dependencies(${COMPONENT_TARGET} esp32_test_logo) \ No newline at end of file diff --git a/components/esptool_py/CMakeLists.txt b/components/esptool_py/CMakeLists.txt index 05293be37..82750e2d6 100644 --- a/components/esptool_py/CMakeLists.txt +++ b/components/esptool_py/CMakeLists.txt @@ -9,15 +9,18 @@ if(CONFIG_SECURE_BOOT_ENABLED) set(ESPTOOLPY_FLASH_PROJECT_OPTIONS "") endif() -# Generate pre-canned flasher args files suitable for passing to esptool.py -foreach(part project app bootloader partition_table) - configure_file( - "${CMAKE_CURRENT_LIST_DIR}/flash_${part}_args.in" - "${CMAKE_BINARY_DIR}/flash_${part}_args" - ) -endforeach() +if(IDF_BUILD_ARTIFACTS) + # Generate pre-canned flasher args files suitable for passing to esptool.py + foreach(part project app bootloader partition_table) + configure_file( + "${CMAKE_CURRENT_LIST_DIR}/flash_${part}_args.in" + "${IDF_BUILD_ARTIFACTS_DIR}/flash_${part}_args" + ) + endforeach() + + configure_file( + "${CMAKE_CURRENT_LIST_DIR}/flasher_args.json.in" + "${IDF_BUILD_ARTIFACTS_DIR}/flasher_args.json" + ) +endif() -configure_file( - "${CMAKE_CURRENT_LIST_DIR}/flasher_args.json.in" - "${CMAKE_BINARY_DIR}/flasher_args.json" - ) diff --git a/components/esptool_py/flash_app_args.in b/components/esptool_py/flash_app_args.in index 6d31ca4fe..bd4f2a6e0 100644 --- a/components/esptool_py/flash_app_args.in +++ b/components/esptool_py/flash_app_args.in @@ -1 +1 @@ -${APP_PARTITION_OFFSET} ${PROJECT_NAME}.bin +${APP_PARTITION_OFFSET} ${IDF_PROJECT_BIN} diff --git a/components/esptool_py/flash_project_args.in b/components/esptool_py/flash_project_args.in index 18ee9ab2c..441144b5c 100644 --- a/components/esptool_py/flash_project_args.in +++ b/components/esptool_py/flash_project_args.in @@ -2,5 +2,5 @@ ${ESPTOOLPY_FLASH_PROJECT_OPTIONS} ${PARTITION_TABLE_OFFSET} partition_table/partition-table.bin ${PHY_PARTITION_OFFSET} ${PHY_PARTITION_BIN_FILE} ${OTADATA_PARTITION_OFFSET} ${BLANK_OTADATA_FILE} -${APP_PARTITION_OFFSET} ${PROJECT_NAME}.bin +${APP_PARTITION_OFFSET} ${IDF_PROJECT_BIN} diff --git a/components/esptool_py/flasher_args.json.in b/components/esptool_py/flasher_args.json.in index bc0e5e340..1a56d5ced 100644 --- a/components/esptool_py/flasher_args.json.in +++ b/components/esptool_py/flasher_args.json.in @@ -7,7 +7,7 @@ "${PARTITION_TABLE_OFFSET}" : "partition_table/partition-table.bin", "${PHY_PARTITION_OFFSET}" : "${PHY_PARTITION_BIN_FILE}", "${OTADATA_PARTITION_OFFSET}" : "${BLANK_OTADATA_FILE}", - "${APP_PARTITION_OFFSET}" : "${PROJECT_NAME}.bin" + "${APP_PARTITION_OFFSET}" : "${IDF_PROJECT_BIN}" }, "bootloader" : { "offset" : "${BOOTLOADER_OFFSET}", "file" : "bootloader/bootloader.bin" }, @@ -16,7 +16,7 @@ "otadata" : { "offset" : "${OTADATA_PARTITION_OFFSET}", "file" : "${BLANK_OTADATA_FILE}" }, "app" : { "offset" : "${APP_PARTITION_OFFSET}", - "file" : "${PROJECT_NAME}.bin" }, + "file" : "${IDF_PROJECT_BIN}" }, "extra_esptool_args" : { "after" : "${ESPTOOLPY_AFTER}", "before" : "${ESPTOOLPY_BEFORE}" diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake index 7ab07f5b8..83e129ae6 100644 --- a/components/esptool_py/project_include.cmake +++ b/components/esptool_py/project_include.cmake @@ -1,3 +1,7 @@ +if(NOT IDF_BUILD_ARTIFACTS) + return() +endif() + # Set some global esptool.py variables # # Many of these are read when generating flash_app_args & flash_project_args @@ -60,38 +64,44 @@ if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) set(PHY_PARTITION_BIN_FILE "esp32/phy_init_data.bin") endif() +get_filename_component(IDF_PROJECT_NAME ${IDF_PROJECT_EXECUTABLE} NAME_WE) if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES AND NOT BOOTLOADER_BUILD) - set(unsigned_project_binary "${PROJECT_NAME}-unsigned.bin") + set(unsigned_project_binary "${IDF_PROJECT_NAME}-unsigned.bin") else() - set(unsigned_project_binary "${PROJECT_NAME}.bin") + set(unsigned_project_binary "${IDF_PROJECT_NAME}.bin") endif() # # Add 'app.bin' target - generates with elf2image # -add_custom_command(OUTPUT "${unsigned_project_binary}" +add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}" COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} - -o "${unsigned_project_binary}" "${PROJECT_NAME}.elf" - DEPENDS ${PROJECT_NAME}.elf + -o "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}" "${IDF_PROJECT_EXECUTABLE}" + DEPENDS ${IDF_PROJECT_EXECUTABLE} VERBATIM + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) +get_filename_component(IDF_PROJECT_BIN ${IDF_PROJECT_EXECUTABLE} NAME_WE) +set(IDF_PROJECT_BIN ${IDF_PROJECT_BIN}.bin) + if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + # for locally signed secure boot image, add a signing step to get from unsigned app to signed app - add_custom_target(gen_unsigned_project_binary ALL DEPENDS "${unsigned_project_binary}") - add_custom_command(OUTPUT "${PROJECT_NAME}.bin" + add_custom_target(gen_unsigned_project_binary ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}") + add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}" COMMAND ${ESPSECUREPY} sign_data --keyfile ${secure_boot_signing_key} - -o "${PROJECT_NAME}.bin" "${unsigned_project_binary}" + -o "${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}" "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}" DEPENDS gen_unsigned_project_binary VERBATIM ) endif() if(NOT BOOTLOADER_BUILD) - add_custom_target(app ALL DEPENDS "${PROJECT_NAME}.bin") + add_custom_target(app ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}") else() - add_custom_target(bootloader ALL DEPENDS "${PROJECT_NAME}.bin") + add_custom_target(bootloader ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}") endif() if(NOT BOOTLOADER_BUILD AND @@ -101,7 +111,7 @@ if(NOT BOOTLOADER_BUILD AND COMMAND ${CMAKE_COMMAND} -E echo "App built but not signed. Sign app before flashing" COMMAND ${CMAKE_COMMAND} -E echo - "\t${ESPSECUREPY} sign_data --keyfile KEYFILE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.bin" + "\t${ESPSECUREPY} sign_data --keyfile KEYFILE ${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}" VERBATIM) endif() @@ -114,7 +124,7 @@ function(esptool_py_custom_target target_name flasher_filename dependencies) -D IDF_PATH="${IDF_PATH}" -D ESPTOOLPY="${ESPTOOLPY}" -D ESPTOOL_ARGS="write_flash;@flash_${flasher_filename}_args" - -D ESPTOOL_WORKING_DIR="${CMAKE_CURRENT_BINARY_DIR}" + -D ESPTOOL_WORKING_DIR="${IDF_BUILD_ARTIFACTS_DIR}" -P run_esptool.cmake WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} USES_TERMINAL diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index 3b0886529..a73a29fdb 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -23,7 +23,7 @@ set(COMPONENT_REQUIRES app_trace) set(COMPONENT_ADD_LDFRAGMENTS linker.lf) register_component() -target_link_libraries(freertos "-Wl,--undefined=uxTopUsedPriority") +target_link_libraries(${COMPONENT_TARGET} "-Wl,--undefined=uxTopUsedPriority") set_source_files_properties( tasks.c diff --git a/components/heap/test/CMakeLists.txt b/components/heap/test/CMakeLists.txt index 66a8c8231..aed6c9743 100644 --- a/components/heap/test/CMakeLists.txt +++ b/components/heap/test/CMakeLists.txt @@ -1,6 +1,6 @@ set(COMPONENT_SRCDIRS ".") set(COMPONENT_ADD_INCLUDEDIRS ".") -set(COMPONENT_REQUIRES unity test_utils) +set(COMPONENT_REQUIRES unity test_utils heap) register_component() \ No newline at end of file diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index cb8ba6085..f9964f2e7 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -91,7 +91,7 @@ set(COMPONENT_REQUIRES lwip) register_component() -target_compile_definitions(mbedtls PUBLIC +target_compile_definitions(${COMPONENT_TARGET} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h" ) diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index d541b87bf..893d9f7d1 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -28,7 +28,7 @@ set(COMPONENT_REQUIRES vfs) # for sys/ioctl.h register_component() -target_link_libraries(newlib "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib") -target_link_libraries(newlib ${LIBC} ${LIBM}) +target_link_libraries(${COMPONENT_TARGET} "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib") +target_link_libraries(${COMPONENT_TARGET} ${LIBC} ${LIBM}) -set_source_files_properties(syscalls.c PROPERTIES COMPILE_FLAGS -fno-builtin) +set_source_files_properties(syscalls.c PROPERTIES COMPILE_FLAGS -fno-builtin) \ No newline at end of file diff --git a/components/nvs_flash/test_nvs_host/Makefile b/components/nvs_flash/test_nvs_host/Makefile index b125aaffe..73aec3253 100644 --- a/components/nvs_flash/test_nvs_host/Makefile +++ b/components/nvs_flash/test_nvs_host/Makefile @@ -21,7 +21,7 @@ SOURCE_FILES = \ crc.cpp \ main.cpp -CPPFLAGS += -I../include -I../src -I./ -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -DCONFIG_NVS_ENCRYPTION +CPPFLAGS += -I../include -I../src -I./ -I../../esp32/include -I ../../esp_mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -DCONFIG_NVS_ENCRYPTION CFLAGS += -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage @@ -33,8 +33,8 @@ COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(OBJ_FILES): %.o: %.cpp $(TEST_PROGRAM): $(OBJ_FILES) - $(MAKE) -C ../../mbedtls/mbedtls/ lib - g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) ../../mbedtls/mbedtls/library/libmbedcrypto.a + $(MAKE) -C ../../esp_mbedtls/mbedtls/ lib + g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) ../../esp_mbedtls/mbedtls/library/libmbedcrypto.a $(OUTPUT_DIR): mkdir -p $(OUTPUT_DIR) @@ -56,7 +56,7 @@ coverage_report: coverage.info @echo "Coverage report is in coverage_report/index.html" clean: - $(MAKE) -C ../../mbedtls/mbedtls/ clean + $(MAKE) -C ../../esp_mbedtls/mbedtls/ clean rm -f $(OBJ_FILES) $(TEST_PROGRAM) rm -f $(COVERAGE_FILES) *.gcov rm -rf coverage_report/ diff --git a/components/partition_table/CMakeLists.txt b/components/partition_table/CMakeLists.txt index fc2ecf7ad..6020820fe 100644 --- a/components/partition_table/CMakeLists.txt +++ b/components/partition_table/CMakeLists.txt @@ -1,6 +1,6 @@ register_config_only_component() -if(NOT BOOTLOADER_BUILD) +if(NOT BOOTLOADER_BUILD AND IDF_BUILD_ARTIFACTS) set(partition_csv "${PARTITION_CSV_PATH}") @@ -28,25 +28,28 @@ else() set(partition_secure_opt "") endif() -add_custom_command(OUTPUT "${unsigned_partition_bin}" - COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" - -q --offset ${PARTITION_TABLE_OFFSET} ${md5_opt} ${flashsize_opt} - ${partition_secure_opt} ${partition_csv} ${unsigned_partition_bin} +add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin}" + COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" + -q --offset ${PARTITION_TABLE_OFFSET} ${md5_opt} ${flashsize_opt} + ${partition_secure_opt} ${partition_csv} ${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin} DEPENDS ${partition_csv} "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" VERBATIM) # Add signing steps if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) - add_custom_target(gen_unsigned_partition_bin ALL DEPENDS "${unsigned_partition_bin}") - add_custom_command(OUTPUT "${final_partition_bin}" + add_custom_target(gen_unsigned_partition_bin ALL DEPENDS + "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin}") + + add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${final_partition_bin}" COMMAND ${ESPSECUREPY} sign_data --keyfile "${secure_boot_signing_key}" - -o "${final_partition_bin}" "${unsigned_partition_bin}" - DEPENDS gen_unsigned_partition_bin gen_secure_boot_signing_key + -o "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${final_partition_bin}" + "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin}" + DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin}" VERBATIM) endif() if(EXISTS ${partition_csv}) - add_custom_target(partition_table ALL DEPENDS "${final_partition_bin}") + add_custom_target(partition_table ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${final_partition_bin}") else() # If the partition input CSV is not found, create a phony partition_table target that # fails the build. fail_at_build_time also touches CMakeCache.txt to cause a cmake run next time @@ -73,6 +76,7 @@ add_dependencies(app partition_table) # the list of esptool write arguments for flashing set_property(GLOBAL APPEND_STRING PROPERTY ESPTOOL_WRITE_FLASH_ARGS - "${PARTITION_TABLE_OFFSET} ${final_partition_bin} ") + "${PARTITION_TABLE_OFFSET} ${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${final_partition_bin} ") endif() + diff --git a/components/partition_table/gen_esp32part.py b/components/partition_table/gen_esp32part.py index e3c8a6dc4..d029127ab 100755 --- a/components/partition_table/gen_esp32part.py +++ b/components/partition_table/gen_esp32part.py @@ -29,6 +29,7 @@ import struct import sys import hashlib import binascii +import errno MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature MD5_PARTITION_BEGIN = b"\xEB\xEB" + b"\xFF" * 14 # The first 2 bytes are like magic numbers for MD5 sum @@ -480,6 +481,16 @@ def main(): raise InputError("Partitions defined in '%s' occupy %.1fMB of flash (%d bytes) which does not fit in configured flash size %dMB. Change the flash size in menuconfig under the 'Serial Flasher Config' menu." % (args.input.name, table_size / 1024.0 / 1024.0, table_size, size_mb)) + # Make sure that the output directory is created + output_dir = os.path.abspath(os.path.dirname(args.output)) + + if not os.path.exists(output_dir): + try: + os.makedirs(output_dir) + except OSError as exc: + if exc.errno != errno.EEXIST: + raise + if input_is_binary: output = table.to_csv() with sys.stdout if args.output == '-' else open(args.output, 'w') as f: diff --git a/components/partition_table/project_include.cmake b/components/partition_table/project_include.cmake index 0d168c7bd..80841ed74 100644 --- a/components/partition_table/project_include.cmake +++ b/components/partition_table/project_include.cmake @@ -1,4 +1,4 @@ -if(NOT BOOTLOADER_BUILD) +if(NOT BOOTLOADER_BUILD AND IDF_BUILD_ARTIFACTS) set(PARTITION_TABLE_OFFSET ${CONFIG_PARTITION_TABLE_OFFSET}) @@ -6,7 +6,8 @@ set(PARTITION_TABLE_OFFSET ${CONFIG_PARTITION_TABLE_OFFSET}) # absolute path if(CONFIG_PARTITION_TABLE_CUSTOM) # Custom filename expands any path relative to the project - get_filename_component(PARTITION_CSV_PATH "${CONFIG_PARTITION_TABLE_FILENAME}" ABSOLUTE BASE_DIR "${PROJECT_PATH}") + get_filename_component(PARTITION_CSV_PATH "${CONFIG_PARTITION_TABLE_FILENAME}" + ABSOLUTE BASE_DIR "${IDF_PROJECT_PATH}") if(NOT EXISTS "${PARTITION_CSV_PATH}") message(WARNING "Partition table CSV file ${PARTITION_CSV_PATH} not found. " @@ -46,7 +47,7 @@ endfunction() if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) get_partition_info(PHY_PARTITION_OFFSET "--type data --subtype phy --offset") - set(PHY_PARTITION_BIN_FILE "${CMAKE_BINARY_DIR}/esp32/phy_init_data.bin") + set(PHY_PARTITION_BIN_FILE "esp32/phy_init_data.bin") endif() get_partition_info(APP_PARTITION_OFFSET "--default-boot-partition --offset") diff --git a/components/ulp/component_ulp_common.cmake b/components/ulp/component_ulp_common.cmake index 6b0a631ee..c42ada37e 100644 --- a/components/ulp/component_ulp_common.cmake +++ b/components/ulp/component_ulp_common.cmake @@ -35,7 +35,7 @@ if(NOT CMAKE_BUILD_EARLY_EXPANSION) -DCOMPONENT_PATH=${COMPONENT_PATH} # Even though this resolves to a ';' separated list, this is fine. This must be special behavior # for generator expressions. - -DCOMPONENT_INCLUDES=$ + -DCOMPONENT_INCLUDES=$ -DIDF_PATH=${IDF_PATH} -DSDKCONFIG=${SDKCONFIG_HEADER} BUILD_COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME} --target build @@ -52,8 +52,8 @@ if(NOT CMAKE_BUILD_EARLY_EXPANSION) add_custom_target(${ULP_APP_NAME}_artifacts DEPENDS ${ULP_APP_NAME}) - add_dependencies(${COMPONENT_NAME} ${ULP_APP_NAME}_artifacts) + add_dependencies(${COMPONENT_TARGET} ${ULP_APP_NAME}_artifacts) - target_linker_script(${COMPONENT_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}/${ULP_APP_NAME}.ld) - target_add_binary_data(${COMPONENT_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}/${ULP_APP_NAME}.bin BINARY) + target_linker_script(${COMPONENT_TARGET} ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}/${ULP_APP_NAME}.ld) + target_add_binary_data(${COMPONENT_TARGET} ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}/${ULP_APP_NAME}.bin BINARY) endif() \ No newline at end of file diff --git a/components/unity/CMakeLists.txt b/components/unity/CMakeLists.txt index 82a53f307..e76ffe952 100644 --- a/components/unity/CMakeLists.txt +++ b/components/unity/CMakeLists.txt @@ -14,7 +14,7 @@ endif() register_component() -target_compile_definitions(unity PUBLIC +target_compile_definitions(${COMPONENT_TARGET} PUBLIC -DUNITY_INCLUDE_CONFIG_H ) diff --git a/examples/protocols/aws_iot/subscribe_publish/main/CMakeLists.txt b/examples/protocols/aws_iot/subscribe_publish/main/CMakeLists.txt index d5fc09071..67b51b9f5 100644 --- a/examples/protocols/aws_iot/subscribe_publish/main/CMakeLists.txt +++ b/examples/protocols/aws_iot/subscribe_publish/main/CMakeLists.txt @@ -5,7 +5,7 @@ set(COMPONENT_ADD_INCLUDEDIRS ".") register_component() if(CONFIG_EXAMPLE_EMBEDDED_CERTS) -target_add_binary_data(${COMPONENT_NAME} "certs/aws-root-ca.pem" TEXT) +target_add_binary_data(${COMPONENT_TARGET} "certs/aws-root-ca.pem" TEXT) if(NOT IDF_CI_BUILD) add_custom_command(OUTPUT certs/certificate.pem.crt certs/private.pem.key @@ -17,12 +17,12 @@ if(NOT IDF_CI_BUILD) VERBATIM) add_custom_target(example_certificates DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/certs/certificate.pem.crt ${CMAKE_CURRENT_BINARY_DIR}/certs/private.pem.key) - add_dependencies(${COMPONENT_NAME} example_certificates) + add_dependencies(${COMPONENT_TARGET} example_certificates) - target_add_binary_data(${COMPONENT_NAME} "${CMAKE_CURRENT_BINARY_DIR}/certs/certificate.pem.crt" TEXT) - target_add_binary_data(${COMPONENT_NAME} "${CMAKE_CURRENT_BINARY_DIR}/certs/private.pem.key" TEXT) + target_add_binary_data(${COMPONENT_TARGET} "${CMAKE_CURRENT_BINARY_DIR}/certs/certificate.pem.crt" TEXT) + target_add_binary_data(${COMPONENT_TARGET} "${CMAKE_CURRENT_BINARY_DIR}/certs/private.pem.key" TEXT) else() - target_add_binary_data(${COMPONENT_NAME} "certs/certificate.pem.crt" TEXT) - target_add_binary_data(${COMPONENT_NAME} "certs/private.pem.key" TEXT) + target_add_binary_data(${COMPONENT_TARGET} "certs/certificate.pem.crt" TEXT) + target_add_binary_data(${COMPONENT_TARGET} "certs/private.pem.key" TEXT) endif() endif() \ No newline at end of file diff --git a/examples/protocols/aws_iot/thing_shadow/main/CMakeLists.txt b/examples/protocols/aws_iot/thing_shadow/main/CMakeLists.txt index ee14baf02..0fcad6405 100644 --- a/examples/protocols/aws_iot/thing_shadow/main/CMakeLists.txt +++ b/examples/protocols/aws_iot/thing_shadow/main/CMakeLists.txt @@ -5,7 +5,7 @@ set(COMPONENT_ADD_INCLUDEDIRS ".") register_component() if(CONFIG_EXAMPLE_EMBEDDED_CERTS) -target_add_binary_data(${COMPONENT_NAME} "certs/aws-root-ca.pem" TEXT) +target_add_binary_data(${COMPONENT_TARGET} "certs/aws-root-ca.pem" TEXT) if(NOT IDF_CI_BUILD) add_custom_command(OUTPUT certs/certificate.pem.crt certs/private.pem.key @@ -17,12 +17,12 @@ if(NOT IDF_CI_BUILD) VERBATIM) add_custom_target(example_certificates DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/certs/certificate.pem.crt ${CMAKE_CURRENT_BINARY_DIR}/certs/private.pem.key) - add_dependencies(${COMPONENT_NAME} example_certificates) + add_dependencies(${COMPONENT_TARGET} example_certificates) - target_add_binary_data(${COMPONENT_NAME} "${CMAKE_CURRENT_BINARY_DIR}/certs/certificate.pem.crt" TEXT) - target_add_binary_data(${COMPONENT_NAME} "${CMAKE_CURRENT_BINARY_DIR}/certs/private.pem.key" TEXT) + target_add_binary_data(${COMPONENT_TARGET} "${CMAKE_CURRENT_BINARY_DIR}/certs/certificate.pem.crt" TEXT) + target_add_binary_data(${COMPONENT_TARGET} "${CMAKE_CURRENT_BINARY_DIR}/certs/private.pem.key" TEXT) else() - target_add_binary_data(${COMPONENT_NAME} "certs/certificate.pem.crt" TEXT) - target_add_binary_data(${COMPONENT_NAME} "certs/private.pem.key" TEXT) + target_add_binary_data(${COMPONENT_TARGET} "certs/certificate.pem.crt" TEXT) + target_add_binary_data(${COMPONENT_TARGET} "certs/private.pem.key" TEXT) endif() endif() \ No newline at end of file diff --git a/tools/cmake/component_utils.cmake b/tools/cmake/component_utils.cmake index 63377a2e3..410066477 100644 --- a/tools/cmake/component_utils.cmake +++ b/tools/cmake/component_utils.cmake @@ -1,3 +1,9 @@ +function(debug message) + if(DEBUG) + message(STATUS "${message}") + endif() +endfunction() + # Given a component name (find_name) and a list of component paths (component_paths), # return the path to the component in 'variable' # diff --git a/tools/cmake/components.cmake b/tools/cmake/components.cmake index 8da2c284f..cec044358 100644 --- a/tools/cmake/components.cmake +++ b/tools/cmake/components.cmake @@ -16,7 +16,6 @@ endfunction() # function(register_component) get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY) - set(component ${COMPONENT_NAME}) spaces2list(COMPONENT_SRCDIRS) spaces2list(COMPONENT_ADD_INCLUDEDIRS) @@ -59,10 +58,12 @@ function(register_component) # add as a PUBLIC library (if there are source files) or INTERFACE (if header only) if(COMPONENT_SRCS OR embed_binaries) - add_library(${component} STATIC ${COMPONENT_SRCS}) + add_library(${COMPONENT_TARGET} STATIC ${COMPONENT_SRCS}) set(include_type PUBLIC) + + set_property(TARGET ${COMPONENT_TARGET} PROPERTY OUTPUT_NAME ${COMPONENT_NAME}) else() - add_library(${component} INTERFACE) # header-only component + add_library(${COMPONENT_TARGET} INTERFACE) # header-only component set(include_type INTERFACE) endif() @@ -75,7 +76,7 @@ function(register_component) else() set(embed_type "BINARY") endif() - target_add_binary_data("${component}" "${embed_data}" "${embed_type}") + target_add_binary_data("${COMPONENT_TARGET}" "${embed_data}" "${embed_type}") endforeach() # add component public includes @@ -85,7 +86,7 @@ function(register_component) message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: " "COMPONENT_ADD_INCLUDEDIRS entry '${include_dir}' not found") endif() - target_include_directories(${component} ${include_type} ${abs_dir}) + target_include_directories(${COMPONENT_TARGET} ${include_type} ${abs_dir}) endforeach() # add component private includes @@ -100,17 +101,25 @@ function(register_component) message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: " "COMPONENT_PRIV_INCLUDEDIRS entry '${include_dir}' does not exist") endif() - target_include_directories(${component} PRIVATE ${abs_dir}) + target_include_directories(${COMPONENT_TARGET} PRIVATE ${abs_dir}) endforeach() - if(component IN_LIST BUILD_TEST_COMPONENTS) - target_link_libraries(${component} "-L${CMAKE_CURRENT_BINARY_DIR}") - target_link_libraries(${component} "-Wl,--whole-archive -l${component} -Wl,--no-whole-archive") + if(${COMPONENT_NAME} IN_LIST BUILD_TEST_COMPONENTS) + target_link_libraries(${COMPONENT_TARGET} "-L${CMAKE_CURRENT_BINARY_DIR}") + target_link_libraries(${COMPONENT_TARGET} "-Wl,--whole-archive -l${COMPONENT_NAME} -Wl,--no-whole-archive") + endif() + + if(COMPONENT_SRCS OR embed_binaries) + target_include_directories(${COMPONENT_TARGET} PUBLIC ${IDF_INCLUDE_DIRECTORIES}) + target_compile_options(${COMPONENT_TARGET} PUBLIC ${IDF_COMPILE_OPTIONS}) + target_compile_options(${COMPONENT_TARGET} PUBLIC $<$:${IDF_C_COMPILE_OPTIONS}>) + target_compile_options(${COMPONENT_TARGET} PUBLIC $<$:${IDF_CXX_COMPILE_OPTIONS}>) + target_compile_definitions(${COMPONENT_TARGET} PUBLIC ${IDF_COMPILE_DEFINITIONS}) endif() if(COMPONENT_ADD_LDFRAGMENTS) spaces2list(COMPONENT_ADD_LDFRAGMENTS) - ldgen_add_fragment_files(${component} "${COMPONENT_ADD_LDFRAGMENTS}") + ldgen_add_fragment_files(${COMPONENT_TARGET} "${COMPONENT_ADD_LDFRAGMENTS}") endif() endfunction() @@ -144,56 +153,24 @@ function(require_idf_targets) endif() endfunction() -function(components_finish_registration) - - # have the executable target depend on all components in the build - set_target_properties(${CMAKE_PROJECT_NAME}.elf PROPERTIES INTERFACE_COMPONENT_REQUIRES "${BUILD_COMPONENTS}") - - spaces2list(COMPONENT_REQUIRES_COMMON) - - # each component should see the include directories of its requirements - # - # (we can't do this until all components are registered and targets exist in cmake, as we have - # a circular requirements graph...) - foreach(a ${BUILD_COMPONENTS}) - if(TARGET ${a}) - get_component_requirements("${a}" a_deps a_priv_deps) - list(APPEND a_priv_deps ${COMPONENT_REQUIRES_COMMON}) - foreach(b ${a_deps}) - add_component_dependencies(${a} ${b} PUBLIC) - endforeach() - - foreach(b ${a_priv_deps}) - add_component_dependencies(${a} ${b} PRIVATE) - endforeach() - - get_target_property(a_type ${a} TYPE) - if(${a_type} MATCHES .+_LIBRARY) - list(APPEND COMPONENT_LIBRARIES ${a}) - endif() - endif() - endforeach() - - # Add each component library's link-time dependencies (which are otherwise ignored) to the executable - # LINK_DEPENDS in order to trigger a re-link when needed (on Ninja/Makefile generators at least). - # (maybe this should probably be something CMake does, but it doesn't do it...) - foreach(component ${BUILD_COMPONENTS}) - if(TARGET ${component}) - get_target_property(imported ${component} IMPORTED) - get_target_property(type ${component} TYPE) - if(NOT imported) - if(${type} STREQUAL STATIC_LIBRARY OR ${type} STREQUAL EXECUTABLE) - get_target_property(link_depends "${component}" LINK_DEPENDS) - if(link_depends) - set_property(TARGET ${CMAKE_PROJECT_NAME}.elf APPEND PROPERTY LINK_DEPENDS "${link_depends}") - endif() - endif() - endif() - endif() - endforeach() - - target_link_libraries(${CMAKE_PROJECT_NAME}.elf ${COMPONENT_LIBRARIES}) - - message(STATUS "Component libraries: ${COMPONENT_LIBRARIES}") - +# component_compile_options +# +# Wrapper around target_compile_options that passes the component name +function(component_compile_options) + target_compile_options(${COMPONENT_TARGET} PRIVATE ${ARGV}) endfunction() + +# component_compile_definitions +# +# Wrapper around target_compile_definitions that passes the component name +function(component_compile_definitions) + target_compile_definitions(${COMPONENT_TARGET} PRIVATE ${ARGV}) +endfunction() + +# component_get_target +# +# Get the library target created for the given component +function(component_get_target var component) + get_property(prefix GLOBAL PROPERTY __IDF_COMPONENTS_PREFIX) + set(${var} ${prefix}_${component} PARENT_SCOPE) +endfunction() \ No newline at end of file diff --git a/tools/cmake/idf_functions.cmake b/tools/cmake/idf_functions.cmake index f949ba543..65ba66351 100644 --- a/tools/cmake/idf_functions.cmake +++ b/tools/cmake/idf_functions.cmake @@ -1,52 +1,63 @@ -# Some IDF-specific functions and functions - -include(crosstool_version_check) - # -# Set some variables used by rest of the build +# Load cmake modules # -# Note at the time this macro is expanded, the config is not yet -# loaded and the toolchain and project are not yet set -# -macro(idf_set_global_variables) - # Note that CONFIG_xxx is not available when this function is called - set_default(EXTRA_COMPONENT_DIRS "") +if(NOT IDF_PATH) + set(IDF_PATH $ENV{IDF_PATH}) +endif() - # Commmon components, required by every component in the build - # - set_default(COMPONENT_REQUIRES_COMMON "cxx ${IDF_TARGET} newlib freertos heap log soc") +get_property(__idf_environment_set GLOBAL PROPERTY __IDF_ENVIRONMENT_SET) - # PROJECT_PATH has the path to the IDF project (top-level cmake directory) - # - # (cmake calls this CMAKE_SOURCE_DIR, keeping old name for compatibility.) - set(PROJECT_PATH "${CMAKE_SOURCE_DIR}") +if(NOT __idf_environment_set) + set(CMAKE_MODULE_PATH + "${IDF_PATH}/tools/cmake" + "${IDF_PATH}/tools/cmake/third_party" + ${CMAKE_MODULE_PATH}) + include(utilities) + include(components) + include(kconfig) + include(targets) + include(git_submodules) + include(GetGitRevisionDescription) + include(crosstool_version_check) + include(ldgen) - if(MAIN_SRCS) - message(WARNING "main is now a component, use of MAIN_SRCS is deprecated") - set_default(COMPONENT_DIRS "${PROJECT_PATH}/components ${EXTRA_COMPONENT_DIRS} \ - ${IDF_PATH}/components") - else() - set_default(COMPONENT_DIRS "${PROJECT_PATH}/components ${EXTRA_COMPONENT_DIRS} \ - ${IDF_PATH}/components ${PROJECT_PATH}/main") + set_default(PYTHON "python") + + if(NOT PYTHON_DEPS_CHECKED AND NOT BOOTLOADER_BUILD) + message(STATUS "Checking Python dependencies...") + execute_process(COMMAND "${PYTHON}" "${IDF_PATH}/tools/check_python_dependencies.py" + RESULT_VARIABLE result) + if(NOT result EQUAL 0) + message(FATAL_ERROR "Some Python dependencies must be installed. Check above message for details.") + endif() endif() - spaces2list(COMPONENT_DIRS) + idf_set_target() - spaces2list(COMPONENTS) + set_property(GLOBAL APPEND PROPERTY __IDF_COMPONENTS_PREFIX "idf_component") + set_property(GLOBAL PROPERTY __IDF_ENVIRONMENT_SET 1) +endif() - # Tell cmake to drop executables in the top-level build dir - set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}") +macro(idf_set_variables) + set_default(IDF_BUILD_ARTIFACTS OFF) - # path to idf.py tool - set(IDFTOOL ${PYTHON} "${IDF_PATH}/tools/idf.py") - - # Temporary trick to support both gcc5 and gcc8 builds - if(CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0) - set(GCC_NOT_5_2_0 0) - else() - set(GCC_NOT_5_2_0 1) + if(IDF_BUILD_ARTIFACTS) + if(NOT IDF_BUILD_ARTIFACTS_DIR OR NOT IDF_PROJECT_EXECUTABLE) + message(FATAL_ERROR "IDF_BUILD_ARTIFACTS and IDF_PROJECT_EXECUTABLE needs to be specified \ + if IDF_BUILD_ARTIFACTS is ON.") + endif() endif() + + set_default(IDF_COMPONENT_DIRS "${IDF_EXTRA_COMPONENT_DIRS} ${IDF_PATH}/components") + set_default(IDF_COMPONENTS "") + set_default(IDF_COMPONENT_REQUIRES_COMMON "cxx ${IDF_TARGET} newlib freertos heap log soc") + + set(IDF_PROJECT_PATH "${CMAKE_SOURCE_DIR}") + + spaces2list(IDF_COMPONENT_DIRS) + spaces2list(IDF_COMPONENTS) + spaces2list(IDF_COMPONENT_REQUIRES_COMMON) endmacro() # Add all the IDF global compiler & preprocessor options @@ -55,64 +66,73 @@ endmacro() # If you only want to set options for a particular component, # don't call or edit this function. TODO DESCRIBE WHAT TO DO INSTEAD # -function(idf_set_global_compiler_options) - add_definitions(-DESP_PLATFORM) - add_definitions(-DHAVE_CONFIG_H) - - if(CONFIG_OPTIMIZATION_LEVEL_RELEASE) - add_compile_options(-Os) +function(idf_set_global_compile_options) + # Temporary trick to support both gcc5 and gcc8 builds + if(CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0) + set(GCC_NOT_5_2_0 0) else() - add_compile_options(-Og) + set(GCC_NOT_5_2_0 1) endif() - add_c_compile_options(-std=gnu99) + list(APPEND compile_definitions "ESP_PLATFORM" "HAVE_CONFIG_H") - add_cxx_compile_options(-std=gnu++11 -fno-rtti) + list(APPEND compile_options "${CMAKE_C_FLAGS}") + list(APPEND c_compile_options "${CMAKE_C_FLAGS}") + list(APPEND cxx_compile_options "${CMAKE_CXX_FLAGS}") + + if(CONFIG_OPTIMIZATION_LEVEL_RELEASE) + list(APPEND compile_options "-Os") + else() + list(APPEND compile_options "-Og") + endif() + + list(APPEND c_compile_options "-std=gnu99") + list(APPEND cxx_compile_options "-std=gnu++11" "-fno-rtti") if(CONFIG_CXX_EXCEPTIONS) - add_cxx_compile_options(-fexceptions) + list(APPEND cxx_compile_options "-fexceptions") else() - add_cxx_compile_options(-fno-exceptions) + list(APPEND cxx_compile_options "-fno-exceptions") endif() # Default compiler configuration - add_compile_options(-ffunction-sections -fdata-sections -fstrict-volatile-bitfields -nostdlib) + list(APPEND compile_options "-ffunction-sections" + "-fdata-sections" + "-fstrict-volatile-bitfields" + "-nostdlib") - # Default warnings configuration - add_compile_options( - -Wall - -Werror=all - -Wno-error=unused-function - -Wno-error=unused-but-set-variable - -Wno-error=unused-variable - -Wno-error=deprecated-declarations - -Wextra - -Wno-unused-parameter - -Wno-sign-compare) - add_c_compile_options( - -Wno-old-style-declaration - ) + list(APPEND compile_options "-Wall" + "-Werror=all" + "-Wno-error=unused-function" + "-Wno-error=unused-but-set-variable" + "-Wno-error=unused-variable" + "-Wno-error=deprecated-declarations" + "-Wextra" + "-Wno-unused-parameter" + "-Wno-sign-compare") + + list(APPEND c_compile_options "-Wno-old-style-declaration") if(CONFIG_DISABLE_GCC8_WARNINGS) - add_compile_options( - -Wno-parentheses - -Wno-sizeof-pointer-memaccess - -Wno-clobbered + list(APPEND compile_options + "-Wno-parentheses" + "-Wno-sizeof-pointer-memaccess" + "-Wno-clobbered" ) # doesn't use GCC_NOT_5_2_0 because idf_set_global_variables was not called before if(NOT CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0) - add_compile_options( - -Wno-format-overflow - -Wno-stringop-truncation - -Wno-misleading-indentation - -Wno-cast-function-type - -Wno-implicit-fallthrough - -Wno-unused-const-variable - -Wno-switch-unreachable - -Wno-format-truncation - -Wno-memset-elt-size - -Wno-int-in-bool-context + list(APPEND compile_options + "-Wno-format-overflow" + "-Wno-stringop-truncation" + "-Wno-misleading-indentation" + "-Wno-cast-function-type" + "-Wno-implicit-fallthrough" + "-Wno-unused-const-variable" + "-Wno-switch-unreachable" + "-Wno-format-truncation" + "-Wno-memset-elt-size" + "-Wno-int-in-bool-context" ) endif() endif() @@ -120,39 +140,40 @@ function(idf_set_global_compiler_options) # Stack protection if(NOT BOOTLOADER_BUILD) if(CONFIG_STACK_CHECK_NORM) - add_compile_options(-fstack-protector) + list(APPEND compile_options "-fstack-protector") elseif(CONFIG_STACK_CHECK_STRONG) - add_compile_options(-fstack-protector-strong) + list(APPEND compile_options "-fstack-protector-strong") elseif(CONFIG_STACK_CHECK_ALL) - add_compile_options(-fstack-protector-all) + list(APPEND compile_options "-fstack-protector-all") endif() endif() if(CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED) - add_definitions(-DNDEBUG) + list(APPEND compile_definitions "NDEBUG") endif() # Always generate debug symbols (even in Release mode, these don't # go into the final binary so have no impact on size) - add_compile_options(-ggdb) - - # Enable ccache if it's on the path - if(NOT CCACHE_DISABLE) - find_program(CCACHE_FOUND ccache) - if(CCACHE_FOUND) - message(STATUS "ccache will be used for faster builds") - set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) - endif() - endif() + list(APPEND compile_options "-ggdb") # Temporary trick to support both gcc5 and gcc8 builds - add_definitions(-DGCC_NOT_5_2_0=${GCC_NOT_5_2_0}) -endfunction() + list(APPEND compile_definitions "GCC_NOT_5_2_0=${GCC_NOT_5_2_0}") + set_default(IDF_COMPILE_DEFINITIONS "${compile_definitions}") + set_default(IDF_COMPILE_OPTIONS "${compile_options}") + set_default(IDF_C_COMPILE_OPTIONS "${c_compile_options}") + set_default(IDF_CXX_COMPILE_OPTIONS "${cxx_compile_options}") + set_default(IDF_INCLUDE_DIRECTORIES "${CONFIG_DIR}") + + set(IDF_COMPILE_DEFINITIONS ${IDF_COMPILE_DEFINITIONS} PARENT_SCOPE) + set(IDF_COMPILE_OPTIONS ${IDF_COMPILE_OPTIONS} PARENT_SCOPE) + set(IDF_C_COMPILE_OPTIONS ${IDF_C_COMPILE_OPTIONS} PARENT_SCOPE) + set(IDF_CXX_COMPILE_OPTIONS ${IDF_CXX_COMPILE_OPTIONS} PARENT_SCOPE) + set(IDF_INCLUDE_DIRECTORIES ${CONFIG_DIR} PARENT_SCOPE) +endfunction() # Verify the IDF environment is configured correctly (environment, toolchain, etc) function(idf_verify_environment) - if(NOT CMAKE_PROJECT_NAME) message(FATAL_ERROR "Internal error, IDF project.cmake should have set this variable already") endif() @@ -170,77 +191,6 @@ function(idf_verify_environment) get_expected_ctng_version(expected_toolchain expected_gcc) gcc_version_check("${expected_gcc}") crosstool_version_check("${expected_toolchain}") - -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) - - if(MAIN_SRCS) - spaces2list(MAIN_SRCS) - add_executable(${exe_target} ${MAIN_SRCS}) - else() - # Create a dummy file to work around CMake requirement of having a source - # file while adding an executable - add_executable(${exe_target} "${CMAKE_CURRENT_BINARY_DIR}/dummy_main_src.c") - add_custom_command(OUTPUT dummy_main_src.c - COMMAND ${CMAKE_COMMAND} -E touch dummy_main_src.c - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM) - - add_custom_target(dummy_main_src DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dummy_main_src.c) - - add_dependencies(${exe_target} dummy_main_src) - endif() - - add_map_file(${exe_target}) -endfunction() - - -# 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}") - - # add size targets, depend on map file, run idf_size.py - add_custom_target(size - DEPENDS ${exe_target} - COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py ${mapfile} - ) - add_custom_target(size-files - DEPENDS ${exe_target} - COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py --files ${mapfile} - ) - add_custom_target(size-components - DEPENDS ${exe_target} - COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py --archives ${mapfile} - ) - -endfunction() - -# component_compile_options -# -# Wrapper around target_compile_options that passes the component name -function(component_compile_options) - target_compile_options(${COMPONENT_NAME} PRIVATE ${ARGV}) -endfunction() - -# component_compile_definitions -# -# Wrapper around target_compile_definitions that passes the component name -function(component_compile_definitions) - target_compile_definitions(${COMPONENT_NAME} PRIVATE ${ARGV}) endfunction() # idf_get_git_revision @@ -258,4 +208,47 @@ function(idf_get_git_revision) add_definitions(-DIDF_VER=\"${IDF_VER}\") git_submodule_check("${IDF_PATH}") set(IDF_VER ${IDF_VER} PARENT_SCOPE) +endfunction() + +# idf_link_components +# +# Link library components to the target +function(idf_link_components target components) + foreach(component ${components}) + component_get_target(component_target ${component}) + + # Add each component library's link-time dependencies (which are otherwise ignored) to the executable + # LINK_DEPENDS in order to trigger a re-link when needed (on Ninja/Makefile generators at least). + # (maybe this should probably be something CMake does, but it doesn't do it...) + if(TARGET ${component_target}) + get_target_property(type ${component_target} TYPE) + get_target_property(imported ${component_target} IMPORTED) + if(NOT imported) + if(${type} STREQUAL STATIC_LIBRARY OR ${type} STREQUAL EXECUTABLE) + get_target_property(link_depends "${component_target}" LINK_DEPENDS) + if(link_depends) + set_property(TARGET ${target} APPEND PROPERTY LINK_DEPENDS "${link_depends}") + endif() + endif() + endif() + + if(${type} MATCHES .+_LIBRARY) + list(APPEND libraries ${component_target}) + endif() + endif() + endforeach() + + if(libraries) + target_link_libraries(${target} "-Wl,--start-group") + target_link_libraries(${target} ${libraries}) + message(STATUS "Component libraries: ${IDF_COMPONENT_LIBRARIES}") + endif() +endfunction() + +# idf_import_components +# +# Adds ESP-IDF as a subdirectory to the current project and imports the components +function(idf_import_components var idf_path build_path) + add_subdirectory(${idf_path} ${build_path}) + set(${var} ${BUILD_COMPONENTS} PARENT_SCOPE) endfunction() \ No newline at end of file diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index b5e5d484e..cb2a5c3ca 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -1,79 +1,18 @@ include(ExternalProject) macro(kconfig_set_variables) - set(CONFIG_DIR ${CMAKE_BINARY_DIR}/config) - set_default(SDKCONFIG ${PROJECT_PATH}/sdkconfig) + set_default(IDF_SDKCONFIG_DEFAULTS "") + + set_default(CONFIG_DIR ${IDF_BUILD_ARTIFACTS_DIR}/config) + set_default(SDKCONFIG ${IDF_PROJECT_PATH}/sdkconfig) set(SDKCONFIG_HEADER ${CONFIG_DIR}/sdkconfig.h) set(SDKCONFIG_CMAKE ${CONFIG_DIR}/sdkconfig.cmake) set(SDKCONFIG_JSON ${CONFIG_DIR}/sdkconfig.json) set(KCONFIG_JSON_MENUS ${CONFIG_DIR}/kconfig_menus.json) set(ROOT_KCONFIG ${IDF_PATH}/Kconfig) - - set_default(SDKCONFIG_DEFAULTS "${SDKCONFIG}.defaults") - - # ensure all source files can include sdkconfig.h - include_directories("${CONFIG_DIR}") endmacro() -if(CMAKE_HOST_WIN32) - # Prefer a prebuilt mconf-idf on Windows - if(DEFINED ENV{MSYSTEM}) - find_program(WINPTY winpty) - else() - unset(WINPTY CACHE) # in case previous CMake run was in a tty and this one is not - endif() - find_program(MCONF mconf-idf) - - # Fall back to the old binary which was called 'mconf' not 'mconf-idf' - if(NOT MCONF) - find_program(MCONF mconf) - if(MCONF) - message(WARNING "Falling back to mconf binary '${MCONF}' not mconf-idf. " - "This is probably because an old version of IDF mconf is installed and this is fine. " - "However if there are config problems please check the Getting Started guide for your platform.") - endif() - endif() - - if(NOT MCONF) - find_program(NATIVE_GCC gcc) - if(NOT NATIVE_GCC) - message(FATAL_ERROR - "Windows requires a prebuilt mconf-idf for your platform " - "on the PATH, or an MSYS2 version of gcc on the PATH to build mconf-idf. " - "Consult the setup docs for ESP-IDF on Windows.") - endif() - elseif(WINPTY) - set(MCONF "${WINPTY}" "${MCONF}") - endif() -endif() - -if(NOT MCONF) - # Use the existing Makefile to build mconf (out of tree) when needed - # - set(MCONF kconfig_bin/mconf-idf) - - externalproject_add(mconf-idf - SOURCE_DIR ${IDF_PATH}/tools/kconfig - CONFIGURE_COMMAND "" - BINARY_DIR "kconfig_bin" - BUILD_COMMAND make -f ${IDF_PATH}/tools/kconfig/Makefile mconf-idf - BUILD_BYPRODUCTS ${MCONF} - INSTALL_COMMAND "" - EXCLUDE_FROM_ALL 1 - ) - - file(GLOB mconf_srcfiles ${IDF_PATH}/tools/kconfig/*.c) - externalproject_add_stepdependencies(mconf-idf build - ${mconf_srcfiles} - ${IDF_PATH}/tools/kconfig/Makefile - ${CMAKE_CURRENT_LIST_FILE}) - unset(mconf_srcfiles) - - set(menuconfig_depends DEPENDS mconf-idf) - -endif() - # Find all Kconfig files for all components function(kconfig_process_config) file(MAKE_DIRECTORY "${CONFIG_DIR}") @@ -95,8 +34,8 @@ function(kconfig_process_config) endif() endforeach() - if(EXISTS ${SDKCONFIG_DEFAULTS}) - set(defaults_arg --defaults "${SDKCONFIG_DEFAULTS}") + if(IDF_SDKCONFIG_DEFAULTS) + set(defaults_arg --defaults "${IDF_SDKCONFIG_DEFAULTS}") endif() if(EXISTS "${SDKCONFIG_DEFAULTS}.${IDF_TARGET}") @@ -172,3 +111,61 @@ function(kconfig_process_config) "${SDKCONFIG_HEADER}" "${SDKCONFIG_CMAKE}") endfunction() + +if(CMAKE_HOST_WIN32) + # Prefer a prebuilt mconf-idf on Windows + if(DEFINED ENV{MSYSTEM}) + find_program(WINPTY winpty) + else() + unset(WINPTY CACHE) # in case previous CMake run was in a tty and this one is not + endif() + find_program(MCONF mconf-idf) + + # Fall back to the old binary which was called 'mconf' not 'mconf-idf' + if(NOT MCONF) + find_program(MCONF mconf) + if(MCONF) + message(WARNING "Falling back to mconf binary '${MCONF}' not mconf-idf. " + "This is probably because an old version of IDF mconf is installed and this is fine. " + "However if there are config problems please check the Getting Started guide for your platform.") + endif() + endif() + + if(NOT MCONF) + find_program(NATIVE_GCC gcc) + if(NOT NATIVE_GCC) + message(FATAL_ERROR + "Windows requires a prebuilt mconf-idf for your platform " + "on the PATH, or an MSYS2 version of gcc on the PATH to build mconf-idf. " + "Consult the setup docs for ESP-IDF on Windows.") + endif() + elseif(WINPTY) + set(MCONF "${WINPTY}" "${MCONF}") + endif() +endif() + +if(NOT MCONF) + # Use the existing Makefile to build mconf (out of tree) when needed + # + set(MCONF kconfig_bin/mconf-idf) + + externalproject_add(mconf-idf + SOURCE_DIR ${IDF_PATH}/tools/kconfig + CONFIGURE_COMMAND "" + BINARY_DIR "kconfig_bin" + BUILD_COMMAND make -f ${IDF_PATH}/tools/kconfig/Makefile mconf-idf + BUILD_BYPRODUCTS ${MCONF} + INSTALL_COMMAND "" + EXCLUDE_FROM_ALL 1 + ) + + file(GLOB mconf_srcfiles ${IDF_PATH}/tools/kconfig/*.c) + externalproject_add_stepdependencies(mconf-idf build + ${mconf_srcfiles} + ${IDF_PATH}/tools/kconfig/Makefile + ${CMAKE_CURRENT_LIST_FILE}) + unset(mconf_srcfiles) + + set(menuconfig_depends DEPENDS mconf-idf) + +endif() \ No newline at end of file diff --git a/tools/cmake/ldgen.cmake b/tools/cmake/ldgen.cmake index 26ec26f16..b69ff3bfb 100644 --- a/tools/cmake/ldgen.cmake +++ b/tools/cmake/ldgen.cmake @@ -67,6 +67,8 @@ endfunction() # ldgen_create_commands # # Create the command to generate the output scripts from templates presented. -function(ldgen_add_dependencies executable_name) - add_dependencies(${executable_name} ldgen) +function(ldgen_add_dependencies) + if(IDF_PROJECT_EXECUTABLE) + add_dependencies(${IDF_PROJECT_EXECUTABLE} ldgen) + endif() endfunction() \ No newline at end of file diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index 74042fd07..e2aa7c19f 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -2,7 +2,7 @@ # cmake_minimum_required(VERSION 3.5) -# Set IDF_PATH, as nothing else will work without this +# Set IDF_PATH, as nothing else will work without this. set(IDF_PATH "$ENV{IDF_PATH}") if(NOT IDF_PATH) # Documentation says you should set IDF_PATH in your environment, but we @@ -12,177 +12,135 @@ endif() file(TO_CMAKE_PATH "${IDF_PATH}" IDF_PATH) set(ENV{IDF_PATH} ${IDF_PATH}) +# Set the path of idf.py. +set(IDFTOOL ${PYTHON} "${IDF_PATH}/tools/idf.py") -# -# Load cmake modules -# -set(CMAKE_MODULE_PATH - "${IDF_PATH}/tools/cmake" - "${IDF_PATH}/tools/cmake/third_party" - ${CMAKE_MODULE_PATH}) -include(GetGitRevisionDescription) -include(utilities) -include(components) -include(targets) -include(kconfig) -include(git_submodules) -include(idf_functions) -include(ldgen) +# Trick to temporarily redefine project(). When functions are overriden in CMake, the originals can still be accessed +# using an underscore prefixed function of the same name. The following lines make sure that __project calls +# the original project(). See https://cmake.org/pipermail/cmake/2015-October/061751.html. +function(project) +endfunction() -set_default(PYTHON "python") +function(_project) +endfunction() -if(NOT PYTHON_DEPS_CHECKED AND NOT BOOTLOADER_BUILD) - message(STATUS "Checking Python dependencies...") - execute_process(COMMAND "${PYTHON}" "${IDF_PATH}/tools/check_python_dependencies.py" - RESULT_VARIABLE result) - if(NOT result EQUAL 0) - message(FATAL_ERROR "Some Python dependencies must be installed. Check above message for details.") - endif() -endif() +include(${IDF_PATH}/tools/cmake/idf_functions.cmake) -# project -# -# This macro wraps the cmake 'project' command to add -# all of the IDF-specific functionality required -# -# Implementation Note: This macro wraps 'project' on purpose, because cmake has -# some backwards-compatible magic where if you don't call "project" in the -# top-level CMakeLists file, it will call it implicitly. However, the implicit -# project will not have CMAKE_TOOLCHAIN_FILE set and therefore tries to -# create a native build project. -# -# Therefore, to keep all the IDF "build magic", the cleanest way is to keep the -# top-level "project" call but customize it to do what we want in the IDF build. -# macro(project name) - # Determine the build target - idf_set_target() - # Set global variables used by rest of the build - idf_set_global_variables() + # Bridge existing documented variable names with library namespaced variables in order for old projects to work. + if(COMPONENT_DIRS) + spaces2list(COMPONENT_DIRS) - # Sort the components list, as it may be found via filesystem - # traversal and therefore in a non-deterministic order - list(SORT COMPONENTS) + foreach(component_dir ${COMPONENT_DIRS}) + get_filename_component(full_path ${component_dir} ABSOLUTE) + get_filename_component(idf_path "${IDF_PATH}/components" ABSOLUTE) - execute_process(COMMAND "${CMAKE_COMMAND}" - -D "COMPONENTS=${COMPONENTS}" - -D "COMPONENT_REQUIRES_COMMON=${COMPONENT_REQUIRES_COMMON}" - -D "EXCLUDE_COMPONENTS=${EXCLUDE_COMPONENTS}" - -D "TEST_COMPONENTS=${TEST_COMPONENTS}" - -D "TEST_EXCLUDE_COMPONENTS=${TEST_EXCLUDE_COMPONENTS}" - -D "TESTS_ALL=${TESTS_ALL}" - -D "DEPENDENCIES_FILE=${CMAKE_BINARY_DIR}/component_depends.cmake" - -D "COMPONENT_DIRS=${COMPONENT_DIRS}" - -D "BOOTLOADER_BUILD=${BOOTLOADER_BUILD}" - -D "IDF_PATH=${IDF_PATH}" - -D "IDF_TARGET=${IDF_TARGET}" - -D "DEBUG=${DEBUG}" - -P "${IDF_PATH}/tools/cmake/scripts/expand_requirements.cmake" - WORKING_DIRECTORY "${PROJECT_PATH}") - include("${CMAKE_BINARY_DIR}/component_depends.cmake") - - # We now have the following component-related variables: - # COMPONENTS is the list of initial components set by the user (or empty to include all components in the build). - # BUILD_COMPONENTS is the list of components to include in the build. - # BUILD_COMPONENT_PATHS is the paths to all of these components. - - # Print list of components - string(REPLACE ";" " " BUILD_COMPONENTS_SPACES "${BUILD_COMPONENTS}") - message(STATUS "Component names: ${BUILD_COMPONENTS_SPACES}") - unset(BUILD_COMPONENTS_SPACES) - message(STATUS "Component paths: ${BUILD_COMPONENT_PATHS}") - - # Print list of test components - if(TESTS_ALL EQUAL 1 OR TEST_COMPONENTS) - string(REPLACE ";" " " BUILD_TEST_COMPONENTS_SPACES "${BUILD_TEST_COMPONENTS}") - message(STATUS "Test component names: ${BUILD_TEST_COMPONENTS_SPACES}") - unset(BUILD_TEST_COMPONENTS_SPACES) - message(STATUS "Test component paths: ${BUILD_TEST_COMPONENT_PATHS}") + if(NOT full_path STREQUAL idf_path) + set(IDF_EXTRA_COMPONENT_DIRS "${IDF_EXTRA_COMPONENT_DIRS} ${component_dir}") + endif() + endforeach() + else() + if(MAIN_SRCS) + set(IDF_EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${CMAKE_SOURCE_DIR}/components") + else() + set(IDF_EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} \ + ${CMAKE_SOURCE_DIR}/components ${CMAKE_SOURCE_DIR}/main") + endif() endif() - kconfig_set_variables() + if(COMPONENTS) + set(IDF_COMPONENTS "${COMPONENTS}") + endif() - kconfig_process_config() + if(COMPONENT_REQUIRES_COMMON) + set(IDF_COMPONENT_REQUIRES_COMMON "${COMPONENT_REQUIRES_COMMON}") + endif() - # Include sdkconfig.cmake so rest of the build knows the configuration - include(${SDKCONFIG_CMAKE}) + if(EXCLUDE_COMPONENTS) + set(IDF_EXCLUDE_COMPONENTS "${COMPONENT_EXCLUDES}") + endif() - # Check that the targets set in cache, sdkconfig, and in environment all match - idf_check_config_target() + if(TESTS_ALL EQUAL 1 OR TEST_COMPONENTS) + set(IDF_BUILD_TESTS 1) + endif() + + if(TEST_COMPONENTS) + set(IDF_TEST_COMPONENTS "${TEST_COMPONENTS}") + endif() + + if(TEST_EXCLUDE_COMPONENTS) + set(IDF_TEST_EXCLUDE_COMPONENTS "${TEST_EXCLUDE_COMPONENTS}") + endif() + + if(NOT SDKCONFIG_DEFAULTS) + if(EXISTS ${CMAKE_SOURCE_DIR}/sdkconfig.defaults) + set(IDF_SDKCONFIG_DEFAULTS ${CMAKE_SOURCE_DIR}/sdkconfig.defaults) + endif() + else() + set(IDF_SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS}) + endif() + + # Set build variables + idf_set_variables() # Now the configuration is loaded, set the toolchain appropriately idf_set_toolchain() - # Declare the actual cmake-level project - _project(${name} ASM C CXX) + __project(${name} C CXX ASM) - # generate compile_commands.json (needs to come after project) - set(CMAKE_EXPORT_COMPILE_COMMANDS 1) + set(IDF_BUILD_ARTIFACTS ON) + set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf) + set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR}) - # Verify the environment is configured correctly - idf_verify_environment() + if(MAIN_SRCS) + spaces2list(MAIN_SRCS) + add_executable(${IDF_PROJECT_EXECUTABLE} ${MAIN_SRCS}) + else() + # Create a dummy file to work around CMake requirement of having a source + # file while adding an executable + add_executable(${IDF_PROJECT_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/dummy_main_src.c") + add_custom_command(OUTPUT dummy_main_src.c + COMMAND ${CMAKE_COMMAND} -E touch dummy_main_src.c + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + VERBATIM) - # Add some idf-wide definitions - idf_set_global_compiler_options() + add_custom_target(dummy_main_src DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dummy_main_src.c) - # Check git revision (may trigger reruns of cmake) - ## sets IDF_VER to IDF git revision - idf_get_git_revision() - ## if project uses git, retrieve revision - git_describe(PROJECT_VER "${CMAKE_CURRENT_SOURCE_DIR}") + add_dependencies(${IDF_PROJECT_EXECUTABLE} dummy_main_src) + endif() - # - # Add the app executable to the build (has name of PROJECT.elf) - # - idf_add_executable() + set(mapfile "${CMAKE_PROJECT_NAME}.map") - # - # Setup variables for linker script generation - # - ldgen_set_variables() + target_link_libraries(${IDF_PROJECT_EXECUTABLE} "-Wl,--gc-sections \ + -Wl,--cref -Wl,--Map=${mapfile}") - # Include any top-level project_include.cmake files from components - foreach(component ${BUILD_COMPONENT_PATHS}) - set(COMPONENT_PATH "${component}") - include_if_exists("${component}/project_include.cmake") - unset(COMPONENT_PATH) - endforeach() + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES + "${CMAKE_CURRENT_BINARY_DIR}/${mapfile}") - # - # Add each component to the build as a library - # - foreach(COMPONENT_PATH ${BUILD_COMPONENT_PATHS}) - list(FIND BUILD_TEST_COMPONENT_PATHS ${COMPONENT_PATH} idx) + # Add size targets, depend on map file, run idf_size.py + add_custom_target(size + DEPENDS ${exe_target} + COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py ${mapfile} + ) + add_custom_target(size-files + DEPENDS ${exe_target} + COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py --files ${mapfile} + ) + add_custom_target(size-components + DEPENDS ${exe_target} + COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py --archives ${mapfile} + ) - if(NOT idx EQUAL -1) - list(GET BUILD_TEST_COMPONENTS ${idx} test_component) - set(COMPONENT_NAME ${test_component}) - else() - get_filename_component(COMPONENT_NAME ${COMPONENT_PATH} NAME) - endif() - - add_subdirectory(${COMPONENT_PATH} ${COMPONENT_NAME}) - endforeach() - unset(COMPONENT_NAME) - unset(COMPONENT_PATH) - - # At this point the fragment files have been collected, generate - # the commands needed to generate the output linker scripts - ldgen_add_dependencies(${PROJECT_NAME}.elf) - - # Write project description JSON file - make_json_list("${BUILD_COMPONENTS}" build_components_json) - make_json_list("${BUILD_COMPONENT_PATHS}" build_component_paths_json) - configure_file("${IDF_PATH}/tools/cmake/project_description.json.in" - "${CMAKE_BINARY_DIR}/project_description.json") - unset(build_components_json) - unset(build_component_paths_json) - - # - # Finish component registration (add cross-dependencies, make - # executable dependent on all components) - # - components_finish_registration() + # Since components can import third-party libraries, the original definition of project() should be restored + # before the call to add components to the build. + function(project) + set(project_ARGV ARGV) + __project(${${project_ARGV}}) + endfunction() + # Finally, add the rest of the components to the build. + idf_import_components(components $ENV{IDF_PATH} esp-idf) + idf_link_components(${IDF_PROJECT_EXECUTABLE} "${components}") endmacro() diff --git a/tools/cmake/project_description.json.in b/tools/cmake/project_description.json.in index 878dce3b3..55c3fb97d 100644 --- a/tools/cmake/project_description.json.in +++ b/tools/cmake/project_description.json.in @@ -1,11 +1,11 @@ { - "project_name": "${PROJECT_NAME}", - "project_path": "${PROJECT_PATH}", - "build_dir": "${CMAKE_BINARY_DIR}", + "project_name": "${IDF_PROJECT_NAME}", + "project_path": "${IDF_PROJECT_PATH}", + "build_dir": "${IDF_BUILD_ARTIFACTS_DIR}", "config_file": "${SDKCONFIG}", - "config_defaults": "${SDKCONFIG_DEFAULTS}", - "app_elf": "${PROJECT_NAME}.elf", - "app_bin": "${PROJECT_NAME}.bin", + "config_defaults": "${IDF_SDKCONFIG_DEFAULTS}", + "app_elf": "${IDF_PROJECT_EXECUTABLE}", + "app_bin": "${IDF_PROJECT_BIN}", "git_revision": "${IDF_VER}", "phy_data_partition": "${CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION}", "monitor_baud" : "${CONFIG_MONITOR_BAUD}", diff --git a/tools/cmake/scripts/expand_requirements.cmake b/tools/cmake/scripts/expand_requirements.cmake index 55e293bdd..bcfa76aa4 100644 --- a/tools/cmake/scripts/expand_requirements.cmake +++ b/tools/cmake/scripts/expand_requirements.cmake @@ -1,4 +1,4 @@ -# expand_requires.cmake is a utility cmake script to expand component requirements early in the build, +# expand_requirements.cmake is a utility cmake script to expand component requirements early in the build, # before the components are ready to be included. # # Parameters: @@ -44,12 +44,6 @@ spaces2list(COMPONENT_DIRS) spaces2list(COMPONENT_REQUIRES_COMMON) -function(debug message) - if(DEBUG) - message(STATUS "${message}") - endif() -endfunction() - # Dummy register_component used to save requirements variables as global properties, for later expansion # # (expand_component_requirements() includes the component CMakeLists.txt, which then sets its component variables, @@ -85,10 +79,6 @@ function(require_idf_targets) endif() endfunction() -# Dummy call for ldgen_add_fragment_file -function(ldgen_add_fragment_file files) -endfunction() - # expand_component_requirements: Recursively expand a component's requirements, # setting global properties BUILD_COMPONENTS & BUILD_COMPONENT_PATHS and # also invoking the components to call register_component() above, @@ -160,15 +150,15 @@ macro(filter_components_list) endif() else() set(add_component 1) - endif() if(NOT ${component} IN_LIST EXCLUDE_COMPONENTS AND add_component EQUAL 1) list(APPEND components ${component}) list(APPEND component_paths ${component_path}) - if(TESTS_ALL EQUAL 1 OR TEST_COMPONENTS) - if(NOT TESTS_ALL EQUAL 1 AND TEST_COMPONENTS) + if(BUILD_TESTS EQUAL 1) + + if(TEST_COMPONENTS) if(${component} IN_LIST TEST_COMPONENTS) set(add_test_component 1) else() diff --git a/tools/cmake/targets.cmake b/tools/cmake/targets.cmake index 95f7d5e10..2092985a8 100644 --- a/tools/cmake/targets.cmake +++ b/tools/cmake/targets.cmake @@ -45,7 +45,8 @@ macro(idf_set_toolchain) set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_global}) else() # Try to load the toolchain file from the directory of ${IDF_TARGET} component - find_component_path(${IDF_TARGET} "${BUILD_COMPONENTS}" "${BUILD_COMPONENT_PATHS}" target_component_path) + components_find_all("${IDF_COMPONENT_DIRS}" ALL_COMPONENT_PATHS ALL_COMPONENTS ALL_TEST_COMPONENTS) + find_component_path(${IDF_TARGET} "${ALL_COMPONENTS}" "${ALL_COMPONENT_PATHS}" target_component_path) set(toolchain_file_component ${target_component_path}/toolchain-${IDF_TARGET}.cmake) if(EXISTS ${toolchain_file_component}) set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_component}) diff --git a/tools/cmake/utilities.cmake b/tools/cmake/utilities.cmake index 8abeef89a..9e7019f0e 100644 --- a/tools/cmake/utilities.cmake +++ b/tools/cmake/utilities.cmake @@ -105,7 +105,7 @@ function(target_add_binary_data target embed_file embed_type) get_filename_component(embed_file "${embed_file}" ABSOLUTE) get_filename_component(name "${embed_file}" NAME) - set(embed_srcfile "${CMAKE_BINARY_DIR}/${name}.S") + set(embed_srcfile "${IDF_BUILD_ARTIFACTS_DIR}/${name}.S") add_custom_command(OUTPUT "${embed_srcfile}" COMMAND "${CMAKE_COMMAND}" @@ -115,7 +115,7 @@ function(target_add_binary_data target embed_file embed_type) -P "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake" MAIN_DEPENDENCY "${embed_file}" DEPENDS "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + WORKING_DIRECTORY "${IDF_BUILD_ARTIFACTS_DIR}" VERBATIM) set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${embed_srcfile}") From 0908fba1a3c3dd7d474041677819b296dffa1f76 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 11 Nov 2018 15:44:54 +0800 Subject: [PATCH 2/5] mbedtls: import mbedtls project w/o modification --- components/mbedtls/CMakeLists.txt | 142 +++++++------------- components/mbedtls/mbedtls.c | 1 + components/mbedtls/port/esp_bignum.c | 3 +- components/mbedtls/port/esp_hardware.c | 2 + components/mbedtls/port/esp_mem.c | 1 + components/mbedtls/port/mbedtls_debug.c | 5 +- components/mbedtls/port/net_sockets.c | 6 +- components/mbedtls/test/CMakeLists.txt | 2 +- components/nvs_flash/test_nvs_host/Makefile | 8 +- 9 files changed, 68 insertions(+), 102 deletions(-) create mode 100644 components/mbedtls/mbedtls.c diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index f9964f2e7..c99985d1c 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -1,101 +1,57 @@ -set(COMPONENT_ADD_INCLUDEDIRS port/include mbedtls/include) -set(COMPONENT_SRCS "mbedtls/library/aes.c" - "mbedtls/library/aesni.c" - "mbedtls/library/arc4.c" - "mbedtls/library/aria.c" - "mbedtls/library/asn1parse.c" - "mbedtls/library/asn1write.c" - "mbedtls/library/base64.c" - "mbedtls/library/bignum.c" - "mbedtls/library/blowfish.c" - "mbedtls/library/camellia.c" - "mbedtls/library/ccm.c" - "mbedtls/library/certs.c" - "mbedtls/library/chacha20.c" - "mbedtls/library/chachapoly.c" - "mbedtls/library/cipher.c" - "mbedtls/library/cipher_wrap.c" - "mbedtls/library/cmac.c" - "mbedtls/library/ctr_drbg.c" - "mbedtls/library/debug.c" - "mbedtls/library/des.c" - "mbedtls/library/dhm.c" - "mbedtls/library/ecdh.c" - "mbedtls/library/ecdsa.c" - "mbedtls/library/ecjpake.c" - "mbedtls/library/ecp.c" - "mbedtls/library/ecp_curves.c" - "mbedtls/library/entropy.c" - "mbedtls/library/entropy_poll.c" - "mbedtls/library/error.c" - "mbedtls/library/gcm.c" - "mbedtls/library/havege.c" - "mbedtls/library/hkdf.c" - "mbedtls/library/hmac_drbg.c" - "mbedtls/library/md.c" - "mbedtls/library/md2.c" - "mbedtls/library/md4.c" - "mbedtls/library/md5.c" - "mbedtls/library/md_wrap.c" - "mbedtls/library/memory_buffer_alloc.c" - "mbedtls/library/net_sockets.c" - "mbedtls/library/nist_kw.c" - "mbedtls/library/oid.c" - "mbedtls/library/padlock.c" - "mbedtls/library/pem.c" - "mbedtls/library/pk.c" - "mbedtls/library/pk_wrap.c" - "mbedtls/library/pkcs11.c" - "mbedtls/library/pkcs12.c" - "mbedtls/library/pkcs5.c" - "mbedtls/library/pkparse.c" - "mbedtls/library/pkwrite.c" - "mbedtls/library/platform.c" - "mbedtls/library/platform_util.c" - "mbedtls/library/poly1305.c" - "mbedtls/library/ripemd160.c" - "mbedtls/library/rsa.c" - "mbedtls/library/rsa_internal.c" - "mbedtls/library/sha1.c" - "mbedtls/library/sha256.c" - "mbedtls/library/sha512.c" - "mbedtls/library/ssl_cache.c" - "mbedtls/library/ssl_ciphersuites.c" - "mbedtls/library/ssl_cli.c" - "mbedtls/library/ssl_cookie.c" - "mbedtls/library/ssl_srv.c" - "mbedtls/library/ssl_ticket.c" - "mbedtls/library/ssl_tls.c" - "mbedtls/library/threading.c" - "mbedtls/library/timing.c" - "mbedtls/library/version.c" - "mbedtls/library/version_features.c" - "mbedtls/library/x509.c" - "mbedtls/library/x509_create.c" - "mbedtls/library/x509_crl.c" - "mbedtls/library/x509_crt.c" - "mbedtls/library/x509_csr.c" - "mbedtls/library/x509write_crt.c" - "mbedtls/library/x509write_csr.c" - "mbedtls/library/xtea.c" - "port/esp_bignum.c" - "port/esp_hardware.c" - "port/esp_mem.c" - "port/esp_sha1.c" - "port/esp_sha256.c" - "port/esp_sha512.c" - "port/mbedtls_debug.c" - "port/net_sockets.c") - +set(COMPONENT_ADD_INCLUDEDIRS "port/include" "mbedtls/include") +set(COMPONENT_SRCS "mbedtls.c") set(COMPONENT_REQUIRES lwip) register_component() -target_compile_definitions(${COMPONENT_TARGET} PUBLIC - -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h" -) +# Only build mbedtls libraries +set(ENABLE_TESTING CACHE BOOL OFF) +set(ENABLE_PROGRAMS CACHE BOOL OFF) + +# Use same policy between IDF and mbedtls build +function(project) + set(_args ARGV) + _project(${${_args}}) + cmake_policy(SET CMP0022 NEW) +endfunction() + +# Needed to for include_next includes to work from within mbedtls +include_directories("${COMPONENT_PATH}/port/include") + +# Import mbedtls library targets +add_subdirectory(mbedtls) + +set(mbedtls_targets mbedtls mbedcrypto mbedx509) + +# Add port files to mbedtls targets +target_sources(mbedtls PRIVATE "${COMPONENT_PATH}/port/esp_bignum.c" + "${COMPONENT_PATH}/port/esp_hardware.c" + "${COMPONENT_PATH}/port/esp_mem.c" + "${COMPONENT_PATH}/port/esp_sha1.c" + "${COMPONENT_PATH}/port/esp_sha256.c" + "${COMPONENT_PATH}/port/esp_sha512.c" + "${COMPONENT_PATH}/port/mbedtls_debug.c" + "${COMPONENT_PATH}/port/net_sockets.c") + +foreach(target ${mbedtls_targets}) + # Propagate compile options to mbedtls library targets + target_include_directories(${target} PRIVATE "${IDF_INCLUDE_DIRECTORIES}") + target_compile_options(${target} PRIVATE "${IDF_COMPILE_OPTIONS};${IDF_C_COMPILE_OPTIONS}") + target_compile_definitions(${target} PRIVATE "${IDF_COMPILE_DEFINITIONS}") + target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h") + + # The mbedtls targets also depends on core components + foreach(common ${IDF_COMPONENT_REQUIRES_COMMON}) + component_get_target(common_target ${common}) + set_property(TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${common_target}) + set_property(TARGET ${target} APPEND PROPERTY LINK_LIBRARIES ${common_target}) + endforeach() +endforeach() + +# Link mbedtls libraries to component library +target_link_libraries(${COMPONENT_TARGET} ${mbedtls_targets}) # Catch usage of deprecated mbedTLS functions when building tests if(mbedtls_test IN_LIST BUILD_TEST_COMPONENTS) add_definitions(-DMBEDTLS_DEPRECATED_WARNING) -endif() +endif() \ No newline at end of file diff --git a/components/mbedtls/mbedtls.c b/components/mbedtls/mbedtls.c new file mode 100644 index 000000000..fab17ac78 --- /dev/null +++ b/components/mbedtls/mbedtls.c @@ -0,0 +1 @@ +// Empty file diff --git a/components/mbedtls/port/esp_bignum.c b/components/mbedtls/port/esp_bignum.c index 4dac2b510..ebcd208cc 100644 --- a/components/mbedtls/port/esp_bignum.c +++ b/components/mbedtls/port/esp_bignum.c @@ -27,7 +27,6 @@ #include #include #include -#include "mbedtls/bignum.h" #include "rom/bigint.h" #include "soc/hwcrypto_reg.h" #include "esp_system.h" @@ -36,6 +35,8 @@ #include "esp_intr_alloc.h" #include "esp_attr.h" +#include + #include "soc/dport_reg.h" #include "freertos/FreeRTOS.h" diff --git a/components/mbedtls/port/esp_hardware.c b/components/mbedtls/port/esp_hardware.c index 09ededb18..a919ca340 100644 --- a/components/mbedtls/port/esp_hardware.c +++ b/components/mbedtls/port/esp_hardware.c @@ -9,6 +9,8 @@ #include #include +#include "mbedtls/entropy_poll.h" + #ifndef MBEDTLS_ENTROPY_HARDWARE_ALT #error "MBEDTLS_ENTROPY_HARDWARE_ALT should always be set in ESP-IDF" #endif diff --git a/components/mbedtls/port/esp_mem.c b/components/mbedtls/port/esp_mem.c index 198c0c6cc..c7b8e706f 100644 --- a/components/mbedtls/port/esp_mem.c +++ b/components/mbedtls/port/esp_mem.c @@ -15,6 +15,7 @@ #include #include #include +#include "esp_mem.h" #ifndef CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC diff --git a/components/mbedtls/port/mbedtls_debug.c b/components/mbedtls/port/mbedtls_debug.c index 316a76a99..f7b554145 100644 --- a/components/mbedtls/port/mbedtls_debug.c +++ b/components/mbedtls/port/mbedtls_debug.c @@ -20,6 +20,7 @@ #include "mbedtls/ssl.h" #include "mbedtls/esp_debug.h" +#ifdef CONFIG_MBEDTLS_DEBUG static const char *TAG = "mbedtls"; static void mbedtls_esp_debug(void *ctx, int level, @@ -28,9 +29,9 @@ static void mbedtls_esp_debug(void *ctx, int level, void mbedtls_esp_enable_debug_log(mbedtls_ssl_config *conf, int threshold) { + esp_log_level_t level = ESP_LOG_NONE; mbedtls_debug_set_threshold(threshold); mbedtls_ssl_conf_dbg(conf, mbedtls_esp_debug, NULL); - esp_log_level_t level = ESP_LOG_NONE; switch(threshold) { case 1: level = ESP_LOG_WARN; @@ -53,6 +54,7 @@ void mbedtls_esp_disable_debug_log(mbedtls_ssl_config *conf) mbedtls_ssl_conf_dbg(conf, NULL, NULL); } + /* Default mbedtls debug function that translates mbedTLS debug output to ESP_LOGx debug output. */ @@ -89,3 +91,4 @@ static void mbedtls_esp_debug(void *ctx, int level, break; } } +#endif \ No newline at end of file diff --git a/components/mbedtls/port/net_sockets.c b/components/mbedtls/port/net_sockets.c index 1a182d8f4..6d8a1cc55 100644 --- a/components/mbedtls/port/net_sockets.c +++ b/components/mbedtls/port/net_sockets.c @@ -131,6 +131,10 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char { int ret; struct addrinfo hints, *addr_list, *cur; + struct sockaddr_in *serv_addr = NULL; +#if SO_REUSE + int n = 1; +#endif if ( ( ret = net_prepare() ) != 0 ) { return ( ret ); @@ -157,7 +161,6 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char /*SO_REUSEADDR option dafault is disable in source code(lwip)*/ #if SO_REUSE - int n = 1; if ( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof( n ) ) != 0 ) { close( fd ); @@ -166,7 +169,6 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char } #endif /*bind interface dafault don't process the addr is 0xffffffff for TCP Protocol*/ - struct sockaddr_in *serv_addr = NULL; serv_addr = (struct sockaddr_in *)cur->ai_addr; serv_addr->sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ if ( bind( fd, (struct sockaddr *)serv_addr, cur->ai_addrlen ) != 0 ) { diff --git a/components/mbedtls/test/CMakeLists.txt b/components/mbedtls/test/CMakeLists.txt index 0c2125acc..e1aad74fa 100644 --- a/components/mbedtls/test/CMakeLists.txt +++ b/components/mbedtls/test/CMakeLists.txt @@ -3,4 +3,4 @@ set(COMPONENT_ADD_INCLUDEDIRS ".") set(COMPONENT_REQUIRES unity test_utils mbedtls) -register_component() \ No newline at end of file +register_component() diff --git a/components/nvs_flash/test_nvs_host/Makefile b/components/nvs_flash/test_nvs_host/Makefile index 73aec3253..b125aaffe 100644 --- a/components/nvs_flash/test_nvs_host/Makefile +++ b/components/nvs_flash/test_nvs_host/Makefile @@ -21,7 +21,7 @@ SOURCE_FILES = \ crc.cpp \ main.cpp -CPPFLAGS += -I../include -I../src -I./ -I../../esp32/include -I ../../esp_mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -DCONFIG_NVS_ENCRYPTION +CPPFLAGS += -I../include -I../src -I./ -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -DCONFIG_NVS_ENCRYPTION CFLAGS += -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage @@ -33,8 +33,8 @@ COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(OBJ_FILES): %.o: %.cpp $(TEST_PROGRAM): $(OBJ_FILES) - $(MAKE) -C ../../esp_mbedtls/mbedtls/ lib - g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) ../../esp_mbedtls/mbedtls/library/libmbedcrypto.a + $(MAKE) -C ../../mbedtls/mbedtls/ lib + g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) ../../mbedtls/mbedtls/library/libmbedcrypto.a $(OUTPUT_DIR): mkdir -p $(OUTPUT_DIR) @@ -56,7 +56,7 @@ coverage_report: coverage.info @echo "Coverage report is in coverage_report/index.html" clean: - $(MAKE) -C ../../esp_mbedtls/mbedtls/ clean + $(MAKE) -C ../../mbedtls/mbedtls/ clean rm -f $(OBJ_FILES) $(TEST_PROGRAM) rm -f $(COVERAGE_FILES) *.gcov rm -rf coverage_report/ From 90f5432f2ad2a4646117dfeedae7b0c978eed299 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 11 Nov 2018 15:36:24 +0800 Subject: [PATCH 3/5] examples: generic cmake support examples --- .gitmodules | 5 ++ examples/README.md | 1 + .../cmake/idf_as_lib/CMakeLists.txt | 24 +++++++ .../build_system/cmake/idf_as_lib/README.md | 69 ++++++++++++++++++ .../build_system/cmake/idf_as_lib/build.sh | 8 +++ examples/build_system/cmake/idf_as_lib/main.c | 39 ++++++++++ .../cmake/import_lib/CMakeLists.txt | 6 ++ .../build_system/cmake/import_lib/README.md | 36 ++++++++++ .../cmake/import_lib/main/CMakeLists.txt | 21 ++++++ .../cmake/import_lib/main/lib/tinyxml2 | 1 + .../cmake/import_lib/main/main.cpp | 72 +++++++++++++++++++ .../cmake/import_lib/main/sample.xml | 7 ++ .../cmake/import_lib/partitions_example.csv | 6 ++ .../cmake/import_lib/sdkconfig.defaults | 5 ++ .../get-started/hello_world/CMakeLists.txt | 2 +- .../native_ota_example/main/CMakeLists.txt | 2 +- .../simple_ota_example/main/CMakeLists.txt | 2 +- 17 files changed, 303 insertions(+), 3 deletions(-) create mode 100644 examples/build_system/cmake/idf_as_lib/CMakeLists.txt create mode 100644 examples/build_system/cmake/idf_as_lib/README.md create mode 100755 examples/build_system/cmake/idf_as_lib/build.sh create mode 100644 examples/build_system/cmake/idf_as_lib/main.c create mode 100644 examples/build_system/cmake/import_lib/CMakeLists.txt create mode 100644 examples/build_system/cmake/import_lib/README.md create mode 100644 examples/build_system/cmake/import_lib/main/CMakeLists.txt create mode 160000 examples/build_system/cmake/import_lib/main/lib/tinyxml2 create mode 100644 examples/build_system/cmake/import_lib/main/main.cpp create mode 100644 examples/build_system/cmake/import_lib/main/sample.xml create mode 100644 examples/build_system/cmake/import_lib/partitions_example.csv create mode 100644 examples/build_system/cmake/import_lib/sdkconfig.defaults diff --git a/.gitmodules b/.gitmodules index eb60d7eaa..a9489d8a1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -61,6 +61,11 @@ [submodule "components/protobuf-c/protobuf-c"] path = components/protobuf-c/protobuf-c url = https://github.com/protobuf-c/protobuf-c + [submodule "components/unity/unity"] path = components/unity/unity url = https://github.com/ThrowTheSwitch/Unity + +[submodule "examples/build_system/cmake/import_lib/main/lib/tinyxml2"] + path = examples/build_system/cmake/import_lib/main/lib/tinyxml2 + url = https://github.com/leethomason/tinyxml2 diff --git a/examples/README.md b/examples/README.md index b164fc30f..62e0b73bd 100644 --- a/examples/README.md +++ b/examples/README.md @@ -15,6 +15,7 @@ The examples are grouped into subdirectories by category. Each category director * `storage` contains examples showing data storage methods using SPI flash or external storage like the SD/MMC interface. * `system` contains examples which demonstrate some internal chip features, or debugging & development tools. * `wifi` contains examples of advanced Wi-Fi features. (For network protocol examples, see `protocols` instead.) +* `build_system` contains examples of build system features # Using Examples diff --git a/examples/build_system/cmake/idf_as_lib/CMakeLists.txt b/examples/build_system/cmake/idf_as_lib/CMakeLists.txt new file mode 100644 index 000000000..ba0176f1d --- /dev/null +++ b/examples/build_system/cmake/idf_as_lib/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.5) +project(idf_as_lib C) + +# The source file main.c contains app_main() definition +add_executable(${CMAKE_PROJECT_NAME}.elf main.c) + +# Provides idf_import_components() and idf_link_components() +include($ENV{IDF_PATH}/tools/cmake/idf_functions.cmake) + +# Create artifacts used for flashing the project to target chip +set(IDF_BUILD_ARTIFACTS ON) +set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf) +set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR}) + +# Trim down components included in the build. Although freertos and spi_flash are the ones needed by the application +# itself, the bootloader and esptool_py components are also needed in order to create the artifacts to be used +# for flashing to the target chip +set(IDF_COMPONENTS freertos spi_flash bootloader esptool_py) + +# Wraps add_subdirectory() to create library targets for components, and then return them using the specified variable +idf_import_components(components $ENV{IDF_PATH} esp-idf) + +# Wraps target_link_libraries() to link processed components by idf_import_components to target +idf_link_components(${CMAKE_PROJECT_NAME}.elf "${components}") \ No newline at end of file diff --git a/examples/build_system/cmake/idf_as_lib/README.md b/examples/build_system/cmake/idf_as_lib/README.md new file mode 100644 index 000000000..19506a8fa --- /dev/null +++ b/examples/build_system/cmake/idf_as_lib/README.md @@ -0,0 +1,69 @@ +# Using ESP-IDF in Custom CMake Projects + +This example illustrates using ESP-IDF components as libraries in custom CMake projects. This builds +an equivalent application to the `hello_world` example under `examples/get-started/hello_world`. + +## Example Flow + +Users looking at this example should focus on the [top-level CMakeLists.txt file](./CMakeLists.txt). This builds an +application that can run on targets without relying on the typical ESP-IDF application template. The application itself +follows a similar code flow to the aforementioned `hello_world` example. + +### Output + +``` +Hello world! +This is ESP32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 0, 4MB external flash +Restarting in 10 seconds... +Restarting in 9 seconds... +Restarting in 8 seconds... +Restarting in 7 seconds... +Restarting in 6 seconds... +Restarting in 5 seconds... +Restarting in 4 seconds... +Restarting in 3 seconds... +Restarting in 2 seconds... +Restarting in 1 seconds... +Restarting in 0 seconds... +``` + +## Building this Example + +To build this example, run the following commands from this directory: + +```bash +# Create a build directory, and change location to that directory. +mkdir build; cd build +# Invoke CMake, specifying the top-level CMakeLists.txt directory and toolchain file to use. This will generate +# the build system files. +cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DIDF_TARGET=esp32 +# Build using the generated build system files. +cmake --build . +``` + +Or, execute `build.sh` script, which contains the same commands mentioned above. + +## Flashing and Running this Example + +To flash this example, we will have to invoke `esptool.py` and `idf_monitor.py` manually. While still in the build directory: + +### Flashing to target + +```bash +# Write project binaries to flash. +esptool.py --port /dev/ttyUSB0 write_flash @flash_project_args +``` + +### Running on target + +```bash +# Monitor the output of the flashed firmware. +idf_monitor.py --port /dev/ttyUSB0 idf_as_lib.elf +``` + +Of course, you should replace the specified ports in the commands specified above to the proper one where your device +is connected. + +--- + +There is a discussion on using ESP-IDF in custom CMake projects in the programming guide under `API Guides` -> `Build System (CMake)` -> `Using ESP-IDF in Custom CMake Projects` diff --git a/examples/build_system/cmake/idf_as_lib/build.sh b/examples/build_system/cmake/idf_as_lib/build.sh new file mode 100755 index 000000000..23de02c83 --- /dev/null +++ b/examples/build_system/cmake/idf_as_lib/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# +# Build this example, which does not use that standard IDF app template. See README.md for +# more information about the build and how to run this example on the target once built. + +mkdir build; cd build +cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DIDF_TARGET=esp32 +cmake --build . \ No newline at end of file diff --git a/examples/build_system/cmake/idf_as_lib/main.c b/examples/build_system/cmake/idf_as_lib/main.c new file mode 100644 index 000000000..59f0aa0f5 --- /dev/null +++ b/examples/build_system/cmake/idf_as_lib/main.c @@ -0,0 +1,39 @@ +/* Hello World Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "esp_spi_flash.h" + +void app_main() +{ + printf("Hello world!\n"); + + /* Print chip information */ + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ", + chip_info.cores, + (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); + + printf("silicon revision %d, ", chip_info.revision); + + printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); + + for (int i = 10; i >= 0; i--) { + printf("Restarting in %d seconds...\n", i); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + printf("Restarting now.\n"); + fflush(stdout); + esp_restart(); +} diff --git a/examples/build_system/cmake/import_lib/CMakeLists.txt b/examples/build_system/cmake/import_lib/CMakeLists.txt new file mode 100644 index 000000000..e145bd43a --- /dev/null +++ b/examples/build_system/cmake/import_lib/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following 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) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(import_cmake_lib) diff --git a/examples/build_system/cmake/import_lib/README.md b/examples/build_system/cmake/import_lib/README.md new file mode 100644 index 000000000..e24090a87 --- /dev/null +++ b/examples/build_system/cmake/import_lib/README.md @@ -0,0 +1,36 @@ +# Import Third-Party CMake Library Example + +This example demonstrates how to import third-party CMake libraries. + +## Example Flow + +[tinyxml2](https://github.com/leethomason/tinyxml2) is a +a small C++ XML parser. It is imported, without modification, for use in the project's `main` component (see the `main` component's [CMakeLists.txt](main/CMakeLists.txt)). To demonstrate the library being used, a sample XML is embedded into the project. +This sample XML is then read and parsed later on using `tinyxml2`. + +### Output + +``` +I (317) example: Setting up... +I (317) example: Copying sample XML to filesystem... +I (647) example: Reading XML file +I (657) example: Read XML data: + + + Tove + Jani + Reminder + Don't forget me this weekend! + + +I (667) example: Parsed XML data: + +To: Tove +From: Jani +Heading: Reminder +Body: Don't forget me this weekend! +I (677) example: Example end +``` +--- + +There is a discussion on importing third-party CMake libraries in the programming guide under `API Guides` -> `Build System (CMake)` -> `Using Third-Party CMake Projects with Components` diff --git a/examples/build_system/cmake/import_lib/main/CMakeLists.txt b/examples/build_system/cmake/import_lib/main/CMakeLists.txt new file mode 100644 index 000000000..92d44e324 --- /dev/null +++ b/examples/build_system/cmake/import_lib/main/CMakeLists.txt @@ -0,0 +1,21 @@ +set(COMPONENT_SRCS "main.cpp") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +set(COMPONENT_EMBED_TXTFILES "sample.xml") + +register_component() + +# Build static library, do not build test executables +option(BUILD_SHARED_LIBS OFF) +option(BUILD_TESTING OFF) + +# Import tinyxml2 targets +add_subdirectory(lib/tinyxml2) + +# Propagate compile settings to tinyxml2 +target_include_directories(tinyxml2 PRIVATE ${IDF_INCLUDE_DIRECTORIES}) +target_compile_options(tinyxml2 PRIVATE "${IDF_COMPILE_OPTIONS}") +target_compile_options(tinyxml2 PRIVATE "${IDF_CXX_COMPILE_OPTIONS}") + +# Link tinyxml2 to main component +target_link_libraries(${COMPONENT_TARGET} tinyxml2) diff --git a/examples/build_system/cmake/import_lib/main/lib/tinyxml2 b/examples/build_system/cmake/import_lib/main/lib/tinyxml2 new file mode 160000 index 000000000..7e8e24999 --- /dev/null +++ b/examples/build_system/cmake/import_lib/main/lib/tinyxml2 @@ -0,0 +1 @@ +Subproject commit 7e8e249990ec491ec15990cf95b6d871a66cf64a diff --git a/examples/build_system/cmake/import_lib/main/main.cpp b/examples/build_system/cmake/import_lib/main/main.cpp new file mode 100644 index 000000000..6df76dcaf --- /dev/null +++ b/examples/build_system/cmake/import_lib/main/main.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include "esp_err.h" +#include "esp_log.h" +#include "esp_vfs_fat.h" +#include "lib/tinyxml2/tinyxml2.h" + +using namespace tinyxml2; + +static const char *TAG = "example"; + +// Handle of the wear levelling library instance +static wl_handle_t s_wl_handle = WL_INVALID_HANDLE; + +// Mount path for the partition +const char *base_path = "/spiflash"; + +extern "C" void app_main(void) +{ + // Do example setup + ESP_LOGI(TAG, "Setting up..."); + esp_vfs_fat_mount_config_t mount_config; + mount_config.max_files = 4; + mount_config.format_if_mount_failed = true; + mount_config.allocation_unit_size = CONFIG_WL_SECTOR_SIZE; + + esp_err_t err = esp_vfs_fat_spiflash_mount(base_path, "storage", &mount_config, &s_wl_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); + return; + } + + // The sample XML is embedded binary data. Create a file first containing the embedded + // so it can be accessed. + ESP_LOGI(TAG, "Copying sample XML to filesystem..."); + + extern const char data_start[] asm("_binary_sample_xml_start"); + extern const char data_end[] asm("_binary_sample_xml_end"); + FILE *f = fopen("/spiflash/sample.xml", "wb"); + + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for writing"); + return; + } + fwrite(data_start, sizeof(char), data_end - data_start + 1, f); + fclose(f); + + // Now that the file is created, load it using tinyxml2 and parse + ESP_LOGI(TAG, "Reading XML file"); + + XMLDocument data; + data.LoadFile("/spiflash/sample.xml"); + + XMLPrinter printer; + data.Print(&printer); + + ESP_LOGI(TAG, "Read XML data:\n%s", printer.CStr()); + + const char* to_data = data.FirstChildElement("note")->FirstChildElement("to")->GetText(); + const char* from_data = data.FirstChildElement("note")->FirstChildElement("from")->GetText(); + const char* heading_data = data.FirstChildElement("note")->FirstChildElement("heading")->GetText(); + const char* body_data = data.FirstChildElement("note")->FirstChildElement("body")->GetText(); + + ESP_LOGI(TAG, "Parsed XML data:\n\nTo: %s\nFrom: %s\nHeading: %s\nBody: %s", + to_data, from_data, heading_data, body_data); + + ESP_LOGI(TAG, "Example end"); +} \ No newline at end of file diff --git a/examples/build_system/cmake/import_lib/main/sample.xml b/examples/build_system/cmake/import_lib/main/sample.xml new file mode 100644 index 000000000..fa0c0a5b6 --- /dev/null +++ b/examples/build_system/cmake/import_lib/main/sample.xml @@ -0,0 +1,7 @@ + + + Tove + Jani + Reminder + Don't forget me this weekend! + \ No newline at end of file diff --git a/examples/build_system/cmake/import_lib/partitions_example.csv b/examples/build_system/cmake/import_lib/partitions_example.csv new file mode 100644 index 000000000..3e9543311 --- /dev/null +++ b/examples/build_system/cmake/import_lib/partitions_example.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +storage, data, fat, , 528K, diff --git a/examples/build_system/cmake/import_lib/sdkconfig.defaults b/examples/build_system/cmake/import_lib/sdkconfig.defaults new file mode 100644 index 000000000..f30f322c6 --- /dev/null +++ b/examples/build_system/cmake/import_lib/sdkconfig.defaults @@ -0,0 +1,5 @@ +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" +CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 +CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" +CONFIG_APP_OFFSET=0x10000 diff --git a/examples/get-started/hello_world/CMakeLists.txt b/examples/get-started/hello_world/CMakeLists.txt index 8a022b848..519e5a1d7 100644 --- a/examples/get-started/hello_world/CMakeLists.txt +++ b/examples/get-started/hello_world/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(hello-world) +project(hello-world) \ No newline at end of file diff --git a/examples/system/ota/native_ota_example/main/CMakeLists.txt b/examples/system/ota/native_ota_example/main/CMakeLists.txt index a700e0b3b..fa4644e45 100644 --- a/examples/system/ota/native_ota_example/main/CMakeLists.txt +++ b/examples/system/ota/native_ota_example/main/CMakeLists.txt @@ -2,6 +2,6 @@ set(COMPONENT_SRCS "native_ota_example.c") set(COMPONENT_ADD_INCLUDEDIRS ".") # Embed the server root certificate into the final binary -set(COMPONENT_EMBED_TXTFILES ${PROJECT_PATH}/server_certs/ca_cert.pem) +set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem) register_component() diff --git a/examples/system/ota/simple_ota_example/main/CMakeLists.txt b/examples/system/ota/simple_ota_example/main/CMakeLists.txt index 8adb69a8f..98a7208f8 100644 --- a/examples/system/ota/simple_ota_example/main/CMakeLists.txt +++ b/examples/system/ota/simple_ota_example/main/CMakeLists.txt @@ -3,6 +3,6 @@ set(COMPONENT_ADD_INCLUDEDIRS ".") # Embed the server root certificate into the final binary -set(COMPONENT_EMBED_TXTFILES ${PROJECT_PATH}/server_certs/ca_cert.pem) +set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem) register_component() From f1f0bd4b1c4efde5ea2447db3ebf4c3e7c15ff73 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Wed, 7 Nov 2018 15:19:56 +0800 Subject: [PATCH 4/5] ci: update for running cmake examples --- .flake8 | 1 + tools/ci/build_examples.sh | 11 ++++---- tools/ci/build_examples_cmake.sh | 9 +++++-- tools/ci/check_examples_cmake_make.sh | 4 +-- tools/ci/executable-list.txt | 3 ++- tools/ci/mirror-list.txt | 39 ++++++++++++++------------- tools/ci/test_build_system_cmake.sh | 19 ++++++------- 7 files changed, 48 insertions(+), 38 deletions(-) diff --git a/.flake8 b/.flake8 index db94eed6f..be4d0fd62 100644 --- a/.flake8 +++ b/.flake8 @@ -33,6 +33,7 @@ exclude = components/mbedtls/mbedtls, components/expat/expat, components/unity/unity, + examples/build_system/cmake/import_lib/main/lib/tinyxml2 # temporary list (should be empty) components/app_update/dump_otadata.py, components/app_update/gen_empty_partition.py, diff --git a/tools/ci/build_examples.sh b/tools/ci/build_examples.sh index b17e5625e..9ab8fee57 100755 --- a/tools/ci/build_examples.sh +++ b/tools/ci/build_examples.sh @@ -62,6 +62,8 @@ RESULT_ISSUES=22 # magic number result code for issues found LOG_SUSPECTED=${LOG_PATH}/common_log.txt touch ${LOG_SUSPECTED} +EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name Makefile | grep -v "/build_system/cmake/" | sort ) + if [ $# -eq 0 ] then START_NUM=0 @@ -84,7 +86,7 @@ else [ -z ${NUM_OF_JOBS} ] && die "NUM_OF_JOBS is bad" # count number of examples - NUM_OF_EXAMPLES=$( find ${IDF_PATH}/examples/ -type f -name Makefile | wc -l ) + NUM_OF_EXAMPLES=$( echo "${EXAMPLE_PATHS}" | wc -l ) [ -z ${NUM_OF_EXAMPLES} ] && die "NUM_OF_EXAMPLES is bad" # separate intervals @@ -155,17 +157,16 @@ build_example () { EXAMPLE_NUM=0 -find ${IDF_PATH}/examples -type f -name Makefile | sort | \ -while read FN +for EXAMPLE_PATH in ${EXAMPLE_PATHS} do if [[ $EXAMPLE_NUM -lt $START_NUM || $EXAMPLE_NUM -ge $END_NUM ]] then EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 )) continue fi - echo ">>> example [ ${EXAMPLE_NUM} ] - $FN" + echo ">>> example [ ${EXAMPLE_NUM} ] - $EXAMPLE_PATH" - build_example "${EXAMPLE_NUM}" "${FN}" + build_example "${EXAMPLE_NUM}" "${EXAMPLE_PATH}" EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 )) done diff --git a/tools/ci/build_examples_cmake.sh b/tools/ci/build_examples_cmake.sh index 50ce7f1e6..868621981 100755 --- a/tools/ci/build_examples_cmake.sh +++ b/tools/ci/build_examples_cmake.sh @@ -126,8 +126,13 @@ build_example () { local BUILDLOG=${LOG_PATH}/ex_${ID}_log.txt touch ${BUILDLOG} - idf.py fullclean >>${BUILDLOG} 2>&1 && - idf.py build >>${BUILDLOG} 2>&1 && + if [ "$EXAMPLE_NAME" != "idf_as_lib" ]; then + idf.py fullclean >>${BUILDLOG} 2>&1 && + idf.py build >>${BUILDLOG} 2>&1 + else + rm -rf build sdkconfig && + ./build.sh >>${BUILDLOG} 2>&1 + fi && cp build/flash_project_args build/download.config || # backwards compatible download.config filename { RESULT=$?; FAILED_EXAMPLES+=" ${EXAMPLE_NAME}" ; diff --git a/tools/ci/check_examples_cmake_make.sh b/tools/ci/check_examples_cmake_make.sh index 28b5a5b24..64463ab21 100755 --- a/tools/ci/check_examples_cmake_make.sh +++ b/tools/ci/check_examples_cmake_make.sh @@ -2,8 +2,8 @@ # While we support GNU Make & CMake together, check the same examples are present for both -CMAKE_EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/main/") -MAKE_EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name Makefile ) +CMAKE_EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/main/" | grep -v "/build_system/cmake/") +MAKE_EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name Makefile | grep -v "/build_system/cmake/") CMAKE_EXAMPLE_PATHS="$(/usr/bin/dirname $CMAKE_EXAMPLE_PATHS | sort -n)" MAKE_EXAMPLE_PATHS="$(/usr/bin/dirname $MAKE_EXAMPLE_PATHS | sort -n)" diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 65f765fe2..6c3756fe6 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -66,4 +66,5 @@ components/espcoredump/test/test_espcoredump.py components/espcoredump/test/test_espcoredump.sh tools/ldgen/ldgen.py tools/ldgen/test/test_fragments.py -tools/ldgen/test/test_generation.py \ No newline at end of file +tools/ldgen/test/test_generation.py +examples/build_system/cmake/idf_as_lib/build.sh diff --git a/tools/ci/mirror-list.txt b/tools/ci/mirror-list.txt index 6c55df173..9b9ac550a 100644 --- a/tools/ci/mirror-list.txt +++ b/tools/ci/mirror-list.txt @@ -1,19 +1,20 @@ -components/esp32/lib @GENERAL_MIRROR_SERVER@/idf/esp32-wifi-lib.git -components/bt/lib @GENERAL_MIRROR_SERVER@/idf/esp32-bt-lib.git -components/aws_iot/aws-iot-device-sdk-embedded-C @GENERAL_MIRROR_SERVER@/idf/aws-iot-device-sdk-embedded-C.git ALLOW_TO_SYNC_FROM_PUBLIC -components/coap/libcoap @GENERAL_MIRROR_SERVER@/idf/libcoap.git ALLOW_TO_SYNC_FROM_PUBLIC -components/esptool_py/esptool @GENERAL_MIRROR_SERVER@/idf/esptool.git ALLOW_TO_SYNC_FROM_PUBLIC -components/json/cJSON @GENERAL_MIRROR_SERVER@/idf/cJSON.git ALLOW_TO_SYNC_FROM_PUBLIC -components/libsodium/libsodium @GENERAL_MIRROR_SERVER@/idf/libsodium.git ALLOW_TO_SYNC_FROM_PUBLIC -components/mbedtls/mbedtls @GENERAL_MIRROR_SERVER@/idf/mbedtls.git ALLOW_TO_SYNC_FROM_PUBLIC -components/expat/expat @GENERAL_MIRROR_SERVER@/idf/libexpat.git ALLOW_TO_SYNC_FROM_PUBLIC -components/micro-ecc/micro-ecc @GENERAL_MIRROR_SERVER@/idf/micro-ecc.git ALLOW_TO_SYNC_FROM_PUBLIC -components/nghttp/nghttp2 @GENERAL_MIRROR_SERVER@/idf/nghttp2.git ALLOW_TO_SYNC_FROM_PUBLIC -components/spiffs/spiffs @GENERAL_MIRROR_SERVER@/idf/spiffs.git ALLOW_TO_SYNC_FROM_PUBLIC -components/asio/asio @GENERAL_MIRROR_SERVER@/idf/asio.git -components/lwip/lwip @GENERAL_MIRROR_SERVER@/idf/esp-lwip.git -third-party/mruby @GENERAL_MIRROR_SERVER@/idf/mruby.git ALLOW_TO_SYNC_FROM_PUBLIC -third-party/neverbleed @GENERAL_MIRROR_SERVER@/idf/neverbleed.git ALLOW_TO_SYNC_FROM_PUBLIC -components/mqtt/esp-mqtt @GENERAL_MIRROR_SERVER@/idf/esp-mqtt.git ALLOW_TO_SYNC_FROM_PUBLIC -components/protobuf-c/protobuf-c @GENERAL_MIRROR_SERVER@/idf/protobuf-c.git ALLOW_TO_SYNC_FROM_PUBLIC -components/unity/unity @GENERAL_MIRROR_SERVER@/idf/Unity.git ALLOW_TO_SYNC_FROM_PUBLIC \ No newline at end of file +components/esp32/lib @GENERAL_MIRROR_SERVER@/idf/esp32-wifi-lib.git +components/bt/lib @GENERAL_MIRROR_SERVER@/idf/esp32-bt-lib.git +components/aws_iot/aws-iot-device-sdk-embedded-C @GENERAL_MIRROR_SERVER@/idf/aws-iot-device-sdk-embedded-C.git ALLOW_TO_SYNC_FROM_PUBLIC +components/coap/libcoap @GENERAL_MIRROR_SERVER@/idf/libcoap.git ALLOW_TO_SYNC_FROM_PUBLIC +components/esptool_py/esptool @GENERAL_MIRROR_SERVER@/idf/esptool.git ALLOW_TO_SYNC_FROM_PUBLIC +components/json/cJSON @GENERAL_MIRROR_SERVER@/idf/cJSON.git ALLOW_TO_SYNC_FROM_PUBLIC +components/libsodium/libsodium @GENERAL_MIRROR_SERVER@/idf/libsodium.git ALLOW_TO_SYNC_FROM_PUBLIC +components/mbedtls/mbedtls @GENERAL_MIRROR_SERVER@/idf/mbedtls.git ALLOW_TO_SYNC_FROM_PUBLIC +components/expat/expat @GENERAL_MIRROR_SERVER@/idf/libexpat.git ALLOW_TO_SYNC_FROM_PUBLIC +components/micro-ecc/micro-ecc @GENERAL_MIRROR_SERVER@/idf/micro-ecc.git ALLOW_TO_SYNC_FROM_PUBLIC +components/nghttp/nghttp2 @GENERAL_MIRROR_SERVER@/idf/nghttp2.git ALLOW_TO_SYNC_FROM_PUBLIC +components/spiffs/spiffs @GENERAL_MIRROR_SERVER@/idf/spiffs.git ALLOW_TO_SYNC_FROM_PUBLIC +components/asio/asio @GENERAL_MIRROR_SERVER@/idf/asio.git +components/lwip/lwip @GENERAL_MIRROR_SERVER@/idf/esp-lwip.git +third-party/mruby @GENERAL_MIRROR_SERVER@/idf/mruby.git ALLOW_TO_SYNC_FROM_PUBLIC +third-party/neverbleed @GENERAL_MIRROR_SERVER@/idf/neverbleed.git ALLOW_TO_SYNC_FROM_PUBLIC +components/mqtt/esp-mqtt @GENERAL_MIRROR_SERVER@/idf/esp-mqtt.git ALLOW_TO_SYNC_FROM_PUBLIC +components/protobuf-c/protobuf-c @GENERAL_MIRROR_SERVER@/idf/protobuf-c.git ALLOW_TO_SYNC_FROM_PUBLIC +components/unity/unity @GENERAL_MIRROR_SERVER@/idf/Unity.git ALLOW_TO_SYNC_FROM_PUBLIC +examples/build_system/cmake/import_lib/main/lib/tinyxml2 @GENERAL_MIRROR_SERVER@/idf/tinyxml2.git ALLOW_TO_SYNC_FROM_PUBLIC diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index 1e38e1890..1a73c16e6 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -58,6 +58,7 @@ function run_tests() BOOTLOADER_BINS="bootloader/bootloader.elf bootloader/bootloader.bin" APP_BINS="app-template.elf app-template.bin" PARTITION_BIN="partition_table/partition-table.bin" + IDF_COMPONENT_PREFIX="idf_component" print_status "Initial clean build" # if build fails here, everything fails @@ -71,14 +72,14 @@ function run_tests() take_build_snapshot touch ${IDF_PATH}/components/esp32/cpu_start.c idf.py build || failure "Failed to partial build" - assert_rebuilt ${APP_BINS} esp32/libesp32.a esp32/CMakeFiles/esp32.dir/cpu_start.c.obj - assert_not_rebuilt lwip/liblwip.a freertos/libfreertos.a ${BOOTLOADER_BINS} ${PARTITION_BIN} + assert_rebuilt ${APP_BINS} esp-idf/esp32/libesp32.a esp-idf/esp32/CMakeFiles/${IDF_COMPONENT_PREFIX}_esp32.dir/cpu_start.c.obj + assert_not_rebuilt esp-idf/lwip/liblwip.a esp-idf/freertos/libfreertos.a ${BOOTLOADER_BINS} ${PARTITION_BIN} print_status "Bootloader source file rebuilds bootloader" take_build_snapshot touch ${IDF_PATH}/components/bootloader/subproject/main/bootloader_start.c idf.py build || failure "Failed to partial build bootloader" - assert_rebuilt ${BOOTLOADER_BINS} bootloader/main/CMakeFiles/main.dir/bootloader_start.c.obj + assert_rebuilt ${BOOTLOADER_BINS} bootloader/esp-idf/main/CMakeFiles/${IDF_COMPONENT_PREFIX}_main.dir/bootloader_start.c.obj assert_not_rebuilt ${APP_BINS} ${PARTITION_BIN} print_status "Partition CSV file rebuilds partitions" @@ -172,9 +173,9 @@ function run_tests() assert_rebuilt config/sdkconfig.h # pick one each of .c, .cpp, .S that #includes sdkconfig.h # and therefore should rebuild - assert_rebuilt newlib/CMakeFiles/newlib.dir/syscall_table.c.obj - assert_rebuilt nvs_flash/CMakeFiles/nvs_flash.dir/src/nvs_api.cpp.obj - assert_rebuilt freertos/CMakeFiles/freertos.dir/xtensa_vectors.S.obj + assert_rebuilt esp-idf/newlib/CMakeFiles/${IDF_COMPONENT_PREFIX}_newlib.dir/syscall_table.c.obj + assert_rebuilt esp-idf/nvs_flash/CMakeFiles/${IDF_COMPONENT_PREFIX}_nvs_flash.dir/src/nvs_api.cpp.obj + assert_rebuilt esp-idf/freertos/CMakeFiles/${IDF_COMPONENT_PREFIX}_freertos.dir/xtensa_vectors.S.obj print_status "Updating project CMakeLists.txt triggers full recompile" clean_build_dir @@ -186,9 +187,9 @@ function run_tests() idf.py build || failure "Build failed" mv CMakeLists.bak CMakeLists.txt # similar to previous test - assert_rebuilt newlib/CMakeFiles/newlib.dir/syscall_table.c.obj - assert_rebuilt nvs_flash/CMakeFiles/nvs_flash.dir/src/nvs_api.cpp.obj - assert_rebuilt freertos/CMakeFiles/freertos.dir/xtensa_vectors.S.obj + assert_rebuilt esp-idf/newlib/CMakeFiles/${IDF_COMPONENT_PREFIX}_newlib.dir/syscall_table.c.obj + assert_rebuilt esp-idf/nvs_flash/CMakeFiles/${IDF_COMPONENT_PREFIX}_nvs_flash.dir/src/nvs_api.cpp.obj + assert_rebuilt esp-idf/freertos/CMakeFiles/${IDF_COMPONENT_PREFIX}_freertos.dir/xtensa_vectors.S.obj print_status "Can build with Ninja (no idf.py)" clean_build_dir From 7e7cc99241b2b1ae90cd992c0822086410e0fc06 Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Tue, 23 Oct 2018 09:12:06 +0800 Subject: [PATCH 5/5] docs: generic cmake support --- docs/en/api-guides/build-system-cmake.rst | 95 ++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/docs/en/api-guides/build-system-cmake.rst b/docs/en/api-guides/build-system-cmake.rst index 3cd1465e8..80204f69f 100644 --- a/docs/en/api-guides/build-system-cmake.rst +++ b/docs/en/api-guides/build-system-cmake.rst @@ -313,6 +313,7 @@ The following component-specific variables are available for use inside componen - ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``component.mk``. The component path cannot contain spaces. This is the same as the ``CMAKE_CURRENT_SOURCE_DIR`` variable. - ``COMPONENT_NAME``: Name of the component. Same as the name of the component directory. +- ``COMPONENT_TARGET``: Name of the library target created internally by the build system for the component. The following variables are set at the project level, but available for use in component CMakeLists: @@ -637,7 +638,7 @@ file called graphics_lib.c:: VERBATIM) add_custom_target(logo DEPENDS logo.h) - add_dependencies(${COMPONENT_NAME} logo) + add_dependencies(${COMPONENT_TARGET} logo) set_property(DIRECTORY "${COMPONENT_PATH}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES logo.h) @@ -652,7 +653,7 @@ it is added to the `ADDITIONAL_MAKE_CLEAN_FILES`_ property. .. note:: - If generating files as part of the project CMakeLists.txt file, not a component CMakeLists.txt, then use ``${PROJECT_PATH}`` instead of ``${COMPONENT_PATH}`` and ``${PROJECT_NAME}.elf`` instead of ``${COMPONENT_NAME}``.) + If generating files as part of the project CMakeLists.txt file, not a component CMakeLists.txt, then use ``${PROJECT_PATH}`` instead of ``${COMPONENT_PATH}`` and ``${PROJECT_NAME}.elf`` instead of ``${COMPONENT_TARGET}``.) If a a source file from another component included ``logo.h``, then ``add_dependencies`` would need to be called to add a dependency between the two components, to ensure that the component source files were always compiled in the correct order. @@ -838,6 +839,96 @@ Here is an example minimal "pure CMake" component CMakeLists file for a componen - This file is quite simple as there are not a lot of source files. For components with a large number of files, the globbing behaviour of ESP-IDF's component logic can make the component CMakeLists style simpler.) - Any time a component adds a library target with the component name, the ESP-IDF build system will automatically add this to the build, expose public include directories, etc. If a component wants to add a library target with a different name, dependencies will need to be added manually via CMake commands. + +Using Third-Party CMake Projects with Components +================================================ + +CMake is used for a lot of open-source C and C++ projects — code that users can tap into for their applications. One of the benefits of having a CMake build system +is the ability to import these third-party projects, sometimes even without modification! This allows for users to be able to get functionality that may +not yet be provided by a component, or use another library for the same functionality. + +.. highlight:: cmake + +Importing a library might look like this for a hypothetical library ``foo`` to be used in the ``main`` component:: + + # Register the component + register_component() + + # Set values of hypothetical variables that control the build of `foo` + set(FOO_BUILD_STATIC OFF) + set(FOO_BUILD_TESTS OFF) + + # Create and import the library targets + add_subdirectory(foo) + + # Propagate IDF-wide compile settings/definitions/options to `foo` + target_include_directories(foo ${IDF_INCLUDE_DIRECTORIES}) + target_compile_options(foo ${IDF_COMPILE_OPTIONS}) + target_compile_definitions(foo ${IDF_COMPILE_DEFINITIONS}) + + # Link `foo` to `main` component + target_link_libraries(main foo) + +For an actual example, take a look at :example:`build_system/cmake/import_lib`. Take note that what needs to be done in order to import +the library may vary. It is recommended to read up on the library's documentation for instructions on how to +import it from other projects. Studying the library's CMakeLists.txt and build structure can also be helpful. + +It is also possible to wrap a third-party library to be used as a component in this manner. For example, the :component:`mbedtls` component is a wrapper for +Espressif's fork of `mbedtls `_. See its :component_file:`component CMakeLists.txt `. + +Using ESP-IDF in Custom CMake Projects +====================================== + +ESP-IDF provides a template CMake project for easily creating an application. However, in some instances the user might already +have an existing CMake project or may want to create one. In these cases it is desirable to be able to consume IDF components +as libraries to be linked to the user's targets (libraries/ executables). + +.. highlight:: cmake + +It is possible to do so by using functions ``idf_import_components`` +and ``idf_link_components`` provided provided by :idf_file:`tools/cmake/idf_functions.cmake`. For example:: + + cmake_minimum_required(VERSION 3.5) + project(my_custom_app C) + + # The source file main.c contains app_main() definition + add_executable(${CMAKE_PROJECT_NAME}.elf main.c) + + # Provides idf_import_components and idf_link_components + include($ENV{IDF_PATH}/tools/cmake/idf_functions.cmake) + + # Do some configuration for idf_import_components. This enables creation of artifacts (which might not be + # needed) for some projects + set(IDF_BUILD_ARTIFACTS ON) + set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf) + set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR}) + + # Wraps add_subdirectory() to create library targets for components, and then `return` them using the given variable. + # In this case the variable is named `component` + idf_import_components(components $ENV{IDF_PATH} esp-idf) + + # Wraps target_link_libraries() to link processed components by idf_import_components to target + idf_link_components(${CMAKE_PROJECT_NAME}.elf "${components}") + + +The snippet above includes all of the components in the ESP-IDF directory and uses KConfig defaults. +It also builds artifacts (partition table, project information json files, bootloader, etc.). There are also other build +parameters which can be set, the full list of which is as follows: + +- ``IDF_BUILD_ARTIFACTS``: Build artifacts such as bootloader, partition table binary file, partition binaries, project information json typically needed for flashing binaries to the target chip. Requires ``IDF_PROJECT_EXECUTABLE`` and ``IDF_BUILD_ARTIFACTS_DIR`` to be set as well. +- ``IDF_PROJECT_EXECUTABLE``: Name of the final executable file. This parameter is needed for creating some of the artifacts. +- ``IDF_BUILD_ARTIFACTS_DIR``: Location where created artifacts are to be placed. +- ``IDF_EXTRA_COMPONENTS_DIR``: Locations to search for components in aside from the :idf:`default components directory ` +- ``IDF_COMPONENTS``: A list of components to import. Use this to trim down the imported components to only what is needed for faster builds. If not set, all components found from the default components directory as well as ``IDF_EXTRA_COMPONENTS_DIR`` (if specified) are imported. Note that dependencies of components in this list (other than ``IDF_COMPONENT_REQUIRES_COMMON``) will also get pulled into the build. +- ``IDF_COMPONENT_REQUIRES_COMMON``: List of components that every component requires. Components in this list (and their dependencies) are imported regardless of the value of ``IDF_COMPONENTS``. By default, this variable is set to the minimal set of core "system" components. +- ``IDF_SDKCONFIG_DEFAULTS``: Path to the configuration override file. If unset, components are built with default configurations. +- ``IDF_BUILD_TESTS``: Include component tests in the build. By default, all component tests are included. The component tests are filtered using ``IDF_TEST_COMPONENTS`` and ``IDF_TEST_EXCLUDE_COMPONENTS``. +- ``IDF_TEST_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, only component tests in this list will be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set. +- ``IDF_TEST_EXCLUDE_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, component tests in this list will not be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set. This variable takes precedence over ``IDF_TEST_COMPONENTS``. This means that a component test in this list will not be included in the build even if it is also present in ``IDF_TEST_COMPONENTS``. + +The example in :example:`build_system/cmake/idf_as_lib` demonstrates the creation of an application equivalent to :example:`hello world application ` +using a custom CMake project. + .. _cmake-file-globbing: File Globbing & Incremental Builds