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
|
unset MAKEFLAGS
export MAKEFLAGS=s
cd "$(dirname "$0")"
export TOPDIR=$(realpath ..)
if gmake --help >/dev/null 2>&1; then
export GMAKE=gmake
else
export GMAKE=make
fi
GMAKE="$GMAKE --no-print-directory"
(( x_cols = (COLUMNS > 10) ? COLUMNS - 2 : 80 ))
typeset -L$x_cols pbar
# check for trailing whitespace
#grep -H '[[:space:]]$' */Makefile && print "Found trailing whitespace, please fix"
# build a cache of “ipkg package name” → “package conf option” for
# use with dependency resolution
rm -rf pkglist.d
mkdir pkglist.d
for dn in */Makefile; do
dn=${dn%/*}
pbar="Pass 1: $dn ..."
print -nu2 "$pbar\r"
cd $dn
# ALL_PKGOPTS: all subpackage conf options
# PKGNAME_*: subpackage (ipkg) package name, by subpackage option
eval $($GMAKE dump="ALL_PKGOPTS \
\$(foreach x,\${ALL_PKGOPTS},PKGNAME_\${x})")
cd ..
if [[ -z $ALL_PKGOPTS ]]; then
#print -u2 "Warning: $dn/Makefile contains no packages, skipped"
continue
fi
for spcu in $ALL_PKGOPTS; do # spcu: package option, ucase
eval sppn=\$PKGNAME_$spcu # sppn: subpackage (ipkg) name
# once mksh R40 is out, use its new associative arrays here!
print -r -- "$spcu" >pkglist.d/"$sppn"
done
done
# build Config.in files and resolve dependencies
rm -f package_sections
rm -rf pkgconfigs.d
mkdir pkgconfigs.d
for dn in */Makefile; do
dn=${dn%/*}
pbar="Pass 2: $dn ..."
print -nu2 "$pbar\r"
mkdir pkgconfigs.d/$dn
cd $dn
# PKG_NAME: package name (directory, free-format)
# PKG_FLAVOURS: all package flavours (boolean options), uppercase
# PKG_CHOICES: all package choices (boolean options), uppercase
# PKG_DESCR: package description (directory)
# PKG_URL: package homepage
# PKG_CXX: uppercase varname part to use for CFrustFrust checks
# ALL_PKGOPTS: all subpackage conf options
# PKGNAME_*: subpackage (ipkg) package name, by subpackage option
# PKGDESC_*: subpackage description, by subpackage option
# PKGDEPS_*: subpackage depends on ipkg packages, by subpkg option
# PKGDFLT_*: subpackage 'default {:-n}', by subpackage option
# CFLINE_*: one free-format Config.in line per subpackage option
# PKGFD_*: flavour description, per package flavour option
# PKG_{HOST,TARGET}_DEPENDS: add host or target dependencies
eval $($GMAKE dump="PKG_NAME PKG_FLAVOURS PKG_CHOICES PKG_DESCR PKG_SECTION PKG_URL PKG_MULTI PKG_CXX \
ALL_PKGOPTS \$(foreach x,\${ALL_PKGOPTS},PKGNAME_\${x} \
PKGDESC_\${x} PKGDEPS_\${x} PKGDFLT_\${x} PKGSECT_\${x} CFLINE_\${x}) \
\$(foreach x,\${PKG_FLAVOURS},PKGFD_\${x}) \
\$(foreach x,\${PKG_FLAVOURS},PKGFS_\${x}) \
\$(foreach x,\${PKG_CHOICES},PKGCD_\${x}) \
\$(foreach x,\${PKG_CHOICES},PKGCS_\${x}) \
PKG_HOST_DEPENDS PKG_TARGET_DEPENDS")
# dnu: directory name, uppercase, y/-+/_X/
typeset -u dnu=${dn//-/_}
dnu=${dnu//+/X}
echo "pkgconfigs.d/$dn/Config.in ${PKG_SECTION:=none}" >>../package_sections
echo "$dn/Config.in.manual ${PKG_SECTION:=none}" >>../package_sections
# skip if we take care of this one manually
[[ $dn != "base-files" ]] && [[ -s Config.in.manual ]] && { cd ..; continue; }
exec 4>../pkgconfigs.d/$dn/Config.in
# Handle master package (directory)
print -u4 "config ADK_COMPILE_$dnu"
if [[ -z $ALL_PKGOPTS ]]; then
# pseudo package, does not produce an ipkg package
ppnf=$PKG_NAME # ppnf: pseudopkg name, filled
if [[ -n $PKG_DESCR ]]; then
while (( ${#ppnf} < 23 )); do
ppnf=$ppnf.
done
ppnf="$ppnf $PKG_DESCR"
fi
print -u4 "\tprompt \"$ppnf\""
fi
print -u4 \\ttristate
if [[ -n $ALL_PKGOPTS ]]; then
# real (master) package, contains 1+ ipkg (sub)packages
print -nu4 \\tdepends on
sp=' ' # local sp: space (or ' || ')
for spcu in $ALL_PKGOPTS; do # spcu: package option, ucase
if [[ -n $PKG_MULTI ]]; then
if [[ $dnu != $spcu ]]; then
print -nu4 "${sp}ADK_PACKAGE_$spcu"
sp=' || '
else
print -nu4 "${sp}ADK_HAVE_DOT_CONFIG"
sp=' || '
fi
else
print -nu4 "${sp}ADK_PACKAGE_$spcu"
sp=' || '
fi
done
print -u4
fi
print -u4 \\tdefault n
# Handle NOT/ONLY_FOR_PLATFORM alikes
phd= # phd: PKG_HOST_DEPENDS expand.
if [[ -n $PKG_HOST_DEPENDS ]]; then
phd='\tdepends on'
if [[ $PKG_HOST_DEPENDS = *\!* ]]; then
sp=' !'
else
sp=' '
fi
for x in $PKG_HOST_DEPENDS; do
typeset -u x=${x#!}
phd="$phd${sp}ADK_HOST_$x"
if [[ $PKG_HOST_DEPENDS = *\!* ]]; then
sp=' && !'
else
sp=' || '
fi
done
fi
ptd= # ptd: PKG_TARGET_DEPENDS exp.
if [[ -n $PKG_TARGET_DEPENDS ]]; then
ptd='\tdepends on'
sp=' ' # local sp: space (or ' || ')
if [[ $PKG_TARGET_DEPENDS = *\!* ]]; then
sp=' !'
else
sp=' '
fi
for x in $PKG_TARGET_DEPENDS; do
typeset -l x=${x#!}
#XXX cache this with mksh R40+
found=0
while read friendlyname sym; do
[[ $friendlyname = $x ]] || continue
found=1
break
done <../../target/target.lst
if (( !found )); then
print -u2 "$dn: Target '$x' not found!"
exit 1
fi
ptd="$ptd${sp}$sym"
if [[ $PKG_TARGET_DEPENDS = *\!* ]]; then
sp=' && !'
else
sp=' || '
fi
done
fi
# Handle subpackages / multipackages
for spcu in $ALL_PKGOPTS; do # spcu: package option, ucase
eval sppn=\$PKGNAME_$spcu # sppn: subpackage (ipkg) name
eval desc=\$PKGDESC_$spcu # desc: subpackage description
: ${desc:=$PKG_DESCR} # take from main pkg if empty
eval sect=\$PKGSECT_$spcu # sect: subpackage section
: ${sect:=$PKG_SECTION} # take from main pkg if empty
eval deps=\$PKGDEPS_$spcu # deps: subpackage dependencies
eval dflt=\$PKGDFLT_$spcu # dflt: config 'default' opt.
eval xline=\$CFLINE_$spcu # xline: one free-format line
echo "pkgconfigs.d/$dn/Config.in.$sppn $sect" >>../package_sections
exec 4>../pkgconfigs.d/$dn/Config.in.$sppn
h=4
print -u$h config ADK_PACKAGE_$spcu
spnf=$sppn # spnf: subpackage name, filled
if [[ -n ${desc:-$PKG_NAME} ]]; then
while (( ${#spnf} < 23 )); do
spnf=$spnf.
done
spnf="$spnf ${desc:-$PKG_NAME}"
fi
print -u$h "\tprompt \"$spnf\""
print -u$h \\ttristate
if [[ -n $PKG_MULTI ]]; then
if [[ $spcu != $dnu ]]; then
print -u$h "\tdepends on ADK_PACKAGE_$dnu"
fi
fi
[[ -n $phd ]] && print -u$h "$phd"
[[ -n $ptd ]] && print -u$h "$ptd"
print -u$h "\tdefault ${dflt:-n}"
for dep in $deps; do # dep: ipkg name of one rundep.
# skip dependencies on uclibc++ and libstdcxx iff
# we produce these automatically
[[ -n $PKG_CXX && $dep = @(uclibc++|libstdcxx) ]] && \
continue
case $dep {
(kmod-*)
# produce dependency on kernel package
# which have special name→sym mangling
typeset -u udep=${dep//-/_}
print -u$h "\tselect ADK_KPACKAGE_$udep"
;;
(*)
# produce dependency on regular package
# where the symbol is cached (see above)
if [[ ! -f ../pkglist.d/"$dep" ]]; then
print -u2 "Warning: $PKG_NAME: unreachable dependency '$dep'"
continue
fi
print -u$h '\tselect' \
ADK_PACKAGE_$(<../pkglist.d/"$dep")
;;
}
done
print -u$h \\tselect ADK_COMPILE_$dnu
[[ -n $xline ]] && print -u$h "\t$xline"
if [[ -n $desc$PKG_URL ]]; then
# produce (optional) help text
print -u$h \\thelp
[[ -n $desc ]] && print -u$h "\t $desc"
[[ -n $desc && -n $PKG_URL ]] && print -u$h '\t '
[[ -n $PKG_URL ]] && print -u$h "\t WWW: $PKG_URL"
fi
done
# Handle CFrustFrust library selection, if necessary
[[ -n $PKG_CXX ]] && cat >&4 <<EOF
choice
prompt "C++ library to use"
depends on ADK_COMPILE_$dnu
default ADK_COMPILE_${PKG_CXX}_WITH_STDCXX if ADK_TARGET_LIB_GLIBC || ADK_TARGET_LIB_EGLIBC
default ADK_COMPILE_${PKG_CXX}_WITH_UCLIBCXX if ADK_TARGET_LIB_UCLIBC
config ADK_COMPILE_${PKG_CXX}_WITH_STDCXX
bool "GNU C++ library"
select ADK_PACKAGE_LIBSTDCXX
config ADK_COMPILE_${PKG_CXX}_WITH_UCLIBCXX
bool "uClibc++ library"
select ADK_PACKAGE_UCLIBCXX
endchoice
EOF
[[ -n $PKG_CHOICES ]] && cat >&4 <<EOF
choice
prompt "Package flavour choice"
depends on ADK_COMPILE_$dnu
EOF
# Handle choices
for pfco in $PKG_CHOICES; do
eval pfcd=\$PKGCD_$pfco
eval pfcs=\$PKGCS_$pfco
typeset -u pfcs=${pfcs#!}
print
print config ADK_PACKAGE_${dnu}_$pfco
print "\tbool \"$pfcd\""
print "\\tselect ADK_PACKAGE_${pfcs}"
done >&4
[[ -n $PKG_CHOICES ]] && cat >&4 <<EOF
endchoice
EOF
# Handle flavours (per directory)
for pfcu in $PKG_FLAVOURS; do # pfcu: pkg flavour conf opt.
eval pfd=\$PKGFD_$pfcu # pfd: pkg flavour description
eval pfs=\$PKGFS_$pfcu # pfs: pkg flavour dependencies
print
print config ADK_PACKAGE_${dnu}_$pfcu
print "\tbool \"${pfd:-$PKG_NAME -> flavour $pfcu}\""
print \\tdefault n
print \\tdepends on ADK_COMPILE_$dnu
for pfso in $pfs; do
typeset -u pfso=${pfso#!}
print \\tselect ADK_PACKAGE_${pfso}
done
print \\thelp
print "\t flavour ADK_PACKAGE_${dnu}_$pfcu for $PKG_NAME"
done >&4
cd ..
done
# return good if given file exists and is non-empty
function non_empty_file() {
[[ -f "$1" ]] || return 1
[[ -n "$(cat "$1")" ]] || return 1
return 0
}
# print the verbose section name for a given section tag
function lookup_section_string() {
str="$(grep ^$1\ sections.lst | cut -d ' ' -f '2-')"
[[ -n $str ]] && { echo $str; return; }
echo $1
}
# print the first prompt's first word's value in a given Config.in file
function get_first_prompt() {
prompt="$(grep -m 1 "prompt " $1 | sed -n 's/.*"\([^ \.]*\)[ \.].*"/\1/p')"
[[ -n $prompt ]] && echo $prompt
}
# prepare Config.in list for sorting
while read config_in section; do
pbar="Pass 3: $config_in ..."
print -nu2 "$pbar\r"
non_empty_file $config_in || continue
prompt="$(get_first_prompt $config_in)"
[[ -n $prompt ]] || continue
echo "$prompt $config_in $(lookup_section_string $section)"
done <package_sections >package_section_list
# create the Config.in.auto from the sorted list from above
cursec=""
sort -k 3 -k 1 -f package_section_list | while read name file section; do
pbar="Pass 4: $name ..."
print -nu2 "$pbar\r"
if [[ $cursec != $section ]]; then
[[ -n $cursec ]] && print "endmenu\n"
print "menu \"$section\""
cursec="$section"
fi
print "source \"package/$file\""
print -u3 "source \"package/${file%.*}\""
done >Config.in.auto 3>Config.in.auto.pre
print "endmenu\n" >>Config.in.auto
grep pkgconfigs.d Config.in.auto.pre | sort | uniq > Config.in.auto.global
rm -f package_sections package_section_list Config.in.auto.pre
|