mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-25 19:21:35 +01:00
167 lines
5.9 KiB
Python
Executable File
167 lines
5.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import os
|
|
import shutil
|
|
|
|
import common
|
|
from shell_helpers import LF
|
|
|
|
class Main(common.BuildCliFunction):
|
|
def __init__(self):
|
|
super().__init__(
|
|
description='''\
|
|
Build the Linux kernel.
|
|
'''
|
|
)
|
|
self.add_argument(
|
|
'--config', default=[], action='append',
|
|
help='''\
|
|
Add a single kernel config configs to the current build. Sample value:
|
|
'CONFIG_FORTIFY_SOURCE=y'. Can be used multiple times to add multiple
|
|
configs. Takes precedence over any config files.
|
|
'''
|
|
)
|
|
self.add_argument(
|
|
'--config-fragment', default=[], action='append',
|
|
help='''\
|
|
Also use the given kernel configuration fragment file.
|
|
Pass multiple times to use multiple fragment files.
|
|
'''
|
|
)
|
|
self.add_argument(
|
|
'--config-only', default=False,
|
|
help='''\
|
|
Configure the kernel, but don't build it.
|
|
'''
|
|
)
|
|
self.add_argument(
|
|
'--custom-config-file',
|
|
help='''\
|
|
Ignore all default kernel configurations and use this file instead.
|
|
Still uses options explicitly passed with `--config` and
|
|
`--config-fragment` on top of it.
|
|
'''
|
|
)
|
|
self.add_argument(
|
|
'--custom-config-file-gem5', default=False,
|
|
help='''\
|
|
Use the gem5 Linux kernel fork config as the custom config file.
|
|
Ignore --custom-config-file.
|
|
'''
|
|
)
|
|
self.add_argument(
|
|
'--modules-install', default=True,
|
|
help='''\
|
|
Run `make modules_install` after `make`.
|
|
'''
|
|
)
|
|
self.add_argument(
|
|
'extra_make_args',
|
|
default=[],
|
|
metavar='extra-make-args',
|
|
nargs='*'
|
|
)
|
|
|
|
def build(self):
|
|
build_dir = self.get_build_dir()
|
|
if self.env['initrd'] or self.env['initramfs']:
|
|
raise Exception('just trolling, --initrd and --initramfs are broken for now')
|
|
os.makedirs(build_dir, exist_ok=True)
|
|
tool = 'gcc'
|
|
gcc = self.get_toolchain_tool(tool)
|
|
prefix = gcc[:-len(tool)]
|
|
common_args = {
|
|
'cwd': self.env['linux_source_dir'],
|
|
}
|
|
ccache = shutil.which('ccache')
|
|
if ccache is not None:
|
|
cc = '{} {}'.format(ccache, gcc)
|
|
else:
|
|
cc = gcc
|
|
if self.env['verbose']:
|
|
verbose = ['V=1']
|
|
else:
|
|
verbose = []
|
|
common_make_args = [
|
|
'make', LF,
|
|
'-j', str(self.env['nproc']), LF,
|
|
'ARCH={}'.format(self.env['linux_arch']), LF,
|
|
'CROSS_COMPILE={}'.format(prefix), LF,
|
|
'CC={}'.format(cc), LF,
|
|
'O={}'.format(build_dir), LF,
|
|
] + verbose
|
|
if self.env['custom_config_file_gem5']:
|
|
custom_config_file = os.path.join(self.env['linux_source_dir'], 'arch', self.env['linux_arch'], 'configs', 'gem5_defconfig')
|
|
else:
|
|
custom_config_file = self.env['custom_config_file']
|
|
if custom_config_file is not None:
|
|
if not os.path.exists(custom_config_file):
|
|
raise Exception('config fragment file does not exist: {}'.format(custom_config_file))
|
|
base_config_file = custom_config_file
|
|
config_fragments = []
|
|
else:
|
|
base_config_file = os.path.join(self.env['linux_config_dir'], 'buildroot-{}'.format(self.env['arch']))
|
|
config_fragments = ['min', 'default']
|
|
for i, config_fragment in enumerate(config_fragments):
|
|
config_fragments[i] = os.path.join(self.env['linux_config_dir'], config_fragment)
|
|
config_fragments.extend(self.env['config_fragment'])
|
|
if self.env['config'] != []:
|
|
cli_config_fragment_path = os.path.join(build_dir, 'lkmc_cli_config_fragment')
|
|
cli_config_str = '\n'.join(self.env['config'])
|
|
self.sh.write_string_to_file(cli_config_fragment_path, cli_config_str)
|
|
config_fragments.append(cli_config_fragment_path)
|
|
self.sh.cp(
|
|
base_config_file,
|
|
os.path.join(build_dir, '.config'),
|
|
)
|
|
self.sh.run_cmd(
|
|
[
|
|
os.path.join(self.env['linux_source_dir'], 'scripts', 'kconfig', 'merge_config.sh'), LF,
|
|
'-m', LF,
|
|
'-O', build_dir, LF,
|
|
os.path.join(build_dir, '.config'), LF,
|
|
] +
|
|
self.sh.add_newlines(config_fragments)
|
|
)
|
|
self.sh.run_cmd(
|
|
(
|
|
common_make_args +
|
|
['olddefconfig', LF]
|
|
),
|
|
**common_args
|
|
)
|
|
if not self.env['config_only']:
|
|
self.sh.run_cmd(
|
|
(
|
|
common_make_args +
|
|
self.sh.add_newlines(self.env['extra_make_args'])
|
|
),
|
|
extra_env={
|
|
'KBUILD_BUILD_VERSION': '1',
|
|
'KBUILD_BUILD_TIMESTAMP': 'Thu Jan 1 00:00:00 UTC 1970',
|
|
'KBUILD_BUILD_USER': 'lkmc',
|
|
'KBUILD_BUILD_HOST': common.git_sha(self.env['linux_source_dir']),
|
|
},
|
|
**common_args
|
|
)
|
|
if self.env['modules_install']:
|
|
self.sh.run_cmd(
|
|
(
|
|
common_make_args +
|
|
[
|
|
'INSTALL_MOD_PATH={}'.format(self.env['out_rootfs_overlay_dir']), LF,
|
|
'modules_install', LF,
|
|
]
|
|
),
|
|
**common_args
|
|
)
|
|
# TODO: remove build and source https://stackoverflow.com/questions/13578618/what-does-build-and-source-link-do-in-lib-modules-kernel-version
|
|
# TODO Basically all kernel modules also basically leak full host paths. Just terrible. Buildroot deals with that stuff nicely for us.
|
|
# self.rmrf()
|
|
|
|
def get_build_dir(self):
|
|
return self.env['linux_build_dir']
|
|
|
|
if __name__ == '__main__':
|
|
Main().cli()
|