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
-----------------
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.
4.3.4 (2020-05-23)

2
docs

Submodule docs updated: cfba4f4568...439f402c5b

View File

@ -55,6 +55,7 @@ DEFAULT_ENV_OPTIONS = dict(
"c++",
"link",
"platformio",
"piotarget",
"pioplatform",
"pioproject",
"piomaxlen",
@ -217,7 +218,7 @@ if "idedata" in COMMAND_LINE_TARGETS:
click.echo(
"\n%s\n"
% dump_json_to_unicode(
projenv.DumpIDEData() # pylint: disable=undefined-variable
projenv.DumpIDEData(env) # pylint: disable=undefined-variable
)
)
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]
def DumpIDEData(env):
def DumpIDEData(env, globalenv):
""" env here is `projenv`"""
env["__escape_build_flag"] = _escape_build_flag
@ -169,6 +170,7 @@ def DumpIDEData(env):
],
"svd_path": _get_svd_path(env),
"compiler_type": env.GetCompilerType(),
"targets": globalenv.DumpTargets(),
}
env_ = env.Clone()

View File

@ -16,15 +16,12 @@ from __future__ import absolute_import
import atexit
import io
import os
import re
import sys
from os import environ, remove, walk
from os.path import basename, isdir, isfile, join, realpath, relpath, sep
from tempfile import mkstemp
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.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(
out_file, tmp_path
),
"Converting " + basename(out_file[:-4]),
"Converting " + os.path.basename(out_file[:-4]),
)
)
atexit.register(_delete_file, tmp_path)
return isfile(out_file)
return os.path.isfile(out_file)
def _join_multiline_strings(self, contents):
if "\\\n" not in contents:
@ -233,7 +230,9 @@ class InoToCPPConverter(object):
def ConvertInoToCpp(env):
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:
return
c = InoToCPPConverter(env)
@ -244,8 +243,8 @@ def ConvertInoToCpp(env):
def _delete_file(path):
try:
if isfile(path):
remove(path)
if os.path.isfile(path):
os.remove(path)
except: # pylint: disable=bare-except
pass
@ -255,7 +254,7 @@ def _get_compiler_type(env):
if env.subst("$CC").endswith("-gcc"):
return "gcc"
try:
sysenv = environ.copy()
sysenv = os.environ.copy()
sysenv["PATH"] = str(env["ENV"]["PATH"])
result = exec_command([env.subst("$CC"), "-v"], env=sysenv)
except OSError:
@ -277,8 +276,8 @@ def GetCompilerType(env):
def GetActualLDScript(env):
def _lookup_in_ldpath(script):
for d in env.get("LIBPATH", []):
path = join(env.subst(d), script)
if isfile(path):
path = os.path.join(env.subst(d), script)
if os.path.isfile(path):
return path
return None
@ -297,7 +296,7 @@ def GetActualLDScript(env):
else:
continue
script = env.subst(raw_script.replace('"', "").strip())
if isfile(script):
if os.path.isfile(script):
return script
path = _lookup_in_ldpath(script)
if path:
@ -319,29 +318,6 @@ def GetActualLDScript(env):
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 _cleanup_debug_flags(scope):
if scope not in env:
@ -370,16 +346,16 @@ def ConfigureDebugFlags(env):
def ConfigureTestTarget(env):
env.Append(
CPPDEFINES=["UNIT_TEST", "UNITY_INCLUDE_CONFIG_H"],
CPPPATH=[join("$BUILD_DIR", "UnityTestLib")],
CPPPATH=[os.path.join("$BUILD_DIR", "UnityTestLib")],
)
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])
src_filter = ["+<*.cpp>", "+<*.c>"]
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)
@ -393,7 +369,7 @@ def GetExtraScripts(env, scope):
if not items:
return items
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(_):
@ -404,8 +380,6 @@ def generate(env):
env.AddMethod(ConvertInoToCpp)
env.AddMethod(GetCompilerType)
env.AddMethod(GetActualLDScript)
env.AddMethod(VerboseAction)
env.AddMethod(PioClean)
env.AddMethod(ConfigureDebugFlags)
env.AddMethod(ConfigureTestTarget)
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