Fix build error with scons-4.4.0 version which is based on python3
[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 = list(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 = list(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                 # This is a helper function to build Arduino libraries. Scripts are using this function
74                 # to add all the files in a folder as compilation targets rather than specifying each
75                 # file to compile from a Arduino library folder.
76
77                 # Since the function is recursive, it adds even "/library/<library-name>/examples" to the
78                 # compilation list. This is an extra overhead as stack is never going to use ".o" generated
79                 # for these examples.
80                 if 'examples' not in root:
81                         matches.extend(Glob(os.path.join(root, pattern), ondisk, source, strings))
82         return matches
83
84 # To make sure the src is built in 'BUILD_DIR' (by default it will be built at
85 # the same directory as the .c .cpp .S)
86 def __src_to_obj(env, srcs):
87         objs = []
88         prefix = env.get('BOARD') + '_'
89         if env.get('CPU'):
90                 prefix += env.get('CPU') + '_'
91
92         build_dir = os.path.join(env.get('BUILD_DIR'), 'arduino')
93         for src in srcs:
94                 if (os.path.isabs(src.path)):
95                         obj = src.path.replace(arduino_home, build_dir)
96                 else:
97                         obj = os.path.join(build_dir, src.path)
98                 i = obj.rfind('.')
99                 obj = obj[0:i]
100                 if env.get('OBJSUFFIX'):
101                         obj += env.get('OBJSUFFIX')
102                 objs.extend(env.Object(obj, src, OBJPREFIX=prefix))
103         return objs
104
105 def __import_lib(env, lib):
106         lib_path = os.path.join(arduino_home, 'libraries', lib)
107         if not os.path.exists(lib_path):
108                 if target_arch == 'avr':
109                         lib_path = os.path.join(arduino_home, 'hardware', 'arduino', 'avr', 'libraries', lib)
110                 else:
111                         lib_path = os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'libraries', lib)
112
113         if os.path.exists(os.path.join(lib_path, 'src')):
114                 lib_path = os.path.join(lib_path, 'src')
115
116         env.AppendUnique(CPPPATH = [lib_path])
117
118         if os.path.exists(os.path.join(lib_path, 'utility')):
119                 env.AppendUnique(CPPPATH = [os.path.join(lib_path, 'utility')])
120
121         lib_src = []
122         lib_src.extend(__search_files(lib_path, '*.S'))
123         lib_src.extend(__search_files(lib_path, '*.c'))
124         lib_src.extend(__search_files(lib_path, '*.cpp'))
125
126         lib_obj = __src_to_obj(env, lib_src)
127         build_dir = env.get('BUILD_DIR')
128         if build_dir:
129                 lib_a = env.StaticLibrary(build_dir + lib, lib_obj)
130         else:
131                 lib_a = env.StaticLibrary(lib, lib_obj)
132
133         # If we link libSPI.a, the final binary is not getting launched
134         # on the board.  Which is not the case if we directly use SPI.o.
135
136         if env.get('TARGET_ARCH') == 'arm':
137                 if lib == 'SPI':
138                         for obj in lib_obj:
139                                 if obj.name.endswith('SPI.o'):
140                                         env.PrependUnique(LIBS = [File(obj)])
141                 else:
142
143                         env.AppendUnique(LIBS = [File(lib_a[0])])
144         else:
145                 env.PrependUnique(LIBS = [File(lib_a[0])])
146
147         #env.AppendUnique(LIBS = [File(lib_a[0])])
148
149 def __build_core(env):
150         core_src = __search_files(core_folder, '*.S')
151         core_src.extend(__search_files(core_folder, '*.c'))
152         core_src.extend(__search_files(core_folder, '*.cpp'))
153
154         core_src.extend(__search_files(variant_folder, '*.S'))
155         core_src.extend(__search_files(variant_folder, '*.c'))
156         core_src.extend(__search_files(variant_folder, '*.cpp'))
157
158         core_obj = __src_to_obj(env, core_src)
159
160         prefix = env.get('BOARD') + '_'
161         if env.get('CPU'):
162                 prefix += env.get('CPU') + '_'
163
164         core = os.path.join(env.get('BUILD_DIR', '.'), 'arduino', prefix + 'core')
165         s_core = env.StaticLibrary(core, core_obj)
166
167         env.AppendUnique(LIBS = [File(s_core[0])])
168
169         # To avoid compiler issue. Otherewise there may be warnings:
170         #       undefined reference to '_exit' '_close', '_getpid' ...
171         # Above functions are used in libc.a and implemented in syscalls_sam3.c
172         if env.get('TARGET_ARCH') == 'arm':
173                 for obj in core_obj:
174                         if obj.name.endswith('syscalls_sam3.o'):
175                                 env.AppendUnique(LIBS = [File(obj)])
176
177 def __create_bin(env, source):
178         name = source
179         if env.get('TARGET_ARCH') == 'avr':
180                 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')
181                 hex = env.Command(name + '.hex', source, 'avr-objcopy -O ihex -R .eeprom $SOURCE $TARGET')
182         else:
183                 hex = env.Command(name + '.hex', source, 'arm-none-eabi-objcopy -O binary $SOURCE $TARGET')
184
185 #Currently supporting only mega (ie. Arduino ATMega2560) and arduino_due_x/arduino_due_x_dbg (i.e. Arduino Due) builds
186 def __upload(env, binary):
187         if target_arch == 'avr':
188                 protocol = __get_board_info(board, '.upload.protocol')
189                 speed = __get_board_info(board, '.upload.speed')
190                 port = '/dev/ttyACM0'
191                 upload_cmd = arduino_home + '/hardware/tools/avr/bin/avrdude -C' + arduino_home +'/hardware/tools/avr/etc/avrdude.conf -p' \
192                 + mcu + ' -c' + protocol + ' -P' + port + ' -b' + speed + ' -D -Uflash:w:' + binary + ':i'
193                 print("Upload command: %s" %upload_cmd)
194                 install_cmd = env.Command('install_cmd', None, upload_cmd)
195                 env.Default('install_cmd')
196         elif target_arch == 'arm':
197                 port = 'ttyACM0'
198                 upload_cmd = 'stty -F /dev/' + port + ' speed 1200 cs8 -cstopb -parenb \n' + arduino_home + '/hardware/tools/bossac -i --port=' + port + ' -U false -e -w -b ' + binary + ' -R'
199                 print("Upload command: %s" %upload_cmd)
200                 install_cmd = env.Command('install_cmd', None, upload_cmd)
201                 env.Default('install_cmd')
202
203 # Print the command line that to upload binary to the board
204 def __upload_help(env):
205         if target_arch == 'avr':
206                 protocol = __get_board_info(board, '.upload.protocol')
207                 speed = __get_board_info(board, '.upload.speed')
208
209                 upload_cmd = arduino_home + '/hardware/tools/avr/bin/avrdude -C' + arduino_home +'/hardware/tools/avr/etc/avrdude.conf -v -v -v -v -p' \
210         + mcu + ' -c' + protocol + ' -P<serial_port>' + ' -b' + speed + ' -D -Uflash:w:<hex_file>:i'
211         else:
212                 uu = __get_board_info(board, '.upload.native_usb')
213                 upload_cmd = arduino_home + '/hardware/tools/bossac -i -d --port=<serial_port> -U ' + uu + ' -e -w -v -b <bin file> -R'
214
215         Help('''
216 ===============================================================================
217 You can upload the bin file with following command line:
218 ''')
219         Help('\n   $ ' + upload_cmd)
220         Help('''
221 \nPlease replace <xxx> according to the actual situation.
222 ===============================================================================
223 ''')
224
225 # ARDUINO_HOME build option
226 help_vars = Variables()
227 help_vars.Add(PathVariable('ARDUINO_HOME', 'ARDUINO root directory', os.environ.get('ARDUINO_HOME')))
228 help_vars.Update(env)
229 Help(help_vars.GenerateHelpText(env))
230
231 target_arch = env.get('TARGET_ARCH')
232
233 # Verify that the arduino, time, red bear, and nordic libraries are
234 # installed.  If not, get them and install them.
235 SConscript(os.path.join(env.get('SRC_DIR'), 'extlibs', 'arduino', 'SConscript'))
236 arduino_home = env.get('ARDUINO_HOME')
237 print('ARDUINO_HOME = ' + env.get('ARDUINO_HOME'))
238
239 # Overwrite suffixes and prefixes
240 if env['HOST_OS'] == 'win32':
241         env['OBJSUFFIX'] = '.o'
242         env['SHOBJSUFFIX'] = '.os'
243         env['LIBPREFIX'] = 'lib'
244         env['LIBSUFFIX'] = '.a'
245         env['SHLIBPREFIX'] = 'lib'
246         env['SHLIBSUFFIX'] = '.so'
247         env['LIBPREFIXES'] = ['lib']
248         env['LIBSUFFIXES'] = ['.a', '.so']
249         env['PROGSUFFIX'] = ''
250 elif platform.system().lower() == 'darwin':
251         env['SHLIBSUFFIX'] = '.so'
252         env['LIBSUFFIXES'] = ['.a', '.so']
253         env['PROGSUFFIX'] = ''
254
255 # Debug/release relative flags
256 if env.get('RELEASE'):
257         env.AppendUnique(CCFLAGS = ['-Os'])
258         env.AppendUnique(CPPDEFINES = ['NDEBUG'])
259 else:
260         env.AppendUnique(CCFLAGS = ['-g'])
261
262 # Force header presence defines
263 env.AppendUnique(CPPDEFINES = ['HAVE_ARDUINO_TIME_H'])
264
265 # BOARD / CPU option
266
267 # Get IDE version
268 if os.path.exists(os.path.join(arduino_home, 'lib', 'version.txt')):
269         vf = open(os.path.join(arduino_home, 'lib', 'version.txt'), 'r')
270         version = vf.readline().replace('.', '').strip()
271 else:
272         print('''
273 ************************************* Error ***********************************
274 * Can't find version file (lib/version.txt), please check if (%s)
275 * is arduino root directory.                                                  *
276 *******************************************************************************
277 ''' % arduino_home)
278         Exit(1)
279
280 if version[0:2] == '10':
281         is_1_0_x = True
282         boards_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'boards.txt'))
283         env.PrependENVPath('PATH', os.path.join(arduino_home, 'hardware', 'tools', 'avr', 'bin'))
284         env.Replace(CC = 'avr-gcc')
285         env.Replace(CXX = 'avr-g++')
286         env.Replace(AR = 'avr-ar')
287         env.Replace(AS = 'avr-as')
288         env.Replace(LINK = 'avr-gcc')
289         env.Replace(RANLIB = 'avr-ranlib')
290         if target_arch != 'avr':
291                 print('''
292 ************************************* Error ***********************************
293 * Arduino 1.0.x IDE only support 'avr', to support other arch at least 1.5.x  *
294 * is required.
295 *******************************************************************************
296 ''')
297                 Exit(1)
298 else:
299         is_1_0_x = False
300         if target_arch == 'avr':
301                 boards_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'avr', 'boards.txt'))
302                 platform_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'avr', 'platform.txt'))
303         elif target_arch == 'arm':
304                 boards_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'boards.txt'))
305                 platform_info = __parse_config(os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'platform.txt'))
306         else:
307                 print('''
308 ************************************* Error ***********************************
309 * CPU arch %s isn't supported currently.
310 *******************************************************************************
311 ''' % target_arch)
312
313 #Board option, let user to select the board
314 boards = __get_boards(boards_info)
315 help_vars = Variables()
316 help_vars.Add(EnumVariable('BOARD', 'arduino board', boards[0], boards))
317 help_vars.Update(env)
318 Help(help_vars.GenerateHelpText(env))
319
320 #CPU option
321 board = env.get('BOARD')
322 cpus = __get_cpu(boards_info, board)
323 if len(cpus) > 0:
324         help_vars = Variables()
325         help_vars.Add(EnumVariable('CPU', 'arduino board cpu', cpus[0], cpus))
326         help_vars.Update(env)
327         Help(help_vars.GenerateHelpText(env))
328
329 # Arduino commom flags
330 cpu = env.get('CPU')
331 board = env.get('BOARD')
332 mcu = __get_board_info(board, '.build.mcu')
333 f_cpu = __get_board_info(board, '.build.f_cpu')
334 usb_vid = __get_board_info(board, '.build.vid')
335 usb_pid = __get_board_info(board, '.build.pid')
336 variant = __get_board_info(board, '.build.variant')
337
338 if not usb_vid:
339         usb_vid = __get_board_info(board, '.vid.0')
340 if not usb_pid:
341         usb_pid = __get_board_info(board, '.pid.0')
342
343 if is_1_0_x:
344         core_base = os.path.join(arduino_home, 'hardware', 'arduino')
345 else:
346         if target_arch == 'avr':
347                 core_base = os.path.join(arduino_home, 'hardware', 'arduino', 'avr')
348         else:
349                 core_base = os.path.join(arduino_home, 'hardware', 'arduino', 'sam')
350
351 variant_folder = os.path.join(core_base, 'variants', variant)
352 env.AppendUnique(CPPPATH = [variant_folder])
353
354 core = __get_board_info(board, '.build.core')
355 core_folder = os.path.join(core_base, 'cores', core)
356 env.AppendUnique(CPPPATH = [core_folder])
357
358 if is_1_0_x:
359         comm_flags = ['-std=c99']
360         if mcu:
361                 comm_flags.extend(['-mmcu=' + mcu])
362         if f_cpu:
363                 comm_flags.extend(['-DF_CPU=' + f_cpu])
364         comm_flags.extend(['-DARDUINO=' + version])
365         if usb_vid:
366                 comm_flags.extend(['-DUSB_VID=' + usb_vid])
367         if usb_pid:
368                 comm_flags.extend(['-DUSB_PID=' + usb_pid])
369
370         env.AppendUnique(ASFLAGS = ['-x', 'assembler-with-cpp'])
371         env.AppendUnique(ASFLAGS = comm_flags)
372
373         env.AppendUnique(CFLAGS = ['-Os', '-ffunction-sections', '-fdata-sections', '-MMD'])
374         env.AppendUnique(CFLAGS = comm_flags)
375
376         env.AppendUnique(CXXFLAGS = ['-Os', '-fno-exceptions', '-ffunction-sections', '-fdata-sections','-MMD'])
377         env.AppendUnique(CXXFLAGS = comm_flags)
378
379         env.AppendUnique(LINKFLAGS = ['-Os'])
380         if mcu == 'atmega2560':
381                 env.AppendUnique(LINKFLAGS = ['-Wl,--gc-sections,--relax'])
382         else:
383                 env.AppendUnique(LINKFLAGS = ['-Wl,--gc-sections'])
384         env.AppendUnique(LINKFLAGS = ['-mmcu=' + mcu])
385 else:
386         if target_arch == 'avr':
387                 cpu_flag = '-mmcu=' + mcu
388         else:
389                 cpu_flag = '-mcpu=' + mcu
390
391         comm_flag = [cpu_flag, '-DF_CPU=' + f_cpu, '-DARDUINO=' + version, '-DARDUINO_' + __get_board_info(board, '.build.board')]
392         if target_arch == 'arm':
393                 # As of 1.5.8 the arduino headers for arm had _asm_ bugs with ARM and
394                 # require gnu99 to be used
395                 comm_flag.extend(['-std=gnu99', '-DARDUINO_ARCH_SAM'])
396         else:
397                 comm_flag.extend(['-std=c99', '-DARDUINO_ARCH_AVR'])
398
399         compiler_path = platform_info.get('compiler.path')
400         compiler_path = compiler_path.replace('{runtime.ide.path}', arduino_home)
401         env.PrependENVPath('PATH', compiler_path)
402         env.Replace(CC = platform_info.get('compiler.c.cmd'))
403         env.Replace(CXX = platform_info.get('compiler.cpp.cmd'))
404         env.Replace(AR = platform_info.get('compiler.ar.cmd'))
405         if target_arch == 'arm':
406                 env.AppendUnique(CPPPATH = [os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'system', 'libsam'),
407                                                         os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'system', 'CMSIS', 'CMSIS', 'Include'),
408                                                         os.path.join(arduino_home, 'hardware', 'arduino', 'sam', 'system', '', 'CMSIS', 'Device', 'ATMEL')])
409         env.AppendUnique(ASFLAGS = ['-x', 'assembler-with-cpp'])
410         env.AppendUnique(ASFLAGS = comm_flag)
411         env.AppendUnique(CFLAGS = Split(platform_info.get('compiler.c.flags')))
412         env.AppendUnique(CXXFLAGS = Split(platform_info.get('compiler.cpp.flags')))
413         env.AppendUnique(ARFLAGS = Split(platform_info.get('compiler.ar.flags')))
414         env.AppendUnique(CCFLAGS = comm_flag)
415
416         extra_flags = __get_board_info(board, '.build.extra_flags')
417         if extra_flags:
418                 extra_flags = extra_flags.replace('{build.usb_flags}', '')
419                 env.AppendUnique(CCFLAGS = Split(extra_flags))
420                 usb_flags = ['-DUSB_VID=' + usb_vid, '-DUSB_PID=' + usb_pid, '-DUSBCON', '-DUSB_MANUFACTURER="Unknown"']
421                 env.AppendUnique(CCFLAGS = usb_flags)
422
423         if target_arch == 'arm':
424                 env.AppendUnique(LINKFLAGS = ['-Os', '-Wl,--gc-sections', cpu_flag,
425                                         '-T' + os.path.join(variant_folder,  __get_board_info(board, '.build.ldscript'))])
426                 env.AppendUnique(LINKFLAGS = Split('-lm -lgcc -mthumb -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'))
427
428                 variant_system_lib = __get_board_info(board, '.build.variant_system_lib')
429                 if variant_system_lib:
430                         if variant_folder.find(' ') >= 0:
431                                 variant_folder = '"' + variant_folder + '"'
432                         env.Replace(LINKCOM = '$LINK -o $TARGET $_LIBDIRFLAGS $LINKFLAGS $SOURCES $_LIBFLAGS '
433                                         + os.path.join(variant_folder, variant_system_lib) + ' -Wl,--end-group')
434                 else:
435                         env.Replace(LINKCOM = '$LINK -o $TARGET $_LIBDIRFLAGS $LINKFLAGS $SOURCES $_LIBFLAGS -Wl,--end-group')
436         else:
437                 env.AppendUnique(LINKFLAGS = Split(platform_info.get('compiler.c.elf.flags')))
438                 env.AppendUnique(LINKFLAGS = [cpu_flag])
439                 env.AppendUnique(LIBS = 'm')
440         env.Replace(ARCOM = '$AR ' + platform_info.get('compiler.ar.flags') + ' $TARGET $SOURCES')
441
442 # Make sure the .d files are removed when clean the build
443 if env.GetOption('clean'):
444         dfs = __search_files(env.get('BUILD_DIR'), '*.d')
445         for df in dfs:
446                 Execute(Delete(df))
447 __build_core(env)
448
449 env.AddMethod(__import_lib, "ImportLib") #import arduino library
450 env.AddMethod(__build_core, "BuildCore") #build arduino core
451 env.AddMethod(__create_bin, "CreateBin") #create binary files(.eep and .hex)
452 env.AddMethod(__upload, "Upload") #Upload binary to board
453 env.AddMethod(__upload_help, "UploadHelp") #print the command line that to upload binary to the boardf