1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
|
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# merge_config.sh - Takes a list of config fragment values, and merges
# them one by one. Provides warnings on overridden values, and specified
# values that did not make it to the resulting .config file (due to missed
# dependencies or config symbol removal).
#
# Portions reused from kconf_check and generate_cfg:
# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check
# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg
#
# Copyright (c) 2009-2010 Wind River Systems, Inc.
# Copyright 2011 Linaro
set -e
clean_up() {
rm -f "$TMP_FILE"
rm -f "$TMP_FILE.new"
}
usage() {
echo "Usage: $0 [OPTIONS] [CONFIG [...]]"
echo " -h display this help text"
echo " -m only merge the fragments, do not execute the make command"
echo " -n use allnoconfig instead of alldefconfig"
echo " -r list redundant entries when merging fragments"
echo " -y make builtin have precedence over modules"
echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead."
echo " -s strict mode. Fail if the fragment redefines any value."
echo " -Q disable warning messages for overridden options."
echo
echo "Used prefix: '$CONFIG_PREFIX'. You can redefine it with \$CONFIG_ environment variable."
}
RUNMAKE=true
ALLTARGET=alldefconfig
WARNREDUN=false
BUILTIN=false
OUTPUT=.
STRICT=false
CONFIG_PREFIX=${CONFIG_-CONFIG_}
WARNOVERRIDE=echo
if [ -z "$AWK" ]; then
AWK=awk
fi
while true; do
case $1 in
"-n")
ALLTARGET=allnoconfig
shift
continue
;;
"-m")
RUNMAKE=false
shift
continue
;;
"-h")
usage
exit
;;
"-r")
WARNREDUN=true
shift
continue
;;
"-y")
BUILTIN=true
shift
continue
;;
"-O")
if [ -d $2 ];then
OUTPUT=$(echo $2 | sed 's/\/*$//')
else
echo "output directory $2 does not exist" 1>&2
exit 1
fi
shift 2
continue
;;
"-s")
STRICT=true
shift
continue
;;
"-Q")
WARNOVERRIDE=true
shift
continue
;;
*)
break
;;
esac
done
if [ "$#" -lt 1 ] ; then
usage
exit
fi
if [ -z "$KCONFIG_CONFIG" ]; then
if [ "$OUTPUT" != . ]; then
KCONFIG_CONFIG=$(readlink -m -- "$OUTPUT/.config")
else
KCONFIG_CONFIG=.config
fi
fi
INITFILE=$1
shift;
if [ ! -r "$INITFILE" ]; then
echo "The base file '$INITFILE' does not exist. Creating one..." >&2
touch "$INITFILE"
fi
MERGE_LIST=$*
TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
echo "Using $INITFILE as base"
trap clean_up EXIT
cat $INITFILE > $TMP_FILE
PROCESSED_FILES=""
# Merge files, printing warnings on overridden values
for ORIG_MERGE_FILE in $MERGE_LIST ; do
echo "Merging $ORIG_MERGE_FILE"
if [ ! -r "$ORIG_MERGE_FILE" ]; then
echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2
exit 1
fi
# Check for duplicate input files
case " $PROCESSED_FILES " in
*" $ORIG_MERGE_FILE "*)
${WARNOVERRIDE} "WARNING: Input file provided multiple times: $ORIG_MERGE_FILE"
;;
esac
# Use awk for single-pass processing instead of per-symbol grep/sed
if ! "$AWK" -v prefix="$CONFIG_PREFIX" \
-v warnoverride="$WARNOVERRIDE" \
-v strict="$STRICT" \
-v outfile="$TMP_FILE.new" \
-v builtin="$BUILTIN" \
-v warnredun="$WARNREDUN" '
BEGIN {
strict_violated = 0
cfg_regex = "^" prefix "[a-zA-Z0-9_]+"
notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$"
}
# Extract config name from a line, returns "" if not a config line
function get_cfg(line) {
if (match(line, cfg_regex)) {
return substr(line, RSTART, RLENGTH)
} else if (match(line, notset_regex)) {
# Extract CONFIG_FOO from "# CONFIG_FOO is not set"
sub(/^# /, "", line)
sub(/ is not set$/, "", line)
return line
}
return ""
}
function warn_builtin(cfg, prev, new) {
if (warnoverride == "true") return
print cfg ": -y passed, will not demote y to m"
print "Previous value: " prev
print "New value: " new
print ""
}
function warn_redefined(cfg, prev, new) {
if (warnoverride == "true") return
print "Value of " cfg " is redefined by fragment " mergefile ":"
print "Previous value: " prev
print "New value: " new
print ""
}
function warn_redundant(cfg) {
if (warnredun != "true" || warnoverride == "true") return
print "Value of " cfg " is redundant by fragment " mergefile ":"
}
# First pass: read merge file, store all lines and index
FILENAME == ARGV[1] {
mergefile = FILENAME
merge_lines[FNR] = $0
merge_total = FNR
cfg = get_cfg($0)
if (cfg != "") {
merge_cfg[cfg] = $0
merge_cfg_line[cfg] = FNR
}
next
}
# Second pass: process base file (TMP_FILE)
FILENAME == ARGV[2] {
cfg = get_cfg($0)
# Not a config or not in merge file - keep it
if (cfg == "" || !(cfg in merge_cfg)) {
print $0 >> outfile
next
}
prev_val = $0
new_val = merge_cfg[cfg]
# BUILTIN: do not demote y to m
if (builtin == "true" && new_val ~ /=m$/ && prev_val ~ /=y$/) {
warn_builtin(cfg, prev_val, new_val)
print $0 >> outfile
skip_merge[merge_cfg_line[cfg]] = 1
next
}
# Values equal - redundant
if (prev_val == new_val) {
warn_redundant(cfg)
next
}
# "=n" is the same as "is not set"
if (prev_val ~ /=n$/ && new_val ~ / is not set$/) {
print $0 >> outfile
next
}
# Values differ - redefined
warn_redefined(cfg, prev_val, new_val)
if (strict == "true") {
strict_violated = 1
}
}
END {
# Newline in case base file lacks trailing newline
print "" >> outfile
# Append merge file, skipping lines marked for builtin preservation
for (i = 1; i <= merge_total; i++) {
if (!(i in skip_merge)) {
print merge_lines[i] >> outfile
}
}
if (strict_violated) {
exit 1
}
}' \
"$ORIG_MERGE_FILE" "$TMP_FILE"; then
# awk exited non-zero, strict mode was violated
STRICT_MODE_VIOLATED=true
fi
mv "$TMP_FILE.new" "$TMP_FILE"
PROCESSED_FILES="$PROCESSED_FILES $ORIG_MERGE_FILE"
done
if [ "$STRICT_MODE_VIOLATED" = "true" ]; then
echo "The fragment redefined a value and strict mode had been passed."
exit 1
fi
if [ "$RUNMAKE" = "false" ]; then
cp -T -- "$TMP_FILE" "$KCONFIG_CONFIG"
echo "#"
echo "# merged configuration written to $KCONFIG_CONFIG (needs make)"
echo "#"
exit
fi
# If we have an output dir, setup the O= argument, otherwise leave
# it blank, since O=. will create an unnecessary ./source softlink
OUTPUT_ARG=""
if [ "$OUTPUT" != "." ] ; then
OUTPUT_ARG="O=$OUTPUT"
fi
# Use the merged file as the starting point for:
# alldefconfig: Fills in any missing symbols with Kconfig default
# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
# Check all specified config values took effect (might have missed-dependency issues)
if ! "$AWK" -v prefix="$CONFIG_PREFIX" \
-v warnoverride="$WARNOVERRIDE" \
-v strict="$STRICT" \
-v warnredun="$WARNREDUN" '
BEGIN {
strict_violated = 0
cfg_regex = "^" prefix "[a-zA-Z0-9_]+"
notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$"
}
# Extract config name from a line, returns "" if not a config line
function get_cfg(line) {
if (match(line, cfg_regex)) {
return substr(line, RSTART, RLENGTH)
} else if (match(line, notset_regex)) {
# Extract CONFIG_FOO from "# CONFIG_FOO is not set"
sub(/^# /, "", line)
sub(/ is not set$/, "", line)
return line
}
return ""
}
function warn_mismatch(cfg, merged, final) {
if (warnredun == "true") return
if (final == "" && !(merged ~ / is not set$/ || merged ~ /=n$/)) {
print "WARNING: Value requested for " cfg " not in final .config"
print "Requested value: " merged
print "Actual value: " final
} else if (final == "" && merged ~ / is not set$/) {
# not set, pass
} else if (merged == "" && final != "") {
print "WARNING: " cfg " not in merged config but added in final .config:"
print "Requested value: " merged
print "Actual value: " final
} else {
print "WARNING: " cfg " differs:"
print "Requested value: " merged
print "Actual value: " final
}
}
# First pass: read effective config file, store all lines
FILENAME == ARGV[1] {
cfg = get_cfg($0)
if (cfg != "") {
config_cfg[cfg] = $0
}
next
}
# Second pass: process merged config and compare against effective config
{
cfg = get_cfg($0)
if (cfg == "") next
# strip trailing comment
sub(/[[:space:]]+#.*/, "", $0)
merged_val = $0
final_val = config_cfg[cfg]
if (merged_val == final_val) next
if (merged_val ~ /=n$/ && final_val ~ / is not set$/) next
if (merged_val ~ /=n$/ && final_val == "") next
warn_mismatch(cfg, merged_val, final_val)
if (strict == "true") {
strict_violated = 1
}
}
END {
if (strict_violated) {
exit 1
}
}' \
"$KCONFIG_CONFIG" "$TMP_FILE"; then
# awk exited non-zero, strict mode was violated
STRICT_MODE_VIOLATED=true
fi
if [ "$STRICT" = "true" ] && [ "$STRICT_MODE_VIOLATED" = "true" ]; then
echo "Requested and effective config differ"
exit 1
fi
|