We're opening source files with the default encoding (utf-8) but we can't necessarily be sure that they are UTF-8 clean - for example, recipetool create ftp://mama.indstate.edu/linux/tree/tree-1.7.0.tgz prior to this patch resulted in a UnicodeDecodeError. Use the "surrogateescape" mode to avoid this. Fixes [YOCTO #9822]. (From OE-Core rev: 50fcd9d1b9a20d49bc873467a82a071f2f2f8b5a) Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Ross Burton <ross.burton@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
153 lines
6.3 KiB
Python
153 lines
6.3 KiB
Python
# Recipe creation tool - kernel module support plugin
|
|
#
|
|
# Copyright (C) 2016 Intel Corporation
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License version 2 as
|
|
# published by the Free Software Foundation.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
import re
|
|
import logging
|
|
from recipetool.create import RecipeHandler, read_pkgconfig_provides, validate_pv
|
|
|
|
logger = logging.getLogger('recipetool')
|
|
|
|
tinfoil = None
|
|
|
|
def tinfoil_init(instance):
|
|
global tinfoil
|
|
tinfoil = instance
|
|
|
|
|
|
class KernelModuleRecipeHandler(RecipeHandler):
|
|
def process(self, srctree, classes, lines_before, lines_after, handled, extravalues):
|
|
import bb.process
|
|
if 'buildsystem' in handled:
|
|
return False
|
|
|
|
module_inc_re = re.compile(r'^#include\s+<linux/module.h>$')
|
|
makefiles = []
|
|
is_module = False
|
|
|
|
makefiles = []
|
|
|
|
files = RecipeHandler.checkfiles(srctree, ['*.c', '*.h'], recursive=True)
|
|
if files:
|
|
for cfile in files:
|
|
# Look in same dir or parent for Makefile
|
|
for makefile in [os.path.join(os.path.dirname(cfile), 'Makefile'), os.path.join(os.path.dirname(os.path.dirname(cfile)), 'Makefile')]:
|
|
if makefile in makefiles:
|
|
break
|
|
else:
|
|
if os.path.exists(makefile):
|
|
makefiles.append(makefile)
|
|
break
|
|
else:
|
|
continue
|
|
with open(cfile, 'r', errors='surrogateescape') as f:
|
|
for line in f:
|
|
if module_inc_re.match(line.strip()):
|
|
is_module = True
|
|
break
|
|
if is_module:
|
|
break
|
|
|
|
if is_module:
|
|
classes.append('module')
|
|
handled.append('buildsystem')
|
|
# module.bbclass and the classes it inherits do most of the hard
|
|
# work, but we need to tweak it slightly depending on what the
|
|
# Makefile does (and there is a range of those)
|
|
# Check the makefile for the appropriate install target
|
|
install_lines = []
|
|
compile_lines = []
|
|
in_install = False
|
|
in_compile = False
|
|
install_target = None
|
|
with open(makefile, 'r', errors='surrogateescape') as f:
|
|
for line in f:
|
|
if line.startswith('install:'):
|
|
if not install_lines:
|
|
in_install = True
|
|
install_target = 'install'
|
|
elif line.startswith('modules_install:'):
|
|
install_lines = []
|
|
in_install = True
|
|
install_target = 'modules_install'
|
|
elif line.startswith('modules:'):
|
|
compile_lines = []
|
|
in_compile = True
|
|
elif line.startswith(('all:', 'default:')):
|
|
if not compile_lines:
|
|
in_compile = True
|
|
elif line:
|
|
if line[0] == '\t':
|
|
if in_install:
|
|
install_lines.append(line)
|
|
elif in_compile:
|
|
compile_lines.append(line)
|
|
elif ':' in line:
|
|
in_install = False
|
|
in_compile = False
|
|
|
|
def check_target(lines, install):
|
|
kdirpath = ''
|
|
manual_install = False
|
|
for line in lines:
|
|
splitline = line.split()
|
|
if splitline[0] in ['make', 'gmake', '$(MAKE)']:
|
|
if '-C' in splitline:
|
|
idx = splitline.index('-C') + 1
|
|
if idx < len(splitline):
|
|
kdirpath = splitline[idx]
|
|
break
|
|
elif install and splitline[0] == 'install':
|
|
if '.ko' in line:
|
|
manual_install = True
|
|
return kdirpath, manual_install
|
|
|
|
kdirpath = None
|
|
manual_install = False
|
|
if install_lines:
|
|
kdirpath, manual_install = check_target(install_lines, install=True)
|
|
if compile_lines and not kdirpath:
|
|
kdirpath, _ = check_target(compile_lines, install=False)
|
|
|
|
if manual_install or not install_lines:
|
|
lines_after.append('EXTRA_OEMAKE_append_task-install = " -C ${STAGING_KERNEL_DIR} M=${S}"')
|
|
elif install_target and install_target != 'modules_install':
|
|
lines_after.append('MODULES_INSTALL_TARGET = "install"')
|
|
|
|
warnmsg = None
|
|
kdirvar = None
|
|
if kdirpath:
|
|
res = re.match(r'\$\(([^$)]+)\)', kdirpath)
|
|
if res:
|
|
kdirvar = res.group(1)
|
|
if kdirvar != 'KERNEL_SRC':
|
|
lines_after.append('EXTRA_OEMAKE += "%s=${STAGING_KERNEL_DIR}"' % kdirvar)
|
|
elif kdirpath.startswith('/lib/'):
|
|
warnmsg = 'Kernel path in install makefile is hardcoded - you will need to patch the makefile'
|
|
if not kdirvar and not warnmsg:
|
|
warnmsg = 'Unable to find means of passing kernel path into install makefile - if kernel path is hardcoded you will need to patch the makefile'
|
|
if warnmsg:
|
|
warnmsg += '. Note that the variable KERNEL_SRC will be passed in as the kernel source path.'
|
|
logger.warn(warnmsg)
|
|
lines_after.append('# %s' % warnmsg)
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
def register_recipe_handlers(handlers):
|
|
handlers.append((KernelModuleRecipeHandler(), 15))
|