1*4882a593Smuzhiyun# Recipe creation tool - kernel module support plugin 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# Copyright (C) 2016 Intel Corporation 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 6*4882a593Smuzhiyun# 7*4882a593Smuzhiyun 8*4882a593Smuzhiyunimport re 9*4882a593Smuzhiyunimport logging 10*4882a593Smuzhiyunfrom recipetool.create import RecipeHandler, read_pkgconfig_provides, validate_pv 11*4882a593Smuzhiyun 12*4882a593Smuzhiyunlogger = logging.getLogger('recipetool') 13*4882a593Smuzhiyun 14*4882a593Smuzhiyuntinfoil = None 15*4882a593Smuzhiyun 16*4882a593Smuzhiyundef tinfoil_init(instance): 17*4882a593Smuzhiyun global tinfoil 18*4882a593Smuzhiyun tinfoil = instance 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun 21*4882a593Smuzhiyunclass KernelModuleRecipeHandler(RecipeHandler): 22*4882a593Smuzhiyun def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): 23*4882a593Smuzhiyun import bb.process 24*4882a593Smuzhiyun if 'buildsystem' in handled: 25*4882a593Smuzhiyun return False 26*4882a593Smuzhiyun 27*4882a593Smuzhiyun module_inc_re = re.compile(r'^#include\s+<linux/module.h>$') 28*4882a593Smuzhiyun makefiles = [] 29*4882a593Smuzhiyun is_module = False 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun makefiles = [] 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun files = RecipeHandler.checkfiles(srctree, ['*.c', '*.h'], recursive=True, excludedirs=['contrib', 'test', 'examples']) 34*4882a593Smuzhiyun if files: 35*4882a593Smuzhiyun for cfile in files: 36*4882a593Smuzhiyun # Look in same dir or parent for Makefile 37*4882a593Smuzhiyun for makefile in [os.path.join(os.path.dirname(cfile), 'Makefile'), os.path.join(os.path.dirname(os.path.dirname(cfile)), 'Makefile')]: 38*4882a593Smuzhiyun if makefile in makefiles: 39*4882a593Smuzhiyun break 40*4882a593Smuzhiyun else: 41*4882a593Smuzhiyun if os.path.exists(makefile): 42*4882a593Smuzhiyun makefiles.append(makefile) 43*4882a593Smuzhiyun break 44*4882a593Smuzhiyun else: 45*4882a593Smuzhiyun continue 46*4882a593Smuzhiyun with open(cfile, 'r', errors='surrogateescape') as f: 47*4882a593Smuzhiyun for line in f: 48*4882a593Smuzhiyun if module_inc_re.match(line.strip()): 49*4882a593Smuzhiyun is_module = True 50*4882a593Smuzhiyun break 51*4882a593Smuzhiyun if is_module: 52*4882a593Smuzhiyun break 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun if is_module: 55*4882a593Smuzhiyun classes.append('module') 56*4882a593Smuzhiyun handled.append('buildsystem') 57*4882a593Smuzhiyun # module.bbclass and the classes it inherits do most of the hard 58*4882a593Smuzhiyun # work, but we need to tweak it slightly depending on what the 59*4882a593Smuzhiyun # Makefile does (and there is a range of those) 60*4882a593Smuzhiyun # Check the makefile for the appropriate install target 61*4882a593Smuzhiyun install_lines = [] 62*4882a593Smuzhiyun compile_lines = [] 63*4882a593Smuzhiyun in_install = False 64*4882a593Smuzhiyun in_compile = False 65*4882a593Smuzhiyun install_target = None 66*4882a593Smuzhiyun with open(makefile, 'r', errors='surrogateescape') as f: 67*4882a593Smuzhiyun for line in f: 68*4882a593Smuzhiyun if line.startswith('install:'): 69*4882a593Smuzhiyun if not install_lines: 70*4882a593Smuzhiyun in_install = True 71*4882a593Smuzhiyun install_target = 'install' 72*4882a593Smuzhiyun elif line.startswith('modules_install:'): 73*4882a593Smuzhiyun install_lines = [] 74*4882a593Smuzhiyun in_install = True 75*4882a593Smuzhiyun install_target = 'modules_install' 76*4882a593Smuzhiyun elif line.startswith('modules:'): 77*4882a593Smuzhiyun compile_lines = [] 78*4882a593Smuzhiyun in_compile = True 79*4882a593Smuzhiyun elif line.startswith(('all:', 'default:')): 80*4882a593Smuzhiyun if not compile_lines: 81*4882a593Smuzhiyun in_compile = True 82*4882a593Smuzhiyun elif line: 83*4882a593Smuzhiyun if line[0] == '\t': 84*4882a593Smuzhiyun if in_install: 85*4882a593Smuzhiyun install_lines.append(line) 86*4882a593Smuzhiyun elif in_compile: 87*4882a593Smuzhiyun compile_lines.append(line) 88*4882a593Smuzhiyun elif ':' in line: 89*4882a593Smuzhiyun in_install = False 90*4882a593Smuzhiyun in_compile = False 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun def check_target(lines, install): 93*4882a593Smuzhiyun kdirpath = '' 94*4882a593Smuzhiyun manual_install = False 95*4882a593Smuzhiyun for line in lines: 96*4882a593Smuzhiyun splitline = line.split() 97*4882a593Smuzhiyun if splitline[0] in ['make', 'gmake', '$(MAKE)']: 98*4882a593Smuzhiyun if '-C' in splitline: 99*4882a593Smuzhiyun idx = splitline.index('-C') + 1 100*4882a593Smuzhiyun if idx < len(splitline): 101*4882a593Smuzhiyun kdirpath = splitline[idx] 102*4882a593Smuzhiyun break 103*4882a593Smuzhiyun elif install and splitline[0] == 'install': 104*4882a593Smuzhiyun if '.ko' in line: 105*4882a593Smuzhiyun manual_install = True 106*4882a593Smuzhiyun return kdirpath, manual_install 107*4882a593Smuzhiyun 108*4882a593Smuzhiyun kdirpath = None 109*4882a593Smuzhiyun manual_install = False 110*4882a593Smuzhiyun if install_lines: 111*4882a593Smuzhiyun kdirpath, manual_install = check_target(install_lines, install=True) 112*4882a593Smuzhiyun if compile_lines and not kdirpath: 113*4882a593Smuzhiyun kdirpath, _ = check_target(compile_lines, install=False) 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun if manual_install or not install_lines: 116*4882a593Smuzhiyun lines_after.append('EXTRA_OEMAKE:append:task-install = " -C ${STAGING_KERNEL_DIR} M=${S}"') 117*4882a593Smuzhiyun elif install_target and install_target != 'modules_install': 118*4882a593Smuzhiyun lines_after.append('MODULES_INSTALL_TARGET = "install"') 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun warnmsg = None 121*4882a593Smuzhiyun kdirvar = None 122*4882a593Smuzhiyun if kdirpath: 123*4882a593Smuzhiyun res = re.match(r'\$\(([^$)]+)\)', kdirpath) 124*4882a593Smuzhiyun if res: 125*4882a593Smuzhiyun kdirvar = res.group(1) 126*4882a593Smuzhiyun if kdirvar != 'KERNEL_SRC': 127*4882a593Smuzhiyun lines_after.append('EXTRA_OEMAKE += "%s=${STAGING_KERNEL_DIR}"' % kdirvar) 128*4882a593Smuzhiyun elif kdirpath.startswith('/lib/'): 129*4882a593Smuzhiyun warnmsg = 'Kernel path in install makefile is hardcoded - you will need to patch the makefile' 130*4882a593Smuzhiyun if not kdirvar and not warnmsg: 131*4882a593Smuzhiyun warnmsg = 'Unable to find means of passing kernel path into install makefile - if kernel path is hardcoded you will need to patch the makefile' 132*4882a593Smuzhiyun if warnmsg: 133*4882a593Smuzhiyun warnmsg += '. Note that the variable KERNEL_SRC will be passed in as the kernel source path.' 134*4882a593Smuzhiyun logger.warning(warnmsg) 135*4882a593Smuzhiyun lines_after.append('# %s' % warnmsg) 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun return True 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun return False 140*4882a593Smuzhiyun 141*4882a593Smuzhiyundef register_recipe_handlers(handlers): 142*4882a593Smuzhiyun handlers.append((KernelModuleRecipeHandler(), 15)) 143