123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- #!/usr/bin/env python3
- import os
- import common
- from shell_helpers import LF
- class Main(common.BuildCliFunction):
- def __init__(self):
- super().__init__(
- defaults={
- 'gcc_which':'crosstool-ng',
- },
- description='''\
- Build the baremetal examples with crosstool-NG.
- ''',
- supported_archs=common.consts['crosstool_ng_supported_archs']
- )
- self._add_argument('--ccflags')
- self._add_argument('--force-rebuild')
- self._add_argument('--optimization-level')
- def build(self):
- build_dir = self.get_build_dir()
- bootloader_obj = os.path.join(
- self.env['baremetal_build_lib_dir'],
- 'bootloader{}'.format(self.env['obj_ext'])
- )
- common_obj = os.path.join(
- self.env['baremetal_build_lib_dir'],
- self.env['common_basename_noext'] + self.env['obj_ext']
- )
- syscalls_basename_noext = 'syscalls'
- syscalls_src = os.path.join(
- self.env['baremetal_source_lib_dir'],
- syscalls_basename_noext + self.env['c_ext']
- )
- syscalls_obj = os.path.join(
- self.env['baremetal_build_lib_dir'],
- syscalls_basename_noext + self.env['obj_ext']
- )
- common_objs = [common_obj, syscalls_obj]
- cflags = [
- '-I', self.env['baremetal_source_lib_dir'], LF,
- '-I', self.env['root_dir'], LF,
- '-O{}'.format(self.env['optimization_level']), LF,
- '-ggdb3', LF,
- '-mcpu={}'.format(self.env['mcpu']), LF,
- '-nostartfiles', LF,
- ]
- if self.env['arch'] == 'arm':
- cflags.extend([
- '-mhard-float', LF,
- # This uses the soft float ABI for calling functions from objets in Newlib which
- # our crosstool-NG config compiles with soft floats, while emiting hard float
- # from C and allowing us to use it from assembly, e.g. for the VMRS instruction:
- # which would otherwise fail "with selected processor does not support XXX in ARM mode"
- # Bibliography:
- # - https://stackoverflow.com/questions/9753749/arm-compilation-error-vfp-registered-used-by-executable-not-object-file
- # - https://stackoverflow.com/questions/41131432/cross-compiling-error-selected-processor-does-not-support-fmrx-r3-fpexc-in/41131782#41131782
- # - https://embeddedartistry.com/blog/2017/10/9/r1q7pksku2q3gww9rpqef0dnskphtc
- '-mfloat-abi=softfp', LF,
- '-mfpu=crypto-neon-fp-armv8', LF,
- ])
- cflags_after = ['-lm']
- if self.env['emulator'] == 'gem5':
- if self.env['machine'] == 'VExpress_GEM5_V1':
- entry_address = 0x80000000
- uart_address = 0x1c090000
- elif self.env['machine'] == 'RealViewPBX':
- entry_address = 0x10000
- uart_address = 0x10009000
- else:
- raise Exception('unknown machine: ' + self.env['machine'])
- cflags.extend([
- '-D', 'GEM5'.format(uart_address), LF,
- '-DLKMC_M5OPS_ENABLE=1', LF,
- ])
- else:
- entry_address = 0x40000000
- uart_address = 0x09000000
- os.makedirs(build_dir, exist_ok=True)
- os.makedirs(self.env['baremetal_build_lib_dir'], exist_ok=True)
- src = os.path.join(
- self.env['baremetal_source_lib_dir'],
- '{}{}'.format(
- self.env['arch'],
- self.env['asm_ext']
- )
- )
- cflags.extend(self.sh.shlex_split(self.env['ccflags']))
- if self.need_rebuild([src], bootloader_obj):
- self.sh.run_cmd(
- [self.env['gcc_path'], LF] +
- cflags +
- [
- '-c', LF,
- '-o', bootloader_obj, LF,
- src, LF,
- ] +
- cflags_after
- )
- for src, obj in [
- (self.env['common_c'], common_obj),
- (syscalls_src, syscalls_obj),
- ]:
- if self.need_rebuild([src, self.env['common_h']], obj):
- self.sh.run_cmd(
- [self.env['gcc_path'], LF] +
- cflags +
- [
- '-D', 'UART0_ADDR={:#x}'.format(uart_address), LF,
- '-c', LF,
- '-o', obj, LF,
- src, LF,
- ] +
- cflags_after
- )
- for subpath in [
- '',
- 'interactive',
- self.env['baremetal_source_arch_subpath'],
- os.path.join(self.env['baremetal_source_arch_subpath'], 'no_bootloader'),
- ]:
- in_dir = os.path.join(self.env['baremetal_source_dir'], subpath)
- if os.path.isdir(in_dir):
- out_dir = os.path.join(self.env['baremetal_build_dir'], subpath)
- os.makedirs(out_dir, exist_ok=True)
- common_objs_bootloader = common_objs.copy()
- if os.path.basename(subpath) != 'no_bootloader':
- common_objs_bootloader.append(bootloader_obj)
- for in_basename in sorted(os.listdir(in_dir)):
- in_path = os.path.join(in_dir, in_basename)
- in_name, in_ext = os.path.splitext(in_basename)
- if (
- os.path.isfile(in_path) and
- in_ext in self.env['build_in_exts']
- ):
- out = os.path.join(out_dir, in_name + self.env['baremetal_build_ext'])
- src = os.path.join(self.env['baremetal_source_dir'], in_path)
- if self.need_rebuild(
- common_objs_bootloader +
- [
- src,
- self.env['baremetal_link_script'],
- self.env['common_h']
- ],
- out
- ):
- self.sh.run_cmd(
- [self.env['gcc_path'], LF] +
- cflags +
- [
- '-Wl,--section-start=.text={:#x}'.format(entry_address), LF,
- '-o', out, LF,
- '-T', self.env['baremetal_link_script'], LF,
- ] +
- [
- src, LF,
- ] +
- self.sh.add_newlines(common_objs_bootloader) +
- cflags_after
- )
- def get_build_dir(self):
- return self.env['baremetal_build_dir']
- if __name__ == '__main__':
- Main().cli()
|