c03f93521b
* Add new option --skip-packages for check command Check tools might fail if they're not able to preprocess source files, for example, Cppcheck uses a custom preprocessor that is not able to parse complex preprocessor code in zephyr framework). Instead user can specify this option to skip headers included from packages and only check project sources. * Fix toolchain built-in include paths order C++ and fixed directories should have higher priority * Refactor check feature The main purpose is to prepare a more comprehensive build environment. It's crucial for cppcheck to be able to check complex frameworks like zephyr, esp-idf, etc. Also detect a special case when cppcheck fails to check the entire project (e.g. a syntax error due to custom preprocessor) * Add new test for check feature Tests ststm32 platform all tools and the main frameworks * Update check tools to the latest available versions * Test check tools and Zephyr framework only with Python 3 * Tidy up code * Add history entry
197 lines
6.0 KiB
Python
197 lines
6.0 KiB
Python
# 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 glob import glob
|
|
|
|
from SCons.Defaults import processDefines # pylint: disable=import-error
|
|
|
|
from platformio.compat import glob_escape
|
|
from platformio.managers.core import get_core_package_dir
|
|
from platformio.proc import exec_command, where_is_program
|
|
|
|
|
|
def _dump_includes(env):
|
|
includes = {}
|
|
|
|
includes["build"] = [
|
|
env.subst("$PROJECT_INCLUDE_DIR"),
|
|
env.subst("$PROJECT_SRC_DIR"),
|
|
]
|
|
includes["build"].extend(
|
|
[os.path.realpath(env.subst(item)) for item in env.get("CPPPATH", [])]
|
|
)
|
|
|
|
# installed libs
|
|
includes["compatlib"] = []
|
|
for lb in env.GetLibBuilders():
|
|
includes["compatlib"].extend(
|
|
[os.path.realpath(inc) for inc in lb.get_include_dirs()]
|
|
)
|
|
|
|
# includes from toolchains
|
|
p = env.PioPlatform()
|
|
includes["toolchain"] = []
|
|
for name in p.get_installed_packages():
|
|
if p.get_package_type(name) != "toolchain":
|
|
continue
|
|
toolchain_dir = glob_escape(p.get_package_dir(name))
|
|
toolchain_incglobs = [
|
|
os.path.join(toolchain_dir, "*", "include", "c++", "*"),
|
|
os.path.join(toolchain_dir, "*", "include", "c++", "*", "*-*-*"),
|
|
os.path.join(toolchain_dir, "lib", "gcc", "*", "*", "include*"),
|
|
os.path.join(toolchain_dir, "*", "include*"),
|
|
]
|
|
for g in toolchain_incglobs:
|
|
includes["toolchain"].extend([os.path.realpath(inc) for inc in glob(g)])
|
|
|
|
includes["unity"] = []
|
|
unity_dir = get_core_package_dir("tool-unity")
|
|
if unity_dir:
|
|
includes["unity"].append(unity_dir)
|
|
|
|
return includes
|
|
|
|
|
|
def _get_gcc_defines(env):
|
|
items = []
|
|
try:
|
|
sysenv = os.environ.copy()
|
|
sysenv["PATH"] = str(env["ENV"]["PATH"])
|
|
result = exec_command(
|
|
"echo | %s -dM -E -" % env.subst("$CC"), env=sysenv, shell=True
|
|
)
|
|
except OSError:
|
|
return items
|
|
if result["returncode"] != 0:
|
|
return items
|
|
for line in result["out"].split("\n"):
|
|
tokens = line.strip().split(" ", 2)
|
|
if not tokens or tokens[0] != "#define":
|
|
continue
|
|
if len(tokens) > 2:
|
|
items.append("%s=%s" % (tokens[1], tokens[2]))
|
|
else:
|
|
items.append(tokens[1])
|
|
return items
|
|
|
|
|
|
def _dump_defines(env):
|
|
defines = []
|
|
# global symbols
|
|
for item in processDefines(env.get("CPPDEFINES", [])):
|
|
defines.append(env.subst(item).replace("\\", ""))
|
|
|
|
# special symbol for Atmel AVR MCU
|
|
if env["PIOPLATFORM"] == "atmelavr":
|
|
board_mcu = env.get("BOARD_MCU")
|
|
if not board_mcu and "BOARD" in env:
|
|
board_mcu = env.BoardConfig().get("build.mcu")
|
|
if board_mcu:
|
|
defines.append(
|
|
str(
|
|
"__AVR_%s__"
|
|
% board_mcu.upper()
|
|
.replace("ATMEGA", "ATmega")
|
|
.replace("ATTINY", "ATtiny")
|
|
)
|
|
)
|
|
|
|
# built-in GCC marcos
|
|
# if env.GetCompilerType() == "gcc":
|
|
# defines.extend(_get_gcc_defines(env))
|
|
|
|
return defines
|
|
|
|
|
|
def _get_svd_path(env):
|
|
svd_path = env.GetProjectOption("debug_svd_path")
|
|
if svd_path:
|
|
return os.path.realpath(svd_path)
|
|
|
|
if "BOARD" not in env:
|
|
return None
|
|
try:
|
|
svd_path = env.BoardConfig().get("debug.svd_path")
|
|
assert svd_path
|
|
except (AssertionError, KeyError):
|
|
return None
|
|
# custom path to SVD file
|
|
if os.path.isfile(svd_path):
|
|
return svd_path
|
|
# default file from ./platform/misc/svd folder
|
|
p = env.PioPlatform()
|
|
if os.path.isfile(os.path.join(p.get_dir(), "misc", "svd", svd_path)):
|
|
return os.path.realpath(os.path.join(p.get_dir(), "misc", "svd", svd_path))
|
|
return None
|
|
|
|
|
|
def _escape_build_flag(flags):
|
|
return [flag if " " not in flag else '"%s"' % flag for flag in flags]
|
|
|
|
|
|
def DumpIDEData(env):
|
|
|
|
env["__escape_build_flag"] = _escape_build_flag
|
|
|
|
LINTCCOM = (
|
|
"${__escape_build_flag(CFLAGS)} ${__escape_build_flag(CCFLAGS)} $CPPFLAGS"
|
|
)
|
|
LINTCXXCOM = (
|
|
"${__escape_build_flag(CXXFLAGS)} ${__escape_build_flag(CCFLAGS)} $CPPFLAGS"
|
|
)
|
|
|
|
data = {
|
|
"env_name": env["PIOENV"],
|
|
"libsource_dirs": [env.subst(l) for l in env.GetLibSourceDirs()],
|
|
"defines": _dump_defines(env),
|
|
"includes": _dump_includes(env),
|
|
"cc_path": where_is_program(env.subst("$CC"), env.subst("${ENV['PATH']}")),
|
|
"cxx_path": where_is_program(env.subst("$CXX"), env.subst("${ENV['PATH']}")),
|
|
"gdb_path": where_is_program(env.subst("$GDB"), env.subst("${ENV['PATH']}")),
|
|
"prog_path": env.subst("$PROG_PATH"),
|
|
"flash_extra_images": [
|
|
{"offset": item[0], "path": env.subst(item[1])}
|
|
for item in env.get("FLASH_EXTRA_IMAGES", [])
|
|
],
|
|
"svd_path": _get_svd_path(env),
|
|
"compiler_type": env.GetCompilerType(),
|
|
}
|
|
|
|
env_ = env.Clone()
|
|
# https://github.com/platformio/platformio-atom-ide/issues/34
|
|
_new_defines = []
|
|
for item in processDefines(env_.get("CPPDEFINES", [])):
|
|
item = item.replace('\\"', '"')
|
|
if " " in item:
|
|
_new_defines.append(item.replace(" ", "\\\\ "))
|
|
else:
|
|
_new_defines.append(item)
|
|
env_.Replace(CPPDEFINES=_new_defines)
|
|
|
|
data.update({"cc_flags": env_.subst(LINTCCOM), "cxx_flags": env_.subst(LINTCXXCOM)})
|
|
|
|
return data
|
|
|
|
|
|
def exists(_):
|
|
return True
|
|
|
|
|
|
def generate(env):
|
|
env.AddMethod(DumpIDEData)
|
|
return env
|