-
Notifications
You must be signed in to change notification settings - Fork 0
/
TTScons.py
153 lines (130 loc) · 6.21 KB
/
TTScons.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import os, os.path, re, time
from pprint import pformat
from SCons.Environment import Environment
def _readConfFile():
confFile = file(os.path.join(os.environ['HOME'], '.ttscons'))
if not confFile: return {}
# Ultra-crude parser !
return dict((line.rstrip().split('=', 1) for line in confFile if not line.startswith('#')))
_conf = _readConfFile()
_arduinoDir = os.environ.get('ARDUINO_DIR') or _conf.get('ARDUINO_DIR')
if not _arduinoDir:
raise Exception('Please set ARDUINO_DIR with your arduino environment path, either as an environment variable or in your $HOME/.ttscons file')
def _parseBoardsTxt(variant='teensy31'):
variantDotLen = len(variant) + 1
return dict((_.rstrip()[variantDotLen:].split('=', 1)
for _ in file(os.path.join(_arduinoDir, 'hardware/teensy/avr/boards.txt'))
if _.startswith(variant)))
_extractRe = re.compile(r'{([^}]*)}')
_purifyRe = re.compile(r' (-o|-c|"{source_file}"|"{object_file}"|{object_files})( |$)')
#_linkNotMapped = frozenset('"{build.path}/{archive_file}" "-L{build.path}" {build.flags.libs} {object_files}'.split())
class _PlatformTxtParser:
def __init__(self, boardsTxt, options, target):
self.d = d = boardsTxt.copy()
d['runtime.ide.path'] = _arduinoDir
d['includes'] = '' # Not using the rules here, scons will take care of it
d['build.path'] = '.' # Still in dev
d['archive_file'] = 'build/lib/libcore.a'
d['extra.time.local'] = '%d' % time.time()
d['build.core.path'] = os.path.join(_arduinoDir, 'hardware/teensy/avr/cores/teensy3')
d['build.project_name'] = target
d['build.elfpatch'] = 'BUILD.ELFPATCH'
d['sketch_path'] = 'SKETCH_PATH'
d['cmd.path'] = 'CMD.PATH'
d['object_files'] = '$SOURCE'
# highly inefficient (o^2), but hell
for k, v in options.iteritems():
selector = 'menu.%s.%s.' % (k, v)
selectorLen = len(selector)
for key in boardsTxt:
if not key.startswith(selector): continue
d[key[selectorLen:]] = boardsTxt[key]
#
# The following methods take a line from platform.txt
# _post_<rulename> is called after rulename is parsed
# parse(self, rule) is the default method, basically, it performs
# the variable substitution inside the rule
# _parse_<rulename> can be used to override the default method.
def parse(self, rule, purify=True):
if purify:
while True:
# remove what is handled through scons construction variables
newRule = _purifyRe.sub(' ', rule)
if newRule == rule: break
rule = newRule
while True:
m = _extractRe.search(rule)
if not m: return rule
rule = '%s%s%s' % (
rule[:m.start(0)],
self.d[rule[m.start(1):m.end(1)]],
rule[m.end(0):])
def full_parse(self, rule): return self.parse(rule, False)
_parse_recipe_c_combine_pattern = full_parse
def _post_version(self):
self.d['runtime.ide.version'] = self.d['version'].replace('.', '0') # Don't ask
# def _parse_recipe_c_combine_pattern(self, line):
# return self.parse(' '.join((_ for _ in line.split() if not _ in _linkNotMapped)), False)
def _parsePlatformTxt(boardsTxt, options, target):
parser = _PlatformTxtParser(boardsTxt, options, target)
for line in file(os.path.join(_arduinoDir, 'hardware/teensy/avr/platform.txt')):
line = line.split('#')[0].rstrip()
if not line: continue
k, line = line.split('=', 1)
kk = k.replace('.', '_')
v = getattr(parser, '_parse_' + kk, parser.parse)(line)
parser.d[k] = v
specialFn = getattr(parser, '_post_' + kk, None)
if specialFn: specialFn()
return parser.d
def _setEnv(env, boardsTxt, platformTxt):
env['CPPPATH'] = platformTxt['build.core.path']
# This is the tricky part, since there's no real correspondance
# between platform.txt (using one line per command) and SCons
# (which split the arguments make-style between various
# variables). So I kind of "extract" informations for the
# platform.txt file, hoping they won't change much from one
# version to the next.
# A much more simpler idea would be to hardcode everything in
# YATScons from an "intelligent" (human) analysis of platform.txt, but it
# would then need to be updated for every Arduino / Teensyduino
# version, precisely what I think is the problem with sconsduino
# that we're trying to solve.
env['CXX'] = platformTxt['recipe.cpp.o.pattern']
env['CC'] = platformTxt['recipe.c.o.pattern']
env['AR'] = platformTxt['recipe.ar.pattern'].split(' ')[0]
env['ASFLAGS'] = platformTxt['build.flags.S']
print 'LINKCOM=', env['LINKCOM']
env['LINKCOM'] = platformTxt['recipe.c.combine.pattern']
_defaultOptions = {
'speed': '96opt',
'usb': 'serial',
'keys': 'en-us',
}
def teensy31(target, userOptions={}, env=Environment()):
options = _defaultOptions.copy()
options.update(userOptions)
boardsTxt = _parseBoardsTxt()
platformTxt = _parsePlatformTxt(boardsTxt, options, target)
_setEnv(env, boardsTxt, platformTxt)
# ok
# env.VariantDir('build', 'src')
# env.Program('build/y', ['build/x.cpp', 'build/z.cpp'])
#
# ok
# env.VariantDir('build', 'src')
# env.Library('build/y', ['build/x.cpp', 'build/z.cpp'])
#
# ok
#env.VariantDir('build/a', '/tmp/t/7/src')
#env.Library('build/a/y', ['build/a/x.cpp', 'build/a/z.cpp'])
env.VariantDir('build/lib', env['CPPPATH'])
coreList = [os.path.join('build/lib', os.path.basename(_))
for _ in env.Glob(os.path.join(env['CPPPATH'], '*.*'), strings=True)
if not _.endswith('h')]
env.Library('build/lib/core', coreList)
env.VariantDir('build/code', '.')
o = env.Object('build/code/' + target +'.o', [target + '.cpp'])
elf = env.Command(target + '.elf', [o, 'build/lib/libcore.a'], platformTxt['recipe.c.combine.pattern'])
eep = env.Command(target + '.eep', elf, platformTxt['recipe.objcopy.eep.pattern'])
hex_ = env.Command(target + '.hex', eep, platformTxt['recipe.objcopy.hex.pattern'])