diff --git a/docs b/docs index 00f8cfe7..ecd4a795 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 00f8cfe790bd9b7a7649acf45376f6f6df646a4b +Subproject commit ecd4a795a4c72842d12711615b3ac6c1803dad01 diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 3b9bf46d..aa8428ed 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -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: diff --git a/platformio/builder/tools/piodebug.py b/platformio/builder/tools/piodebug.py new file mode 100644 index 00000000..78ef4862 --- /dev/null +++ b/platformio/builder/tools/piodebug.py @@ -0,0 +1,98 @@ +# Copyright 2014-present PlatformIO +# +# 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 diff --git a/platformio/builder/tools/pioide.py b/platformio/builder/tools/pioide.py new file mode 100644 index 00000000..95c7b974 --- /dev/null +++ b/platformio/builder/tools/pioide.py @@ -0,0 +1,149 @@ +# Copyright 2014-present PlatformIO +# +# 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 diff --git a/platformio/builder/tools/piomisc.py b/platformio/builder/tools/piomisc.py index 2aa259e3..6dc3296a 100644 --- a/platformio/builder/tools/piomisc.py +++ b/platformio/builder/tools/piomisc.py @@ -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) diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index e23d78d0..fe67fb65 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -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")) diff --git a/platformio/commands/debug.py b/platformio/commands/debug.py new file mode 100644 index 00000000..24acae6c --- /dev/null +++ b/platformio/commands/debug.py @@ -0,0 +1,39 @@ +# Copyright 2014-present PlatformIO +# +# 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="") +@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:]) diff --git a/platformio/commands/run.py b/platformio/commands/run.py index 9818dd95..bd8a77e7 100644 --- a/platformio/commands/run.py +++ b/platformio/commands/run.py @@ -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"} diff --git a/platformio/managers/core.py b/platformio/managers/core.py index c711fcc6..7f838a7f 100644 --- a/platformio/managers/core.py +++ b/platformio/managers/core.py @@ -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" }