feat(tools): Added create-project argument to allow cpp project creation

Closes https://github.com/espressif/esp-idf/issues/16121
This commit is contained in:
Jakub Kocka
2026-04-28 09:24:20 +02:00
parent b1d68624e1
commit fb02854ad6
8 changed files with 58 additions and 10 deletions
+24 -9
View File
@@ -1,12 +1,12 @@
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import os
import re
import stat
import sys
from collections.abc import Callable
from shutil import copyfile
from shutil import copytree
from typing import Dict
import click
@@ -65,9 +65,11 @@ def make_directory_permissions_writable(root_path: str) -> None:
continue
def create_project(target_path: str, name: str) -> None:
def create_project(target_path: str, name: str, *, use_cpp: bool = False) -> None:
template = 'sample_project_cpp' if use_cpp else 'sample_project'
main_ext = 'cpp' if use_cpp else 'c'
copytree(
os.path.join(os.environ['IDF_PATH'], 'tools', 'templates', 'sample_project'),
os.path.join(os.environ['IDF_PATH'], 'tools', 'templates', template),
target_path,
# 'copyfile' ensures only data are copied, without any metadata (file permissions) - for files only
copy_function=copyfile,
@@ -76,7 +78,10 @@ def create_project(target_path: str, name: str) -> None:
# since 'copyfile' does preserve directory metadata, we need to make sure the directories are writable
make_directory_permissions_writable(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'))))
os.rename(
os.path.join(main_folder, '.'.join(('main', main_ext))),
os.path.join(main_folder, '.'.join((name, main_ext))),
)
replace_in_file(os.path.join(main_folder, 'CMakeLists.txt'), 'main', name)
replace_in_file(os.path.join(target_path, 'CMakeLists.txt'), 'main', name)
@@ -100,14 +105,17 @@ def create_component(target_path: str, name: str) -> None:
replace_in_file(os.path.join(target_path, 'CMakeLists.txt'), 'main', name)
def action_extensions(base_actions: Dict, project_path: str) -> Dict:
def create_new(action: str, ctx: click.core.Context, global_args: PropertyDict, **action_args: str) -> Dict:
def action_extensions(base_actions: dict, project_path: str) -> dict:
def create_new(action: str, ctx: click.core.Context, global_args: PropertyDict, **action_args: str) -> dict:
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'])
func_action_map: dict[str, Callable[..., None]] = {
'create-project': lambda tp, n, aa: create_project(tp, n, use_cpp=bool(aa.get('cpp'))),
'create-component': lambda tp, n, aa: create_component(tp, n),
}
func_action_map[action](target_path, action_args['name'], action_args)
print('The', get_type(action), 'was created in', os.path.abspath(target_path))
@@ -125,6 +133,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'`idf.py create-project new_proj` '
'will create a new project in subdirectory called `new_proj` '
'of the current working directory. '
'Use `--cpp` to generate a C++ source file (`NAME.cpp`) with `extern "C" void app_main(void)`. '
"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. '
@@ -143,6 +152,12 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'will be created directly in the given folder if it does not contain anything'
),
},
{
'names': ['--cpp'],
'is_flag': True,
'default': False,
'help': 'Create a C++ main source file instead of C.',
},
],
},
'create-component': {