#!/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'], 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'], 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['c_ext'], self.env['asm_ext']) ): out = os.path.join(out_dir, in_name + self.env['baremetal_build_ext']) if self.need_rebuild( common_objs_bootloader + [self.env['baremetal_link_script'] + self.env['common_h']], out ): self.sh.run_cmd( [self.env['gcc'], LF] + cflags + [ '-Wl,--section-start=.text={:#x}'.format(entry_address), LF, '-o', out, LF, '-T', self.env['baremetal_link_script'], LF, ] + [ os.path.join(self.env['baremetal_source_dir'], in_path), 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()