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