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