diff --git a/doc/faq/readme.rst b/doc/faq/readme.rst index 4fb065a38f..5bea6ce0da 100644 --- a/doc/faq/readme.rst +++ b/doc/faq/readme.rst @@ -72,7 +72,7 @@ version). WPS is always available, and not using it will give an extra ~4.5KB compared to releases until 2.4.1 included. This Arduino library doesn't work on ESP. How do I make it work? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You would like to use this Arduino library with ESP8266 and it does not perform. It is not listed among libraries verified to work with ESP8266. @@ -80,7 +80,7 @@ perform. It is not listed among libraries verified to work with ESP8266. `Read more `__. In the IDE, for ESP-12E that has 4M flash, I can choose 4M (1M FS) or 4M (3M FS). No matter what I select, the IDE tells me the maximum code space is about 1M. Where does my flash go? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The reason we cannot have more than 1MB of code in flash has to do with a hardware limitation. Flash cache hardware on the ESP8266 only allows @@ -152,6 +152,44 @@ Artificially clearing them is a workaround to help saving precious heap. Ref. `#1923 `__ +Use custom defines from build options file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A file named ``build_opt.h`` next to the ``sketch.ino`` file enables the user +to specify custom definitons in a central and organized location. + +The following code is a slightly modified Blink example sketch. It opens the +possibility to define the ``WAIT_TIME`` between the LED state changes. If no +``build_opt.h`` file is placed next to the sketch file, the default value will +be set as 1000ms in this example. + +.. code:: cpp + + #ifndef WAIT_TIME + #define WAIT_TIME 1000 // use 1000ms if not defined different + #endif + + void setup() { + // initialize digital pin LED_BUILTIN as an output. + pinMode(LED_BUILTIN, OUTPUT); + } + + void loop() { + digitalWrite(LED_BUILTIN, HIGH); + delay(WAIT_TIME); + digitalWrite(LED_BUILTIN, LOW); + delay(WAIT_TIME); + } + +Place the following content in a file named ``build_opt.h`` at the same +location as the ``sketch.ino`` file to define the ``WAIT_TIME`` to 500ms. + +.. code:: cpp + + -DWAIT_TIME=500 + +``core.s`` files are not automatically rebuilt when changes are made to the +``build_opt.h`` file. Why is there a board generator and what about it ? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/platform.txt b/platform.txt index 7541466196..555171d473 100644 --- a/platform.txt +++ b/platform.txt @@ -12,6 +12,7 @@ version=3.0.1-dev runtime.tools.xtensa-lx106-elf-gcc.path={runtime.platform.path}/tools/xtensa-lx106-elf runtime.tools.python3.path={runtime.platform.path}/tools/python3 +runtime.tools.prebuild={runtime.platform.path}/tools/prebuild.py runtime.tools.esptool.path={runtime.platform.path}/tools/esptool runtime.tools.signing={runtime.platform.path}/tools/signing.py runtime.tools.elf2bin={runtime.platform.path}/tools/elf2bin.py @@ -85,6 +86,13 @@ compiler.size.cmd=xtensa-lx106-elf-size # This can be overridden in boards.txt build.extra_flags=-DESP8266 +# Pre and post build hooks +build.opt.name=build_opt.h +build.opt.path={build.path}/sketch/{build.opt.name} + +# Create empty {build.opt} if it does not exist in the output sketch dir +recipe.hooks.prebuild.1.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.prebuild}" "{build.path}" "{build.source.path}" + # These can be overridden in platform.local.txt compiler.c.extra_flags= compiler.c.elf.extra_flags= @@ -107,13 +115,13 @@ recipe.hooks.linking.prelink.3.pattern="{compiler.path}{compiler.c.cmd}" -CC -E recipe.hooks.linking.prelink.4.pattern="{compiler.path}{compiler.c.cmd}" -CC -E -P {build.vtable_flags} {build.mmuflags} "{runtime.platform.path}/tools/sdk/ld/eagle.app.v6.common.ld.h" -o "{build.path}/local.eagle.app.v6.common.ld" ## Compile c files -recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -D{build.sdk}=1 -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {build.flash_flags} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -D{build.sdk}=1 -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {build.flash_flags} {compiler.c.extra_flags} {build.extra_flags} "@{build.opt.path}" {includes} "{source_file}" -o "{object_file}" ## Compile c++ files -recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -D{build.sdk}=1 -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {build.flash_flags} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -D{build.sdk}=1 -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {build.flash_flags} {compiler.cpp.extra_flags} {build.extra_flags} "@{build.opt.path}" {includes} "{source_file}" -o "{object_file}" ## Compile S files -recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -D{build.sdk}=1 -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {build.flash_flags} {compiler.S.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" +recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -D{build.sdk}=1 -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {build.led} {build.flash_flags} {compiler.S.extra_flags} {build.extra_flags} "@{build.opt.path}" {includes} "{source_file}" -o "{object_file}" ## Create archives recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" diff --git a/tools/prebuild.py b/tools/prebuild.py new file mode 100644 index 0000000000..3b074ca65e --- /dev/null +++ b/tools/prebuild.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# prebuild.py — create build_opt.h file in build directory if it does not exist +# +# This script will create a folder called "sketch" in the build path if it does +# not yet exist and create an empty build options file inside if this does also +# not exist yet +# +# Written by brainelectronics, 2021. +# + +import os +import sys + + +def create_sketch_dir(build_path): + """ + Create the sketch directory + :param build_path: The path to the build directory + :type build_path: str + """ + sketch_build_path = os.path.join(build_path, "sketch") + + if not os.path.exists(sketch_build_path): + os.makedirs(sketch_build_path) + + +def create_build_options_file(source_path, build_path, build_opt_name="build_opt.h"): + """ + Create the build options file in the build directory. + The modification time of the build options file is set to the sketch + modification time in case the file did not exist or the users build options + modification time to reflect changes which require a recompilation + :param source_path: The path to the source directory + :type source_path: str + :param build_path: The path to the build directory + :type build_path: str + :param build_opt_name: The build option file name + :type build_opt_name: str, optional + """ + build_opt_source_path = os.path.join(source_path, build_opt_name) + build_opt_build_path = os.path.join(build_path, "sketch", build_opt_name) + + # check for an existing build options file in the source directory + if os.path.exists(build_opt_source_path): + # user does have/use an build options file in it's sketch directory + + if os.path.exists(build_opt_build_path): + # set build options file modification time to the same time as the + # sketch modification time to avoid rebuilding libraries + set_file_time_to_sketch_time(source_path, build_opt_build_path) + else: + # the build options file does not yet exist in the build directory + # just continue as it will be copied by the IDE automatically on + # time. This section is only entered on the very first run + pass + else: + # user does not have a build options file, create empty one to avoid + # compilation error due to missing file for compilation + open(build_opt_build_path, 'a').close() + + # set build options file modification time to the same time as the + # sketch modification time to avoid rebuilding libraries + set_file_time_to_sketch_time(source_path, build_opt_build_path) + + +def set_file_time_to_sketch_time(source_path, destination_path): + """ + Set the file ctime and mtime to the ctime and mtime of the sketch. + :param source_path: The source path to the sketch + :type source_path: str + :param destination_path: The destination path to the file to modify + :type destination_path: str + """ + sketch_path = get_full_sketch_path(source_path) + sketch_mtime = get_modification_time(sketch_path) + destination_ctime = get_creation_time(destination_path) + + os.utime(destination_path, (destination_ctime, sketch_mtime)) + + +def get_full_sketch_path(source_path): + """ + Get the full sketch path. + :param source_path: The source path + :type source_path: str + :returns: The full sketch path including the '.ino' extension. + :rtype: str + """ + base_name = os.path.basename(source_path) + + sketch_path = os.path.join(source_path, base_name + '.ino') + + return sketch_path + + +def get_modification_time(file_path): + """ + Get the modification time of a file. + :param file_path: The file path + :type file_path: str + :returns: The modification time. + :rtype: float + """ + return os.path.getmtime(file_path) + + +def get_creation_time(file_path): + """ + Gets the creation time if a file. + :param file_path: The file path + :type file_path: str + :returns: The creation time. + :rtype: float + """ + return os.path.getctime(file_path) + + +def main(): + if len(sys.argv) == 3: + build_path = sys.argv[1] + source_path = sys.argv[2] + + create_sketch_dir(build_path) + create_build_options_file(source_path, build_path) + + +if __name__ == '__main__': + sys.exit(main())