From 688542197656bb57eead6b330638ec0bd54279a4 Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Tue, 21 Jul 2020 16:00:05 +0800 Subject: [PATCH] CI: add size info for binaries --- .../esp_rom/include/esp32/rom/secure_boot.h | 2 +- .../get-started/hello_world/example_test.py | 22 +++ .../hello_world/main/hello_world_main.c | 2 +- examples/peripherals/gpio/example_test.py | 22 +++ .../peripherals/gpio/main/gpio_example_main.c | 2 + tools/build_apps.py | 7 + tools/ci/build_examples.sh | 105 ----------- tools/ci/build_test_apps.sh | 100 ---------- tools/ci/build_unit_test.sh | 108 ----------- tools/ci/config/build.yml | 48 +++-- tools/ci/config/target-test.yml | 2 +- tools/ci/executable-list.txt | 5 +- tools/ci/find_apps_build_apps.sh | 172 ++++++++++++++++++ tools/ci/python_packages/ttfw_idf/__init__.py | 20 ++ tools/find_build_apps/cmake.py | 14 +- tools/find_build_apps/common.py | 72 ++++++-- tools/find_build_apps/make.py | 2 + .../system/panic/main/test_panic_main.c | 40 ++-- tools/unit-test-app/tools/UnitTestParser.py | 41 ++--- 19 files changed, 387 insertions(+), 399 deletions(-) create mode 100644 examples/get-started/hello_world/example_test.py create mode 100644 examples/peripherals/gpio/example_test.py delete mode 100755 tools/ci/build_examples.sh delete mode 100755 tools/ci/build_test_apps.sh delete mode 100755 tools/ci/build_unit_test.sh create mode 100755 tools/ci/find_apps_build_apps.sh diff --git a/components/esp_rom/include/esp32/rom/secure_boot.h b/components/esp_rom/include/esp32/rom/secure_boot.h index 04ffec0a2c..1ec326ca0b 100644 --- a/components/esp_rom/include/esp32/rom/secure_boot.h +++ b/components/esp_rom/include/esp32/rom/secure_boot.h @@ -107,7 +107,7 @@ void ets_secure_boot_verify_boot_bootloader(void); * @return true if is Secure boot v2 has been enabled * False if Secure boot v2 has not been enabled. */ -bool ets_use_secure_boot_v2(); +bool ets_use_secure_boot_v2(void); #endif /* CONFIG_ESP32_REV_MIN_3 */ diff --git a/examples/get-started/hello_world/example_test.py b/examples/get-started/hello_world/example_test.py new file mode 100644 index 0000000000..116fa402f6 --- /dev/null +++ b/examples/get-started/hello_world/example_test.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import ttfw_idf + + +@ttfw_idf.idf_example_test(env_tag="Example_GENERIC", target=['esp32', 'esp32s2'], ci_target=['esp32']) +def test_examples_hello_world(env, extra_data): + app_name = 'hello_world' + dut = env.get_dut(app_name, "examples/get-started/hello_world") + dut.start_app() + res = dut.expect(ttfw_idf.MINIMUM_FREE_HEAP_SIZE_RE) + if not res: + raise ValueError('Maximum heap size info not found') + ttfw_idf.print_heap_size(app_name, dut.app.config_name, dut.TARGET, res[0]) + + +if __name__ == '__main__': + test_examples_hello_world() diff --git a/examples/get-started/hello_world/main/hello_world_main.c b/examples/get-started/hello_world/main/hello_world_main.c index 1bbb227906..53ed3bf5de 100644 --- a/examples/get-started/hello_world/main/hello_world_main.c +++ b/examples/get-started/hello_world/main/hello_world_main.c @@ -31,7 +31,7 @@ void app_main(void) printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024), (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); - printf("Free heap: %d\n", esp_get_free_heap_size()); + printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size()); for (int i = 10; i >= 0; i--) { printf("Restarting in %d seconds...\n", i); diff --git a/examples/peripherals/gpio/example_test.py b/examples/peripherals/gpio/example_test.py new file mode 100644 index 0000000000..935bef36cd --- /dev/null +++ b/examples/peripherals/gpio/example_test.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import ttfw_idf + + +@ttfw_idf.idf_example_test(env_tag="Example_TWAI1", target=['esp32', 'esp32s2'], ci_target=['esp32']) +def test_examples_gpio(env, extra_data): + app_name = "gpio" + dut = env.get_dut(app_name, "examples/peripherals/gpio") + dut.start_app() + res = dut.expect(ttfw_idf.MINIMUM_FREE_HEAP_SIZE_RE) + if not res: + raise ValueError('Maximum heap size info not found') + ttfw_idf.print_heap_size(app_name, dut.app.config_name, dut.TARGET, res[0]) + + +if __name__ == '__main__': + test_examples_gpio() diff --git a/examples/peripherals/gpio/main/gpio_example_main.c b/examples/peripherals/gpio/main/gpio_example_main.c index 76cb81c05c..05abd57dd3 100644 --- a/examples/peripherals/gpio/main/gpio_example_main.c +++ b/examples/peripherals/gpio/main/gpio_example_main.c @@ -103,6 +103,8 @@ void app_main(void) //hook isr handler for specific gpio pin again gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); + printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size()); + int cnt = 0; while(1) { printf("cnt: %d\n", cnt++); diff --git a/tools/build_apps.py b/tools/build_apps.py index c18e259c91..1abd2012c5 100755 --- a/tools/build_apps.py +++ b/tools/build_apps.py @@ -65,6 +65,11 @@ def main(): type=argparse.FileType("w"), help="If specified, the list of builds (with all the placeholders expanded) will be written to this file.", ) + parser.add_argument( + "--size-info", + type=argparse.FileType("a"), + help="If specified, the test case name and size info json will be written to this file" + ) parser.add_argument( "build_list", type=argparse.FileType("r"), @@ -119,6 +124,8 @@ def main(): else: raise SystemExit(1) else: + if args.size_info: + build_info.write_size_info(args.size_info) if not build_info.preserve: logging.info("Removing build directory {}".format(build_info.build_dir)) # we only remove binaries here, log files are still needed by check_build_warnings.py diff --git a/tools/ci/build_examples.sh b/tools/ci/build_examples.sh deleted file mode 100755 index df7e4745a3..0000000000 --- a/tools/ci/build_examples.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash -# -# Build all examples from the examples directory, in BUILD_PATH to -# ensure they can run when copied to a new directory. -# -# Runs as part of CI process. -# - -# ----------------------------------------------------------------------------- -# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d). - -if [[ ! -z ${DEBUG_SHELL} ]] -then - set -x # Activate the expand mode if DEBUG is anything but empty. -fi - -set -o errexit # Exit if command failed. -set -o pipefail # Exit if pipe failed. - -export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH" - -# ----------------------------------------------------------------------------- - -die() { - echo "${1:-"Unknown Error"}" 1>&2 - exit 1 -} - -[ -z ${IDF_PATH} ] && die "IDF_PATH is not set" -[ -z ${LOG_PATH} ] && die "LOG_PATH is not set" -[ -z ${BUILD_PATH} ] && die "BUILD_PATH is not set" -[ -z ${IDF_TARGET} ] && die "IDF_TARGET is not set" -[ -z ${EXAMPLE_TEST_BUILD_SYSTEM} ] && die "EXAMPLE_TEST_BUILD_SYSTEM is not set" -[ -z ${SCAN_EXAMPLE_TEST_JSON} ] && die "SCAN_EXAMPLE_TEST_JSON is not set" -[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH} -[ -d ${BUILD_PATH} ] || mkdir -p ${BUILD_PATH} - -if [ -z ${CI_NODE_TOTAL} ]; then - CI_NODE_TOTAL=1 - echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}" -fi -if [ -z ${CI_NODE_INDEX} ]; then - # Gitlab uses a 1-based index - CI_NODE_INDEX=1 - echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}" -fi - - -export EXTRA_CFLAGS="${PEDANTIC_CFLAGS:-}" -export EXTRA_CXXFLAGS="${PEDANTIC_CXXFLAGS:-}" - -set -o nounset # Exit if variable not set. - -export REALPATH=realpath -if [ "$(uname -s)" = "Darwin" ]; then - export REALPATH=grealpath -fi - -# Convert LOG_PATH and BUILD_PATH to relative, to make the json file less verbose. -LOG_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${LOG_PATH}) -BUILD_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${BUILD_PATH}) - -ALL_BUILD_LIST_JSON="${BUILD_PATH}/list.json" -JOB_BUILD_LIST_JSON="${BUILD_PATH}/list_job_${CI_NODE_INDEX}.json" - -echo "build_examples running for target $IDF_TARGET" - -cd ${IDF_PATH} - -# This part of the script produces the same result for all the example build jobs. It may be moved to a separate stage -# (pre-build) later, then the build jobs will receive ${BUILD_LIST_JSON} file as an artifact. - -# If changing the work-dir or build-dir format, remember to update the "artifacts" in gitlab-ci configs, and IDFApp.py. - -${IDF_PATH}/tools/find_apps.py \ - -vv \ - --format json \ - --work-dir "${BUILD_PATH}/@f/@w/@t" \ - --build-dir build \ - --build-log "${LOG_PATH}/@f_@w.txt" \ - --output ${ALL_BUILD_LIST_JSON} \ - --config 'sdkconfig.ci=default' \ - --config 'sdkconfig.ci.*=' \ - --config '=default' \ - --app-list ${SCAN_EXAMPLE_TEST_JSON} - -# --config rules above explained: -# 1. If sdkconfig.ci exists, use it build the example with configuration name "default" -# 2. If sdkconfig.ci.* exists, use it to build the "*" configuration -# 3. If none of the above exist, build the default configuration under the name "default" - -# The part below is where the actual builds happen - -${IDF_PATH}/tools/build_apps.py \ - -vv \ - --format json \ - --keep-going \ - --parallel-count ${CI_NODE_TOTAL} \ - --parallel-index ${CI_NODE_INDEX} \ - --output-build-list ${JOB_BUILD_LIST_JSON} \ - ${ALL_BUILD_LIST_JSON}\ - - -# Check for build warnings -${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON} diff --git a/tools/ci/build_test_apps.sh b/tools/ci/build_test_apps.sh deleted file mode 100755 index 7909044f07..0000000000 --- a/tools/ci/build_test_apps.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env bash -# -# Build test apps -# -# Runs as part of CI process. -# - -# ----------------------------------------------------------------------------- -# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d). - -if [[ ! -z ${DEBUG_SHELL} ]] -then - set -x # Activate the expand mode if DEBUG is anything but empty. -fi - -set -o errexit # Exit if command failed. -set -o pipefail # Exit if pipe failed. - -export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH" - -# ----------------------------------------------------------------------------- - -die() { - echo "${1:-"Unknown Error"}" 1>&2 - exit 1 -} - -[ -z ${IDF_PATH} ] && die "IDF_PATH is not set" -[ -z ${LOG_PATH} ] && die "LOG_PATH is not set" -[ -z ${BUILD_PATH} ] && die "BUILD_PATH is not set" -[ -z ${IDF_TARGET} ] && die "IDF_TARGET is not set" -[ -z ${SCAN_CUSTOM_TEST_JSON} ] && die "SCAN_CUSTOM_TEST_JSON is not set" -[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH} -[ -d ${BUILD_PATH} ] || mkdir -p ${BUILD_PATH} - -if [ -z ${CI_NODE_TOTAL} ]; then - CI_NODE_TOTAL=1 - echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}" -fi -if [ -z ${CI_NODE_INDEX} ]; then - # Gitlab uses a 1-based index - CI_NODE_INDEX=1 - echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}" -fi - - -set -o nounset # Exit if variable not set. - -# Convert LOG_PATH to relative, to make the json file less verbose. -LOG_PATH=$(realpath --relative-to ${IDF_PATH} ${LOG_PATH}) -BUILD_PATH=$(realpath --relative-to ${IDF_PATH} ${BUILD_PATH}) - -ALL_BUILD_LIST_JSON="${BUILD_PATH}/list.json" -JOB_BUILD_LIST_JSON="${BUILD_PATH}/list_job_${CI_NODE_INDEX}.json" - -echo "build_test_apps running for target $IDF_TARGET" - -cd ${IDF_PATH} - -# This part of the script produces the same result for all the test app build jobs. It may be moved to a separate stage -# (pre-build) later, then the build jobs will receive ${BUILD_LIST_JSON} file as an artifact. - -# If changing the work-dir or build-dir, remember to update the "artifacts" in gitlab-ci configs, and IDFApp.py. - -${IDF_PATH}/tools/find_apps.py \ - -vv \ - --format json \ - --work-dir "${BUILD_PATH}/@f/@w/@t" \ - --build-dir build \ - --build-log "${LOG_PATH}/@f_@w.txt" \ - --output ${ALL_BUILD_LIST_JSON} \ - --config 'sdkconfig.ci=default' \ - --config 'sdkconfig.ci.*=' \ - --config '=default' \ - --app-list ${SCAN_CUSTOM_TEST_JSON} - -# --config rules above explained: -# 1. If sdkconfig.ci exists, use it build the example with configuration name "default" -# 2. If sdkconfig.ci.* exists, use it to build the "*" configuration -# 3. If none of the above exist, build the default configuration under the name "default" -# --work-dir and --build-log above uses "placeholders" @x: -# - @f: full path to the test with slashes replaced with underscores -# - @w: wildcard used as config name -# - @t: target name -# so the workdir .../@f/@w/@t would expand to e.g. tools_test_apps_system_startup/default/esp32 - -# The part below is where the actual builds happen - -${IDF_PATH}/tools/build_apps.py \ - -vv \ - --format json \ - --keep-going \ - --parallel-count ${CI_NODE_TOTAL} \ - --parallel-index ${CI_NODE_INDEX} \ - --output-build-list ${JOB_BUILD_LIST_JSON} \ - ${ALL_BUILD_LIST_JSON}\ - - -# Check for build warnings -${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON} diff --git a/tools/ci/build_unit_test.sh b/tools/ci/build_unit_test.sh deleted file mode 100755 index deeb0e8cd3..0000000000 --- a/tools/ci/build_unit_test.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/bin/bash -# -# Build unit test app -# -# Runs as part of CI process. -# - -# ----------------------------------------------------------------------------- -# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d). - -if [[ ! -z ${DEBUG_SHELL} ]] -then - set -x # Activate the expand mode if DEBUG is anything but empty. -fi - -set -o errexit # Exit if command failed. -set -o pipefail # Exit if pipe failed. - -export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH" - -# ----------------------------------------------------------------------------- - -die() { - echo "${1:-"Unknown Error"}" 1>&2 - exit 1 -} - -[ -z ${IDF_PATH} ] && die "IDF_PATH is not set" -[ -z ${LOG_PATH} ] && die "LOG_PATH is not set" -[ -z ${IDF_TARGET} ] && die "IDF_TARGET is not set" -[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH} - -# Relative to IDF_PATH -# If changing the BUILD_PATH, remember to update the "artifacts" in gitlab-ci configs, and IDFApp.py. -BUILD_PATH=${IDF_PATH}/tools/unit-test-app/builds -OUTPUT_PATH=${IDF_PATH}/tools/unit-test-app/output -mkdir -p ${BUILD_PATH}/${IDF_TARGET} -mkdir -p ${OUTPUT_PATH}/${IDF_TARGET} - -if [ -z ${CI_NODE_TOTAL} ]; then - CI_NODE_TOTAL=1 - echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}" -fi -if [ -z ${CI_NODE_INDEX} ]; then - # Gitlab uses a 1-based index - CI_NODE_INDEX=1 - echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}" -fi - - -set -o nounset # Exit if variable not set. - -# Convert LOG_PATH to relative, to make the json file less verbose. -LOG_PATH=$(realpath --relative-to ${IDF_PATH} ${LOG_PATH}) - -ALL_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list.json" -JOB_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list_job_${CI_NODE_INDEX}.json" - -echo "build_unit_test running for target $IDF_TARGET" - -cd ${IDF_PATH} - -# This part of the script produces the same result for all the unit test app build jobs. It may be moved to a separate stage -# (pre-build) later, then the build jobs will receive ${BUILD_LIST_JSON} file as an artifact. - -${IDF_PATH}/tools/find_apps.py \ - -p tools/unit-test-app \ - -vv \ - --format json \ - --build-system cmake \ - --target ${IDF_TARGET} \ - --recursive \ - --build-dir "builds/@t/@w" \ - --build-log "${LOG_PATH}/@w.txt" \ - --output ${ALL_BUILD_LIST_JSON} \ - --config 'configs/*=' - -# The part below is where the actual builds happen - -${IDF_PATH}/tools/build_apps.py \ - -vv \ - --format json \ - --keep-going \ - --parallel-count ${CI_NODE_TOTAL} \ - --parallel-index ${CI_NODE_INDEX} \ - --output-build-list ${JOB_BUILD_LIST_JSON} \ - ${ALL_BUILD_LIST_JSON}\ - -# Copy build artifacts to output directory -build_names=$(cd ${BUILD_PATH}/${IDF_TARGET}; find . -maxdepth 1 \! -name . -prune -type d | cut -c 3-) -for build_name in $build_names; do - src=${BUILD_PATH}/${IDF_TARGET}/${build_name} - dst=${OUTPUT_PATH}/${IDF_TARGET}/${build_name} - echo "Copying artifacts from ${src} to ${dst}" - - rm -rf ${dst} - mkdir -p ${dst} - cp ${src}/{*.bin,*.elf,*.map,sdkconfig,flasher_args.json} ${dst}/ - - mkdir -p ${dst}/bootloader - cp ${src}/bootloader/*.bin ${dst}/bootloader/ - - mkdir -p ${dst}/partition_table - cp ${src}/partition_table/*.bin ${dst}/partition_table/ -done - -# Check for build warnings -${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON} diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml index 4a6b41df96..7c00d383da 100644 --- a/tools/ci/config/build.yml +++ b/tools/ci/config/build.yml @@ -6,6 +6,7 @@ variables: BATCH_BUILD: "1" V: "0" + SIZE_INFO_LOCATION: "$CI_PROJECT_DIR/size_info.txt" .build_ssc_template: extends: .build_template @@ -45,8 +46,10 @@ build_ssc_esp32s2: paths: - tools/unit-test-app/output/${IDF_TARGET} - tools/unit-test-app/builds/${IDF_TARGET}/*.json + - tools/unit-test-app/builds/${IDF_TARGET}/*/size.json - components/idf_test/unit_test/*.yml - - ${LOG_PATH} + - $LOG_PATH + - $SIZE_INFO_LOCATION when: always expire_in: 4 days only: @@ -58,16 +61,17 @@ build_ssc_esp32s2: - $BOT_LABEL_REGULAR_TEST variables: LOG_PATH: "$CI_PROJECT_DIR/log_ut_cmake" + BUILD_PATH: ${CI_PROJECT_DIR}/tools/unit-test-app/builds + OUTPUT_PATH: ${CI_PROJECT_DIR}/tools/unit-test-app/output + BUILD_SYSTEM: "cmake" + TEST_TYPE: "unit_test" script: # RISC-V toolchain is optional but ULP may need it, so install: - $IDF_PATH/tools/idf_tools.py install riscv-none-embed-gcc - . $IDF_PATH/export.sh - - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} - - export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS} - - mkdir -p ${LOG_PATH} - - ${CI_PROJECT_DIR}/tools/ci/build_unit_test.sh + - ${IDF_PATH}/tools/ci/find_apps_build_apps.sh - cd $CI_PROJECT_DIR/tools/unit-test-app - - python tools/UnitTestParser.py + - python tools/UnitTestParser.py ${BUILD_PATH} build_esp_idf_tests_cmake_esp32: extends: .build_esp_idf_tests_cmake @@ -85,8 +89,6 @@ build_esp_idf_tests_cmake_esp32s2: artifacts: when: always expire_in: 4 days - variables: - SCAN_EXAMPLE_TEST_JSON: ${CI_PROJECT_DIR}/examples/test_configs/scan_${IDF_TARGET}_${EXAMPLE_TEST_BUILD_SYSTEM}.json only: # Here both 'variables' and 'refs' conditions are given. They are combined with "AND" logic. variables: @@ -95,15 +97,16 @@ build_esp_idf_tests_cmake_esp32s2: - $BOT_LABEL_EXAMPLE_TEST - $BOT_LABEL_REGULAR_TEST - $BOT_LABEL_WEEKEND_TEST + variables: + SCAN_TEST_JSON: ${CI_PROJECT_DIR}/examples/test_configs/scan_${IDF_TARGET}_${BUILD_SYSTEM}.json + TEST_TYPE: "example_test" script: - # RISC-V toolchain is optional but ULP may need it, so install: + # RISC-V toolchain is optional but ULP may need it, so install: - $IDF_PATH/tools/idf_tools.py install riscv-none-embed-gcc - . $IDF_PATH/export.sh # it's not possible to build 100% out-of-tree and have the "artifacts" # mechanism work, but this is the next best thing - - mkdir ${BUILD_PATH} - - mkdir -p ${LOG_PATH} - - ${IDF_PATH}/tools/ci/build_examples.sh + - ${IDF_PATH}/tools/ci/find_apps_build_apps.sh build_examples_make: extends: .build_examples_template @@ -113,10 +116,12 @@ build_examples_make: artifacts: paths: - $LOG_PATH + - build_examples/*/*/*/build/size.json + - $SIZE_INFO_LOCATION variables: LOG_PATH: "${CI_PROJECT_DIR}/log_examples_make" BUILD_PATH: "${CI_PROJECT_DIR}/build_examples_make" - EXAMPLE_TEST_BUILD_SYSTEM: "make" + BUILD_SYSTEM: "make" IDF_TARGET: "esp32" # currently we only support esp32 only: refs: @@ -138,6 +143,7 @@ build_examples_make: - build_examples/list.json - build_examples/list_job_*.json - build_examples/*/*/*/sdkconfig + - build_examples/*/*/*/build/size.json - build_examples/*/*/*/build/*.bin - build_examples/*/*/*/build/*.elf - build_examples/*/*/*/build/*.map @@ -145,10 +151,11 @@ build_examples_make: - build_examples/*/*/*/build/bootloader/*.bin - build_examples/*/*/*/build/partition_table/*.bin - $LOG_PATH + - $SIZE_INFO_LOCATION variables: LOG_PATH: "${CI_PROJECT_DIR}/log_examples" BUILD_PATH: "${CI_PROJECT_DIR}/build_examples" - EXAMPLE_TEST_BUILD_SYSTEM: "cmake" + BUILD_SYSTEM: "cmake" build_examples_cmake_esp32: extends: .build_examples_cmake @@ -170,20 +177,23 @@ build_examples_cmake_esp32s2: paths: - build_test_apps/list.json - build_test_apps/list_job_*.json - - build_test_apps/*/*/*/build/*.bin - build_test_apps/*/*/*/sdkconfig + - build_test_apps/*/*/*/build/size.json + - build_test_apps/*/*/*/build/*.bin - build_test_apps/*/*/*/build/*.elf - build_test_apps/*/*/*/build/*.map - build_test_apps/*/*/*/build/flasher_args.json - build_test_apps/*/*/*/build/bootloader/*.bin - build_test_apps/*/*/*/build/partition_table/*.bin - $LOG_PATH + - $SIZE_INFO_LOCATION expire_in: 3 days variables: LOG_PATH: "${CI_PROJECT_DIR}/log_test_apps" BUILD_PATH: "${CI_PROJECT_DIR}/build_test_apps" - CUSTOM_TEST_BUILD_SYSTEM: "cmake" - SCAN_CUSTOM_TEST_JSON: ${CI_PROJECT_DIR}/tools/test_apps/test_configs/scan_${IDF_TARGET}_${CUSTOM_TEST_BUILD_SYSTEM}.json + BUILD_SYSTEM: "cmake" + SCAN_TEST_JSON: ${CI_PROJECT_DIR}/tools/test_apps/test_configs/scan_${IDF_TARGET}_${BUILD_SYSTEM}.json + TEST_TYPE: custom_test only: variables: - $BOT_TRIGGER_WITH_LABEL == null @@ -192,9 +202,7 @@ build_examples_cmake_esp32s2: - $BOT_LABEL_CUSTOM_TEST - $BOT_LABEL_WEEKEND_TEST script: - - mkdir -p ${BUILD_PATH} - - mkdir -p ${LOG_PATH} - - ${IDF_PATH}/tools/ci/build_test_apps.sh + - ${IDF_PATH}/tools/ci/find_apps_build_apps.sh build_test_apps_esp32: extends: .build_test_apps diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml index 539aa5126b..987f268011 100644 --- a/tools/ci/config/target-test.yml +++ b/tools/ci/config/target-test.yml @@ -224,7 +224,7 @@ example_test_001B: example_test_001C: extends: .example_test_template - parallel: 2 + parallel: 3 tags: - ESP32 - Example_GENERIC diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 119ae39157..059a7384c0 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -33,10 +33,6 @@ tools/build_apps.py tools/check_kconfigs.py tools/check_python_dependencies.py tools/ci/apply_bot_filter.py -tools/ci/build_examples.sh -tools/ci/build_examples_cmake.sh -tools/ci/build_test_apps.sh -tools/ci/build_unit_test.sh tools/ci/check-executable.sh tools/ci/check-line-endings.sh tools/ci/check_build_warnings.py @@ -50,6 +46,7 @@ tools/ci/check_ut_cmake_make.sh tools/ci/checkout_project_ref.py tools/ci/deploy_docs.py tools/ci/envsubst.py +tools/ci/find_apps_build_apps.sh tools/ci/fix_empty_prototypes.sh tools/ci/get-full-sources.sh tools/ci/get_supported_examples.sh diff --git a/tools/ci/find_apps_build_apps.sh b/tools/ci/find_apps_build_apps.sh new file mode 100755 index 0000000000..8f4b205cec --- /dev/null +++ b/tools/ci/find_apps_build_apps.sh @@ -0,0 +1,172 @@ +#!/usr/bin/env bash +# +# Find apps and build apps for example_test, custom_test, and unit_test +# +# Runs as part of CI process. +# + +# ----------------------------------------------------------------------------- +# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d). + +if [[ -n ${DEBUG_SHELL} ]]; then + set -x # Activate the expand mode if DEBUG is anything but empty. +fi + +if [ -z ${CI_NODE_TOTAL} ]; then + CI_NODE_TOTAL=1 + echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}" +fi + +if [ -z ${CI_NODE_INDEX} ]; then + # Gitlab uses a 1-based index + CI_NODE_INDEX=1 + echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}" +fi + +set -o errexit # Exit if command failed. +set -o pipefail # Exit if pipe failed. +set -o nounset # Exit if variable not set. + +export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH" + +# ----------------------------------------------------------------------------- + +die() { + echo "${1:-"Unknown Error"}" 1>&2 + exit 1 +} + +[ -d ${BUILD_PATH} ] || mkdir -p ${BUILD_PATH} +[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH} +[ -f ${SIZE_INFO_LOCATION} ] && rm ${SIZE_INFO_LOCATION} + +export REALPATH=realpath +if [ "$(uname -s)" = "Darwin" ]; then + export REALPATH=grealpath +fi + +# Convert LOG_PATH and BUILD_PATH to relative, to make the json file less verbose. +BUILD_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${BUILD_PATH}) +LOG_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${LOG_PATH}) + +ALL_BUILD_LIST_JSON="${BUILD_PATH}/list.json" +JOB_BUILD_LIST_JSON="${BUILD_PATH}/list_job_${CI_NODE_INDEX}.json" + +# ----------------------------------------------------------------------------- +# common variables, will specify special cases later +WORK_DIR="--work-dir ${BUILD_PATH}/@f/@w/@t" +BUILD_DIR="build" +BUILD_LOG="${LOG_PATH}/@f_@w.txt" +CONFIG="--config sdkconfig.ci=default + --config sdkconfig.ci.*= + --config =default" + +export EXTRA_CFLAGS="${PEDANTIC_CFLAGS}" +export EXTRA_CXXFLAGS="${PEDANTIC_CXXFLAGS}" + +# --config rules above explained: +# 1. If sdkconfig.ci exists, use it build the example with configuration name "default" +# 2. If sdkconfig.ci.* exists, use it to build the "*" configuration +# 3. If none of the above exist, build the default configuration under the name "default" +# --work-dir and --build-log above uses "placeholders" @x: +# - @f: full path to the test with slashes replaced with underscores +# - @w: wildcard used as config name +# - @t: target name +# so the workdir .../@f/@w/@t would expand to e.g. tools_test_apps_system_startup/default/esp32 + +# ----------------------------------------------------------------------------- +# Example tests specific settings +if [ "${TEST_TYPE}" = "example_test" ]; then + export EXTRA_CFLAGS="${PEDANTIC_CFLAGS:-}" + export EXTRA_CXXFLAGS="${PEDANTIC_CXXFLAGS:-}" + + EXTRA_ARGS="--app-list ${SCAN_TEST_JSON}" +# ----------------------------------------------------------------------------- +# Custom tests specific settings +elif [ "${TEST_TYPE}" = "custom_test" ]; then + EXTRA_ARGS="--app-list ${SCAN_TEST_JSON}" +# ----------------------------------------------------------------------------- +# Unit tests specific settings +elif [ "${TEST_TYPE}" = "unit_test" ]; then + ALL_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list.json" + JOB_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list_job_${CI_NODE_INDEX}.json" + + mkdir -p ${BUILD_PATH}/${IDF_TARGET} + mkdir -p ${OUTPUT_PATH}/${IDF_TARGET} + + WORK_DIR="" + BUILD_DIR="builds/@t/@w" + BUILD_LOG="${LOG_PATH}/@w.txt" + + APP_FOLDER="tools/unit-test-app" + + EXTRA_ARGS=" + -p ${APP_FOLDER} + --build-system ${BUILD_SYSTEM} + --target ${IDF_TARGET} + --recursive + " + CONFIG="--config configs/*=" +# ----------------------------------------------------------------------------- +else + die "TEST_TYPE should only be one of {example_test, custom_test, unit_test}" +fi + +echo "$TEST_TYPE running for target $IDF_TARGET" +cd ${IDF_PATH} + +# This part of the script produces the same result for all the build jobs. +# +# It may be moved to a separate stage (pre-build) later, then the build jobs +# will receive ${BUILD_LIST_JSON} file as an artifact. +# +# If changing the work-dir or build-dir, remember to update the "artifacts" in +# gitlab-ci configs, and IDFApp.py. + +${IDF_PATH}/tools/find_apps.py \ + -vv \ + --format json \ + ${WORK_DIR} \ + --build-dir ${BUILD_DIR} \ + --build-log ${BUILD_LOG} \ + --output ${ALL_BUILD_LIST_JSON} \ + ${EXTRA_ARGS} \ + ${CONFIG} + +# The part below is where the actual builds happen + +${IDF_PATH}/tools/build_apps.py \ + -vv \ + --format json \ + --keep-going \ + --parallel-count ${CI_NODE_TOTAL} \ + --parallel-index ${CI_NODE_INDEX} \ + --output-build-list ${JOB_BUILD_LIST_JSON} \ + --size-info ${SIZE_INFO_LOCATION} \ + ${ALL_BUILD_LIST_JSON} + +# Check for build warnings +${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON} + +if [ "${TEST_TYPE}" = "unit_test" ]; then + # Copy build artifacts to output directory + build_names=$( + cd ${BUILD_PATH}/${IDF_TARGET} + find . -maxdepth 1 \! -name . -prune -type d | cut -c 3- + ) + for build_name in $build_names; do + src=${BUILD_PATH}/${IDF_TARGET}/${build_name} + dst=${OUTPUT_PATH}/${IDF_TARGET}/${build_name} + echo "Copying artifacts from ${src} to ${dst}" + + rm -rf ${dst} + mkdir -p ${dst} + cp ${src}/{*.bin,*.elf,*.map,sdkconfig,flasher_args.json} ${dst}/ + + mkdir -p ${dst}/bootloader + cp ${src}/bootloader/*.bin ${dst}/bootloader/ + + mkdir -p ${dst}/partition_table + cp ${src}/partition_table/*.bin ${dst}/partition_table/ + done +fi diff --git a/tools/ci/python_packages/ttfw_idf/__init__.py b/tools/ci/python_packages/ttfw_idf/__init__.py index b4e047242b..4abcadcd29 100644 --- a/tools/ci/python_packages/ttfw_idf/__init__.py +++ b/tools/ci/python_packages/ttfw_idf/__init__.py @@ -63,6 +63,7 @@ def local_test_check(decorator_target): if os.getenv('CI_JOB_ID'): # Only auto-detect target when running locally return idf_target + decorator_target = upper_list_or_str(decorator_target) expected_json_path = os.path.join('build', 'config', 'sdkconfig.json') if os.path.exists(expected_json_path): sdkconfig = json.load(open(expected_json_path)) @@ -262,3 +263,22 @@ def check_performance(item, value, target): _check_perf(op, value) # if no exception was thrown then the performance is met and no need to continue break + + +MINIMUM_FREE_HEAP_SIZE_RE = re.compile(r'Minimum free heap size: (\d+) bytes') + + +def print_heap_size(app_name, config_name, target, minimum_free_heap_size): + """ + Do not change the print output in case you really need to. + The result is parsed by ci-dashboard project + """ + print('------ heap size info ------\n' + '[app_name] {}\n' + '[config_name] {}\n' + '[target] {}\n' + '[minimum_free_heap_size] {} Bytes\n' + '------ heap size end ------'.format(app_name, + '' if not config_name else config_name, + target, + minimum_free_heap_size)) diff --git a/tools/find_build_apps/cmake.py b/tools/find_build_apps/cmake.py index 56b57c864f..27ed361bb0 100644 --- a/tools/find_build_apps/cmake.py +++ b/tools/find_build_apps/cmake.py @@ -1,14 +1,14 @@ -import os -import sys -import subprocess import logging -import shutil +import os import re +import shutil +import subprocess +import sys from .common import BuildSystem, BuildItem, BuildError BUILD_SYSTEM_CMAKE = "cmake" -IDF_PY = "idf.py" +IDF_PY = os.path.join(os.environ["IDF_PATH"], "tools", "idf.py") # While ESP-IDF component CMakeLists files can be identified by the presence of 'idf_component_register' string, # there is no equivalent for the project CMakeLists files. This seems to be the best option... @@ -30,8 +30,7 @@ class CMakeBuildSystem(BuildSystem): build_path, work_path, extra_cmakecache_items = cls.build_prepare(build_item) # Prepare the build arguments args = [ - # Assume it is the responsibility of the caller to - # set up the environment (run . ./export.sh) + sys.executable, IDF_PY, "-B", build_path, @@ -73,6 +72,7 @@ class CMakeBuildSystem(BuildSystem): os.path.join(work_path, "sdkconfig"), os.path.join(build_path, "sdkconfig"), ) + build_item.size_json_fp = build_item.get_size_json_fp() finally: if log_file: log_file.close() diff --git a/tools/find_build_apps/common.py b/tools/find_build_apps/common.py index a068f5f5bc..2aa92a5974 100644 --- a/tools/find_build_apps/common.py +++ b/tools/find_build_apps/common.py @@ -1,15 +1,18 @@ # coding=utf-8 +import fnmatch +import json +import logging +import os import re import shutil +import subprocess import sys -import os from abc import abstractmethod from collections import namedtuple -import logging -import json -import typing from io import open +import typing + DEFAULT_TARGET = "esp32" TARGET_PLACEHOLDER = "@t" @@ -18,6 +21,8 @@ NAME_PLACEHOLDER = "@n" FULL_NAME_PLACEHOLDER = "@f" INDEX_PLACEHOLDER = "@i" +IDF_SIZE_PY = os.path.join(os.environ["IDF_PATH"], "tools", "idf_size.py") + SDKCONFIG_LINE_REGEX = re.compile(r"^([^=]+)=\"?([^\"\n]*)\"?\n*$") # If these keys are present in sdkconfig.defaults, they will be extracted and passed to CMake @@ -55,6 +60,14 @@ def config_rules_from_str(rule_strings): # type: (typing.List[str]) -> typing.L return rules +def find_first_match(pattern, path): + for root, _, files in os.walk(path): + res = fnmatch.filter(files, pattern) + if res: + return os.path.join(root, res[0]) + return None + + class BuildItem(object): """ Instance of this class represents one build of an application. @@ -88,6 +101,7 @@ class BuildItem(object): self.preserve = preserve_artifacts self._app_name = os.path.basename(os.path.normpath(app_path)) + self.size_json_fp = None # Some miscellaneous build properties which are set later, at the build stage self.index = None @@ -95,6 +109,14 @@ class BuildItem(object): self.dry_run = False self.keep_going = False + self.work_path = self.work_dir or self.app_dir + if not self.build_dir: + self.build_path = os.path.join(self.work_path, "build") + elif os.path.isabs(self.build_dir): + self.build_path = self.build_dir + else: + self.build_path = os.path.normpath(os.path.join(self.work_path, self.build_dir)) + @property def app_dir(self): """ @@ -208,6 +230,39 @@ class BuildItem(object): path = os.path.expandvars(path) return path + def get_size_json_fp(self): + if self.size_json_fp and os.path.exists(self.size_json_fp): + return self.size_json_fp + + assert os.path.exists(self.build_path) + assert os.path.exists(self.work_path) + + map_file = find_first_match('*.map', self.build_path) + if not map_file: + raise ValueError('.map file not found under "{}"'.format(self.build_path)) + + size_json_fp = os.path.join(self.build_path, 'size.json') + idf_size_args = [ + sys.executable, + IDF_SIZE_PY, + '--json', + '-o', size_json_fp, + map_file + ] + subprocess.check_call(idf_size_args) + return size_json_fp + + def write_size_info(self, size_info_fs): + if not self.size_json_fp or (not os.path.exists(self.size_json_fp)): + raise OSError('Run get_size_json_fp() for app {} after built binary'.format(self.app_dir)) + size_info_dict = { + 'app_name': self._app_name, + 'config_name': self.config_name, + 'target': self.target, + 'path': self.size_json_fp, + } + size_info_fs.write(json.dumps(size_info_dict) + '\n') + class BuildSystem(object): """ @@ -221,13 +276,8 @@ class BuildSystem(object): @classmethod def build_prepare(cls, build_item): app_path = build_item.app_dir - work_path = build_item.work_dir or app_path - if not build_item.build_dir: - build_path = os.path.join(work_path, "build") - elif os.path.isabs(build_item.build_dir): - build_path = build_item.build_dir - else: - build_path = os.path.join(work_path, build_item.build_dir) + work_path = build_item.work_path + build_path = build_item.build_path if work_path != app_path: if os.path.exists(work_path): diff --git a/tools/find_build_apps/make.py b/tools/find_build_apps/make.py index e7b8857321..950d85ec20 100644 --- a/tools/find_build_apps/make.py +++ b/tools/find_build_apps/make.py @@ -48,6 +48,8 @@ class MakeBuildSystem(BuildSystem): log_file.close() raise BuildError("Build failed with exit code {}".format(e.returncode)) + build_item.size_json_fp = build_item.get_size_json_fp() + @staticmethod def is_app(path): makefile_path = os.path.join(path, "Makefile") diff --git a/tools/test_apps/system/panic/main/test_panic_main.c b/tools/test_apps/system/panic/main/test_panic_main.c index f72afaebad..9cff436c8b 100644 --- a/tools/test_apps/system/panic/main/test_panic_main.c +++ b/tools/test_apps/system/panic/main/test_panic_main.c @@ -10,18 +10,18 @@ /* utility functions */ static void die(const char* msg) __attribute__ ((noreturn)); -static const char* get_test_name(); +static const char* get_test_name(void); /* functions which cause an exception/panic in different ways */ -static void test_abort(); -static void test_int_wdt(); -static void test_task_wdt(); -static void test_storeprohibited(); -static void test_cache_error(); -static void test_int_wdt_cache_disabled(); -static void test_stack_overflow(); -static void test_illegal_instruction(); -static void test_instr_fetch_prohibited(); +static void test_abort(void); +static void test_int_wdt(void); +static void test_task_wdt(void); +static void test_storeprohibited(void); +static void test_cache_error(void); +static void test_int_wdt_cache_disabled(void); +static void test_stack_overflow(void); +static void test_illegal_instruction(void); +static void test_instr_fetch_prohibited(void); void app_main(void) @@ -60,12 +60,12 @@ void app_main(void) /* implementations of the test functions */ -static void test_abort() +static void test_abort(void) { abort(); } -static void test_int_wdt() +static void test_int_wdt(void) { portDISABLE_INTERRUPTS(); while (true) { @@ -73,25 +73,25 @@ static void test_int_wdt() } } -static void test_task_wdt() +static void test_task_wdt(void) { while (true) { ; } } -static void test_storeprohibited() +static void test_storeprohibited(void) { *(int*) 0x1 = 0; } -static IRAM_ATTR void test_cache_error() +static IRAM_ATTR void test_cache_error(void) { esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data); die("this should not be printed"); } -static void IRAM_ATTR test_int_wdt_cache_disabled() +static void IRAM_ATTR test_int_wdt_cache_disabled(void) { esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data); portDISABLE_INTERRUPTS(); @@ -100,7 +100,7 @@ static void IRAM_ATTR test_int_wdt_cache_disabled() } } -static void test_stack_overflow() +static void test_stack_overflow(void) { volatile uint8_t stuff[CONFIG_ESP_MAIN_TASK_STACK_SIZE * 2]; for (int i = 0; i < sizeof(stuff); ++i) { @@ -108,12 +108,12 @@ static void test_stack_overflow() } } -static void test_illegal_instruction() +static void test_illegal_instruction(void) { __asm__ __volatile__("ill"); } -static void test_instr_fetch_prohibited() +static void test_instr_fetch_prohibited(void) { typedef void (*fptr_t)(void); volatile fptr_t fptr = (fptr_t) 0x4; @@ -124,7 +124,7 @@ static void test_instr_fetch_prohibited() #define BOOT_CMD_MAX_LEN (128) -static const char* get_test_name() +static const char* get_test_name(void) { static char test_name_str[BOOT_CMD_MAX_LEN] = {0}; diff --git a/tools/unit-test-app/tools/UnitTestParser.py b/tools/unit-test-app/tools/UnitTestParser.py index e174f3cfdf..512431e1a2 100644 --- a/tools/unit-test-app/tools/UnitTestParser.py +++ b/tools/unit-test-app/tools/UnitTestParser.py @@ -1,10 +1,12 @@ from __future__ import print_function + +import argparse + import yaml import os import re import shutil import subprocess -import sys from copy import deepcopy import CreateSectionTable @@ -45,7 +47,6 @@ class Parser(object): CONFIG_DEPENDENCY_FILE = os.path.join("tools", "unit-test-app", "tools", "ConfigDependency.yml") MODULE_ARTIFACT_FILE = os.path.join("components", "idf_test", "ModuleDefinition.yml") TEST_CASE_FILE_DIR = os.path.join("components", "idf_test", "unit_test") - UT_BIN_FOLDER = os.path.join("tools", "unit-test-app", "output") UT_CONFIG_FOLDER = os.path.join("tools", "unit-test-app", "configs") ELF_FILE = "unit-test-app.elf" SDKCONFIG_FILE = "sdkconfig" @@ -55,12 +56,15 @@ class Parser(object): "esp32s2": "xtensa-esp32s2-elf-", } - def __init__(self, idf_path=os.getenv("IDF_PATH"), idf_target=os.getenv("IDF_TARGET")): + def __init__(self, binary_folder): + idf_path = os.getenv('IDF_PATH') + idf_target = os.getenv('IDF_TARGET') self.test_env_tags = {} self.unit_jobs = {} self.file_name_cache = {} self.idf_path = idf_path self.idf_target = idf_target + self.ut_bin_folder = binary_folder self.objdump = Parser.TOOLCHAIN_FOR_TARGET.get(idf_target, "") + "objdump" self.tag_def = yaml.load(open(os.path.join(idf_path, self.TAG_DEF_FILE), "r"), Loader=Loader) self.module_map = yaml.load(open(os.path.join(idf_path, self.MODULE_DEF_FILE), "r"), Loader=Loader) @@ -300,19 +304,19 @@ class Parser(object): """ parse test cases from multiple built unit test apps """ test_cases = [] - output_folder = os.path.join(self.idf_path, self.UT_BIN_FOLDER, self.idf_target) + output_folder = os.path.join(self.idf_path, self.ut_bin_folder, self.idf_target) configs_folder = os.path.join(self.idf_path, self.UT_CONFIG_FOLDER) test_configs = os.listdir(output_folder) for config in test_configs: - config_output_folder = os.path.join(output_folder, config) + config_output_folder = os.path.join(output_folder, 'build', config) if os.path.exists(config_output_folder): test_cases.extend(self.parse_test_cases_for_one_config(configs_folder, config_output_folder, config)) test_cases.sort(key=lambda x: x["config"] + x["summary"]) self.dump_test_cases(test_cases) -def test_parser(): - parser = Parser() +def test_parser(binary_folder): + parser = Parser(binary_folder) # test parsing tags # parsing module only and module in module list prop = parser.parse_case_properities("[esp32]") @@ -353,20 +357,12 @@ def test_parser(): assert sorted(tags) == ['a', 'd', 'f'] # sorted is required for older Python3, e.g. 3.4.8 -def main(): - test_parser() +def main(binary_folder): + assert os.getenv('IDF_PATH'), 'IDF_PATH must be set to use this script' + assert os.getenv('IDF_TARGET'), 'IDF_TARGET must be set to use this script' + test_parser(binary_folder) - idf_path = os.getenv("IDF_PATH") - if not idf_path: - print("IDF_PATH must be set to use this script", file=sys.stderr) - raise SystemExit(1) - - idf_target = os.getenv("IDF_TARGET") - if not idf_target: - print("IDF_TARGET must be set to use this script", file=sys.stderr) - raise SystemExit(1) - - parser = Parser(idf_path, idf_target) + parser = Parser(binary_folder) parser.parse_test_cases() parser.copy_module_def_file() if len(parser.parsing_errors) > 0: @@ -376,4 +372,7 @@ def main(): if __name__ == '__main__': - main() + parser = argparse.ArgumentParser() + parser.add_argument('bin_dir', help='Binary Folder') + args = parser.parse_args() + main(args.bin_dir)