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