From 439a1ad80b7618ae58477fe75477670d44f654d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B8e?= Date: Fri, 1 Mar 2019 13:22:00 +0100 Subject: [PATCH] [nrf noup] cmake: multi image build support with IMAGE prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: This was originally submitted upstream in #13672 and was rejected. NCS is carrying it as a noup for now. Another, more upstream-friendly approach will be needed. We are seeing the need to boot Zephyr applications in multiple stages, a real-world use-case of even a 3-stage bootloader has been identified and tested. Each bootloader needs to be individually upgrade-able and have it's own configurations of Zephyr libraries. To achieve this each bootloader is organized as it's own executable. The problem is that the build system can only build one executable. This creates a usability issue as the user must invoke a large set of arcane commands to build, sign, and flash each bootloader. To resolve this we re-organize the build system such that it can build multiple executables. To work within CMake restrictions that logical target names must be globally unique (among other naming restrictions), we add an IMAGE variable which is used to name the current Zephyr application being built. Signed-off-by: Sebastian Bøe Signed-off-by: Håkon Øye Amundsen Signed-off-by: Øyvind Rønningstad Signed-off-by: Robert Lubos Signed-off-by: Ruth Fuchss (cherry picked from commit 3db22acba35aa62abb18f4823102401f8b211a57) (Conflicts were resolved in lib/posix/CMakeLists.txt. Changes to ia32.cmake were dropped entirely since Intel has rejected this approach. Finally, these follow-up fixes and dependent patches were squashed in: 02eeeb779665f126f59c185430d854bc7392f18e c6c3fed492e0f49679f5c6230dfc955c72f4ffaf 56f6a33a71c46ec5b2e1beb6076edf9521014ad3 1dc0ca5ccead37a53f600c65a941938f4138cf38 6e348b8e609109981cbc140f06c324d938b52cd4) Signed-off-by: Marti Bolivar (cherry picked from commit 1e0a3dc603d9cbb9969563f1cbf308b147582461) (Conflict resolved in cmake/app/boilerplate.cmake) Signed-off-by: Robert Lubos --- CMakeLists.txt | 226 +++++---- arch/arm/core/cortex_m/tz/CMakeLists.txt | 2 +- cmake/app/boilerplate.cmake | 470 +++++++++++------- cmake/compiler/gcc/target.cmake | 5 +- cmake/dts.cmake | 12 +- cmake/extensions.cmake | 110 ++-- cmake/flash/CMakeLists.txt | 6 +- .../eclipse_cdt4_generator_amendment.cmake | 4 +- cmake/kconfig.cmake | 62 ++- cmake/linker/ld/target.cmake | 10 +- cmake/linker/ld/target_base.cmake | 2 +- cmake/linker/ld/target_relocation.cmake | 8 +- cmake/reports/CMakeLists.txt | 2 +- cmake/usage/CMakeLists.txt | 15 - doc/application/index.rst | 168 +++++++ kernel/CMakeLists.txt | 18 +- samples/subsys/ipc/ipm_mcux/CMakeLists.txt | 2 +- samples/subsys/ipc/openamp/CMakeLists.txt | 2 +- soc/arm/nxp_lpc/lpc54xxx/CMakeLists.txt | 4 +- subsys/bluetooth/CMakeLists.txt | 4 +- subsys/bluetooth/common/CMakeLists.txt | 2 +- subsys/bluetooth/controller/CMakeLists.txt | 2 +- subsys/bluetooth/host/CMakeLists.txt | 2 +- subsys/bluetooth/mesh/CMakeLists.txt | 2 +- 24 files changed, 734 insertions(+), 406 deletions(-) delete mode 100644 cmake/usage/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fbd2f38dd82a0..bacfc76f5c89cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,31 +45,37 @@ assert(toolchain_is_ok "The toolchain is unable to build a dummy C file. See CMa # is the last station. See "logical_target_for_zephyr_elf" below for # details. set(CMAKE_EXECUTABLE_SUFFIX .elf) -set(ZEPHYR_PREBUILT_EXECUTABLE zephyr_prebuilt) -set(ZEPHYR_FINAL_EXECUTABLE zephyr_final) +set(ZEPHYR_PREBUILT_EXECUTABLE ${IMAGE}zephyr_prebuilt) +set(ZEPHYR_FINAL_EXECUTABLE ${IMAGE}zephyr_final) # Set some phony targets to collect dependencies -set(OFFSETS_H_TARGET offsets_h) -set(SYSCALL_MACROS_H_TARGET syscall_macros_h_target) -set(SYSCALL_LIST_H_TARGET syscall_list_h_target) -set(DRIVER_VALIDATION_H_TARGET driver_validation_h_target) -set(KOBJ_TYPES_H_TARGET kobj_types_h_target) -set(LINKER_SCRIPT_TARGET linker_script_target) + +set(OFFSETS_H_TARGET ${IMAGE}offsets_h) +set(SYSCALL_MACROS_H_TARGET ${IMAGE}syscall_macros_h_target) +set(SYSCALL_LIST_H_TARGET ${IMAGE}syscall_list_h_target) +set(DRIVER_VALIDATION_H_TARGET ${IMAGE}driver_validation_h_target) +set(KOBJ_TYPES_H_TARGET ${IMAGE}kobj_types_h_target) +set(LINKER_SCRIPT_TARGET ${IMAGE}linker_script_target) + +set(OFFSETS_LIB ${IMAGE}offsets) +set(KERNEL_LIBRARY ${IMAGE}kernel) + +set(PRIV_STACKS_PREBUILT ${IMAGE}priv_stacks_prebuilt) define_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT BRIEF_DOCS " " FULL_DOCS " ") set_property( GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf32-little${ARCH}) # BFD format -# "zephyr_interface" is a source-less library that encapsulates all the global +# ${IMAGE}zephyr_interface is a source-less library that encapsulates all the global # compiler options needed by all source files. All zephyr libraries, # including the library named "zephyr" link with this library to # obtain these flags. # https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#interface-libraries -add_library(zephyr_interface INTERFACE) +add_library(${IMAGE}zephyr_interface INTERFACE) # "zephyr" is a catch-all CMake library for source files that can be # built purely with the include paths, defines, and other compiler -# flags that come with zephyr_interface. +# flags that come with ${IMAGE}zephyr_interface. zephyr_library_named(zephyr) zephyr_include_directories( @@ -343,11 +349,14 @@ zephyr_cc_option(-fmacro-prefix-map=${ZEPHYR_BASE}=ZEPHYR_BASE) # Declare MPU userspace dependencies before the linker scripts to make # sure the order of dependencies are met +unset(APP_SMEM_ALIGNED_DEP) +unset(APP_SMEM_UNALIGNED_DEP) +unset(PRIV_STACK_DEP) if(CONFIG_USERSPACE) - set(APP_SMEM_ALIGNED_DEP app_smem_aligned_linker) - set(APP_SMEM_UNALIGNED_DEP app_smem_unaligned_linker) + set(APP_SMEM_ALIGNED_DEP ${IMAGE}app_smem_aligned_linker) + set(APP_SMEM_UNALIGNED_DEP ${IMAGE}app_smem_unaligned_linker) if(CONFIG_ARM) - set(PRIV_STACK_DEP priv_stacks_prebuilt) + set(PRIV_STACK_DEP ${PRIV_STACKS_PREBUILT}) endif() endif() @@ -399,15 +408,15 @@ foreach(path endif() endforeach() -set_ifndef( DTS_BOARD_FIXUP_FILE ${BOARD_DIR}/dts_fixup.h) -set_ifndef( DTS_SOC_FIXUP_FILE ${SOC_DIR}/${ARCH}/${SOC_PATH}/dts_fixup.h) -set( DTS_APP_FIXUP_FILE ${APPLICATION_SOURCE_DIR}/dts_fixup.h) +set_ifndef(${IMAGE}DTS_BOARD_FIXUP_FILE ${BOARD_DIR}/dts_fixup.h) +set_ifndef(${IMAGE}DTS_SOC_FIXUP_FILE ${SOC_DIR}/${ARCH}/${SOC_PATH}/dts_fixup.h) +set( DTS_APP_FIXUP_FILE ${APPLICATION_SOURCE_DIR}/dts_fixup.h) -set_ifndef(DTS_CAT_OF_FIXUP_FILES ${ZEPHYR_BINARY_DIR}/include/generated/generated_dts_board_fixups.h) +set_ifndef(${IMAGE}DTS_CAT_OF_FIXUP_FILES ${ZEPHYR_BINARY_DIR}/include/generated/generated_dts_board_fixups.h) # Concatenate the fixups into a single header file for easy # #include'ing -file(WRITE ${DTS_CAT_OF_FIXUP_FILES} "/* May only be included by generated_dts_board.h */\n\n") +file(WRITE ${${IMAGE}DTS_CAT_OF_FIXUP_FILES} "/* May only be included by generated_dts_board.h */\n\n") foreach(fixup_file ${DTS_BOARD_FIXUP_FILE} ${DTS_SOC_FIXUP_FILE} @@ -416,7 +425,7 @@ foreach(fixup_file ) if(EXISTS ${fixup_file}) file(READ ${fixup_file} contents) - file(APPEND ${DTS_CAT_OF_FIXUP_FILES} "${contents}") + file(APPEND ${${IMAGE}DTS_CAT_OF_FIXUP_FILES} "${contents}") endif() endforeach() @@ -426,12 +435,12 @@ endforeach() # build are not exported to external build systems #5605"; when we # integrate with an external build system we read out all compiler # flags when the external project is created. So an external project -# defined in subsys or ext will not get global flags added by drivers/ +# defined in subsys or ext will not get image-global flags added by drivers/ # or tests/ as the subdirectories are ordered now. # # Another example of when the order matters is the reading and writing -# of global properties such as ZEPHYR_LIBS or -# GENERATED_KERNEL_OBJECT_FILES. +# of global properties such as ${IMAGE}ZEPHYR_LIBS or +# ${IMAGE}GENERATED_KERNEL_OBJECT_FILES. # # Arch is placed early because it defines important compiler flags # that must be exported to external build systems defined in @@ -470,7 +479,7 @@ if(EXISTS ${CMAKE_BINARY_DIR}/zephyr_modules.txt) # this binary_dir is created but stays empty. Object files land in # the main binary dir instead. # https://cmake.org/pipermail/cmake/2019-June/069547.html - add_subdirectory(${module_path} ${CMAKE_BINARY_DIR}/modules/${module_name}) + add_subdirectory(${module_path} ${CMAKE_CURRENT_BINARY_DIR}/modules/${module_name}) endforeach() endif() @@ -612,13 +621,10 @@ gen_kobj(KOBJ_INCLUDE_PATH) # Generate offsets.c.obj from offsets.c # Generate offsets.h from offsets.c.obj -set(OFFSETS_LIB offsets) - set(OFFSETS_C_PATH ${ARCH_DIR}/${ARCH}/core/offsets/offsets.c) set(OFFSETS_H_PATH ${PROJECT_BINARY_DIR}/include/generated/offsets.h) - add_library( ${OFFSETS_LIB} OBJECT ${OFFSETS_C_PATH}) -target_link_libraries(${OFFSETS_LIB} zephyr_interface) +target_link_libraries(${OFFSETS_LIB} ${IMAGE}zephyr_interface) add_dependencies( ${OFFSETS_LIB} ${SYSCALL_LIST_H_TARGET} ${SYSCALL_MACROS_H_TARGET} @@ -644,17 +650,18 @@ zephyr_get_include_directories_for_lang(C ZEPHYR_INCLUDES) add_subdirectory(kernel) # Read list content -get_property(ZEPHYR_LIBS_PROPERTY GLOBAL PROPERTY ZEPHYR_LIBS) +get_property(ZEPHYR_LIBS_PROPERTY GLOBAL PROPERTY ${IMAGE}ZEPHYR_LIBS) foreach(zephyr_lib ${ZEPHYR_LIBS_PROPERTY}) - # TODO: Could this become an INTERFACE property of zephyr_interface? + # TODO: Could this become an INTERFACE property of ${IMAGE}zephyr_interface? add_dependencies(${zephyr_lib} ${OFFSETS_H_TARGET}) endforeach() get_property(OUTPUT_FORMAT GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT) +unset(CODE_RELOCATION_DEP) if (CONFIG_CODE_DATA_RELOCATION) - set(CODE_RELOCATION_DEP code_relocation_source_lib) + set(CODE_RELOCATION_DEP ${IMAGE}code_relocation_source_lib) endif() # CONFIG_CODE_DATA_RELOCATION configure_linker_script( @@ -718,7 +725,7 @@ if(CONFIG_GEN_ISR_TABLES) ${GEN_ISR_TABLE_EXTRA_ARG} DEPENDS ${ZEPHYR_PREBUILT_EXECUTABLE} ) - set_property(GLOBAL APPEND PROPERTY GENERATED_KERNEL_SOURCE_FILES isr_tables.c) + set_property(GLOBAL APPEND PROPERTY ${IMAGE}GENERATED_KERNEL_SOURCE_FILES isr_tables.c) endif() if(CONFIG_CODE_DATA_RELOCATION) @@ -755,6 +762,14 @@ if(CONFIG_ARM AND CONFIG_USERSPACE) set(PRIV_STACKS_OUTPUT_OBJ priv_stacks_hash.c.obj) set(PRIV_STACKS_OUTPUT_OBJ_RENAMED priv_stacks_hash_renamed.o) + set(PRIV_STACKS_T ${IMAGE}priv_stacks) + set(PRIV_STACKS_OUTPUT_SRC_PRE_T ${IMAGE}priv_stacks_output_src_pre) + set(PRIV_STACKS_OUTPUT_SRC_T ${IMAGE}priv_stacks_output_src) + set(PRIV_STACKS_OUTPUT_LIB ${IMAGE}priv_stacks_output_lib) + set(PRIV_STACKS_OUTPUT_LIB_INTERFACE ${IMAGE}priv_stacks_output_lib_interface) + set(PRIV_STACKS_OUTPUT_OBJ_RENAMED_T ${IMAGE}priv_stacks_output_obj_renamed) + set(PRIV_STACKS_OUTPUT_OBJ_RENAMED_LIB ${IMAGE}priv_stacks_output_obj_renamed_lib) + # Essentially what we are doing here is extracting some information # out of the nearly finished elf file, generating the source code # for a hash table based on that information, and then compiling and @@ -769,13 +784,13 @@ if(CONFIG_ARM AND CONFIG_USERSPACE) COMMAND ${PYTHON_EXECUTABLE} ${GEN_PRIV_STACKS} - --kernel $ + --kernel $ --output ${PRIV_STACKS} $<$:--verbose> - DEPENDS priv_stacks_prebuilt + DEPENDS ${PRIV_STACKS_PREBUILT} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - add_custom_target(priv_stacks DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS}) + add_custom_target(${PRIV_STACKS_T} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS}) # Use gperf to generate C code (PRIV_STACKS_OUTPUT_SRC_PRE) which implements a # perfect hashtable based on PRIV_STACKS @@ -785,10 +800,11 @@ if(CONFIG_ARM AND CONFIG_USERSPACE) ${GPERF} -C --output-file ${PRIV_STACKS_OUTPUT_SRC_PRE} ${PRIV_STACKS} - DEPENDS priv_stacks ${PRIV_STACKS} + DEPENDS ${PRIV_STACKS_T} ${PRIV_STACKS} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - add_custom_target(priv_stacks_output_src_pre DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC_PRE}) + add_custom_target(${PRIV_STACKS_OUTPUT_SRC_PRE_T} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC_PRE}) # For our purposes the code/data generated by gperf is not optimal. # @@ -804,10 +820,11 @@ if(CONFIG_ARM AND CONFIG_USERSPACE) -o ${PRIV_STACKS_OUTPUT_SRC} -p "struct _k_priv_stack_map" $<$:--verbose> - DEPENDS priv_stacks_output_src_pre ${PRIV_STACKS_OUTPUT_SRC_PRE} + DEPENDS ${PRIV_STACKS_OUTPUT_SRC_PRE_T} ${PRIV_STACKS_OUTPUT_SRC_PRE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - add_custom_target(priv_stacks_output_src DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC}) + add_custom_target(${PRIV_STACKS_OUTPUT_SRC_T} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC}) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC} PROPERTIES COMPILE_DEFINITIONS "${compile_definitions_interface}") @@ -819,25 +836,29 @@ if(CONFIG_ARM AND CONFIG_USERSPACE) # We need precise control of where generated text/data ends up in the final # kernel image. Disable function/data sections and use objcopy to move # generated data into special section names - add_library(priv_stacks_output_lib STATIC + add_library(${PRIV_STACKS_OUTPUT_LIB} STATIC ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_SRC} ) # Turn off -ffunction-sections, etc. - # NB: Using a library instead of target_compile_options(priv_stacks_output_lib + # NB: Using a library instead of + # target_compile_options(${PRIV_STACKS_OUTPUT_LIB} # [...]) because a library's options have precedence - add_library(priv_stacks_output_lib_interface INTERFACE) + add_library(${PRIV_STACKS_OUTPUT_LIB_INTERFACE} INTERFACE) foreach(incl ${include_dir_in_interface}) - target_include_directories(priv_stacks_output_lib_interface INTERFACE ${incl}) + target_include_directories(${PRIV_STACKS_OUTPUT_LIB_INTERFACE} INTERFACE ${incl}) endforeach() foreach(incl ${sys_include_dir_in_interface}) target_include_directories(priv_stacks_output_lib_interface SYSTEM INTERFACE ${incl}) endforeach() - target_link_libraries(priv_stacks_output_lib priv_stacks_output_lib_interface) + target_link_libraries(${PRIV_STACKS_OUTPUT_LIB} + ${PRIV_STACKS_OUTPUT_LIB_INTERFACE}) - set(PRIV_STACKS_OUTPUT_OBJ_PATH ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/priv_stacks_output_lib.dir/${PRIV_STACKS_OUTPUT_OBJ}) + + set(PRIV_STACKS_OUTPUT_OBJ_PATH + ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PRIV_STACKS_OUTPUT_LIB}.dir/${PRIV_STACKS_OUTPUT_OBJ}) set(obj_copy_cmd "") set(obj_copy_sections_rename @@ -855,23 +876,25 @@ if(CONFIG_ARM AND CONFIG_USERSPACE) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_OBJ_RENAMED} ${obj_copy_cmd} - DEPENDS priv_stacks_output_lib + DEPENDS ${PRIV_STACKS_OUTPUT_LIB} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - add_custom_target(priv_stacks_output_obj_renamed DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_OBJ_RENAMED}) + add_custom_target(${PRIV_STACKS_OUTPUT_OBJ_RENAMED_T} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_OBJ_RENAMED}) - add_library(priv_stacks_output_obj_renamed_lib STATIC IMPORTED GLOBAL) + add_library(${PRIV_STACKS_OUTPUT_OBJ_RENAMED_LIB} STATIC IMPORTED GLOBAL) set_property( - TARGET priv_stacks_output_obj_renamed_lib + TARGET ${PRIV_STACKS_OUTPUT_OBJ_RENAMED_LIB} PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${PRIV_STACKS_OUTPUT_OBJ_RENAMED} ) add_dependencies( - priv_stacks_output_obj_renamed_lib - priv_stacks_output_obj_renamed + ${PRIV_STACKS_OUTPUT_OBJ_RENAMED_LIB} + ${PRIV_STACKS_OUTPUT_OBJ_RENAMED_T} ) - set_property(GLOBAL APPEND PROPERTY GENERATED_KERNEL_OBJECT_FILES priv_stacks_output_obj_renamed_lib) + set_property(GLOBAL APPEND PROPERTY ${IMAGE}GENERATED_KERNEL_OBJECT_FILES + ${PRIV_STACKS_OUTPUT_OBJ_RENAMED_LIB}) endif() # Warning: most of this gperf code is duplicated above for @@ -886,6 +909,13 @@ if(CONFIG_USERSPACE) set(OUTPUT_OBJ kobject_hash.c.obj) set(OUTPUT_OBJ_RENAMED kobject_hash_renamed.o) + set(OUTPUT_SRC_PRE_T ${IMAGE}output_src_pre) + set(OBJ_LIST_T ${IMAGE}obj_list) + set(OUTPUT_SRC_T ${IMAGE}output_src) + set(OUTPUT_LIB ${IMAGE}output_lib) + set(OUTPUT_LIB_INTERFACE ${IMAGE}output_lib_interface) + set(OUTPUT_OBJ_RENAMED_T ${IMAGE}output_obj_renamed) + set(OUTPUT_OBJ_RENAMED_LIB ${IMAGE}output_obj_renamed_lib) # Essentially what we are doing here is extracting some information # out of the nearly finished elf file, generating the source code # for a hash table based on that information, and then compiling and @@ -906,7 +936,7 @@ if(CONFIG_USERSPACE) DEPENDS ${ZEPHYR_PREBUILT_EXECUTABLE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - add_custom_target(obj_list DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OBJ_LIST}) + add_custom_target(${OBJ_LIST_T} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OBJ_LIST}) # Use gperf to generate C code (OUTPUT_SRC_PRE) which implements a # perfect hashtable based on OBJ_LIST @@ -916,10 +946,10 @@ if(CONFIG_USERSPACE) ${GPERF} --output-file ${OUTPUT_SRC_PRE} ${OBJ_LIST} - DEPENDS obj_list ${OBJ_LIST} + DEPENDS ${OBJ_LIST_T} ${OBJ_LIST} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - add_custom_target(output_src_pre DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SRC_PRE}) + add_custom_target(${OUTPUT_SRC_PRE_T} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SRC_PRE}) # For our purposes the code/data generated by gperf is not optimal. # @@ -935,15 +965,15 @@ if(CONFIG_USERSPACE) -o ${OUTPUT_SRC} -p "struct _k_object" $<$:--verbose> - DEPENDS output_src_pre ${OUTPUT_SRC_PRE} + DEPENDS ${OUTPUT_SRC_PRE_T} ${OUTPUT_SRC_PRE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - add_custom_target(output_src DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SRC}) + add_custom_target(${OUTPUT_SRC_T} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SRC}) # We need precise control of where generated text/data ends up in the final # kernel image. Disable function/data sections and use objcopy to move # generated data into special section names - add_library(output_lib STATIC + add_library(${OUTPUT_LIB} STATIC ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SRC} ) @@ -954,21 +984,21 @@ if(CONFIG_USERSPACE) PROPERTIES COMPILE_DEFINITIONS "${compile_definitions_interface}") # Turn off -ffunction-sections, etc. - # NB: Using a library instead of target_compile_options(output_lib + # NB: Using a library instead of target_compile_options(${OUTPUT_LIB} # [...]) because a library's options have precedence - add_library(output_lib_interface INTERFACE) + add_library(${OUTPUT_LIB}_interface INTERFACE) - target_link_libraries(output_lib output_lib_interface) + target_link_libraries(${OUTPUT_LIB} ${OUTPUT_LIB_INTERFACE}) foreach(incl ${include_dir_in_interface}) - target_include_directories(output_lib_interface INTERFACE ${incl}) + target_include_directories(${OUTPUT_LIB_INTERFACE} INTERFACE ${incl}) endforeach() foreach(incl ${sys_include_dir_in_interface}) target_include_directories(output_lib_interface SYSTEM INTERFACE ${incl}) endforeach() - set(OUTPUT_OBJ_PATH ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/output_lib.dir/${OUTPUT_OBJ}) + set(OUTPUT_OBJ_PATH ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${OUTPUT_LIB}.dir/${OUTPUT_OBJ}) set(obj_copy_cmd "") set(obj_copy_sections_rename @@ -985,28 +1015,29 @@ if(CONFIG_USERSPACE) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_OBJ_RENAMED} ${obj_copy_cmd} - DEPENDS output_lib + DEPENDS ${OUTPUT_LIB} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - add_custom_target(output_obj_renamed DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_OBJ_RENAMED}) + add_custom_target(${OUTPUT_OBJ_RENAMED_T} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_OBJ_RENAMED}) - add_library(output_obj_renamed_lib STATIC IMPORTED GLOBAL) + add_library(${OUTPUT_OBJ_RENAMED_LIB} STATIC IMPORTED GLOBAL) set_property( - TARGET output_obj_renamed_lib + TARGET ${OUTPUT_OBJ_RENAMED_LIB} PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_OBJ_RENAMED} ) add_dependencies( - output_obj_renamed_lib - output_obj_renamed + ${OUTPUT_OBJ_RENAMED_LIB} + ${OUTPUT_OBJ_RENAMED_T} ) - set_property(GLOBAL APPEND PROPERTY GENERATED_KERNEL_OBJECT_FILES output_obj_renamed_lib) + set_property(GLOBAL APPEND PROPERTY ${IMAGE}GENERATED_KERNEL_OBJECT_FILES + ${OUTPUT_OBJ_RENAMED_LIB}) endif() # Read global variables into local variables -get_property(GKOF GLOBAL PROPERTY GENERATED_KERNEL_OBJECT_FILES) -get_property(GKSF GLOBAL PROPERTY GENERATED_KERNEL_SOURCE_FILES) +get_property(GKOF GLOBAL PROPERTY ${IMAGE}GENERATED_KERNEL_OBJECT_FILES) +get_property(GKSF GLOBAL PROPERTY ${IMAGE}GENERATED_KERNEL_SOURCE_FILES) get_property(CSTD GLOBAL PROPERTY CSTD) @@ -1103,7 +1134,7 @@ if(CONFIG_USERSPACE) ${NEWLIB_PART} ${MBEDTLS_PART} $<$:--verbose> DEPENDS - kernel + ${KERNEL_LIBRARY} ${ZEPHYR_LIBS_PROPERTY} app_smem_unaligned_prebuilt WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/ @@ -1122,29 +1153,29 @@ if(CONFIG_USERSPACE AND CONFIG_ARM) ) add_custom_target( - linker_priv_stacks_script + ${IMAGE}linker_priv_stacks_script DEPENDS linker_priv_stacks.cmd ) set_property(TARGET - linker_priv_stacks_script + ${IMAGE}linker_priv_stacks_script PROPERTY INCLUDE_DIRECTORIES ${ZEPHYR_INCLUDE_DIRS} ) - set(PRIV_STACK_LIB priv_stacks_output_obj_renamed_lib) - add_executable( priv_stacks_prebuilt misc/empty_file.c) + set(PRIV_STACK_LIB ${IMAGE}priv_stacks_output_obj_renamed_lib) + add_executable( ${PRIV_STACKS_PREBUILT} misc/empty_file.c) toolchain_ld_link_elf( - TARGET_ELF priv_stacks_prebuilt - OUTPUT_MAP ${PROJECT_BINARY_DIR}/priv_stacks_prebuilt.map + TARGET_ELF ${PRIV_STACKS_PREBUILT} + OUTPUT_MAP ${PROJECT_BINARY_DIR}/${PRIV_STACKS_PREBUILT}.map LIBRARIES_PRE_SCRIPT "" LINKER_SCRIPT ${PROJECT_BINARY_DIR}/linker_priv_stacks.cmd LIBRARIES_POST_SCRIPT "" DEPENDENCIES ${CODE_RELOCATION_DEP} ) - set_property(TARGET priv_stacks_prebuilt PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker_priv_stacks.cmd) - add_dependencies( priv_stacks_prebuilt linker_priv_stacks_script ${OFFSETS_LIB}) + set_property(TARGET ${PRIV_STACKS_PREBUILT} PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker_priv_stacks.cmd) + add_dependencies( ${PRIV_STACKS_PREBUILT} ${IMAGE}linker_priv_stacks_script ${OFFSETS_LIB}) endif() # FIXME: Is there any way to get rid of empty_file.c? @@ -1179,7 +1210,7 @@ else() ${OFFSETS_H_TARGET} ) - set(LINKER_PASS_FINAL_SCRIPT_TARGET linker_pass_final_script_target) + set(LINKER_PASS_FINAL_SCRIPT_TARGET ${IMAGE}linker_pass_final_script_target) add_custom_target( ${LINKER_PASS_FINAL_SCRIPT_TARGET} DEPENDS @@ -1415,14 +1446,14 @@ list(APPEND ${extra_post_build_commands} ) -get_property(extra_post_build_byproducts +get_property(${IMAGE}extra_post_build_byproducts GLOBAL PROPERTY - extra_post_build_byproducts + ${IMAGE}extra_post_build_byproducts ) list(APPEND post_build_byproducts - ${extra_post_build_byproducts} + ${${IMAGE}extra_post_build_byproducts} ) # Add post_build_commands to post-process the final .elf file produced by @@ -1436,34 +1467,14 @@ add_custom_command( ${post_build_byproducts} COMMENT "Generating files from ${KERNEL_ELF_NAME} for board: ${BOARD}" # NB: COMMENT only works for some CMake-Generators + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) -# To populate with hex files to merge, do the following: -# set_property(GLOBAL APPEND PROPERTY HEX_FILES_TO_MERGE ${my_local_list}) -# Note that the zephyr.hex file will not be included automatically. -get_property(HEX_FILES_TO_MERGE GLOBAL PROPERTY HEX_FILES_TO_MERGE) -if(HEX_FILES_TO_MERGE) - # Merge in out-of-tree hex files. - set(MERGED_HEX_NAME merged.hex) - - add_custom_command( - OUTPUT ${MERGED_HEX_NAME} - COMMAND - ${PYTHON_EXECUTABLE} - ${ZEPHYR_BASE}/scripts/mergehex.py - -o ${MERGED_HEX_NAME} - ${HEX_FILES_TO_MERGE} - DEPENDS ${HEX_FILES_TO_MERGE} ${logical_target_for_zephyr_elf} - ) - - add_custom_target(mergehex ALL DEPENDS ${MERGED_HEX_NAME}) - list(APPEND FLASH_DEPS mergehex) -endif() if(EMU_PLATFORM) include(${ZEPHYR_BASE}/cmake/emu/${EMU_PLATFORM}.cmake) else() - add_custom_target(run + add_custom_target(${IMAGE}run COMMAND ${CMAKE_COMMAND} -E echo "===================================================" @@ -1473,7 +1484,6 @@ else() endif() add_subdirectory(cmake/flash) -add_subdirectory(cmake/usage) add_subdirectory(cmake/reports) if(NOT CONFIG_TEST) diff --git a/arch/arm/core/cortex_m/tz/CMakeLists.txt b/arch/arm/core/cortex_m/tz/CMakeLists.txt index 04c398adb8a747..3957cb149413aa 100644 --- a/arch/arm/core/cortex_m/tz/CMakeLists.txt +++ b/arch/arm/core/cortex_m/tz/CMakeLists.txt @@ -22,7 +22,7 @@ if(CONFIG_ARM_FIRMWARE_HAS_SECURE_ENTRY_FUNCS) # Indicate that the entry veneers library file is created during linking of this firmware. set_property( GLOBAL APPEND PROPERTY - extra_post_build_byproducts + ${IMAGE}extra_post_build_byproducts ${CMAKE_BINARY_DIR}/${CONFIG_ARM_ENTRY_VENEERS_LIB_NAME} ) endif() diff --git a/cmake/app/boilerplate.cmake b/cmake/app/boilerplate.cmake index 604fba339f5da5..e2792282d44b00 100644 --- a/cmake/app/boilerplate.cmake +++ b/cmake/app/boilerplate.cmake @@ -28,42 +28,72 @@ cmake_policy(SET CMP0002 NEW) # CMP0079: "target_link_libraries() allows use with targets in other directories" cmake_policy(SET CMP0079 OLD) -define_property(GLOBAL PROPERTY ZEPHYR_LIBS - BRIEF_DOCS "Global list of all Zephyr CMake libs that should be linked in" - FULL_DOCS "Global list of all Zephyr CMake libs that should be linked in. +get_property(IMAGE GLOBAL PROPERTY IMAGE) + +if(IMAGE) + set(FIRST_BOILERPLATE_EXECUTION 0) +else() + set(FIRST_BOILERPLATE_EXECUTION 1) +endif() + +if (NOT FIRST_BOILERPLATE_EXECUTION) + # Clear the Kconfig namespace of the other image. + # Since the CMake context of each subsequent image is loaded by "add_subdirectory" + # the Kconfig namespace is automatically restored by CMake. + get_cmake_property(names VARIABLES) + foreach (name ${names}) + if("${name}" MATCHES "^CONFIG_") + # When a variable starts with 'CONFIG_' it is assumed to be a + # Kconfig symbol. + unset(${name}) + endif() + endforeach() +endif() + +define_property(GLOBAL PROPERTY ${IMAGE}ZEPHYR_LIBS + BRIEF_DOCS "Image-global list of all Zephyr CMake libs that should be linked in" + FULL_DOCS "Image-global list of all Zephyr CMake libs that should be linked in zephyr_library() appends libs to this list.") -set_property(GLOBAL PROPERTY ZEPHYR_LIBS "") +set_property(GLOBAL PROPERTY ${IMAGE}ZEPHYR_LIBS "") -define_property(GLOBAL PROPERTY ZEPHYR_INTERFACE_LIBS - BRIEF_DOCS "Global list of all Zephyr interface libs that should be linked in." - FULL_DOCS "Global list of all Zephyr interface libs that should be linked in. +define_property(GLOBAL PROPERTY ${IMAGE}ZEPHYR_INTERFACE_LIBS + BRIEF_DOCS "Image-global list of all Zephyr interface libs that should be linked in." + FULL_DOCS "Image-global list of all Zephyr interface libs that should be linked in. zephyr_interface_library_named() appends libs to this list.") -set_property(GLOBAL PROPERTY ZEPHYR_INTERFACE_LIBS "") +set_property(GLOBAL PROPERTY ${IMAGE}ZEPHYR_INTERFACE_LIBS "") -define_property(GLOBAL PROPERTY GENERATED_KERNEL_OBJECT_FILES +define_property(GLOBAL PROPERTY ${IMAGE}GENERATED_KERNEL_OBJECT_FILES BRIEF_DOCS "Object files that are generated after Zephyr has been linked once." FULL_DOCS "\ Object files that are generated after Zephyr has been linked once.\ May include mmu tables, etc." ) -set_property(GLOBAL PROPERTY GENERATED_KERNEL_OBJECT_FILES "") +set_property(GLOBAL PROPERTY ${IMAGE}GENERATED_KERNEL_OBJECT_FILES "") -define_property(GLOBAL PROPERTY GENERATED_KERNEL_SOURCE_FILES +define_property(GLOBAL PROPERTY ${IMAGE}GENERATED_KERNEL_SOURCE_FILES BRIEF_DOCS "Source files that are generated after Zephyr has been linked once." FULL_DOCS "\ Source files that are generated after Zephyr has been linked once.\ May include isr_tables.c etc." ) -set_property(GLOBAL PROPERTY GENERATED_KERNEL_SOURCE_FILES "") +set_property(GLOBAL PROPERTY ${IMAGE}GENERATED_KERNEL_SOURCE_FILES "") + +set(APPLICATION_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(APPLICATION_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) -set(APPLICATION_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Application Source Directory") -set(APPLICATION_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "Application Binary Directory") +message(STATUS "Using application from '${APPLICATION_SOURCE_DIR}'") set(__build_dir ${CMAKE_CURRENT_BINARY_DIR}/zephyr) set(PROJECT_BINARY_DIR ${__build_dir}) -add_custom_target(code_data_relocation_target) +define_property(GLOBAL PROPERTY ${IMAGE}PROJECT_BINARY_DIR + BRIEF_DOCS "Build directory (PROJECT_BINARY_DIR) for the ${IMAGE} image." + FULL_DOCS "To be used to access e.g. this image's hex file." + ) +set_property(GLOBAL PROPERTY ${IMAGE}PROJECT_BINARY_DIR ${PROJECT_BINARY_DIR}) + +add_custom_target(${IMAGE}code_data_relocation_target) # CMake's 'project' concept has proven to not be very useful for Zephyr # due in part to how Zephyr is organized and in part to it not fitting well @@ -94,93 +124,147 @@ include(CheckCXXCompilerFlag) include(${ZEPHYR_BASE}/cmake/extensions.cmake) include(${ZEPHYR_BASE}/cmake/version.cmake) # depends on hex.cmake -# -# Find tools -# - -include(${ZEPHYR_BASE}/cmake/python.cmake) -include(${ZEPHYR_BASE}/cmake/git.cmake) # depends on version.cmake -include(${ZEPHYR_BASE}/cmake/ccache.cmake) - if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) message(FATAL_ERROR "Source directory equals build directory.\ In-source builds are not supported.\ Please specify a build directory, e.g. cmake -Bbuild -H.") endif() -add_custom_target( - pristine - COMMAND ${CMAKE_COMMAND} -P ${ZEPHYR_BASE}/cmake/pristine.cmake - # Equivalent to rm -rf build/* - ) - # Dummy add to generate files. zephyr_linker_sources(SECTIONS) -# The BOARD can be set by 3 sources. Through environment variables, -# through the cmake CLI, and through CMakeLists.txt. -# -# CLI has the highest precedence, then comes environment variables, -# and then finally CMakeLists.txt. -# -# A user can ignore all the precedence rules if he simply always uses -# the same source. E.g. always specifies -DBOARD= on the command line, -# always has an environment variable set, or always has a set(BOARD -# foo) line in his CMakeLists.txt and avoids mixing sources. -# -# The selected BOARD can be accessed through the variable 'BOARD'. +if(FIRST_BOILERPLATE_EXECUTION) + # + # Find tools + # -# Read out the cached board value if present -get_property(cached_board_value CACHE BOARD PROPERTY VALUE) + include(${ZEPHYR_BASE}/cmake/python.cmake) + include(${ZEPHYR_BASE}/cmake/git.cmake) # depends on version.cmake + include(${ZEPHYR_BASE}/cmake/ccache.cmake) -# There are actually 4 sources, the three user input sources, and the -# previously used value (CACHED_BOARD). The previously used value has -# precedence, and if we detect that the user is trying to change the -# value we give him a warning about needing to clean the build -# directory to be able to change boards. + add_custom_target( + pristine + COMMAND ${CMAKE_COMMAND} -P ${ZEPHYR_BASE}/cmake/pristine.cmake + # Equivalent to rm -rf build/* + ) -set(board_cli_argument ${cached_board_value}) # Either new or old -if(board_cli_argument STREQUAL CACHED_BOARD) - # We already have a CACHED_BOARD so there is no new input on the CLI - unset(board_cli_argument) -endif() + # 'BOARD_ROOT' is a prioritized list of directories where boards may + # be found. It always includes ${ZEPHYR_BASE} at the lowest priority. + list(APPEND BOARD_ROOT ${ZEPHYR_BASE}) -set(board_app_cmake_lists ${BOARD}) -if(cached_board_value STREQUAL BOARD) - # The app build scripts did not set a default, The BOARD we are - # reading is the cached value from the CLI - unset(board_app_cmake_lists) -endif() + # The BOARD can be set by 3 sources. Through environment variables, + # through the cmake CLI, and through CMakeLists.txt. + # + # CLI has the highest precedence, then comes environment variables, + # and then finally CMakeLists.txt. + # + # A user can ignore all the precedence rules if he simply always uses + # the same source. E.g. always specifies -DBOARD= on the command line, + # always has an environment variable set, or always has a set(BOARD + # foo) line in his CMakeLists.txt and avoids mixing sources. + # + # The selected BOARD can be accessed through the variable 'BOARD'. -if(CACHED_BOARD) - # Warn the user if it looks like he is trying to change the board - # without cleaning first - if(board_cli_argument) - if(NOT (CACHED_BOARD STREQUAL board_cli_argument)) - message(WARNING "The build directory must be cleaned pristinely when changing boards") - # TODO: Support changing boards without requiring a clean build + # Read out the cached board value if present + get_property(cached_board_value CACHE BOARD PROPERTY VALUE) + + # There are actually 4 sources, the three user input sources, and the + # previously used value (CACHED_BOARD). The previously used value has + # precedence, and if we detect that the user is trying to change the + # value we give him a warning about needing to clean the build + # directory to be able to change boards. + + set(board_cli_argument ${cached_board_value}) # Either new or old + if(board_cli_argument STREQUAL CACHED_BOARD) + # We already have a CACHED_BOARD so there is no new input on the CLI + unset(board_cli_argument) + endif() + + set(board_app_cmake_lists ${BOARD}) + if(cached_board_value STREQUAL BOARD) + # The app build scripts did not set a default, The BOARD we are + # reading is the cached value from the CLI + unset(board_app_cmake_lists) + endif() + + if(CACHED_BOARD) + # Warn the user if it looks like he is trying to change the board + # without cleaning first + if(board_cli_argument) + if(NOT (CACHED_BOARD STREQUAL board_cli_argument)) + message(WARNING "The build directory must be cleaned pristinely when changing boards") + # TODO: Support changing boards without requiring a clean build + endif() endif() + + set(BOARD ${CACHED_BOARD}) + elseif(board_cli_argument) + set(BOARD ${board_cli_argument}) + + elseif(DEFINED ENV{BOARD}) + set(BOARD $ENV{BOARD}) + + elseif(board_app_cmake_lists) + set(BOARD ${board_app_cmake_lists}) + + else() + message(FATAL_ERROR "BOARD is not being defined on the CMake command-line in the environment or by the app.") endif() - set(BOARD ${CACHED_BOARD}) -elseif(board_cli_argument) - set(BOARD ${board_cli_argument}) + assert(BOARD "BOARD not set") + message(STATUS "Selected BOARD ${BOARD}") -elseif(DEFINED ENV{BOARD}) - set(BOARD $ENV{BOARD}) + # Store the selected board in the cache + set(CACHED_BOARD ${BOARD} CACHE STRING "Selected board") -elseif(board_app_cmake_lists) - set(BOARD ${board_app_cmake_lists}) + if(NOT ARCH_ROOT) + set(ARCH_DIR ${ZEPHYR_BASE}/arch) + else() + set(ARCH_DIR ${ARCH_ROOT}/arch) + endif() -else() - message(FATAL_ERROR "BOARD is not being defined on the CMake command-line in the environment or by the app.") -endif() + if(NOT SOC_ROOT) + set(SOC_DIR ${ZEPHYR_BASE}/soc) + else() + set(SOC_DIR ${SOC_ROOT}/soc) + endif() + + # Prevent CMake from testing the toolchain + set(CMAKE_C_COMPILER_FORCED 1) + set(CMAKE_CXX_COMPILER_FORCED 1) + + include(${ZEPHYR_BASE}/cmake/host-tools.cmake) -assert(BOARD "BOARD not set") -message(STATUS "Selected BOARD ${BOARD}") + string(REPLACE ";" " " BOARD_ROOT_SPACE_SEPARATED "${BOARD_ROOT}") + string(REPLACE ";" " " SHIELD_LIST_SPACE_SEPARATED "${SHIELD_LIST}") -# Store the selected board in the cache -set(CACHED_BOARD ${BOARD} CACHE STRING "Selected board") + # NB: The reason it is 'usage' and not help is that CMake already + # defines a target 'help' + add_custom_target( + usage + ${CMAKE_COMMAND} + -DBOARD_ROOT_SPACE_SEPARATED=${BOARD_ROOT_SPACE_SEPARATED} + -DSHIELD_LIST_SPACE_SEPARATED=${SHIELD_LIST_SPACE_SEPARATED} + -P ${ZEPHYR_BASE}/cmake/usage/usage.cmake + ) + + include(${ZEPHYR_BASE}/cmake/zephyr_module.cmake) + + if(NOT DEFINED USER_CACHE_DIR) + find_appropriate_cache_directory(USER_CACHE_DIR) + endif() + message(STATUS "Cache files will be written to: ${USER_CACHE_DIR}") +else() # NOT FIRST_BOILERPLATE_EXECUTION + + # Have the child image select the same BOARD that was selected by + # the parent. + set(BOARD ${CACHED_BOARD}) + + unset(${IMAGE}DTC_OVERLAY_FILE) + if(EXISTS ${APPLICATION_SOURCE_DIR}/${BOARD}.overlay) + set(${IMAGE}DTC_OVERLAY_FILE ${APPLICATION_SOURCE_DIR}/${BOARD}.overlay) + endif() +endif(FIRST_BOILERPLATE_EXECUTION) # The SHIELD can be set by 3 sources. Through environment variables, # through the cmake CLI, and through CMakeLists.txt. @@ -188,15 +272,18 @@ set(CACHED_BOARD ${BOARD} CACHE STRING "Selected board") # CLI has the highest precedence, then comes environment variables, # and then finally CMakeLists.txt. # -# A user can ignore all the precedence rules if he simply always uses +# A user can ignore all the precedence rules if she simply always uses # the same source. E.g. always specifies -DSHIELD= on the command line, # always has an environment variable set, or always has a set(SHIELD -# foo) line in his CMakeLists.txt and avoids mixing sources. +# foo) line in her CMakeLists.txt and avoids mixing sources. # # The selected SHIELD can be accessed through the variable 'SHIELD'. +# +# To specify a SHIELD specifically for an image, prefix with the image +# name. E.g. -Dmcuboot_SHIELD= on the command line. # Read out the cached shield value if present -get_property(cached_shield_value CACHE SHIELD PROPERTY VALUE) +get_property(cached_shield_value CACHE ${IMAGE}SHIELD PROPERTY VALUE) # There are actually 4 sources, the three user input sources, and the # previously used value (CACHED_SHIELD). The previously used value has @@ -205,70 +292,64 @@ get_property(cached_shield_value CACHE SHIELD PROPERTY VALUE) # directory to be able to change shields. set(shield_cli_argument ${cached_shield_value}) # Either new or old -if(shield_cli_argument STREQUAL CACHED_SHIELD) +if(shield_cli_argument STREQUAL ${IMAGE}CACHED_SHIELD) # We already have a CACHED_SHIELD so there is no new input on the CLI unset(shield_cli_argument) endif() -set(shield_app_cmake_lists ${SHIELD}) -if(cached_shield_value STREQUAL SHIELD) +set(shield_app_cmake_lists ${${IMAGE}SHIELD}) +if(cached_shield_value STREQUAL ${IMAGE}SHIELD) # The app build scripts did not set a default, The SHIELD we are # reading is the cached value from the CLI unset(shield_app_cmake_lists) endif() -if(CACHED_SHIELD) - # Warn the user if it looks like he is trying to change the shield +if(${IMAGE}CACHED_SHIELD) + # Warn the user if it looks like she is trying to change the shield # without cleaning first if(shield_cli_argument) - if(NOT (CACHED_SHIELD STREQUAL shield_cli_argument)) + if(NOT (${IMAGE}CACHED_SHIELD STREQUAL shield_cli_argument)) message(WARNING "The build directory must be cleaned pristinely when changing shields") # TODO: Support changing shields without requiring a clean build endif() endif() - set(SHIELD ${CACHED_SHIELD}) + set(${IMAGE}SHIELD ${${IMAGE}CACHED_SHIELD}) elseif(shield_cli_argument) - set(SHIELD ${shield_cli_argument}) + set(${IMAGE}SHIELD ${shield_cli_argument}) -elseif(DEFINED ENV{SHIELD}) - set(SHIELD $ENV{SHIELD}) +elseif(DEFINED ENV{${IMAGE}SHIELD}) + set(${IMAGE}SHIELD $ENV{${IMAGE}SHIELD}) elseif(shield_app_cmake_lists) - set(SHIELD ${shield_app_cmake_lists}) + set(${IMAGE}SHIELD ${shield_app_cmake_lists}) endif() # Store the selected shield in the cache -set(CACHED_SHIELD ${SHIELD} CACHE STRING "Selected shield") - -# 'BOARD_ROOT' is a prioritized list of directories where boards may -# be found. It always includes ${ZEPHYR_BASE} at the lowest priority. -list(APPEND BOARD_ROOT ${ZEPHYR_BASE}) - -if(NOT SOC_ROOT) - set(SOC_DIR ${ZEPHYR_BASE}/soc) -else() - set(SOC_DIR ${SOC_ROOT}/soc) -endif() - -if(NOT ARCH_ROOT) - set(ARCH_DIR ${ZEPHYR_BASE}/arch) -else() - set(ARCH_DIR ${ARCH_ROOT}/arch) -endif() +set(${IMAGE}CACHED_SHIELD ${${IMAGE}SHIELD} CACHE STRING "Selected shield") # Use BOARD to search for a '_defconfig' file. # e.g. zephyr/boards/arm/96b_carbon_nrf51/96b_carbon_nrf51_defconfig. # When found, use that path to infer the ARCH we are building for. foreach(root ${BOARD_ROOT}) - # NB: find_path will return immediately if the output variable is - # already set - find_path(BOARD_DIR - NAMES ${BOARD}_defconfig - PATHS ${root}/boards/*/* - NO_DEFAULT_PATH - ) + if (NOT BOARD_DIR) + # NB: find_path will return immediately if the output variable is + # already set this because it will set the output variable in the + # CACHE as well. + find_path(TMP_BOARD_DIR + NAMES ${BOARD}_defconfig + PATHS ${root}/boards/*/* + NO_DEFAULT_PATH + ) + set(BOARD_DIR ${TMP_BOARD_DIR}) + unset(TMP_BOARD_DIR CACHE) + endif() + + # Ensure that BOARD_DIR is not in CACHE so that different images can use + # different BOARD_DIR. + if(BOARD_DIR AND NOT (${root} STREQUAL ${ZEPHYR_BASE})) + message("USING OUT OF TREE BOARD") set(USING_OUT_OF_TREE_BOARD 1) endif() @@ -360,6 +441,15 @@ foreach(root ${BOARD_ROOT}) endif() endforeach() endif() + + if(DEFINED SHIELD AND DEFINED NOT_FOUND_SHIELD_LIST) + foreach (s ${NOT_FOUND_SHIELD_LIST}) + message("No shield named '${s}' found") + endforeach() + print_usage() + unset(CACHED_SHIELD CACHE) + message(FATAL_ERROR "Invalid usage") + endif() endforeach() if(NOT BOARD_DIR) @@ -369,45 +459,52 @@ if(NOT BOARD_DIR) message(FATAL_ERROR "Invalid usage") endif() -if(DEFINED SHIELD AND DEFINED NOT_FOUND_SHIELD_LIST) - foreach (s ${NOT_FOUND_SHIELD_LIST}) - message("No shield named '${s}' found") - endforeach() - print_usage() - unset(CACHED_SHIELD CACHE) - message(FATAL_ERROR "Invalid usage") -endif() +unset(BOARD_ARCH_DIR CACHE) +unset(BOARD_FAMILY CACHE) +unset(ARCH CACHE) -get_filename_component(BOARD_ARCH_DIR ${BOARD_DIR} DIRECTORY) +get_filename_component(BOARD_ARCH_DIR ${BOARD_DIR} DIRECTORY) get_filename_component(BOARD_FAMILY ${BOARD_DIR} NAME) get_filename_component(ARCH ${BOARD_ARCH_DIR} NAME) -if(CONF_FILE) - # CONF_FILE has either been specified on the cmake CLI or is already - # in the CMakeCache.txt. This has precedence over the environment - # variable CONF_FILE and the default prj.conf -elseif(DEFINED ENV{CONF_FILE}) - set(CONF_FILE $ENV{CONF_FILE}) +# DTS should be close to kconfig because CONFIG_ variables from +# kconfig and dts should be available at the same time. +# +# The DT system uses a C preprocessor for it's code generation needs. +# This creates an awkward chicken-and-egg problem, because we don't +# always know exactly which toolchain the user needs until we know +# more about the target, e.g. after DT and Kconfig. +# +# To resolve this we find "some" C toolchain, configure it generically +# with the minimal amount of configuration needed to have it +# preprocess DT sources, and then, after we have finished processing +# both DT and Kconfig we complete the target-specific configuration, +# and possibly change the toolchain. + +# Populate USER_CACHE_DIR with a directory that user applications may +# write cache files to. +include(${ZEPHYR_BASE}/cmake/generic_toolchain.cmake) + +if(${IMAGE}CONF_FILE) + # ${IMAGE}CONF_FILE has either been specified on the cmake CLI or is already + # in the CMakeCache.txt. This has precedence over the environment + # variable ${IMAGE}CONF_FILE and the default prj.conf +elseif(DEFINED ENV{${IMAGE}CONF_FILE}) + set(${IMAGE}CONF_FILE $ENV{${IMAGE}CONF_FILE}) elseif(COMMAND set_conf_file) message(WARNING "'set_conf_file' is deprecated, it will be removed in a future release.") set_conf_file() - elseif(EXISTS ${APPLICATION_SOURCE_DIR}/prj_${BOARD}.conf) - set(CONF_FILE ${APPLICATION_SOURCE_DIR}/prj_${BOARD}.conf) + set(${IMAGE}CONF_FILE ${APPLICATION_SOURCE_DIR}/prj_${BOARD}.conf) elseif(EXISTS ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf) - set(CONF_FILE ${APPLICATION_SOURCE_DIR}/prj.conf ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf) + set(${IMAGE}CONF_FILE ${APPLICATION_SOURCE_DIR}/prj.conf ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf) elseif(EXISTS ${APPLICATION_SOURCE_DIR}/prj.conf) - set(CONF_FILE ${APPLICATION_SOURCE_DIR}/prj.conf) + set(${IMAGE}CONF_FILE ${APPLICATION_SOURCE_DIR}/prj.conf) endif() -set(CONF_FILE ${CONF_FILE} CACHE STRING "If desired, you can build the application using\ -the configuration settings specified in an alternate .conf file using this parameter. \ -These settings will override the settings in the application’s .config file or its default .conf file.\ -Multiple files may be listed, e.g. CONF_FILE=\"prj1.conf prj2.conf\"") - if(ZEPHYR_EXTRA_MODULES) # ZEPHYR_EXTRA_MODULES has either been specified on the cmake CLI or is # already in the CMakeCache.txt. This has precedence over the environment @@ -416,47 +513,35 @@ elseif(DEFINED ENV{ZEPHYR_EXTRA_MODULES}) set(ZEPHYR_EXTRA_MODULES $ENV{ZEPHYR_EXTRA_MODULES}) endif() -if(DTC_OVERLAY_FILE) - # DTC_OVERLAY_FILE has either been specified on the cmake CLI or is already - # in the CMakeCache.txt. This has precedence over the environment - # variable DTC_OVERLAY_FILE -elseif(DEFINED ENV{DTC_OVERLAY_FILE}) - set(DTC_OVERLAY_FILE $ENV{DTC_OVERLAY_FILE}) +if(${IMAGE}DTC_OVERLAY_FILE) + # DTC_OVERLAY_FILE has either been specified on the cmake CLI or is + # already in the CMakeCache.txt. This has precedence over the + # environment variable DTC_OVERLAY_FILE +elseif(DEFINED ENV{${IMAGE}DTC_OVERLAY_FILE}) + set(${IMAGE}DTC_OVERLAY_FILE $ENV{${IMAGE}DTC_OVERLAY_FILE}) elseif(EXISTS ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.overlay) set(DTC_OVERLAY_FILE ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.overlay) elseif(EXISTS ${APPLICATION_SOURCE_DIR}/${BOARD}.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_SOURCE_DIR}/${BOARD}.overlay) + set(${IMAGE}DTC_OVERLAY_FILE ${APPLICATION_SOURCE_DIR}/${BOARD}.overlay) elseif(EXISTS ${APPLICATION_SOURCE_DIR}/app.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_SOURCE_DIR}/app.overlay) + set(${IMAGE}DTC_OVERLAY_FILE ${APPLICATION_SOURCE_DIR}/app.overlay) endif() -set(DTC_OVERLAY_FILE ${DTC_OVERLAY_FILE} CACHE STRING "If desired, you can \ +set(${IMAGE}CONF_FILE ${${IMAGE}CONF_FILE} CACHE STRING "If desired, you can build the application using\ +the configuration settings specified in an alternate .conf file using this parameter. \ +These settings will override the settings in the application’s .config file or its default .conf file.\ +Multiple files may be listed, e.g. CONF_FILE=\"prj1.conf prj2.conf\". \ +To specify an alternate .conf file for a specific image, prefix \"CONF_FILE\" \ +with the image name. For instance \"mcuboot_CONF_FILE\".") + +set(${IMAGE}DTC_OVERLAY_FILE ${${IMAGE}DTC_OVERLAY_FILE} CACHE STRING "If desired, you can \ build the application using the DT configuration settings specified in an \ alternate .overlay file using this parameter. These settings will override the \ settings in the board's .dts file. Multiple files may be listed, e.g. \ -DTC_OVERLAY_FILE=\"dts1.overlay dts2.overlay\"") +DTC_OVERLAY_FILE=\"dts1.overlay dts2.overlay\". To specify an alternate +.overlay file for a specific image, prefix \"DTC_OVERLAY_FILE\" with the image name. \ +For instance \"mcuboot_DTC_OVERLAY_FILE\".") -# Prevent CMake from testing the toolchain -set(CMAKE_C_COMPILER_FORCED 1) -set(CMAKE_CXX_COMPILER_FORCED 1) - -include(${ZEPHYR_BASE}/cmake/host-tools.cmake) - -# DTS should be close to kconfig because CONFIG_ variables from -# kconfig and dts should be available at the same time. -# -# The DT system uses a C preprocessor for it's code generation needs. -# This creates an awkward chicken-and-egg problem, because we don't -# always know exactly which toolchain the user needs until we know -# more about the target, e.g. after DT and Kconfig. -# -# To resolve this we find "some" C toolchain, configure it generically -# with the minimal amount of configuration needed to have it -# preprocess DT sources, and then, after we have finished processing -# both DT and Kconfig we complete the target-specific configuration, -# and possibly change the toolchain. -include(${ZEPHYR_BASE}/cmake/zephyr_module.cmake) -include(${ZEPHYR_BASE}/cmake/generic_toolchain.cmake) include(${ZEPHYR_BASE}/cmake/dts.cmake) include(${ZEPHYR_BASE}/cmake/kconfig.cmake) @@ -493,12 +578,11 @@ set(KERNEL_EXE_NAME ${KERNEL_NAME}.exe) set(KERNEL_STAT_NAME ${KERNEL_NAME}.stat) set(KERNEL_STRIP_NAME ${KERNEL_NAME}.strip) -# Populate USER_CACHE_DIR with a directory that user applications may -# write cache files to. -if(NOT DEFINED USER_CACHE_DIR) - find_appropriate_cache_directory(USER_CACHE_DIR) -endif() -message(STATUS "Cache files will be written to: ${USER_CACHE_DIR}") +define_property(GLOBAL PROPERTY ${IMAGE}KERNEL_NAME + BRIEF_DOCS "Name (KERNEL_NAME) for the ${IMAGE} image." + FULL_DOCS "To be used to access e.g. this image's hex file." + ) +set_property(GLOBAL PROPERTY ${IMAGE}KERNEL_NAME ${KERNEL_NAME}) include(${BOARD_DIR}/board.cmake OPTIONAL) @@ -529,7 +613,7 @@ endif() # modified by the entry point ${APPLICATION_SOURCE_DIR}/CMakeLists.txt # that was specified when cmake was called. zephyr_library_named(app) -set_property(TARGET app PROPERTY ARCHIVE_OUTPUT_DIRECTORY app) +set_property(TARGET ${IMAGE}app PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${IMAGE}app) add_subdirectory(${ZEPHYR_BASE} ${__build_dir}) @@ -540,17 +624,35 @@ add_subdirectory(${ZEPHYR_BASE} ${__build_dir}) # done after 'add_subdirectory(${ZEPHYR_BASE} ${__build_dir})' # because interface libraries are defined while processing that # subdirectory. -get_property(ZEPHYR_INTERFACE_LIBS_PROPERTY GLOBAL PROPERTY ZEPHYR_INTERFACE_LIBS) +get_property(ZEPHYR_INTERFACE_LIBS_PROPERTY GLOBAL PROPERTY ${IMAGE}ZEPHYR_INTERFACE_LIBS) foreach(boilerplate_lib ${ZEPHYR_INTERFACE_LIBS_PROPERTY}) # Linking 'app' with 'boilerplate_lib' causes 'app' to inherit the INTERFACE # properties of 'boilerplate_lib'. The most common property is 'include # directories', but it is also possible to have defines and compiler # flags in the interface of a library. - # - string(TOUPPER ${boilerplate_lib} boilerplate_lib_upper_case) # Support lowercase lib names + + # 'boilerplate_lib' is formatted as '0_mbedtls' (for instance). But + # the Kconfig options are formatted as + # 'CONFIG_APP_LINK_WITH_MBEDTLS'. So we need to strip the '0_' and + # convert to upper case. + + # Match the non-image'ified library name. E.g. '1_mylib' -> 'mylib'. + set(image_regex "^${IMAGE}(.*)") + string(REGEX MATCH + ${image_regex} + unused_out_var + ${boilerplate_lib} + ) + if(CMAKE_MATCH_1) + set(boilerplate_lib_without_image ${CMAKE_MATCH_1}) + else() + message(FATAL_ERROR "Internal error. Expected '${boilerplate_lib}' to match '${image_regex}'") + endif() + + string(TOUPPER ${boilerplate_lib_without_image} boilerplate_lib_upper_case) # Support lowercase lib names target_link_libraries_ifdef( CONFIG_APP_LINK_WITH_${boilerplate_lib_upper_case} - app + ${IMAGE}app PUBLIC ${boilerplate_lib} ) diff --git a/cmake/compiler/gcc/target.cmake b/cmake/compiler/gcc/target.cmake index ef8e4794666fe7..7bd47fb7d4d0b9 100644 --- a/cmake/compiler/gcc/target.cmake +++ b/cmake/compiler/gcc/target.cmake @@ -70,8 +70,9 @@ if(NOT no_libgcc) assert_exists(LIBGCC_DIR) - LIST(APPEND LIB_INCLUDE_DIR "-L\"${LIBGCC_DIR}\"") - LIST(APPEND TOOLCHAIN_LIBS gcc) + #TODO multi_image add ${IMAGE} prefix to other toolchains. + LIST(APPEND ${IMAGE}LIB_INCLUDE_DIR "-L\"${LIBGCC_DIR}\"") + LIST(APPEND ${IMAGE}TOOLCHAIN_LIBS gcc) endif() if(SYSROOT_DIR) diff --git a/cmake/dts.cmake b/cmake/dts.cmake index 3e9186fce297cd..d3da1f579de9ed 100644 --- a/cmake/dts.cmake +++ b/cmake/dts.cmake @@ -16,8 +16,8 @@ set(GENERATED_DTS_BOARD_UNFIXED_H ${PROJECT_BINARY_DIR}/include/generated/genera set(GENERATED_DTS_BOARD_CONF ${PROJECT_BINARY_DIR}/include/generated/generated_dts_board.conf) set(DTS_POST_CPP ${PROJECT_BINARY_DIR}/${BOARD}.dts.pre.tmp) -set_ifndef(DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts) -set_ifndef(DTS_COMMON_OVERLAYS ${ZEPHYR_BASE}/dts/common/common.dts) +set_ifndef(${IMAGE}DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts) +set_ifndef(${IMAGE}DTS_COMMON_OVERLAYS ${ZEPHYR_BASE}/dts/common/common.dts) # 'DTS_ROOT' is a list of directories where a directory tree with DT # files may be found. It always includes the application directory, @@ -33,23 +33,23 @@ list(REMOVE_DUPLICATES ) set(dts_files - ${DTS_SOURCE} + ${${IMAGE}DTS_SOURCE} ${DTS_COMMON_OVERLAYS} ${shield_dts_files} ) # TODO: What to do about non-posix platforms where NOT CONFIG_HAS_DTS (xtensa)? # Drop support for NOT CONFIG_HAS_DTS perhaps? -if(EXISTS ${DTS_SOURCE}) +if(EXISTS ${${IMAGE}DTS_SOURCE}) set(SUPPORTS_DTS 1) else() set(SUPPORTS_DTS 0) endif() if(SUPPORTS_DTS) - if(DTC_OVERLAY_FILE) + if(${IMAGE}DTC_OVERLAY_FILE) # Convert from space-separated files into file list - string(REPLACE " " ";" DTC_OVERLAY_FILE_AS_LIST ${DTC_OVERLAY_FILE}) + string(REPLACE " " ";" DTC_OVERLAY_FILE_AS_LIST ${${IMAGE}DTC_OVERLAY_FILE}) list(APPEND dts_files ${DTC_OVERLAY_FILE_AS_LIST} diff --git a/cmake/extensions.cmake b/cmake/extensions.cmake index cbb640ca15841e..9d85ea1ce05fc9 100644 --- a/cmake/extensions.cmake +++ b/cmake/extensions.cmake @@ -68,7 +68,7 @@ function(zephyr_sources) if(IS_DIRECTORY ${arg}) message(FATAL_ERROR "zephyr_sources() was called on a directory") endif() - target_sources(zephyr PRIVATE ${arg}) + target_sources(${IMAGE}zephyr PRIVATE ${arg}) endforeach() endfunction() @@ -80,7 +80,7 @@ function(zephyr_include_directories) else() set(path ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) endif() - target_include_directories(zephyr_interface INTERFACE ${path}) + target_include_directories(${IMAGE}zephyr_interface INTERFACE ${path}) endforeach() endfunction() @@ -92,42 +92,87 @@ function(zephyr_system_include_directories) else() set(path ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) endif() - target_include_directories(zephyr_interface SYSTEM INTERFACE ${path}) + target_include_directories(${IMAGE}zephyr_interface SYSTEM INTERFACE ${path}) endforeach() endfunction() # https://cmake.org/cmake/help/latest/command/target_compile_definitions.html function(zephyr_compile_definitions) - target_compile_definitions(zephyr_interface INTERFACE ${ARGV}) + target_compile_definitions(${IMAGE}zephyr_interface INTERFACE ${ARGV}) endfunction() # https://cmake.org/cmake/help/latest/command/target_compile_options.html function(zephyr_compile_options) - target_compile_options(zephyr_interface INTERFACE ${ARGV}) + target_compile_options(${IMAGE}zephyr_interface INTERFACE ${ARGV}) endfunction() # https://cmake.org/cmake/help/latest/command/target_link_libraries.html function(zephyr_link_libraries) - target_link_libraries(zephyr_interface INTERFACE ${ARGV}) + target_link_libraries(${IMAGE}zephyr_interface INTERFACE ${ARGV}) endfunction() # See this file section 3.1. target_cc_option function(zephyr_cc_option) foreach(arg ${ARGV}) - target_cc_option(zephyr_interface INTERFACE ${arg}) + target_cc_option(${IMAGE}zephyr_interface INTERFACE ${arg}) endforeach() endfunction() +# Add new executable which is built using a separate configuration. This is +# needed when a component needs to be built as an independent hex file, or with +# different configuration. Examples of use include bootloaders, and +# secure/non-secure partitions in a TrustZone environment. +# +# This function creates a new 'app' context, equivalent to the one defined by +# the 'origin' context. The CMakeLists.txt file pointed to by the users +# 'cmake' command defines the 'origin' context. All targets defined by the new +# context is prefixed with the name provided in the 'name' argument. As +# a result of this, in order to execute the 'menuconfig' target to perform +# configuration 'name_menuconfig' must be used instead. Note the targets +# defined by the 'origin' context is not prefixed in any way. +# +# Only a small set of configurations is shared between the 'origin' context and +# the new context, notably CMake properties. The new context defines its own +# set of: - CMake variables (note: not properties) - DTS configuration - +# KConfig configuration +# +# When multiple contexts are defined, a new merge target is defined which +# merges the resulting hex files. The 'flash' target is updated to use this +# merged hex file instead of the 'zephyr.hex' file from the origin context. +# +function(zephyr_add_executable name output_variable) + set(${output_variable} 0 PARENT_SCOPE) + string(TOUPPER ${name} UPNAME) + + if (CONFIG_${UPNAME}_BUILD_STRATEGY_USE_HEX_FILE) + assert_exists(CONFIG_${UPNAME}_HEX_FILE) + message("Using ${CONFIG_${UPNAME}_HEX_FILE} instead of building ${name}") + set_property(GLOBAL APPEND PROPERTY + HEX_FILES_TO_MERGE + ${CONFIG_${UPNAME}_HEX_FILE} + ${APPLICATION_BINARY_DIR}/zephyr/${KERNEL_HEX_NAME} + ) + elseif (CONFIG_${UPNAME}_BUILD_STRATEGY_SKIP_BUILD) + message("Skipping building of ${name}") + else() + # Build normally + set_property(GLOBAL PROPERTY IMAGE ${name}_) + set(${output_variable} 1 PARENT_SCOPE) + endif() + +endfunction() + + function(zephyr_cc_option_fallback option1 option2) - target_cc_option_fallback(zephyr_interface INTERFACE ${option1} ${option2}) + target_cc_option_fallback(${IMAGE}zephyr_interface INTERFACE ${option1} ${option2}) endfunction() function(zephyr_ld_options) - target_ld_options(zephyr_interface INTERFACE ${ARGV}) + target_ld_options(${IMAGE}zephyr_interface INTERFACE ${ARGV}) endfunction() # Getter functions for extracting build information from -# zephyr_interface. Returning lists, and strings is supported, as is +# ${IMAGE}zephyr_interface. Returning lists, and strings is supported, as is # requesting specific categories of build information (defines, # includes, options). # @@ -195,7 +240,7 @@ function(zephyr_get_compile_options_for_lang_as_string lang i) endfunction() function(zephyr_get_include_directories_for_lang lang i) - get_property_and_add_prefix(flags zephyr_interface INTERFACE_INCLUDE_DIRECTORIES + get_property_and_add_prefix(flags ${IMAGE}zephyr_interface INTERFACE_INCLUDE_DIRECTORIES "-I" ${ARGN} ) @@ -206,7 +251,7 @@ function(zephyr_get_include_directories_for_lang lang i) endfunction() function(zephyr_get_system_include_directories_for_lang lang i) - get_property_and_add_prefix(flags zephyr_interface INTERFACE_SYSTEM_INCLUDE_DIRECTORIES + get_property_and_add_prefix(flags ${IMAGE}zephyr_interface INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "-isystem" ${ARGN} ) @@ -217,7 +262,7 @@ function(zephyr_get_system_include_directories_for_lang lang i) endfunction() function(zephyr_get_compile_definitions_for_lang lang i) - get_property_and_add_prefix(flags zephyr_interface INTERFACE_COMPILE_DEFINITIONS + get_property_and_add_prefix(flags ${IMAGE}zephyr_interface INTERFACE_COMPILE_DEFINITIONS "-D" ${ARGN} ) @@ -228,7 +273,7 @@ function(zephyr_get_compile_definitions_for_lang lang i) endfunction() function(zephyr_get_compile_options_for_lang lang i) - get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS) + get_property(flags TARGET ${IMAGE}zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS) process_flags(${lang} flags output_list) @@ -367,17 +412,17 @@ endmacro() macro(zephyr_library_named name) # This is a macro because we need add_library() to be executed # within the scope of the caller. - set(ZEPHYR_CURRENT_LIBRARY ${name}) - add_library(${name} STATIC "") + set(ZEPHYR_CURRENT_LIBRARY ${IMAGE}${name}) + add_library(${ZEPHYR_CURRENT_LIBRARY} STATIC "") - zephyr_append_cmake_library(${name}) + zephyr_append_cmake_library(${ZEPHYR_CURRENT_LIBRARY}) - target_link_libraries(${name} PUBLIC zephyr_interface) + target_link_libraries(${ZEPHYR_CURRENT_LIBRARY} PUBLIC ${IMAGE}zephyr_interface) endmacro() function(zephyr_link_interface interface) - target_link_libraries(${interface} INTERFACE zephyr_interface) + target_link_libraries(${interface} INTERFACE ${IMAGE}zephyr_interface) endfunction() # @@ -407,8 +452,8 @@ function(zephyr_library_compile_options item) # library and link with it to obtain the flags. # # Linking with a dummy interface library will place flags later on - # the command line than the the flags from zephyr_interface because - # zephyr_interface will be the first interface library that flags + # the command line than the the flags from ${IMAGE}zephyr_interface because + # ${IMAGE}zephyr_interface will be the first interface library that flags # are taken from. string(MD5 uniqueness ${item}) @@ -441,7 +486,7 @@ endfunction() # constructor but must called explicitly on CMake libraries that do # not use a zephyr library constructor. function(zephyr_append_cmake_library library) - set_property(GLOBAL APPEND PROPERTY ZEPHYR_LIBS ${library}) + set_property(GLOBAL APPEND PROPERTY ${IMAGE}ZEPHYR_LIBS ${library}) endfunction() # Add the imported library 'library_name', located at 'library_path' to the @@ -481,8 +526,10 @@ endfunction() # This API has a constructor like the zephyr_library API has, but it # does not have wrappers over the other cmake target functions. macro(zephyr_interface_library_named name) - add_library(${name} INTERFACE) - set_property(GLOBAL APPEND PROPERTY ZEPHYR_INTERFACE_LIBS ${name}) + add_library(${IMAGE}${name} INTERFACE) + set_property(GLOBAL APPEND PROPERTY + ${IMAGE}ZEPHYR_INTERFACE_LIBS + ${IMAGE}${name}) endmacro() # 1.3 generate_inc_* @@ -851,14 +898,14 @@ function(zephyr_linker_sources location) set(rodata_path "${snippet_base}/snippets-rodata.ld") # Clear destination files if this is the first time the function is called. - get_property(cleared GLOBAL PROPERTY snippet_files_cleared) + get_property(cleared GLOBAL PROPERTY ${IMAGE}snippet_files_cleared) if (NOT DEFINED cleared) file(WRITE ${sections_path} "") file(WRITE ${ram_sections_path} "") file(WRITE ${noinit_path} "") file(WRITE ${rwdata_path} "") file(WRITE ${rodata_path} "") - set_property(GLOBAL PROPERTY snippet_files_cleared true) + set_property(GLOBAL PROPERTY ${IMAGE}snippet_files_cleared true) endif() # Choose destination file, based on the argument. @@ -900,7 +947,7 @@ endfunction(zephyr_linker_sources) # Helper function for CONFIG_CODE_DATA_RELOCATION # Call this function with 2 arguments file and then memory location function(zephyr_code_relocate file location) - set_property(TARGET code_data_relocation_target + set_property(TARGET ${IMAGE}code_data_relocation_target APPEND PROPERTY COMPILE_DEFINITIONS "${location}:${CMAKE_CURRENT_SOURCE_DIR}/${file}") endfunction() @@ -1012,6 +1059,13 @@ function(import_kconfig prefix kconfig_fragment) endforeach() endfunction() +function(get_image_name image out_var) + string(LENGTH ${image} len) + MATH(EXPR len "${len}-1") + string(SUBSTRING ${image} 0 ${len} ${out_var}) + set(${out_var} ${${out_var}} PARENT_SCOPE) +endfunction() + ######################################################## # 3. CMake-generic extensions ######################################################## @@ -1168,7 +1222,7 @@ endfunction() function(zephyr_link_interface_ifdef feature_toggle interface) if(${${feature_toggle}}) - target_link_libraries(${interface} INTERFACE zephyr_interface) + target_link_libraries(${interface} INTERFACE ${IMAGE}zephyr_interface) endif() endfunction() diff --git a/cmake/flash/CMakeLists.txt b/cmake/flash/CMakeLists.txt index 05edc8ddf826b2..fda524a5fc8296 100644 --- a/cmake/flash/CMakeLists.txt +++ b/cmake/flash/CMakeLists.txt @@ -124,7 +124,7 @@ foreach(target flash debug debugserver attach) WORKING_DIRECTORY ${APPLICATION_BINARY_DIR} ) - add_custom_target(${target} + add_custom_target(${IMAGE}${target} COMMAND ${cmd} COMMENT @@ -132,14 +132,14 @@ foreach(target flash debug debugserver attach) USES_TERMINAL ) elseif(WEST) - add_custom_target(${target} + add_custom_target(${IMAGE}${target} COMMAND ${CMAKE_COMMAND} -E echo \"West version found in path does not support '${CMAKE_MAKE_PROGRAM} ${target}', ensure west is installed and not only the bootstrapper. run 'west init' to fetch west.\" USES_TERMINAL ) else() - add_custom_target(${target} + add_custom_target(${IMAGE}${target} COMMAND ${CMAKE_COMMAND} -E echo \"West was not found in path. To support '${CMAKE_MAKE_PROGRAM} ${target}', please install west bootstrapper with: 'pip install west --user', and thereafter 'west init'.\" diff --git a/cmake/ide/eclipse_cdt4_generator_amendment.cmake b/cmake/ide/eclipse_cdt4_generator_amendment.cmake index 1bad729118e377..9179e4e4b77ab8 100644 --- a/cmake/ide/eclipse_cdt4_generator_amendment.cmake +++ b/cmake/ide/eclipse_cdt4_generator_amendment.cmake @@ -92,8 +92,8 @@ set(OUTPUT_FILE ${CMAKE_BINARY_DIR}/zephyr/include/generated/cmake_intdef.h) file(WRITE ${OUTPUT_FILE} "/* Generated by eclipse_cd4_generator_amendment.cmake */\n") file(APPEND ${OUTPUT_FILE} "/* The header contains the defines collected from the */\n") file(APPEND ${OUTPUT_FILE} "/* INTERFACE_COMPILE_DEFINITIONS target property */\n") -file(APPEND ${OUTPUT_FILE} "/* corresponding to zephyr_interface */\n") -get_target_property(_int_comp_def zephyr_interface INTERFACE_COMPILE_DEFINITIONS) +file(APPEND ${OUTPUT_FILE} "/* corresponding to ${IMAGE}zephyr_interface */\n") +get_target_property(_int_comp_def ${IMAGE}zephyr_interface INTERFACE_COMPILE_DEFINITIONS) foreach( d ${_int_comp_def} ) string(REGEX MATCH "([A-Za-z_][A-Za-z0-9_]*) *=* *(.*) *$" _dummy "${d}") file(APPEND ${OUTPUT_FILE} "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}\n") diff --git a/cmake/kconfig.cmake b/cmake/kconfig.cmake index 22a09a73590c81..e1788466a0ee0a 100644 --- a/cmake/kconfig.cmake +++ b/cmake/kconfig.cmake @@ -5,7 +5,7 @@ file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig/include/generated) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig/include/config) -if(KCONFIG_ROOT) +if(${IMAGE}KCONFIG_ROOT) # KCONFIG_ROOT has either been specified as a CMake variable or is # already in the CMakeCache.txt. This has precedence. elseif(EXISTS ${APPLICATION_SOURCE_DIR}/Kconfig) @@ -18,12 +18,12 @@ set(BOARD_DEFCONFIG ${BOARD_DIR}/${BOARD}_defconfig) set(DOTCONFIG ${PROJECT_BINARY_DIR}/.config) set(PARSED_KCONFIG_SOURCES_TXT ${PROJECT_BINARY_DIR}/kconfig/sources.txt) -if(CONF_FILE) -string(REPLACE " " ";" CONF_FILE_AS_LIST "${CONF_FILE}") +if(${IMAGE}CONF_FILE) +string(REPLACE " " ";" ${IMAGE}CONF_FILE_AS_LIST "${${IMAGE}CONF_FILE}") endif() -if(OVERLAY_CONFIG) - string(REPLACE " " ";" OVERLAY_CONFIG_AS_LIST "${OVERLAY_CONFIG}") +if(${IMAGE}OVERLAY_CONFIG) + string(REPLACE " " ";" ${IMAGE}OVERLAY_CONFIG_AS_LIST "${${IMAGE}OVERLAY_CONFIG}") endif() # DTS_ROOT_BINDINGS is a semicolon separated list, this causes @@ -71,7 +71,7 @@ foreach(kconfig_target ${EXTRA_KCONFIG_TARGETS} ) add_custom_target( - ${kconfig_target} + ${IMAGE}${kconfig_target} ${CMAKE_COMMAND} -E env PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} srctree=${ZEPHYR_BASE} @@ -101,16 +101,33 @@ endforeach() # user-testing. unset(EXTRA_KCONFIG_OPTIONS) get_cmake_property(cache_variable_names CACHE_VARIABLES) + +if ("${IMAGE}" STREQUAL "") + foreach (name ${cache_variable_names}) + if("${name}" MATCHES "^CONFIG_") + set(app_${name} ${${name}} CACHE STRING "") + unset(${name} CACHE) + endif() + endforeach() + set(KCONFIG_CACHE_IMAGE_PREFIX app_) +else() + set(KCONFIG_CACHE_IMAGE_PREFIX ${IMAGE}) +endif() + +get_cmake_property(cache_variable_names CACHE_VARIABLES) + foreach (name ${cache_variable_names}) - if("${name}" MATCHES "^CONFIG_") - # When a cache variable starts with 'CONFIG_', it is assumed to be + if("${name}" MATCHES "^${KCONFIG_CACHE_IMAGE_PREFIX}CONFIG_") + # When a cache variable starts with 'CONFIG_', it is assumed to be # a Kconfig symbol assignment from the CMake command line. + string(REPLACE "${KCONFIG_CACHE_IMAGE_PREFIX}" "" config_name ${name}) set(EXTRA_KCONFIG_OPTIONS - "${EXTRA_KCONFIG_OPTIONS}\n${name}=${${name}}" + "${EXTRA_KCONFIG_OPTIONS}\n${config_name}=${${name}}" ) endif() endforeach() +unset(EXTRA_KCONFIG_OPTIONS_FILE) if(EXTRA_KCONFIG_OPTIONS) set(EXTRA_KCONFIG_OPTIONS_FILE ${PROJECT_BINARY_DIR}/misc/generated/extra_kconfig_options.conf) file(WRITE @@ -126,9 +143,9 @@ list(SORT config_files) set( merge_config_files ${BOARD_DEFCONFIG} - ${CONF_FILE_AS_LIST} + ${${IMAGE}CONF_FILE_AS_LIST} ${shield_conf_files} - ${OVERLAY_CONFIG_AS_LIST} + ${${IMAGE}OVERLAY_CONFIG_AS_LIST} ${EXTRA_KCONFIG_OPTIONS_FILE} ${config_files} ) @@ -203,7 +220,7 @@ execute_process( ${merge_fragments} WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR} # The working directory is set to the app dir such that the user - # can use relative paths in CONF_FILE, e.g. CONF_FILE=nrf5.conf + # can use relative paths in ${IMAGE}CONF_FILE, e.g. CONF_FILE=nrf5.conf RESULT_VARIABLE ret ) if(NOT "${ret}" STREQUAL "0") @@ -222,26 +239,17 @@ foreach(kconfig_input set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${kconfig_input}) endforeach() -add_custom_target(config-sanitycheck DEPENDS ${DOTCONFIG}) - -# Remove the CLI Kconfig symbols from the namespace and -# CMakeCache.txt. If the symbols end up in DOTCONFIG they will be -# re-introduced to the namespace through 'import_kconfig'. -foreach (name ${cache_variable_names}) - if("${name}" MATCHES "^CONFIG_") - unset(${name}) - unset(${name} CACHE) - endif() -endforeach() +add_custom_target(${IMAGE}config-sanitycheck DEPENDS ${DOTCONFIG}) # Parse the lines prefixed with CONFIG_ in the .config file from Kconfig import_kconfig(CONFIG_ ${DOTCONFIG}) -# Re-introduce the CLI Kconfig symbols that survived +# Clear CLI Kconfig symbols that were not set. foreach (name ${cache_variable_names}) - if("${name}" MATCHES "^CONFIG_") - if(DEFINED ${name}) - set(${name} ${${name}} CACHE STRING "") + if("${name}" MATCHES "^${KCONFIG_CACHE_IMAGE_PREFIX}CONFIG_") + string(REPLACE "${KCONFIG_CACHE_IMAGE_PREFIX}" "" config_name ${name}) + if(NOT DEFINED ${config_name}) + unset(${name} CACHE) endif() endif() endforeach() diff --git a/cmake/linker/ld/target.cmake b/cmake/linker/ld/target.cmake index d3f63e474af763..7a372a0f1a9456 100644 --- a/cmake/linker/ld/target.cmake +++ b/cmake/linker/ld/target.cmake @@ -27,8 +27,8 @@ macro(configure_linker_script linker_script_gen linker_pass_define) endif() zephyr_get_include_directories_for_lang(C current_includes) - get_filename_component(base_name ${CMAKE_CURRENT_BINARY_DIR} NAME) - get_property(current_defines GLOBAL PROPERTY PROPERTY_LINKER_SCRIPT_DEFINES) + file(RELATIVE_PATH base_name "${CMAKE_BINARY_DIR}" "${PROJECT_BINARY_DIR}") + get_property(current_defines GLOBAL PROPERTY ${IMAGE}PROPERTY_LINKER_SCRIPT_DEFINES) add_custom_command( OUTPUT ${linker_script_gen} @@ -90,11 +90,11 @@ function(toolchain_ld_link_elf) ${LINKERFLAGPREFIX},--whole-archive ${ZEPHYR_LIBS_PROPERTY} ${LINKERFLAGPREFIX},--no-whole-archive - kernel + ${KERNEL_LIBRARY} $ - ${LIB_INCLUDE_DIR} + ${${IMAGE}LIB_INCLUDE_DIR} -L${PROJECT_BINARY_DIR} - ${TOOLCHAIN_LIBS} + ${${IMAGE}TOOLCHAIN_LIBS} ${TOOLCHAIN_LD_LINK_ELF_DEPENDENCIES} ) diff --git a/cmake/linker/ld/target_base.cmake b/cmake/linker/ld/target_base.cmake index a96c6d637c989f..8ca2adad677869 100644 --- a/cmake/linker/ld/target_base.cmake +++ b/cmake/linker/ld/target_base.cmake @@ -5,7 +5,7 @@ macro(toolchain_ld_base) if(NOT PROPERTY_LINKER_SCRIPT_DEFINES) - set_property(GLOBAL PROPERTY PROPERTY_LINKER_SCRIPT_DEFINES -D__GCC_LINKER_CMD__) + set_property(GLOBAL PROPERTY ${IMAGE}PROPERTY_LINKER_SCRIPT_DEFINES -D__GCC_LINKER_CMD__) endif() # TOOLCHAIN_LD_FLAGS comes from compiler/gcc/target.cmake diff --git a/cmake/linker/ld/target_relocation.cmake b/cmake/linker/ld/target_relocation.cmake index 076209a3ab26fb..0fcb0a8d9db804 100644 --- a/cmake/linker/ld/target_relocation.cmake +++ b/cmake/linker/ld/target_relocation.cmake @@ -17,14 +17,14 @@ macro(toolchain_ld_relocation) ${ZEPHYR_BASE}/scripts/gen_relocate_app.py $<$:--verbose> -d ${APPLICATION_BINARY_DIR} - -i '$' + -i '$' -o ${MEM_RELOCATION_LD} -s ${MEM_RELOCATION_SRAM_DATA_LD} -b ${MEM_RELOCATION_SRAM_BSS_LD} -c ${MEM_RELOCATION_CODE} - DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY} + DEPENDS ${IMAGE}app ${KERNEL_LIBRARY} ${ZEPHYR_LIBS_PROPERTY} ) - add_library(code_relocation_source_lib STATIC ${MEM_RELOCATION_CODE}) - target_link_libraries(code_relocation_source_lib zephyr_interface) + add_library(${IMAGE}code_relocation_source_lib STATIC ${MEM_RELOCATION_CODE}) + target_link_libraries(${IMAGE}code_relocation_source_lib ${IMAGE}zephyr_interface) endmacro() diff --git a/cmake/reports/CMakeLists.txt b/cmake/reports/CMakeLists.txt index 7c2140dc828fa5..8adedcd401de89 100644 --- a/cmake/reports/CMakeLists.txt +++ b/cmake/reports/CMakeLists.txt @@ -5,7 +5,7 @@ set(flag_for_rom_report -F) foreach(report ram_report rom_report) add_custom_target( - ${report} + ${IMAGE}${report} ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/footprint/size_report ${flag_for_${report}} diff --git a/cmake/usage/CMakeLists.txt b/cmake/usage/CMakeLists.txt deleted file mode 100644 index 5b042a47fe4f2b..00000000000000 --- a/cmake/usage/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -string(REPLACE ";" " " BOARD_ROOT_SPACE_SEPARATED "${BOARD_ROOT}") -string(REPLACE ";" " " SHIELD_LIST_SPACE_SEPARATED "${SHIELD_LIST}") - -add_custom_target( - usage - ${CMAKE_COMMAND} - -DBOARD_ROOT_SPACE_SEPARATED=${BOARD_ROOT_SPACE_SEPARATED} - -DSHIELD_LIST_SPACE_SEPARATED=${SHIELD_LIST_SPACE_SEPARATED} - -P ${CMAKE_CURRENT_SOURCE_DIR}/usage.cmake - ) - -# NB: The reason it is 'usage' and not help is that CMake already -# defines a target 'help' diff --git a/doc/application/index.rst b/doc/application/index.rst index ae4fb1ed82fe0c..2104f2a2596efa 100644 --- a/doc/application/index.rst +++ b/doc/application/index.rst @@ -1551,6 +1551,174 @@ After running the preprocessor, the final devicetree used in the build is created by running the devicetree compiler, ``dtc``, on the preprocessor output. +.. _application_multiple_images: + +Building and configuring multiple images +**************************************** + +When an embedded application includes functionality for firmware +updates or bootloaders, the final firmware that is programmed to +the device must usually consist of not one but multiple +executables that chain-load, or boot, each other. This section +describes how to build and configure such a Zephyr application. + +When and why to use multiple images +=================================== + +First off, you need a basic understanding of what exactly an +executable is and why we would want to have more than one. An +executable can be referred to by other names depending on context, +like program, image, or elf file. We will use the name *image*. You +probably have an idea of what an image is by reading the names, but if +not: An image consists of pieces of code and data that is identified +by image-unique names recorded in a single symbol table. The symbol +table exists as metadata in a ``.elf`` or ``.exe`` file and is not +included when the image is converted to a HEX file for +programming. Object files also consist of symbols, code, and data, but +object files are not images because unlike object files, images have +their code and data placed at addresses by a linker. In the end, it is +the linker that creates images. Therefore, if you want to determine if +you have zero, one, or more images, count the number of times the linker +has been run. + +From this definition, using two images gives you two opportunities: +Firstly, it allows you to run the linker multiple times and in this +process partition the final firmware into several regions, something +that is often desired by bootloaders. And secondly, since there are +multiple symbol tables, it allows the same symbol name to exist +multiple times in the final firmware. This again is useful for +bootloader images, as they often need to have their own fixed copies +of the same libraries that the application image is using. + +Enabling and configuring multiple images +======================================== + +Images are organized in a tree of parent-child relationships, which +means that a parent image requires one or more child images and +enables them through Kconfig. Usually, the tree is branchless: a +linked list of images where each image enables the child image that +boots it. The simplest and most common organization is a single +application image that enables a single bootloader image. + +When a parent image enables a child image through Kconfig, both images are +configured when CMake is run. +When configuring the parent image, you can decide how the child image +should be handled: + +* Build the child image from source while building the parent image. +* Use a prebuilt HEX file of the child image. +* Ignore the child image. + +When building the child image from source or using a prebuilt HEX +file, the build system will merge the HEX files of the parent and +child image together so that they can easily be programmed using +the ``ninja flash`` target. This means that in the simplest scenario, +it is possible to enable and integrate an additional image without +even realizing it, using the same workflow as for additional +libraries, namely enabling through Kconfig. + +Child images are configured with the same mechanisms as parent +images: through CMake variables, Kconfig input fragments, and by +modifying the ``.config`` file in the build directory. For example, to +change the CONF_FILE for the MCUBoot image and the parent image, you +could run the following command:: + + cmake -Dmcuboot_CONF_FILE=prj_a.conf -DCONF_FILE=app_prj.conf + +If you check the CONF_FILE, you can see that all CMake Cache +variables that are image-specific are given a prefix to disambiguate +them. To simplify configuation of single-image builds, the top-level +image has the empty string as its prefix. + +The same prefix convention is used to disambiguate targets. This means +that to run menuconfig, for example, you can simply invoke the +``menuconfig`` target to configure the top-level image and +``mcuboot_menuconfig`` to configure the MCUBoot child image. + +.. _application_defining_child_images: + +Defining new child images +========================= + +This section describes how to take an existing parent image and turn +it into a child image that can be enabled. A parent image typically +consists of source code, Kconfig fragments, and build script code. The +source code and Kconfig fragments can be reused as-is, but several +changes to the build scripts are necessary. + +As mentioned earlier, each target needs a prefix for disambiguation. This +includes the library target ``app``, so any references to ``app`` must +be changed to ``${IMAGE}app``. Or, even better, you could use +the ``zephyr_library_*`` API instead of the ``target_*`` API to indirectly +modify ``${IMAGE}app``. + +After the application build scripts have been ported, we need some +build scripts as shown below to connect the build scripts of the +parent and child. This code should be placed somewhere in-tree that is +conditional on a Kconfig option for having the parent image use the +child image. + +.. code-block:: cmake + + set(child_image_name mcuboot) + zephyr_add_executable(${child_image_name} require_build) + + set(build_directory ${CMAKE_CURRENT_BINARY_DIR}/mcuboot + set(child_image_application_directory ${MCUBOOT_BASE}/boot/zephyr) + + if(${require_build}) + add_subdirectory(${child_image_application_directory} ${build_directory}) + endif() + +In the above code, ``zephyr_add_executable`` registers the child image as +present in the build, and ``add_subdirectory`` actually executes the +child's build scripts. Note that in addition to the child image's +application build scripts being executed, most of the core build +scripts are executed for a second time as well, but now with a +different Kconfig configuration and possibly DeviceTree settings. + +Some Kconfig options must be added to allow the parent image to choose how to +include the child image. The three options are: + +1. Build from source. +#. Include as HEX file. +#. Skip building entirely. + +The first option will result in the child image being built from +source alongside the parent image. Option 2 requires a prebuilt HEX +file to be specified in Kconfig, which will be merged with the parent +image HEX file. Option 3 will cause the child image to not be built. These options are shown below for MCUBoot. + +.. code-block:: Kconfig + + choice + prompt "MCUBoot build strategy" + default MCUBOOT_BUILD_STRATEGY_FROM_SOURCE + + config MCUBOOT_BUILD_STRATEGY_USE_HEX_FILE + # Mandatory option when being built through 'zephyr_add_executable' + bool "Use hex file instead of building MCUBoot" + + if MCUBOOT_BUILD_STRATEGY_USE_HEX_FILE + + config MCUBOOT_HEX_FILE + # Mandatory option when being built through 'zephyr_add_executable' + string "MCUBoot hex file" + + endif # MCUBOOT_USE_HEX_FILE + + config MCUBOOT_BUILD_STRATEGY_SKIP_BUILD + # Mandatory option when being built through 'zephyr_add_executable' + bool "Skip building MCUBoot" + + config MCUBOOT_BUILD_STRATEGY_FROM_SOURCE + # Mandatory option when being built through 'zephyr_add_executable' + bool "Build from source" + + endchoice + + + Application-Specific Code ************************* diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 7d8e8585b11f2f..0d81a9889c7f68 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -2,7 +2,7 @@ # kernel is a normal CMake library and not a zephyr_library because it # should not be --whole-archive'd -add_library(kernel +add_library(${KERNEL_LIBRARY} device.c errno.c fatal.c @@ -29,16 +29,16 @@ add_library(kernel # Kernel files has the macro __ZEPHYR_SUPERVISOR__ set so that it # optimizes the code when userspace is enabled. set_target_properties( - kernel + ${KERNEL_LIBRARY} PROPERTIES COMPILE_DEFINITIONS __ZEPHYR_SUPERVISOR__ ) -target_sources_ifdef(CONFIG_STACK_CANARIES kernel PRIVATE compiler_stack_protect.c) -target_sources_ifdef(CONFIG_SYS_CLOCK_EXISTS kernel PRIVATE timeout.c timer.c) -target_sources_ifdef(CONFIG_ATOMIC_OPERATIONS_C kernel PRIVATE atomic_c.c) -target_sources_if_kconfig( kernel PRIVATE poll.c) +target_sources_ifdef(CONFIG_STACK_CANARIES ${KERNEL_LIBRARY} PRIVATE compiler_stack_protect.c) +target_sources_ifdef(CONFIG_SYS_CLOCK_EXISTS ${KERNEL_LIBRARY} PRIVATE timeout.c timer.c) +target_sources_ifdef(CONFIG_ATOMIC_OPERATIONS_C ${KERNEL_LIBRARY} PRIVATE atomic_c.c) +target_sources_if_kconfig( ${KERNEL_LIBRARY} PRIVATE poll.c) # The last 2 files inside the target_sources_ifdef should be # userspace_handler.c and userspace.c. If not the linker would complain. @@ -46,7 +46,7 @@ target_sources_if_kconfig( kernel PRIVATE poll.c) # above these 2 files. target_sources_ifdef( CONFIG_USERSPACE - kernel PRIVATE + ${KERNEL_LIBRARY} PRIVATE futex.c mem_domain.c userspace_handler.c @@ -54,6 +54,6 @@ target_sources_ifdef( ) -add_dependencies(kernel ${OFFSETS_H_TARGET}) +add_dependencies(${KERNEL_LIBRARY} ${OFFSETS_H_TARGET}) -target_link_libraries(kernel zephyr_interface) +target_link_libraries(${KERNEL_LIBRARY} ${IMAGE}zephyr_interface) diff --git a/samples/subsys/ipc/ipm_mcux/CMakeLists.txt b/samples/subsys/ipc/ipm_mcux/CMakeLists.txt index 4b7fb8118848f0..e69eec0277e42c 100644 --- a/samples/subsys/ipc/ipm_mcux/CMakeLists.txt +++ b/samples/subsys/ipc/ipm_mcux/CMakeLists.txt @@ -24,4 +24,4 @@ ExternalProject_Add( project(ipm_mcux) target_sources(app PRIVATE src/main_master.c) -add_dependencies(core_m0_inc_target ipm_mcux_remote) +add_dependencies(${IMAGE}core_m0_inc_target ipm_mcux_remote) diff --git a/samples/subsys/ipc/openamp/CMakeLists.txt b/samples/subsys/ipc/openamp/CMakeLists.txt index fe0456425bc519..399f7dc5c77d5a 100644 --- a/samples/subsys/ipc/openamp/CMakeLists.txt +++ b/samples/subsys/ipc/openamp/CMakeLists.txt @@ -25,6 +25,6 @@ ExternalProject_Add( BUILD_BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/openamp_remote-prefix/src/openamp_remote-build/zephyr/zephyr.bin" # NB: Do we need to pass on more CMake variables? ) -add_dependencies(core_m0_inc_target openamp_remote) +add_dependencies(${IMAGE}core_m0_inc_target openamp_remote) target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/soc/arm/nxp_lpc/lpc54xxx/CMakeLists.txt b/soc/arm/nxp_lpc/lpc54xxx/CMakeLists.txt index 2347dcb3a0c961..c1ff4cbe58aaf4 100644 --- a/soc/arm/nxp_lpc/lpc54xxx/CMakeLists.txt +++ b/soc/arm/nxp_lpc/lpc54xxx/CMakeLists.txt @@ -13,10 +13,10 @@ if (CONFIG_SLAVE_CORE_MCUX) set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) string(CONFIGURE ${CONFIG_SLAVE_IMAGE_MCUX} core_m0_image) - add_custom_target(core_m0_inc_target DEPENDS ${gen_dir}/core-m0.inc) + add_custom_target(${IMAGE}core_m0_inc_target DEPENDS ${gen_dir}/core-m0.inc) generate_inc_file_for_gen_target(${ZEPHYR_CURRENT_LIBRARY} ${core_m0_image} ${gen_dir}/core-m0.inc - core_m0_inc_target) + ${IMAGE}core_m0_inc_target) endif() diff --git a/subsys/bluetooth/CMakeLists.txt b/subsys/bluetooth/CMakeLists.txt index 4cac45c2e0c019..6a8a34705dc9b7 100644 --- a/subsys/bluetooth/CMakeLists.txt +++ b/subsys/bluetooth/CMakeLists.txt @@ -1,8 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 -add_library(subsys__bluetooth INTERFACE) +add_library(${IMAGE}subsys__bluetooth INTERFACE) -target_include_directories(subsys__bluetooth INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(${IMAGE}subsys__bluetooth INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(common) add_subdirectory_ifdef(CONFIG_BT_HCI host) diff --git a/subsys/bluetooth/common/CMakeLists.txt b/subsys/bluetooth/common/CMakeLists.txt index 059a0d6ab1255e..a0d6656219e8d9 100644 --- a/subsys/bluetooth/common/CMakeLists.txt +++ b/subsys/bluetooth/common/CMakeLists.txt @@ -7,4 +7,4 @@ zephyr_library_sources(log.c) zephyr_library_sources_ifdef(CONFIG_BT_RPA rpa.c) -zephyr_library_link_libraries(subsys__bluetooth) +zephyr_library_link_libraries(${IMAGE}subsys__bluetooth) diff --git a/subsys/bluetooth/controller/CMakeLists.txt b/subsys/bluetooth/controller/CMakeLists.txt index 764ccadab66122..557808e15f6e7f 100644 --- a/subsys/bluetooth/controller/CMakeLists.txt +++ b/subsys/bluetooth/controller/CMakeLists.txt @@ -172,4 +172,4 @@ zephyr_library_compile_options_ifdef( ${OPTIMIZE_FOR_SPEED_FLAG} ) -zephyr_library_link_libraries(subsys__bluetooth) +zephyr_library_link_libraries(${IMAGE}subsys__bluetooth) diff --git a/subsys/bluetooth/host/CMakeLists.txt b/subsys/bluetooth/host/CMakeLists.txt index 5edfb9491b8726..ce915889da9b76 100644 --- a/subsys/bluetooth/host/CMakeLists.txt +++ b/subsys/bluetooth/host/CMakeLists.txt @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library() -zephyr_library_link_libraries(subsys__bluetooth) +zephyr_library_link_libraries(${IMAGE}subsys__bluetooth) zephyr_library_sources_ifdef(CONFIG_BT_HCI_RAW hci_raw.c) zephyr_library_sources_ifdef(CONFIG_BT_DEBUG_MONITOR monitor.c) diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 72f5adcbdf2907..a419c71659ad88 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library() -zephyr_library_link_libraries(subsys__bluetooth) +zephyr_library_link_libraries(${IMAGE}subsys__bluetooth) zephyr_library_sources_ifdef(CONFIG_BT_MESH main.c