source: kernel-config/kernel-config.py@ 5ca8d70

12.0 12.1 ken/TL2024 ken/tuningfonts lazarus plabs/newcss python3.11 rahul/power-profiles-daemon renodr/vulkan-addition trunk xry111/llvm18
Last change on this file since 5ca8d70 was 5ca8d70, checked in by Xi Ruoyao <xry111@…>, 11 months ago

kernel-config: Allow setting comments for options, and convert Mesa

  • Property mode set to 100755
File size: 6.5 KB
Line 
1#!/usr/bin/env python3
2
3# SPDX-License-Identifier: MIT
4# Copyright 2023 The LFS Editors
5
6# Stupid script to render "mconf"-style kernel configuration
7# Usage: kernel-config.py [path to kernel tree] [needed config].toml
8# The toml file should be like:
9# for bool and tristate:
10# EXT4="*"
11# DRM="*M"
12# EXPERT=" "
13# DRM_I915="*M"
14# for choice:
15# HIGHMEM64G="X"
16# an entry with comment:
17# DRM_I915 = { value = " *M", comment = "for i915, crocus, or iris" }
18
19choice_bit = 1 << 30
20ind0 = 0
21ind1 = 0
22menu_id = 1
23stack = []
24
25expand_var_mp = { 'SRCARCH': 'x86' }
26
27def expand_var(s):
28 for k in expand_var_mp:
29 s = s.replace('$(' + k + ')', expand_var_mp[k])
30 return s
31
32def pop_stack(cond):
33 global ind0, ind1, stack
34 assert(cond(stack[-1][0]))
35 s, i0, i1, _ = stack[-1]
36 stack = stack[:-1]
37 ind0 -= i0
38 ind1 -= i1
39
40def pop_stack_while(cond):
41 while len(stack) and cond(stack[-1][0]):
42 pop_stack(cond)
43
44def cur_menu():
45 global stack
46 return stack[-1][3] if len(stack) else 0
47
48def parse_config(buf):
49 global ind0, ind1, stack, menu_id
50 is_menu = buf[0].startswith('menu')
51 key = buf[0].split()[1].strip()
52
53 deps = ['menu']
54 title = None
55 klass = None
56 for line in buf[1:]:
57 line = line.strip()
58 if line.startswith('depends on '):
59 new_deps = line[len('depends on '):].split('&&')
60 deps += [x.strip() for x in new_deps]
61 else:
62 for prefix in ['tristate', 'bool', 'string']:
63 if line.startswith(prefix + ' '):
64 title = line[len(prefix) + 1:]
65 klass = prefix
66 elif line.startswith('def_' + prefix + ' '):
67 klass = prefix
68 elif line.startswith('prompt '):
69 title = line[len('prompt '):]
70
71 pop_stack_while(lambda x: x not in deps)
72
73 if key not in known_config:
74 return []
75 val = known_config[key]
76 comment = None
77
78 if type(val) == dict:
79 comment = val['comment']
80 val = val['value']
81
82 assert(title and klass)
83 title = title.strip('"')
84
85 if klass == 'string':
86 val = '(' + val + ')'
87 else:
88 assert((val == 'X') == bool(cur_menu() & choice_bit))
89 if (val == 'X'):
90 val = '(X)'
91 else:
92 val = list(val)
93 val.sort()
94 for c in val:
95 if c not in 'M* ' or (c == 'M' and klass != 'tristate'):
96 raise Exception('unknown setting %s for %s' % (c, key))
97 val = '/'.join(val)
98 if klass == 'tristate':
99 val = '<' + val + '>'
100 elif klass == 'bool':
101 val = '[' + val + ']'
102 else:
103 raise Exception('should not reach here')
104
105 arrow = ' --->' if is_menu else ''
106 r = [(ind0, val, ind1, title, arrow, key, cur_menu(), comment)]
107 menu_id += is_menu
108 stack_ent = (key, 2, 0, menu_id) if is_menu else (key, 0, 2, cur_menu())
109 ind0 += stack_ent[1]
110 ind1 += stack_ent[2]
111 stack += [stack_ent]
112 return r
113
114def parse_choice(buf):
115 global ind0, ind1, stack, menu_id
116 assert(buf[0] == 'choice\n')
117 title = ''
118 for line in buf:
119 line = line.strip()
120 if line.startswith('prompt '):
121 title = line[len('prompt '):].strip().strip('"')
122 r = [(ind0, "", ind1, title, ' --->', '', cur_menu(), None)]
123 menu_id += 1
124 stack += [('menu', 2, 0, menu_id | choice_bit)]
125 ind0 += 2
126 return r
127
128def load_kconfig(file):
129 global ind0, ind1, stack, path, menu_id
130 r = []
131 config_buf = []
132 with open(path + file) as f:
133 for line in f:
134 if len(config_buf):
135 if not line.startswith('\t'):
136 if config_buf[0] == 'choice\n':
137 r += parse_choice(config_buf)
138 else:
139 r += parse_config(config_buf)
140 config_buf = []
141 else:
142 config_buf += [line]
143 continue
144 if line.startswith('source'):
145 sub = expand_var(line.split()[1].strip('"'))
146 r += load_kconfig(sub)
147 elif line.startswith('config') or line.startswith('menuconfig'):
148 config_buf = [line]
149 elif line.startswith('choice'):
150 config_buf = [line]
151 elif line.startswith("menu"):
152 title = expand_var(line[4:].strip().strip('"'))
153 r += [(ind0, "", ind1, title, ' --->', '', cur_menu(), None)]
154 menu_id += 1
155 stack += [('menu', 2, 0, menu_id)]
156 ind0 += 2
157 elif line.startswith('endmenu') or line.startswith('endchoice'):
158 pop_stack_while(lambda x: x != 'menu')
159 pop_stack(lambda x: x == 'menu')
160 if r[-1][1] == "":
161 # prune empty menu
162 r = r[:-1]
163 return r
164
165known_config = {}
166
167from sys import argv
168import tomllib
169
170path = argv[1]
171if path[-1] != '/':
172 path += '/'
173with open(argv[2], 'rb') as f:
174 known_config = tomllib.load(f)
175
176r = load_kconfig("Kconfig")
177
178# Now we are going to pretty-print r
179
180## Calculate the maximum value length for each menu
181max_val_len = {}
182for _, val, _, _, _, _, menu, _ in r:
183 x = max_val_len[menu] if menu in max_val_len else 0
184 max_val_len[menu] = max(x, len(val))
185
186## Output
187
188max_line = 80
189buf = []
190
191done = [x[5] for x in r]
192for i in known_config:
193 if i not in done:
194 raise Exception("%s seems not exist" % i)
195
196for i0, val, i1, title, arrow, key, menu, comment in r:
197 if val:
198 val += (max_val_len[menu] - len(val)) * ' '
199 line = i0 * ' ' + val + (i1 + bool(val)) * ' '
200
201 rem = max_line - len(line) - len(arrow)
202
203 if len(title) > rem:
204 title = title[:rem - 3] + '...'
205
206 line += title + arrow
207 rem = max_line - len(line)
208
209 if key:
210 key = ' [' + key + ']'
211
212 if len(key) <= rem:
213 line += (rem - len(key)) * ' ' + key
214 else:
215 key = '... ' + key
216 line += '\n' + ' ' * (max_line - len(key)) + key
217 if comment:
218 line = ' ' * i0 + '# ' + comment + ':\n' + line
219 buf += [line.replace('<', '&lt;').replace('>', '&gt;').rstrip()]
220
221import kernel_version
222kver = kernel_version.kernel_version(path)
223
224print('''<?xml version="1.0" encoding="ISO-8859-1"?>
225<!DOCTYPE note PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
226 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">''')
227print('<!-- Automatically generated by kernel-config.py for Linux', kver)
228print(' DO NOT EDIT! -->')
229print('<screen><literal>' + '\n'.join(buf) + '</literal></screen>')
Note: See TracBrowser for help on using the repository browser.