building.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. import os
  2. import sys
  3. import string
  4. from SCons.Script import *
  5. from utils import _make_path_relative
  6. BuildOptions = {}
  7. Projects = []
  8. Rtt_Root = ''
  9. Env = None
  10. class Win32Spawn:
  11. def spawn(self, sh, escape, cmd, args, env):
  12. import subprocess
  13. newargs = string.join(args[1:], ' ')
  14. cmdline = cmd + " " + newargs
  15. startupinfo = subprocess.STARTUPINFO()
  16. proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
  17. stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False)
  18. data, err = proc.communicate()
  19. rv = proc.wait()
  20. if data:
  21. print data
  22. if err:
  23. print err
  24. if rv:
  25. return rv
  26. return 0
  27. def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = []):
  28. import SCons.cpp
  29. import rtconfig
  30. global BuildOptions
  31. global Projects
  32. global Env
  33. global Rtt_Root
  34. Env = env
  35. Rtt_Root = root_directory
  36. # add compability with Keil MDK 4.6 which changes the directory of armcc.exe
  37. if rtconfig.PLATFORM == 'armcc':
  38. if not os.path.isfile(os.path.join(rtconfig.EXEC_PATH, 'armcc.exe')):
  39. if rtconfig.EXEC_PATH.find('bin40') > 0:
  40. rtconfig.EXEC_PATH = rtconfig.EXEC_PATH.replace('bin40', 'armcc/bin')
  41. Env['LINKFLAGS']=Env['LINKFLAGS'].replace('RV31', 'armcc')
  42. # reset AR command flags
  43. env['ARCOM'] = '$AR --create $TARGET $SOURCES'
  44. env['LIBPREFIX'] = ''
  45. env['LIBSUFFIX'] = '_rvds.lib'
  46. # patch for win32 spawn
  47. if env['PLATFORM'] == 'win32' and rtconfig.PLATFORM == 'gcc':
  48. win32_spawn = Win32Spawn()
  49. win32_spawn.env = env
  50. env['SPAWN'] = win32_spawn.spawn
  51. if env['PLATFORM'] == 'win32':
  52. os.environ['PATH'] = rtconfig.EXEC_PATH + ";" + os.environ['PATH']
  53. else:
  54. os.environ['PATH'] = rtconfig.EXEC_PATH + ":" + os.environ['PATH']
  55. # add program path
  56. env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
  57. # parse rtconfig.h to get used component
  58. PreProcessor = SCons.cpp.PreProcessor()
  59. f = file('rtconfig.h', 'r')
  60. contents = f.read()
  61. f.close()
  62. PreProcessor.process_contents(contents)
  63. BuildOptions = PreProcessor.cpp_namespace
  64. # add copy option
  65. AddOption('--copy',
  66. dest='copy',
  67. action='store_true',
  68. default=False,
  69. help='copy rt-thread directory to local.')
  70. AddOption('--copy-header',
  71. dest='copy-header',
  72. action='store_true',
  73. default=False,
  74. help='copy header of rt-thread directory to local.')
  75. AddOption('--cscope',
  76. dest='cscope',
  77. action='store_true',
  78. default=False,
  79. help='Build Cscope cross reference database. Requires cscope installed.')
  80. AddOption('--clang-analyzer',
  81. dest='clang-analyzer',
  82. action='store_true',
  83. default=False,
  84. help='Perform static analyze with Clang-analyzer. '+\
  85. 'Requires Clang installed.\n'+\
  86. 'It is recommended to use with scan-build like this:\n'+\
  87. '`scan-build scons --clang-analyzer`\n'+\
  88. 'If things goes well, scan-build will instruct you to invoke scan-view.')
  89. if GetOption('clang-analyzer'):
  90. # perform what scan-build does
  91. env.Replace(
  92. CC = 'ccc-analyzer',
  93. CXX = 'c++-analyzer',
  94. # skip as and link
  95. LINK = 'true',
  96. AS = 'true',)
  97. env["ENV"].update(x for x in os.environ.items() if x[0].startswith("CCC_"))
  98. # only check, don't compile. ccc-analyzer use CCC_CC as the CC.
  99. # fsyntax-only will give us some additional warning messages
  100. env['ENV']['CCC_CC'] = 'clang'
  101. env.Append(CFLAGS=['-fsyntax-only', '-Wall', '-Wno-invalid-source-encoding'])
  102. env['ENV']['CCC_CXX'] = 'clang++'
  103. env.Append(CXXFLAGS=['-fsyntax-only', '-Wall', '-Wno-invalid-source-encoding'])
  104. # remove the POST_ACTION as it will cause meaningless errors(file not
  105. # found or something like that).
  106. rtconfig.POST_ACTION = ''
  107. # add build library option
  108. AddOption('--buildlib',
  109. dest='buildlib',
  110. type='string',
  111. help='building library of a component')
  112. # add target option
  113. AddOption('--target',
  114. dest='target',
  115. type='string',
  116. help='set target project: mdk')
  117. #{target_name:(CROSS_TOOL, PLATFORM)}
  118. tgt_dict = {'mdk':('keil', 'armcc'),
  119. 'mdk4':('keil', 'armcc'),
  120. 'iar':('iar', 'iar'),
  121. 'vs':('msvc', 'cl'),
  122. 'vs2012':('msvc', 'cl'),
  123. 'cb':('keil', 'armcc')}
  124. tgt_name = GetOption('target')
  125. if tgt_name:
  126. # --target will change the toolchain settings which clang-analyzer is
  127. # depend on
  128. if GetOption('clang-analyzer'):
  129. print '--clang-analyzer cannot be used with --target'
  130. sys.exit(1)
  131. SetOption('no_exec', 1)
  132. try:
  133. rtconfig.CROSS_TOOL, rtconfig.PLATFORM = tgt_dict[tgt_name]
  134. except KeyError:
  135. print 'Unknow target: %s. Avaible targets: %s' % \
  136. (tgt_name, ', '.join(tgt_dict.keys()))
  137. sys.exit(1)
  138. elif (GetDepend('RT_USING_NEWLIB') == False and GetDepend('RT_USING_NOLIBC') == False) \
  139. and rtconfig.PLATFORM == 'gcc':
  140. AddDepend('RT_USING_MINILIBC')
  141. # add comstr option
  142. AddOption('--verbose',
  143. dest='verbose',
  144. action='store_true',
  145. default=False,
  146. help='print verbose information during build')
  147. if not GetOption('verbose'):
  148. # override the default verbose command string
  149. env.Replace(
  150. ARCOMSTR = 'AR $TARGET',
  151. ASCOMSTR = 'AS $TARGET',
  152. ASPPCOMSTR = 'AS $TARGET',
  153. CCCOMSTR = 'CC $TARGET',
  154. CXXCOMSTR = 'CXX $TARGET',
  155. LINKCOMSTR = 'LINK $TARGET'
  156. )
  157. # board build script
  158. objs = SConscript('SConscript', variant_dir='build', duplicate=0)
  159. Repository(Rtt_Root)
  160. # include kernel
  161. objs.extend(SConscript(Rtt_Root + '/src/SConscript', variant_dir='build/src', duplicate=0))
  162. # include libcpu
  163. if not has_libcpu:
  164. objs.extend(SConscript(Rtt_Root + '/libcpu/SConscript', variant_dir='build/libcpu', duplicate=0))
  165. # include components
  166. objs.extend(SConscript(Rtt_Root + '/components/SConscript',
  167. variant_dir='build/components',
  168. duplicate=0,
  169. exports='remove_components'))
  170. return objs
  171. def PrepareModuleBuilding(env, root_directory):
  172. import SCons.cpp
  173. import rtconfig
  174. global BuildOptions
  175. global Projects
  176. global Env
  177. global Rtt_Root
  178. Env = env
  179. Rtt_Root = root_directory
  180. # add program path
  181. env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
  182. def GetConfigValue(name):
  183. assert type(name) == str, 'GetConfigValue: only string parameter is valid'
  184. try:
  185. return BuildOptions[name]
  186. except:
  187. return ''
  188. def GetDepend(depend):
  189. building = True
  190. if type(depend) == type('str'):
  191. if not BuildOptions.has_key(depend) or BuildOptions[depend] == 0:
  192. building = False
  193. elif BuildOptions[depend] != '':
  194. return BuildOptions[depend]
  195. return building
  196. # for list type depend
  197. for item in depend:
  198. if item != '':
  199. if not BuildOptions.has_key(item) or BuildOptions[item] == 0:
  200. building = False
  201. return building
  202. def AddDepend(option):
  203. BuildOptions[option] = 1
  204. def MergeGroup(src_group, group):
  205. src_group['src'] = src_group['src'] + group['src']
  206. if group.has_key('CCFLAGS'):
  207. if src_group.has_key('CCFLAGS'):
  208. src_group['CCFLAGS'] = src_group['CCFLAGS'] + group['CCFLAGS']
  209. else:
  210. src_group['CCFLAGS'] = group['CCFLAGS']
  211. if group.has_key('CPPPATH'):
  212. if src_group.has_key('CPPPATH'):
  213. src_group['CPPPATH'] = src_group['CPPPATH'] + group['CPPPATH']
  214. else:
  215. src_group['CPPPATH'] = group['CPPPATH']
  216. if group.has_key('CPPDEFINES'):
  217. if src_group.has_key('CPPDEFINES'):
  218. src_group['CPPDEFINES'] = src_group['CPPDEFINES'] + group['CPPDEFINES']
  219. else:
  220. src_group['CPPDEFINES'] = group['CPPDEFINES']
  221. if group.has_key('LINKFLAGS'):
  222. if src_group.has_key('LINKFLAGS'):
  223. src_group['LINKFLAGS'] = src_group['LINKFLAGS'] + group['LINKFLAGS']
  224. else:
  225. src_group['LINKFLAGS'] = group['LINKFLAGS']
  226. if group.has_key('LIBS'):
  227. if src_group.has_key('LIBS'):
  228. src_group['LIBS'] = src_group['LIBS'] + group['LIBS']
  229. else:
  230. src_group['LIBS'] = group['LIBS']
  231. if group.has_key('LIBPATH'):
  232. if src_group.has_key('LIBPATH'):
  233. src_group['LIBPATH'] = src_group['LIBPATH'] + group['LIBPATH']
  234. else:
  235. src_group['LIBPATH'] = group['LIBPATH']
  236. def DefineGroup(name, src, depend, **parameters):
  237. global Env
  238. if not GetDepend(depend):
  239. return []
  240. group = parameters
  241. group['name'] = name
  242. group['path'] = GetCurrentDir()
  243. if type(src) == type(['src1', 'str2']):
  244. group['src'] = File(src)
  245. else:
  246. group['src'] = src
  247. if group.has_key('CCFLAGS'):
  248. Env.Append(CCFLAGS = group['CCFLAGS'])
  249. if group.has_key('CPPPATH'):
  250. Env.Append(CPPPATH = group['CPPPATH'])
  251. if group.has_key('CPPDEFINES'):
  252. Env.Append(CPPDEFINES = group['CPPDEFINES'])
  253. if group.has_key('LINKFLAGS'):
  254. Env.Append(LINKFLAGS = group['LINKFLAGS'])
  255. if group.has_key('LIBS'):
  256. Env.Append(LIBS = group['LIBS'])
  257. if group.has_key('LIBPATH'):
  258. Env.Append(LIBPATH = group['LIBPATH'])
  259. objs = Env.Object(group['src'])
  260. if group.has_key('LIBRARY'):
  261. objs = Env.Library(name, objs)
  262. # merge group
  263. for g in Projects:
  264. if g['name'] == name:
  265. # merge to this group
  266. MergeGroup(g, group)
  267. return objs
  268. # add a new group
  269. Projects.append(group)
  270. return objs
  271. def GetCurrentDir():
  272. conscript = File('SConscript')
  273. fn = conscript.rfile()
  274. name = fn.name
  275. path = os.path.dirname(fn.abspath)
  276. return path
  277. PREBUILDING = []
  278. def RegisterPreBuildingAction(act):
  279. global PREBUILDING
  280. assert callable(act), 'Could only register callable objects. %s received' % repr(act)
  281. PREBUILDING.append(act)
  282. def PreBuilding():
  283. global PREBUILDING
  284. for a in PREBUILDING:
  285. a()
  286. def DoBuilding(target, objects):
  287. program = None
  288. # check whether special buildlib option
  289. lib_name = GetOption('buildlib')
  290. if lib_name:
  291. # build library with special component
  292. for Group in Projects:
  293. if Group['name'] == lib_name:
  294. objects = Env.Object(Group['src'])
  295. program = Env.Library(lib_name, objects)
  296. break
  297. else:
  298. program = Env.Program(target, objects)
  299. EndBuilding(target, program)
  300. def EndBuilding(target, program = None):
  301. import rtconfig
  302. from keil import MDKProject
  303. from keil import MDK4Project
  304. from iar import IARProject
  305. from vs import VSProject
  306. from vs2012 import VS2012Project
  307. from codeblocks import CBProject
  308. Env.AddPostAction(target, rtconfig.POST_ACTION)
  309. if GetOption('target') == 'mdk':
  310. template = os.path.isfile('template.Uv2')
  311. if template:
  312. MDKProject('project.Uv2', Projects)
  313. else:
  314. template = os.path.isfile('template.uvproj')
  315. if template:
  316. MDK4Project('project.uvproj', Projects)
  317. else:
  318. print 'No template project file found.'
  319. if GetOption('target') == 'mdk4':
  320. MDK4Project('project.uvproj', Projects)
  321. if GetOption('target') == 'iar':
  322. IARProject('project.ewp', Projects)
  323. if GetOption('target') == 'vs':
  324. VSProject('project.vcproj', Projects, program)
  325. if GetOption('target') == 'vs2012':
  326. VS2012Project('project.vcxproj', Projects, program)
  327. if GetOption('target') == 'cb':
  328. CBProject('project.cbp', Projects, program)
  329. if GetOption('copy') and program != None:
  330. MakeCopy(program)
  331. if GetOption('copy-header') and program != None:
  332. MakeCopyHeader(program)
  333. if GetOption('cscope'):
  334. from cscope import CscopeDatabase
  335. CscopeDatabase(Projects)
  336. def SrcRemove(src, remove):
  337. if type(src[0]) == type('str'):
  338. for item in src:
  339. if os.path.basename(item) in remove:
  340. src.remove(item)
  341. return
  342. for item in src:
  343. if os.path.basename(item.rstr()) in remove:
  344. src.remove(item)
  345. def GetVersion():
  346. import SCons.cpp
  347. import string
  348. rtdef = os.path.join(Rtt_Root, 'include', 'rtdef.h')
  349. # parse rtdef.h to get RT-Thread version
  350. prepcessor = SCons.cpp.PreProcessor()
  351. f = file(rtdef, 'r')
  352. contents = f.read()
  353. f.close()
  354. prepcessor.process_contents(contents)
  355. def_ns = prepcessor.cpp_namespace
  356. version = int(filter(lambda ch: ch in '0123456789.', def_ns['RT_VERSION']))
  357. subversion = int(filter(lambda ch: ch in '0123456789.', def_ns['RT_SUBVERSION']))
  358. if def_ns.has_key('RT_REVISION'):
  359. revision = int(filter(lambda ch: ch in '0123456789.', def_ns['RT_REVISION']))
  360. return '%d.%d.%d' % (version, subversion, revision)
  361. return '0.%d.%d' % (version, subversion)
  362. def GlobSubDir(sub_dir, ext_name):
  363. import os
  364. import glob
  365. def glob_source(sub_dir, ext_name):
  366. list = os.listdir(sub_dir)
  367. src = glob.glob(os.path.join(sub_dir, ext_name))
  368. for item in list:
  369. full_subdir = os.path.join(sub_dir, item)
  370. if os.path.isdir(full_subdir):
  371. src += glob_source(full_subdir, ext_name)
  372. return src
  373. dst = []
  374. src = glob_source(sub_dir, ext_name)
  375. for item in src:
  376. dst.append(os.path.relpath(item, sub_dir))
  377. return dst
  378. def do_copy_file(src, dst):
  379. import shutil
  380. # check source file
  381. if not os.path.exists(src):
  382. return
  383. path = os.path.dirname(dst)
  384. # mkdir if path not exist
  385. if not os.path.exists(path):
  386. os.makedirs(path)
  387. shutil.copy2(src, dst)
  388. def do_copy_folder(src_dir, dst_dir):
  389. import shutil
  390. # check source directory
  391. if not os.path.exists(src_dir):
  392. return
  393. if os.path.exists(dst_dir):
  394. shutil.rmtree(dst_dir)
  395. shutil.copytree(src_dir, dst_dir)
  396. source_ext = ["c", "h", "s", "S", "cpp", "xpm"]
  397. source_list = []
  398. def walk_children(child):
  399. global source_list
  400. global source_ext
  401. # print child
  402. full_path = child.rfile().abspath
  403. file_type = full_path.rsplit('.',1)[1]
  404. #print file_type
  405. if file_type in source_ext:
  406. if full_path not in source_list:
  407. source_list.append(full_path)
  408. children = child.all_children()
  409. if children != []:
  410. for item in children:
  411. walk_children(item)
  412. def MakeCopy(program):
  413. global source_list
  414. global Rtt_Root
  415. global Env
  416. target_path = os.path.join(Dir('#').abspath, 'rt-thread')
  417. if Env['PLATFORM'] == 'win32':
  418. RTT_ROOT = Rtt_Root.lower()
  419. else:
  420. RTT_ROOT = Rtt_Root
  421. if target_path.startswith(RTT_ROOT):
  422. return
  423. for item in program:
  424. walk_children(item)
  425. source_list.sort()
  426. # filte source file in RT-Thread
  427. target_list = []
  428. for src in source_list:
  429. if Env['PLATFORM'] == 'win32':
  430. src = src.lower()
  431. if src.startswith(RTT_ROOT):
  432. target_list.append(src)
  433. source_list = target_list
  434. # get source path
  435. src_dir = []
  436. for src in source_list:
  437. src = src.replace(RTT_ROOT, '')
  438. if src[0] == os.sep or src[0] == '/':
  439. src = src[1:]
  440. path = os.path.dirname(src)
  441. sub_path = path.split(os.sep)
  442. full_path = RTT_ROOT
  443. for item in sub_path:
  444. full_path = os.path.join(full_path, item)
  445. if full_path not in src_dir:
  446. src_dir.append(full_path)
  447. for item in src_dir:
  448. source_list.append(os.path.join(item, 'SConscript'))
  449. for src in source_list:
  450. dst = src.replace(RTT_ROOT, '')
  451. if dst[0] == os.sep or dst[0] == '/':
  452. dst = dst[1:]
  453. print '=> ', dst
  454. dst = os.path.join(target_path, dst)
  455. do_copy_file(src, dst)
  456. # copy tools directory
  457. print "=> tools"
  458. do_copy_folder(os.path.join(RTT_ROOT, "tools"), os.path.join(target_path, "tools"))
  459. do_copy_file(os.path.join(RTT_ROOT, 'AUTHORS'), os.path.join(target_path, 'AUTHORS'))
  460. do_copy_file(os.path.join(RTT_ROOT, 'COPYING'), os.path.join(target_path, 'COPYING'))
  461. def MakeCopyHeader(program):
  462. global source_ext
  463. source_ext = []
  464. source_ext = ["h", "xpm"]
  465. global source_list
  466. global Rtt_Root
  467. global Env
  468. target_path = os.path.join(Dir('#').abspath, 'rt-thread')
  469. if Env['PLATFORM'] == 'win32':
  470. RTT_ROOT = Rtt_Root.lower()
  471. else:
  472. RTT_ROOT = Rtt_Root
  473. if target_path.startswith(RTT_ROOT):
  474. return
  475. for item in program:
  476. walk_children(item)
  477. source_list.sort()
  478. # filte source file in RT-Thread
  479. target_list = []
  480. for src in source_list:
  481. if Env['PLATFORM'] == 'win32':
  482. src = src.lower()
  483. if src.startswith(RTT_ROOT):
  484. target_list.append(src)
  485. source_list = target_list
  486. for src in source_list:
  487. dst = src.replace(RTT_ROOT, '')
  488. if dst[0] == os.sep or dst[0] == '/':
  489. dst = dst[1:]
  490. print '=> ', dst
  491. dst = os.path.join(target_path, dst)
  492. do_copy_file(src, dst)
  493. # copy tools directory
  494. print "=> tools"
  495. do_copy_folder(os.path.join(RTT_ROOT, "tools"), os.path.join(target_path, "tools"))
  496. do_copy_file(os.path.join(RTT_ROOT, 'AUTHORS'), os.path.join(target_path, 'AUTHORS'))
  497. do_copy_file(os.path.join(RTT_ROOT, 'COPYING'), os.path.join(target_path, 'COPYING'))