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

Tools: Check compiler version #7247

Merged
merged 9 commits into from Jun 27, 2018
1 change: 1 addition & 0 deletions tools/build_api.py
Expand Up @@ -552,6 +552,7 @@ def build_project(src_paths, build_path, target, toolchain_name,
src_paths, build_path, target, toolchain_name, macros=macros,
clean=clean, jobs=jobs, notify=notify, config=config,
app_config=app_config, build_profile=build_profile, ignore=ignore)
toolchain.version_check()

# The first path will give the name to the library
name = (name or toolchain.config.name or
Expand Down
73 changes: 73 additions & 0 deletions tools/test/toolchains/api_test.py
Expand Up @@ -18,6 +18,79 @@

ALPHABET = [char for char in printable if char not in [u'.', u'/', u'\\']]


@patch('tools.toolchains.arm.run_cmd')
def test_arm_version_check(_run_cmd):
_run_cmd.return_value = ("""
Product: ARM Compiler 5.06
Component: ARM Compiler 5.06 update 5 (build 528)
Tool: armcc [4d3621]
""", "", 0)
notifier = MockNotifier()
toolchain = TOOLCHAIN_CLASSES["ARM"](TARGET_MAP["K64F"], notify=notifier)
toolchain.version_check()
assert notifier.messages == []
_run_cmd.return_value = ("""
Product: ARM Compiler
Component: ARM Compiler
Tool: armcc [4d3621]
""", "", 0)
toolchain.version_check()
assert len(notifier.messages) == 1


@patch('tools.toolchains.iar.run_cmd')
def test_iar_version_check(_run_cmd):
_run_cmd.return_value = ("""
IAR ANSI C/C++ Compiler V7.80.1.28/LNX for ARM
""", "", 0)
notifier = MockNotifier()
toolchain = TOOLCHAIN_CLASSES["IAR"](TARGET_MAP["K64F"], notify=notifier)
toolchain.version_check()
assert notifier.messages == []
_run_cmd.return_value = ("""
IAR ANSI C/C++ Compiler V/LNX for ARM
""", "", 0)
toolchain.version_check()
assert len(notifier.messages) == 1
_run_cmd.return_value = ("""
IAR ANSI C/C++ Compiler V/8.80LNX for ARM
""", "", 0)
toolchain.version_check()
assert len(notifier.messages) == 2


@patch('tools.toolchains.gcc.run_cmd')
def test_gcc_version_check(_run_cmd):
_run_cmd.return_value = ("""
arm-none-eabi-gcc (Arch Repository) 6.4.4
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
""", "", 0)
notifier = MockNotifier()
toolchain = TOOLCHAIN_CLASSES["GCC_ARM"](
TARGET_MAP["K64F"], notify=notifier)
toolchain.version_check()
assert notifier.messages == []
_run_cmd.return_value = ("""
arm-none-eabi-gcc (Arch Repository) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
""", "", 0)
toolchain.version_check()
assert len(notifier.messages) == 1
_run_cmd.return_value = ("""
arm-none-eabi-gcc (Arch Repository)
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
""", "", 0)
toolchain.version_check()
assert len(notifier.messages) == 2


@given(fixed_dictionaries({
'common': lists(text()),
'c': lists(text()),
Expand Down
7 changes: 7 additions & 0 deletions tools/toolchains/__init__.py
Expand Up @@ -1539,6 +1539,13 @@ def redirect_symbol(source, sync, build_dir):
def get_config_macros(self):
return self.config.config_to_macros(self.config_data) if self.config_data else []

@abstractmethod
def version_check(self):
"""Check the version of a compiler being used and raise a
NotSupportedException when it's incorrect.
"""
raise NotImplemented

@property
def report(self):
to_ret = {}
Expand Down
32 changes: 31 additions & 1 deletion tools/toolchains/arm.py
Expand Up @@ -23,10 +23,11 @@
from os import makedirs, write, curdir, remove
from tempfile import mkstemp
from shutil import rmtree
from distutils.version import LooseVersion

from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
from tools.hooks import hook_tool
from tools.utils import mkdir, NotSupportedException
from tools.utils import mkdir, NotSupportedException, run_cmd

class ARM(mbedToolchain):
LINKER_EXT = '.sct'
Expand All @@ -39,6 +40,8 @@ class ARM(mbedToolchain):
SHEBANG = "#! armcc -E"
SUPPORTED_CORES = ["Cortex-M0", "Cortex-M0+", "Cortex-M3", "Cortex-M4",
"Cortex-M4F", "Cortex-M7", "Cortex-M7F", "Cortex-M7FD", "Cortex-A9"]
ARMCC_RANGE = (LooseVersion("5.06"), LooseVersion("5.07"))
ARMCC_VERSION_RE = re.compile("Product: ARM Compiler (\d+\.\d+)")

@staticmethod
def check_executable():
Expand Down Expand Up @@ -91,6 +94,31 @@ def __init__(self, target, notify=None, macros=None,

self.SHEBANG += " --cpu=%s" % cpu

def version_check(self):
stdout, _, retcode = run_cmd([self.cc[0], "--vsn"], redirect=True)
msg = None
min_ver, max_ver = self.ARMCC_RANGE
match = self.ARMCC_VERSION_RE.search(stdout)
found_version = LooseVersion(match.group(1)) if match else None
min_ver, max_ver = self.ARMCC_RANGE
if found_version and (found_version < min_ver or found_version >= max_ver):
msg = ("Compiler version mismatch: Have {}; "
"expected version >= {} and < {}"
.format(found_version, min_ver, max_ver))
elif not match or len(match.groups()) != 1:
msg = ("Compiler version mismatch: Could not detect version; "
"expected version >= {} and < {}"
.format(min_ver, max_ver))

if msg:
self.notify.cc_info({
"message": msg,
"file": "",
"line": "",
"col": "",
"severity": "ERROR",
})

def _get_toolchain_labels(self):
if getattr(self.target, "default_lib", "std") == "small":
return ["ARM", "ARM_MICRO"]
Expand Down Expand Up @@ -324,6 +352,8 @@ class ARMC6(ARM_STD):
"Cortex-M4F", "Cortex-M7", "Cortex-M7F", "Cortex-M7FD",
"Cortex-M23", "Cortex-M23-NS", "Cortex-M33",
"CortexM33-NS", "Cortex-A9"]
ARMCC_RANGE = (LooseVersion("6.10"), LooseVersion("7.0"))

@staticmethod
def check_executable():
return mbedToolchain.generic_check_executable("ARMC6", "armclang", 1)
Expand Down
28 changes: 28 additions & 0 deletions tools/toolchains/gcc.py
Expand Up @@ -17,9 +17,11 @@
import re
from os.path import join, basename, splitext, dirname, exists
from distutils.spawn import find_executable
from distutils.version import LooseVersion

from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
from tools.hooks import hook_tool
from tools.utils import run_cmd, NotSupportedException

class GCC(mbedToolchain):
LINKER_EXT = '.ld'
Expand All @@ -28,6 +30,9 @@ class GCC(mbedToolchain):
STD_LIB_NAME = "lib%s.a"
DIAGNOSTIC_PATTERN = re.compile('((?P<file>[^:]+):(?P<line>\d+):)(?P<col>\d+):? (?P<severity>warning|[eE]rror|fatal error): (?P<message>.+)')

GCC_RANGE = (LooseVersion("6.0.0"), LooseVersion("7.0.0"))
GCC_VERSION_RE = re.compile("\d+\.\d+\.\d+")

def __init__(self, target, notify=None, macros=None, build_profile=None,
build_dir=None):
mbedToolchain.__init__(self, target, notify, macros,
Expand Down Expand Up @@ -107,6 +112,29 @@ def __init__(self, target, notify=None, macros=None, build_profile=None,
self.ar = join(tool_path, "arm-none-eabi-ar")
self.elf2bin = join(tool_path, "arm-none-eabi-objcopy")

def version_check(self):
stdout, _, retcode = run_cmd([self.cc[0], "--version"], redirect=True)
msg = None
match = self.GCC_VERSION_RE.search(stdout)
found_version = LooseVersion(match.group(0)) if match else None
min_ver, max_ver = self.GCC_RANGE
if found_version and (found_version < min_ver or found_version >= max_ver):
msg = ("Compiler version mismatch: Have {}; "
"expected version >= {} and < {}"
.format(found_version, min_ver, max_ver))
elif not match:
msg = ("Compiler version mismatch: Could not detect version; "
"expected version >= {} and < {}"
.format(min_ver, max_ver))
if msg:
self.notify.cc_info({
"message": msg,
"file": "",
"line": "",
"col": "",
"severity": "ERROR",
})

def is_not_supported_error(self, output):
return "error: #error [NOT_SUPPORTED]" in output

Expand Down
25 changes: 25 additions & 0 deletions tools/toolchains/iar.py
Expand Up @@ -17,9 +17,11 @@
import re
from os import remove
from os.path import join, splitext, exists
from distutils.version import LooseVersion

from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
from tools.hooks import hook_tool
from tools.utils import run_cmd, NotSupportedException

class IAR(mbedToolchain):
LIBRARY_EXT = '.a'
Expand All @@ -28,6 +30,8 @@ class IAR(mbedToolchain):

DIAGNOSTIC_PATTERN = re.compile('"(?P<file>[^"]+)",(?P<line>[\d]+)\s+(?P<severity>Warning|Error|Fatal error)(?P<message>.+)')
INDEX_PATTERN = re.compile('(?P<col>\s*)\^')
IAR_VERSION_RE = re.compile("IAR ANSI C/C\+\+ Compiler V(\d+\.\d+)")
IAR_VERSION = LooseVersion("7.80")

@staticmethod
def check_executable():
Expand Down Expand Up @@ -91,6 +95,27 @@ def __init__(self, target, notify=None, macros=None, build_profile=None,
self.ar = join(IAR_BIN, "iarchive")
self.elf2bin = join(IAR_BIN, "ielftool")

def version_check(self):
stdout, _, retcode = run_cmd([self.cc[0], "--version"], redirect=True)
msg = None
match = self.IAR_VERSION_RE.search(stdout)
found_version = match.group(1) if match else None
if found_version and LooseVersion(found_version) != self.IAR_VERSION:
msg = "Compiler version mismatch: Have {}; expected {}".format(
found_version, self.IAR_VERSION)
elif not match or len(match.groups()) != 1:
msg = ("Compiler version mismatch: Could Not detect compiler "
"version; expected {}".format(self.IAR_VERSION))
if msg:
self.notify.cc_info({
"message": msg,
"file": "",
"line": "",
"col": "",
"severity": "ERROR",
})


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