base-files: add generic sdcard upgrade method
[openwrt/staging/dedeckeh.git] / scripts / target-metadata.pl
1 #!/usr/bin/env perl
2 use FindBin;
3 use lib "$FindBin::Bin";
4 use strict;
5 use metadata;
6 use Getopt::Long;
7
8 sub target_config_features(@) {
9 my $ret;
10
11 while ($_ = shift @_) {
12 /^arm_v(\w+)$/ and $ret .= "\tselect arm_v$1\n";
13 /^audio$/ and $ret .= "\tselect AUDIO_SUPPORT\n";
14 /^boot-part$/ and $ret .= "\tselect USES_BOOT_PART\n";
15 /^broken$/ and $ret .= "\tdepends on BROKEN\n";
16 /^cpiogz$/ and $ret .= "\tselect USES_CPIOGZ\n";
17 /^display$/ and $ret .= "\tselect DISPLAY_SUPPORT\n";
18 /^dt$/ and $ret .= "\tselect USES_DEVICETREE\n";
19 /^dt-overlay$/ and $ret .= "\tselect HAS_DT_OVERLAY_SUPPORT\n";
20 /^ext4$/ and $ret .= "\tselect USES_EXT4\n";
21 /^fpu$/ and $ret .= "\tselect HAS_FPU\n";
22 /^gpio$/ and $ret .= "\tselect GPIO_SUPPORT\n";
23 /^jffs2$/ and $ret .= "\tselect USES_JFFS2\n";
24 /^jffs2_nand$/ and $ret .= "\tselect USES_JFFS2_NAND\n";
25 /^low_mem$/ and $ret .= "\tselect LOW_MEMORY_FOOTPRINT\n";
26 /^minor$/ and $ret .= "\tselect USES_MINOR\n";
27 /^mips16$/ and $ret .= "\tselect HAS_MIPS16\n";
28 /^nand$/ and $ret .= "\tselect NAND_SUPPORT\n";
29 /^nommu$/ and $ret .= "\tselect NOMMU\n";
30 /^pci$/ and $ret .= "\tselect PCI_SUPPORT\n";
31 /^pcie$/ and $ret .= "\tselect PCIE_SUPPORT\n";
32 /^pcmcia$/ and $ret .= "\tselect PCMCIA_SUPPORT\n";
33 /^powerpc64$/ and $ret .= "\tselect powerpc64\n";
34 /^pwm$/ and $ret .= "\select PWM_SUPPORT\n";
35 /^ramdisk$/ and $ret .= "\tselect USES_INITRAMFS\n";
36 /^rfkill$/ and $ret .= "\tselect RFKILL_SUPPORT\n";
37 /^rootfs-part$/ and $ret .= "\tselect USES_ROOTFS_PART\n";
38 /^rtc$/ and $ret .= "\tselect RTC_SUPPORT\n";
39 /^sdcard$/ and $ret .= "\tselect SDCARD_SUPPORT\n";
40 /^separate_ramdisk$/ and $ret .= "\tselect USES_INITRAMFS\n\tselect USES_SEPARATE_INITRAMFS\n";
41 /^small_flash$/ and $ret .= "\tselect SMALL_FLASH\n";
42 /^spe_fpu$/ and $ret .= "\tselect HAS_SPE_FPU\n";
43 /^squashfs$/ and $ret .= "\tselect USES_SQUASHFS\n";
44 /^targz$/ and $ret .= "\tselect USES_TARGZ\n";
45 /^testing-kernel$/ and $ret .= "\tselect HAS_TESTING_KERNEL\n";
46 /^ubifs$/ and $ret .= "\tselect USES_UBIFS\n";
47 /^usb$/ and $ret .= "\tselect USB_SUPPORT\n";
48 /^usbgadget$/ and $ret .= "\tselect USB_GADGET_SUPPORT\n";
49 /^virtio$/ and $ret .= "\tselect VIRTIO_SUPPORT\n";
50 }
51 return $ret;
52 }
53
54 sub target_name($) {
55 my $target = shift;
56 my $parent = $target->{parent};
57 if ($parent) {
58 return $target->{parent}->{name}." - ".$target->{name};
59 } else {
60 return $target->{name};
61 }
62 }
63
64 sub kver($) {
65 my $v = shift;
66 $v =~ tr/\./_/;
67 if (substr($v,0,2) eq "2_") {
68 $v =~ /(\d+_\d+_\d+)(_\d+)?/ and $v = $1;
69 } else {
70 $v =~ /(\d+_\d+)(_\d+)?/ and $v = $1;
71 }
72 return $v;
73 }
74
75 sub print_target($) {
76 my $target = shift;
77 my $features = target_config_features(@{$target->{features}});
78 my $help = $target->{desc};
79 my $confstr;
80
81 chomp $features;
82 $features .= "\n";
83 if ($help =~ /\w+/) {
84 $help =~ s/^\s*/\t /mg;
85 $help = "\thelp\n$help";
86 } else {
87 undef $help;
88 }
89
90 my $v = kver($target->{version});
91 my $tv = kver($target->{testing_version});
92 $tv or $tv = $v;
93 if (@{$target->{subtargets}} == 0) {
94 $confstr = <<EOF;
95 config TARGET_$target->{conf}
96 bool "$target->{name}"
97 select LINUX_$v if !TESTING_KERNEL
98 select LINUX_$tv if TESTING_KERNEL
99 EOF
100 }
101 else {
102 $confstr = <<EOF;
103 config TARGET_$target->{conf}
104 bool "$target->{name}"
105 EOF
106 }
107 if ($target->{subtarget}) {
108 $confstr .= "\tdepends on TARGET_$target->{boardconf}\n";
109 }
110 if (@{$target->{subtargets}} > 0) {
111 $confstr .= "\tselect HAS_SUBTARGETS\n";
112 grep { /broken/ } @{$target->{features}} and $confstr .= "\tdepends on BROKEN\n";
113 } else {
114 $confstr .= $features;
115 if ($target->{arch} =~ /\w/) {
116 $confstr .= "\tselect $target->{arch}\n";
117 }
118 if ($target->{has_devices}) {
119 $confstr .= "\tselect HAS_DEVICES\n";
120 }
121 }
122
123 foreach my $dep (@{$target->{depends}}) {
124 my $mode = "depends on";
125 my $flags;
126 my $name;
127
128 $dep =~ /^([@\+\-]+)(.+)$/;
129 $flags = $1;
130 $name = $2;
131
132 next if $name =~ /:/;
133 $flags =~ /-/ and $mode = "deselect";
134 $flags =~ /\+/ and $mode = "select";
135 $flags =~ /@/ and $confstr .= "\t$mode $name\n";
136 }
137 $confstr .= "$help\n\n";
138 print $confstr;
139 }
140
141 sub merge_package_lists($$) {
142 my $list1 = shift;
143 my $list2 = shift;
144 my @l = ();
145 my %pkgs;
146
147 foreach my $pkg (@$list1, @$list2) {
148 $pkgs{$pkg} = 1;
149 }
150 foreach my $pkg (keys %pkgs) {
151 push @l, $pkg unless ($pkg =~ /^-/ or $pkgs{"-$pkg"});
152 }
153 return sort(@l);
154 }
155
156 sub gen_target_config() {
157 my $file = shift @ARGV;
158 my @target = parse_target_metadata($file);
159 my %defaults;
160
161 my @target_sort = sort {
162 target_name($a) cmp target_name($b);
163 } @target;
164
165 foreach my $target (@target_sort) {
166 next if @{$target->{subtargets}} > 0;
167 print <<EOF;
168 config DEFAULT_TARGET_$target->{conf}
169 bool
170 depends on TARGET_PER_DEVICE_ROOTFS
171 default y if TARGET_$target->{conf}
172 EOF
173 foreach my $pkg (@{$target->{packages}}) {
174 print "\tselect DEFAULT_$pkg if TARGET_PER_DEVICE_ROOTFS\n";
175 }
176 }
177
178 print <<EOF;
179 choice
180 prompt "Target System"
181 default TARGET_ath79
182 reset if !DEVEL
183
184 EOF
185
186 foreach my $target (@target_sort) {
187 next if $target->{subtarget};
188 print_target($target);
189 }
190
191 print <<EOF;
192 endchoice
193
194 choice
195 prompt "Subtarget" if HAS_SUBTARGETS
196 EOF
197 foreach my $target (@target) {
198 next unless $target->{def_subtarget};
199 print <<EOF;
200 default TARGET_$target->{conf}_$target->{def_subtarget} if TARGET_$target->{conf}
201 EOF
202 }
203 print <<EOF;
204
205 EOF
206 foreach my $target (@target) {
207 next unless $target->{subtarget};
208 print_target($target);
209 }
210
211 print <<EOF;
212 endchoice
213
214 choice
215 prompt "Target Profile"
216 default TARGET_MULTI_PROFILE if BUILDBOT
217
218 EOF
219 foreach my $target (@target) {
220 my $profile = $target->{profiles}->[0];
221 $profile or next;
222 print <<EOF;
223 default TARGET_$target->{conf}_$profile->{id} if TARGET_$target->{conf} && !BUILDBOT
224 EOF
225 }
226
227 print <<EOF;
228
229 config TARGET_MULTI_PROFILE
230 bool "Multiple devices"
231 depends on HAS_DEVICES
232 help
233 Instead of only building a single image, or all images, this allows you
234 to select images to be built for multiple devices in one build.
235
236 EOF
237
238 foreach my $target (@target) {
239 my $profiles = $target->{profiles};
240 foreach my $profile (@{$target->{profiles}}) {
241 print <<EOF;
242 config TARGET_$target->{conf}_$profile->{id}
243 bool "$profile->{name}"
244 depends on TARGET_$target->{conf}
245 EOF
246 $profile->{broken} and print "\tdepends on BROKEN\n";
247 my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
248 foreach my $pkg (@pkglist) {
249 print "\tselect DEFAULT_$pkg\n";
250 $defaults{$pkg} = 1;
251 }
252 my $help = $profile->{desc};
253 if ($help =~ /\w+/) {
254 $help =~ s/^\s*/\t /mg;
255 $help = "\thelp\n$help";
256 } else {
257 undef $help;
258 }
259 print "$help\n";
260 }
261 }
262
263 print <<EOF;
264 endchoice
265
266 menu "Target Devices"
267 depends on TARGET_MULTI_PROFILE
268
269 config TARGET_ALL_PROFILES
270 bool "Enable all profiles by default"
271 default BUILDBOT
272
273 config TARGET_PER_DEVICE_ROOTFS
274 bool "Use a per-device root filesystem that adds profile packages"
275 default BUILDBOT
276 help
277 When disabled, all device packages from all selected devices
278 will be included in all images by default. (Marked as <*>) You will
279 still be able to manually deselect any/all packages.
280 When enabled, each device builds it's own image, including only the
281 profile packages for that device. (Marked as {M}) You will be able
282 to change a package to included in all images by marking as {*}, but
283 will not be able to disable a profile package completely.
284
285 To get the most use of this setting, you must set in a .config stub
286 before calling "make defconfig". Selecting TARGET_MULTI_PROFILE and
287 then manually selecting (via menuconfig for instance) this option
288 will have pre-defaulted all profile packages to included, making this
289 option appear to have had no effect.
290
291 EOF
292 foreach my $target (@target) {
293 my @profiles = sort {
294 my $x = $a->{name};
295 my $y = $b->{name};
296 "\L$x" cmp "\L$y";
297 } @{$target->{profiles}};
298 foreach my $profile (@profiles) {
299 next unless $profile->{id} =~ /^DEVICE_/;
300 print <<EOF;
301 menuconfig TARGET_DEVICE_$target->{conf}_$profile->{id}
302 bool "$profile->{name}"
303 depends on TARGET_$target->{conf}
304 default $profile->{default}
305 EOF
306 $profile->{broken} and print "\tdepends on BROKEN\n";
307 my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
308 foreach my $pkg (@pkglist) {
309 print "\tselect DEFAULT_$pkg if !TARGET_PER_DEVICE_ROOTFS\n";
310 print "\tselect MODULE_DEFAULT_$pkg if TARGET_PER_DEVICE_ROOTFS\n";
311 $defaults{$pkg} = 1;
312 }
313
314 print <<EOF;
315
316
317 config TARGET_DEVICE_PACKAGES_$target->{conf}_$profile->{id}
318 string "$profile->{name} additional packages"
319 default ""
320 depends on TARGET_PER_DEVICE_ROOTFS
321 depends on TARGET_DEVICE_$target->{conf}_$profile->{id}
322
323 EOF
324 }
325 }
326
327 print <<EOF;
328
329 endmenu
330
331 config HAS_SUBTARGETS
332 bool
333
334 config HAS_DEVICES
335 bool
336
337 config TARGET_BOARD
338 string
339
340 EOF
341 foreach my $target (@target) {
342 $target->{subtarget} or print "\t\tdefault \"".$target->{board}."\" if TARGET_".$target->{conf}."\n";
343 }
344 print <<EOF;
345 config TARGET_SUBTARGET
346 string
347 default "generic" if !HAS_SUBTARGETS
348
349 EOF
350
351 foreach my $target (@target) {
352 foreach my $subtarget (@{$target->{subtargets}}) {
353 print "\t\tdefault \"$subtarget\" if TARGET_".$target->{conf}."_$subtarget\n";
354 }
355 }
356 print <<EOF;
357 config TARGET_PROFILE
358 string
359 EOF
360 foreach my $target (@target) {
361 my $profiles = $target->{profiles};
362 foreach my $profile (@$profiles) {
363 print "\tdefault \"$profile->{id}\" if TARGET_$target->{conf}_$profile->{id}\n";
364 }
365 }
366
367 print <<EOF;
368
369 config TARGET_ARCH_PACKAGES
370 string
371
372 EOF
373 foreach my $target (@target) {
374 next if @{$target->{subtargets}} > 0;
375 print "\t\tdefault \"".($target->{arch_packages} || $target->{board})."\" if TARGET_".$target->{conf}."\n";
376 }
377 print <<EOF;
378
379 config DEFAULT_TARGET_OPTIMIZATION
380 string
381 EOF
382 foreach my $target (@target) {
383 next if @{$target->{subtargets}} > 0;
384 print "\tdefault \"".$target->{cflags}."\" if TARGET_".$target->{conf}."\n";
385 }
386 print "\tdefault \"-Os -pipe -funit-at-a-time\"\n";
387 print <<EOF;
388
389 config CPU_TYPE
390 string
391 EOF
392 foreach my $target (@target) {
393 next if @{$target->{subtargets}} > 0;
394 print "\tdefault \"".$target->{cputype}."\" if TARGET_".$target->{conf}."\n";
395 }
396 print "\tdefault \"\"\n";
397
398 my %kver;
399 foreach my $target (@target) {
400 foreach my $tv ($target->{version}, $target->{testing_version}) {
401 next unless $tv;
402 my $v = kver($tv);
403 next if $kver{$v};
404 $kver{$v} = 1;
405 print <<EOF;
406
407 config LINUX_$v
408 bool
409
410 EOF
411 }
412 }
413 foreach my $def (sort keys %defaults) {
414 print <<EOF;
415 config DEFAULT_$def
416 bool
417
418 config MODULE_DEFAULT_$def
419 tristate
420 depends on TARGET_PER_DEVICE_ROOTFS
421 depends on m
422 default m if DEFAULT_$def
423 select PACKAGE_$def
424
425 EOF
426 }
427 }
428
429 sub gen_profile_mk() {
430 my $file = shift @ARGV;
431 my $target = shift @ARGV;
432 my @targets = parse_target_metadata($file);
433 foreach my $cur (@targets) {
434 next unless $cur->{id} eq $target;
435 my @profile_ids_unique = do { my %seen; grep { !$seen{$_}++} map { $_->{id} } @{$cur->{profiles}}};
436 print "PROFILE_NAMES = ".join(" ", @profile_ids_unique)."\n";
437 foreach my $profile (@{$cur->{profiles}}) {
438 print $profile->{id}.'_NAME:='.$profile->{name}."\n";
439 print $profile->{id}.'_HAS_IMAGE_METADATA:='.$profile->{has_image_metadata}."\n";
440 if (defined($profile->{supported_devices}) and @{$profile->{supported_devices}} > 0) {
441 print $profile->{id}.'_SUPPORTED_DEVICES:='.join(' ', @{$profile->{supported_devices}})."\n";
442 }
443 print $profile->{id}.'_PACKAGES:='.join(' ', @{$profile->{packages}})."\n";
444 }
445 }
446 }
447
448 sub parse_command() {
449 GetOptions("ignore=s", \@ignore);
450 my $cmd = shift @ARGV;
451 for ($cmd) {
452 /^config$/ and return gen_target_config();
453 /^profile_mk$/ and return gen_profile_mk();
454 }
455 die <<EOF
456 Available Commands:
457 $0 config [file] Target metadata in Kconfig format
458 $0 profile_mk [file] [target] Profile metadata in makefile format
459
460 EOF
461 }
462
463 parse_command();