ee0ab5a71811a900a1b79152a3acd924724bf4cf
[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 my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
243 foreach my $pkg (@pkglist) {
244 print "\tselect DEFAULT_$pkg\n";
245 $defaults{$pkg} = 1;
246 }
247 my $help = $profile->{desc};
248 if ($help =~ /\w+/) {
249 $help =~ s/^\s*/\t /mg;
250 $help = "\thelp\n$help";
251 } else {
252 undef $help;
253 }
254 print "$help\n";
255 }
256 }
257
258 print <<EOF;
259 endchoice
260
261 menu "Target Devices"
262 depends on TARGET_MULTI_PROFILE
263
264 config TARGET_ALL_PROFILES
265 bool "Enable all profiles by default"
266 default BUILDBOT
267
268 config TARGET_PER_DEVICE_ROOTFS
269 bool "Use a per-device root filesystem that adds profile packages"
270 default BUILDBOT
271 help
272 When disabled, all device packages from all selected devices
273 will be included in all images by default. (Marked as <*>) You will
274 still be able to manually deselect any/all packages.
275 When enabled, each device builds it's own image, including only the
276 profile packages for that device. (Marked as {M}) You will be able
277 to change a package to included in all images by marking as {*}, but
278 will not be able to disable a profile package completely.
279
280 To get the most use of this setting, you must set in a .config stub
281 before calling "make defconfig". Selecting TARGET_MULTI_PROFILE and
282 then manually selecting (via menuconfig for instance) this option
283 will have pre-defaulted all profile packages to included, making this
284 option appear to have had no effect.
285
286 EOF
287 foreach my $target (@target) {
288 my @profiles = sort {
289 my $x = $a->{name};
290 my $y = $b->{name};
291 "\L$x" cmp "\L$y";
292 } @{$target->{profiles}};
293 foreach my $profile (@profiles) {
294 next unless $profile->{id} =~ /^DEVICE_/;
295 print <<EOF;
296 menuconfig TARGET_DEVICE_$target->{conf}_$profile->{id}
297 bool "$profile->{name}"
298 depends on TARGET_$target->{conf}
299 default $profile->{default}
300 EOF
301 my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
302 foreach my $pkg (@pkglist) {
303 print "\tselect DEFAULT_$pkg if !TARGET_PER_DEVICE_ROOTFS\n";
304 print "\tselect MODULE_DEFAULT_$pkg if TARGET_PER_DEVICE_ROOTFS\n";
305 $defaults{$pkg} = 1;
306 }
307
308 print <<EOF;
309
310
311 config TARGET_DEVICE_PACKAGES_$target->{conf}_$profile->{id}
312 string "$profile->{name} additional packages"
313 default ""
314 depends on TARGET_PER_DEVICE_ROOTFS
315 depends on TARGET_DEVICE_$target->{conf}_$profile->{id}
316
317 EOF
318 }
319 }
320
321 print <<EOF;
322
323 endmenu
324
325 config HAS_SUBTARGETS
326 bool
327
328 config HAS_DEVICES
329 bool
330
331 config TARGET_BOARD
332 string
333
334 EOF
335 foreach my $target (@target) {
336 $target->{subtarget} or print "\t\tdefault \"".$target->{board}."\" if TARGET_".$target->{conf}."\n";
337 }
338 print <<EOF;
339 config TARGET_SUBTARGET
340 string
341 default "generic" if !HAS_SUBTARGETS
342
343 EOF
344
345 foreach my $target (@target) {
346 foreach my $subtarget (@{$target->{subtargets}}) {
347 print "\t\tdefault \"$subtarget\" if TARGET_".$target->{conf}."_$subtarget\n";
348 }
349 }
350 print <<EOF;
351 config TARGET_PROFILE
352 string
353 EOF
354 foreach my $target (@target) {
355 my $profiles = $target->{profiles};
356 foreach my $profile (@$profiles) {
357 print "\tdefault \"$profile->{id}\" if TARGET_$target->{conf}_$profile->{id}\n";
358 }
359 }
360
361 print <<EOF;
362
363 config TARGET_ARCH_PACKAGES
364 string
365
366 EOF
367 foreach my $target (@target) {
368 next if @{$target->{subtargets}} > 0;
369 print "\t\tdefault \"".($target->{arch_packages} || $target->{board})."\" if TARGET_".$target->{conf}."\n";
370 }
371 print <<EOF;
372
373 config DEFAULT_TARGET_OPTIMIZATION
374 string
375 EOF
376 foreach my $target (@target) {
377 next if @{$target->{subtargets}} > 0;
378 print "\tdefault \"".$target->{cflags}."\" if TARGET_".$target->{conf}."\n";
379 }
380 print "\tdefault \"-Os -pipe -funit-at-a-time\"\n";
381 print <<EOF;
382
383 config CPU_TYPE
384 string
385 EOF
386 foreach my $target (@target) {
387 next if @{$target->{subtargets}} > 0;
388 print "\tdefault \"".$target->{cputype}."\" if TARGET_".$target->{conf}."\n";
389 }
390 print "\tdefault \"\"\n";
391
392 my %kver;
393 foreach my $target (@target) {
394 foreach my $tv ($target->{version}, $target->{testing_version}) {
395 next unless $tv;
396 my $v = kver($tv);
397 next if $kver{$v};
398 $kver{$v} = 1;
399 print <<EOF;
400
401 config LINUX_$v
402 bool
403
404 EOF
405 }
406 }
407 foreach my $def (sort keys %defaults) {
408 print <<EOF;
409 config DEFAULT_$def
410 bool
411
412 config MODULE_DEFAULT_$def
413 tristate
414 depends on TARGET_PER_DEVICE_ROOTFS
415 depends on m
416 default m if DEFAULT_$def
417 select PACKAGE_$def
418
419 EOF
420 }
421 }
422
423 sub gen_profile_mk() {
424 my $file = shift @ARGV;
425 my $target = shift @ARGV;
426 my @targets = parse_target_metadata($file);
427 foreach my $cur (@targets) {
428 next unless $cur->{id} eq $target;
429 print "PROFILE_NAMES = ".join(" ", map { $_->{id} } @{$cur->{profiles}})."\n";
430 foreach my $profile (@{$cur->{profiles}}) {
431 print $profile->{id}.'_NAME:='.$profile->{name}."\n";
432 print $profile->{id}.'_HAS_IMAGE_METADATA:='.$profile->{has_image_metadata}."\n";
433 if (defined($profile->{supported_devices}) and @{$profile->{supported_devices}} > 0) {
434 print $profile->{id}.'_SUPPORTED_DEVICES:='.join(' ', @{$profile->{supported_devices}})."\n";
435 }
436 print $profile->{id}.'_PACKAGES:='.join(' ', @{$profile->{packages}})."\n";
437 }
438 }
439 }
440
441 sub parse_command() {
442 GetOptions("ignore=s", \@ignore);
443 my $cmd = shift @ARGV;
444 for ($cmd) {
445 /^config$/ and return gen_target_config();
446 /^profile_mk$/ and return gen_profile_mk();
447 }
448 die <<EOF
449 Available Commands:
450 $0 config [file] Target metadata in Kconfig format
451 $0 profile_mk [file] [target] Profile metadata in makefile format
452
453 EOF
454 }
455
456 parse_command();