Browse Source

pio: simplify single-source builder

Generate resulting .cpp in the $BUILD_DIR, no need for atexit
Register middleware only once, there's no need to manually walk the
project directory since fnmatch.fnmatch(...) supports globs

Provide a SCons Action instead of simple function, so there's a way to
generate things on demand via command line
```
$ pio run -e $env -t .pio/build/$env/espurna_single_source/src/main.cpp
```
pull/2490/head
Maxim Prokhorov 2 years ago
parent
commit
c738b91b6a
3 changed files with 36 additions and 31 deletions
  1. +8
    -2
      code/scripts/espurna_utils/__init__.py
  2. +26
    -16
      code/scripts/espurna_utils/build.py
  3. +2
    -13
      code/scripts/pio_pre.py

+ 8
- 2
code/scripts/espurna_utils/__init__.py View File

@ -19,7 +19,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .build import firmware_destination, app_add_target_build_and_copy, app_add_target_build_re2c
from .build import (
firmware_destination,
app_add_builder_single_source,
app_add_target_build_and_copy,
app_add_target_build_re2c,
)
from .checks import check_env, check_cppcheck, check_printsize
from .flags import app_inject_flags
from .float_support import remove_float_support
@ -28,14 +33,15 @@ from .postmortem import dummy_ets_printf
from .version import app_inject_version, app_full_version_for_env
__all__ = [
"app_add_builder_single_source",
"app_add_target_build_and_copy",
"app_add_target_build_re2c",
"app_full_version_for_env",
"app_inject_flags",
"app_inject_version",
"app_version",
"check_env",
"check_cppcheck",
"check_env",
"check_printsize",
"dummy_ets_printf",
"firmware_destination",


+ 26
- 16
code/scripts/espurna_utils/build.py View File

@ -1,33 +1,43 @@
import atexit
import os
import shutil
import tempfile
from .display import print_warning
from .version import app_full_version_for_env
def try_remove(path):
try:
os.remove(path)
except: # pylint: disable=bare-except
print_warning("Please manually remove the file `{}`".format(path))
# emulate .ino concatenation to speed up compilation times
def merge_cpp(sources, output):
def merge_cpp(target, source, env, encoding="utf-8"):
with tempfile.TemporaryFile() as tmp:
tmp.write(b"// !!! Automatically generated file; DO NOT EDIT !!! \n")
tmp.write(b'#include "espurna.h"\n')
for source in sources:
src_include = '#include "{}"\n'.format(source)
tmp.write(src_include.encode("utf-8"))
tmp.write(
'#include "{}"\n'.format(
env.File("${PROJECT_DIR}/espurna/espurna.h").get_abspath()
).encode(encoding)
)
for src in source:
src_include = '#include "{}"\n'.format(src.get_abspath())
tmp.write(src_include.encode(encoding))
tmp.seek(0)
with open(output, "wb") as fobj:
with open(target[0].get_abspath(), "wb") as fobj:
shutil.copyfileobj(tmp, fobj)
atexit.register(try_remove, output)
def app_add_builder_single_source(env):
# generate things in the $BUILD_DIR, so there's no need for any extra clean-up code
source = os.path.join("${BUILD_DIR}", "espurna_single_source", "src", "main.cpp")
# substitute a single node instead of building it somewhere else as a lib or extra source dir
# (...and since we can't seem to modify src_filter specifically for the project dir, only middleware works :/)
def ignore_node(node):
if node.name.endswith("main.cpp"):
return env.File(source)
return None
project = env.Dir("${PROJECT_DIR}/espurna")
env.AddBuildMiddleware(ignore_node, os.path.join(project.get_abspath(), "*.cpp"))
env.Command(source, env.Glob("${PROJECT_DIR}/espurna/*.cpp"), env.Action(merge_cpp))
def firmware_prefix(env):


+ 2
- 13
code/scripts/pio_pre.py View File

@ -15,7 +15,7 @@ import sys
from SCons.Script import Import, ARGUMENTS
from espurna_utils import check_env
from espurna_utils.build import merge_cpp, app_add_target_build_re2c
from espurna_utils.build import app_add_builder_single_source, app_add_target_build_re2c
Import("env")
env = globals()["env"]
@ -127,18 +127,7 @@ if len(ino) == 1 and ino[0].name == "espurna.ino":
# merge every .cpp into a single file and **only** build that single file
if check_env("ESPURNA_BUILD_SINGLE_SOURCE", "0"):
cpp_files = []
for root, dirs, filenames in os.walk("espurna"):
for name in filenames:
if not name.endswith(".cpp"):
continue
abspath = os.path.join(os.path.abspath(root), name)
env.AddBuildMiddleware(lambda node: None, abspath)
relpath = os.path.relpath(abspath, "espurna")
cpp_files.append(relpath)
merge_cpp(cpp_files, "espurna/espurna_single_source.cpp")
app_add_builder_single_source(env)
# handle explicit targets that have .re.cpp.inc, build them before falling into the next sconsfile
app_add_target_build_re2c(env)

Loading…
Cancel
Save