xref: /OK3568_Linux_fs/yocto/poky/scripts/lib/recipetool/create_kmod.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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