Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise checking toolchain path #2675

Merged
merged 4 commits into from
Sep 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion tools/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
sys.path.insert(0, ROOT)


from tools.toolchains import TOOLCHAINS
from tools.toolchains import TOOLCHAINS, TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS
from tools.toolchains import mbedToolchain
from tools.targets import TARGET_NAMES, TARGET_MAP
from tools.options import get_default_options_parser
Expand Down Expand Up @@ -161,6 +161,7 @@
print mcu_toolchain_matrix(platform_filter=options.general_filter_regex)
exit(0)


# Get target list
targets = options.mcu if options.mcu else TARGET_NAMES

Expand Down Expand Up @@ -212,6 +213,11 @@
# CPPCHECK code validation
if options.cppcheck_validation:
for toolchain in toolchains:
if not TOOLCHAIN_CLASSES[toolchain].check_executable():
search_path = TOOLCHAIN_PATHS[toolchain] or "No path set"
args_error(parser, "Could not find executable for %s.\n"
"Currently set search path: %s"
% (toolchain, search_path))
for target in targets:
try:
mcu = TARGET_MAP[target]
Expand Down
11 changes: 8 additions & 3 deletions tools/make.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import sys
from time import sleep
from shutil import copy
from os.path import join, abspath, dirname, isfile, isdir
from os.path import join, abspath, dirname

# Be sure that the tools directory is in the search path
ROOT = abspath(join(dirname(__file__), ".."))
Expand All @@ -46,8 +46,7 @@
from utils import argparse_filestring_type
from utils import argparse_many
from utils import argparse_dir_not_parent
from argparse import ArgumentTypeError
from tools.toolchains import mbedToolchain
from tools.toolchains import mbedToolchain, TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS
from tools.settings import CLI_COLOR_MAP

if __name__ == '__main__':
Expand Down Expand Up @@ -232,6 +231,12 @@
else:
notify = None

if not TOOLCHAIN_CLASSES[toolchain].check_executable():
search_path = TOOLCHAIN_PATHS[toolchain] or "No path set"
args_error(parser, "Could not find executable for %s.\n"
"Currently set search path: %s"
%(toolchain,search_path))

# Test
for test_no in p:
test = Test(test_no)
Expand Down
9 changes: 8 additions & 1 deletion tools/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from tools.test_exporters import ReportExporter, ResultExporterType
from utils import argparse_filestring_type, argparse_lowercase_type, argparse_many
from utils import argparse_dir_not_parent
from tools.toolchains import mbedToolchain
from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS, TOOLCHAIN_CLASSES
from tools.settings import CLI_COLOR_MAP

if __name__ == '__main__':
Expand Down Expand Up @@ -115,6 +115,12 @@
args_error(parser, "argument -t/--tool is required")
toolchain = options.tool[0]

if not TOOLCHAIN_CLASSES[toolchain].check_executable():
search_path = TOOLCHAIN_PATHS[toolchain] or "No path set"
args_error(parser, "Could not find executable for %s.\n"
"Currently set search path: %s"
% (toolchain, search_path))

# Find all tests in the relevant paths
for path in all_paths:
all_tests.update(find_tests(path, mcu, toolchain, options.options,
Expand Down Expand Up @@ -196,6 +202,7 @@
print "Failed to build library"
else:
# Build all the tests

test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, mcu, toolchain,
options=options.options,
clean=options.clean,
Expand Down
66 changes: 46 additions & 20 deletions tools/toolchains/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from copy import deepcopy
from tools.config import Config
from abc import ABCMeta, abstractmethod
from distutils.spawn import find_executable

from multiprocessing import Pool, cpu_count
from tools.utils import run_cmd, mkdir, rel_path, ToolException, NotSupportedException, split_path, compile_worker
Expand Down Expand Up @@ -188,23 +189,6 @@ def __str__(self):
}


def check_toolchain_path(function):
"""Check if the path to toolchain is valid. Exit if not.
Use this function as a decorator. Causes a system exit if the path does
not exist. Execute the function as normal if the path does exist.

Positional arguments:
function -- the function to decorate
"""
def perform_check(self, *args, **kwargs):
if not exists(self.toolchain_path) and not exists(self.toolchain_path+'.exe'):
error_string = 'Could not find executable for %s.\n Currently ' \
'set search path: %s'% (self.name, self.toolchain_path)
raise Exception(error_string)
return function(self, *args, **kwargs)
return perform_check


class mbedToolchain:
# Verbose logging
VERBOSE = True
Expand Down Expand Up @@ -720,7 +704,6 @@ def get_arch_file(self, objects):

# THIS METHOD IS BEING CALLED BY THE MBED ONLINE BUILD SYSTEM
# ANY CHANGE OF PARAMETERS OR RETURN VALUES WILL BREAK COMPATIBILITY
@check_toolchain_path
def compile_sources(self, resources, build_path, inc_dirs=None):
# Web IDE progress bar for project build
files_to_compile = resources.s_sources + resources.c_sources + resources.cpp_sources
Expand Down Expand Up @@ -919,7 +902,6 @@ def compile_output(self, output=[]):
else:
raise ToolException(_stderr)

@check_toolchain_path
def build_library(self, objects, dir, name):
needed_update = False
lib = self.STD_LIB_NAME % name
Expand All @@ -931,7 +913,6 @@ def build_library(self, objects, dir, name):

return needed_update

@check_toolchain_path
def link_program(self, r, tmp_path, name):
needed_update = False
ext = 'bin'
Expand Down Expand Up @@ -1111,6 +1092,51 @@ def get_config_header(self):
self.config_processed = True
return self.config_file

@staticmethod
def generic_check_executable(tool_key, executable_name, levels_up,
nested_dir=None):
"""
Positional args:
tool_key: the key to index TOOLCHAIN_PATHS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are only indexing, should we just pass the list of paths itself?

Copy link
Contributor Author

@sarahmarshy sarahmarshy Sep 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guess it is an argument for clarity/readability. I feel like it looks better this way from each respective toolchain point of view, and this function shows where that path comes from. Just passing in **["ARM", "armcc", 2, "bin"] looks better to me than **[TOOLCHAIN_PATHS["ARM"], "armcc", 2, "bin"] (Though I will admit that neither look great, but I am open to suggestions).

Copy link
Contributor Author

@sarahmarshy sarahmarshy Sep 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it is better to have the key, because this line:

TOOLCHAIN_PATHS[tool_key] = exe

changes the value

executable_name: the toolchain's named executable (ex. armcc)
levels_up: each toolchain joins the toolchain_path, some
variable directories (bin, include), and the executable name,
so the TOOLCHAIN_PATH value must be appropriately distanced

Keyword args:
nested_dir: the directory within TOOLCHAIN_PATHS where the executable
is found (ex: 'bin' for ARM\bin\armcc (necessary to check for path
that will be used by toolchain's compile)

Returns True if the executable location specified by the user
exists and is valid OR the executable can be found on the PATH.
Returns False otherwise.
"""
# Search PATH if user did not specify a path or specified path doesn't
# exist.
if not TOOLCHAIN_PATHS[tool_key] or not exists(TOOLCHAIN_PATHS[tool_key]):
exe = find_executable(executable_name)
if not exe:
return False
for level in range(levels_up):
# move up the specified number of directories
exe = dirname(exe)
TOOLCHAIN_PATHS[tool_key] = exe
if nested_dir:
subdir = join(TOOLCHAIN_PATHS[tool_key], nested_dir,
executable_name)
else:
subdir = join(TOOLCHAIN_PATHS[tool_key],executable_name)
# User could have specified a path that exists but does not contain exe
return exists(subdir) or exists(subdir +'.exe')

@abstractmethod
def check_executable(self):
"""Returns True if the executable (armcc) location specified by the
user exists OR the executable can be found on the PATH.
Returns False otherwise."""
raise NotImplemented

@abstractmethod
def get_config_option(self, config_header):
"""Generate the compiler option that forces the inclusion of the configuration
Expand Down
15 changes: 7 additions & 8 deletions tools/toolchains/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"""
import re
from os.path import join, dirname, splitext, basename
from distutils.spawn import find_executable

from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
from tools.hooks import hook_tool
Expand All @@ -42,6 +41,13 @@ class ARM(mbedToolchain):
'ld': [],
}

@staticmethod
def check_executable():
"""Returns True if the executable (armcc) location specified by the
user exists OR the executable can be found on the PATH.
Returns False otherwise."""
return mbedToolchain.generic_check_executable("ARM", 'armcc', 2, 'bin')

def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False):
mbedToolchain.__init__(self, target, options, notify, macros, silent, extra_verbose=extra_verbose)

Expand All @@ -56,11 +62,6 @@ def __init__(self, target, options=None, notify=None, macros=None, silent=False,
else:
cpu = target.core

if not TOOLCHAIN_PATHS['ARM']:
exe = find_executable('armcc')
if exe:
TOOLCHAIN_PATHS['ARM'] = dirname(dirname(exe))

ARM_BIN = join(TOOLCHAIN_PATHS['ARM'], "bin")
ARM_INC = join(TOOLCHAIN_PATHS['ARM'], "include")

Expand All @@ -86,8 +87,6 @@ def __init__(self, target, options=None, notify=None, macros=None, silent=False,
self.ar = join(ARM_BIN, "armar")
self.elf2bin = join(ARM_BIN, "fromelf")

self.toolchain_path = TOOLCHAIN_PATHS['ARM']

def parse_dependencies(self, dep_path):
dependencies = []
for line in open(dep_path).readlines():
Expand Down
22 changes: 15 additions & 7 deletions tools/toolchains/gcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
limitations under the License.
"""
import re
from os.path import join, basename, splitext, dirname, exists
from distutils.spawn import find_executable
from os.path import join, basename, splitext

from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
from tools.hooks import hook_tool
Expand Down Expand Up @@ -111,11 +110,6 @@ def __init__(self, target, options=None, notify=None, macros=None, silent=False,
self.ar = join(tool_path, "arm-none-eabi-ar")
self.elf2bin = join(tool_path, "arm-none-eabi-objcopy")

if tool_path:
self.toolchain_path = main_cc
else:
self.toolchain_path = find_executable("arm-none-eabi-gcc") or ''

def parse_dependencies(self, dep_path):
dependencies = []
buff = open(dep_path).readlines()
Expand Down Expand Up @@ -275,6 +269,13 @@ def binary(self, resources, elf, bin):


class GCC_ARM(GCC):
@staticmethod
def check_executable():
"""Returns True if the executable (arm-none-eabi-gcc) location
specified by the user exists OR the executable can be found on the PATH.
Returns False otherwise."""
return mbedToolchain.generic_check_executable("GCC_ARM", 'arm-none-eabi-gcc', 1)

def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False):
GCC.__init__(self, target, options, notify, macros, silent, TOOLCHAIN_PATHS['GCC_ARM'], extra_verbose=extra_verbose)

Expand All @@ -300,6 +301,13 @@ def __init__(self, target, options=None, notify=None, macros=None, silent=False,


class GCC_CR(GCC):
@staticmethod
def check_executable():
"""Returns True if the executable (arm-none-eabi-gcc) location
specified by the user exists OR the executable can be found on the PATH.
Returns False otherwise."""
return mbedToolchain.generic_check_executable("GCC_CR", 'arm-none-eabi-gcc', 1)

def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False):
GCC.__init__(self, target, options, notify, macros, silent, TOOLCHAIN_PATHS['GCC_CR'], extra_verbose=extra_verbose)

Expand Down
17 changes: 8 additions & 9 deletions tools/toolchains/iar.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
"""
import re
from os import remove
from os.path import join, exists, dirname, splitext, exists
from distutils.spawn import find_executable
from os.path import join, splitext

from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
from tools.hooks import hook_tool
Expand Down Expand Up @@ -45,18 +44,20 @@ class IAR(mbedToolchain):
'ld': ["--skip_dynamic_initialization", "--threaded_lib"],
}

@staticmethod
def check_executable():
"""Returns True if the executable (arm-none-eabi-gcc) location
specified by the user exists OR the executable can be found on the PATH.
Returns False otherwise."""
return mbedToolchain.generic_check_executable("IAR", 'iccarm', 2, "bin")

def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False):
mbedToolchain.__init__(self, target, options, notify, macros, silent, extra_verbose=extra_verbose)
if target.core == "Cortex-M7F" or target.core == "Cortex-M7FD":
cpuchoice = "Cortex-M7"
else:
cpuchoice = target.core

if not TOOLCHAIN_PATHS['IAR']:
exe = find_executable('iccarm')
if exe:
TOOLCHAIN_PATHS['IAR'] = dirname(dirname(exe))

# flags_cmd are used only by our scripts, the project files have them already defined,
# using this flags results in the errors (duplication)
# asm accepts --cpu Core or --fpu FPU, not like c/c++ --cpu=Core
Expand Down Expand Up @@ -108,8 +109,6 @@ def __init__(self, target, options=None, notify=None, macros=None, silent=False,
self.ar = join(IAR_BIN, "iarchive")
self.elf2bin = join(IAR_BIN, "ielftool")

self.toolchain_path = TOOLCHAIN_PATHS['IAR']

def parse_dependencies(self, dep_path):
return [(self.CHROOT if self.CHROOT else '')+path.strip() for path in open(dep_path).readlines()
if (path and not path.isspace())]
Expand Down