Seperate Android x86 and Armeabi Builds
[platform/upstream/iotivity.git] / auto_build.py
1 #!/usr/bin/python
2
3 import os
4 import sys
5 import platform
6 import subprocess
7 import multiprocessing
8
9 # help message
10 def helpmsg(script):
11     helpstr = '''
12 Usage:
13     build:
14         python %s <targetbuild>
15         Allowed values for <target_build>: all, linux_unsecured, linux_secured, linux_unsecured_with_ra, linux_secured_with_ra, linux_unsecured_with_rd, linux_secured_with_rd, android, arduino, tizen, simulator, darwin, windows, msys
16         Note: \"linux\" will build \"linux_unsecured\", \"linux_secured\", \"linux_unsecured_with_ra\", \"linux_secured_with_ra\", \"linux_secured_with_rd\", \"linux_unsecured_with_mq\", \"linux_unsecured_with_tcp\" & \"linux_unsecured_with_rd\".
17         Any selection will build both debug and release versions of all available targets in the scope you've selected.
18         To choose any specific command, please use the SCons commandline directly. Please refer to [IOTIVITY_REPO]/Readme.scons.txt.
19     clean:
20         python %s -c
21     '''
22     print (helpstr % (script, script))
23     sys.exit()
24
25 def call_scons(build_options, extra_option_str):
26     """
27     This function formats and runs a scons command
28     Arguments:
29     build_options    -- {Dictionary} build flags (keys) associated with values;
30     extra_option_str -- {String} extra options to append to scons command
31     """
32     cmd_line = "scons VERBOSE=" + VERBOSE
33     for key in build_options:
34         cmd_line += " " + key + "=" + str(build_options[key])
35
36     cmd_line += " " + str(extra_option_str)
37
38     print ("Running : " + cmd_line)
39     exit_code = subprocess.Popen([cmd_line], shell=True).wait()
40     if exit_code != 0:
41         exit(exit_code)
42
43 def build_all(flag, extra_option_str):
44     if platform.system() == "Linux":
45         build_linux_unsecured(flag, extra_option_str)
46         build_linux_secured(flag, extra_option_str)
47         build_linux_unsecured_with_ra(flag, extra_option_str)
48         build_linux_secured_with_ra(flag, extra_option_str)
49         build_linux_unsecured_with_rm(flag, extra_option_str)
50         build_linux_unsecured_with_rd(flag, extra_option_str)
51         build_linux_secured_with_rd(flag, extra_option_str)
52         build_linux_unsecured_with_mq(flag, extra_option_str)
53         build_linux_unsecured_with_tcp(flag, extra_option_str)
54         build_simulator(flag, extra_option_str)
55
56     build_android(flag, extra_option_str)
57     build_arduino(flag, extra_option_str)
58     build_tizen(flag, extra_option_str)
59
60     if platform.system() == "Windows":
61         build_windows(flag, extra_option_str)
62
63     if platform.system() == "Darwin":
64         build_darwin(flag, extra_option_str)
65
66 def build_linux(flag, extra_option_str):
67     build_linux_unsecured(flag, extra_option_str)
68     build_linux_secured(flag, extra_option_str)
69
70 def build_linux_unsecured(flag, extra_option_str):
71     print ("*********** Build for linux ************")
72     build_options = {
73                         'RELEASE':flag,
74                     }
75     call_scons(build_options, extra_option_str)
76
77 def build_linux_unsecured_with_tcp(flag, extra_option_str):
78     print ("*********** Build for linux with TCP ************")
79     build_options = {
80                         'RELEASE':flag,
81                         'WITH_TCP': 1,
82                         'TARGET_TRANSPORT': 'IP',
83                     }
84     call_scons(build_options, extra_option_str)
85
86 def build_linux_unsecured_with_rm(flag, extra_option_str):
87     print ("*********** Build for linux with RoutingManager************")
88     build_options = {
89                         'ROUTING':'GW',
90                         'RELEASE':flag,
91                     }
92     call_scons(build_options, extra_option_str)
93
94 def build_linux_secured(flag, extra_option_str):
95     print ("*********** Build for linux with Security *************")
96     build_options = {
97                         'RELEASE':flag,
98                         'SECURED':1,
99                     }
100     call_scons(build_options, extra_option_str)
101
102 def build_linux_unsecured_with_ra(flag, extra_option_str):
103     print ("*********** Build for linux With Remote Access *************")
104     build_options = {
105                         'RELEASE':flag,
106                         'WITH_RA':1,
107                         'WITH_RA_IBB':1,
108                     }
109     call_scons(build_options, extra_option_str)
110
111 def build_linux_secured_with_ra(flag, extra_option_str):
112     print ("*********** Build for linux With Remote Access & Security ************")
113     build_options = {
114                         'RELEASE':flag,
115                         'WITH_RA':1,
116                         'WITH_RA_IBB':1,
117                         'SECURED':1,
118                     }
119     call_scons(build_options, extra_option_str)
120
121 def build_linux_unsecured_with_rd(flag, extra_option_str):
122     print ("*********** Build for linux With Resource Directory *************")
123     build_options = {
124                         'RELEASE':flag,
125                         'WITH_RD':1,
126                     }
127     call_scons(build_options, extra_option_str)
128
129 def build_linux_secured_with_rd(flag, extra_option_str):
130     print ("*********** Build for linux With Resource Directory & Security ************")
131     build_options = {
132                         'RELEASE':flag,
133                         'WITH_RD':1,
134                         'SECURED':1,
135                     }
136     call_scons(build_options, extra_option_str)
137
138 def build_linux_unsecured_with_mq(flag, extra_option_str):
139     print ("*********** Build for linux With Message Queue ************")
140     build_options = {
141                         'RELEASE':flag,
142                         'WITH_MQ':'PUB,SUB,BROKER',
143                     }
144     call_scons(build_options, extra_option_str)
145
146 def build_linux_unsecured_with_tcp(flag, extra_option_str):
147     print ("*********** Build for linux With tcp ************")
148     build_options = {
149                         'RELEASE':flag,
150                         'WITH_TCP':'1',
151                     }
152     call_scons(build_options, extra_option_str)
153
154 def build_android(flag, extra_option_str):
155     # Note: for android, as oic-resource uses C++11 feature stoi and to_string,
156     # it requires gcc-4.9, currently only android-ndk-r10(for linux)
157     # and windows android-ndk-r10(64bit target version) support these features.
158
159     build_android_x86(flag, extra_option_str)
160     build_android_x86_with_rm(flag, extra_option_str)
161     build_android_armeabi(flag, extra_option_str)
162     build_android_armeabi_with_rm(flag, extra_option_str)
163
164 def build_android_x86(flag, extra_option_str):
165     """ Build Android x86 Suite """
166     build_android_x86_with_ip(flag, extra_option_str)
167     build_android_x86_with_bt(flag, extra_option_str)
168     build_android_x86_with_ble(flag, extra_option_str)
169
170 def build_android_x86_with_ip(flag, extra_option_str):
171     print ("*********** Build for android x86 *************")
172     build_options = {
173                         'TARGET_OS':'android',
174                         'TARGET_ARCH':'x86',
175                         'RELEASE':flag,
176                         'TARGET_TRANSPORT':'IP',
177                     }
178     call_scons(build_options, extra_option_str)
179
180 def build_android_x86_with_bt(flag, extra_option_str):
181     print ("*********** Build for android x86 with Bluetooth *************")
182     build_options = {
183                         'TARGET_OS':'android',
184                         'TARGET_ARCH':'x86',
185                         'RELEASE':flag,
186                         'TARGET_TRANSPORT':'BT',
187                     }
188     call_scons(build_options, extra_option_str)
189
190 def build_android_x86_with_ble(flag, extra_option_str):
191     print ("*********** Build for android x86 with Bluetooth Low Energy *************")
192     build_options = {
193                         'TARGET_OS':'android',
194                         'TARGET_ARCH':'x86',
195                         'RELEASE':flag,
196                         'TARGET_TRANSPORT':'BLE',
197                     }
198     call_scons(build_options, extra_option_str)
199
200 def build_android_x86_with_rm(flag, extra_option_str):
201     """ Build Android x86 Routing Manager Suite """
202     build_android_x86_with_rm_and_ip(flag, extra_option_str)
203     build_android_x86_with_rm_and_bt(flag, extra_option_str)
204     build_android_x86_with_rm_and_ble(flag, extra_option_str)
205
206 def build_android_x86_with_rm_and_ip(flag, extra_option_str):
207     print ("*********** Build for android x86 with Routing Manager *************")
208     build_options = {
209                         'TARGET_OS':'android',
210                         'TARGET_ARCH':'x86',
211                         'ROUTING':'GW',
212                         'RELEASE':flag,
213                         'TARGET_TRANSPORT':'IP',
214                     }
215     call_scons(build_options, extra_option_str)
216
217 def build_android_x86_with_rm_and_bt(flag, extra_option_str):
218     print ("*********** Build for android x86 with Routing Manager and Bluetooth *************")
219     build_options = {
220                         'TARGET_OS':'android',
221                         'TARGET_ARCH':'x86',
222                         'ROUTING':'GW',
223                         'RELEASE':flag,
224                         'TARGET_TRANSPORT':'BT',
225                     }
226     call_scons(build_options, extra_option_str)
227
228 def build_android_x86_with_rm_and_ble(flag, extra_option_str):
229     print ("*********** Build for android x86 with Routing Manager and Bluetooth Low Energy *************")
230     build_options = {
231                         'TARGET_OS':'android',
232                         'TARGET_ARCH':'x86',
233                         'ROUTING':'GW',
234                         'RELEASE':flag,
235                         'TARGET_TRANSPORT':'BLE',
236                     }
237     call_scons(build_options, extra_option_str)
238
239 def build_android_armeabi(flag, extra_option_str):
240     """ Build Android Armeabi Suite """
241     build_android_armeabi_with_ip(flag, extra_option_str)
242     build_android_armeabi_with_bt(flag, extra_option_str)
243     build_android_armeabi_with_ble(flag, extra_option_str)
244
245 def build_android_armeabi_with_ip(flag, extra_option_str):
246     print ("*********** Build for android armeabi *************")
247     build_options = {
248                         'TARGET_OS':'android',
249                         'TARGET_ARCH':'armeabi',
250                         'RELEASE':flag,
251                         'TARGET_TRANSPORT':'IP',
252                     }
253     call_scons(build_options, extra_option_str)
254
255 def build_android_armeabi_with_bt(flag, extra_option_str):
256     print ("*********** Build for android armeabi with Bluetooth *************")
257     build_options = {
258                         'TARGET_OS':'android',
259                         'TARGET_ARCH':'armeabi',
260                         'RELEASE':flag,
261                         'TARGET_TRANSPORT':'BT',
262                     }
263     call_scons(build_options, extra_option_str)
264
265 def build_android_armeabi_with_ble(flag, extra_option_str):
266     print ("*********** Build for android armeabi with Bluetooth Low Energy *************")
267     build_options = {
268                         'TARGET_OS':'android',
269                         'TARGET_ARCH':'armeabi',
270                         'RELEASE':flag,
271                         'TARGET_TRANSPORT':'BLE',
272                     }
273     call_scons(build_options, extra_option_str)
274
275 def build_android_armeabi_with_rm(flag, extra_option_str):
276     """ Build Android Armeabi Routing Manager Suite """
277     build_android_armeabi_with_rm_and_ip(flag, extra_option_str)
278     build_android_armeabi_with_rm_and_bt(flag, extra_option_str)
279     build_android_armeabi_with_rm_and_ble(flag, extra_option_str)
280
281 def build_android_armeabi_with_rm_and_ip(flag, extra_option_str):
282     print ("*********** Build for android armeabi with Routing Manager *************")
283     build_options = {
284                         'TARGET_OS':'android',
285                         'TARGET_ARCH':'armeabi',
286                         'ROUTING':'GW',
287                         'RELEASE':flag,
288                         'TARGET_TRANSPORT':'IP',
289                     }
290     call_scons(build_options, extra_option_str)
291
292 def build_android_armeabi_with_rm_and_bt(flag, extra_option_str):
293     print ("*********** Build for android armeabi with Routing Manager and Bluetooth *************")
294     build_options = {
295                         'TARGET_OS':'android',
296                         'TARGET_ARCH':'armeabi',
297                         'ROUTING':'GW',
298                         'RELEASE':flag,
299                         'TARGET_TRANSPORT':'BT',
300                     }
301     call_scons(build_options, extra_option_str)
302
303 def build_android_armeabi_with_rm_and_ble(flag, extra_option_str):
304     print ("*********** Build for android armeabi with Routing Manager and Bluetooth Low Energy *************")
305     build_options = {
306                         'TARGET_OS':'android',
307                         'TARGET_ARCH':'armeabi',
308                         'ROUTING':'GW',
309                         'RELEASE':flag,
310                         'TARGET_TRANSPORT':'BLE',
311                     }
312     call_scons(build_options, extra_option_str)
313
314 def build_arduino(flag, extra_option_str):
315     print ("*********** Build for arduino avr *************")
316     extra_option_str = "resource " + extra_option_str
317     build_options = {
318                         'TARGET_OS':'arduino',
319                         'UPLOAD':'false',
320                         'BOARD':'mega',
321                         'TARGET_ARCH':'avr',
322                         'TARGET_TRANSPORT':'IP',
323                         'SHIELD':'ETH',
324                         'RELEASE':flag,
325                     }
326     call_scons(build_options, extra_option_str)
327
328     build_options['SHIELD'] = 'WIFI'
329     call_scons(build_options, extra_option_str)
330
331     build_options['TARGET_TRANSPORT'] = 'BLE'
332     build_options['SHIELD']           = 'RBL_NRF8001'
333     call_scons(build_options, extra_option_str)
334
335     print ("*********** Build for arduino arm *************")
336     build_options['BOARD']            = 'arduino_due_x'
337     build_options['TARGET_ARCH']      = 'arm'
338     build_options['TARGET_TRANSPORT'] = 'IP'
339     build_options['SHIELD']           = 'ETH'
340     call_scons(build_options, extra_option_str)
341
342     build_options['SHIELD'] = 'WIFI'
343     call_scons(build_options, extra_option_str)
344
345     # BLE support for the Arduino Due is currently unavailable.
346
347 def build_tizen(flag, extra_option_str):
348     print ("*********** Build for Tizen *************")
349     cmd_line = "/bin/sh " + os.getcwd() + "/gbsbuild.sh"
350     print ("Running : " + cmd_line)
351     subprocess.Popen([cmd_line], shell=True).wait()
352
353     print ("*********** Build for Tizen octbstack lib and sample *************")
354     extra_option_str = "-f resource/csdk/stack/samples/tizen/build/SConscript " + extra_option_str
355     build_options = {
356                         'TARGET_OS':'tizen',
357                         'TARGET_TRANSPORT':'IP',
358                         'LOGGING':'true',
359                         'RELEASE':flag,
360                     }
361     call_scons(build_options, extra_option_str)
362
363     print ("*********** Build for Tizen octbstack lib and sample with Security*************")
364     build_options['SECURED'] = 1
365     call_scons(build_options, extra_option_str)
366
367     print ("*********** Build for Tizen octbstack lib and sample with Routing Manager*************")
368     del build_options['SECURED']
369     build_options['ROUTING'] = 'GW'
370     call_scons(build_options, extra_option_str)
371
372 # Mac OS and iOS
373 def build_darwin(flag, extra_option_str):
374     print ("*********** Build for OSX *************")
375     build_options = {
376                         'TARGET_OS':'darwin',
377                         'SYS_VERSION':'10.9',
378                         'RELEASE':flag,
379                     }
380     call_scons(build_options, extra_option_str)
381
382     print ("*********** Build for IOS i386 *************")
383     build_options = {
384                         'TARGET_OS':'ios',
385                         'TARGET_ARCH':'i386',
386                         'SYS_VERSION':'7.0',
387                         'RELEASE':flag,
388                     }
389     call_scons(build_options, extra_option_str)
390
391     print ("*********** Build for IOS x86_64 *************")
392     build_options['TARGET_ARCH'] = 'x86_64'
393     call_scons(build_options, extra_option_str)
394
395     print ("*********** Build for IOS armv7 *************")
396     build_options['TARGET_ARCH'] = 'armv7'
397     call_scons(build_options, extra_option_str)
398
399     print ("*********** Build for IOS armv7s *************")
400     build_options['TARGET_ARCH'] = 'armv7s'
401     call_scons(build_options, extra_option_str)
402
403     print ("*********** Build for IOS arm64 *************")
404     build_options['TARGET_ARCH'] = 'arm64'
405     call_scons(build_options, extra_option_str)
406
407 # Windows
408 def build_windows(flag, extra_option_str):
409     print ("*********** Build for Windows *************")
410     os.environ["SCONSFLAGS"] = ""
411     build_options = {
412                         'TARGET_OS':'windows',
413                         'TARGET_ARCH':'amd64',
414                         'RELEASE':flag,
415                         'WITH_RA':0,
416                         'TARGET_TRANSPORT':'IP',
417                         'SECURED':1,
418                         'WITH_TCP':0,
419                         'BUILD_SAMPLE':'ON',
420                         'LOGGING':'off',
421                         'TEST':1,
422                         'WITH_RD':1,
423                     }
424     call_scons(build_options, extra_option_str)
425
426 # Windows msys
427 def build_msys(flag, extra_option_str):
428     print ("*********** Build for msys_nt *************")
429     os.environ["SCONSFLAGS"] = ""
430     build_options = {
431                         'TARGET_OS':'msys_nt',
432                         'TARGET_ARCH':'x86_64',
433                         'RELEASE':flag,
434                         'WITH_RA':0,
435                         'TARGET_TRANSPORT':'IP',
436                         'SECURED':1,
437                         'WITH_TCP':0,
438                         'BUILD_SAMPLE':'ON',
439                         'LOGGING':'off',
440                         'TEST':1,
441                         'WITH_RD':1,
442                     }
443     call_scons(build_options, extra_option_str)
444
445 def build_simulator(flag, extra_option_str):
446     print ("*********** Build for simulator plugin *************")
447     build_options = {
448                         'SIMULATOR':1,
449                         'RELEASE':flag,
450                     }
451     call_scons(build_options, extra_option_str)
452
453 def unit_tests():
454     print ("*********** Unit test Start *************")
455     build_options = {
456                         'RELEASE':'false',
457                     }
458     extra_option_str = "resource -c"
459     call_scons(build_options, extra_option_str)
460
461     build_options = {
462                         'LOGGING':'false',
463                         'RELEASE':'false',
464                     }
465     extra_option_str = "resource"
466     call_scons(build_options, extra_option_str)
467
468     build_options = {
469                         'TEST':1,
470                         'RELEASE':'false',
471                     }
472     extra_option_str = "resource"
473     call_scons(build_options, extra_option_str)
474
475     print ("*********** Unit test Stop *************")
476
477 # Main module starts here
478 if os.getenv("SCONSFLAGS", "") == "":
479     os.environ["SCONSFLAGS"] = "-Q -j " + str(multiprocessing.cpu_count())
480
481 arg_num     = len(sys.argv)
482 script_name = sys.argv[0]
483
484 # May be overridden in user's shell
485 VERBOSE = os.getenv("VERBOSE", "1")
486
487 if arg_num == 1:
488     build_all("true", "")
489     build_all("false", "")
490     unit_tests()
491
492 elif arg_num == 2:
493     if str(sys.argv[1]) == '-c':
494         build_all("true", "-c")
495         build_all("false", "-c")
496
497     elif str(sys.argv[1]) == "all":
498         build_all("true", "")
499         build_all("false", "")
500         unit_tests()
501
502     elif str(sys.argv[1]) == "linux":
503         build_linux("true", "")
504         build_linux("false", "")
505
506     elif str(sys.argv[1]) == "linux_unsecured":
507         build_linux_unsecured("true", "")
508         build_linux_unsecured("false", "")
509         build_linux_unsecured_with_rm("true", "")
510         build_linux_unsecured_with_rm("false", "")
511
512     elif str(sys.argv[1]) == "linux_secured":
513         build_linux_secured("true", "")
514         build_linux_secured("false", "")
515
516     elif str(sys.argv[1]) == "linux_unsecured_with_ra":
517         build_linux_unsecured_with_ra("true", "")
518         build_linux_unsecured_with_ra("false", "")
519
520     elif str(sys.argv[1]) == "linux_secured_with_ra":
521         build_linux_secured_with_ra("true", "")
522         build_linux_secured_with_ra("false", "")
523
524     elif str(sys.argv[1]) == "linux_unsecured_with_rd":
525         build_linux_unsecured_with_rd("true", "")
526         build_linux_unsecured_with_rd("false", "")
527
528     elif str(sys.argv[1]) == "linux_secured_with_rd":
529         build_linux_secured_with_rd("true", "")
530         build_linux_secured_with_rd("false", "")
531
532     elif str(sys.argv[1]) == "linux_unsecured_with_mq":
533         build_linux_unsecured_with_mq("true", "")
534         build_linux_unsecured_with_mq("false", "")
535
536     elif str(sys.argv[1]) == "linux_unsecured_with_tcp":
537         build_linux_unsecured_with_tcp("true", "")
538         build_linux_unsecured_with_tcp("false", "")
539
540     elif str(sys.argv[1]) == "android":
541         build_android("true", "")
542         build_android("false", "")
543
544     elif str(sys.argv[1]) == "android_x86":
545         build_android_x86("true", "")
546         build_android_x86("false", "")
547         build_android_x86_with_rm("true", "")
548         build_android_x86_with_rm("false", "")
549
550     elif str(sys.argv[1]) == "android_x86_with_ip":
551         build_android_x86_with_ip("true", "")
552         build_android_x86_with_ip("false", "")
553
554     elif str(sys.argv[1]) == "android_x86_with_bt":
555         build_android_x86_with_bt("true", "")
556         build_android_x86_with_bt("false", "")
557
558     elif str(sys.argv[1]) == "android_x86_with_ble":
559         build_android_x86_with_ble("true", "")
560         build_android_x86_with_ble("false", "")
561
562     elif str(sys.argv[1]) == "android_x86_with_rm_and_ip":
563         build_android_x86_with_rm_and_ip("true", "")
564         build_android_x86_with_rm_and_ip("false", "")
565
566     elif str(sys.argv[1]) == "android_x86_with_rm_and_bt":
567         build_android_x86_with_rm_and_bt("true", "")
568         build_android_x86_with_rm_and_bt("false", "")
569
570     elif str(sys.argv[1]) == "android_x86_with_rm_and_ble":
571         build_android_x86_with_rm_and_ble("true", "")
572         build_android_x86_with_rm_and_ble("false", "")
573
574     elif str(sys.argv[1]) == "android_armeabi":
575         build_android_armeabi("true", "")
576         build_android_armeabi("false", "")
577         build_android_armeabi_with_rm("true", "")
578         build_android_armeabi_with_rm("false", "")
579
580     elif str(sys.argv[1]) == "android_armeabi_with_ip":
581         build_android_armeabi_with_ip("true", "")
582         build_android_armeabi_with_ip("false", "")
583
584     elif str(sys.argv[1]) == "android_armeabi_with_bt":
585         build_android_armeabi_with_bt("true", "")
586         build_android_armeabi_with_bt("false", "")
587
588     elif str(sys.argv[1]) == "android_armeabi_with_ble":
589         build_android_armeabi_with_ble("true", "")
590         build_android_armeabi_with_ble("false", "")
591
592     elif str(sys.argv[1]) == "android_armeabi_with_rm_and_ip":
593         build_android_armeabi_with_rm_and_ip("true", "")
594         build_android_armeabi_with_rm_and_ip("false", "")
595
596     elif str(sys.argv[1]) == "android_armeabi_with_rm_and_bt":
597         build_android_armeabi_with_rm_and_bt("true", "")
598         build_android_armeabi_with_rm_and_bt("false", "")
599
600     elif str(sys.argv[1]) == "android_armeabi_with_rm_and_ble":
601         build_android_armeabi_with_rm_and_ble("true", "")
602         build_android_armeabi_with_rm_and_ble("false", "")
603
604     elif str(sys.argv[1]) == "arduino":
605         build_arduino("true", "")
606         build_arduino("false", "")
607
608     elif str(sys.argv[1]) == "windows":
609         build_windows("true", "")
610         build_windows("false", "")
611
612     elif str(sys.argv[1]) == "msys":
613         build_msys("true", "")
614         build_msys("false", "")
615
616     elif str(sys.argv[1]) == "tizen":
617         build_tizen("true", "")
618         build_tizen("false", "")
619
620     elif str(sys.argv[1]) == "simulator":
621         build_simulator("true", "")
622         build_simulator("false", "")
623
624     elif str(sys.argv[1]) == "darwin":
625         build_darwin("true", "")
626         build_darwin("false", "")
627
628     elif str(sys.argv[1]) == "unit_tests":
629         unit_tests()
630
631     else:
632         helpmsg(script_name)
633 else:
634         helpmsg(script_name)
635
636 print ("===================== done =====================")