diff --git a/builder/frameworks/_embed_files.py b/builder/frameworks/_embed_files.py new file mode 100644 index 0000000..24cb387 --- /dev/null +++ b/builder/frameworks/_embed_files.py @@ -0,0 +1,178 @@ +# Copyright 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import shutil +from os import SEEK_CUR, SEEK_END +from os.path import basename, isfile, join + +from SCons.Script import Builder + +Import("env") + +board = env.BoardConfig() + +# +# Embedded files helpers +# + + +def extract_files(cppdefines, files_type): + result = [] + files = env.GetProjectOption("board_build.%s" % files_type, "").splitlines() + if files: + result.extend([join("$PROJECT_DIR", f.strip()) for f in files if f]) + else: + files_define = "COMPONENT_" + files_type.upper() + for define in cppdefines: + if files_define not in define: + continue + + value = define[1] + if not isinstance(define, tuple): + print("Warning! %s macro cannot be empty!" % files_define) + return [] + + if not isinstance(value, str): + print( + "Warning! %s macro must contain " + "a list of files separated by ':'" % files_define + ) + return [] + + for f in value.split(":"): + if not f: + continue + result.append(join("$PROJECT_DIR", f)) + + for f in result: + if not isfile(env.subst(f)): + print('Warning! Could not find file "%s"' % basename(f)) + + return result + + +def remove_config_define(cppdefines, files_type): + for define in cppdefines: + if files_type in define: + env.ProcessUnFlags("-D%s" % "=".join(str(d) for d in define)) + return + + +def prepare_file(source, target, env): + filepath = source[0].get_abspath() + shutil.copy(filepath, filepath + ".piobkp") + + with open(filepath, "rb+") as fp: + fp.seek(-1, SEEK_END) + if fp.read(1) != "\0": + fp.seek(0, SEEK_CUR) + fp.write(b"\0") + + +def revert_original_file(source, target, env): + filepath = source[0].get_abspath() + if isfile(filepath + ".piobkp"): + shutil.move(filepath + ".piobkp", filepath) + + +def embed_files(files, files_type): + for f in files: + filename = basename(f) + ".txt.o" + file_target = env.TxtToBin(join("$BUILD_DIR", filename), f) + env.Depends("$PIOMAINPROG", file_target) + if files_type == "embed_txtfiles": + env.AddPreAction(file_target, prepare_file) + env.AddPostAction(file_target, revert_original_file) + env.AppendUnique(PIOBUILDFILES=[env.File(join("$BUILD_DIR", filename))]) + + +def transform_to_asm(target, source, env): + files = [join("$BUILD_DIR", s.name + ".S") for s in source] + return files, source + + +env.Append( + BUILDERS=dict( + TxtToBin=Builder( + action=env.VerboseAction( + " ".join( + [ + "xtensa-lx106-elf-objcopy", + "--input-target", + "binary", + "--output-target", + "elf32-xtensa-le", + "--binary-architecture", + "xtensa", + "--rename-section", + ".data=.rodata.embedded", + "$SOURCE", + "$TARGET", + ] + ), + "Converting $TARGET", + ), + suffix=".txt.o", + ), + FileToAsm=Builder( + action=env.VerboseAction( + " ".join( + [ + join( + env.PioPlatform().get_package_dir("tool-cmake") or "", + "bin", + "cmake", + ), + "-DDATA_FILE=$SOURCE", + "-DSOURCE_FILE=$TARGET", + "-DFILE_TYPE=$FILE_TYPE", + "-P", + join( + env.PioPlatform().get_package_dir("framework-esp8266-rtos-sdk") or "", + "tools", + "cmake", + "scripts", + "data_file_embed_asm.cmake", + ), + ] + ), + "Generating assembly for $TARGET", + ), + emitter=transform_to_asm, + single_source=True, + ), + ) +) + + +flags = env.get("CPPDEFINES") +for files_type in ("embed_txtfiles", "embed_files"): + if ( + "COMPONENT_" + files_type.upper() not in env.Flatten(flags) + and "build." + files_type not in board + ): + continue + + files = extract_files(flags, files_type) + if "espidf" in env.subst("$PIOFRAMEWORK"): + env.Requires( + join("$BUILD_DIR", "${PROGNAME}.elf"), + env.FileToAsm( + files, + FILE_TYPE="TEXT" if files_type == "embed_txtfiles" else "BINARY", + ), + ) + else: + embed_files(files, files_type) + remove_config_define(flags, files_type) diff --git a/builder/frameworks/arduino.py b/builder/frameworks/arduino.py index e979a97..67fbd4e 100644 --- a/builder/frameworks/arduino.py +++ b/builder/frameworks/arduino.py @@ -26,6 +26,8 @@ from SCons.Script import COMMAND_LINE_TARGETS, DefaultEnvironment, SConscript +env = DefaultEnvironment() +SConscript("_embed_files.py", exports="env") if "nobuild" not in COMMAND_LINE_TARGETS: SConscript( diff --git a/platform.json b/platform.json index 5569302..08a27b1 100644 --- a/platform.json +++ b/platform.json @@ -94,6 +94,11 @@ "optional": true, "owner": "platformio", "version": "~1.203.0" + }, + "tool-cmake": { + "optional": true, + "owner": "platformio", + "version": "~3.16.0" } } }