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