build-baremetal 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #!/usr/bin/env python3
  2. import os
  3. import common
  4. from shell_helpers import LF
  5. class Main(common.BuildCliFunction):
  6. def __init__(self):
  7. super().__init__(
  8. description='''\
  9. Build the baremetal examples with crosstool-NG.
  10. ''',
  11. supported_archs=common.consts['crosstool_ng_supported_archs']
  12. )
  13. def build(self):
  14. build_dir = self.get_build_dir()
  15. bootloader_obj = os.path.join(self.env['baremetal_build_lib_dir'], 'bootloader{}'.format(self.env['obj_ext']))
  16. common_basename_noext = 'common'
  17. common_src = os.path.join(self.env['root_dir'], common_basename_noext + self.env['c_ext'])
  18. common_obj = os.path.join(self.env['baremetal_build_lib_dir'], common_basename_noext + self.env['obj_ext'])
  19. syscalls_basename_noext = 'syscalls'
  20. syscalls_src = os.path.join(self.env['baremetal_source_lib_dir'], syscalls_basename_noext + self.env['c_ext'])
  21. syscalls_obj = os.path.join(self.env['baremetal_build_lib_dir'], syscalls_basename_noext + self.env['obj_ext'])
  22. common_objs = [common_obj, syscalls_obj]
  23. cflags = [
  24. '-I', self.env['baremetal_source_lib_dir'], LF,
  25. '-I', self.env['root_dir'], LF,
  26. '-O0', LF,
  27. '-ggdb3', LF,
  28. '-mcpu={}'.format(self.env['mcpu']), LF,
  29. '-nostartfiles', LF,
  30. ]
  31. if self.env['prebuilt']:
  32. gcc = 'arm-none-eabi-gcc'
  33. else:
  34. os.environ['PATH'] = self.env['crosstool_ng_bin_dir'] + os.environ['PATH']
  35. gcc = self.get_toolchain_tool('gcc', allowed_toolchains=['crosstool-ng'])
  36. if self.env['emulator'] == 'gem5':
  37. if self.env['machine'] == 'VExpress_GEM5_V1':
  38. entry_address = 0x80000000
  39. uart_address = 0x1c090000
  40. elif self.env['machine'] == 'RealViewPBX':
  41. entry_address = 0x10000
  42. uart_address = 0x10009000
  43. else:
  44. raise Exception('unknown machine: ' + self.env['machine'])
  45. cflags.extend(['-D', 'GEM5'.format(uart_address), LF])
  46. else:
  47. entry_address = 0x40000000
  48. uart_address = 0x09000000
  49. os.makedirs(build_dir, exist_ok=True)
  50. os.makedirs(self.env['baremetal_build_lib_dir'], exist_ok=True)
  51. src = os.path.join(self.env['baremetal_source_lib_dir'], '{}{}'.format(self.env['arch'], self.env['asm_ext']))
  52. if self.need_rebuild([src], bootloader_obj):
  53. self.sh.run_cmd(
  54. [gcc, LF] +
  55. cflags +
  56. [
  57. '-c', LF,
  58. '-o', bootloader_obj, LF,
  59. src, LF,
  60. ]
  61. )
  62. for src, obj in [
  63. (common_src, common_obj),
  64. (syscalls_src, syscalls_obj),
  65. ]:
  66. if self.need_rebuild([src], obj):
  67. self.sh.run_cmd(
  68. [gcc, LF] +
  69. cflags +
  70. [
  71. '-c', LF,
  72. '-D', 'UART0_ADDR={:#x}'.format(uart_address), LF,
  73. '-o', obj, LF,
  74. src, LF,
  75. ]
  76. )
  77. self._build_dir(
  78. '',
  79. gcc=gcc,
  80. cflags=cflags,
  81. entry_address=entry_address,
  82. bootloader_obj=bootloader_obj,
  83. common_objs=common_objs,
  84. )
  85. self._build_dir(
  86. 'interactive',
  87. gcc=gcc,
  88. cflags=cflags,
  89. entry_address=entry_address,
  90. bootloader_obj=bootloader_obj,
  91. common_objs=common_objs,
  92. )
  93. if os.path.isdir(os.path.join(self.env['baremetal_source_arch_dir'])):
  94. self._build_dir(
  95. self.env['baremetal_source_arch_subpath'],
  96. gcc=gcc,
  97. cflags=cflags,
  98. entry_address=entry_address,
  99. bootloader_obj=bootloader_obj,
  100. common_objs=common_objs,
  101. )
  102. arch_dir = os.path.join('arch', self.env['arch'], 'no_bootloader')
  103. if os.path.isdir(os.path.join(self.env['baremetal_source_dir'], arch_dir)):
  104. self._build_dir(
  105. arch_dir,
  106. gcc=gcc,
  107. cflags=cflags,
  108. entry_address=entry_address,
  109. bootloader_obj=bootloader_obj,
  110. common_objs=common_objs,
  111. bootloader=False,
  112. )
  113. def get_build_dir(self):
  114. return self.env['baremetal_build_dir']
  115. def _build_dir(
  116. self,
  117. subpath,
  118. gcc,
  119. cflags,
  120. entry_address,
  121. bootloader_obj,
  122. common_objs,
  123. bootloader=True
  124. ):
  125. '''
  126. Build all .c and .S files in a given subpath of the baremetal source
  127. directory non recursively.
  128. Place outputs on the same subpath or the output directory.
  129. '''
  130. in_dir = os.path.join(self.env['baremetal_source_dir'], subpath)
  131. out_dir = os.path.join(self.env['baremetal_build_dir'], subpath)
  132. os.makedirs(out_dir, exist_ok=True)
  133. common_objs = common_objs.copy()
  134. if bootloader:
  135. common_objs.append(bootloader_obj)
  136. for in_basename in os.listdir(in_dir):
  137. in_path = os.path.join(in_dir, in_basename)
  138. if os.path.isfile(in_path) and os.path.splitext(in_basename)[1] in (self.env['c_ext'], self.env['asm_ext']):
  139. in_name = os.path.splitext(in_basename)[0]
  140. main_obj = os.path.join(self.env['baremetal_build_dir'], subpath, '{}{}'.format(in_name, self.env['obj_ext']))
  141. src = os.path.join(self.env['baremetal_source_dir'], in_path)
  142. if self.need_rebuild([src], main_obj):
  143. self.sh.run_cmd(
  144. [gcc, LF] +
  145. cflags +
  146. [
  147. '-c', LF,
  148. '-o', main_obj, LF,
  149. src, LF,
  150. ]
  151. )
  152. objs = common_objs + [main_obj]
  153. out = os.path.join(self.env['baremetal_build_dir'], subpath, in_name + self.env['baremetal_build_ext'])
  154. link_script = os.path.join(self.env['baremetal_source_dir'], 'link.ld')
  155. if self.need_rebuild(objs + [link_script], out):
  156. self.sh.run_cmd(
  157. [gcc, LF] +
  158. cflags +
  159. [
  160. '-Wl,--section-start=.text={:#x}'.format(entry_address), LF,
  161. '-o', out, LF,
  162. '-T', link_script, LF,
  163. ] +
  164. self.sh.add_newlines(objs)
  165. )
  166. if __name__ == '__main__':
  167. Main().cli()