Update support for ESP-IDF v4.1

This commit is contained in:
valeros
2020-09-01 21:26:55 +03:00
parent 78be15e0d1
commit ff997d3677
4 changed files with 280 additions and 178 deletions
+261 -168
View File
@@ -24,53 +24,52 @@ import copy
import json import json
import subprocess import subprocess
import sys import sys
from os import environ, listdir, makedirs, rename, pathsep import os
from os.path import (
abspath,
basename,
dirname,
getmtime,
isabs,
isdir,
isfile,
join,
realpath,
relpath,
)
import click import click
from SCons.Script import ( from SCons.Script import (
ARGUMENTS, ARGUMENTS,
COMMAND_LINE_TARGETS, COMMAND_LINE_TARGETS,
AlwaysBuild,
DefaultEnvironment, DefaultEnvironment,
) )
from platformio.builder.tools.piolib import ProjectAsLibBuilder from platformio import fs
from platformio.fs import to_unix_path from platformio.proc import exec_command
from platformio.proc import exec_command, where_is_program
from platformio.util import get_systype from platformio.util import get_systype
from platformio.builder.tools.piolib import ProjectAsLibBuilder
env = DefaultEnvironment() env = DefaultEnvironment()
platform = env.PioPlatform()
env.SConscript("_embed_files.py", exports="env") env.SConscript("_embed_files.py", exports="env")
FRAMEWORK_DIR = platform.get_package_dir("framework-espidf") platform = env.PioPlatform()
assert FRAMEWORK_DIR and isdir(FRAMEWORK_DIR) board = env.BoardConfig()
mcu = board.get("build.mcu", "esp32")
idf_variant = board.get(
"build.esp-idf.variant", "esp32s2beta" if mcu == "esp32s2" else "esp32"
)
FRAMEWORK_DIR = platform.get_package_dir("framework-espidf")
TOOLCHAIN_DIR = platform.get_package_dir(
"toolchain-xtensa%s" % ("32s2" if mcu == "esp32s2" else "32")
)
assert os.path.isdir(FRAMEWORK_DIR)
# Arduino framework as a component is not compatible with ESP-IDF >=4.1
if "arduino" in env.subst("$PIOFRAMEWORK"): if "arduino" in env.subst("$PIOFRAMEWORK"):
ARDUINO_FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32") ARDUINO_FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32")
# Possible package names in 'package@version' format is not compatible with CMake # Possible package names in 'package@version' format is not compatible with CMake
if "@" in basename(ARDUINO_FRAMEWORK_DIR): if "@" in os.path.basename(ARDUINO_FRAMEWORK_DIR):
new_path = join( new_path = os.path.join(
dirname(ARDUINO_FRAMEWORK_DIR), os.path.dirname(ARDUINO_FRAMEWORK_DIR),
basename(ARDUINO_FRAMEWORK_DIR).replace("@", "-"), os.path.basename(ARDUINO_FRAMEWORK_DIR).replace("@", "-"),
) )
rename(ARDUINO_FRAMEWORK_DIR, new_path) os.rename(ARDUINO_FRAMEWORK_DIR, new_path)
ARDUINO_FRAMEWORK_DIR = new_path ARDUINO_FRAMEWORK_DIR = new_path
assert ARDUINO_FRAMEWORK_DIR and isdir(ARDUINO_FRAMEWORK_DIR) assert ARDUINO_FRAMEWORK_DIR and os.path.isdir(ARDUINO_FRAMEWORK_DIR)
BUILD_DIR = env.subst("$BUILD_DIR")
CMAKE_API_REPLY_PATH = os.path.join(".cmake", "api", "v1", "reply")
try: try:
import future import future
@@ -79,23 +78,28 @@ try:
except ImportError: except ImportError:
env.Execute( env.Execute(
env.VerboseAction( env.VerboseAction(
'$PYTHONEXE -m pip install "cryptography>=2.1.4" "future>=0.15.2" "pyparsing>=2.0.3,<2.4.0"', '$PYTHONEXE -m pip install "cryptography>=2.1.4" "future>=0.15.2" "pyparsing>=2.0.3,<2.4.0" ',
"Installing ESP-IDF's Python dependencies", "Installing ESP-IDF's Python dependencies",
) )
) )
platform = env.PioPlatform() # a special "esp-windows-curses" python package is required on Windows for Menuconfig
board = env.BoardConfig() if "windows" in get_systype():
import pkg_resources
FRAMEWORK_DIR = platform.get_package_dir("framework-espidf") if "esp-windows-curses" not in {pkg.key for pkg in pkg_resources.working_set}:
assert isdir(FRAMEWORK_DIR) env.Execute(
env.VerboseAction(
BUILD_DIR = env.subst("$BUILD_DIR") '$PYTHONEXE -m pip install "file://%s/tools/kconfig_new/esp-windows-curses"'
CMAKE_API_REPLY_PATH = join(".cmake", "api", "v1", "reply") % FRAMEWORK_DIR,
"Installing windows-curses package",
)
)
def get_project_lib_includes(env): def get_project_lib_includes(env):
project = ProjectAsLibBuilder(env, "$PROJECT_DIR") project = ProjectAsLibBuilder(env, "$PROJECT_DIR")
project.install_dependencies()
project.search_deps_recursive() project.search_deps_recursive()
paths = [] paths = []
@@ -111,25 +115,27 @@ def get_project_lib_includes(env):
def is_cmake_reconfigure_required(cmake_api_reply_dir): def is_cmake_reconfigure_required(cmake_api_reply_dir):
cmake_cache_file = join(BUILD_DIR, "CMakeCache.txt") cmake_cache_file = os.path.join(BUILD_DIR, "CMakeCache.txt")
cmake_txt_files = [ cmake_txt_files = [
join(env.subst("$PROJECT_DIR"), "CMakeLists.txt"), os.path.join(env.subst("$PROJECT_DIR"), "CMakeLists.txt"),
join(env.subst("$PROJECT_SRC_DIR"), "CMakeLists.txt") os.path.join(env.subst("$PROJECT_SRC_DIR"), "CMakeLists.txt"),
] ]
cmake_preconf_dir = join(BUILD_DIR, "config") cmake_preconf_dir = os.path.join(BUILD_DIR, "config")
sdkconfig = join(env.subst("$PROJECT_DIR"), "sdkconfig") sdkconfig = os.path.join(env.subst("$PROJECT_DIR"), "sdkconfig")
for d in (cmake_api_reply_dir, cmake_preconf_dir): for d in (cmake_api_reply_dir, cmake_preconf_dir):
if not isdir(d) or not listdir(d): if not os.path.isdir(d) or not os.listdir(d):
return True return True
if not isfile(cmake_cache_file): if not os.path.isfile(cmake_cache_file):
return True return True
if not isfile(join(BUILD_DIR, "build.ninja")): if not os.path.isfile(os.path.join(BUILD_DIR, "build.ninja")):
return True return True
if isfile(sdkconfig) and getmtime(sdkconfig) > getmtime(cmake_cache_file): if os.path.isfile(sdkconfig) and os.path.getmtime(sdkconfig) > os.path.getmtime(
cmake_cache_file
):
return True return True
if any( if any(
getmtime(f) > getmtime(cmake_cache_file) os.path.getmtime(f) > os.path.getmtime(cmake_cache_file)
for f in cmake_txt_files + [cmake_preconf_dir] for f in cmake_txt_files + [cmake_preconf_dir]
): ):
return True return True
@@ -139,10 +145,10 @@ def is_cmake_reconfigure_required(cmake_api_reply_dir):
def is_proper_idf_project(): def is_proper_idf_project():
return all( return all(
isfile(path) os.path.isfile(path)
for path in ( for path in (
join(env.subst("$PROJECT_DIR"), "CMakeLists.txt"), os.path.join(env.subst("$PROJECT_DIR"), "CMakeLists.txt"),
join(env.subst("$PROJECT_SRC_DIR"), "CMakeLists.txt"), os.path.join(env.subst("$PROJECT_SRC_DIR"), "CMakeLists.txt"),
) )
) )
@@ -159,7 +165,7 @@ def normalize_path(path):
project_dir = env.subst("$PROJECT_DIR") project_dir = env.subst("$PROJECT_DIR")
if project_dir in path: if project_dir in path:
path = path.replace(project_dir, "${CMAKE_SOURCE_DIR}") path = path.replace(project_dir, "${CMAKE_SOURCE_DIR}")
return to_unix_path(path) return fs.to_unix_path(path)
def create_default_project_files(): def create_default_project_files():
@@ -175,33 +181,30 @@ FILE(GLOB_RECURSE app_sources %s/*.*)
idf_component_register(SRCS ${app_sources}) idf_component_register(SRCS ${app_sources})
""" """
if not listdir(join(env.subst("$PROJECT_SRC_DIR"))): if not os.listdir(os.path.join(env.subst("$PROJECT_SRC_DIR"))):
# create a default main file to make CMake happy during first init # create a default main file to make CMake happy during first init
with open(join(env.subst("$PROJECT_SRC_DIR"), "main.c"), "w") as fp: with open(os.path.join(env.subst("$PROJECT_SRC_DIR"), "main.c"), "w") as fp:
fp.write("void app_main() {}") fp.write("void app_main() {}")
project_dir = env.subst("$PROJECT_DIR") project_dir = env.subst("$PROJECT_DIR")
if not isfile(join(project_dir, "CMakeLists.txt")): if not os.path.isfile(os.path.join(project_dir, "CMakeLists.txt")):
with open(join(project_dir, "CMakeLists.txt"), "w") as fp: with open(os.path.join(project_dir, "CMakeLists.txt"), "w") as fp:
fp.write(root_cmake_tpl % basename(project_dir)) fp.write(root_cmake_tpl % os.path.basename(project_dir))
project_src_dir = env.subst("$PROJECT_SRC_DIR") project_src_dir = env.subst("$PROJECT_SRC_DIR")
if not isfile(join(project_src_dir, "CMakeLists.txt")): if not os.path.isfile(os.path.join(project_src_dir, "CMakeLists.txt")):
with open(join(project_src_dir, "CMakeLists.txt"), "w") as fp: with open(os.path.join(project_src_dir, "CMakeLists.txt"), "w") as fp:
fp.write( fp.write(prj_cmake_tpl % normalize_path(env.subst("$PROJECT_SRC_DIR")))
prj_cmake_tpl
% normalize_path(env.subst("$PROJECT_SRC_DIR"))
)
def get_cmake_code_model(src_dir, build_dir, extra_args=None): def get_cmake_code_model(src_dir, build_dir, extra_args=None):
cmake_api_dir = join(build_dir, ".cmake", "api", "v1") cmake_api_dir = os.path.join(build_dir, ".cmake", "api", "v1")
cmake_api_query_dir = join(cmake_api_dir, "query") cmake_api_query_dir = os.path.join(cmake_api_dir, "query")
cmake_api_reply_dir = join(cmake_api_dir, "reply") cmake_api_reply_dir = os.path.join(cmake_api_dir, "reply")
query_file = join(cmake_api_query_dir, "codemodel-v2") query_file = os.path.join(cmake_api_query_dir, "codemodel-v2")
if not isfile(query_file): if not os.path.isfile(query_file):
makedirs(dirname(query_file)) os.makedirs(os.path.dirname(query_file))
open(query_file, "a").close() # create an empty file open(query_file, "a").close() # create an empty file
if not is_proper_idf_project(): if not is_proper_idf_project():
@@ -210,14 +213,14 @@ def get_cmake_code_model(src_dir, build_dir, extra_args=None):
if is_cmake_reconfigure_required(cmake_api_reply_dir): if is_cmake_reconfigure_required(cmake_api_reply_dir):
run_cmake(src_dir, build_dir, extra_args) run_cmake(src_dir, build_dir, extra_args)
if not isdir(cmake_api_reply_dir) or not listdir(cmake_api_reply_dir): if not os.path.isdir(cmake_api_reply_dir) or not os.listdir(cmake_api_reply_dir):
sys.stderr.write("Error: Couldn't find CMake API response file\n") sys.stderr.write("Error: Couldn't find CMake API response file\n")
env.Exit(1) env.Exit(1)
codemodel = {} codemodel = {}
for target in listdir(cmake_api_reply_dir): for target in os.listdir(cmake_api_reply_dir):
if target.startswith("codemodel-v2"): if target.startswith("codemodel-v2"):
with open(join(cmake_api_reply_dir, target), "r") as fp: with open(os.path.join(cmake_api_reply_dir, target), "r") as fp:
codemodel = json.load(fp) codemodel = json.load(fp)
assert codemodel["version"]["major"] == 2 assert codemodel["version"]["major"] == 2
@@ -225,26 +228,25 @@ def get_cmake_code_model(src_dir, build_dir, extra_args=None):
def populate_idf_env_vars(idf_env): def populate_idf_env_vars(idf_env):
idf_env["IDF_PATH"] = platform.get_package_dir("framework-espidf") idf_env["IDF_PATH"] = FRAMEWORK_DIR
additional_packages = [ additional_packages = [
join(platform.get_package_dir("toolchain-xtensa32"), "bin"), os.path.join(TOOLCHAIN_DIR, "bin"),
join(platform.get_package_dir("toolchain-esp32ulp"), "bin"), os.path.join(platform.get_package_dir("toolchain-%sulp" % mcu), "bin"),
platform.get_package_dir("tool-ninja"), platform.get_package_dir("tool-ninja"),
join(platform.get_package_dir("tool-cmake"), "bin"), os.path.join(platform.get_package_dir("tool-cmake"), "bin"),
dirname(where_is_program("python")), os.path.dirname(env.subst("$PYTHONEXE")),
] ]
if "windows" in get_systype(): if "windows" in get_systype():
additional_packages.append(platform.get_package_dir("tool-mconf")) additional_packages.append(platform.get_package_dir("tool-mconf"))
idf_env["PATH"] = pathsep.join(additional_packages + [idf_env["PATH"]]) idf_env["PATH"] = os.pathsep.join(additional_packages + [idf_env["PATH"]])
def get_target_config(project_configs, target_index, cmake_api_reply_dir): def get_target_config(project_configs, target_index, cmake_api_reply_dir):
target_json = project_configs.get("targets")[target_index].get("jsonFile", "") target_json = project_configs.get("targets")[target_index].get("jsonFile", "")
target_config_file = join(cmake_api_reply_dir, target_json) target_config_file = os.path.join(cmake_api_reply_dir, target_json)
if not isfile(target_config_file): if not os.path.isfile(target_config_file):
sys.stderr.write("Error: Couldn't find target config %s\n" % target_json) sys.stderr.write("Error: Couldn't find target config %s\n" % target_json)
env.Exit(1) env.Exit(1)
@@ -269,12 +271,12 @@ def build_library(default_env, lib_config, project_src_dir, prepend_dir=None):
lib_name = lib_config["nameOnDisk"] lib_name = lib_config["nameOnDisk"]
lib_path = lib_config["paths"]["build"] lib_path = lib_config["paths"]["build"]
if prepend_dir: if prepend_dir:
lib_path = join(prepend_dir, lib_path) lib_path = os.path.join(prepend_dir, lib_path)
lib_objects = compile_source_files( lib_objects = compile_source_files(
lib_config, default_env, project_src_dir, prepend_dir lib_config, default_env, project_src_dir, prepend_dir
) )
return default_env.Library( return default_env.Library(
target=join("$BUILD_DIR", lib_path, lib_name), source=lib_objects target=os.path.join("$BUILD_DIR", lib_path, lib_name), source=lib_objects
) )
@@ -331,17 +333,17 @@ def extract_link_args(target_config):
elif fragment.startswith("-") and not fragment.startswith("-l"): elif fragment.startswith("-") and not fragment.startswith("-l"):
# CMake mistakenly marks LINKFLAGS as libraries # CMake mistakenly marks LINKFLAGS as libraries
link_args["LINKFLAGS"].extend(args) link_args["LINKFLAGS"].extend(args)
elif isfile(fragment) and isabs(fragment): elif os.path.isfile(fragment) and os.path.isabs(fragment):
# In case of precompiled archives from framework package # In case of precompiled archives from framework package
lib_path = dirname(fragment) lib_path = os.path.dirname(fragment)
if lib_path not in link_args["LIBPATH"]: if lib_path not in link_args["LIBPATH"]:
link_args["LIBPATH"].append(dirname(fragment)) link_args["LIBPATH"].append(os.path.dirname(fragment))
link_args["LIBS"].extend( link_args["LIBS"].extend(
[basename(l) for l in args if l.endswith(".a")] [os.path.basename(lib) for lib in args if lib.endswith(".a")]
) )
elif fragment.endswith(".a"): elif fragment.endswith(".a"):
link_args["__LIB_DEPS"].extend( link_args["__LIB_DEPS"].extend(
[basename(l) for l in args if l.endswith(".a")] [os.path.basename(lib) for lib in args if lib.endswith(".a")]
) )
return link_args return link_args
@@ -394,8 +396,8 @@ def get_app_flags(app_config, default_config):
def get_sdk_configuration(): def get_sdk_configuration():
config_path = join(env.subst("$BUILD_DIR"), "config", "sdkconfig.json") config_path = os.path.join(BUILD_DIR, "config", "sdkconfig.json")
if not isfile(config_path): if not os.path.isfile(config_path):
print('Warning: Could not find "sdkconfig.json" file\n') print('Warning: Could not find "sdkconfig.json" file\n')
try: try:
@@ -410,38 +412,56 @@ def find_framework_service_files(search_path, sdk_config):
result["lf_files"] = list() result["lf_files"] = list()
result["kconfig_files"] = list() result["kconfig_files"] = list()
result["kconfig_build_files"] = list() result["kconfig_build_files"] = list()
for d in listdir(search_path): for d in os.listdir(search_path):
path = join(search_path, d) path = os.path.join(search_path, d)
if not isdir(path): if not os.path.isdir(path):
continue continue
for f in listdir(path): for f in os.listdir(path):
if f == "linker.lf": # Skip hardware specific files as they will be added later
result["lf_files"].append(join(path, f)) if f == "linker.lf" and not os.path.basename(path).startswith("esp32"):
result["lf_files"].append(os.path.join(path, f))
elif f == "Kconfig.projbuild": elif f == "Kconfig.projbuild":
result["kconfig_build_files"].append(join(path, f)) result["kconfig_build_files"].append(os.path.join(path, f))
elif f == "Kconfig": elif f == "Kconfig":
result["kconfig_files"].append(join(path, f)) result["kconfig_files"].append(os.path.join(path, f))
result["lf_files"].extend([ result["lf_files"].extend(
join(FRAMEWORK_DIR, "components", "esp32", "ld", "esp32_fragments.lf"), [
join(FRAMEWORK_DIR, "components", "newlib", "newlib.lf") os.path.join(
]) FRAMEWORK_DIR,
"components",
idf_variant,
"ld",
"%s_fragments.lf" % idf_variant,
),
os.path.join(
FRAMEWORK_DIR,
"components",
idf_variant,
"linker.lf",
),
os.path.join(FRAMEWORK_DIR, "components", "newlib", "newlib.lf"),
]
)
if sdk_config.get("SPIRAM_CACHE_WORKAROUND", False): if sdk_config.get("SPIRAM_CACHE_WORKAROUND", False):
result["lf_files"].append(join( result["lf_files"].append(
FRAMEWORK_DIR, "components", "newlib", "esp32-spiram-rom-functions-c.lf")) os.path.join(
FRAMEWORK_DIR, "components", "newlib", "esp32-spiram-rom-functions-c.lf"
)
)
return result return result
def create_custom_libraries_list(ldgen_libraries_file, ignore_targets): def create_custom_libraries_list(ldgen_libraries_file, ignore_targets):
if not isfile(ldgen_libraries_file): if not os.path.isfile(ldgen_libraries_file):
sys.stderr.write("Error: Couldn't find the list of framework libraries\n") sys.stderr.write("Error: Couldn't find the list of framework libraries\n")
env.Exit(1) env.Exit(1)
pio_libraries_file = ldgen_libraries_file + "_pio" pio_libraries_file = ldgen_libraries_file + "_pio"
if isfile(pio_libraries_file): if os.path.isfile(pio_libraries_file):
return pio_libraries_file return pio_libraries_file
lib_paths = [] lib_paths = []
@@ -462,26 +482,24 @@ def create_custom_libraries_list(ldgen_libraries_file, ignore_targets):
def generate_project_ld_script(sdk_config, ignore_targets=None): def generate_project_ld_script(sdk_config, ignore_targets=None):
ignore_targets = ignore_targets or [] ignore_targets = ignore_targets or []
project_files = find_framework_service_files( project_files = find_framework_service_files(
join(FRAMEWORK_DIR, "components"), sdk_config os.path.join(FRAMEWORK_DIR, "components"), sdk_config
) )
# Create a new file to avoid automatically generated library entry as files from # Create a new file to avoid automatically generated library entry as files from
# this library are built internally by PlatformIO # this library are built internally by PlatformIO
libraries_list = create_custom_libraries_list( libraries_list = create_custom_libraries_list(
join(env.subst("$BUILD_DIR"), "ldgen_libraries"), ignore_targets os.path.join(BUILD_DIR, "ldgen_libraries"), ignore_targets
) )
args = { args = {
"script": join(FRAMEWORK_DIR, "tools", "ldgen", "ldgen.py"), "script": os.path.join(FRAMEWORK_DIR, "tools", "ldgen", "ldgen.py"),
"config": join(env.subst("$PROJECT_DIR"), "sdkconfig"), "config": os.path.join(env.subst("$PROJECT_DIR"), "sdkconfig"),
"fragments": " ".join(['"%s"' % f for f in project_files.get("lf_files")]), "fragments": " ".join(['"%s"' % f for f in project_files.get("lf_files")]),
"kconfig": join(FRAMEWORK_DIR, "Kconfig"), "kconfig": os.path.join(FRAMEWORK_DIR, "Kconfig"),
"env_file": join("$BUILD_DIR", "config.env"), "env_file": os.path.join("$BUILD_DIR", "config.env"),
"libraries_list": libraries_list, "libraries_list": libraries_list,
"objdump": join( "objdump": os.path.join(
platform.get_package_dir("toolchain-xtensa32"), TOOLCHAIN_DIR, "bin", env.subst("$CC").replace("-gcc", "-objdump"),
"bin",
env.subst("$CC").replace("-gcc", "-objdump"),
), ),
} }
@@ -494,8 +512,14 @@ def generate_project_ld_script(sdk_config, ignore_targets=None):
).format(**args) ).format(**args)
return env.Command( return env.Command(
join("$BUILD_DIR", "esp32.project.ld"), os.path.join("$BUILD_DIR", "%s.project.ld" % idf_variant),
join(FRAMEWORK_DIR, "components", "esp32", "ld", "esp32.project.ld.in"), os.path.join(
FRAMEWORK_DIR,
"components",
idf_variant,
"ld",
"%s.project.ld.in" % idf_variant,
),
env.VerboseAction(cmd, "Generating project linker script $TARGET"), env.VerboseAction(cmd, "Generating project linker script $TARGET"),
) )
@@ -546,17 +570,21 @@ def compile_source_files(config, default_env, project_src_dir, prepend_dir=None)
compile_group_idx = source.get("compileGroupIndex") compile_group_idx = source.get("compileGroupIndex")
if compile_group_idx is not None: if compile_group_idx is not None:
src_path = source.get("path") src_path = source.get("path")
if not isabs(src_path): if not os.path.isabs(src_path):
# For cases when sources are located near CMakeLists.txt # For cases when sources are located near CMakeLists.txt
src_path = join(project_src_dir, src_path) src_path = os.path.join(project_src_dir, src_path)
local_path = config["paths"]["source"] local_path = config["paths"]["source"]
if not isabs(local_path): if not os.path.isabs(local_path):
local_path = join(project_src_dir, config["paths"]["source"]) local_path = os.path.join(project_src_dir, config["paths"]["source"])
obj_path = join("$BUILD_DIR", prepend_dir or "", config["paths"]["build"]) obj_path = os.path.join(
"$BUILD_DIR", prepend_dir or "", config["paths"]["build"]
)
objects.append( objects.append(
build_envs[compile_group_idx].StaticObject( build_envs[compile_group_idx].StaticObject(
target=join(obj_path, relpath(src_path, local_path) + ".o"), target=os.path.join(
source=realpath(src_path), obj_path, os.path.relpath(src_path, local_path) + ".o"
),
source=os.path.realpath(src_path),
) )
) )
@@ -564,7 +592,7 @@ def compile_source_files(config, default_env, project_src_dir, prepend_dir=None)
def run_tool(cmd): def run_tool(cmd):
idf_env = environ.copy() idf_env = os.environ.copy()
populate_idf_env_vars(idf_env) populate_idf_env_vars(idf_env)
result = exec_command(cmd, env=idf_env) result = exec_command(cmd, env=idf_env)
@@ -579,14 +607,14 @@ def run_tool(cmd):
def RunMenuconfig(target, source, env): def RunMenuconfig(target, source, env):
idf_env = environ.copy() idf_env = os.environ.copy()
populate_idf_env_vars(idf_env) populate_idf_env_vars(idf_env)
rc = subprocess.call( rc = subprocess.call(
[ [
join(platform.get_package_dir("tool-cmake"), "bin", "cmake"), os.path.join(platform.get_package_dir("tool-cmake"), "bin", "cmake"),
"--build", "--build",
env.subst("$BUILD_DIR"), BUILD_DIR,
"--target", "--target",
"menuconfig", "menuconfig",
], ],
@@ -598,9 +626,29 @@ def RunMenuconfig(target, source, env):
env.Exit(1) env.Exit(1)
def ReconfigureProject(target, source, env):
idf_env = os.environ.copy()
populate_idf_env_vars(idf_env)
rc = subprocess.call(
[
os.path.join(platform.get_package_dir("tool-cmake"), "bin", "cmake"),
"--build",
BUILD_DIR,
"--target",
"reconfigure",
],
env=idf_env,
)
if rc != 0:
sys.stderr.write("Error: Couldn't execute 'reconfigure' target.\n")
env.Exit(1)
def run_cmake(src_dir, build_dir, extra_args=None): def run_cmake(src_dir, build_dir, extra_args=None):
cmd = [ cmd = [
join(platform.get_package_dir("tool-cmake") or "", "bin", "cmake"), os.path.join(platform.get_package_dir("tool-cmake") or "", "bin", "cmake"),
"-S", "-S",
src_dir, src_dir,
"-B", "-B",
@@ -642,16 +690,21 @@ def find_lib_deps(components_map, elf_config, link_args, ignore_components=None)
def build_bootloader(): def build_bootloader():
bootloader_src_dir = join(FRAMEWORK_DIR, "components", "bootloader", "subproject") bootloader_src_dir = os.path.join(
FRAMEWORK_DIR, "components", "bootloader", "subproject"
)
code_model = get_cmake_code_model( code_model = get_cmake_code_model(
bootloader_src_dir, bootloader_src_dir,
join(BUILD_DIR, "bootloader"), os.path.join(BUILD_DIR, "bootloader"),
[ [
"-DIDF_TARGET=esp32", "-DIDF_TARGET=" + idf_variant,
"-DPYTHON_DEPS_CHECKED=1", "-DPYTHON_DEPS_CHECKED=1",
"-DIDF_PATH=" + platform.get_package_dir("framework-espidf"), "-DPYTHON=" + env.subst("$PYTHONEXE"),
"-DSDKCONFIG=" + join(env.subst("$PROJECT_DIR"), "sdkconfig"), "-DIDF_PATH=" + FRAMEWORK_DIR,
"-DEXTRA_COMPONENT_DIRS=" + join(FRAMEWORK_DIR, "components", "bootloader"), "-DSDKCONFIG=" + os.path.join(env.subst("$PROJECT_DIR"), "sdkconfig"),
"-DLEGACY_INCLUDE_COMMON_HEADERS=",
"-DEXTRA_COMPONENT_DIRS="
+ os.path.join(FRAMEWORK_DIR, "components", "bootloader"),
], ],
) )
@@ -660,7 +713,8 @@ def build_bootloader():
env.Exit(1) env.Exit(1)
target_configs = load_target_configurations( target_configs = load_target_configurations(
code_model, join(BUILD_DIR, "bootloader", CMAKE_API_REPLY_PATH) code_model,
os.path.join(BUILD_DIR, "bootloader", ".cmake", "api", "v1", "reply"),
) )
elf_config = get_project_elf(target_configs) elf_config = get_project_elf(target_configs)
@@ -692,8 +746,10 @@ def build_bootloader():
) )
return bootloader_env.ElfToBin( return bootloader_env.ElfToBin(
join("$BUILD_DIR", "bootloader"), os.path.join("$BUILD_DIR", "bootloader"),
bootloader_env.Program(join("$BUILD_DIR", "bootloader.elf"), bootloader_libs), bootloader_env.Program(
os.path.join("$BUILD_DIR", "bootloader.elf"), bootloader_libs
),
) )
@@ -743,17 +799,17 @@ def generate_default_component():
file(GLOB component_sources *.c* *.S) file(GLOB component_sources *.c* *.S)
idf_component_register(SRCS ${component_sources}) idf_component_register(SRCS ${component_sources})
""" """
dummy_component_path = join(BUILD_DIR, "__pio_env") dummy_component_path = os.path.join(BUILD_DIR, "__pio_env")
if not isdir(dummy_component_path): if not os.path.isdir(dummy_component_path):
makedirs(dummy_component_path) os.makedirs(dummy_component_path)
for ext in (".cpp", ".c", ".S"): for ext in (".cpp", ".c", ".S"):
dummy_file = join(dummy_component_path, "__dummy" + ext) dummy_file = os.path.join(dummy_component_path, "__dummy" + ext)
if not isfile(dummy_file): if not os.path.isfile(dummy_file):
open(dummy_file, "a").close() open(dummy_file, "a").close()
component_cmake = join(dummy_component_path, "CMakeLists.txt") component_cmake = os.path.join(dummy_component_path, "CMakeLists.txt")
if not isfile(component_cmake): if not os.path.isfile(component_cmake):
with open(component_cmake, "w") as fp: with open(component_cmake, "w") as fp:
fp.write(prj_cmake_tpl) fp.write(prj_cmake_tpl)
@@ -767,16 +823,32 @@ def find_default_component(target_configs):
return "" return ""
def create_verion_file():
version_file = os.path.join(FRAMEWORK_DIR, "version.txt")
if not os.path.isfile(version_file):
with open(version_file, "w") as fp:
fp.write(platform.get_package_version("framework-espidf"))
#
# ESP-IDF package doesn't contain .git folder, instead package version is specified
# in a special file "version.h" in the root folder of the package
#
create_verion_file()
# #
# Generate final linker script # Generate final linker script
# #
if not board.get("build.ldscript", ""): if not board.get("build.ldscript", ""):
linker_script = env.Command( linker_script = env.Command(
join("$BUILD_DIR", "esp32_out.ld"), os.path.join("$BUILD_DIR", "%s_out.ld" % idf_variant),
board.get( board.get(
"build.esp-idf.ldscript", "build.esp-idf.ldscript",
join(FRAMEWORK_DIR, "components", "esp32", "ld", "esp32.ld"), os.path.join(
FRAMEWORK_DIR, "components", idf_variant, "ld", "%s.ld" % idf_variant
),
), ),
env.VerboseAction( env.VerboseAction(
'$CC -I"$BUILD_DIR/config" -C -P -x c -E $SOURCE -o $TARGET', '$CC -I"$BUILD_DIR/config" -C -P -x c -E $SOURCE -o $TARGET',
@@ -785,29 +857,31 @@ if not board.get("build.ldscript", ""):
) )
env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", linker_script) env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", linker_script)
env.Replace(LDSCRIPT_PATH="esp32_out.ld") env.Replace(LDSCRIPT_PATH="%s_out.ld" % idf_variant)
# #
# Generate partition table # Generate partition table
# #
fwpartitions_dir = join(FRAMEWORK_DIR, "components", "partition_table") fwpartitions_dir = os.path.join(FRAMEWORK_DIR, "components", "partition_table")
partitions_csv = board.get("build.partitions", "partitions_singleapp.csv") partitions_csv = board.get("build.partitions", "partitions_singleapp.csv")
env.Replace( env.Replace(
PARTITIONS_TABLE_CSV=abspath( PARTITIONS_TABLE_CSV=os.path.abspath(
join(fwpartitions_dir, partitions_csv) os.path.join(fwpartitions_dir, partitions_csv)
if isfile(join(fwpartitions_dir, partitions_csv)) if os.path.isfile(os.path.join(fwpartitions_dir, partitions_csv))
else partitions_csv else partitions_csv
) )
) )
partition_table = env.Command( partition_table = env.Command(
join("$BUILD_DIR", "partitions.bin"), os.path.join("$BUILD_DIR", "partitions.bin"),
"$PARTITIONS_TABLE_CSV", "$PARTITIONS_TABLE_CSV",
env.VerboseAction( env.VerboseAction(
'"$PYTHONEXE" "%s" -q --flash-size "%s" $SOURCE $TARGET' '"$PYTHONEXE" "%s" -q --flash-size "%s" $SOURCE $TARGET'
% ( % (
join(FRAMEWORK_DIR, "components", "partition_table", "gen_esp32part.py"), os.path.join(
FRAMEWORK_DIR, "components", "partition_table", "gen_esp32part.py"
),
board.get("upload.flash_size", "4MB"), board.get("upload.flash_size", "4MB"),
), ),
"Generating partitions $TARGET", "Generating partitions $TARGET",
@@ -833,7 +907,7 @@ if env.subst("$SRC_FILTER"):
) )
) )
if isfile(join(env.subst("$PROJECT_SRC_DIR"), "sdkconfig.h")): if os.path.isfile(os.path.join(env.subst("$PROJECT_SRC_DIR"), "sdkconfig.h")):
print( print(
"Warning! Starting with ESP-IDF v4.0, new project structure is required: \n" "Warning! Starting with ESP-IDF v4.0, new project structure is required: \n"
"https://docs.platformio.org/en/latest/frameworks/espidf.html#project-structure" "https://docs.platformio.org/en/latest/frameworks/espidf.html#project-structure"
@@ -847,7 +921,7 @@ if isfile(join(env.subst("$PROJECT_SRC_DIR"), "sdkconfig.h")):
# default 'src' folder we need to add this as an extra component. If there is no 'main' # default 'src' folder we need to add this as an extra component. If there is no 'main'
# folder CMake won't generate dependencies properly # folder CMake won't generate dependencies properly
extra_components = [generate_default_component()] extra_components = [generate_default_component()]
if env.subst("$PROJECT_SRC_DIR") != join(env.subst("$PROJECT_DIR"), "main"): if env.subst("$PROJECT_SRC_DIR") != os.path.join(env.subst("$PROJECT_DIR"), "main"):
extra_components.append(env.subst("$PROJECT_SRC_DIR")) extra_components.append(env.subst("$PROJECT_SRC_DIR"))
if "arduino" in env.subst("$PIOFRAMEWORK"): if "arduino" in env.subst("$PIOFRAMEWORK"):
extra_components.append(ARDUINO_FRAMEWORK_DIR) extra_components.append(ARDUINO_FRAMEWORK_DIR)
@@ -856,8 +930,11 @@ print("Reading CMake configuration...")
project_codemodel = get_cmake_code_model( project_codemodel = get_cmake_code_model(
env.subst("$PROJECT_DIR"), env.subst("$PROJECT_DIR"),
BUILD_DIR, BUILD_DIR,
["-DEXTRA_COMPONENT_DIRS:PATH=" + ";".join(extra_components)] + [
click.parser.split_arg_string(board.get("build.cmake_extra_args", "")) "-DIDF_TARGET=" + idf_variant,
"-DEXTRA_COMPONENT_DIRS:PATH=" + ";".join(extra_components),
]
+ click.parser.split_arg_string(board.get("build.cmake_extra_args", "")),
) )
if not project_codemodel: if not project_codemodel:
@@ -865,13 +942,13 @@ if not project_codemodel:
env.Exit(1) env.Exit(1)
target_configs = load_target_configurations( target_configs = load_target_configurations(
project_codemodel, join(BUILD_DIR, CMAKE_API_REPLY_PATH) project_codemodel, os.path.join(BUILD_DIR, CMAKE_API_REPLY_PATH)
) )
sdk_config = get_sdk_configuration() sdk_config = get_sdk_configuration()
project_target_name = "__idf_%s" % basename(env.subst("$PROJECT_SRC_DIR")) project_target_name = "__idf_%s" % os.path.basename(env.subst("$PROJECT_SRC_DIR"))
if project_target_name not in target_configs: if project_target_name not in target_configs:
sys.stderr.write("Error: Couldn't find the main target of the project!\n") sys.stderr.write("Error: Couldn't find the main target of the project!\n")
env.Exit(1) env.Exit(1)
@@ -887,7 +964,8 @@ if project_target_name != "__idf_main" and "__idf_main" in target_configs:
env.Exit(1) env.Exit(1)
project_ld_scipt = generate_project_ld_script( project_ld_scipt = generate_project_ld_script(
sdk_config, [project_target_name, "__pio_env"]) sdk_config, [project_target_name, "__pio_env"]
)
env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", project_ld_scipt) env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", project_ld_scipt)
elf_config = get_project_elf(target_configs) elf_config = get_project_elf(target_configs)
@@ -925,8 +1003,21 @@ env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", build_bootloader())
# Target: ESP-IDF menuconfig # Target: ESP-IDF menuconfig
# #
env.AddPlatformTarget("menuconfig", None, [env.VerboseAction( env.AddPlatformTarget(
RunMenuconfig, "Running menuconfig...")], "Run Menuconfig") "menuconfig",
None,
[env.VerboseAction(RunMenuconfig, "Running menuconfig...")],
"Run Menuconfig",
)
env.AddPlatformTarget(
"reconfigure",
None,
[env.VerboseAction(ReconfigureProject, "Reconfiguring project...")],
"Reconfigure Project",
)
# #
# Process main parts of the framework # Process main parts of the framework
@@ -943,7 +1034,7 @@ link_args["LINKFLAGS"] = sorted(list(set(link_args["LINKFLAGS"]) - set(extra_fla
# remove the main linker script flags '-T esp32_out.ld' # remove the main linker script flags '-T esp32_out.ld'
try: try:
ld_index = extra_flags.index("esp32_out.ld") ld_index = extra_flags.index("%s_out.ld" % idf_variant)
extra_flags.pop(ld_index) extra_flags.pop(ld_index)
extra_flags.pop(ld_index - 1) extra_flags.pop(ld_index - 1)
except: except:
@@ -953,6 +1044,7 @@ except:
# Process project sources # Process project sources
# #
# Remove project source files from following build stages as they're # Remove project source files from following build stages as they're
# built as part of the framework # built as part of the framework
def _skip_prj_source_files(node): def _skip_prj_source_files(node):
@@ -1002,8 +1094,8 @@ env.Prepend(
LINKFLAGS=extra_flags, LINKFLAGS=extra_flags,
LIBS=libs, LIBS=libs,
FLASH_EXTRA_IMAGES=[ FLASH_EXTRA_IMAGES=[
("0x1000", join("$BUILD_DIR", "bootloader.bin")), ("0x1000", os.path.join("$BUILD_DIR", "bootloader.bin")),
("0x8000", join("$BUILD_DIR", "partitions.bin")), ("0x8000", os.path.join("$BUILD_DIR", "partitions.bin")),
], ],
) )
@@ -1013,13 +1105,14 @@ env.Prepend(
action = copy.deepcopy(env["BUILDERS"]["ElfToBin"].action) action = copy.deepcopy(env["BUILDERS"]["ElfToBin"].action)
action.cmd_list = env["BUILDERS"]["ElfToBin"].action.cmd_list.replace( action.cmd_list = env["BUILDERS"]["ElfToBin"].action.cmd_list.replace(
"-o", "--elf-sha256-offset 0xb0 -o") "-o", "--elf-sha256-offset 0xb0 -o"
)
env["BUILDERS"]["ElfToBin"].action = action env["BUILDERS"]["ElfToBin"].action = action
# #
# Compile ULP sources in 'ulp' folder # Compile ULP sources in 'ulp' folder
# #
ulp_dir = join(env.subst("$PROJECT_DIR"), "ulp") ulp_dir = os.path.join(env.subst("$PROJECT_DIR"), "ulp")
if isdir(ulp_dir) and listdir(ulp_dir): if os.path.isdir(ulp_dir) and os.listdir(ulp_dir):
env.SConscript("ulp.py", exports="env project_config") env.SConscript("ulp.py", exports="env project_config idf_variant")
+4 -5
View File
@@ -13,14 +13,13 @@
# limitations under the License. # limitations under the License.
import os import os
import sys
from SCons.Script import COMMAND_LINE_TARGETS, Import, Return from SCons.Script import Import
from platformio.util import get_systype from platformio.util import get_systype
from platformio.proc import where_is_program from platformio.proc import where_is_program
Import("env project_config") Import("env project_config idf_variant")
ulp_env = env.Clone() ulp_env = env.Clone()
platform = ulp_env.PioPlatform() platform = ulp_env.PioPlatform()
@@ -79,7 +78,7 @@ def generate_ulp_config(target_config):
"components", "components",
"ulp", "ulp",
"cmake", "cmake",
"toolchain-ulp.cmake", "toolchain-%s-ulp.cmake" % idf_variant,
), ),
'-DULP_S_SOURCES="%s"' % ";".join(ulp_sources), '-DULP_S_SOURCES="%s"' % ";".join(ulp_sources),
"-DULP_APP_NAME=ulp_main", "-DULP_APP_NAME=ulp_main",
@@ -87,7 +86,7 @@ def generate_ulp_config(target_config):
'-DCOMPONENT_INCLUDES="%s"' % ";".join(get_component_includes(target_config)), '-DCOMPONENT_INCLUDES="%s"' % ";".join(get_component_includes(target_config)),
"-DIDF_PATH=" + FRAMEWORK_DIR, "-DIDF_PATH=" + FRAMEWORK_DIR,
"-DSDKCONFIG=" + os.path.join(BUILD_DIR, "config", "sdkconfig.h"), "-DSDKCONFIG=" + os.path.join(BUILD_DIR, "config", "sdkconfig.h"),
"-DPYTHON=python", "-DPYTHON=" + env.subst("$PYTHONEXE"),
"-GNinja", "-GNinja",
"-B", "-B",
ULP_BUILD_DIR, ULP_BUILD_DIR,
+8 -2
View File
@@ -68,7 +68,13 @@
"type": "toolchain", "type": "toolchain",
"optional": true, "optional": true,
"owner": "platformio", "owner": "platformio",
"version": "~1.22851.190618" "version": "~1.22851.0"
},
"toolchain-esp32s2ulp": {
"type": "toolchain",
"optional": true,
"owner": "platformio",
"version": "~1.22851.0"
}, },
"framework-arduinoespressif32": { "framework-arduinoespressif32": {
"type": "framework", "type": "framework",
@@ -86,7 +92,7 @@
"type": "framework", "type": "framework",
"optional": true, "optional": true,
"owner": "platformio", "owner": "platformio",
"version": "~3.40001.0" "version": "~3.40100.0"
}, },
"framework-simba": { "framework-simba": {
"type": "framework", "type": "framework",
+7 -3
View File
@@ -26,25 +26,29 @@ class Espressif32Platform(PlatformBase):
self, variables, targets) self, variables, targets)
board_config = self.board_config(variables.get("board")) board_config = self.board_config(variables.get("board"))
mcu = variables.get("board_build.mcu", board_config.get( mcu = variables.get("board_build.mcu", board_config.get("build.mcu", "esp32"))
"build.mcu", "esp32")) frameworks = variables.get("pioframework", [])
if "buildfs" in targets: if "buildfs" in targets:
self.packages['tool-mkspiffs']['optional'] = False self.packages['tool-mkspiffs']['optional'] = False
if variables.get("upload_protocol"): if variables.get("upload_protocol"):
self.packages['tool-openocd-esp32']['optional'] = False self.packages['tool-openocd-esp32']['optional'] = False
if isdir("ulp"): if isdir("ulp"):
self.packages['toolchain-esp32ulp']['optional'] = False self.packages['toolchain-esp32ulp']['optional'] = False
if "espidf" in variables.get("pioframework", []): if "espidf" in frameworks:
for p in self.packages: for p in self.packages:
if p in ("tool-cmake", "tool-ninja", "toolchain-%sulp" % mcu): if p in ("tool-cmake", "tool-ninja", "toolchain-%sulp" % mcu):
self.packages[p]["optional"] = False self.packages[p]["optional"] = False
elif p in ("tool-mconf", "tool-idf") and "windows" in get_systype(): elif p in ("tool-mconf", "tool-idf") and "windows" in get_systype():
self.packages[p]['optional'] = False self.packages[p]['optional'] = False
self.packages['toolchain-xtensa32']['version'] = "~2.80200.0" self.packages['toolchain-xtensa32']['version'] = "~2.80200.0"
if "arduino" in frameworks:
# Arduino component is not compatible with ESP-IDF >=4.1
self.packages['framework-espidf']['version'] = "~3.40001.0"
# ESP32-S2 toolchain is identical for both Arduino and ESP-IDF # ESP32-S2 toolchain is identical for both Arduino and ESP-IDF
if mcu == "esp32s2": if mcu == "esp32s2":
self.packages.pop("toolchain-xtensa32", None) self.packages.pop("toolchain-xtensa32", None)
self.packages['toolchain-xtensa32s2']['optional'] = False self.packages['toolchain-xtensa32s2']['optional'] = False
self.packages['toolchain-esp32s2ulp']['optional'] = False
self.packages['tool-esptoolpy']['version'] = "~1.30000.0" self.packages['tool-esptoolpy']['version'] = "~1.30000.0"
build_core = variables.get( build_core = variables.get(