Mercurial > lcfOS
annotate python/zcc.py @ 336:d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
author | Windel Bouwman |
---|---|
date | Wed, 19 Feb 2014 22:32:15 +0100 |
parents | 6f4753202b9a |
children | 86b02c98a717 |
rev | line source |
---|---|
292 | 1 #!/usr/bin/env python |
104 | 2 |
287 | 3 import sys |
331 | 4 import os |
287 | 5 import argparse |
6 import logging | |
331 | 7 import yaml |
287 | 8 |
334 | 9 from ppci.buildtasks import Compile, Assemble, Link |
329 | 10 from ppci.tasks import TaskRunner |
331 | 11 from ppci.report import RstFormatter |
334 | 12 from ppci.objectfile import ObjectFile |
323 | 13 from target.target_list import target_list |
331 | 14 import ppci |
281 | 15 |
289 | 16 |
253 | 17 def logLevel(s): |
312 | 18 """ Converts a string to a valid logging level """ |
253 | 19 numeric_level = getattr(logging, s.upper(), None) |
20 if not isinstance(numeric_level, int): | |
21 raise ValueError('Invalid log level: {}'.format(s)) | |
22 return numeric_level | |
105 | 23 |
289 | 24 |
323 | 25 targets = {t.name: t for t in target_list} |
292 | 26 targetnames = list(targets.keys()) |
290 | 27 |
331 | 28 def make_parser(): |
29 parser = argparse.ArgumentParser(description='lcfos Compiler') | |
30 | |
31 parser.add_argument('--log', help='Log level (INFO,DEBUG,[WARN])', | |
334 | 32 type=logLevel, default='INFO') |
332 | 33 parser.add_argument('--display-build-steps', action='store_true') |
331 | 34 sub_parsers = parser.add_subparsers(title='commands', |
35 description='possible commands', dest='command') | |
36 recipe_parser = sub_parsers.add_parser('recipe', help="Bake recipe") | |
37 recipe_parser.add_argument('recipe_file', help='recipe file') | |
38 | |
39 compile_parser = sub_parsers.add_parser('compile', help="compile source") | |
40 compile_parser.add_argument('source', type=argparse.FileType('r'), | |
41 help='the source file to build', nargs="+") | |
42 compile_parser.add_argument('-i', '--imp', type=argparse.FileType('r'), | |
43 help='Possible import module', action='append', default=[]) | |
44 compile_parser.add_argument('--target', help="Backend selection", | |
45 choices=targetnames, required=True) | |
46 compile_parser.add_argument('-o', '--output', help='Output file', | |
47 metavar='filename') | |
48 compile_parser.add_argument('--report', | |
49 help='Specify a file to write the compile report to', | |
50 type=argparse.FileType('w')) | |
51 return parser | |
52 | |
287 | 53 |
331 | 54 class RecipeLoader: |
334 | 55 """ Loads a recipe into a runner from a dictionary or file """ |
56 def __init__(self): | |
57 self.directive_handlers = {} | |
58 for a in dir(self): | |
59 if a.startswith('handle_'): | |
60 f = getattr(self, a) | |
61 self.directive_handlers[a[7:]] = f | |
62 | |
331 | 63 def load_file(self, recipe_file, runner): |
64 """ Loads a recipe dictionary into a task runner """ | |
65 self.recipe_dir = os.path.abspath(os.path.dirname(recipe_file)) | |
66 with open(recipe_file, 'r') as f: | |
67 recipe = yaml.load(f) | |
334 | 68 self.runner = runner |
69 self.load_dict(recipe) | |
331 | 70 |
71 def relpath(self, filename): | |
72 return os.path.join(self.recipe_dir, filename) | |
73 | |
74 def openfile(self, filename): | |
75 return open(self.relpath(filename), 'r') | |
76 | |
334 | 77 def handle_compile(self, value): |
78 sources = [self.openfile(s) for s in value['sources']] | |
79 includes = [self.openfile(i) for i in value['includes']] | |
80 target = targets[value['machine']] | |
81 output = ObjectFile() | |
82 task = Compile(sources, includes, target, output) | |
83 self.runner.add_task(task) | |
84 return task | |
85 | |
86 def handle_assemble(self, value): | |
87 asm_src = self.openfile(value['source']) | |
88 target = targets[value['machine']] | |
89 output = ObjectFile() | |
90 task = Assemble(asm_src, target, output) | |
91 self.runner.add_task(task) | |
92 return task | |
93 | |
94 def handle_link(self, value): | |
95 inputs = value['inputs'] | |
96 objs = [] | |
97 for i in inputs: | |
98 task = self.load_dict(i) | |
99 objs.append(task.output) | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
334
diff
changeset
|
100 layout = value['layout'] |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
334
diff
changeset
|
101 output = self.relpath(value['output']) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
334
diff
changeset
|
102 self.runner.add_task(Link(objs, layout, output)) |
334 | 103 |
104 def handle_apps(self, value): | |
105 for a in value: | |
106 self.load_dict(a) | |
107 | |
108 def load_dict(self, recipe): | |
331 | 109 for command, value in recipe.items(): |
334 | 110 return self.directive_handlers[command](value) |
104 | 111 |
288 | 112 |
249 | 113 def main(args): |
315 | 114 # Configure some logging: |
115 logging.getLogger().setLevel(logging.DEBUG) | |
116 ch = logging.StreamHandler() | |
331 | 117 ch.setFormatter(logging.Formatter(ppci.logformat)) |
315 | 118 ch.setLevel(args.log) |
119 logging.getLogger().addHandler(ch) | |
329 | 120 |
331 | 121 runner = TaskRunner() |
122 if args.command == 'compile': | |
123 tg = targets[args.target] | |
334 | 124 output = ObjectFile() |
125 runner.add_task(Compile(args.source, args.imp, tg, output)) | |
331 | 126 elif args.command == 'recipe': |
127 recipe_loader = RecipeLoader() | |
128 recipe_loader.load_file(args.recipe_file, runner) | |
129 else: | |
130 raise NotImplementedError('Invalid option') | |
105 | 131 |
332 | 132 if args.display_build_steps: |
133 runner.display() | |
134 res = 0 | |
135 else: | |
136 res = runner.run_tasks() | |
104 | 137 |
315 | 138 logging.getLogger().removeHandler(ch) |
331 | 139 return res |
246 | 140 |
288 | 141 |
207 | 142 if __name__ == '__main__': |
331 | 143 parser = make_parser() |
213 | 144 arguments = parser.parse_args() |
331 | 145 if not arguments.command: |
146 parser.print_usage() | |
147 sys.exit(1) | |
276 | 148 sys.exit(main(arguments)) |