kopia lustrzana https://github.com/espressif/esp-idf
Merge branch 'feature/build_system_multi_target' into 'master'
build system: support for multiple targets (CMake only) See merge request idf/esp-idf!3499pull/2729/head
commit
7efb3926c5
16
Kconfig
16
Kconfig
|
@ -8,6 +8,22 @@ config IDF_CMAKE
|
|||
bool
|
||||
option env="IDF_CMAKE"
|
||||
|
||||
|
||||
# A proxy to get environment variable $IDF_TARGET
|
||||
config IDF_TARGET_ENV
|
||||
string
|
||||
option env="IDF_TARGET"
|
||||
|
||||
# This option records the IDF target when sdkconfig is generated the first time.
|
||||
# It is not updated if environment variable $IDF_TARGET changes later, and
|
||||
# the build system is responsible for detecting the mismatch between
|
||||
# CONFIG_IDF_TARGET and $IDF_TARGET.
|
||||
config IDF_TARGET
|
||||
string
|
||||
default "IDF_TARGET_NOT_SET" if IDF_TARGET_ENV=""
|
||||
default IDF_TARGET_ENV
|
||||
|
||||
|
||||
menu "SDK tool configuration"
|
||||
config TOOLPREFIX
|
||||
string "Compiler toolchain path/prefix"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require_idf_targets(esp32)
|
||||
|
||||
if(BOOTLOADER_BUILD)
|
||||
# For bootloader, all we need from esp32 is headers
|
||||
set(COMPONENT_ADD_INCLUDEDIRS include)
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
menu "ESP32-specific"
|
||||
|
||||
# Hidden option to support checking for this specific target in C code and Kconfig files
|
||||
config IDF_TARGET_ESP32
|
||||
bool
|
||||
default "y" if IDF_TARGET="esp32"
|
||||
default "n"
|
||||
|
||||
choice ESP32_DEFAULT_CPU_FREQ_MHZ
|
||||
prompt "CPU frequency"
|
||||
default ESP32_DEFAULT_CPU_FREQ_160
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
set(SOC_NAME esp32)
|
||||
set(SOC_NAME ${IDF_TARGET})
|
||||
|
||||
include(${IDF_PATH}/components/soc/${SOC_NAME}/sources.cmake)
|
||||
if(EXISTS "${COMPONENT_PATH}/${SOC_NAME}")
|
||||
include(${COMPONENT_PATH}/${SOC_NAME}/sources.cmake)
|
||||
|
||||
spaces2list(SOC_SRCS)
|
||||
add_prefix(COMPONENT_SRCS "${SOC_NAME}/" ${SOC_SRCS})
|
||||
spaces2list(SOC_SRCS)
|
||||
add_prefix(COMPONENT_SRCS "${SOC_NAME}/" ${SOC_SRCS})
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ${SOC_NAME}/include)
|
||||
endif()
|
||||
|
||||
list(APPEND COMPONENT_ADD_INCLUDEDIRS include)
|
||||
list(APPEND COMPONENT_SRCS "src/memory_layout_utils.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ${SOC_NAME}/include include)
|
||||
|
||||
set(COMPONENT_REQUIRES)
|
||||
register_component()
|
||||
register_component()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
# currently the only SoC supported; to be moved into Kconfig
|
||||
SOC_NAME := esp32
|
||||
SOC_NAME := $(IDF_TARGET)
|
||||
|
||||
COMPONENT_SRCDIRS := $(SOC_NAME) src/
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
set(SOC_NAME esp32)
|
||||
set(COMPONENT_SRCDIRS "../${SOC_NAME}/test")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "../${SOC_NAME}/test")
|
||||
set(SOC_NAME ${IDF_TARGET})
|
||||
if(EXISTS "../${SOC_NAME}/test")
|
||||
set(COMPONENT_SRCDIRS "../${SOC_NAME}/test")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "../${SOC_NAME}/test")
|
||||
|
||||
set(COMPONENT_REQUIRES unity)
|
||||
set(COMPONENT_REQUIRES unity)
|
||||
|
||||
register_component()
|
||||
register_component()
|
||||
endif()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
# currently the only SoC supported; to be moved into Kconfig
|
||||
SOC_NAME := esp32
|
||||
SOC_NAME := $(IDF_TARGET)
|
||||
|
||||
COMPONENT_SRCDIRS := ../$(SOC_NAME)/test
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ Concepts
|
|||
|
||||
- "components" are modular pieces of standalone code which are compiled into static libraries (.a files) and linked into an app. Some are provided by ESP-IDF itself, others may be sourced from other places.
|
||||
|
||||
- "Target" is the hardware for which an application is built. At the moment, ESP-IDF supports only one target, ``esp32``.
|
||||
|
||||
Some things are not part of the project:
|
||||
|
||||
- "ESP-IDF" is not part of the project. Instead it is standalone, and linked to the project via the ``IDF_PATH`` environment variable which holds the path of the ``esp-idf`` directory. This allows the IDF framework to be decoupled from your project.
|
||||
|
@ -79,7 +81,6 @@ Type ``idf.py --help`` for a full list of commands. Here are a summary of the mo
|
|||
Building is incremental so if no source files or configuration has changed since the last build, nothing will be done.
|
||||
- ``idf.py clean`` will "clean" the project by deleting build output files from the build directory, forcing a "full rebuild" the next time the project is built. Cleaning doesn't delete CMake configuration output and some other files.
|
||||
- ``idf.py fullclean`` will delete the entire "build" directory contents. This includes all CMake configuration output. The next time the project is built, CMake will configure it from scratch. Note that this option recursively deletes *all* files in the build directory, so use with care. Project configuration is not deleted.
|
||||
- ``idf.py reconfigure`` re-runs CMake_ even if it doesn't seem to need re-running. This isn't necessary during normal usage, but can be useful after adding/removing files from the source tree.
|
||||
- ``idf.py flash`` will automatically build the project if necessary, and then flash it to an ESP32. The ``-p`` and ``-b`` options can be used to set serial port name and flasher baud rate, respectively.
|
||||
- ``idf.py monitor`` will display serial output from the ESP32. The ``-p`` option can be used to set the serial port name. Type ``Ctrl-]`` to exit the monitor. See :doc:`/get-started/idf-monitor` for more details about using the monitor.
|
||||
|
||||
|
@ -94,6 +95,7 @@ Advanced Commands
|
|||
- There are matching commands ``idf.py app-flash``, etc. to flash only that single part of the project to the ESP32.
|
||||
- ``idf.py -p PORT erase_flash`` will use esptool.py to erase the ESP32's entire flash chip.
|
||||
- ``idf.py size`` prints some size information about the app. ``size-components`` and ``size-files`` are similar commands which print more detailed per-component or per-source-file information, respectively.
|
||||
- ``idf.py reconfigure`` re-runs CMake_ even if it doesn't seem to need re-running. This isn't necessary during normal usage, but can be useful after adding/removing files from the source tree, or when modifying CMake cache variables. For example, ``idf.py -DNAME='VALUE' reconfigure`` can be used to set variable ``NAME`` in CMake cache to value ``VALUE``.
|
||||
|
||||
The order of multiple ``idf.py`` commands on the same invocation is not important, they will automatically be executed in the correct order for everything to take effect (ie building before flashing, erasing before flashing, etc.).
|
||||
|
||||
|
@ -319,6 +321,7 @@ The following variables are set at the project level, but available for use in c
|
|||
- ``COMPONENTS``: Names of all components that are included in this build, formatted as a semicolon-delimited CMake list.
|
||||
- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in make. All names begin with ``CONFIG_``. :doc:`More information here </api-reference/kconfig>`.
|
||||
- ``IDF_VER``: Git version of ESP-IDF (produced by ``git describe``)
|
||||
- ``IDF_TARGET``: Name of the target for which the project is being built.
|
||||
|
||||
If you modify any of these variables inside ``CMakeLists.txt`` then this will not prevent other components from building but it may make your component hard to build and/or debug.
|
||||
|
||||
|
@ -417,6 +420,8 @@ When writing a component
|
|||
- The values of ``COMPONENT_REQUIRES`` and ``COMPONENT_PRIV_REQUIRES`` should not depend on any configuration choices (``CONFIG_xxx`` macros). This is because requirements are expanded before configuration is loaded. Other component variables (like include paths or source files) can depend on configuration choices.
|
||||
- Not setting either or both ``REQUIRES`` variables is fine. If the component has no requirements except for the "common" components needed for RTOS, libc, etc (``COMPONENT_REQUIRES_COMMON``) then both variables can be empty or unset.
|
||||
|
||||
Components which support only some targets (values of ``IDF_TARGET``) may call ``require_idf_targets(NAMES...)`` CMake function to express these requirements. In this case the build system will generate an error if the component is included into the build, but does not support selected target.
|
||||
|
||||
When creating a project
|
||||
-----------------------
|
||||
|
||||
|
@ -465,16 +470,17 @@ project function
|
|||
|
||||
The custom ``project()`` function performs the following steps:
|
||||
|
||||
- Determines the target (set by ``IDF_TARGET`` environment variable) and saves the target in CMake cache. If the target set in the environment does not match the one in cache, exits with an error.
|
||||
- Evaluates component dependencies and builds the ``BUILD_COMPONENTS`` list of components to include in the build (see :ref:`above<component-requirements-implementation>`).
|
||||
- Finds all components in the project (searching ``COMPONENT_DIRS`` and filtering by ``COMPONENTS`` if this is set).
|
||||
- Loads the project configuration from the ``sdkconfig`` file and generates a ``sdkconfig.cmake`` file and a ``sdkconfig.h`` header. These define configuration values in CMake and C/C++, respectively. If the project configuration changes, cmake will automatically be re-run to re-generate these files and re-configure the project.
|
||||
- Sets the `CMAKE_TOOLCHAIN_FILE`_ variable to the ESP-IDF toolchain file with the Xtensa ESP32 toolchain.
|
||||
- Declare the actual cmake-level project by calling the `CMake project function <cmake project_>`_.
|
||||
- Load the git version. This includes some magic which will automatically re-run CMake if a new revision is checked out in git. See `File Globbing & Incremental Builds`_.
|
||||
- Include :ref:`project_include.cmake` files from any components which have them.
|
||||
- Add each component to the build. Each component CMakeLists file calls ``register_component``, calls the CMake `add_library <cmake add_library_>`_ function to add a library and then adds source files, compile options, etc.
|
||||
- Add the final app executable to the build.
|
||||
- Go back and add inter-component dependencies between components (ie adding the public header directories of each component to each other component).
|
||||
- Sets the `CMAKE_TOOLCHAIN_FILE`_ variable to the correct toolchain file, depending on the target.
|
||||
- Declares the actual cmake-level project by calling the `CMake project function <cmake project_>`_.
|
||||
- Loads the git version. This includes some magic which will automatically re-run CMake if a new revision is checked out in git. See `File Globbing & Incremental Builds`_.
|
||||
- Includes :ref:`project_include.cmake` files from any components which have them.
|
||||
- Adds each component to the build. Each component CMakeLists file calls ``register_component``, calls the CMake `add_library <cmake add_library_>`_ function to add a library and then adds source files, compile options, etc.
|
||||
- Adds the final app executable to the build.
|
||||
- Goes back and adds inter-component dependencies between components (ie adding the public header directories of each component to each other component).
|
||||
|
||||
Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details.
|
||||
|
||||
|
@ -604,6 +610,16 @@ This can also be used to select or stub out an implementation, as such:
|
|||
endif()
|
||||
|
||||
|
||||
Conditions which depend on the target
|
||||
-------------------------------------
|
||||
|
||||
The current target is available to CMake files via ``IDF_TARGET`` variable.
|
||||
|
||||
In addition to that, if target ``xyz`` is used (``IDF_TARGET=xyz``), then Kconfig variable ``CONFIG_IDF_TARGET_XYZ`` will be set.
|
||||
|
||||
Note that component dependencies may depend on ``IDF_TARGET`` variable, but not on Kconfig variables. Also one can not use Kconfig variables in ``include`` statements in CMake files, but ``IDF_TARGET`` can be used in such context.
|
||||
|
||||
|
||||
Source Code Generation
|
||||
----------------------
|
||||
|
||||
|
@ -745,6 +761,13 @@ For example projects or other projects where you don't want to specify a full sd
|
|||
|
||||
To override the name of this file, set the ``SDKCONFIG_DEFAULTS`` environment variable.
|
||||
|
||||
Target-dependent sdkconfig defaults
|
||||
-----------------------------------
|
||||
|
||||
In addition to ``sdkconfig.defaults`` file, build system will also load defaults from ``sdkconfig.defaults.TARGET_NAME`` file, where ``TARGET_NAME`` is the value of ``IDF_TARGET``. For example, for ``esp32`` target, default settings will be taken from ``sdkconfig.defaults`` first, and then from ``sdkconfig.defaults.esp32``.
|
||||
|
||||
If ``SDKCONFIG_DEFAULTS`` is used to override the name of defaults file, the name of target-specific defaults file will be derived from ``SDKCONFIG_DEFAULTS`` value.
|
||||
|
||||
|
||||
Flash arguments
|
||||
===============
|
||||
|
@ -776,6 +799,15 @@ The bootloader is a special "subproject" inside :idf:`/components/bootloader/sub
|
|||
|
||||
The subproject is inserted as an external project from the top-level project, by the file :idf_file:`/components/bootloader/project_include.cmake`. The main build process runs CMake for the subproject, which includes discovering components (a subset of the main components) and generating a bootloader-specific config (derived from the main ``sdkconfig``).
|
||||
|
||||
Selecting the Target
|
||||
====================
|
||||
|
||||
Currently ESP-IDF supports one target, ``esp32``. It is used by default by the build system. Developers working on adding multiple target support can change the target as follows::
|
||||
|
||||
rm sdkconfig
|
||||
idf.py -DIDF_TARGET=new_target reconfigure
|
||||
|
||||
|
||||
Writing Pure CMake Components
|
||||
=============================
|
||||
|
||||
|
|
|
@ -91,6 +91,15 @@ ifndef IDF_PATH
|
|||
$(error IDF_PATH variable is not set to a valid directory.)
|
||||
endif
|
||||
|
||||
ifdef IDF_TARGET
|
||||
ifneq ($(IDF_TARGET),esp32)
|
||||
$(error GNU Make based build system only supports esp32 target, but IDF_TARGET is set to $(IDF_TARGET))
|
||||
endif
|
||||
else
|
||||
export IDF_TARGET := esp32
|
||||
endif
|
||||
|
||||
|
||||
ifneq ("$(IDF_PATH)","$(SANITISED_IDF_PATH)")
|
||||
# implies IDF_PATH was overriden on make command line.
|
||||
# Due to the way make manages variables, this is hard to account for
|
||||
|
|
|
@ -212,6 +212,41 @@ function run_tests()
|
|||
mv CMakeLists.bak CMakeLists.txt
|
||||
assert_built ${APP_BINS} ${BOOTLOADER_BINS} ${PARTITION_BIN}
|
||||
|
||||
# Next two tests will use this fake 'esp31b' target
|
||||
export fake_target=esp31b
|
||||
mkdir -p components/$fake_target
|
||||
touch components/$fake_target/CMakeLists.txt
|
||||
cp ${IDF_PATH}/tools/cmake/toolchain-esp32.cmake components/$fake_target/toolchain-$fake_target.cmake
|
||||
sed -i.old '/cmake_minimum_required/ a\
|
||||
set(COMPONENTS esptool_py)' CMakeLists.txt
|
||||
|
||||
print_status "Can override IDF_TARGET from environment"
|
||||
clean_build_dir
|
||||
rm sdkconfig
|
||||
export IDF_TARGET=$fake_target
|
||||
(cd build && cmake -G Ninja .. ) || failure "Failed to configure with IDF_TARGET set in environment"
|
||||
grep "CONFIG_IDF_TARGET=\"${fake_target}\"" sdkconfig || failure "Project not configured for IDF_TARGET correctly"
|
||||
grep "IDF_TARGET:STRING=${fake_target}" build/CMakeCache.txt || failure "IDF_TARGET not set in CMakeCache.txt"
|
||||
unset IDF_TARGET
|
||||
|
||||
print_status "Can set target using idf.py -D"
|
||||
clean_build_dir
|
||||
rm sdkconfig
|
||||
idf.py -DIDF_TARGET=$fake_target reconfigure || failure "Failed to set target via idf.py"
|
||||
grep "CONFIG_IDF_TARGET=\"${fake_target}\"" sdkconfig || failure "Project not configured correctly using idf.py -D"
|
||||
grep "IDF_TARGET:STRING=${fake_target}" build/CMakeCache.txt || failure "IDF_TARGET not set in CMakeCache.txt using idf.py -D"
|
||||
|
||||
# Clean up modifications for the fake target
|
||||
mv CMakeLists.txt.old CMakeLists.txt
|
||||
rm -rf components
|
||||
|
||||
print_status "Can find toolchain file in component directory"
|
||||
clean_build_dir
|
||||
mv ${IDF_PATH}/tools/cmake/toolchain-esp32.cmake ${IDF_PATH}/components/esp32/
|
||||
idf.py build || failure "Failed to build with toolchain file in component directory"
|
||||
mv ${IDF_PATH}/components/esp32/toolchain-esp32.cmake ${IDF_PATH}/tools/cmake/
|
||||
assert_built ${APP_BINS} ${BOOTLOADER_BINS} ${PARTITION_BIN}
|
||||
|
||||
print_status "All tests completed"
|
||||
if [ -n "${FAILURES}" ]; then
|
||||
echo "Some failures were detected:"
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
# Given a component name (find_name) and a list of component paths (component_paths),
|
||||
# return the path to the component in 'variable'
|
||||
#
|
||||
# Fatal error is printed if the component is not found.
|
||||
function(find_component_path find_name components component_paths variable)
|
||||
list(FIND components ${find_name} idx)
|
||||
if(NOT idx EQUAL -1)
|
||||
list(GET component_paths ${idx} path)
|
||||
set("${variable}" "${path}" PARENT_SCOPE)
|
||||
return()
|
||||
else()
|
||||
endif()
|
||||
# TODO: find a way to print the dependency chain that lead to this not-found component
|
||||
message(WARNING "Required component ${find_name} is not found in any of the provided COMPONENT_DIRS")
|
||||
endfunction()
|
||||
|
||||
# components_find_all: Search 'component_dirs' for components and return them
|
||||
# as a list of names in 'component_names' and a list of full paths in
|
||||
# 'component_paths'
|
||||
#
|
||||
# component_paths contains only unique component names. Directories
|
||||
# earlier in the component_dirs list take precedence.
|
||||
function(components_find_all component_dirs component_paths component_names test_component_names)
|
||||
# component_dirs entries can be files or lists of files
|
||||
set(paths "")
|
||||
set(names "")
|
||||
set(test_names "")
|
||||
|
||||
# start by expanding the component_dirs list with all subdirectories
|
||||
foreach(dir ${component_dirs})
|
||||
# Iterate any subdirectories for values
|
||||
file(GLOB subdirs LIST_DIRECTORIES true "${dir}/*")
|
||||
foreach(subdir ${subdirs})
|
||||
set(component_dirs "${component_dirs};${subdir}")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Look for a component in each component_dirs entry
|
||||
foreach(dir ${component_dirs})
|
||||
debug("Looking for CMakeLists.txt in ${dir}")
|
||||
file(GLOB component "${dir}/CMakeLists.txt")
|
||||
if(component)
|
||||
debug("CMakeLists.txt file ${component}")
|
||||
get_filename_component(component "${component}" DIRECTORY)
|
||||
get_filename_component(name "${component}" NAME)
|
||||
if(NOT name IN_LIST names)
|
||||
list(APPEND names "${name}")
|
||||
list(APPEND paths "${component}")
|
||||
|
||||
# Look for test component directory
|
||||
file(GLOB test "${component}/test/CMakeLists.txt")
|
||||
if(test)
|
||||
list(APPEND test_names "${name}")
|
||||
endif()
|
||||
endif()
|
||||
else() # no CMakeLists.txt file
|
||||
# test for legacy component.mk and warn
|
||||
file(GLOB legacy_component "${dir}/component.mk")
|
||||
if(legacy_component)
|
||||
get_filename_component(legacy_component "${legacy_component}" DIRECTORY)
|
||||
message(WARNING "Component ${legacy_component} contains old-style component.mk but no CMakeLists.txt. "
|
||||
"Component will be skipped.")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${component_paths} ${paths} PARENT_SCOPE)
|
||||
set(${component_names} ${names} PARENT_SCOPE)
|
||||
set(${test_component_names} ${test_names} PARENT_SCOPE)
|
||||
endfunction()
|
|
@ -133,6 +133,12 @@ function(add_component_dependencies target dep dep_type)
|
|||
endif()
|
||||
endfunction()
|
||||
|
||||
function(require_idf_targets)
|
||||
if(NOT ${IDF_TARGET} IN_LIST ARGN)
|
||||
message(FATAL_ERROR "Component ${COMPONENT_NAME} only supports targets: ${ARGN}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(components_finish_registration)
|
||||
|
||||
# have the executable target depend on all components in the build
|
||||
|
|
|
@ -15,7 +15,7 @@ macro(idf_set_global_variables)
|
|||
|
||||
# Commmon components, required by every component in the build
|
||||
#
|
||||
set_default(COMPONENT_REQUIRES_COMMON "cxx esp32 newlib freertos heap log soc")
|
||||
set_default(COMPONENT_REQUIRES_COMMON "cxx ${IDF_TARGET} newlib freertos heap log soc")
|
||||
|
||||
# PROJECT_PATH has the path to the IDF project (top-level cmake directory)
|
||||
#
|
||||
|
@ -76,7 +76,7 @@ function(idf_set_global_compiler_options)
|
|||
endif()
|
||||
|
||||
# Default compiler configuration
|
||||
add_compile_options(-ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib)
|
||||
add_compile_options(-ffunction-sections -fdata-sections -fstrict-volatile-bitfields -nostdlib)
|
||||
|
||||
# Default warnings configuration
|
||||
add_compile_options(
|
||||
|
|
|
@ -99,6 +99,10 @@ function(kconfig_process_config)
|
|||
set(defaults_arg --defaults "${SDKCONFIG_DEFAULTS}")
|
||||
endif()
|
||||
|
||||
if(EXISTS "${SDKCONFIG_DEFAULTS}.${IDF_TARGET}")
|
||||
list(APPEND defaults_arg --defaults "${SDKCONFIG_DEFAULTS}.${IDF_TARGET}")
|
||||
endif()
|
||||
|
||||
# Set these in the parent scope, so that they can be written to project_description.json
|
||||
set(kconfigs "${kconfigs}")
|
||||
set(COMPONENT_KCONFIGS "${kconfigs}" PARENT_SCOPE)
|
||||
|
|
|
@ -23,6 +23,7 @@ set(CMAKE_MODULE_PATH
|
|||
include(GetGitRevisionDescription)
|
||||
include(utilities)
|
||||
include(components)
|
||||
include(targets)
|
||||
include(kconfig)
|
||||
include(git_submodules)
|
||||
include(idf_functions)
|
||||
|
@ -53,6 +54,9 @@ endif()
|
|||
# top-level "project" call but customize it to do what we want in the IDF build.
|
||||
#
|
||||
macro(project name)
|
||||
# Determine the build target
|
||||
idf_set_target()
|
||||
|
||||
# Set global variables used by rest of the build
|
||||
idf_set_global_variables()
|
||||
|
||||
|
@ -71,6 +75,7 @@ macro(project name)
|
|||
-D "COMPONENT_DIRS=${COMPONENT_DIRS}"
|
||||
-D "BOOTLOADER_BUILD=${BOOTLOADER_BUILD}"
|
||||
-D "IDF_PATH=${IDF_PATH}"
|
||||
-D "IDF_TARGET=${IDF_TARGET}"
|
||||
-D "DEBUG=${DEBUG}"
|
||||
-P "${IDF_PATH}/tools/cmake/scripts/expand_requirements.cmake"
|
||||
WORKING_DIRECTORY "${PROJECT_PATH}")
|
||||
|
@ -102,10 +107,11 @@ macro(project name)
|
|||
# Include sdkconfig.cmake so rest of the build knows the configuration
|
||||
include(${SDKCONFIG_CMAKE})
|
||||
|
||||
# Check that the targets set in cache, sdkconfig, and in environment all match
|
||||
idf_check_config_target()
|
||||
|
||||
# Now the configuration is loaded, set the toolchain appropriately
|
||||
#
|
||||
# TODO: support more toolchains than just ESP32
|
||||
set(CMAKE_TOOLCHAIN_FILE $ENV{IDF_PATH}/tools/cmake/toolchain-esp32.cmake)
|
||||
idf_set_toolchain()
|
||||
|
||||
# Declare the actual cmake-level project
|
||||
_project(${name} ASM C CXX)
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
# TODO: Error out if a component requirement is missing
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
include("${IDF_PATH}/tools/cmake/utilities.cmake")
|
||||
include("${IDF_PATH}/tools/cmake/component_utils.cmake")
|
||||
|
||||
if(NOT DEPENDENCIES_FILE)
|
||||
message(FATAL_ERROR "DEPENDENCIES_FILE must be set.")
|
||||
|
@ -78,75 +79,10 @@ macro(register_config_only_component)
|
|||
register_component()
|
||||
endmacro()
|
||||
|
||||
# Given a component name (find_name) and a list of component paths (component_paths),
|
||||
# return the path to the component in 'variable'
|
||||
#
|
||||
# Fatal error is printed if the component is not found.
|
||||
function(find_component_path find_name components component_paths variable)
|
||||
list(FIND components ${find_name} idx)
|
||||
if(NOT idx EQUAL -1)
|
||||
list(GET component_paths ${idx} path)
|
||||
set("${variable}" "${path}" PARENT_SCOPE)
|
||||
return()
|
||||
else()
|
||||
function(require_idf_targets)
|
||||
if(NOT ${IDF_TARGET} IN_LIST ARGN)
|
||||
message(FATAL_ERROR "Component ${COMPONENT_NAME} only supports targets: ${ARGN}")
|
||||
endif()
|
||||
# TODO: find a way to print the dependency chain that lead to this not-found component
|
||||
message(WARNING "Required component ${find_name} is not found in any of the provided COMPONENT_DIRS")
|
||||
endfunction()
|
||||
|
||||
# components_find_all: Search 'component_dirs' for components and return them
|
||||
# as a list of names in 'component_names' and a list of full paths in
|
||||
# 'component_paths'
|
||||
#
|
||||
# component_paths contains only unique component names. Directories
|
||||
# earlier in the component_dirs list take precedence.
|
||||
function(components_find_all component_dirs component_paths component_names test_component_names)
|
||||
# component_dirs entries can be files or lists of files
|
||||
set(paths "")
|
||||
set(names "")
|
||||
set(test_names "")
|
||||
|
||||
# start by expanding the component_dirs list with all subdirectories
|
||||
foreach(dir ${component_dirs})
|
||||
# Iterate any subdirectories for values
|
||||
file(GLOB subdirs LIST_DIRECTORIES true "${dir}/*")
|
||||
foreach(subdir ${subdirs})
|
||||
set(component_dirs "${component_dirs};${subdir}")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Look for a component in each component_dirs entry
|
||||
foreach(dir ${component_dirs})
|
||||
debug("Looking for CMakeLists.txt in ${dir}")
|
||||
file(GLOB component "${dir}/CMakeLists.txt")
|
||||
if(component)
|
||||
debug("CMakeLists.txt file ${component}")
|
||||
get_filename_component(component "${component}" DIRECTORY)
|
||||
get_filename_component(name "${component}" NAME)
|
||||
if(NOT name IN_LIST names)
|
||||
list(APPEND names "${name}")
|
||||
list(APPEND paths "${component}")
|
||||
|
||||
# Look for test component directory
|
||||
file(GLOB test "${component}/test/CMakeLists.txt")
|
||||
if(test)
|
||||
list(APPEND test_names "${name}")
|
||||
endif()
|
||||
endif()
|
||||
else() # no CMakeLists.txt file
|
||||
# test for legacy component.mk and warn
|
||||
file(GLOB legacy_component "${dir}/component.mk")
|
||||
if(legacy_component)
|
||||
get_filename_component(legacy_component "${legacy_component}" DIRECTORY)
|
||||
message(WARNING "Component ${legacy_component} contains old-style component.mk but no CMakeLists.txt. "
|
||||
"Component will be skipped.")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${component_paths} ${paths} PARENT_SCOPE)
|
||||
set(${component_names} ${names} PARENT_SCOPE)
|
||||
set(${test_component_names} ${test_names} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
include(component_utils)
|
||||
|
||||
macro(idf_set_target)
|
||||
# Input is IDF_TARGET environement variable
|
||||
set(env_idf_target $ENV{IDF_TARGET})
|
||||
|
||||
if(NOT env_idf_target)
|
||||
# IDF_TARGET not set in environment, see if it is set in cache
|
||||
if(IDF_TARGET)
|
||||
set(env_idf_target ${IDF_TARGET})
|
||||
else()
|
||||
set(env_idf_target esp32)
|
||||
message(STATUS "IDF_TARGET not set, using default target: ${env_idf_target}")
|
||||
endif()
|
||||
else()
|
||||
# IDF_TARGET set both in environment and in cache, must be the same
|
||||
if(NOT ${IDF_TARGET} STREQUAL ${env_idf_target})
|
||||
message(FATAL_ERROR "IDF_TARGET in CMake cache does not match "
|
||||
"IDF_TARGET environment variable. To change the target, clear "
|
||||
"the build directory and sdkconfig file, and build the project again")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# IDF_TARGET will be used by Kconfig, make sure it is set
|
||||
set(ENV{IDF_TARGET} ${env_idf_target})
|
||||
|
||||
# Finally, set IDF_TARGET in cache
|
||||
set(IDF_TARGET ${env_idf_target} CACHE STRING "IDF Build Target")
|
||||
|
||||
message(STATUS "Building for target ${IDF_TARGET}")
|
||||
endmacro()
|
||||
|
||||
macro(idf_check_config_target)
|
||||
if(NOT ${IDF_TARGET} STREQUAL ${CONFIG_IDF_TARGET})
|
||||
message(FATAL_ERROR "CONFIG_IDF_TARGET in sdkconfig does not match "
|
||||
"IDF_TARGET environement variable. To change the target, delete "
|
||||
"sdkconfig file and build the project again.")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(idf_set_toolchain)
|
||||
# First try to load the toolchain file from the tools/cmake/ directory of IDF
|
||||
set(toolchain_file_global $ENV{IDF_PATH}/tools/cmake/toolchain-${IDF_TARGET}.cmake)
|
||||
if(EXISTS ${toolchain_file_global})
|
||||
set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_global})
|
||||
else()
|
||||
# Try to load the toolchain file from the directory of ${IDF_TARGET} component
|
||||
find_component_path(${IDF_TARGET} "${BUILD_COMPONENTS}" "${BUILD_COMPONENT_PATHS}" target_component_path)
|
||||
set(toolchain_file_component ${target_component_path}/toolchain-${IDF_TARGET}.cmake)
|
||||
if(EXISTS ${toolchain_file_component})
|
||||
set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_component})
|
||||
else()
|
||||
message(FATAL_ERROR "Toolchain file toolchain-${IDF_TARGET}.cmake not found,"
|
||||
"checked ${toolchain_file_global} and ${toolchain_file_component}")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
|
@ -5,3 +5,5 @@ set(CMAKE_CXX_COMPILER xtensa-esp32-elf-g++)
|
|||
set(CMAKE_ASM_COMPILER xtensa-esp32-elf-gcc)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-nostdlib" CACHE STRING "Linker Base Flags")
|
||||
set(CMAKE_C_FLAGS "-mlongcalls" CACHE STRING "C Compiler Base Flags")
|
||||
set(CMAKE_CXX_FLAGS "-mlongcalls" CACHE STRING "C++ Compiler Base Flags")
|
||||
|
|
|
@ -46,9 +46,10 @@ def main():
|
|||
default=None)
|
||||
|
||||
parser.add_argument('--defaults',
|
||||
help='Optional project defaults file, used if --config file doesn\'t exist',
|
||||
help='Optional project defaults file, used if --config file doesn\'t exist. Multiple files can be specified using multiple --defaults arguments.',
|
||||
nargs='?',
|
||||
default=None)
|
||||
default=[],
|
||||
action='append')
|
||||
|
||||
parser.add_argument('--create-config-if-missing',
|
||||
help='If set, a new config file will be saved if the old one is not found',
|
||||
|
@ -84,12 +85,14 @@ def main():
|
|||
|
||||
config = kconfiglib.Kconfig(args.kconfig)
|
||||
|
||||
if args.defaults is not None:
|
||||
if len(args.defaults) > 0:
|
||||
# always load defaults first, so any items which are not defined in that config
|
||||
# will have the default defined in the defaults file
|
||||
if not os.path.exists(args.defaults):
|
||||
raise RuntimeError("Defaults file not found: %s" % args.defaults)
|
||||
config.load_config(args.defaults)
|
||||
for name in args.defaults:
|
||||
print("Loading defaults file %s..." % name)
|
||||
if not os.path.exists(name):
|
||||
raise RuntimeError("Defaults file not found: %s" % name)
|
||||
config.load_config(name, replace=False)
|
||||
|
||||
if args.config is not None:
|
||||
if os.path.exists(args.config):
|
||||
|
@ -97,7 +100,7 @@ def main():
|
|||
elif args.create_config_if_missing:
|
||||
print("Creating config file %s..." % args.config)
|
||||
config.write_config(args.config)
|
||||
elif args.default is None:
|
||||
elif args.config is None:
|
||||
raise RuntimeError("Config file not found: %s" % args.config)
|
||||
|
||||
for output_type, filename in args.output:
|
||||
|
|
Ładowanie…
Reference in New Issue