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