Skip to content

Commit a7c82ff

Browse files
committed
Merge branch 'release/v5.2.1'
2 parents 624d6b3 + c348fec commit a7c82ff

File tree

21 files changed

+266
-72
lines changed

21 files changed

+266
-72
lines changed

.github/workflows/examples.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
strategy:
88
fail-fast: false
99
matrix:
10-
os: [ubuntu-16.04, windows-latest, macos-latest]
10+
os: [ubuntu-18.04, windows-latest, macos-latest]
1111
python-version: [3.7]
1212
runs-on: ${{ matrix.os }}
1313
steps:

.pylintrc

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ disable=
1616
useless-import-alias,
1717
bad-option-value,
1818
consider-using-dict-items,
19+
consider-using-f-string,
1920

2021
; PY2 Compat
2122
super-with-arguments,

HISTORY.rst

+12
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ PlatformIO Core 5
88

99
**A professional collaborative platform for embedded development**
1010

11+
5.2.1 (2021-10-11)
12+
~~~~~~~~~~~~~~~~~~
13+
14+
- Clean a build environment and installed library dependencies using a new ``cleanall`` target (`issue #4062 <https://github.com/platformio/platformio-core/issues/4062>`_)
15+
- Override a default library builder via a new ``builder`` field in a ``build`` group of `library.json <https://docs.platformio.org/page/librarymanager/config.html#build>`__ manifest (`issue #3957 <https://github.com/platformio/platformio-core/issues/3957>`_)
16+
- Updated `Cppcheck <https://docs.platformio.org/page/plus/check-tools/cppcheck.html>`__ v2.6 with new checks, increased reliability of advanced addons (MISRA/CERT) and various improvements
17+
- Handle the "test" folder as a part of CLion project (`issue #4005 <https://github.com/platformio/platformio-core/issues/4005>`_)
18+
- Improved handling of a library root based on "Conan" or "CMake" build systems (`issue #3887 <https://github.com/platformio/platformio-core/issues/3887>`_)
19+
- Fixed a "KeyError: Invalid board option 'build.cpu'" when using a precompiled library with a board that does not have a CPU field in the manifest (`issue #4056 <https://github.com/platformio/platformio-core/issues/4056>`_)
20+
- Fixed a "FileExist" error when the `platformio ci <https://docs.platformio.org/en/latest/userguide/cmd_ci.html>`__ command is used in pair with the ``--keep-build-dir`` option (`issue #4011 <https://github.com/platformio/platformio-core/issues/4011>`_)
21+
- Fixed an issue with draft values of C++ language standards that broke static analysis via Cppcheck (`issue #3944 <https://github.com/platformio/platformio-core/issues/3944>`_)
22+
1123
5.2.0 (2021-09-13)
1224
~~~~~~~~~~~~~~~~~~
1325

platformio/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import sys
1616

17-
VERSION = (5, 2, 0)
17+
VERSION = (5, 2, 1)
1818
__version__ = ".".join([str(s) for s in VERSION])
1919

2020
__title__ = "platformio"
@@ -51,7 +51,7 @@
5151
"contrib-pysite": "~2.%d%d.0" % (sys.version_info.major, sys.version_info.minor),
5252
"tool-unity": "~1.20500.0",
5353
"tool-scons": "~4.40200.0",
54-
"tool-cppcheck": "~1.250.0",
54+
"tool-cppcheck": "~1.260.0",
5555
"tool-clangtidy": "~1.120001.0",
5656
"tool-pvs-studio": "~7.14.0",
5757
}

platformio/__main__.py

+18-3
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,24 @@ def cli(ctx, force, caller, no_ansi):
6767
maintenance.on_platformio_start(ctx, force, caller)
6868

6969

70-
@cli.resultcallback()
71-
@click.pass_context
72-
def process_result(ctx, result, *_, **__):
70+
try:
71+
72+
@cli.result_callback()
73+
@click.pass_context
74+
def process_result(ctx, result, *_, **__):
75+
_process_result(ctx, result)
76+
77+
78+
except (AttributeError, TypeError): # legacy support for CLick > 8.0.1
79+
print("legacy Click")
80+
81+
@cli.resultcallback()
82+
@click.pass_context
83+
def process_result(ctx, result, *_, **__):
84+
_process_result(ctx, result)
85+
86+
87+
def _process_result(ctx, result):
7388
from platformio import maintenance
7489

7590
maintenance.on_platformio_end(ctx, result)

platformio/builder/main.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,12 @@
149149
# pylint: disable=protected-access
150150
click._compat.isatty = lambda stream: True
151151

152-
if env.GetOption("clean"):
153-
env.PioClean(env.subst("$BUILD_DIR"))
152+
is_clean_all = "cleanall" in COMMAND_LINE_TARGETS
153+
if env.GetOption("clean") or is_clean_all:
154+
env.PioClean(is_clean_all)
154155
env.Exit(0)
155-
elif not int(ARGUMENTS.get("PIOVERBOSE", 0)):
156+
157+
if not int(ARGUMENTS.get("PIOVERBOSE", 0)):
156158
click.echo("Verbose mode can be enabled via `-v, --verbose` option")
157159

158160
# Dynamically load dependent tools

platformio/builder/tools/piolib.py

+34-19
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ def new(env, path, verbose=int(ARGUMENTS.get("PIOVERBOSE", 0))):
5959
clsname = "%sLibBuilder" % used_frameworks[0].title()
6060

6161
obj = getattr(sys.modules[__name__], clsname)(env, path, verbose=verbose)
62+
63+
# Handle PlatformIOLibBuilder.manifest.build.builder
64+
# pylint: disable=protected-access
65+
if isinstance(obj, PlatformIOLibBuilder) and obj._manifest.get("build", {}).get(
66+
"builder"
67+
):
68+
obj = getattr(
69+
sys.modules[__name__], obj._manifest.get("build", {}).get("builder")
70+
)(env, path, verbose=verbose)
71+
6272
assert isinstance(obj, LibBuilderBase)
6373
return obj
6474

@@ -174,19 +184,19 @@ def src_filter(self):
174184

175185
@property
176186
def include_dir(self):
177-
if not all(
178-
os.path.isdir(os.path.join(self.path, d)) for d in ("include", "src")
179-
):
180-
return None
181-
return os.path.join(self.path, "include")
187+
for name in ("include", "Include"):
188+
d = os.path.join(self.path, name)
189+
if os.path.isdir(d):
190+
return d
191+
return None
182192

183193
@property
184194
def src_dir(self):
185-
return (
186-
os.path.join(self.path, "src")
187-
if os.path.isdir(os.path.join(self.path, "src"))
188-
else self.path
189-
)
195+
for name in ("src", "Src"):
196+
d = os.path.join(self.path, name)
197+
if os.path.isdir(d):
198+
return d
199+
return self.path
190200

191201
def get_include_dirs(self):
192202
items = []
@@ -491,6 +501,14 @@ def load_manifest(self):
491501
return {}
492502
return ManifestParserFactory.new_from_file(manifest_path).as_dict()
493503

504+
@property
505+
def include_dir(self):
506+
if not all(
507+
os.path.isdir(os.path.join(self.path, d)) for d in ("include", "src")
508+
):
509+
return None
510+
return os.path.join(self.path, "include")
511+
494512
def get_include_dirs(self):
495513
include_dirs = LibBuilderBase.get_include_dirs(self)
496514
if os.path.isdir(os.path.join(self.path, "src")):
@@ -566,9 +584,12 @@ def build_flags(self):
566584
if self._manifest.get("precompiled") in ("true", "full"):
567585
# add to LDPATH {build.mcu} folder
568586
board_config = self.env.BoardConfig()
569-
self.env.PrependUnique(
570-
LIBPATH=os.path.join(self.src_dir, board_config.get("build.cpu"))
571-
)
587+
for key in ("build.mcu", "build.cpu"):
588+
libpath = os.path.join(self.src_dir, board_config.get(key, ""))
589+
if not os.path.isdir(libpath):
590+
continue
591+
self.env.PrependUnique(LIBPATH=libpath)
592+
break
572593
ldflags = [flag for flag in ldflags if flag] # remove empty
573594
return " ".join(ldflags) if ldflags else None
574595

@@ -580,12 +601,6 @@ def load_manifest(self):
580601
return {}
581602
return ManifestParserFactory.new_from_file(manifest_path).as_dict()
582603

583-
@property
584-
def include_dir(self):
585-
if os.path.isdir(os.path.join(self.path, "include")):
586-
return os.path.join(self.path, "include")
587-
return None
588-
589604
@property
590605
def src_dir(self):
591606
if os.path.isdir(os.path.join(self.path, "source")):

platformio/builder/tools/piotarget.py

+31-16
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def VerboseAction(_, act, actstr):
2929
return Action(act, actstr)
3030

3131

32-
def PioClean(env, clean_dir):
32+
def PioClean(env, clean_all=False):
3333
def _relpath(path):
3434
if compat.IS_WINDOWS:
3535
prefix = os.getcwd()[:2].lower()
@@ -41,21 +41,30 @@ def _relpath(path):
4141
return path
4242
return os.path.relpath(path)
4343

44-
if not os.path.isdir(clean_dir):
44+
def _clean_dir(path):
45+
clean_rel_path = _relpath(path)
46+
for root, _, files in os.walk(path):
47+
for f in files:
48+
dst = os.path.join(root, f)
49+
os.remove(dst)
50+
print(
51+
"Removed %s"
52+
% (dst if not clean_rel_path.startswith(".") else _relpath(dst))
53+
)
54+
55+
build_dir = env.subst("$BUILD_DIR")
56+
libdeps_dir = env.subst("$PROJECT_LIBDEPS_DIR")
57+
if os.path.isdir(build_dir):
58+
_clean_dir(build_dir)
59+
fs.rmtree(build_dir)
60+
else:
4561
print("Build environment is clean")
46-
env.Exit(0)
47-
clean_rel_path = _relpath(clean_dir)
48-
for root, _, files in os.walk(clean_dir):
49-
for f in files:
50-
dst = os.path.join(root, f)
51-
os.remove(dst)
52-
print(
53-
"Removed %s"
54-
% (dst if not clean_rel_path.startswith(".") else _relpath(dst))
55-
)
62+
63+
if clean_all and os.path.isdir(libdeps_dir):
64+
_clean_dir(libdeps_dir)
65+
fs.rmtree(libdeps_dir)
66+
5667
print("Done cleaning")
57-
fs.rmtree(clean_dir)
58-
env.Exit(0)
5968

6069

6170
def AddTarget( # pylint: disable=too-many-arguments
@@ -65,7 +74,7 @@ def AddTarget( # pylint: disable=too-many-arguments
6574
actions,
6675
title=None,
6776
description=None,
68-
group="Generic",
77+
group="General",
6978
always_build=True,
7079
):
7180
if "__PIO_TARGETS" not in env:
@@ -101,7 +110,13 @@ def DumpTargets(env):
101110
description="Generate compilation database `compile_commands.json`",
102111
group="Advanced",
103112
)
104-
targets["clean"] = dict(name="clean", title="Clean", group="Generic")
113+
targets["clean"] = dict(name="clean", title="Clean", group="General")
114+
targets["cleanall"] = dict(
115+
name="cleanall",
116+
title="Clean All",
117+
group="General",
118+
description="Clean a build environment and installed library dependencies",
119+
)
105120
return list(targets.values())
106121

107122

platformio/commands/check/tools/cppcheck.py

+20-4
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,11 @@ def configure_command(self, language, src_file): # pylint: disable=arguments-di
141141

142142
build_flags = self.cxx_flags if language == "c++" else self.cc_flags
143143

144-
for flag in build_flags:
145-
if "-std" in flag:
146-
# Standards with GNU extensions are not allowed
147-
cmd.append("-" + flag.replace("gnu", "c"))
144+
if not self.is_flag_set("--std", flags):
145+
# Try to guess the standard version from the build flags
146+
for flag in build_flags:
147+
if "-std" in flag:
148+
cmd.append("-" + self.convert_language_standard(flag))
148149

149150
cmd.extend(
150151
["-D%s" % d for d in self.cpp_defines + self.toolchain_defines[language]]
@@ -224,6 +225,21 @@ def is_check_successful(cmd_result):
224225
# Cppcheck is configured to return '3' if a defect is found
225226
return cmd_result["returncode"] in (0, 3)
226227

228+
@staticmethod
229+
def convert_language_standard(flag):
230+
cpp_standards_map = {
231+
"0x": "11",
232+
"1y": "14",
233+
"1z": "17",
234+
"2a": "20",
235+
}
236+
237+
standard = flag[-2:]
238+
# Note: GNU extensions are not supported and converted to regular standards
239+
return flag.replace("gnu", "c").replace(
240+
standard, cpp_standards_map.get(standard, standard)
241+
)
242+
227243
def check(self, on_defect_callback=None):
228244
self._on_defect_callback = on_defect_callback
229245

platformio/commands/ci.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def cli( # pylint: disable=too-many-arguments, too-many-branches
122122
fs.rmtree(build_dir)
123123

124124

125-
def _copy_contents(dst_dir, contents):
125+
def _copy_contents(dst_dir, contents): # pylint: disable=too-many-branches
126126
items = {"dirs": set(), "files": set()}
127127

128128
for path in contents:
@@ -134,14 +134,15 @@ def _copy_contents(dst_dir, contents):
134134
dst_dir_name = os.path.basename(dst_dir)
135135

136136
if dst_dir_name == "src" and len(items["dirs"]) == 1:
137-
shutil.copytree(list(items["dirs"]).pop(), dst_dir, symlinks=True)
137+
if not os.path.isdir(dst_dir):
138+
shutil.copytree(list(items["dirs"]).pop(), dst_dir, symlinks=True)
138139
else:
139140
if not os.path.isdir(dst_dir):
140141
os.makedirs(dst_dir)
141142
for d in items["dirs"]:
142-
shutil.copytree(
143-
d, os.path.join(dst_dir, os.path.basename(d)), symlinks=True
144-
)
143+
src_dst_dir = os.path.join(dst_dir, os.path.basename(d))
144+
if not os.path.isdir(src_dst_dir):
145+
shutil.copytree(d, src_dst_dir, symlinks=True)
145146

146147
if not items["files"]:
147148
return

platformio/commands/home/rpc/handlers/project.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,8 @@ def _generate_project_main(project_dir, board, framework):
265265
fp.write(main_content.strip())
266266
return project_dir
267267

268-
async def import_arduino(self, board, use_arduino_libs, arduino_project_dir):
268+
@staticmethod
269+
async def import_arduino(board, use_arduino_libs, arduino_project_dir):
269270
board = str(board)
270271
# don't import PIO Project
271272
if is_platformio_project(arduino_project_dir):

platformio/commands/remote/command.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,10 @@ def device_monitor(ctx, agents, **kwargs):
336336
kwargs["baud"] = kwargs["baud"] or 9600
337337

338338
def _tx_target(sock_dir):
339-
subcmd_argv = ["remote", "device", "monitor"]
339+
subcmd_argv = ["remote"]
340+
for agent in agents:
341+
subcmd_argv.extend(["--agent", agent])
342+
subcmd_argv.extend(["device", "monitor"])
340343
subcmd_argv.extend(device_helpers.options_to_argv(kwargs, project_options))
341344
subcmd_argv.extend(["--sock", sock_dir])
342345
subprocess.call([proc.where_is_program("platformio")] + subcmd_argv)

platformio/ide/projectgenerator.py

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def _load_tplvars(self):
8181
"src_files": self.get_src_files(),
8282
"project_src_dir": self.config.get_optional_dir("src"),
8383
"project_lib_dir": self.config.get_optional_dir("lib"),
84+
"project_test_dir": self.config.get_optional_dir("test"),
8485
"project_libdeps_dir": os.path.join(
8586
self.config.get_optional_dir("libdeps"), self.env_name
8687
),

platformio/ide/tpls/clion/CMakeListsPrivate.txt.tpl

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ endif()
115115
% end
116116

117117
FILE(GLOB_RECURSE SRC_LIST
118-
% for path in (project_src_dir, project_lib_dir):
118+
% for path in (project_src_dir, project_lib_dir, project_test_dir):
119119
{{ _normalize_path(path) + "/*.*" }}
120120
% end
121121
)

0 commit comments

Comments
 (0)