The Unified Debugger

This commit is contained in:
Ivan Kravets
2017-04-28 01:38:25 +03:00
parent 81c96808b6
commit 9658bcdb73
12 changed files with 87 additions and 242 deletions

View File

@ -12,10 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from os import getenv, listdir
import os
import sys
from os.path import join
from platform import system
from sys import exit as sys_exit
from traceback import format_exc
import click
@ -29,7 +29,7 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904
def list_commands(self, ctx):
cmds = []
for filename in listdir(join(get_source_dir(), "commands")):
for filename in os.listdir(join(get_source_dir(), "commands")):
if filename.startswith("__init__"):
continue
if filename.endswith(".py"):
@ -96,7 +96,7 @@ def main():
"< https://github.com/platformio/platformio-core/issues/252 >")
# handle PLATFORMIO_FORCE_COLOR
if str(getenv("PLATFORMIO_FORCE_COLOR", "")).lower() == "true":
if str(os.getenv("PLATFORMIO_FORCE_COLOR", "")).lower() == "true":
try:
# pylint: disable=protected-access
click._compat.isatty = lambda stream: True
@ -133,5 +133,10 @@ An unexpected error occurred. Further steps:
return 0
def debug_gdb_main():
sys.argv = [sys.argv[0], "debug", "--interface", "gdb"] + sys.argv[1:]
return main()
if __name__ == "__main__":
sys_exit(main())
sys.exit(main())

View File

@ -62,20 +62,14 @@ commonvars.AddVariables(
("UPLOAD_PROTOCOL",),
("UPLOAD_SPEED",),
("UPLOAD_FLAGS",),
("UPLOAD_RESETMETHOD",),
# debug options
("DEBUG_TOOL",),
("DEBUG_PORT",),
("DEBUG_GDBINIT",)
("UPLOAD_RESETMETHOD",)
) # yapf: disable
DEFAULT_ENV_OPTIONS = dict(
tools=[
"ar", "as", "gcc", "g++", "gnulink", "platformio", "pioplatform",
"piowinhooks", "piolib", "piotest", "pioupload", "piomisc", "pioide",
"piodebug"
"piowinhooks", "piolib", "pioupload", "piomisc", "pioide"
], # yapf: disable
toolpath=[join(util.get_source_dir(), "builder", "tools")],
variables=commonvars,

View File

@ -1,115 +0,0 @@
# Copyright 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 sys
from fnmatch import fnmatch
from os.path import isfile
from platform import system
from platformio import util
def ProcessDebug(env):
env.Append(
BUILD_FLAGS=["-Og", "-ggdb"],
BUILD_UNFLAGS=["-Os", "-O0", "-O1", "-O2", "-O3"])
def DebugToolSettings(env):
if "BOARD" not in env:
return
board_debug = env.BoardConfig().get("debug", {})
if not board_debug or not board_debug.get("tools"):
return
debug_tools = board_debug.get("tools")
tool_name = (env.subst("$DEBUG_TOOL") or
board_debug.get("default_tool", debug_tools.keys()[0]))
settings = debug_tools.get(tool_name)
if not settings:
return
settings.update({"name": tool_name})
return settings
def AutodetectDebugPort(env):
def _get_pattern():
if "DEBUG_PORT" not in env:
return None
if set(["*", "?", "[", "]"]) & set(env['DEBUG_PORT']):
return env['DEBUG_PORT']
return None
def _is_match_pattern(port):
pattern = _get_pattern()
if not pattern:
return True
return fnmatch(port, pattern)
def _look_for_serial_port(hwids):
for item in util.get_serialports(filter_hwid=True):
if not _is_match_pattern(item['port']):
continue
if "GDB" in item['port']:
return item['port']
for hwid in hwids:
hwid_str = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "")
if hwid_str in item['hwid']:
return item['port']
return None
if "BOARD" not in env or ("DEBUG_PORT" in env and not _get_pattern()):
return
tool_settings = env.DebugToolSettings()
if not tool_settings:
return
if not tool_settings.get("require_debug_port"):
return
need_openocd_rules = [
system() == "Linux",
"openocd" in tool_settings.get("server", {}).get("package", ""),
not any([
isfile("/etc/udev/rules.d/98-openocd-udev.rules"),
isfile("/lib/udev/rules.d/98-openocd-udev.rules")
])
]
if all(need_openocd_rules):
sys.stderr.write(
"\nWarning! Please install `98-openocd-udev.rules` and check "
"that your debug adapter's PID and VID are listed in the rules."
"\n https://raw.githubusercontent.com/platformio/platformio"
"/develop/scripts/98-openocd-udev.rules\n")
env.Replace(
DEBUG_PORT=_look_for_serial_port(tool_settings.get("hwids", [])))
if not env.subst("$DEBUG_PORT"):
sys.stderr.write(
"Error: Please specify `debug_port` for environment.\n")
env.Exit(1)
def exists(_):
return True
def generate(env):
env.AddMethod(ProcessDebug)
env.AddMethod(DebugToolSettings)
env.AddMethod(AutodetectDebugPort)
return env

View File

@ -15,7 +15,7 @@
from __future__ import absolute_import
from glob import glob
from os.path import join, sep
from os.path import join
from SCons.Defaults import processDefines
@ -67,54 +67,6 @@ def dump_defines(env):
return defines
def dump_debug(env):
def _fix_path_sep(path):
result = []
items = path if isinstance(path, list) else [path]
for item in items:
result.append(item.replace("/", sep).replace("\\", sep))
return result if isinstance(path, list) else result[0]
def _dump_server(configuration):
if not configuration:
return
if not set(configuration.keys()) >= set(["package", "executable"]):
return
pkg_dir = env.PioPlatform().get_package_dir(configuration['package'])
if not pkg_dir:
return
return {
"cwd": pkg_dir,
"executable": _fix_path_sep(configuration['executable']),
"arguments": _fix_path_sep(configuration.get("arguments"))
}
gdbinit = None
if "DEBUG_GDBINIT" in env:
if isinstance(env['DEBUG_GDBINIT'], list):
gdbinit = env['DEBUG_GDBINIT']
else:
gdbinit = [env['DEBUG_GDBINIT']]
tool_settings = env.DebugToolSettings()
if tool_settings and not gdbinit:
gdbinit = tool_settings.get("gdbinit")
env.AutodetectDebugPort()
return {
"gdb_path": util.where_is_program(
env.subst("$GDB"), env.subst("${ENV['PATH']}")),
"prog_path": env.subst("$PROG_PATH"),
"tool": tool_settings['name'] if tool_settings else None,
"gdbinit": [env.subst(cmd) for cmd in gdbinit] if gdbinit else None,
"port": env.subst("$DEBUG_PORT"),
"server": (_dump_server(tool_settings['server'])
if tool_settings and "server" in tool_settings else None)
}
def DumpIDEData(env):
LINTCCOM = "$CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS"
LINTCXXCOM = "$CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS"
@ -124,13 +76,15 @@ def DumpIDEData(env):
[env.subst(l) for l in env.get("LIBSOURCE_DIRS", [])],
"defines": dump_defines(env),
"includes": dump_includes(env),
"debug": dump_debug(env),
"cc_flags": env.subst(LINTCCOM),
"cxx_flags": env.subst(LINTCXXCOM),
"cc_path": util.where_is_program(
env.subst("$CC"), env.subst("${ENV['PATH']}")),
"cxx_path": util.where_is_program(
env.subst("$CXX"), env.subst("${ENV['PATH']}")),
"gdb_path": util.where_is_program(
env.subst("$GDB"), env.subst("${ENV['PATH']}")),
"prog_path": env.subst("$PROG_PATH")
}
env_ = env.Clone()

View File

@ -18,13 +18,14 @@ import atexit
import re
import sys
from os import environ, remove, walk
from os.path import basename, isdir, isfile, join, relpath
from os.path import basename, isdir, isfile, join, relpath, sep
from tempfile import mkstemp
from SCons.Action import Action
from SCons.Script import ARGUMENTS
from platformio import util
from platformio.managers.core import get_core_package_dir
class InoToCPPConverter(object):
@ -268,6 +269,34 @@ def PioClean(env, clean_dir):
env.Exit(0)
def ProcessDebug(env):
if not env.subst("$PIODEBUGFLAGS"):
env.Replace(PIODEBUGFLAGS=["-Og", "-g3", "-ggdb"])
env.Append(
BUILD_FLAGS=env.get("PIODEBUGFLAGS", []),
BUILD_UNFLAGS=["-Os", "-O0", "-O1", "-O2", "-O3"])
def ProcessTest(env):
env.Append(
CPPDEFINES=["UNIT_TEST", "UNITY_INCLUDE_CONFIG_H"],
CPPPATH=[join("$BUILD_DIR", "UnityTestLib")])
unitylib = env.BuildLibrary(
join("$BUILD_DIR", "UnityTestLib"), get_core_package_dir("tool-unity"))
env.Prepend(LIBS=[unitylib])
src_filter = None
if "PIOTEST" in env:
src_filter = "+<output_export.cpp>"
src_filter += " +<%s%s>" % (env['PIOTEST'], sep)
return env.CollectBuildFiles(
"$BUILDTEST_DIR",
"$PROJECTTEST_DIR",
src_filter=src_filter,
duplicate=False)
def exists(_):
return True
@ -278,4 +307,6 @@ def generate(env):
env.AddMethod(GetActualLDScript)
env.AddMethod(VerboseAction)
env.AddMethod(PioClean)
env.AddMethod(ProcessDebug)
env.AddMethod(ProcessTest)
return env

View File

@ -1,48 +0,0 @@
# Copyright 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
from os.path import join, sep
from platformio.managers.core import get_core_package_dir
def ProcessTest(env):
env.Append(
CPPDEFINES=["UNIT_TEST", "UNITY_INCLUDE_CONFIG_H"],
CPPPATH=[join("$BUILD_DIR", "UnityTestLib")])
unitylib = env.BuildLibrary(
join("$BUILD_DIR", "UnityTestLib"), get_core_package_dir("tool-unity"))
env.Prepend(LIBS=[unitylib])
src_filter = None
if "PIOTEST" in env:
src_filter = "+<output_export.cpp>"
src_filter += " +<%s%s>" % (env['PIOTEST'], sep)
return env.CollectBuildFiles(
"$BUILDTEST_DIR",
"$PROJECTTEST_DIR",
src_filter=src_filter,
duplicate=False)
def exists(_):
return True
def generate(env):
env.AddMethod(ProcessTest)
return env

View File

@ -20,7 +20,10 @@ import click
from platformio.managers.core import pioplus_call
@click.command("debug", short_help="Project Debugger")
@click.command(
"debug",
context_settings=dict(ignore_unknown_options=True),
short_help="The Unified Debugger")
@click.option(
"-d",
"--project-dir",
@ -32,8 +35,8 @@ from platformio.managers.core import pioplus_call
writable=True,
resolve_path=True))
@click.option("--environment", "-e", metavar="<environment>")
@click.option("--configuration", is_flag=True)
@click.option("--json-output", is_flag=True)
@click.option("--verbose", "-v", is_flag=True)
@click.option("--interface", type=click.Choice(["gdb"]))
@click.argument("__unprocessed", nargs=-1, type=click.UNPROCESSED)
def cli(*args, **kwargs): # pylint: disable=unused-argument
pioplus_call(sys.argv[1:])

View File

@ -122,15 +122,18 @@ def cli(ctx, environment, target, upload_port, project_dir, silent, verbose,
class EnvironmentProcessor(object):
KNOWN_OPTIONS = (
"platform", "framework", "board", "board_mcu", "board_f_cpu",
"board_f_flash", "board_flash_mode", "build_flags", "src_build_flags",
"build_unflags", "src_filter", "extra_script", "targets",
"upload_port", "upload_protocol", "upload_speed", "upload_flags",
"upload_resetmethod", "lib_install", "lib_deps", "lib_force",
"lib_ignore", "lib_extra_dirs", "lib_ldf_mode", "lib_compat_mode",
"test_ignore", "test_port", "piotest", "debug_tool", "debug_port",
"debug_gdbinit")
KNOWN_OPTIONS = ("platform", "framework", "board", "board_mcu",
"board_f_cpu", "board_f_flash", "board_flash_mode",
"build_flags", "src_build_flags", "build_unflags",
"src_filter", "extra_script", "targets", "upload_port",
"upload_protocol", "upload_speed", "upload_flags",
"upload_resetmethod", "lib_deps", "lib_ignore",
"lib_extra_dirs", "lib_ldf_mode", "lib_compat_mode",
"piotest", "test_ignore", "test_port", "debug_tool",
"debug_port", "debug_init_cmds", "debug_extra_cmds")
IGNORE_BUILD_OPTIONS = ("debug_tool", "debug_port", "debug_init_cmds",
"debug_extra_cmds")
REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"}
@ -224,6 +227,8 @@ class EnvironmentProcessor(object):
for k, v in self.options.items():
if k in self.REMAPED_OPTIONS:
k = self.REMAPED_OPTIONS[k]
if k in self.IGNORE_BUILD_OPTIONS:
continue
if k == "targets" or (k == "upload_port" and self.upload_port):
continue
variables[k] = v

View File

@ -38,8 +38,11 @@ def in_silence(ctx=None):
ctx = ctx or app.get_session_var("command_ctx")
assert ctx
ctx_args = ctx.args or []
return (ctx_args and
(ctx.args[0] == "upgrade" or "--json-output" in ctx_args))
conditions = [
ctx.args[0] == "upgrade", "--json-output" in ctx_args,
"--version" in ctx_args
]
return ctx_args and any(conditions)
def on_platformio_start(ctx, force, caller):

View File

@ -22,7 +22,7 @@ from platformio.managers.package import PackageManager
CORE_PACKAGES = {
"pysite-pioplus": ">=0.3.0,<2",
"tool-pioplus": ">=0.7.3,<2",
"tool-pioplus": ">=0.8.1,<2",
"tool-unity": "~1.20302.1",
"tool-scons": "~3.20501.2"
}

View File

@ -643,6 +643,18 @@ class PlatformBoardConfig(object):
"ram": self._manifest.get("upload", {}).get("maximum_ram_size", 0),
"rom": self._manifest.get("upload", {}).get("maximum_size", 0),
"frameworks": self._manifest.get("frameworks"),
"debug": self.get_debug_data(),
"vendor": self._manifest['vendor'],
"url": self._manifest['url']
}
def get_debug_data(self):
if not self._manifest.get("debug", {}).get("tools"):
return
tools = {}
for name, options in self._manifest['debug']['tools'].items():
tools[name] = {}
for key, value in options.items():
if key in ("default", "onboard"):
tools[name][key] = value
return {"tools": tools}

View File

@ -51,6 +51,7 @@ setup(
entry_points={
"console_scripts": [
"pio = platformio.__main__:main",
"piodebuggdb = platformio.__main__:debug_gdb_main",
"platformio = platformio.__main__:main"
]
},