Added support for custom targets

This commit is contained in:
Ivan Kravets
2020-06-09 18:43:50 +03:00
parent e0023bb908
commit 3c8e0b17a7
6 changed files with 139 additions and 46 deletions

View File

@ -6,9 +6,16 @@ Release Notes
PlatformIO Core 4 PlatformIO Core 4
----------------- -----------------
4.3.5 (2020-??-??) 4.4.0 (2020-??-??)
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
* New `Account Management System <https://docs.platformio.org/page/plus/pio-account.html>`__ (preview)
- Manage own organizations
- Manage organization teams
- Manage resource access
* Added support for `custom targets <https://docs.platformio.org/page/projectconf/advanced_scripting.html#custom-targets>`__ (user cases: command shortcuts, pre/post processing based on dependencies, custom command launcher with options, etc.)
* Added support for "globstar/`**`" (recursive) pattern for the different commands and configuration options (`platformio ci <https://docs.platformio.org/page/core/userguide/cmd_ci.html>`__, `src_filter <https://docs.platformio.org/page/projectconf/section_env_build.html#src-filter>`__, `check_patterns <https://docs.platformio.org/page/projectconf/section_env_check.html#check-patterns>`__, `library.json > srcFilter <https://docs.platformio.org/page/librarymanager/config.html#srcfilter>`__). Python 3.5+ is required. * Added support for "globstar/`**`" (recursive) pattern for the different commands and configuration options (`platformio ci <https://docs.platformio.org/page/core/userguide/cmd_ci.html>`__, `src_filter <https://docs.platformio.org/page/projectconf/section_env_build.html#src-filter>`__, `check_patterns <https://docs.platformio.org/page/projectconf/section_env_check.html#check-patterns>`__, `library.json > srcFilter <https://docs.platformio.org/page/librarymanager/config.html#srcfilter>`__). Python 3.5+ is required.
4.3.4 (2020-05-23) 4.3.4 (2020-05-23)

2
docs

Submodule docs updated: cfba4f4568...439f402c5b

View File

@ -55,6 +55,7 @@ DEFAULT_ENV_OPTIONS = dict(
"c++", "c++",
"link", "link",
"platformio", "platformio",
"piotarget",
"pioplatform", "pioplatform",
"pioproject", "pioproject",
"piomaxlen", "piomaxlen",
@ -217,7 +218,7 @@ if "idedata" in COMMAND_LINE_TARGETS:
click.echo( click.echo(
"\n%s\n" "\n%s\n"
% dump_json_to_unicode( % dump_json_to_unicode(
projenv.DumpIDEData() # pylint: disable=undefined-variable projenv.DumpIDEData(env) # pylint: disable=undefined-variable
) )
) )
env.Exit(0) env.Exit(0)

View File

@ -143,7 +143,8 @@ def _escape_build_flag(flags):
return [flag if " " not in flag else '"%s"' % flag for flag in flags] return [flag if " " not in flag else '"%s"' % flag for flag in flags]
def DumpIDEData(env): def DumpIDEData(env, globalenv):
""" env here is `projenv`"""
env["__escape_build_flag"] = _escape_build_flag env["__escape_build_flag"] = _escape_build_flag
@ -169,6 +170,7 @@ def DumpIDEData(env):
], ],
"svd_path": _get_svd_path(env), "svd_path": _get_svd_path(env),
"compiler_type": env.GetCompilerType(), "compiler_type": env.GetCompilerType(),
"targets": globalenv.DumpTargets(),
} }
env_ = env.Clone() env_ = env.Clone()

View File

@ -16,15 +16,12 @@ from __future__ import absolute_import
import atexit import atexit
import io import io
import os
import re import re
import sys import sys
from os import environ, remove, walk
from os.path import basename, isdir, isfile, join, realpath, relpath, sep
from tempfile import mkstemp from tempfile import mkstemp
import click import click
from SCons.Action import Action # pylint: disable=import-error
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from platformio import fs, util from platformio import fs, util
from platformio.compat import get_filesystem_encoding, get_locale_encoding, glob_escape from platformio.compat import get_filesystem_encoding, get_locale_encoding, glob_escape
@ -126,11 +123,11 @@ class InoToCPPConverter(object):
'$CXX -o "{0}" -x c++ -fpreprocessed -dD -E "{1}"'.format( '$CXX -o "{0}" -x c++ -fpreprocessed -dD -E "{1}"'.format(
out_file, tmp_path out_file, tmp_path
), ),
"Converting " + basename(out_file[:-4]), "Converting " + os.path.basename(out_file[:-4]),
) )
) )
atexit.register(_delete_file, tmp_path) atexit.register(_delete_file, tmp_path)
return isfile(out_file) return os.path.isfile(out_file)
def _join_multiline_strings(self, contents): def _join_multiline_strings(self, contents):
if "\\\n" not in contents: if "\\\n" not in contents:
@ -233,7 +230,9 @@ class InoToCPPConverter(object):
def ConvertInoToCpp(env): def ConvertInoToCpp(env):
src_dir = glob_escape(env.subst("$PROJECT_SRC_DIR")) src_dir = glob_escape(env.subst("$PROJECT_SRC_DIR"))
ino_nodes = env.Glob(join(src_dir, "*.ino")) + env.Glob(join(src_dir, "*.pde")) ino_nodes = env.Glob(os.path.join(src_dir, "*.ino")) + env.Glob(
os.path.join(src_dir, "*.pde")
)
if not ino_nodes: if not ino_nodes:
return return
c = InoToCPPConverter(env) c = InoToCPPConverter(env)
@ -244,8 +243,8 @@ def ConvertInoToCpp(env):
def _delete_file(path): def _delete_file(path):
try: try:
if isfile(path): if os.path.isfile(path):
remove(path) os.remove(path)
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
pass pass
@ -255,7 +254,7 @@ def _get_compiler_type(env):
if env.subst("$CC").endswith("-gcc"): if env.subst("$CC").endswith("-gcc"):
return "gcc" return "gcc"
try: try:
sysenv = environ.copy() sysenv = os.environ.copy()
sysenv["PATH"] = str(env["ENV"]["PATH"]) sysenv["PATH"] = str(env["ENV"]["PATH"])
result = exec_command([env.subst("$CC"), "-v"], env=sysenv) result = exec_command([env.subst("$CC"), "-v"], env=sysenv)
except OSError: except OSError:
@ -277,8 +276,8 @@ def GetCompilerType(env):
def GetActualLDScript(env): def GetActualLDScript(env):
def _lookup_in_ldpath(script): def _lookup_in_ldpath(script):
for d in env.get("LIBPATH", []): for d in env.get("LIBPATH", []):
path = join(env.subst(d), script) path = os.path.join(env.subst(d), script)
if isfile(path): if os.path.isfile(path):
return path return path
return None return None
@ -297,7 +296,7 @@ def GetActualLDScript(env):
else: else:
continue continue
script = env.subst(raw_script.replace('"', "").strip()) script = env.subst(raw_script.replace('"', "").strip())
if isfile(script): if os.path.isfile(script):
return script return script
path = _lookup_in_ldpath(script) path = _lookup_in_ldpath(script)
if path: if path:
@ -319,29 +318,6 @@ def GetActualLDScript(env):
env.Exit(1) env.Exit(1)
def VerboseAction(_, act, actstr):
if int(ARGUMENTS.get("PIOVERBOSE", 0)):
return act
return Action(act, actstr)
def PioClean(env, clean_dir):
if not isdir(clean_dir):
print("Build environment is clean")
env.Exit(0)
clean_rel_path = relpath(clean_dir)
for root, _, files in walk(clean_dir):
for f in files:
dst = join(root, f)
remove(dst)
print(
"Removed %s" % (dst if clean_rel_path.startswith(".") else relpath(dst))
)
print("Done cleaning")
fs.rmtree(clean_dir)
env.Exit(0)
def ConfigureDebugFlags(env): def ConfigureDebugFlags(env):
def _cleanup_debug_flags(scope): def _cleanup_debug_flags(scope):
if scope not in env: if scope not in env:
@ -370,16 +346,16 @@ def ConfigureDebugFlags(env):
def ConfigureTestTarget(env): def ConfigureTestTarget(env):
env.Append( env.Append(
CPPDEFINES=["UNIT_TEST", "UNITY_INCLUDE_CONFIG_H"], CPPDEFINES=["UNIT_TEST", "UNITY_INCLUDE_CONFIG_H"],
CPPPATH=[join("$BUILD_DIR", "UnityTestLib")], CPPPATH=[os.path.join("$BUILD_DIR", "UnityTestLib")],
) )
unitylib = env.BuildLibrary( unitylib = env.BuildLibrary(
join("$BUILD_DIR", "UnityTestLib"), get_core_package_dir("tool-unity") os.path.join("$BUILD_DIR", "UnityTestLib"), get_core_package_dir("tool-unity")
) )
env.Prepend(LIBS=[unitylib]) env.Prepend(LIBS=[unitylib])
src_filter = ["+<*.cpp>", "+<*.c>"] src_filter = ["+<*.cpp>", "+<*.c>"]
if "PIOTEST_RUNNING_NAME" in env: if "PIOTEST_RUNNING_NAME" in env:
src_filter.append("+<%s%s>" % (env["PIOTEST_RUNNING_NAME"], sep)) src_filter.append("+<%s%s>" % (env["PIOTEST_RUNNING_NAME"], os.path.sep))
env.Replace(PIOTEST_SRC_FILTER=src_filter) env.Replace(PIOTEST_SRC_FILTER=src_filter)
@ -393,7 +369,7 @@ def GetExtraScripts(env, scope):
if not items: if not items:
return items return items
with fs.cd(env.subst("$PROJECT_DIR")): with fs.cd(env.subst("$PROJECT_DIR")):
return [realpath(item) for item in items] return [os.path.realpath(item) for item in items]
def exists(_): def exists(_):
@ -404,8 +380,6 @@ def generate(env):
env.AddMethod(ConvertInoToCpp) env.AddMethod(ConvertInoToCpp)
env.AddMethod(GetCompilerType) env.AddMethod(GetCompilerType)
env.AddMethod(GetActualLDScript) env.AddMethod(GetActualLDScript)
env.AddMethod(VerboseAction)
env.AddMethod(PioClean)
env.AddMethod(ConfigureDebugFlags) env.AddMethod(ConfigureDebugFlags)
env.AddMethod(ConfigureTestTarget) env.AddMethod(ConfigureTestTarget)
env.AddMethod(GetExtraScripts) env.AddMethod(GetExtraScripts)

View File

@ -0,0 +1,109 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# 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.
from __future__ import absolute_import
import os
from SCons.Action import Action # pylint: disable=import-error
from SCons.Script import ARGUMENTS # pylint: disable=import-error
from SCons.Script import AlwaysBuild # pylint: disable=import-error
from platformio import fs
def VerboseAction(_, act, actstr):
if int(ARGUMENTS.get("PIOVERBOSE", 0)):
return act
return Action(act, actstr)
def PioClean(env, clean_dir):
if not os.path.isdir(clean_dir):
print("Build environment is clean")
env.Exit(0)
clean_rel_path = os.path.relpath(clean_dir)
for root, _, files in os.walk(clean_dir):
for f in files:
dst = os.path.join(root, f)
os.remove(dst)
print(
"Removed %s"
% (dst if clean_rel_path.startswith(".") else os.path.relpath(dst))
)
print("Done cleaning")
fs.rmtree(clean_dir)
env.Exit(0)
def _add_pio_target( # pylint: disable=too-many-arguments
env,
scope,
name,
dependencies,
actions,
title=None,
description=None,
always_build=True,
):
if "__PIO_TARGETS" not in env:
env["__PIO_TARGETS"] = {}
assert name not in env["__PIO_TARGETS"]
env["__PIO_TARGETS"][name] = dict(
name=name, scope=scope, title=title, description=description
)
target = env.Alias(name, dependencies, actions)
if always_build:
AlwaysBuild(target)
return target
def AddSystemTarget(env, *args, **kwargs):
return _add_pio_target(env, "system", *args, **kwargs)
def AddCustomTarget(env, *args, **kwargs):
return _add_pio_target(env, "custom", *args, **kwargs)
def DumpTargets(env):
print("DumpTargets", id(env))
targets = env.get("__PIO_TARGETS") or {}
# pre-fill default system targets
if (
not any(t["scope"] == "system" for t in targets.values())
and env.PioPlatform().is_embedded()
):
targets["upload"] = dict(name="upload", scope="system", title="Upload")
targets["compiledb"] = dict(
name="compiledb",
scope="system",
title="Compilation database",
description="Generate compilation database `compile_commands.json`",
)
targets["clean"] = dict(name="clean", scope="system", title="Clean")
return list(targets.values())
def exists(_):
return True
def generate(env):
env.AddMethod(VerboseAction)
env.AddMethod(PioClean)
env.AddMethod(AddSystemTarget)
env.AddMethod(AddCustomTarget)
env.AddMethod(DumpTargets)
return env