blob: 4569b53c805185ed352eaf1974061c38f82d2b21 [file] [log] [blame]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001# 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
Brad Bishopd7bf8c12018-02-25 22:55:05 -050043 files = RecipeHandler.checkfiles(srctree, ['*.c', '*.h'], recursive=True, excludedirs=['contrib', 'test', 'examples'])
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050044 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
Patrick Williamsc0f7c042017-02-23 20:41:17 -060056 with open(cfile, 'r', errors='surrogateescape') as f:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050057 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
Patrick Williamsc0f7c042017-02-23 20:41:17 -060076 with open(makefile, 'r', errors='surrogateescape') as f:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050077 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.warn(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))