iotivity 0.9.0
[platform/upstream/iotivity.git] / build_common / arduino / SConscript
1 ##
2 # This script includes arduino specific config
3 ##
4 import os
5 import platform
6
7 Import('env')
8
9 def __parse_config(f):
10         dict = {}
11
12         if not os.path.isfile(f):
13                 return dict
14
15         file = open(f, 'r')
16         strs = file.readlines()
17         for str in strs:
18                 str = str.strip()
19                 if len(str) > 0 and str[0] == '#':
20                         continue
21
22                 idx = str.find('=')
23                 if idx > 0:
24                         dict.setdefault(str[0:idx], str[idx + 1:])
25
26         return dict
27
28 def __get_boards(dict):
29         boards = []
30         keys = dict.keys()
31         for key in keys:
32                 idx = key.find('.name')
33                 if idx > 0:
34                         if key.endswith('.name'):
35                                 boards.append(key[0:idx])
36         return boards
37
38 def __get_cpu(dict, board):
39         cpus = []
40         keys = dict.keys()
41         for key in keys:
42                 idx = key.find(board + '.menu.cpu.')
43                 start = len(board + '.menu.cpu.')
44                 if idx >= 0:
45                         end = key.find('.', start)
46                         if end > 0:
47                                 cpu = key[start:end]
48                                 exist = False
49                                 for c in cpus:
50                                         if c == cpu:
51                                                 exist = True
52                                                 break
53
54                                 if not exist:
55                                         cpus.append(cpu)
56         return cpus
57
58 def __get_board_info(board, key):
59         if cpu:
60                 v = boards_info.get(board + '.menu.cpu.' + cpu + key)
61                 if not v:
62                         v = boards_info.get(board + key)
63         else:
64                 v = boards_info.get(board + key)
65         return v
66
67 def __search_files(path, pattern, ondisk=True, source=True, strings=False, recursive=True):
68         if not recursive:
69                 return Glob(pattern, ondisk, source, strings)
70
71         matches = []
72         for root, dirnames, filenames in os.walk(path):
73                 matches.extend(Glob(root + '/' + pattern, ondisk, source, strings))
74
75         return matches
76
77 # To make sure the src is built in 'BUILD_DIR' (by default it will be built at
78 # the same directory as the .c .cpp .S)
79 def __src_to_obj(env, srcs):
80         objs = []
81         prefix = env.get('BOARD') + '_'
82         if env.get('CPU'):
83                 prefix += env.get('CPU') + '_'
84
85         build_dir = env.get('BUILD_DIR') + '/arduino/'
86         for src in srcs:
87                 obj = src.path.replace(arduino_home, build_dir)
88                 i = obj.rfind('.')
89                 obj = obj[0:i]
90                 if env.get('OBJSUFFIX'):
91                         obj += env.get('OBJSUFFIX')
92                 objs.extend(env.Object(obj, src, OBJPREFIX=prefix))
93         return objs
94
95 def __import_lib(env, lib):
96         lib_path = arduino_home + '/libraries/' + lib
97         if not os.path.exists(lib_path):
98                 if target_arch == 'avr':
99                         lib_path = arduino_home + '/hardware/arduino/avr/libraries/' + lib
100                 else:
101                         lib_path = arduino_home + '/hardware/arduino/sam/libraries/' + lib
102
103         if os.path.exists(lib_path + '/src'):
104                 lib_path = lib_path + '/src'
105
106         env.AppendUnique(CPPPATH = [lib_path])
107
108         if os.path.exists(lib_path + '/utility'):
109                 env.AppendUnique(CPPPATH = [lib_path + '/utility'])
110
111         lib_src = []
112         lib_src.extend(__search_files(lib_path, '*.S'))
113         lib_src.extend(__search_files(lib_path, '*.c'))
114         lib_src.extend(__search_files(lib_path, '*.cpp'))
115
116         build_dir = env.get('BUILD_DIR')
117         if build_dir:
118                 lib_a = env.StaticLibrary(build_dir + lib, __src_to_obj(env, lib_src))
119         else:
120                 lib_a = env.StaticLibrary(lib, __src_to_obj(env, lib_src))
121         env.AppendUnique(LIBS = [File(lib_a[0])])
122
123 def __build_core(env):
124         core_src = __search_files(core_folder, '*.S')
125         core_src.extend(__search_files(core_folder, '*.c'))
126         core_src.extend(__search_files(core_folder, '*.cpp'))
127
128         core_src.extend(__search_files(variant_folder, '*.S'))
129         core_src.extend(__search_files(variant_folder, '*.c'))
130         core_src.extend(__search_files(variant_folder, '*.cpp'))
131
132         core_obj = __src_to_obj(env, core_src)
133         build_dir = env.get('BUILD_DIR')
134         if build_dir:
135                 s_core = env.StaticLibrary(build_dir + 'core', core_obj)
136         else:
137                 s_core = env.StaticLibrary('core', core_obj)
138         env.AppendUnique(LIBS = [File(s_core[0])])
139
140         # To avoid compiler issue. Otherewise there may be warnings:
141         #       undefined reference to '_exit' '_close', '_getpid' ...
142         # Above functions are used in libc.a and implemented in syscalls_sam3.c
143         if env.get('TARGET_ARCH') == 'arm':
144                 for obj in core_obj:
145                         if obj.name.endswith('syscalls_sam3.o'):
146                                 env.AppendUnique(LIBS = [File(obj)])
147
148 def __create_bin(env, source):
149         name = source
150         if env.get('TARGET_ARCH') == 'avr':
151                 eep = env.Command(name + '.eep', source, 'avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 $SOURCE $TARGET')
152                 hex = env.Command(name + '.hex', source, 'avr-objcopy -O ihex -R .eeprom $SOURCE $TARGET')
153         else:
154                 hex = env.Command(name + '.hex', source, 'arm-none-eabi-objcopy -O binary $SOURCE $TARGET')
155
156 # Print the command line that to upload binary to the board
157 def __upload_help(env):
158         if target_arch == 'avr':
159                 protocol = __get_board_info(board, '.upload.protocol')
160                 speed = __get_board_info(board, '.upload.speed')
161
162                 upload_cmd = arduino_home + '/hardware/tools/avr/bin/avrdude -C' + arduino_home +'/hardware/tools/avr/etc/avrdude.conf -v -v -v -v -p' \
163         + mcu + ' -c' + protocol + ' -P<serial_port>' + ' -b' + speed + ' -D -Uflash:w:<hex_file>:i'
164         else:
165                 uu = __get_board_info(board, '.upload.native_usb')
166                 upload_cmd = arduino_home + '/hardware/tools/bossac -i -d --port=<serial_port> -U ' + uu + ' -e -w -v -b <bin file> -R'
167
168         Help('''
169 ===============================================================================
170 You can upload the bin file with following command line:
171 ''')
172         Help('\n   $ ' + upload_cmd)
173         Help('''
174 \nPlease replace <xxx> according to the actual situation.
175 ===============================================================================
176 ''')
177
178 # ARDUINO_HOME build option
179 help_vars = Variables()
180 help_vars.Add(PathVariable('ARDUINO_HOME', 'ARDUINO root directory', os.environ.get('ARDUINO_HOME')))
181 help_vars.Update(env)
182 Help(help_vars.GenerateHelpText(env))
183
184 target_arch = env.get('TARGET_ARCH')
185 arduino_home = env.get('ARDUINO_HOME')
186 if not arduino_home:
187         print '''
188 ************************************* Error ***********************************
189 *   Arduino root directory isn't set, you can set enviornment variable        *
190 * ARDUINO_HOME or add it in command line as:                                  *
191 *      # scons ARDUINO_HOME=<path to arduino root directory> ...              *
192 *******************************************************************************
193 '''
194         Exit(1)
195
196 # Overwrite suffixes and prefixes
197 if env['HOST_OS'] == 'win32':
198         env['OBJSUFFIX'] = '.o'
199         env['SHOBJSUFFIX'] = '.os'
200         env['LIBPREFIX'] = 'lib'
201         env['LIBSUFFIX'] = '.a'
202         env['SHLIBPREFIX'] = 'lib'
203         env['SHLIBSUFFIX'] = '.so'
204         env['LIBPREFIXES'] = ['lib']
205         env['LIBSUFFIXES'] = ['.a', '.so']
206         env['PROGSUFFIX'] = ''
207 elif platform.system().lower() == 'darwin':
208         env['SHLIBSUFFIX'] = '.so'
209         env['LIBSUFFIXES'] = ['.a', '.so']
210         env['PROGSUFFIX'] = ''
211
212 # Debug/release relative flags
213 if env.get('RELEASE'):
214         env.AppendUnique(CCFLAGS = ['-Os'])
215         env.AppendUnique(CPPDEFINES = ['NDEBUG'])
216 else:
217         env.AppendUnique(CCFLAGS = ['-g'])
218
219 # BOARD / CPU option
220
221 # Get IDE version
222 if os.path.exists(arduino_home + '/lib/version.txt'):
223         vf = open(arduino_home + '/lib/version.txt', 'r')
224         version = vf.readline().replace('.', '')
225 else:
226         print '''
227 ************************************* Error ***********************************
228 * Can't find version file (lib/version.txt), please check if (%s)
229 * is arduino root directory.                                                  *
230 *******************************************************************************
231 ''' % arduino_home
232         Exit(1)
233
234 if version[0:2] == '10':
235         is_1_0_x = True
236         boards_info = __parse_config(arduino_home + '/hardware/arduino/boards.txt')
237         env.PrependENVPath('PATH', arduino_home + '/hardware/tools/avr/bin/')
238         env.Replace(CC = 'avr-gcc')
239         env.Replace(CXX = 'avr-g++')
240         env.Replace(AR = 'avr-ar')
241         env.Replace(AS = 'avr-as')
242         env.Replace(LINK = 'avr-gcc')
243         env.Replace(RANLIB = 'avr-ranlib')
244         if target_arch != 'avr':
245                 print '''
246 ************************************* Error ***********************************
247 * Arduino 1.0.x IDE only support 'avr', to support other arch at least 1.5.x  *
248 * is required.
249 *******************************************************************************
250 '''
251                 Exit(1)
252 else:
253         is_1_0_x = False
254         if target_arch == 'avr':
255                 boards_info = __parse_config(arduino_home + '/hardware/arduino/avr/boards.txt')
256                 platform_info = __parse_config(arduino_home + '/hardware/arduino/avr/platform.txt')
257         elif target_arch == 'arm':
258                 boards_info = __parse_config(arduino_home + '/hardware/arduino/sam/boards.txt')
259                 platform_info = __parse_config(arduino_home + '/hardware/arduino/sam/platform.txt')
260         else:
261                 print '''
262 ************************************* Error ***********************************
263 * CPU arch %s isn't supported currently.
264 *******************************************************************************
265 ''' % target_arch
266
267 #Board option, let user to select the board
268 boards = __get_boards(boards_info)
269 help_vars = Variables()
270 help_vars.Add(EnumVariable('BOARD', 'arduino board', boards[0], boards))
271 help_vars.Update(env)
272 Help(help_vars.GenerateHelpText(env))
273
274 #CPU option
275 board = env.get('BOARD')
276 cpus = __get_cpu(boards_info, board)
277 if len(cpus) > 0:
278         help_vars = Variables()
279         help_vars.Add(EnumVariable('CPU', 'arduino board cpu', cpus[0], cpus))
280         help_vars.Update(env)
281         Help(help_vars.GenerateHelpText(env))
282
283 # Arduino commom flags
284 cpu = env.get('CPU')
285 board = env.get('BOARD')
286 mcu = __get_board_info(board, '.build.mcu')
287 f_cpu = __get_board_info(board, '.build.f_cpu')
288 usb_vid = __get_board_info(board, '.build.vid')
289 usb_pid = __get_board_info(board, '.build.pid')
290 variant = __get_board_info(board, '.build.variant')
291
292 if not usb_vid:
293         usb_vid = __get_board_info(board, '.vid.0')
294 if not usb_pid:
295         usb_pid = __get_board_info(board, '.pid.0')
296
297 if is_1_0_x:
298         core_base = arduino_home + '/hardware/arduino/'
299 else:
300         if target_arch == 'avr':
301                 core_base = arduino_home + '/hardware/arduino/avr/'
302         else:
303                 core_base = arduino_home + '/hardware/arduino/sam/'
304
305 variant_folder = core_base + 'variants/' + variant
306 env.AppendUnique(CPPPATH = [variant_folder])
307
308 core = __get_board_info(board, '.build.core')
309 core_folder = core_base + 'cores/' + core + '/'
310 env.AppendUnique(CPPPATH = [core_folder])
311
312 if is_1_0_x:
313         comm_flags = []
314         if mcu:
315                 comm_flags.extend(['-mmcu=' + mcu])
316         if f_cpu:
317                 comm_flags.extend(['-DF_CPU=' + f_cpu])
318         comm_flags.extend(['-DARDUINO=' + version])
319         if usb_vid:
320                 comm_flags.extend(['-DUSB_VID=' + usb_vid])
321         if usb_pid:
322                 comm_flags.extend(['-DUSB_PID=' + usb_pid])
323
324         env.AppendUnique(ASFLAGS = ['-x', 'assembler-with-cpp'])
325         env.AppendUnique(ASFLAGS = comm_flags)
326
327         env.AppendUnique(CFLAGS = ['-Os', '-ffunction-sections', '-fdata-sections', '-MMD'])
328         env.AppendUnique(CFLAGS = comm_flags)
329
330         env.AppendUnique(CXXFLAGS = ['-Os', '-fno-exceptions', '-ffunction-sections', '-fdata-sections','-MMD'])
331         env.AppendUnique(CXXFLAGS = comm_flags)
332
333         env.AppendUnique(LINKFLAGS = ['-Os'])
334         if mcu == 'atmega2560':
335                 env.AppendUnique(LINKFLAGS = ['-Wl,--gc-sections,--relax'])
336         else:
337                 env.AppendUnique(LINKFLAGS = ['-Wl,--gc-sections'])
338         env.AppendUnique(LINKFLAGS = ['-mmcu=' + mcu])
339 else:
340         if target_arch == 'avr':
341                 cpu_flag = '-mmcu=' + mcu
342         else:
343                 cpu_flag = '-mcpu=' + mcu
344
345         comm_flag = [cpu_flag, '-DF_CPU=' + f_cpu, '-DARDUINO=' + version, '-DARDUINO_' + __get_board_info(board, '.build.board')]
346         if target_arch == 'arm':
347                 comm_flag.extend(['-DARDUINO_ARCH_SAM'])
348         else:
349                 comm_flag.extend(['-DARDUINO_ARCH_AVR'])
350
351         compiler_path = platform_info.get('compiler.path')
352         compiler_path = compiler_path.replace('{runtime.ide.path}', arduino_home)
353         env.PrependENVPath('PATH', compiler_path)
354         env.Replace(CC = platform_info.get('compiler.c.cmd'))
355         env.Replace(CXX = platform_info.get('compiler.cpp.cmd'))
356         env.Replace(AR = platform_info.get('compiler.ar.cmd'))
357         if target_arch == 'arm':
358                 env.AppendUnique(CPPPATH = [arduino_home + '/hardware/arduino/sam/system/libsam',
359                                                         arduino_home + '/hardware/arduino/sam/system/CMSIS/CMSIS/Include/',
360                                                         arduino_home + '/hardware/arduino/sam/system//CMSIS/Device/ATMEL'])
361         env.AppendUnique(ASFLAGS = ['-x', 'assembler-with-cpp'])
362         env.AppendUnique(ASFLAGS = comm_flag)
363         env.AppendUnique(CFLAGS = Split(platform_info.get('compiler.c.flags')))
364         env.AppendUnique(CXXFLAGS = Split(platform_info.get('compiler.cpp.flags')))
365         env.AppendUnique(ARFLAGS = Split(platform_info.get('compiler.ar.flags')))
366         env.AppendUnique(CCFLAGS = comm_flag)
367
368         extra_flags = __get_board_info(board, '.build.extra_flags')
369         if extra_flags:
370                 extra_flags = extra_flags.replace('{build.usb_flags}', '')
371                 env.AppendUnique(CCFLAGS = Split(extra_flags))
372                 usb_flags = ['-DUSB_VID=' + usb_vid, '-DUSB_PID=' + usb_pid, '-DUSBCON', '-DUSB_MANUFACTURER="Unknown"']
373                 env.AppendUnique(CCFLAGS = usb_flags)
374
375         if target_arch == 'arm':
376                 env.AppendUnique(LINKFLAGS = ['-Os', '-Wl,--gc-sections', cpu_flag,
377                                         '-T' + variant_folder + '/' + __get_board_info(board, '.build.ldscript'),
378                                         '-Wl,-Map,' + env.get('BUILD_DIR') + 'arduino_prj.map'])
379                 env.AppendUnique(LINKFLAGS = Split('-lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group'))
380
381                 variant_system_lib = __get_board_info(board, '.build.variant_system_lib')
382                 if variant_system_lib:
383                         if variant_folder.find(' ') >= 0:
384                                 variant_folder = '"' + variant_folder + '"'
385                         env.Replace(LINKCOM = '$LINK -o $TARGET $_LIBDIRFLAGS $LINKFLAGS $SOURCES $_LIBFLAGS '
386                                         + variant_folder + '/' + variant_system_lib + ' -Wl,--end-group')
387                 else:
388                         env.Replace(LINKCOM = '$LINK -o $TARGET $_LIBDIRFLAGS $LINKFLAGS $SOURCES $_LIBFLAGS -Wl,--end-group')
389         else:
390                 env.AppendUnique(LINKFLAGS = Split(platform_info.get('compiler.c.elf.flags')))
391                 env.AppendUnique(LINKFLAGS = [cpu_flag])
392                 env.AppendUnique(LIBS = 'm')
393         env.Replace(ARCOM = '$AR ' + platform_info.get('compiler.ar.flags') + ' $TARGET $SOURCES')
394
395 __build_core(env)
396
397 env.AddMethod(__import_lib, "ImportLib") #import arduino library
398 #env.AddMethod(__build_core, "BuildCore") #build arduino core
399 env.AddMethod(__create_bin, "CreateBin") #create binary files(.eep and .hex)
400 env.AddMethod(__upload_help, "UploadHelp") #print the command line that to upload binary to the boardf