Created
September 24, 2018 12:50
-
-
Save yashi/f3fbf2fc2062486f60211296324c5f2b to your computer and use it in GitHub Desktop.
compiler driver for zephyr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import sys | |
import re | |
import subprocess | |
import argparse | |
import unittest | |
compiler_options = [ | |
('-Os', '-O2', ), # optimize for speed | |
('-g', '-g', ), # enable debug | |
('-E', '--preproc_only', ), | |
('-o', '--output_file', True), | |
('-x', None, True), | |
('-P', ), | |
('-MF', None, True), | |
('-MD', ), | |
('-MT', None, True), | |
('-Wl,--whole-archive', ), | |
('-Wl,--no-whole-archive', ), | |
('-Wl,-Map', None, True), | |
('-T', ), | |
# warnings | |
('-Wall', ), | |
('-Werror=implicit-int', ), | |
('-Wformat', ), | |
('-Wformat-security', ), | |
('-Wno-format-zero-length', ), | |
('-Wno-main', ), | |
('-Wno-pointer-sign', ), | |
('-Wno-unused-but-set-variable', ), | |
# optimizations | |
('-fdata-sections', ), | |
('-ffreestanding', ), | |
('-ffunction-sections', ), | |
('-fno-asynchronous-unwind-tables', ), | |
('-fno-defer-pop', ), | |
('-fno-pic', ), | |
('-fno-pie', ), | |
('-fno-reorder-functions', ), | |
('-fno-strict-overflow', ), | |
('-fno-strict-overview', ), | |
('-imacros', '--preinclude', True), | |
# misc | |
('-mabi=aapcs', ), | |
('-mbig-endian', ), | |
('-std=c99', '--c99', ), | |
('-xassembler-with-cpp', ), | |
] | |
def iterfixed(seq, times, defaultitem=None): | |
for i in range(times): | |
if i < len(seq): | |
yield seq[i] | |
else: | |
yield defaultitem | |
class Translator: | |
class TranslationTemplate: | |
def __init__(self, original, translated=None, has_arg=None): | |
self.original = original | |
self.translated = translated | |
self.has_arg = has_arg | |
def __repr__(self): | |
return "({}, {}, {})".format(self.original, self.translated, self.has_arg) | |
def __init__(self): | |
self.table = {} | |
self.parser = argparse.ArgumentParser(allow_abbrev=False) | |
self.parsed = False | |
def __repr__(self): | |
ret = "<{} at {}".format(type(self).__qualname__, hex(id(self))) | |
if self.parsed: | |
ret += " parsed" | |
if not self.table: | |
ret += " ()" | |
else: | |
ret += "\n" | |
for value in self.table.values(): | |
ret = ret + " " + repr(value) + "\n" | |
ret += ">" | |
return ret | |
def add(self, trans): | |
if type(trans) is not tuple: | |
raise TypeError | |
original, translated, has_arg = iterfixed(trans, 3) | |
temp = self.TranslationTemplate(original, translated, has_arg) | |
self.table[temp.original] = temp | |
if has_arg: | |
self.parser.add_argument(original, help=argparse.SUPPRESS, nargs=1) | |
else: | |
self.parser.add_argument( | |
original, help=argparse.SUPPRESS, action='store_true') | |
def learn(self, trans): | |
for t in trans: | |
self.add(t) | |
def parse(self, argv=None): | |
args, self.unknown = self.parser.parse_known_args(None) | |
self.given = {k: v for k, v in vars(args).items() if v} | |
self.parsed = True | |
def translate(self): | |
def translate_1(_arg): | |
# let's try single hypen first | |
# hypen is converted to underscore in argparse | |
# convert it back | |
arg = "-" + _arg.replace('_', '-') | |
if arg in self.table: | |
opt = self.table[arg].translated | |
if opt and self.table[arg].has_arg: | |
param = self.given[_arg] | |
if param: | |
return [opt] + param | |
else: | |
return opt | |
#return opt.join(param) | |
else: | |
return opt | |
else: | |
print(f"!!!!! oops: {arg} is not in translation table") | |
return arg | |
def flatten(seq): | |
l = [] | |
for x in seq: | |
if isinstance(x, list): | |
for y in x: | |
l.append(y) | |
else: | |
l.append(x) | |
return l | |
if not self.parsed: | |
self.parse(None) | |
return [flatten(filter(None, map(translate_1, self.given))), self.unknown] | |
class MyTest(unittest.TestCase): | |
def test_parse_simple_flag(self): | |
translator = Translator() | |
translator.learn(compiler_options) | |
translator.parse("-Os".split()) | |
self.assertEqual(translator.given, {'Os': True}) | |
def test_parse_equal_and_arg(self): | |
translator = Translator() | |
translator.learn(compiler_options) | |
translator.parse("-Werror=implicit-int".split()) | |
self.assertEqual(translator.given, {'Werror=implicit_int': True}) | |
def test_translate(self): | |
translator = Translator() | |
translator.learn(compiler_options) | |
translator.parse("-Os".split()) | |
argv, _ = translator.translate() | |
self.assertEqual(argv, ["-O2"]) | |
def test_translate_multi(self): | |
translator = Translator() | |
translator.learn(compiler_options) | |
translator.parse("-Os -g".split()) | |
argv, _ = translator.translate() | |
self.assertEqual(argv, ["-O2", "-g"]) | |
def test_translate_hypen(self): | |
translator = Translator() | |
translator.learn(compiler_options) | |
translator.parse("-Werror=implicit-int".split()) | |
argv, _ = translator.translate() | |
self.assertEqual(argv, []) | |
def convert_unknown(args): | |
pat = re.compile(r"-L(.+)") | |
def l_to_search_path(s, pat): | |
if pat.match(s): | |
return s.replace('-L', '--search_path=') | |
else: | |
return s | |
return [l_to_search_path(x, pat) for x in args] | |
def main(): | |
compiler = os.path.join(os.environ['CGT_ROOT_DIR'], "bin/armcl") | |
translator = Translator() | |
translator.learn(compiler_options) | |
argv, unknown = translator.translate() | |
converted_unknown = convert_unknown(unknown) | |
cmd = [compiler] + argv + converted_unknown | |
ret = subprocess.run(cmd) | |
sys.exit(ret.returncode) | |
if __name__ == '__main__': | |
main() | |
else: | |
#suite = unittest.TestLoader().loadTestsFromName('test_translate_with_prog', MyTest) | |
suite = unittest.TestLoader().loadTestsFromTestCase(MyTest) | |
unittest.TextTestRunner(verbosity=3).run(suite) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment