mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
add new command to idf
This commit is contained in:
parent
eebc71b16d
commit
b599f127b5
@ -117,6 +117,21 @@ Note that some older versions of CCache may exhibit bugs on some platforms, so i
|
|||||||
- ``-v`` flag causes both ``idf.py`` and the build system to produce verbose build output. This can be useful for debugging build problems.
|
- ``-v`` flag causes both ``idf.py`` and the build system to produce verbose build output. This can be useful for debugging build problems.
|
||||||
- ``--cmake-warn-uninitialized`` (or ``-w``) will cause CMake to print uninitialized variable warnings inside the project directory (not for directories not found inside the project directory). This only controls CMake variable warnings inside CMake itself, not other types of build warnings. This option can also be set permanently by setting the ``IDF_CMAKE_WARN_UNINITIALIZED`` environment variable to a non-zero value.
|
- ``--cmake-warn-uninitialized`` (or ``-w``) will cause CMake to print uninitialized variable warnings inside the project directory (not for directories not found inside the project directory). This only controls CMake variable warnings inside CMake itself, not other types of build warnings. This option can also be set permanently by setting the ``IDF_CMAKE_WARN_UNINITIALIZED`` environment variable to a non-zero value.
|
||||||
|
|
||||||
|
|
||||||
|
Start a new project
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Use the command ``idf.py create-project`` for starting a new project. Execute ``idf.py create-project --help`` for more information.
|
||||||
|
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
idf.py create-project --path my_projects my_new_project
|
||||||
|
|
||||||
|
This example will create a new project called my_new_project directly into the directory my_projects.
|
||||||
|
|
||||||
Using CMake Directly
|
Using CMake Directly
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@ -344,6 +359,23 @@ are discussed :ref:`here<cmake-component-register>`.
|
|||||||
|
|
||||||
See `example component requirements`_ and `example component CMakeLists`_ for more complete component ``CMakeLists.txt`` examples.
|
See `example component requirements`_ and `example component CMakeLists`_ for more complete component ``CMakeLists.txt`` examples.
|
||||||
|
|
||||||
|
Create a new component
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Use the command ``idf.py create-component`` for creating a new component.
|
||||||
|
The new component will contain set of files necessary for building a component.
|
||||||
|
You may include the component's header file into your project and use its functionality.
|
||||||
|
For more information execute ``idf.py create-component --help``.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
idf.py -C components create-component my_component
|
||||||
|
|
||||||
|
The example will create a new component in the subdirectory `components` under the current working directory.
|
||||||
|
For more information about components follow the documentation page :ref:`see above <component-directories>`.
|
||||||
|
|
||||||
.. _component variables:
|
.. _component variables:
|
||||||
|
|
||||||
Preset Component Variables
|
Preset Component Variables
|
||||||
|
@ -18,7 +18,7 @@ Select the instructions depending on Espressif chip installed on your developmen
|
|||||||
|
|
||||||
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
|
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
|
||||||
|
|
||||||
ESP-IDF projects are build using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
|
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
|
||||||
|
|
||||||
Below is short explanation of remaining files in the project folder.
|
Below is short explanation of remaining files in the project folder.
|
||||||
|
|
||||||
|
7
examples/get-started/sample_project/CMakeLists.txt
Normal file
7
examples/get-started/sample_project/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# For more information about build system see https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||||
|
# The following five lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(main)
|
8
examples/get-started/sample_project/Makefile
Normal file
8
examples/get-started/sample_project/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := sample_project
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
32
examples/get-started/sample_project/README.md
Normal file
32
examples/get-started/sample_project/README.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# _Sample project_
|
||||||
|
|
||||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||||
|
|
||||||
|
This is the simplest buildable example. The example is used by command `idf.py create-project`
|
||||||
|
that copies the project to user specified path and set it's name. For more information follow the [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## How to use example
|
||||||
|
We encourage the users to use the example as a template for the new projects.
|
||||||
|
A recommended way is to follow the instructions on a [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project).
|
||||||
|
|
||||||
|
## Example folder contents
|
||||||
|
|
||||||
|
The project **sample_project** contains one source file in C language [main.c](main/main.c). The file is located in folder [main](main).
|
||||||
|
|
||||||
|
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt`
|
||||||
|
files that provide set of directives and instructions describing the project's source files and targets
|
||||||
|
(executable, library, or both).
|
||||||
|
|
||||||
|
Below is short explanation of remaining files in the project folder.
|
||||||
|
|
||||||
|
```
|
||||||
|
├── CMakeLists.txt
|
||||||
|
├── main
|
||||||
|
│ ├── CMakeLists.txt
|
||||||
|
│ └── main.c
|
||||||
|
└── README.md This is the file you are currently reading
|
||||||
|
```
|
||||||
|
Additionally, the sample project contains Makefile and component.mk files, used for the legacy Make based build system.
|
||||||
|
They are not used or needed when building with CMake and idf.py.
|
2
examples/get-started/sample_project/main/CMakeLists.txt
Normal file
2
examples/get-started/sample_project/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
idf_component_register(SRCS "main.c"
|
||||||
|
INCLUDE_DIRS ".")
|
5
examples/get-started/sample_project/main/component.mk
Normal file
5
examples/get-started/sample_project/main/component.mk
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||||
|
|
6
examples/get-started/sample_project/main/main.c
Normal file
6
examples/get-started/sample_project/main/main.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -758,7 +758,7 @@ endmenu\n" >> ${IDF_PATH}/Kconfig
|
|||||||
clean_build_dir
|
clean_build_dir
|
||||||
mkdir -p components/esp32
|
mkdir -p components/esp32
|
||||||
echo "idf_component_get_property(overriden_dir \${COMPONENT_NAME} COMPONENT_OVERRIDEN_DIR)" >> components/esp32/CMakeLists.txt
|
echo "idf_component_get_property(overriden_dir \${COMPONENT_NAME} COMPONENT_OVERRIDEN_DIR)" >> components/esp32/CMakeLists.txt
|
||||||
echo "message(STATUS overriden_dir:\${overriden_dir})" >> components/esp32/CMakeLists.txt
|
echo "message(STATUS overriden_dir:\${overriden_dir})" >> components/esp32/CMakeLists.txt
|
||||||
(idf.py reconfigure | grep "overriden_dir:$IDF_PATH/components/esp32") || failure "Failed to get overriden dir" # no registration, overrides registration as well
|
(idf.py reconfigure | grep "overriden_dir:$IDF_PATH/components/esp32") || failure "Failed to get overriden dir" # no registration, overrides registration as well
|
||||||
print_status "Overriding Kconfig"
|
print_status "Overriding Kconfig"
|
||||||
echo "idf_component_register(KCONFIG \${overriden_dir}/Kconfig)" >> components/esp32/CMakeLists.txt
|
echo "idf_component_register(KCONFIG \${overriden_dir}/Kconfig)" >> components/esp32/CMakeLists.txt
|
||||||
@ -767,6 +767,44 @@ endmenu\n" >> ${IDF_PATH}/Kconfig
|
|||||||
(idf.py reconfigure | grep "kconfig:$IDF_PATH/components/esp32/Kconfig") || failure "Failed to verify original `main` directory"
|
(idf.py reconfigure | grep "kconfig:$IDF_PATH/components/esp32/Kconfig") || failure "Failed to verify original `main` directory"
|
||||||
rm -rf components
|
rm -rf components
|
||||||
|
|
||||||
|
print_status "Create project using idf.py and build it"
|
||||||
|
echo "Trying to create project."
|
||||||
|
(idf.py -C projects create-project temp_test_project) || failure "Failed to create the project."
|
||||||
|
cd "$IDF_PATH/projects/temp_test_project"
|
||||||
|
echo "Building the project temp_test_project . . ."
|
||||||
|
idf.py build || failure "Failed to build the project."
|
||||||
|
cd "$IDF_PATH"
|
||||||
|
rm -rf "$IDF_PATH/projects/temp_test_project"
|
||||||
|
|
||||||
|
print_status "Create component using idf.py, create project using idf.py."
|
||||||
|
print_status "Add the component to the created project and build the project."
|
||||||
|
echo "Trying to create project . . ."
|
||||||
|
(idf.py -C projects create-project temp_test_project) || failure "Failed to create the project."
|
||||||
|
echo "Trying to create component . . ."
|
||||||
|
(idf.py -C components create-component temp_test_component) || failure "Failed to create the component."
|
||||||
|
${SED} -i '5i\\tfunc();' "$IDF_PATH/projects/temp_test_project/main/temp_test_project.c"
|
||||||
|
${SED} -i '5i#include "temp_test_component.h"' "$IDF_PATH/projects/temp_test_project/main/temp_test_project.c"
|
||||||
|
cd "$IDF_PATH/projects/temp_test_project"
|
||||||
|
idf.py build || failure "Failed to build the project."
|
||||||
|
cd "$IDF_PATH"
|
||||||
|
rm -rf "$IDF_PATH/projects/temp_test_project"
|
||||||
|
rm -rf "$IDF_PATH/components/temp_test_component"
|
||||||
|
|
||||||
|
print_status "Check that command for creating new project will fail if the target folder is not empty."
|
||||||
|
mkdir "$IDF_PATH/example_proj/"
|
||||||
|
touch "$IDF_PATH/example_proj/tmp_130698"
|
||||||
|
EXPECTED_EXIT_VALUE=3
|
||||||
|
expected_failure $EXPECTED_EXIT_VALUE idf.py create-project --path "$IDF_PATH/example_proj/" temp_test_project || failure "Command exit value is wrong."
|
||||||
|
rm -rf "$IDF_PATH/example_proj/"
|
||||||
|
|
||||||
|
print_status "Check that command for creating new project will fail if the target path is file."
|
||||||
|
touch "$IDF_PATH/example_proj"
|
||||||
|
EXPECTED_EXIT_VALUE=4
|
||||||
|
expected_failure $EXPECTED_EXIT_VALUE idf.py create-project --path "$IDF_PATH/example_proj" temp_test_project || failure "Command exit value is wrong."
|
||||||
|
rm -rf "$IDF_PATH/example_proj"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print_status "All tests completed"
|
print_status "All tests completed"
|
||||||
if [ -n "${FAILURES}" ]; then
|
if [ -n "${FAILURES}" ]; then
|
||||||
echo "Some failures were detected:"
|
echo "Some failures were detected:"
|
||||||
@ -791,6 +829,15 @@ function failure()
|
|||||||
FAILURES="${FAILURES}${STATUS} :: $1\n"
|
FAILURES="${FAILURES}${STATUS} :: $1\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function expected_failure() {
|
||||||
|
"${@:2}"
|
||||||
|
EXIT_VALUE=$?
|
||||||
|
if [ $EXIT_VALUE != "$1" ]; then
|
||||||
|
echo "[ERROR] Exit value of executed command is $EXIT_VALUE (expected $1)"; return 1
|
||||||
|
else return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
TESTDIR=${PWD}/build_system_tests_$$
|
TESTDIR=${PWD}/build_system_tests_$$
|
||||||
mkdir -p ${TESTDIR}
|
mkdir -p ${TESTDIR}
|
||||||
# set NOCLEANUP=1 if you want to keep the test directory around
|
# set NOCLEANUP=1 if you want to keep the test directory around
|
||||||
|
@ -210,6 +210,7 @@ def action_extensions(base_actions, project_path):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"names": ["-C", "--project-dir"],
|
"names": ["-C", "--project-dir"],
|
||||||
|
"scope": "shared",
|
||||||
"help": "Project directory.",
|
"help": "Project directory.",
|
||||||
"type": click.Path(),
|
"type": click.Path(),
|
||||||
"default": os.getcwd(),
|
"default": os.getcwd(),
|
||||||
|
120
tools/idf_py_actions/create_ext.py
Normal file
120
tools/idf_py_actions/create_ext.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from distutils.dir_util import copy_tree
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def get_type(action):
|
||||||
|
return action.split("-")[1]
|
||||||
|
|
||||||
|
|
||||||
|
def replace_in_file(filename, pattern, replacement):
|
||||||
|
with open(filename, 'r+') as f:
|
||||||
|
content = f.read()
|
||||||
|
overwritten_content = re.sub(pattern, replacement, content, flags=re.M)
|
||||||
|
f.seek(0)
|
||||||
|
f.write(overwritten_content)
|
||||||
|
f.truncate()
|
||||||
|
|
||||||
|
|
||||||
|
def is_empty_and_create(path, action):
|
||||||
|
abspath = os.path.abspath(path)
|
||||||
|
if not os.path.exists(abspath):
|
||||||
|
os.makedirs(abspath)
|
||||||
|
elif not os.path.isdir(abspath):
|
||||||
|
print("Your target path is not a directory. Please remove the", os.path.abspath(abspath),
|
||||||
|
"or use different target path.")
|
||||||
|
sys.exit(4)
|
||||||
|
elif len(os.listdir(path)) > 0:
|
||||||
|
print("The directory", abspath, "is not empty. To create a", get_type(action),
|
||||||
|
"you must empty the directory or choose a different path.")
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
|
||||||
|
def create_project(target_path, name):
|
||||||
|
copy_tree(os.path.join(os.environ['IDF_PATH'], "examples", "get-started", "sample_project"), target_path)
|
||||||
|
main_folder = os.path.join(target_path, "main")
|
||||||
|
os.rename(os.path.join(main_folder, "main.c"), os.path.join(main_folder, ".".join((name, "c"))))
|
||||||
|
replace_in_file(os.path.join(main_folder, "CMakeLists.txt"), "main", name)
|
||||||
|
replace_in_file(os.path.join(target_path, "CMakeLists.txt"), "main", name)
|
||||||
|
os.remove(os.path.join(target_path, "README.md"))
|
||||||
|
|
||||||
|
# after manual removing "Makefile" and "component.mk" from `examples/get-started/sample_project`
|
||||||
|
# remove following two lines as well
|
||||||
|
os.remove(os.path.join(target_path, "Makefile"))
|
||||||
|
os.remove(os.path.join(target_path, "main", "component.mk"))
|
||||||
|
|
||||||
|
|
||||||
|
def create_component(target_path, name):
|
||||||
|
copy_tree(os.path.join(os.environ['IDF_PATH'], "tools", "templates", "sample_component"), target_path)
|
||||||
|
os.rename(os.path.join(target_path, "main.c"), os.path.join(target_path, ".".join((name, "c"))))
|
||||||
|
os.rename(os.path.join(target_path, "include", "main.h"),
|
||||||
|
os.path.join(target_path, "include", ".".join((name, "h"))))
|
||||||
|
|
||||||
|
replace_in_file(os.path.join(target_path, ".".join((name, "c"))), "main", name)
|
||||||
|
replace_in_file(os.path.join(target_path, "CMakeLists.txt"), "main", name)
|
||||||
|
|
||||||
|
|
||||||
|
def action_extensions(base_actions, project_path):
|
||||||
|
def create_new(action, ctx, global_args, **action_args):
|
||||||
|
target_path = action_args.get('path') or os.path.join(project_path, action_args['name'])
|
||||||
|
|
||||||
|
is_empty_and_create(target_path, action)
|
||||||
|
|
||||||
|
func_action_map = {"create-project": create_project, "create-component": create_component}
|
||||||
|
func_action_map[action](target_path, action_args['name'])
|
||||||
|
|
||||||
|
print("The", get_type(action), "was created in", os.path.abspath(target_path))
|
||||||
|
|
||||||
|
# after the command execution, no other commands are accepted and idf.py terminates
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"actions": {
|
||||||
|
"create-project": {
|
||||||
|
"callback": create_new,
|
||||||
|
"short_help": "Create a new project.",
|
||||||
|
"help": ("Create a new project with the name NAME specified as argument. "
|
||||||
|
"For example: "
|
||||||
|
"`idf.py create-project new_proj` "
|
||||||
|
"will create a new project in subdirectory called `new_proj` "
|
||||||
|
"of the current working directory. "
|
||||||
|
"For specifying the new project's path, use either the option --path for specifying the "
|
||||||
|
"destination directory, or the global option -C if the project should be created as a "
|
||||||
|
"subdirectory of the specified directory. "
|
||||||
|
"If the target path does not exist it will be created. If the target folder is not empty "
|
||||||
|
"then the operation will fail with return code 3. "
|
||||||
|
"If the target path is not a folder, the script will fail with return code 4. "
|
||||||
|
"After the execution idf.py terminates "
|
||||||
|
"so this operation should be used alone."),
|
||||||
|
"arguments": [{"names": ["name"]}],
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"names": ["-p", "--path"],
|
||||||
|
"help": ("Set the path for the new project. The project "
|
||||||
|
"will be created directly in the given folder if it does not contain anything"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
},
|
||||||
|
"create-component": {
|
||||||
|
"callback": create_new,
|
||||||
|
"short_help": "Create a new component.",
|
||||||
|
"help": ("Create a new component with the name NAME specified as argument. "
|
||||||
|
"For example: "
|
||||||
|
"`idf.py create-component new_comp` "
|
||||||
|
"will create a new component in subdirectory called `new_comp` "
|
||||||
|
"of the current working directory. "
|
||||||
|
"For specifying the new component's path use the option -C. "
|
||||||
|
"If the target path does not exist then it will be created. "
|
||||||
|
"If the target folder is not empty "
|
||||||
|
"then the operation will fail with return code 3. "
|
||||||
|
"If the target path is not a folder, the script will fail with return code 4. "
|
||||||
|
"After the execution idf.py terminates "
|
||||||
|
"so this operation should be used alone."),
|
||||||
|
"arguments": [{"names": ["name"]}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
tools/templates/sample_component/CMakeLists.txt
Normal file
2
tools/templates/sample_component/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
idf_component_register(SRCS "main.c"
|
||||||
|
INCLUDE_DIRS "include")
|
1
tools/templates/sample_component/include/main.h
Normal file
1
tools/templates/sample_component/include/main.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
void func(void);
|
7
tools/templates/sample_component/main.c
Normal file
7
tools/templates/sample_component/main.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
void func(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user