Skip to content

Commit dec4392

Browse files
author
Cruz Monrreal
authored
Merge pull request #7247 from theotherjimmy/toolchain-version-check
Tools: Check compiler version
2 parents 65abff9 + c273de6 commit dec4392

File tree

6 files changed

+165
-1
lines changed

6 files changed

+165
-1
lines changed

tools/build_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@ def build_project(src_paths, build_path, target, toolchain_name,
552552
src_paths, build_path, target, toolchain_name, macros=macros,
553553
clean=clean, jobs=jobs, notify=notify, config=config,
554554
app_config=app_config, build_profile=build_profile, ignore=ignore)
555+
toolchain.version_check()
555556

556557
# The first path will give the name to the library
557558
name = (name or toolchain.config.name or

tools/test/toolchains/api_test.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,79 @@
1818

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

21+
22+
@patch('tools.toolchains.arm.run_cmd')
23+
def test_arm_version_check(_run_cmd):
24+
_run_cmd.return_value = ("""
25+
Product: ARM Compiler 5.06
26+
Component: ARM Compiler 5.06 update 5 (build 528)
27+
Tool: armcc [4d3621]
28+
""", "", 0)
29+
notifier = MockNotifier()
30+
toolchain = TOOLCHAIN_CLASSES["ARM"](TARGET_MAP["K64F"], notify=notifier)
31+
toolchain.version_check()
32+
assert notifier.messages == []
33+
_run_cmd.return_value = ("""
34+
Product: ARM Compiler
35+
Component: ARM Compiler
36+
Tool: armcc [4d3621]
37+
""", "", 0)
38+
toolchain.version_check()
39+
assert len(notifier.messages) == 1
40+
41+
42+
@patch('tools.toolchains.iar.run_cmd')
43+
def test_iar_version_check(_run_cmd):
44+
_run_cmd.return_value = ("""
45+
IAR ANSI C/C++ Compiler V7.80.1.28/LNX for ARM
46+
""", "", 0)
47+
notifier = MockNotifier()
48+
toolchain = TOOLCHAIN_CLASSES["IAR"](TARGET_MAP["K64F"], notify=notifier)
49+
toolchain.version_check()
50+
assert notifier.messages == []
51+
_run_cmd.return_value = ("""
52+
IAR ANSI C/C++ Compiler V/LNX for ARM
53+
""", "", 0)
54+
toolchain.version_check()
55+
assert len(notifier.messages) == 1
56+
_run_cmd.return_value = ("""
57+
IAR ANSI C/C++ Compiler V/8.80LNX for ARM
58+
""", "", 0)
59+
toolchain.version_check()
60+
assert len(notifier.messages) == 2
61+
62+
63+
@patch('tools.toolchains.gcc.run_cmd')
64+
def test_gcc_version_check(_run_cmd):
65+
_run_cmd.return_value = ("""
66+
arm-none-eabi-gcc (Arch Repository) 6.4.4
67+
Copyright (C) 2018 Free Software Foundation, Inc.
68+
This is free software; see the source for copying conditions. There is NO
69+
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
70+
""", "", 0)
71+
notifier = MockNotifier()
72+
toolchain = TOOLCHAIN_CLASSES["GCC_ARM"](
73+
TARGET_MAP["K64F"], notify=notifier)
74+
toolchain.version_check()
75+
assert notifier.messages == []
76+
_run_cmd.return_value = ("""
77+
arm-none-eabi-gcc (Arch Repository) 8.1.0
78+
Copyright (C) 2018 Free Software Foundation, Inc.
79+
This is free software; see the source for copying conditions. There is NO
80+
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
81+
""", "", 0)
82+
toolchain.version_check()
83+
assert len(notifier.messages) == 1
84+
_run_cmd.return_value = ("""
85+
arm-none-eabi-gcc (Arch Repository)
86+
Copyright (C) 2018 Free Software Foundation, Inc.
87+
This is free software; see the source for copying conditions. There is NO
88+
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
89+
""", "", 0)
90+
toolchain.version_check()
91+
assert len(notifier.messages) == 2
92+
93+
2194
@given(fixed_dictionaries({
2295
'common': lists(text()),
2396
'c': lists(text()),

tools/toolchains/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,13 @@ def redirect_symbol(source, sync, build_dir):
15671567
def get_config_macros(self):
15681568
return self.config.config_to_macros(self.config_data) if self.config_data else []
15691569

1570+
@abstractmethod
1571+
def version_check(self):
1572+
"""Check the version of a compiler being used and raise a
1573+
NotSupportedException when it's incorrect.
1574+
"""
1575+
raise NotImplemented
1576+
15701577
@property
15711578
def report(self):
15721579
to_ret = {}

tools/toolchains/arm.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@
2323
from os import makedirs, write, curdir, remove
2424
from tempfile import mkstemp
2525
from shutil import rmtree
26+
from distutils.version import LooseVersion
2627

2728
from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
2829
from tools.hooks import hook_tool
29-
from tools.utils import mkdir, NotSupportedException
30+
from tools.utils import mkdir, NotSupportedException, run_cmd
3031

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

4346
@staticmethod
4447
def check_executable():
@@ -91,6 +94,31 @@ def __init__(self, target, notify=None, macros=None,
9194

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

97+
def version_check(self):
98+
stdout, _, retcode = run_cmd([self.cc[0], "--vsn"], redirect=True)
99+
msg = None
100+
min_ver, max_ver = self.ARMCC_RANGE
101+
match = self.ARMCC_VERSION_RE.search(stdout)
102+
found_version = LooseVersion(match.group(1)) if match else None
103+
min_ver, max_ver = self.ARMCC_RANGE
104+
if found_version and (found_version < min_ver or found_version >= max_ver):
105+
msg = ("Compiler version mismatch: Have {}; "
106+
"expected version >= {} and < {}"
107+
.format(found_version, min_ver, max_ver))
108+
elif not match or len(match.groups()) != 1:
109+
msg = ("Compiler version mismatch: Could not detect version; "
110+
"expected version >= {} and < {}"
111+
.format(min_ver, max_ver))
112+
113+
if msg:
114+
self.notify.cc_info({
115+
"message": msg,
116+
"file": "",
117+
"line": "",
118+
"col": "",
119+
"severity": "ERROR",
120+
})
121+
94122
def _get_toolchain_labels(self):
95123
if getattr(self.target, "default_lib", "std") == "small":
96124
return ["ARM", "ARM_MICRO"]
@@ -324,6 +352,8 @@ class ARMC6(ARM_STD):
324352
"Cortex-M4F", "Cortex-M7", "Cortex-M7F", "Cortex-M7FD",
325353
"Cortex-M23", "Cortex-M23-NS", "Cortex-M33",
326354
"CortexM33-NS", "Cortex-A9"]
355+
ARMCC_RANGE = (LooseVersion("6.10"), LooseVersion("7.0"))
356+
327357
@staticmethod
328358
def check_executable():
329359
return mbedToolchain.generic_check_executable("ARMC6", "armclang", 1)

tools/toolchains/gcc.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
import re
1818
from os.path import join, basename, splitext, dirname, exists
1919
from distutils.spawn import find_executable
20+
from distutils.version import LooseVersion
2021

2122
from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
2223
from tools.hooks import hook_tool
24+
from tools.utils import run_cmd, NotSupportedException
2325

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

33+
GCC_RANGE = (LooseVersion("6.0.0"), LooseVersion("7.0.0"))
34+
GCC_VERSION_RE = re.compile("\d+\.\d+\.\d+")
35+
3136
def __init__(self, target, notify=None, macros=None, build_profile=None,
3237
build_dir=None):
3338
mbedToolchain.__init__(self, target, notify, macros,
@@ -107,6 +112,29 @@ def __init__(self, target, notify=None, macros=None, build_profile=None,
107112
self.ar = join(tool_path, "arm-none-eabi-ar")
108113
self.elf2bin = join(tool_path, "arm-none-eabi-objcopy")
109114

115+
def version_check(self):
116+
stdout, _, retcode = run_cmd([self.cc[0], "--version"], redirect=True)
117+
msg = None
118+
match = self.GCC_VERSION_RE.search(stdout)
119+
found_version = LooseVersion(match.group(0)) if match else None
120+
min_ver, max_ver = self.GCC_RANGE
121+
if found_version and (found_version < min_ver or found_version >= max_ver):
122+
msg = ("Compiler version mismatch: Have {}; "
123+
"expected version >= {} and < {}"
124+
.format(found_version, min_ver, max_ver))
125+
elif not match:
126+
msg = ("Compiler version mismatch: Could not detect version; "
127+
"expected version >= {} and < {}"
128+
.format(min_ver, max_ver))
129+
if msg:
130+
self.notify.cc_info({
131+
"message": msg,
132+
"file": "",
133+
"line": "",
134+
"col": "",
135+
"severity": "ERROR",
136+
})
137+
110138
def is_not_supported_error(self, output):
111139
return "error: #error [NOT_SUPPORTED]" in output
112140

tools/toolchains/iar.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
import re
1818
from os import remove
1919
from os.path import join, splitext, exists
20+
from distutils.version import LooseVersion
2021

2122
from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
2223
from tools.hooks import hook_tool
24+
from tools.utils import run_cmd, NotSupportedException
2325

2426
class IAR(mbedToolchain):
2527
LIBRARY_EXT = '.a'
@@ -28,6 +30,8 @@ class IAR(mbedToolchain):
2830

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

3236
@staticmethod
3337
def check_executable():
@@ -91,6 +95,27 @@ def __init__(self, target, notify=None, macros=None, build_profile=None,
9195
self.ar = join(IAR_BIN, "iarchive")
9296
self.elf2bin = join(IAR_BIN, "ielftool")
9397

98+
def version_check(self):
99+
stdout, _, retcode = run_cmd([self.cc[0], "--version"], redirect=True)
100+
msg = None
101+
match = self.IAR_VERSION_RE.search(stdout)
102+
found_version = match.group(1) if match else None
103+
if found_version and LooseVersion(found_version) != self.IAR_VERSION:
104+
msg = "Compiler version mismatch: Have {}; expected {}".format(
105+
found_version, self.IAR_VERSION)
106+
elif not match or len(match.groups()) != 1:
107+
msg = ("Compiler version mismatch: Could Not detect compiler "
108+
"version; expected {}".format(self.IAR_VERSION))
109+
if msg:
110+
self.notify.cc_info({
111+
"message": msg,
112+
"file": "",
113+
"line": "",
114+
"col": "",
115+
"severity": "ERROR",
116+
})
117+
118+
94119
def parse_dependencies(self, dep_path):
95120
return [(self.CHROOT if self.CHROOT else '')+path.strip() for path in open(dep_path).readlines()
96121
if (path and not path.isspace())]

0 commit comments

Comments
 (0)