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