multiconfig.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. #!/usr/bin/env python
  2. #
  3. # Copyright (C) 2014, Masahiro Yamada <yamada.m@jp.panasonic.com>
  4. #
  5. # SPDX-License-Identifier: GPL-2.0+
  6. #
  7. """
  8. A wrapper script to adjust Kconfig for U-Boot
  9. The biggest difference between Linux Kernel and U-Boot in terms of the
  10. board configuration is that U-Boot has to configure multiple boot images
  11. per board: Normal, SPL, TPL.
  12. We need to expand the functions of Kconfig to handle multiple boot
  13. images.
  14. Instead of touching various parts under the scripts/kconfig/ directory,
  15. pushing necessary adjustments into this single script would be better
  16. for code maintainance. All the make targets related to the configuration
  17. (make %config) should be invoked via this script.
  18. Let's see what is different from the original Kconfig.
  19. - config, menuconfig, etc.
  20. The commands 'make config', 'make menuconfig', etc. are used to create
  21. or modify the .config file, which stores configs for Normal boot image.
  22. The location of the one for SPL, TPL image is spl/.config, tpl/.config,
  23. respectively. Use 'make spl/config', 'make spl/menuconfig', etc.
  24. to create or modify the spl/.config file, which contains configs
  25. for SPL image.
  26. Do likewise for the tpl/.config file.
  27. The generic syntax for SPL, TPL configuration is
  28. 'make <target_image>/<config_command>'.
  29. - silentoldconfig
  30. The command 'make silentoldconfig' updates .config, if necessary, and
  31. additionally updates include/generated/autoconf.h and files under
  32. include/configs/ directory. In U-Boot, it should do the same things for
  33. SPL, TPL images for boards supporting them.
  34. Depending on whether CONFIG_SPL, CONFIG_TPL is defined or not,
  35. 'make silentoldconfig' iterates three times at most changing the target
  36. directory.
  37. To sum up, 'make silentoldconfig' possibly updates
  38. - .config, include/generated/autoconf.h, include/config/*
  39. - spl/.config, spl/include/generated/autoconf.h, spl/include/config/*
  40. (in case CONFIG_SPL=y)
  41. - tpl/.config, tpl/include/generated/autoconf.h, tpl/include/config/*
  42. (in case CONFIG_TPL=y)
  43. - defconfig, <board>_defconfig
  44. The command 'make <board>_defconfig' creates a new .config based on the
  45. file configs/<board>_defconfig. The command 'make defconfig' is the same
  46. but the difference is it uses the file specified with KBUILD_DEFCONFIG
  47. environment.
  48. We need to create .config, spl/.config, tpl/.config for boards where SPL
  49. and TPL images are supported. One possible solution for that is to have
  50. multiple defconfig files per board, but it would produce duplication
  51. among the defconfigs.
  52. The approach chosen here is to expand the feature and support
  53. conditional definition in defconfig, that is, each line in defconfig
  54. files has the form of:
  55. <condition>:<macro definition>
  56. The '<condition>:' prefix specifies which image the line is valid for.
  57. The '<condition>:' is one of:
  58. None - the line is valid only for Normal image
  59. S: - the line is valid only for SPL image
  60. T: - the line is valid only for TPL image
  61. ST: - the line is valid for SPL and TPL images
  62. +S: - the line is valid for Normal and SPL images
  63. +T: - the line is valid for Normal and TPL images
  64. +ST: - the line is valid for Normal, SPL and SPL images
  65. So, if neither CONFIG_SPL nor CONFIG_TPL is defined, the defconfig file
  66. has no '<condition>:' part and therefore has the same form of that of
  67. Linux Kernel.
  68. In U-Boot, for example, a defconfig file can be written like this:
  69. CONFIG_FOO=100
  70. S:CONFIG_FOO=200
  71. T:CONFIG_FOO=300
  72. ST:CONFIG_BAR=y
  73. +S:CONFIG_BAZ=y
  74. +T:CONFIG_QUX=y
  75. +ST:CONFIG_QUUX=y
  76. The defconfig above is parsed by this script and internally divided into
  77. three temporary defconfig files.
  78. - Temporary defconfig for Normal image
  79. CONFIG_FOO=100
  80. CONFIG_BAZ=y
  81. CONFIG_QUX=y
  82. CONFIG_QUUX=y
  83. - Temporary defconfig for SPL image
  84. CONFIG_FOO=200
  85. CONFIG_BAR=y
  86. CONFIG_BAZ=y
  87. CONFIG_QUUX=y
  88. - Temporary defconfig for TPL image
  89. CONFIG_FOO=300
  90. CONFIG_BAR=y
  91. CONFIG_QUX=y
  92. CONFIG_QUUX=y
  93. They are passed to scripts/kconfig/conf, each is used for generating
  94. .config, spl/.config, tpl/.config, respectively.
  95. - savedefconfig
  96. This is the reverse operation of 'make defconfig'.
  97. If neither CONFIG_SPL nor CONFIG_TPL is defined in the .config file,
  98. it works as 'make savedefconfig' in Linux Kernel: create the minimal set
  99. of config based on the .config and save it into 'defconfig' file.
  100. If CONFIG_SPL or CONFIG_TPL is defined, the common lines among .config,
  101. spl/.config, tpl/.config are coalesced together and output to the file
  102. 'defconfig' in the form like:
  103. CONFIG_FOO=100
  104. S:CONFIG_FOO=200
  105. T:CONFIG_FOO=300
  106. ST:CONFIG_BAR=y
  107. +S:CONFIG_BAZ=y
  108. +T:CONFIG_QUX=y
  109. +ST:CONFIG_QUUX=y
  110. This can be used as an input of 'make <board>_defconfig' command.
  111. """
  112. import errno
  113. import os
  114. import re
  115. import subprocess
  116. import sys
  117. # Constant variables
  118. SUB_IMAGES = ('spl', 'tpl')
  119. IMAGES = ('',) + SUB_IMAGES
  120. SYMBOL_MAP = {'': '+', 'spl': 'S', 'tpl': 'T'}
  121. PATTERN_SYMBOL = re.compile(r'(\+?)(S?)(T?):(.*)')
  122. # Environment variables (should be defined in the top Makefile)
  123. # .get('key', 'default_value') method is useful for standalone testing.
  124. MAKE = os.environ.get('MAKE', 'make')
  125. srctree = os.environ.get('srctree', '.')
  126. KCONFIG_CONFIG = os.environ.get('KCONFIG_CONFIG', '.config')
  127. # Useful shorthand
  128. build = '%s -f %s/scripts/Makefile.build obj=scripts/kconfig %%s' % (MAKE, srctree)
  129. autoconf = '%s -f %s/scripts/Makefile.autoconf obj=%%s %%s' % (MAKE, srctree)
  130. ### helper functions ###
  131. def mkdirs(*dirs):
  132. """Make directories ignoring 'File exists' error."""
  133. for d in dirs:
  134. try:
  135. os.makedirs(d)
  136. except OSError as exception:
  137. # Ignore 'File exists' error
  138. if exception.errno != errno.EEXIST:
  139. raise
  140. def rmfiles(*files):
  141. """Remove files ignoring 'No such file or directory' error."""
  142. for f in files:
  143. try:
  144. os.remove(f)
  145. except OSError as exception:
  146. # Ignore 'No such file or directory' error
  147. if exception.errno != errno.ENOENT:
  148. raise
  149. def rmdirs(*dirs):
  150. """Remove directories ignoring 'No such file or directory'
  151. and 'Directory not empty' error.
  152. """
  153. for d in dirs:
  154. try:
  155. os.rmdir(d)
  156. except OSError as exception:
  157. # Ignore 'No such file or directory'
  158. # and 'Directory not empty' error
  159. if exception.errno != errno.ENOENT and \
  160. exception.errno != errno.ENOTEMPTY:
  161. raise
  162. def error(msg):
  163. """Output the given argument to stderr and exit with return code 1."""
  164. print >> sys.stderr, msg
  165. sys.exit(1)
  166. def run_command(command, callback_on_error=None):
  167. """Run the given command in a sub-shell (and exit if it fails).
  168. Arguments:
  169. command: A string of the command
  170. callback_on_error: Callback handler invoked just before exit
  171. when the command fails (Default=None)
  172. """
  173. retcode = subprocess.call(command, shell=True)
  174. if retcode:
  175. if callback_on_error:
  176. callback_on_error()
  177. error("'%s' Failed" % command)
  178. def run_make_config(cmd, objdir, callback_on_error=None):
  179. """Run the make command in a sub-shell (and exit if it fails).
  180. Arguments:
  181. cmd: Make target such as 'config', 'menuconfig', 'defconfig', etc.
  182. objdir: Target directory where the make command is run.
  183. Typically '', 'spl', 'tpl' for Normal, SPL, TPL image,
  184. respectively.
  185. callback_on_error: Callback handler invoked just before exit
  186. when the command fails (Default=None)
  187. """
  188. # Linux expects defconfig files in arch/$(SRCARCH)/configs/ directory,
  189. # but U-Boot puts them in configs/ directory.
  190. # Give SRCARCH=.. to fake scripts/kconfig/Makefile.
  191. options = 'SRCARCH=.. KCONFIG_OBJDIR=%s' % objdir
  192. if objdir:
  193. options += ' KCONFIG_CONFIG=%s/%s' % (objdir, KCONFIG_CONFIG)
  194. mkdirs(objdir)
  195. run_command(build % cmd + ' ' + options, callback_on_error)
  196. def get_enabled_subimages(ignore_error=False):
  197. """Parse .config file to detect if CONFIG_SPL, CONFIG_TPL is enabled
  198. and return a tuple of enabled subimages.
  199. Arguments:
  200. ignore_error: Specify the behavior when '.config' is not found;
  201. Raise an exception if this flag is False.
  202. Return a null tuple if this flag is True.
  203. Returns:
  204. A tuple of enabled subimages as follows:
  205. () if neither CONFIG_SPL nor CONFIG_TPL is defined
  206. ('spl',) if CONFIG_SPL is defined but CONFIG_TPL is not
  207. ('spl', 'tpl') if both CONFIG_SPL and CONFIG_TPL are defined
  208. """
  209. enabled = ()
  210. match_patterns = [ (img, 'CONFIG_' + img.upper() + '=y\n')
  211. for img in SUB_IMAGES ]
  212. try:
  213. f = open(KCONFIG_CONFIG)
  214. except IOError as exception:
  215. if not ignore_error or exception.errno != errno.ENOENT:
  216. raise
  217. return enabled
  218. with f:
  219. for line in f:
  220. for img, pattern in match_patterns:
  221. if line == pattern:
  222. enabled += (img,)
  223. return enabled
  224. def do_silentoldconfig(cmd):
  225. """Run 'make silentoldconfig' for all the enabled images.
  226. Arguments:
  227. cmd: should always be a string 'silentoldconfig'
  228. """
  229. run_make_config(cmd, '')
  230. subimages = get_enabled_subimages()
  231. for obj in subimages:
  232. mkdirs(os.path.join(obj, 'include', 'config'),
  233. os.path.join(obj, 'include', 'generated'))
  234. run_make_config(cmd, obj)
  235. remove_auto_conf = lambda : rmfiles('include/config/auto.conf')
  236. # If the following part failed, include/config/auto.conf should be deleted
  237. # so 'make silentoldconfig' will be re-run on the next build.
  238. run_command(autoconf %
  239. ('include', 'include/autoconf.mk include/autoconf.mk.dep'),
  240. remove_auto_conf)
  241. # include/config.h has been updated after 'make silentoldconfig'.
  242. # We need to touch include/config/auto.conf so it gets newer
  243. # than include/config.h.
  244. # Otherwise, 'make silentoldconfig' would be invoked twice.
  245. os.utime('include/config/auto.conf', None)
  246. for obj in subimages:
  247. run_command(autoconf % (obj + '/include',
  248. obj + '/include/autoconf.mk'),
  249. remove_auto_conf)
  250. def do_tmp_defconfig(output_lines, img):
  251. """Helper function for do_board_defconfig().
  252. Write the defconfig contents into a file '.tmp_defconfig' and
  253. invoke 'make .tmp_defconfig'.
  254. Arguments:
  255. output_lines: A sequence of defconfig lines of each image
  256. img: Target image. Typically '', 'spl', 'tpl' for
  257. Normal, SPL, TPL images, respectively.
  258. """
  259. TMP_DEFCONFIG = '.tmp_defconfig'
  260. TMP_DIRS = ('arch', 'configs')
  261. defconfig_path = os.path.join('configs', TMP_DEFCONFIG)
  262. mkdirs(*TMP_DIRS)
  263. with open(defconfig_path, 'w') as f:
  264. f.write(''.join(output_lines[img]))
  265. cleanup = lambda: (rmfiles(defconfig_path), rmdirs(*TMP_DIRS))
  266. run_make_config(TMP_DEFCONFIG, img, cleanup)
  267. cleanup()
  268. def do_board_defconfig(cmd):
  269. """Run 'make <board>_defconfig'.
  270. Arguments:
  271. cmd: should be a string '<board>_defconfig'
  272. """
  273. defconfig_path = os.path.join(srctree, 'configs', cmd)
  274. output_lines = dict([ (img, []) for img in IMAGES ])
  275. with open(defconfig_path) as f:
  276. for line in f:
  277. m = PATTERN_SYMBOL.match(line)
  278. if m:
  279. for idx, img in enumerate(IMAGES):
  280. if m.group(idx + 1):
  281. output_lines[img].append(m.group(4) + '\n')
  282. continue
  283. output_lines[''].append(line)
  284. do_tmp_defconfig(output_lines, '')
  285. for img in get_enabled_subimages():
  286. do_tmp_defconfig(output_lines, img)
  287. def do_defconfig(cmd):
  288. """Run 'make defconfig'.
  289. Arguments:
  290. cmd: should always be a string 'defconfig'
  291. """
  292. KBUILD_DEFCONFIG = os.environ['KBUILD_DEFCONFIG']
  293. print "*** Default configuration is based on '%s'" % KBUILD_DEFCONFIG
  294. do_board_defconfig(KBUILD_DEFCONFIG)
  295. def do_savedefconfig(cmd):
  296. """Run 'make savedefconfig'.
  297. Arguments:
  298. cmd: should always be a string 'savedefconfig'
  299. """
  300. DEFCONFIG = 'defconfig'
  301. # Continue even if '.config' does not exist
  302. subimages = get_enabled_subimages(True)
  303. run_make_config(cmd, '')
  304. output_lines = []
  305. prefix = {}
  306. with open(DEFCONFIG) as f:
  307. for line in f:
  308. output_lines.append(line)
  309. prefix[line] = '+'
  310. for img in subimages:
  311. run_make_config(cmd, img)
  312. unmatched_lines = []
  313. with open(DEFCONFIG) as f:
  314. for line in f:
  315. if line in output_lines:
  316. index = output_lines.index(line)
  317. output_lines[index:index] = unmatched_lines
  318. unmatched_lines = []
  319. prefix[line] += SYMBOL_MAP[img]
  320. else:
  321. ummatched_lines.append(line)
  322. prefix[line] = SYMBOL_MAP[img]
  323. with open(DEFCONFIG, 'w') as f:
  324. for line in output_lines:
  325. if prefix[line] == '+':
  326. f.write(line)
  327. else:
  328. f.write(prefix[line] + ':' + line)
  329. def do_others(cmd):
  330. """Run the make command other than 'silentoldconfig', 'defconfig',
  331. '<board>_defconfig' and 'savedefconfig'.
  332. Arguments:
  333. cmd: Make target in the form of '<target_image>/<config_command>'
  334. The field '<target_image>/' is typically empty, 'spl/', 'tpl/'
  335. for Normal, SPL, TPL images, respectively.
  336. The field '<config_command>' is make target such as 'config',
  337. 'menuconfig', etc.
  338. """
  339. objdir, _, cmd = cmd.rpartition('/')
  340. run_make_config(cmd, objdir)
  341. cmd_list = {'silentoldconfig': do_silentoldconfig,
  342. 'defconfig': do_defconfig,
  343. 'savedefconfig': do_savedefconfig}
  344. def main():
  345. cmd = sys.argv[1]
  346. if cmd.endswith('_defconfig'):
  347. do_board_defconfig(cmd)
  348. else:
  349. func = cmd_list.get(cmd, do_others)
  350. func(cmd)
  351. if __name__ == '__main__':
  352. main()