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