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