create_kmod.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. import re
  18. import logging
  19. from recipetool.create import RecipeHandler, read_pkgconfig_provides, validate_pv
  20. logger = logging.getLogger('recipetool')
  21. tinfoil = None
  22. def tinfoil_init(instance):
  23. global tinfoil
  24. tinfoil = instance
  25. class KernelModuleRecipeHandler(RecipeHandler):
  26. def process(self, srctree, classes, lines_before, lines_after, handled, extravalues):
  27. import bb.process
  28. if 'buildsystem' in handled:
  29. return False
  30. module_inc_re = re.compile(r'^#include\s+<linux/module.h>$')
  31. makefiles = []
  32. is_module = False
  33. makefiles = []
  34. files = RecipeHandler.checkfiles(srctree, ['*.c', '*.h'], recursive=True, excludedirs=['contrib', 'test', 'examples'])
  35. if files:
  36. for cfile in files:
  37. # Look in same dir or parent for Makefile
  38. for makefile in [os.path.join(os.path.dirname(cfile), 'Makefile'), os.path.join(os.path.dirname(os.path.dirname(cfile)), 'Makefile')]:
  39. if makefile in makefiles:
  40. break
  41. else:
  42. if os.path.exists(makefile):
  43. makefiles.append(makefile)
  44. break
  45. else:
  46. continue
  47. with open(cfile, 'r', errors='surrogateescape') as f:
  48. for line in f:
  49. if module_inc_re.match(line.strip()):
  50. is_module = True
  51. break
  52. if is_module:
  53. break
  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. def check_target(lines, install):
  92. kdirpath = ''
  93. manual_install = False
  94. for line in lines:
  95. splitline = line.split()
  96. if splitline[0] in ['make', 'gmake', '$(MAKE)']:
  97. if '-C' in splitline:
  98. idx = splitline.index('-C') + 1
  99. if idx < len(splitline):
  100. kdirpath = splitline[idx]
  101. break
  102. elif install and splitline[0] == 'install':
  103. if '.ko' in line:
  104. manual_install = True
  105. return kdirpath, manual_install
  106. kdirpath = None
  107. manual_install = False
  108. if install_lines:
  109. kdirpath, manual_install = check_target(install_lines, install=True)
  110. if compile_lines and not kdirpath:
  111. kdirpath, _ = check_target(compile_lines, install=False)
  112. if manual_install or not install_lines:
  113. lines_after.append('EXTRA_OEMAKE_append_task-install = " -C ${STAGING_KERNEL_DIR} M=${S}"')
  114. elif install_target and install_target != 'modules_install':
  115. lines_after.append('MODULES_INSTALL_TARGET = "install"')
  116. warnmsg = None
  117. kdirvar = None
  118. if kdirpath:
  119. res = re.match(r'\$\(([^$)]+)\)', kdirpath)
  120. if res:
  121. kdirvar = res.group(1)
  122. if kdirvar != 'KERNEL_SRC':
  123. lines_after.append('EXTRA_OEMAKE += "%s=${STAGING_KERNEL_DIR}"' % kdirvar)
  124. elif kdirpath.startswith('/lib/'):
  125. warnmsg = 'Kernel path in install makefile is hardcoded - you will need to patch the makefile'
  126. if not kdirvar and not warnmsg:
  127. warnmsg = 'Unable to find means of passing kernel path into install makefile - if kernel path is hardcoded you will need to patch the makefile'
  128. if warnmsg:
  129. warnmsg += '. Note that the variable KERNEL_SRC will be passed in as the kernel source path.'
  130. logger.warning(warnmsg)
  131. lines_after.append('# %s' % warnmsg)
  132. return True
  133. return False
  134. def register_recipe_handlers(handlers):
  135. handlers.append((KernelModuleRecipeHandler(), 15))