create_kmod.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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. import re
  8. import logging
  9. from recipetool.create import RecipeHandler, read_pkgconfig_provides, validate_pv
  10. logger = logging.getLogger('recipetool')
  11. tinfoil = None
  12. def tinfoil_init(instance):
  13. global tinfoil
  14. tinfoil = instance
  15. class KernelModuleRecipeHandler(RecipeHandler):
  16. def process(self, srctree, classes, lines_before, lines_after, handled, extravalues):
  17. import bb.process
  18. if 'buildsystem' in handled:
  19. return False
  20. module_inc_re = re.compile(r'^#include\s+<linux/module.h>$')
  21. makefiles = []
  22. is_module = False
  23. makefiles = []
  24. files = RecipeHandler.checkfiles(srctree, ['*.c', '*.h'], recursive=True, excludedirs=['contrib', 'test', 'examples'])
  25. if files:
  26. for cfile in files:
  27. # Look in same dir or parent for Makefile
  28. for makefile in [os.path.join(os.path.dirname(cfile), 'Makefile'), os.path.join(os.path.dirname(os.path.dirname(cfile)), 'Makefile')]:
  29. if makefile in makefiles:
  30. break
  31. else:
  32. if os.path.exists(makefile):
  33. makefiles.append(makefile)
  34. break
  35. else:
  36. continue
  37. with open(cfile, 'r', errors='surrogateescape') as f:
  38. for line in f:
  39. if module_inc_re.match(line.strip()):
  40. is_module = True
  41. break
  42. if is_module:
  43. break
  44. if is_module:
  45. classes.append('module')
  46. handled.append('buildsystem')
  47. # module.bbclass and the classes it inherits do most of the hard
  48. # work, but we need to tweak it slightly depending on what the
  49. # Makefile does (and there is a range of those)
  50. # Check the makefile for the appropriate install target
  51. install_lines = []
  52. compile_lines = []
  53. in_install = False
  54. in_compile = False
  55. install_target = None
  56. with open(makefile, 'r', errors='surrogateescape') as f:
  57. for line in f:
  58. if line.startswith('install:'):
  59. if not install_lines:
  60. in_install = True
  61. install_target = 'install'
  62. elif line.startswith('modules_install:'):
  63. install_lines = []
  64. in_install = True
  65. install_target = 'modules_install'
  66. elif line.startswith('modules:'):
  67. compile_lines = []
  68. in_compile = True
  69. elif line.startswith(('all:', 'default:')):
  70. if not compile_lines:
  71. in_compile = True
  72. elif line:
  73. if line[0] == '\t':
  74. if in_install:
  75. install_lines.append(line)
  76. elif in_compile:
  77. compile_lines.append(line)
  78. elif ':' in line:
  79. in_install = False
  80. in_compile = False
  81. def check_target(lines, install):
  82. kdirpath = ''
  83. manual_install = False
  84. for line in lines:
  85. splitline = line.split()
  86. if splitline[0] in ['make', 'gmake', '$(MAKE)']:
  87. if '-C' in splitline:
  88. idx = splitline.index('-C') + 1
  89. if idx < len(splitline):
  90. kdirpath = splitline[idx]
  91. break
  92. elif install and splitline[0] == 'install':
  93. if '.ko' in line:
  94. manual_install = True
  95. return kdirpath, manual_install
  96. kdirpath = None
  97. manual_install = False
  98. if install_lines:
  99. kdirpath, manual_install = check_target(install_lines, install=True)
  100. if compile_lines and not kdirpath:
  101. kdirpath, _ = check_target(compile_lines, install=False)
  102. if manual_install or not install_lines:
  103. lines_after.append('EXTRA_OEMAKE_append_task-install = " -C ${STAGING_KERNEL_DIR} M=${S}"')
  104. elif install_target and install_target != 'modules_install':
  105. lines_after.append('MODULES_INSTALL_TARGET = "install"')
  106. warnmsg = None
  107. kdirvar = None
  108. if kdirpath:
  109. res = re.match(r'\$\(([^$)]+)\)', kdirpath)
  110. if res:
  111. kdirvar = res.group(1)
  112. if kdirvar != 'KERNEL_SRC':
  113. lines_after.append('EXTRA_OEMAKE += "%s=${STAGING_KERNEL_DIR}"' % kdirvar)
  114. elif kdirpath.startswith('/lib/'):
  115. warnmsg = 'Kernel path in install makefile is hardcoded - you will need to patch the makefile'
  116. if not kdirvar and not warnmsg:
  117. warnmsg = 'Unable to find means of passing kernel path into install makefile - if kernel path is hardcoded you will need to patch the makefile'
  118. if warnmsg:
  119. warnmsg += '. Note that the variable KERNEL_SRC will be passed in as the kernel source path.'
  120. logger.warning(warnmsg)
  121. lines_after.append('# %s' % warnmsg)
  122. return True
  123. return False
  124. def register_recipe_handlers(handlers):
  125. handlers.append((KernelModuleRecipeHandler(), 15))