#!/usr/bin/env python3 import os import shlex import subprocess import threading from shell_helpers import LF import common import thread_pool class Main(common.BuildCliFunction): def __init__(self, *args, **kwargs): if not 'description' in kwargs: kwargs['description'] = '''\ Build our compiled userland examples. ''' if not 'defaults' in kwargs: kwargs['defaults'] = {} if not 'mode' in kwargs['defaults']: kwargs['defaults']['mode'] = 'userland' super().__init__(*args, **kwargs) self._add_argument('--ccflags') self._add_argument('--force-rebuild') self._add_argument('--optimization-level') self.add_argument( '--out-rootfs-overlay-dir-prefix', default='', help='''\ Place the output files inside the image within this additional prefix. This is mostly useful to place different versions of binaries with different build parameters inside image to compare them. See: * https://cirosantilli.com/linux-kernel-module-cheat#update-the-toolchain * https://cirosantilli.com/linux-kernel-module-cheat#out_rootfs_overlay_dir ''' ) self.add_argument( 'targets', default=[], help='''\ Select to build only the given userland programs, or all programs under the given directories. Default: build all. Must point to either sources or directories under userland/, or to LKMC toplevel which is a synonym for userland/. Default: build all examples that have their package dependencies met, e.g.: - userland/arch/ programs only build if the target arch matches - an OpenBLAS example can only be built if the target root filesystem has the OpenBLAS libraries and headers installed, which you must inform with --package ''', nargs='*', ) def build(self): build_dir = self.get_build_dir() cc_flags = [ '-I', self.env['root_dir'], LF, '-O{}'.format(self.env['optimization_level']), LF, ] + self.sh.shlex_split(self.env['ccflags']) if self.env['static']: cc_flags.extend(['-static', LF]) extra_obj_lkmc_common = os.path.join( build_dir, self.env['common_basename_noext'] + self.env['obj_ext'] ) self._build_one( in_path=self.env['common_c'], out_path=extra_obj_lkmc_common, cc_flags=cc_flags, extra_deps=[self.env['common_h']], link=False, ) with thread_pool.ThreadPool( self._build_one, nthreads=self.env['nproc'], submit_raise_exit=self.env['quit_on_fail'], ) as my_thread_pool: for target in self.env['targets']: for path, in_dirnames, in_filenames in self.sh.walk(target): for in_filename in in_filenames: in_ext = os.path.splitext(in_filename)[1] if not in_ext in self.env['build_in_exts']: continue in_path = os.path.join(path, in_filename) my_thread_pool.submit({ 'cc_flags': cc_flags, 'extra_objs_lkmc_common': [extra_obj_lkmc_common], 'in_path': in_path, 'out_path': self.resolve_userland_executable(in_path), }) exit_status = self._handle_thread_pool_errors(my_thread_pool) if exit_status != 0: return exit_status if not self.env['in_tree']: self.sh.copy_dir_if_update( srcdir=build_dir, destdir=os.path.join( self.env['out_rootfs_overlay_lkmc_dir'], self.env['out_rootfs_overlay_dir_prefix'] ), filter_ext=self.env['userland_executable_ext'], ) return exit_status def clean(self): if self.env['in_tree']: for target in self.env['targets']: if os.path.exists(target): if os.path.isfile(target): self.sh.rmrf(self.resolve_userland_executable(target)) else: for path, dirnames, filenames in self.sh.walk(target): for filename in filenames: if os.path.splitext(filename)[1] in self.env['userland_out_exts']: self.sh.rmrf(os.path.join(path, filename)) else: for target in self.env['targets']: self.sh.rmrf(self.resolve_userland_executable(target)) def get_build_dir(self): return self.env['userland_build_dir'] def setup_one(self): self.env['targets'] = self.resolve_targets( [self.env['userland_source_dir']], self.env['targets'] ) if __name__ == '__main__': Main().cli()