mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-30 01:57:13 +02:00
Initial support for debugging // Resolve #514
This commit is contained in:
2
docs
2
docs
Submodule docs updated: 00f8cfe790...ecd4a795a4
@ -62,13 +62,20 @@ commonvars.AddVariables(
|
||||
("UPLOAD_PROTOCOL",),
|
||||
("UPLOAD_SPEED",),
|
||||
("UPLOAD_FLAGS",),
|
||||
("UPLOAD_RESETMETHOD",)
|
||||
("UPLOAD_RESETMETHOD",),
|
||||
|
||||
# debug options
|
||||
("DEBUG_LINK",),
|
||||
("DEBUG_PORT",),
|
||||
("DEBUG_GDBINIT",)
|
||||
|
||||
) # yapf: disable
|
||||
|
||||
DEFAULT_ENV_OPTIONS = dict(
|
||||
tools=[
|
||||
"ar", "as", "gcc", "g++", "gnulink", "platformio", "pioplatform",
|
||||
"piowinhooks", "piolib", "piotest", "pioupload", "piomisc"
|
||||
"piowinhooks", "piolib", "piotest", "pioupload", "piomisc", "pioide",
|
||||
"piodebug"
|
||||
], # yapf: disable
|
||||
toolpath=[join(util.get_source_dir(), "builder", "tools")],
|
||||
variables=commonvars,
|
||||
@ -77,7 +84,6 @@ DEFAULT_ENV_OPTIONS = dict(
|
||||
PIOVARIABLES=commonvars.keys(),
|
||||
ENV=environ,
|
||||
UNIX_TIME=int(time()),
|
||||
PROGNAME="program",
|
||||
PIOHOME_DIR=util.get_home_dir(),
|
||||
PROJECT_DIR=util.get_project_dir(),
|
||||
PROJECTSRC_DIR=util.get_projectsrc_dir(),
|
||||
@ -91,6 +97,8 @@ DEFAULT_ENV_OPTIONS = dict(
|
||||
util.get_projectlib_dir(), util.get_projectlibdeps_dir(),
|
||||
join("$PIOHOME_DIR", "lib")
|
||||
],
|
||||
PROGNAME="program",
|
||||
PROG_PATH=join("$BUILD_DIR", "$PROGNAME$PROGSUFFIX"),
|
||||
PYTHONEXE=util.get_pythonexe_path())
|
||||
|
||||
if not int(ARGUMENTS.get("PIOVERBOSE", 0)):
|
||||
@ -150,6 +158,7 @@ env.SConscriptChdir(0)
|
||||
env.SConsignFile(join("$PROJECTPIOENVS_DIR", ".sconsign.dblite"))
|
||||
env.SConscript("$BUILD_SCRIPT")
|
||||
|
||||
AlwaysBuild(env.Alias("__debug", DEFAULT_TARGETS + ["size"]))
|
||||
AlwaysBuild(env.Alias("__test", DEFAULT_TARGETS + ["size"]))
|
||||
|
||||
if "UPLOAD_FLAGS" in env:
|
||||
|
98
platformio/builder/tools/piodebug.py
Normal file
98
platformio/builder/tools/piodebug.py
Normal file
@ -0,0 +1,98 @@
|
||||
# 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 platformio import util
|
||||
|
||||
|
||||
def ProcessDebug(env):
|
||||
env.Append(
|
||||
BUILD_FLAGS=["-Og", "-ggdb"],
|
||||
BUILD_UNFLAGS=["-Os", "-O0", "-O1", "-O2", "-O3"])
|
||||
|
||||
|
||||
def DebugLinkSettings(env):
|
||||
if "BOARD" not in env:
|
||||
return
|
||||
board_debug = env.BoardConfig().get("debug")
|
||||
if not board_debug or not board_debug.get("links"):
|
||||
return
|
||||
debug_links = board_debug.get("links")
|
||||
link_name = (env.subst("$DEBUG_LINK") or
|
||||
board_debug.get("default_link", debug_links.keys()[0]))
|
||||
settings = debug_links.get(link_name)
|
||||
if not settings:
|
||||
return
|
||||
settings.update({"name": link_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):
|
||||
port = None
|
||||
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 port
|
||||
return port
|
||||
|
||||
if "BOARD" not in env or ("DEBUG_PORT" in env and not _get_pattern()):
|
||||
return
|
||||
|
||||
link_settings = env.DebugLinkSettings()
|
||||
if not link_settings:
|
||||
return
|
||||
if not link_settings.get("require_debug_port"):
|
||||
return
|
||||
env.Replace(
|
||||
DEBUG_PORT=_look_for_serial_port(link_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(DebugLinkSettings)
|
||||
env.AddMethod(AutodetectDebugPort)
|
||||
return env
|
149
platformio/builder/tools/pioide.py
Normal file
149
platformio/builder/tools/pioide.py
Normal file
@ -0,0 +1,149 @@
|
||||
# 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 glob import glob
|
||||
from os.path import join
|
||||
|
||||
from SCons.Defaults import processDefines
|
||||
|
||||
from platformio import util
|
||||
|
||||
|
||||
def dump_includes(env):
|
||||
includes = []
|
||||
|
||||
for item in env.get("CPPPATH", []):
|
||||
includes.append(env.subst(item))
|
||||
|
||||
# installed libs
|
||||
for lb in env.GetLibBuilders():
|
||||
includes.extend(lb.get_inc_dirs())
|
||||
|
||||
# includes from toolchains
|
||||
p = env.PioPlatform()
|
||||
for name in p.get_installed_packages():
|
||||
if p.get_package_type(name) != "toolchain":
|
||||
continue
|
||||
toolchain_dir = util.glob_escape(p.get_package_dir(name))
|
||||
toolchain_incglobs = [
|
||||
join(toolchain_dir, "*", "include*"),
|
||||
join(toolchain_dir, "lib", "gcc", "*", "*", "include*")
|
||||
]
|
||||
for g in toolchain_incglobs:
|
||||
includes.extend(glob(g))
|
||||
|
||||
return includes
|
||||
|
||||
|
||||
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":
|
||||
defines.append(
|
||||
"__AVR_%s__" % env.BoardConfig().get("build.mcu").upper()
|
||||
.replace("ATMEGA", "ATmega").replace("ATTINY", "ATtiny"))
|
||||
return defines
|
||||
|
||||
|
||||
def dump_debug(env):
|
||||
|
||||
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": configuration['executable'],
|
||||
"arguments": 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']]
|
||||
|
||||
link_settings = env.DebugLinkSettings()
|
||||
if link_settings and not gdbinit:
|
||||
gdbinit = link_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"),
|
||||
"link": link_settings['name'] if link_settings else None,
|
||||
"gdbinit": [env.subst(cmd) for cmd in gdbinit] if gdbinit else None,
|
||||
"port": env.subst("$DEBUG_PORT"),
|
||||
"server": (_dump_server(link_settings['server'])
|
||||
if link_settings and "server" in link_settings else None)
|
||||
}
|
||||
|
||||
|
||||
def DumpIDEData(env):
|
||||
LINTCCOM = "$CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS"
|
||||
LINTCXXCOM = "$CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS"
|
||||
|
||||
data = {
|
||||
"libsource_dirs":
|
||||
[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']}")),
|
||||
}
|
||||
|
||||
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
|
@ -17,13 +17,11 @@ from __future__ import absolute_import
|
||||
import atexit
|
||||
import re
|
||||
import sys
|
||||
from glob import glob
|
||||
from os import environ, remove, walk
|
||||
from os.path import basename, isdir, isfile, join, relpath
|
||||
from tempfile import mkstemp
|
||||
|
||||
from SCons.Action import Action
|
||||
from SCons.Defaults import processDefines
|
||||
from SCons.Script import ARGUMENTS
|
||||
|
||||
from platformio import util
|
||||
@ -200,81 +198,6 @@ def _delete_file(path):
|
||||
pass
|
||||
|
||||
|
||||
def DumpIDEData(env):
|
||||
|
||||
def get_includes(env_):
|
||||
includes = []
|
||||
|
||||
for item in env_.get("CPPPATH", []):
|
||||
includes.append(env_.subst(item))
|
||||
|
||||
# installed libs
|
||||
for lb in env.GetLibBuilders():
|
||||
includes.extend(lb.get_inc_dirs())
|
||||
|
||||
# includes from toolchains
|
||||
p = env.PioPlatform()
|
||||
for name in p.get_installed_packages():
|
||||
if p.get_package_type(name) != "toolchain":
|
||||
continue
|
||||
toolchain_dir = util.glob_escape(p.get_package_dir(name))
|
||||
toolchain_incglobs = [
|
||||
join(toolchain_dir, "*", "include*"),
|
||||
join(toolchain_dir, "lib", "gcc", "*", "*", "include*")
|
||||
]
|
||||
for g in toolchain_incglobs:
|
||||
includes.extend(glob(g))
|
||||
|
||||
return includes
|
||||
|
||||
def get_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":
|
||||
defines.append(
|
||||
"__AVR_%s__" % env.BoardConfig().get("build.mcu").upper()
|
||||
.replace("ATMEGA", "ATmega").replace("ATTINY", "ATtiny"))
|
||||
return defines
|
||||
|
||||
LINTCCOM = "$CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS"
|
||||
LINTCXXCOM = "$CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS"
|
||||
env_ = env.Clone()
|
||||
|
||||
data = {
|
||||
"libsource_dirs":
|
||||
[env_.subst(l) for l in env_.get("LIBSOURCE_DIRS", [])],
|
||||
"defines": get_defines(env_),
|
||||
"includes": get_includes(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']}"))
|
||||
}
|
||||
|
||||
# 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 GetCompilerType(env):
|
||||
try:
|
||||
sysenv = environ.copy()
|
||||
@ -352,7 +275,6 @@ def exists(_):
|
||||
|
||||
def generate(env):
|
||||
env.AddMethod(ConvertInoToCpp)
|
||||
env.AddMethod(DumpIDEData)
|
||||
env.AddMethod(GetCompilerType)
|
||||
env.AddMethod(GetActualLDScript)
|
||||
env.AddMethod(VerboseAction)
|
||||
|
@ -45,6 +45,9 @@ def BuildProgram(env):
|
||||
if not case_sensitive_suffixes(".s", ".S"):
|
||||
env.Replace(AS="$CC", ASCOM="$ASPPCOM")
|
||||
|
||||
if "__debug" in COMMAND_LINE_TARGETS:
|
||||
env.ProcessDebug()
|
||||
|
||||
# process extra flags from board
|
||||
if "BOARD" in env and "build.extra_flags" in env.BoardConfig():
|
||||
env.ProcessFlags(env.BoardConfig().get("build.extra_flags"))
|
||||
|
39
platformio/commands/debug.py
Normal file
39
platformio/commands/debug.py
Normal file
@ -0,0 +1,39 @@
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
from os import getcwd
|
||||
|
||||
import click
|
||||
|
||||
from platformio.managers.core import pioplus_call
|
||||
|
||||
|
||||
@click.command("debug", short_help="Project Debugger")
|
||||
@click.option(
|
||||
"-d",
|
||||
"--project-dir",
|
||||
default=getcwd,
|
||||
type=click.Path(
|
||||
exists=True,
|
||||
file_okay=False,
|
||||
dir_okay=True,
|
||||
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)
|
||||
def cli(*args, **kwargs): # pylint: disable=unused-argument
|
||||
pioplus_call(sys.argv[1:])
|
@ -129,7 +129,8 @@ class EnvironmentProcessor(object):
|
||||
"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")
|
||||
"test_ignore", "test_port", "piotest", "debug_link", "debug_port",
|
||||
"debug_gdbinit")
|
||||
|
||||
REMAPED_OPTIONS = {"framework": "pioframework", "platform": "pioplatform"}
|
||||
|
||||
|
@ -22,7 +22,7 @@ from platformio.managers.package import PackageManager
|
||||
|
||||
CORE_PACKAGES = {
|
||||
"pysite-pioplus": ">=0.3.0,<2",
|
||||
"tool-pioplus": ">=0.6.10,<2",
|
||||
"tool-pioplus": ">=0.7.1,<2",
|
||||
"tool-unity": "~1.20302.1",
|
||||
"tool-scons": "~3.20501.2"
|
||||
}
|
||||
|
Reference in New Issue
Block a user