1# 2# File : building.py 3# This file is part of RT-Thread RTOS 4# COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team 5# 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License along 17# with this program; if not, write to the Free Software Foundation, Inc., 18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19# 20# Change Logs: 21# Date Author Notes 22# 2015-01-20 Bernard Add copyright information 23# 2015-07-25 Bernard Add LOCAL_CCFLAGS/LOCAL_CPPPATH/LOCAL_CPPDEFINES for 24# group definition. 25# 26 27import os 28import sys 29import string 30import utils 31 32from SCons.Script import * 33from utils import _make_path_relative 34from mkdist import do_copy_file 35 36BuildOptions = {} 37Projects = [] 38Rtt_Root = '' 39Env = None 40 41# SCons PreProcessor patch 42def start_handling_includes(self, t=None): 43 """ 44 Causes the PreProcessor object to start processing #import, 45 #include and #include_next lines. 46 47 This method will be called when a #if, #ifdef, #ifndef or #elif 48 evaluates True, or when we reach the #else in a #if, #ifdef, 49 #ifndef or #elif block where a condition already evaluated 50 False. 51 52 """ 53 d = self.dispatch_table 54 p = self.stack[-1] if self.stack else self.default_table 55 56 for k in ('import', 'include', 'include_next', 'define'): 57 d[k] = p[k] 58 59def stop_handling_includes(self, t=None): 60 """ 61 Causes the PreProcessor object to stop processing #import, 62 #include and #include_next lines. 63 64 This method will be called when a #if, #ifdef, #ifndef or #elif 65 evaluates False, or when we reach the #else in a #if, #ifdef, 66 #ifndef or #elif block where a condition already evaluated True. 67 """ 68 d = self.dispatch_table 69 d['import'] = self.do_nothing 70 d['include'] = self.do_nothing 71 d['include_next'] = self.do_nothing 72 d['define'] = self.do_nothing 73 74PatchedPreProcessor = SCons.cpp.PreProcessor 75PatchedPreProcessor.start_handling_includes = start_handling_includes 76PatchedPreProcessor.stop_handling_includes = stop_handling_includes 77 78class Win32Spawn: 79 def spawn(self, sh, escape, cmd, args, env): 80 # deal with the cmd build-in commands which cannot be used in 81 # subprocess.Popen 82 if cmd == 'del': 83 for f in args[1:]: 84 try: 85 os.remove(f) 86 except Exception as e: 87 print ('Error removing file: ' + e) 88 return -1 89 return 0 90 91 import subprocess 92 93 newargs = ' '.join(args[1:]) 94 cmdline = cmd + " " + newargs 95 96 # Make sure the env is constructed by strings 97 _e = dict([(k, str(v)) for k, v in env.items()]) 98 99 # Windows(tm) CreateProcess does not use the env passed to it to find 100 # the executables. So we have to modify our own PATH to make Popen 101 # work. 102 old_path = os.environ['PATH'] 103 os.environ['PATH'] = _e['PATH'] 104 105 try: 106 proc = subprocess.Popen(cmdline, env=_e, shell=False) 107 except Exception as e: 108 print ('Error in calling command:' + cmdline.split(' ')[0]) 109 print ('Exception: ' + os.strerror(e.errno)) 110 if (os.strerror(e.errno) == "No such file or directory"): 111 print ("\nPlease check Toolchains PATH setting.\n") 112 113 return e.errno 114 finally: 115 os.environ['PATH'] = old_path 116 117 return proc.wait() 118 119# generate cconfig.h file 120def GenCconfigFile(env, BuildOptions): 121 import rtconfig 122 123 if rtconfig.PLATFORM == 'gcc': 124 contents = '' 125 if not os.path.isfile('cconfig.h'): 126 import gcc 127 gcc.GenerateGCCConfig(rtconfig) 128 129 # try again 130 if os.path.isfile('cconfig.h'): 131 f = open('cconfig.h', 'r') 132 if f: 133 contents = f.read() 134 f.close() 135 136 prep = PatchedPreProcessor() 137 prep.process_contents(contents) 138 options = prep.cpp_namespace 139 140 BuildOptions.update(options) 141 142 # add HAVE_CCONFIG_H definition 143 env.AppendUnique(CPPDEFINES = ['HAVE_CCONFIG_H']) 144 145def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = []): 146 import rtconfig 147 148 global BuildOptions 149 global Projects 150 global Env 151 global Rtt_Root 152 153 # ===== Add option to SCons ===== 154 AddOption('--dist', 155 dest = 'make-dist', 156 action = 'store_true', 157 default = False, 158 help = 'make distribution') 159 AddOption('--dist-strip', 160 dest = 'make-dist-strip', 161 action = 'store_true', 162 default = False, 163 help = 'make distribution and strip useless files') 164 AddOption('--cscope', 165 dest = 'cscope', 166 action = 'store_true', 167 default = False, 168 help = 'Build Cscope cross reference database. Requires cscope installed.') 169 AddOption('--clang-analyzer', 170 dest = 'clang-analyzer', 171 action = 'store_true', 172 default = False, 173 help = 'Perform static analyze with Clang-analyzer. ' + \ 174 'Requires Clang installed.\n' + \ 175 'It is recommended to use with scan-build like this:\n' + \ 176 '`scan-build scons --clang-analyzer`\n' + \ 177 'If things goes well, scan-build will instruct you to invoke scan-view.') 178 AddOption('--buildlib', 179 dest = 'buildlib', 180 type = 'string', 181 help = 'building library of a component') 182 AddOption('--cleanlib', 183 dest = 'cleanlib', 184 action = 'store_true', 185 default = False, 186 help = 'clean up the library by --buildlib') 187 AddOption('--target', 188 dest = 'target', 189 type = 'string', 190 help = 'set target project: mdk/mdk4/mdk5/iar/vs/vsc/ua/cdk/ses') 191 AddOption('--genconfig', 192 dest = 'genconfig', 193 action = 'store_true', 194 default = False, 195 help = 'Generate .config from rtconfig.h') 196 AddOption('--useconfig', 197 dest = 'useconfig', 198 type = 'string', 199 help = 'make rtconfig.h from config file.') 200 AddOption('--verbose', 201 dest = 'verbose', 202 action = 'store_true', 203 default = False, 204 help = 'print verbose information during build') 205 206 Env = env 207 Rtt_Root = os.path.abspath(root_directory) 208 209 # make an absolute root directory 210 RTT_ROOT = Rtt_Root 211 Export('RTT_ROOT') 212 213 # set RTT_ROOT in ENV 214 Env['RTT_ROOT'] = Rtt_Root 215 # set BSP_ROOT in ENV 216 Env['BSP_ROOT'] = Dir('#').abspath 217 218 sys.path = sys.path + [os.path.join(Rtt_Root, 'tools')] 219 220 # {target_name:(CROSS_TOOL, PLATFORM)} 221 tgt_dict = {'mdk':('keil', 'armcc'), 222 'mdk4':('keil', 'armcc'), 223 'mdk5':('keil', 'armcc'), 224 'iar':('iar', 'iar'), 225 'vs':('msvc', 'cl'), 226 'vs2012':('msvc', 'cl'), 227 'vsc' : ('gcc', 'gcc'), 228 'cb':('keil', 'armcc'), 229 'ua':('gcc', 'gcc'), 230 'cdk':('gcc', 'gcc'), 231 'ses' : ('gcc', 'gcc')} 232 tgt_name = GetOption('target') 233 234 if tgt_name: 235 # --target will change the toolchain settings which clang-analyzer is 236 # depend on 237 if GetOption('clang-analyzer'): 238 print ('--clang-analyzer cannot be used with --target') 239 sys.exit(1) 240 241 SetOption('no_exec', 1) 242 try: 243 rtconfig.CROSS_TOOL, rtconfig.PLATFORM = tgt_dict[tgt_name] 244 # replace the 'RTT_CC' to 'CROSS_TOOL' 245 os.environ['RTT_CC'] = rtconfig.CROSS_TOOL 246 utils.ReloadModule(rtconfig) 247 except KeyError: 248 print ('Unknow target: '+ tgt_name+'. Avaible targets: ' +', '.join(tgt_dict.keys())) 249 sys.exit(1) 250 elif (GetDepend('RT_USING_NEWLIB') == False and GetDepend('RT_USING_NOLIBC') == False) \ 251 and rtconfig.PLATFORM == 'gcc': 252 AddDepend('RT_USING_MINILIBC') 253 254 # auto change the 'RTT_EXEC_PATH' when 'rtconfig.EXEC_PATH' get failed 255 if not os.path.exists(rtconfig.EXEC_PATH): 256 if 'RTT_EXEC_PATH' in os.environ: 257 # del the 'RTT_EXEC_PATH' and using the 'EXEC_PATH' setting on rtconfig.py 258 del os.environ['RTT_EXEC_PATH'] 259 utils.ReloadModule(rtconfig) 260 261 # add compability with Keil MDK 4.6 which changes the directory of armcc.exe 262 if rtconfig.PLATFORM == 'armcc': 263 if not os.path.isfile(os.path.join(rtconfig.EXEC_PATH, 'armcc.exe')): 264 if rtconfig.EXEC_PATH.find('bin40') > 0: 265 rtconfig.EXEC_PATH = rtconfig.EXEC_PATH.replace('bin40', 'armcc/bin') 266 Env['LINKFLAGS'] = Env['LINKFLAGS'].replace('RV31', 'armcc') 267 268 # reset AR command flags 269 env['ARCOM'] = '$AR --create $TARGET $SOURCES' 270 env['LIBPREFIX'] = '' 271 env['LIBSUFFIX'] = '.lib' 272 env['LIBLINKPREFIX'] = '' 273 env['LIBLINKSUFFIX'] = '.lib' 274 env['LIBDIRPREFIX'] = '--userlibpath ' 275 276 elif rtconfig.PLATFORM == 'iar': 277 env['LIBPREFIX'] = '' 278 env['LIBSUFFIX'] = '.a' 279 env['LIBLINKPREFIX'] = '' 280 env['LIBLINKSUFFIX'] = '.a' 281 env['LIBDIRPREFIX'] = '--search ' 282 283 # patch for win32 spawn 284 if env['PLATFORM'] == 'win32': 285 win32_spawn = Win32Spawn() 286 win32_spawn.env = env 287 env['SPAWN'] = win32_spawn.spawn 288 289 if env['PLATFORM'] == 'win32': 290 os.environ['PATH'] = rtconfig.EXEC_PATH + ";" + os.environ['PATH'] 291 else: 292 os.environ['PATH'] = rtconfig.EXEC_PATH + ":" + os.environ['PATH'] 293 294 # add program path 295 env.PrependENVPath('PATH', rtconfig.EXEC_PATH) 296 # add rtconfig.h/BSP path into Kernel group 297 DefineGroup("Kernel", [], [], CPPPATH=[str(Dir('#').abspath)]) 298 299 # add library build action 300 act = SCons.Action.Action(BuildLibInstallAction, 'Install compiled library... $TARGET') 301 bld = Builder(action = act) 302 Env.Append(BUILDERS = {'BuildLib': bld}) 303 304 # parse rtconfig.h to get used component 305 PreProcessor = PatchedPreProcessor() 306 f = open('rtconfig.h', 'r') 307 contents = f.read() 308 f.close() 309 PreProcessor.process_contents(contents) 310 BuildOptions = PreProcessor.cpp_namespace 311 312 if GetOption('clang-analyzer'): 313 # perform what scan-build does 314 env.Replace( 315 CC = 'ccc-analyzer', 316 CXX = 'c++-analyzer', 317 # skip as and link 318 LINK = 'true', 319 AS = 'true',) 320 env["ENV"].update(x for x in os.environ.items() if x[0].startswith("CCC_")) 321 # only check, don't compile. ccc-analyzer use CCC_CC as the CC. 322 # fsyntax-only will give us some additional warning messages 323 env['ENV']['CCC_CC'] = 'clang' 324 env.Append(CFLAGS=['-fsyntax-only', '-Wall', '-Wno-invalid-source-encoding']) 325 env['ENV']['CCC_CXX'] = 'clang++' 326 env.Append(CXXFLAGS=['-fsyntax-only', '-Wall', '-Wno-invalid-source-encoding']) 327 # remove the POST_ACTION as it will cause meaningless errors(file not 328 # found or something like that). 329 rtconfig.POST_ACTION = '' 330 331 # generate cconfig.h file 332 GenCconfigFile(env, BuildOptions) 333 334 # auto append '_REENT_SMALL' when using newlib 'nano.specs' option 335 if rtconfig.PLATFORM == 'gcc' and str(env['LINKFLAGS']).find('nano.specs') != -1: 336 env.AppendUnique(CPPDEFINES = ['_REENT_SMALL']) 337 338 if GetOption('genconfig'): 339 from genconf import genconfig 340 genconfig() 341 exit(0) 342 343 if env['PLATFORM'] != 'win32': 344 AddOption('--menuconfig', 345 dest = 'menuconfig', 346 action = 'store_true', 347 default = False, 348 help = 'make menuconfig for RT-Thread BSP') 349 if GetOption('menuconfig'): 350 from menuconfig import menuconfig 351 menuconfig(Rtt_Root) 352 exit(0) 353 354 AddOption('--pyconfig', 355 dest = 'pyconfig', 356 action = 'store_true', 357 default = False, 358 help = 'make menuconfig for RT-Thread BSP') 359 AddOption('--pyconfig-silent', 360 dest = 'pyconfig_silent', 361 action = 'store_true', 362 default = False, 363 help = 'Don`t show pyconfig window') 364 365 if GetOption('pyconfig_silent'): 366 from menuconfig import pyconfig_silent 367 368 pyconfig_silent(Rtt_Root) 369 exit(0) 370 elif GetOption('pyconfig'): 371 from menuconfig import pyconfig 372 373 pyconfig(Rtt_Root) 374 exit(0) 375 376 configfn = GetOption('useconfig') 377 if configfn: 378 from menuconfig import mk_rtconfig 379 mk_rtconfig(configfn) 380 exit(0) 381 382 383 if not GetOption('verbose'): 384 # override the default verbose command string 385 env.Replace( 386 ARCOMSTR = 'AR $TARGET', 387 ASCOMSTR = 'AS $TARGET', 388 ASPPCOMSTR = 'AS $TARGET', 389 CCCOMSTR = 'CC $TARGET', 390 CXXCOMSTR = 'CXX $TARGET', 391 LINKCOMSTR = 'LINK $TARGET' 392 ) 393 394 # fix the linker for C++ 395 if GetDepend('RT_USING_CPLUSPLUS'): 396 if env['LINK'].find('gcc') != -1: 397 env['LINK'] = env['LINK'].replace('gcc', 'g++') 398 399 # we need to seperate the variant_dir for BSPs and the kernels. BSPs could 400 # have their own components etc. If they point to the same folder, SCons 401 # would find the wrong source code to compile. 402 bsp_vdir = 'build' 403 kernel_vdir = 'build/kernel' 404 # board build script 405 objs = SConscript('SConscript', variant_dir=bsp_vdir, duplicate=0) 406 # include kernel 407 objs.extend(SConscript(Rtt_Root + '/src/SConscript', variant_dir=kernel_vdir + '/src', duplicate=0)) 408 # include libcpu 409 if not has_libcpu: 410 objs.extend(SConscript(Rtt_Root + '/libcpu/SConscript', 411 variant_dir=kernel_vdir + '/libcpu', duplicate=0)) 412 413 # include components 414 objs.extend(SConscript(Rtt_Root + '/components/SConscript', 415 variant_dir=kernel_vdir + '/components', 416 duplicate=0, 417 exports='remove_components')) 418 419 return objs 420 421def PrepareModuleBuilding(env, root_directory, bsp_directory): 422 import rtconfig 423 424 global BuildOptions 425 global Env 426 global Rtt_Root 427 428 # patch for win32 spawn 429 if env['PLATFORM'] == 'win32': 430 win32_spawn = Win32Spawn() 431 win32_spawn.env = env 432 env['SPAWN'] = win32_spawn.spawn 433 434 Env = env 435 Rtt_Root = root_directory 436 437 # parse bsp rtconfig.h to get used component 438 PreProcessor = PatchedPreProcessor() 439 f = open(bsp_directory + '/rtconfig.h', 'r') 440 contents = f.read() 441 f.close() 442 PreProcessor.process_contents(contents) 443 BuildOptions = PreProcessor.cpp_namespace 444 445 # add build/clean library option for library checking 446 AddOption('--buildlib', 447 dest='buildlib', 448 type='string', 449 help='building library of a component') 450 AddOption('--cleanlib', 451 dest='cleanlib', 452 action='store_true', 453 default=False, 454 help='clean up the library by --buildlib') 455 456 # add program path 457 env.PrependENVPath('PATH', rtconfig.EXEC_PATH) 458 459def GetConfigValue(name): 460 assert type(name) == str, 'GetConfigValue: only string parameter is valid' 461 try: 462 return BuildOptions[name] 463 except: 464 return '' 465 466def GetDepend(depend): 467 building = True 468 if type(depend) == type('str'): 469 if not depend in BuildOptions or BuildOptions[depend] == 0: 470 building = False 471 elif BuildOptions[depend] != '': 472 return BuildOptions[depend] 473 474 return building 475 476 # for list type depend 477 for item in depend: 478 if item != '': 479 if not item in BuildOptions or BuildOptions[item] == 0: 480 building = False 481 482 return building 483 484def LocalOptions(config_filename): 485 from SCons.Script import SCons 486 487 # parse wiced_config.h to get used component 488 PreProcessor = SCons.cpp.PreProcessor() 489 490 f = open(config_filename, 'r') 491 contents = f.read() 492 f.close() 493 494 PreProcessor.process_contents(contents) 495 local_options = PreProcessor.cpp_namespace 496 497 return local_options 498 499def GetLocalDepend(options, depend): 500 building = True 501 if type(depend) == type('str'): 502 if not depend in options or options[depend] == 0: 503 building = False 504 elif options[depend] != '': 505 return options[depend] 506 507 return building 508 509 # for list type depend 510 for item in depend: 511 if item != '': 512 if not item in options or options[item] == 0: 513 building = False 514 515 return building 516 517def AddDepend(option): 518 BuildOptions[option] = 1 519 520def MergeGroup(src_group, group): 521 src_group['src'] = src_group['src'] + group['src'] 522 if 'CCFLAGS' in group: 523 if 'CCFLAGS' in src_group: 524 src_group['CCFLAGS'] = src_group['CCFLAGS'] + group['CCFLAGS'] 525 else: 526 src_group['CCFLAGS'] = group['CCFLAGS'] 527 if 'CPPPATH' in group: 528 if 'CPPPATH' in src_group: 529 src_group['CPPPATH'] = src_group['CPPPATH'] + group['CPPPATH'] 530 else: 531 src_group['CPPPATH'] = group['CPPPATH'] 532 if 'CPPDEFINES' in group: 533 if 'CPPDEFINES' in src_group: 534 src_group['CPPDEFINES'] = src_group['CPPDEFINES'] + group['CPPDEFINES'] 535 else: 536 src_group['CPPDEFINES'] = group['CPPDEFINES'] 537 if 'ASFLAGS' in group: 538 if 'ASFLAGS' in src_group: 539 src_group['ASFLAGS'] = src_group['ASFLAGS'] + group['ASFLAGS'] 540 else: 541 src_group['ASFLAGS'] = group['ASFLAGS'] 542 543 # for local CCFLAGS/CPPPATH/CPPDEFINES 544 if 'LOCAL_CCFLAGS' in group: 545 if 'LOCAL_CCFLAGS' in src_group: 546 src_group['LOCAL_CCFLAGS'] = src_group['LOCAL_CCFLAGS'] + group['LOCAL_CCFLAGS'] 547 else: 548 src_group['LOCAL_CCFLAGS'] = group['LOCAL_CCFLAGS'] 549 if 'LOCAL_CPPPATH' in group: 550 if 'LOCAL_CPPPATH' in src_group: 551 src_group['LOCAL_CPPPATH'] = src_group['LOCAL_CPPPATH'] + group['LOCAL_CPPPATH'] 552 else: 553 src_group['LOCAL_CPPPATH'] = group['LOCAL_CPPPATH'] 554 if 'LOCAL_CPPDEFINES' in group: 555 if 'LOCAL_CPPDEFINES' in src_group: 556 src_group['LOCAL_CPPDEFINES'] = src_group['LOCAL_CPPDEFINES'] + group['LOCAL_CPPDEFINES'] 557 else: 558 src_group['LOCAL_CPPDEFINES'] = group['LOCAL_CPPDEFINES'] 559 560 if 'LINKFLAGS' in group: 561 if 'LINKFLAGS' in src_group: 562 src_group['LINKFLAGS'] = src_group['LINKFLAGS'] + group['LINKFLAGS'] 563 else: 564 src_group['LINKFLAGS'] = group['LINKFLAGS'] 565 if 'LIBS' in group: 566 if 'LIBS' in src_group: 567 src_group['LIBS'] = src_group['LIBS'] + group['LIBS'] 568 else: 569 src_group['LIBS'] = group['LIBS'] 570 if 'LIBPATH' in group: 571 if 'LIBPATH' in src_group: 572 src_group['LIBPATH'] = src_group['LIBPATH'] + group['LIBPATH'] 573 else: 574 src_group['LIBPATH'] = group['LIBPATH'] 575 if 'LOCAL_ASFLAGS' in group: 576 if 'LOCAL_ASFLAGS' in src_group: 577 src_group['LOCAL_ASFLAGS'] = src_group['LOCAL_ASFLAGS'] + group['LOCAL_ASFLAGS'] 578 else: 579 src_group['LOCAL_ASFLAGS'] = group['LOCAL_ASFLAGS'] 580 581def DefineGroup(name, src, depend, **parameters): 582 global Env 583 if not GetDepend(depend): 584 return [] 585 586 # find exist group and get path of group 587 group_path = '' 588 for g in Projects: 589 if g['name'] == name: 590 group_path = g['path'] 591 if group_path == '': 592 group_path = GetCurrentDir() 593 594 group = parameters 595 group['name'] = name 596 group['path'] = group_path 597 if type(src) == type([]): 598 group['src'] = File(src) 599 else: 600 group['src'] = src 601 602 if 'CCFLAGS' in group: 603 Env.AppendUnique(CCFLAGS = group['CCFLAGS']) 604 if 'CPPPATH' in group: 605 paths = [] 606 for item in group['CPPPATH']: 607 paths.append(os.path.abspath(item)) 608 group['CPPPATH'] = paths 609 Env.AppendUnique(CPPPATH = group['CPPPATH']) 610 if 'CPPDEFINES' in group: 611 Env.AppendUnique(CPPDEFINES = group['CPPDEFINES']) 612 if 'LINKFLAGS' in group: 613 Env.AppendUnique(LINKFLAGS = group['LINKFLAGS']) 614 if 'ASFLAGS' in group: 615 Env.AppendUnique(ASFLAGS = group['ASFLAGS']) 616 if 'LOCAL_CPPPATH' in group: 617 paths = [] 618 for item in group['LOCAL_CPPPATH']: 619 paths.append(os.path.abspath(item)) 620 group['LOCAL_CPPPATH'] = paths 621 622 import rtconfig 623 if rtconfig.PLATFORM == 'gcc': 624 if 'CCFLAGS' in group: 625 group['CCFLAGS'] = utils.GCCC99Patch(group['CCFLAGS']) 626 if 'LOCAL_CCFLAGS' in group: 627 group['LOCAL_CCFLAGS'] = utils.GCCC99Patch(group['LOCAL_CCFLAGS']) 628 629 # check whether to clean up library 630 if GetOption('cleanlib') and os.path.exists(os.path.join(group['path'], GroupLibFullName(name, Env))): 631 if group['src'] != []: 632 print ('Remove library:'+ GroupLibFullName(name, Env)) 633 fn = os.path.join(group['path'], GroupLibFullName(name, Env)) 634 if os.path.exists(fn): 635 os.unlink(fn) 636 637 if 'LIBS' in group: 638 Env.AppendUnique(LIBS = group['LIBS']) 639 if 'LIBPATH' in group: 640 Env.AppendUnique(LIBPATH = group['LIBPATH']) 641 642 # check whether to build group library 643 if 'LIBRARY' in group: 644 objs = Env.Library(name, group['src']) 645 else: 646 # only add source 647 objs = group['src'] 648 649 # merge group 650 for g in Projects: 651 if g['name'] == name: 652 # merge to this group 653 MergeGroup(g, group) 654 return objs 655 656 # add a new group 657 Projects.append(group) 658 659 return objs 660 661def GetCurrentDir(): 662 conscript = File('SConscript') 663 fn = conscript.rfile() 664 name = fn.name 665 path = os.path.dirname(fn.abspath) 666 return path 667 668PREBUILDING = [] 669def RegisterPreBuildingAction(act): 670 global PREBUILDING 671 assert callable(act), 'Could only register callable objects. %s received' % repr(act) 672 PREBUILDING.append(act) 673 674def PreBuilding(): 675 global PREBUILDING 676 for a in PREBUILDING: 677 a() 678 679def GroupLibName(name, env): 680 import rtconfig 681 if rtconfig.PLATFORM == 'armcc': 682 return name + '_rvds' 683 elif rtconfig.PLATFORM == 'gcc': 684 return name + '_gcc' 685 686 return name 687 688def GroupLibFullName(name, env): 689 return env['LIBPREFIX'] + GroupLibName(name, env) + env['LIBSUFFIX'] 690 691def BuildLibInstallAction(target, source, env): 692 lib_name = GetOption('buildlib') 693 for Group in Projects: 694 if Group['name'] == lib_name: 695 lib_name = GroupLibFullName(Group['name'], env) 696 dst_name = os.path.join(Group['path'], lib_name) 697 print ('Copy '+lib_name+' => ' +dst_name) 698 do_copy_file(lib_name, dst_name) 699 break 700 701def DoBuilding(target, objects): 702 703 # merge all objects into one list 704 def one_list(l): 705 lst = [] 706 for item in l: 707 if type(item) == type([]): 708 lst += one_list(item) 709 else: 710 lst.append(item) 711 return lst 712 713 # handle local group 714 def local_group(group, objects): 715 if 'LOCAL_CCFLAGS' in group or 'LOCAL_CPPPATH' in group or 'LOCAL_CPPDEFINES' in group or 'LOCAL_ASFLAGS' in group: 716 CCFLAGS = Env.get('CCFLAGS', '') + group.get('LOCAL_CCFLAGS', '') 717 CPPPATH = Env.get('CPPPATH', ['']) + group.get('LOCAL_CPPPATH', ['']) 718 CPPDEFINES = Env.get('CPPDEFINES', ['']) + group.get('LOCAL_CPPDEFINES', ['']) 719 ASFLAGS = Env.get('ASFLAGS', '') + group.get('LOCAL_ASFLAGS', '') 720 721 for source in group['src']: 722 objects.append(Env.Object(source, CCFLAGS = CCFLAGS, ASFLAGS = ASFLAGS, 723 CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES)) 724 725 return True 726 727 return False 728 729 objects = one_list(objects) 730 731 program = None 732 # check whether special buildlib option 733 lib_name = GetOption('buildlib') 734 if lib_name: 735 objects = [] # remove all of objects 736 # build library with special component 737 for Group in Projects: 738 if Group['name'] == lib_name: 739 lib_name = GroupLibName(Group['name'], Env) 740 if not local_group(Group, objects): 741 objects = Env.Object(Group['src']) 742 743 program = Env.Library(lib_name, objects) 744 745 # add library copy action 746 Env.BuildLib(lib_name, program) 747 748 break 749 else: 750 # remove source files with local flags setting 751 for group in Projects: 752 if 'LOCAL_CCFLAGS' in group or 'LOCAL_CPPPATH' in group or 'LOCAL_CPPDEFINES' in group: 753 for source in group['src']: 754 for obj in objects: 755 if source.abspath == obj.abspath or (len(obj.sources) > 0 and source.abspath == obj.sources[0].abspath): 756 objects.remove(obj) 757 758 # re-add the source files to the objects 759 for group in Projects: 760 local_group(group, objects) 761 762 program = Env.Program(target, objects) 763 764 EndBuilding(target, program) 765 766def GenTargetProject(program = None): 767 768 if GetOption('target') == 'mdk': 769 from keil import MDKProject 770 from keil import MDK4Project 771 from keil import MDK5Project 772 773 template = os.path.isfile('template.Uv2') 774 if template: 775 MDKProject('project.Uv2', Projects) 776 else: 777 template = os.path.isfile('template.uvproj') 778 if template: 779 MDK4Project('project.uvproj', Projects) 780 else: 781 template = os.path.isfile('template.uvprojx') 782 if template: 783 MDK5Project('project.uvprojx', Projects) 784 else: 785 print ('No template project file found.') 786 787 if GetOption('target') == 'mdk4': 788 from keil import MDK4Project 789 MDK4Project('project.uvproj', Projects) 790 791 if GetOption('target') == 'mdk5': 792 from keil import MDK5Project 793 MDK5Project('project.uvprojx', Projects) 794 795 if GetOption('target') == 'iar': 796 from iar import IARProject 797 IARProject('project.ewp', Projects) 798 799 if GetOption('target') == 'vs': 800 from vs import VSProject 801 VSProject('project.vcproj', Projects, program) 802 803 if GetOption('target') == 'vs2012': 804 from vs2012 import VS2012Project 805 VS2012Project('project.vcxproj', Projects, program) 806 807 if GetOption('target') == 'cb': 808 from codeblocks import CBProject 809 CBProject('project.cbp', Projects, program) 810 811 if GetOption('target') == 'ua': 812 from ua import PrepareUA 813 PrepareUA(Projects, Rtt_Root, str(Dir('#'))) 814 815 if GetOption('target') == 'vsc': 816 from vsc import GenerateVSCode 817 GenerateVSCode(Env) 818 819 if GetOption('target') == 'cdk': 820 from cdk import CDKProject 821 CDKProject('project.cdkproj', Projects) 822 823 if GetOption('target') == 'ses': 824 from ses import SESProject 825 SESProject(Env) 826 827def EndBuilding(target, program = None): 828 import rtconfig 829 830 need_exit = False 831 832 Env['target'] = program 833 Env['project'] = Projects 834 835 if hasattr(rtconfig, 'BSP_LIBRARY_TYPE'): 836 Env['bsp_lib_type'] = rtconfig.BSP_LIBRARY_TYPE 837 838 if hasattr(rtconfig, 'dist_handle'): 839 Env['dist_handle'] = rtconfig.dist_handle 840 841 Env.AddPostAction(target, rtconfig.POST_ACTION) 842 # Add addition clean files 843 Clean(target, 'cconfig.h') 844 Clean(target, 'rtua.py') 845 Clean(target, 'rtua.pyc') 846 847 if GetOption('target'): 848 GenTargetProject(program) 849 850 BSP_ROOT = Dir('#').abspath 851 if GetOption('make-dist') and program != None: 852 from mkdist import MkDist 853 MkDist(program, BSP_ROOT, Rtt_Root, Env) 854 if GetOption('make-dist-strip') and program != None: 855 from mkdist import MkDist_Strip 856 MkDist_Strip(program, BSP_ROOT, Rtt_Root, Env) 857 need_exit = True 858 if GetOption('cscope'): 859 from cscope import CscopeDatabase 860 CscopeDatabase(Projects) 861 862 if not GetOption('help') and not GetOption('target'): 863 if not os.path.exists(rtconfig.EXEC_PATH): 864 print ("Error: the toolchain path (" + rtconfig.EXEC_PATH + ") is not exist, please check 'EXEC_PATH' in path or rtconfig.py.") 865 need_exit = True 866 867 if need_exit: 868 exit(0) 869 870def SrcRemove(src, remove): 871 if not src: 872 return 873 874 src_bak = src[:] 875 876 if type(remove) == type('str'): 877 if os.path.isabs(remove): 878 remove = os.path.relpath(remove, GetCurrentDir()) 879 remove = os.path.normpath(remove) 880 881 for item in src_bak: 882 if type(item) == type('str'): 883 item_str = item 884 else: 885 item_str = item.rstr() 886 887 if os.path.isabs(item_str): 888 item_str = os.path.relpath(item_str, GetCurrentDir()) 889 item_str = os.path.normpath(item_str) 890 891 if item_str == remove: 892 src.remove(item) 893 else: 894 for remove_item in remove: 895 remove_str = str(remove_item) 896 if os.path.isabs(remove_str): 897 remove_str = os.path.relpath(remove_str, GetCurrentDir()) 898 remove_str = os.path.normpath(remove_str) 899 900 for item in src_bak: 901 if type(item) == type('str'): 902 item_str = item 903 else: 904 item_str = item.rstr() 905 906 if os.path.isabs(item_str): 907 item_str = os.path.relpath(item_str, GetCurrentDir()) 908 item_str = os.path.normpath(item_str) 909 910 if item_str == remove_str: 911 src.remove(item) 912 913def GetVersion(): 914 import SCons.cpp 915 import string 916 917 rtdef = os.path.join(Rtt_Root, 'include', 'rtdef.h') 918 919 # parse rtdef.h to get RT-Thread version 920 prepcessor = PatchedPreProcessor() 921 f = open(rtdef, 'r') 922 contents = f.read() 923 f.close() 924 prepcessor.process_contents(contents) 925 def_ns = prepcessor.cpp_namespace 926 927 version = int(filter(lambda ch: ch in '0123456789.', def_ns['RT_VERSION'])) 928 subversion = int(filter(lambda ch: ch in '0123456789.', def_ns['RT_SUBVERSION'])) 929 930 if 'RT_REVISION' in def_ns: 931 revision = int(filter(lambda ch: ch in '0123456789.', def_ns['RT_REVISION'])) 932 return '%d.%d.%d' % (version, subversion, revision) 933 934 return '0.%d.%d' % (version, subversion) 935 936def GlobSubDir(sub_dir, ext_name): 937 import os 938 import glob 939 940 def glob_source(sub_dir, ext_name): 941 list = os.listdir(sub_dir) 942 src = glob.glob(os.path.join(sub_dir, ext_name)) 943 944 for item in list: 945 full_subdir = os.path.join(sub_dir, item) 946 if os.path.isdir(full_subdir): 947 src += glob_source(full_subdir, ext_name) 948 return src 949 950 dst = [] 951 src = glob_source(sub_dir, ext_name) 952 for item in src: 953 dst.append(os.path.relpath(item, sub_dir)) 954 return dst 955 956def PackageSConscript(package): 957 from package import BuildPackage 958 959 return BuildPackage(package) 960