1#!/usr/bin/env bash 2# 3# Test the build system for basic consistency 4# 5# A bash script that tests some likely make failure scenarios in a row 6# 7# Assumes PWD is an out-of-tree build directory, and will create a 8# subdirectory inside it to run build tests in. 9# 10# Environment variables: 11# IDF_PATH - must be set 12# ESP_IDF_TEMPLATE_GIT - Can override git clone source for template app. Otherwise github. 13# NOCLEANUP - Set to '1' if you want the script to leave its temporary directory when done, for post-mortem. 14# 15# 16# Internals: 17# * The tests run in sequence & the system keeps track of all failures to print at the end. 18# * BUILD directory is set to default BUILD_DIR_BASE 19# * The "print_status" function both prints a status line to the log and keeps track of which test is running. 20# * Calling the "failure" function prints a failure message to the log and also adds to the list of failures to print at the end. 21# * The function "assert_built" tests for a file relative to the BUILD directory. 22# * The function "take_build_snapshot" can be paired with the functions "assert_rebuilt" and "assert_not_rebuilt" to compare file timestamps and verify if they were rebuilt or not since the snapshot was taken. 23# 24# To add a new test case, add it to the end of the run_tests function. Note that not all test cases do comprehensive cleanup 25# (although very invasive ones like appending CRLFs to all files take a copy of the esp-idf tree), however the clean_build_dir 26# function can be used to force-delete all files from the build output directory. 27 28# Set up some variables 29# 30# override ESP_IDF_TEMPLATE_GIT to point to a local dir if you're testing and want fast iterations 31[ -z ${ESP_IDF_TEMPLATE_GIT} ] && ESP_IDF_TEMPLATE_GIT=https://github.com/espressif/esp-idf-template.git 32 33# uncomment next line to produce a lot more debug output 34#export V=1 35 36function run_tests() 37{ 38 FAILURES= 39 STATUS="Starting" 40 print_status "Checking prerequisites" 41 [ -z ${IDF_PATH} ] && echo "IDF_PATH is not set. Need path to esp-idf installation." && exit 2 42 43 print_status "Cloning template from ${ESP_IDF_TEMPLATE_GIT}..." 44 git clone ${ESP_IDF_TEMPLATE_GIT} template 45 cd template 46 if [ -z $CHECKOUT_REF_SCRIPT ]; then 47 git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..." 48 else 49 $CHECKOUT_REF_SCRIPT esp-idf-template . 50 fi 51 52 print_status "Updating template config..." 53 make defconfig || exit $? 54 55 print_status "Try to clean fresh directory..." 56 MAKEFLAGS= make clean || exit $? 57 58 BOOTLOADER_BINS="bootloader/bootloader.elf bootloader/bootloader.bin" 59 APP_BINS="app-template.elf app-template.bin" 60 PHY_INIT_BIN="phy_init_data.bin" 61 62 print_status "Initial clean build" 63 # if make fails here, everything fails 64 make || exit $? 65 # check all the expected build artifacts from the clean build 66 assert_built ${APP_BINS} ${BOOTLOADER_BINS} partitions_singleapp.bin 67 [ -f ${BUILD}/partition*.bin ] || failure "A partition table should have been built" 68 69 print_status "Updating component source file rebuilds component" 70 # touch a file & do a build 71 take_build_snapshot 72 touch ${IDF_PATH}/components/esp_system/port/cpu_start.c 73 make || failure "Failed to partial build" 74 assert_rebuilt ${APP_BINS} esp_system/libesp_system.a esp_system/port/cpu_start.o 75 assert_not_rebuilt lwip/liblwip.a freertos/libfreertos.a ${BOOTLOADER_BINS} partitions_singleapp.bin 76 77 print_status "Bootloader source file rebuilds bootloader" 78 take_build_snapshot 79 touch ${IDF_PATH}/components/bootloader/subproject/main/bootloader_start.c 80 make bootloader || failure "Failed to partial build bootloader" 81 assert_rebuilt ${BOOTLOADER_BINS} bootloader/main/bootloader_start.o 82 assert_not_rebuilt ${APP_BINS} partitions_singleapp.bin 83 84 print_status "Partition CSV file rebuilds partitions" 85 take_build_snapshot 86 touch ${IDF_PATH}/components/partition_table/partitions_singleapp.csv 87 make partition_table || failure "Failed to build partition table" 88 assert_rebuilt partitions_singleapp.bin 89 assert_not_rebuilt app-template.bin app-template.elf ${BOOTLOADER_BINS} 90 91 print_status "Partial build doesn't compile anything by default" 92 take_build_snapshot 93 # verify no build files are refreshed by a partial make 94 ALL_BUILD_FILES=$(find ${BUILD} -type f | sed "s@${BUILD}/@@") 95 make || failure "Partial build failed" 96 assert_not_rebuilt ${ALL_BUILD_FILES} 97 98 print_status "Cleaning should remove all files from build" 99 make clean || failure "Failed to make clean" 100 ALL_BUILD_FILES=$(find ${BUILD} -type f) 101 if [ -n "${ALL_BUILD_FILES}" ]; then 102 failure "Files weren't cleaned: ${ALL_BUILD_FILES}" 103 fi 104 105 print_status "Bootloader build shouldn't leave build output anywhere else" 106 clean_build_dir 107 make bootloader 108 # find wizardry: find any file not named sdkconfig.h that 109 # isn't in the "bootloader" or "config" directories 110 find ${BUILD} -type d \( -name bootloader -o -name config \) -prune , -type f ! -name sdkconfig.h || failure "Bootloader built files outside the bootloader or config directories" 111 112 print_status "Moving BUILD_DIR_BASE out of tree" 113 clean_build_dir 114 OUTOFTREE_BUILD=${TESTDIR}/alt_build 115 make BUILD_DIR_BASE=${OUTOFTREE_BUILD} || failure "Failed to build with BUILD_DIR_BASE overriden" 116 NEW_BUILD_FILES=$(find ${OUTOFREE_BUILD} -type f) 117 if [ -z "${NEW_BUILD_FILES}" ]; then 118 failure "No files found in new build directory!" 119 fi 120 DEFAULT_BUILD_FILES=$(find ${BUILD} -mindepth 1) 121 if [ -n "${DEFAULT_BUILD_FILES}" ]; then 122 failure "Some files were incorrectly put into the default build directory: ${DEFAULT_BUILD_FILES}" 123 fi 124 125 print_status "BUILD_DIR_BASE inside default build directory" 126 clean_build_dir 127 make BUILD_DIR_BASE=build/subdirectory || failure "Failed to build with BUILD_DIR_BASE as subdir" 128 NEW_BUILD_FILES=$(find ${BUILD}/subdirectory -type f) 129 if [ -z "${NEW_BUILD_FILES}" ]; then 130 failure "No files found in new build directory!" 131 fi 132 133 print_status "Parallel builds should work OK" 134 clean_build_dir 135 (make -j5 2>&1 | tee ${TESTDIR}/parallel_build.log) || failure "Failed to build in parallel" 136 if grep -q "warning: jobserver unavailable" ${TESTDIR}/parallel_build.log; then 137 failure "Parallel build prints 'warning: jobserver unavailable' errors" 138 fi 139 140 print_status "Can still clean build if all text files are CRLFs" 141 make clean || failure "Unexpected failure to make clean" 142 find . -path .git -prune -exec unix2dos {} \; # CRLFify template dir 143 # make a copy of esp-idf and CRLFify it 144 CRLF_ESPIDF=${TESTDIR}/esp-idf-crlf 145 mkdir -p ${CRLF_ESPIDF} 146 cp -r ${IDF_PATH}/* ${CRLF_ESPIDF} 147 # don't CRLFify executable files, as Linux will fail to execute them 148 find ${CRLF_ESPIDF} -name .git -prune -name build -prune -type f ! -perm 755 -exec unix2dos {} \; 149 make IDF_PATH=${CRLF_ESPIDF} || failure "Failed to build with CRLFs in source" 150 # do the same checks we do for the clean build 151 assert_built ${APP_BINS} ${BOOTLOADER_BINS} partitions_singleapp.bin 152 [ -f ${BUILD}/partition*.bin ] || failure "A partition table should have been built in CRLF mode" 153 154 print_status "Touching rom ld file should re-link app and bootloader" 155 make 156 take_build_snapshot 157 touch ${IDF_PATH}/components/esp_rom/esp32/ld/esp32.rom.ld 158 make 159 assert_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} 160 161 print_status "Touching app-only template ld file should only re-link app" 162 take_build_snapshot 163 touch ${IDF_PATH}/components/esp_system/ld/esp32/sections.ld.in 164 make 165 assert_rebuilt ${APP_BINS} 166 assert_not_rebuilt ${BOOTLOADER_BINS} 167 168 print_status "Touching a linker fragment file should trigger re-link of app" # only app linker script is generated by tool for now 169 take_build_snapshot 170 touch ${IDF_PATH}/components/esp_common/common.lf 171 make 172 assert_rebuilt ${APP_BINS} 173 assert_not_rebuilt ${BOOTLOADER_BINS} 174 175 print_status "sdkconfig update triggers full recompile" 176 make 177 take_build_snapshot 178 touch sdkconfig 179 make 180 # check the component_project_vars.mk file was rebuilt 181 assert_rebuilt esp32/component_project_vars.mk 182 # pick one each of .c, .cpp, .S that #includes sdkconfig.h 183 # and therefore should rebuild 184 assert_rebuilt newlib/newlib_init.o 185 assert_rebuilt nvs_flash/src/nvs_api.o 186 assert_rebuilt freertos/port/xtensa/xtensa_vectors.o 187 188 print_status "Updating project Makefile triggers full recompile" 189 make 190 take_build_snapshot 191 touch Makefile 192 make 193 # similar to previous test 194 assert_rebuilt newlib/newlib_init.o 195 assert_rebuilt nvs_flash/src/nvs_api.o 196 assert_rebuilt freertos/port/xtensa/xtensa_vectors.o 197 198 print_status "print_flash_cmd target should produce one line of output" 199 make 200 test $(make print_flash_cmd V=0 | wc -l | tr -d ' ') -eq 1 201 202 print_status "Can include/exclude object files" 203 echo "#error This file should not compile" > main/excluded_file.c 204 echo "int required_global;" > main/included_file.c 205 echo "COMPONENT_OBJEXCLUDE := excluded_file.o" >> main/component.mk 206 echo "COMPONENT_OBJINCLUDE := included_file.o" >> main/component.mk 207 echo "COMPONENT_ADD_LDFLAGS := -l\$(COMPONENT_NAME) -u required_global" >> main/component.mk 208 make 209 git checkout main/component.mk 210 rm main/{included,excluded}_file.c 211 212 print_status "Can include/exclude object files outside of component tree" 213 mkdir -p extra_source_dir 214 echo "#error This file should not compile" > extra_source_dir/excluded_file.c 215 echo "int required_global;" > extra_source_dir/included_file.c 216 echo "COMPONENT_SRCDIRS := . ../extra_source_dir" >> main/component.mk 217 echo "COMPONENT_OBJEXCLUDE := ../extra_source_dir/excluded_file.o" >> main/component.mk 218 echo "COMPONENT_OBJINCLUDE := ../extra_source_dir/included_file.o" >> main/component.mk 219 echo "COMPONENT_ADD_LDFLAGS := -l\$(COMPONENT_NAME) -u required_global" >> main/component.mk 220 make 221 git checkout main/component.mk 222 rm -rf extra_source_dir 223 224 print_status "Can build without git installed on system" 225 clean_build_dir 226 # Make provision for getting IDF version 227 echo "IDF_VER_0123456789_0123456789_0123456789" > ${IDF_PATH}/version.txt 228 echo "project-version-w.z" > ${TESTDIR}/template/version.txt 229 # Hide .gitmodules so that submodule check is avoided 230 [ -f ${IDF_PATH}/.gitmodules ] && mv ${IDF_PATH}/.gitmodules ${IDF_PATH}/.gitmodules_backup 231 # Overload `git` command 232 echo -e '#!/bin/bash\ntouch ${IDF_PATH}/git_invoked' > git 233 chmod +x git 234 OLD_PATH=$PATH 235 export PATH="$PWD:$PATH" 236 make 237 [ -f ${IDF_PATH}/git_invoked ] && rm ${IDF_PATH}/git_invoked && failure "git should not have been invoked in this case" 238 rm -f ${IDF_PATH}/version.txt git 239 rm -f ${TESTDIR}/template/version.txt 240 [ -f ${IDF_PATH}/.gitmodules_backup ] && mv ${IDF_PATH}/.gitmodules_backup ${IDF_PATH}/.gitmodules 241 export PATH=$OLD_PATH 242 243 print_status "Rebuild when app version was changed" 244 take_build_snapshot 245 # App version 246 echo "project-version-1.0" > ${TESTDIR}/template/version.txt 247 make 248 assert_rebuilt ${APP_BINS} 249 print_status "Change app version" 250 take_build_snapshot 251 echo "project-version-2.0(012345678901234567890123456789)" > ${TESTDIR}/template/version.txt 252 make 253 assert_rebuilt ${APP_BINS} 254 assert_not_rebuilt ${BOOTLOADER_BINS} esp_system/libesp_system.a 255 256 print_status "Re-building does not change app.bin" 257 take_build_snapshot 258 make 259 assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp_system/libesp_system.a 260 rm -f ${TESTDIR}/template/version.txt 261 262 print_status "Get the version of app from git describe. Project is not inside IDF and do not have a tag only a hash commit." 263 make >> log.log || failure "Failed to build" 264 version="App \"app-template\" version: " 265 version+=$(git describe --always --tags --dirty) 266 grep "${version}" log.log || failure "Project version should have a hash commit" 267 268 print_status "Get the version of app from Kconfig option" 269 make clean > /dev/null 270 rm -f sdkconfig.defaults 271 rm -f sdkconfig 272 echo "project_version_from_txt" > ${TESTDIR}/template/version.txt 273 echo "CONFIG_APP_PROJECT_VER_FROM_CONFIG=y" >> sdkconfig.defaults 274 echo 'CONFIG_APP_PROJECT_VER="project_version_from_Kconfig"' >> sdkconfig.defaults 275 make defconfig > /dev/null 276 make >> log.log || failure "Failed to build" 277 version="App \"app-template\" version: " 278 version+="project_version_from_Kconfig" 279 grep "${version}" log.log || failure "Project version should be from Kconfig" 280 rm -f sdkconfig.defaults 281 rm -f sdkconfig 282 rm -f ${TESTDIR}/template/version.txt 283 284 print_status "Build fails if partitions don't fit in flash" 285 sed -i.bak "s/CONFIG_ESPTOOLPY_FLASHSIZE.\+//" sdkconfig # remove all flashsize config 286 echo "CONFIG_ESPTOOLPY_FLASHSIZE_1MB=y" >> sdkconfig # introduce undersize flash 287 make defconfig || failure "Failed to reconfigure with smaller flash" 288 ( make 2>&1 | grep "does not fit in configured flash size 1MB" ) || failure "Build didn't fail with expected flash size failure message" 289 mv sdkconfig.bak sdkconfig 290 291 print_status "Flash size is correctly set in the bootloader image header" 292 # Build with the default 2MB setting 293 rm sdkconfig 294 make defconfig && make bootloader || failure "Failed to build bootloader" 295 bin_header_match build/bootloader/bootloader.bin "0210" 296 # Change to 4MB 297 echo "CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y" > sdkconfig 298 make defconfig && make bootloader || failure "Failed to build bootloader" 299 bin_header_match build/bootloader/bootloader.bin "0220" 300 # Change to QIO, bootloader should still be DIO (will change to QIO in 2nd stage bootloader) 301 echo "CONFIG_FLASHMODE_QIO=y" > sdkconfig 302 make defconfig && make bootloader || failure "Failed to build bootloader" 303 bin_header_match build/bootloader/bootloader.bin "0210" 304 # Change to 80 MHz 305 echo "CONFIG_ESPTOOLPY_FLASHFREQ_80M=y" > sdkconfig 306 make defconfig && make bootloader || failure "Failed to build bootloader" 307 bin_header_match build/bootloader/bootloader.bin "021f" 308 rm sdkconfig 309 310 print_status "sdkconfig should have contents of all files: sdkconfig, sdkconfig.defaults, sdkconfig.defaults.IDF_TARGET" 311 make clean > /dev/null; 312 rm -f sdkconfig.defaults; 313 rm -f sdkconfig; 314 echo "CONFIG_PARTITION_TABLE_OFFSET=0x10000" >> sdkconfig.defaults; 315 echo "CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y" >> sdkconfig.defaults.esp32; 316 echo "CONFIG_PARTITION_TABLE_TWO_OTA=y" >> sdkconfig; 317 make defconfig > /dev/null; 318 grep "CONFIG_PARTITION_TABLE_OFFSET=0x10000" sdkconfig || failure "The define from sdkconfig.defaults should be into sdkconfig" 319 grep "CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y" sdkconfig || failure "The define from sdkconfig.defaults.esp32 should be into sdkconfig" 320 grep "CONFIG_PARTITION_TABLE_TWO_OTA=y" sdkconfig || failure "The define from sdkconfig should be into sdkconfig" 321 rm sdkconfig sdkconfig.defaults sdkconfig.defaults.esp32 322 make defconfig 323 324 print_status "can build with phy_init_data" 325 make clean > /dev/null 326 rm -f sdkconfig.defaults 327 rm -f sdkconfig 328 echo "CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION=y" >> sdkconfig.defaults 329 make defconfig > /dev/null 330 make || failure "Failed to build with PHY_INIT_DATA" 331 assert_built ${APP_BINS} ${BOOTLOADER_BINS} ${PHY_INIT_BIN} 332 rm sdkconfig 333 rm sdkconfig.defaults 334 make defconfig 335 336 print_status "UF2 build works" 337 rm -f -r build sdkconfig 338 make defconfig 339 make uf2 340 assert_built ${APP_BINS} "uf2.bin" 341 make uf2-app 342 assert_built "uf2-app.bin" 343 rm -f -r build sdkconfig 344 345 print_status "Empty directory not treated as a component" 346 mkdir -p components/esp32 347 make || failure "Failed to build with empty esp32 directory in components" 348 rm -rf components 349 350 print_status "If a component directory is added to COMPONENT_DIRS, its subdirectories are not added" 351 mkdir -p main/test 352 touch main/test/component.mk 353 echo "#error This should not be built" > main/test/test.c 354 make || failure "COMPONENT_DIRS has added component subdirectory to the build" 355 rm -rf main/test 356 357 print_status "If a component directory is added to COMPONENT_DIRS, its sibling directories are not added" 358 mkdir -p mycomponents/mycomponent 359 touch mycomponents/mycomponent/component.mk 360 # first test by adding single component directory to EXTRA_COMPONENT_DIRS 361 mkdir -p mycomponents/esp32 362 touch mycomponents/esp32/component.mk 363 make EXTRA_COMPONENT_DIRS=$PWD/mycomponents/mycomponent || failure "EXTRA_COMPONENT_DIRS has added a sibling directory" 364 rm -rf mycomponents/esp32 365 # now the same thing, but add a components directory 366 mkdir -p esp32 367 touch esp32/component.mk 368 make EXTRA_COMPONENT_DIRS=$PWD/mycomponents || failure "EXTRA_COMPONENT_DIRS has added a sibling directory" 369 rm -rf esp32 370 rm -rf mycomponents 371 372 print_status "Handling deprecated Kconfig options" 373 make clean > /dev/null; 374 rm -f sdkconfig.defaults; 375 rm -f sdkconfig; 376 echo "" > ${IDF_PATH}/sdkconfig.rename; 377 make defconfig > /dev/null; 378 echo "CONFIG_TEST_OLD_OPTION=y" >> sdkconfig; 379 echo "CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION" >> ${IDF_PATH}/sdkconfig.rename; 380 echo -e "\n\ 381menu \"test\"\n\ 382 config TEST_NEW_OPTION\n\ 383 bool \"test\"\n\ 384 default \"n\"\n\ 385 help\n\ 386 TEST_NEW_OPTION description\n\ 387endmenu\n" >> ${IDF_PATH}/Kconfig; 388 make defconfig > /dev/null; 389 grep "CONFIG_TEST_OLD_OPTION=y" sdkconfig || failure "CONFIG_TEST_OLD_OPTION should be in sdkconfig for backward compatibility" 390 grep "CONFIG_TEST_NEW_OPTION=y" sdkconfig || failure "CONFIG_TEST_NEW_OPTION should be now in sdkconfig" 391 grep "#define CONFIG_TEST_NEW_OPTION 1" build/include/sdkconfig.h || failure "sdkconfig.h should contain the new macro" 392 grep "#define CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION" build/include/sdkconfig.h || failure "sdkconfig.h should contain the compatibility macro" 393 grep "CONFIG_TEST_OLD_OPTION=y" build/include/config/auto.conf || failure "CONFIG_TEST_OLD_OPTION should be in auto.conf for backward compatibility" 394 grep "CONFIG_TEST_NEW_OPTION=y" build/include/config/auto.conf || failure "CONFIG_TEST_NEW_OPTION should be now in auto.conf" 395 rm -f sdkconfig sdkconfig.defaults 396 pushd ${IDF_PATH} 397 git checkout -- sdkconfig.rename Kconfig 398 popd 399 400 print_status "Handling deprecated Kconfig options in sdkconfig.defaults" 401 make clean; 402 rm -f sdkconfig; 403 echo "CONFIG_TEST_OLD_OPTION=7" > sdkconfig.defaults; 404 echo "CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION" > ${IDF_PATH}/sdkconfig.rename; 405 echo -e "\n\ 406menu \"test\"\n\ 407 config TEST_NEW_OPTION\n\ 408 int \"TEST_NEW_OPTION\"\n\ 409 range 0 10\n\ 410 default 5\n\ 411 help\n\ 412 TEST_NEW_OPTION description\n\ 413endmenu\n" >> ${IDF_PATH}/Kconfig; 414 make defconfig > /dev/null; 415 grep "CONFIG_TEST_OLD_OPTION=7" sdkconfig || failure "CONFIG_TEST_OLD_OPTION=7 should be in sdkconfig for backward compatibility" 416 grep "CONFIG_TEST_NEW_OPTION=7" sdkconfig || failure "CONFIG_TEST_NEW_OPTION=7 should be in sdkconfig" 417 rm -f sdkconfig.defaults; 418 pushd ${IDF_PATH} 419 git checkout -- sdkconfig.rename Kconfig 420 popd 421 422 print_status "Project components prioritized over EXTRA_COMPONENT_DIRS" 423 clean_build_dir 424 mkdir -p extra_dir/my_component 425 echo "COMPONENT_CONFIG_ONLY := 1" > extra_dir/my_component/component.mk 426 cp Makefile Makefile.bak # set EXTRA_COMPONENT_DIRS to point to the other directory 427 sed -i "s%PROJECT_NAME := app-template%PROJECT_NAME := app-template\nEXTRA_COMPONENT_DIRS := extra_dir%" Makefile 428 (make list-components | grep "$PWD/extra_dir/my_component") || failure "Unable to find component specified in EXTRA_COMPONENT_DIRS" 429 mkdir -p components/my_component 430 echo "COMPONENT_CONFIG_ONLY := 1" > components/my_component/component.mk 431 (make list-components | grep "$PWD/components/my_component") || failure "Project components should be prioritized over EXTRA_COMPONENT_DIRS" 432 mv Makefile.bak Makefile # revert previous modifications 433 rm -rf extra_dir components 434 435 print_status "COMPONENT_OWNBUILDTARGET, COMPONENT_OWNCLEANTARGET can work" 436 take_build_snapshot 437 mkdir -p components/test_component 438 cat > components/test_component/component.mk <<EOF 439COMPONENT_OWNBUILDTARGET:=custom_build 440COMPONENT_OWNCLEANTARGET:=custom_clean 441 442.PHONY: custom_target 443 444custom_build: 445 echo "Running custom_build!" 446 echo "" | \$(CC) -x c++ -c -o dummy_obj.o - 447 \$(AR) cr libtest_component.a dummy_obj.o 448 449custom_clean: 450 rm -f libtest_component.a dummy_obj.o 451EOF 452 make || failure "Failed to build with custom component build target" 453 [ -f ${BUILD}/test_component/dummy_obj.o ] || failure "Failed to build dummy_obj.o in custom target" 454 [ -f ${BUILD}/test_component/libtest_component.a ] || failure "Failed to build custom component library" 455 grep -q "libtest_component.a" ${BUILD}/*.map || failure "Linker didn't see the custom library" 456 make clean || failure "Failed to make clean with custom clean target" 457 [ -f ${BUILD}/test_component/dummy_obj.o ] && failure "Custom clean target didn't clean object file" 458 [ -f ${BUILD}/test_component/libtest_component.a ] && failure "Custom clean target didn't clean library" 459 rm -rf components/test_component 460 461 print_status "All tests completed" 462 if [ -n "${FAILURES}" ]; then 463 echo "Some failures were detected:" 464 echo -e "${FAILURES}" 465 exit 1 466 else 467 echo "Build tests passed." 468 fi 469} 470 471function print_status() 472{ 473 echo "******** $1" 474 STATUS="$1" 475} 476 477function failure() 478{ 479 echo "!!!!!!!!!!!!!!!!!!!" 480 echo "FAILURE: $1" 481 echo "!!!!!!!!!!!!!!!!!!!" 482 FAILURES="${FAILURES}${STATUS} :: $1\n" 483} 484 485TESTDIR=${PWD}/build_system_tests_$$ 486mkdir -p ${TESTDIR} 487# set NOCLEANUP=1 if you want to keep the test directory around 488# for post-mortem debugging 489[ -z ${NOCLEANUP} ] && trap "rm -rf ${TESTDIR}" EXIT KILL 490 491SNAPSHOT=${TESTDIR}/snapshot 492BUILD=${TESTDIR}/template/build 493 494# copy all the build output to a snapshot directory 495function take_build_snapshot() 496{ 497 rm -rf ${SNAPSHOT} 498 cp -ap ${TESTDIR}/template/build ${SNAPSHOT} 499} 500 501# verify that all the arguments are present in the build output directory 502function assert_built() 503{ 504 until [ -z "$1" ]; do 505 if [ ! -f "${BUILD}/$1" ]; then 506 failure "File $1 should be in the build output directory" 507 fi 508 shift 509 done 510} 511 512# Test if a file has been rebuilt. 513function file_was_rebuilt() 514{ 515 # can't use [ a -ot b ] here as -ot only gives second resolution 516 # but stat -c %y seems to be microsecond at least for tmpfs, ext4.. 517 if [ "$(stat -c %y ${SNAPSHOT}/$1)" != "$(stat -c %y ${BUILD}/$1)" ]; then 518 return 0 519 else 520 return 1 521 fi 522} 523 524# verify all the arguments passed in were rebuilt relative to the snapshot 525function assert_rebuilt() 526{ 527 until [ -z "$1" ]; do 528 assert_built "$1" 529 if [ ! -f "${SNAPSHOT}/$1" ]; then 530 failure "File $1 should have been original build snapshot" 531 fi 532 if ! file_was_rebuilt "$1"; then 533 failure "File $1 should have been rebuilt" 534 fi 535 shift 536 done 537} 538 539# verify all the arguments are in the build directory & snapshot, 540# but were not rebuilt 541function assert_not_rebuilt() 542{ 543 until [ -z "$1" ]; do 544 assert_built "$1" 545 if [ ! -f "${SNAPSHOT}/$1" ]; then 546 failure "File $1 should be in snapshot build directory" 547 fi 548 if file_was_rebuilt "$1"; then 549 failure "File $1 should not have been rebuilt" 550 fi 551 shift 552 done 553} 554 555# do a "clean" that doesn't depend on 'make clean' 556function clean_build_dir() 557{ 558 rm -rf --preserve-root ${BUILD}/* 559} 560 561# check the bytes 3-4 of the binary image header. e.g.: 562# bin_header_match app.bin 0210 563function bin_header_match() 564{ 565 expected=$2 566 filename=$1 567 actual=$(xxd -s 2 -l 2 -ps $1) 568 if [ ! "$expected" = "$actual" ]; then 569 failure "Incorrect binary image header, expected $expected got $actual" 570 fi 571} 572 573cd ${TESTDIR} 574run_tests 575