build: add ABI_VERSION to binary package names
[oweals/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}.'_PACKAGES:='.join(' ', @{$profile->{packages}})."\n";
426                 }
427         }
428 }
429
430 sub parse_command() {
431         GetOptions("ignore=s", \@ignore);
432         my $cmd = shift @ARGV;
433         for ($cmd) {
434                 /^config$/ and return gen_target_config();
435                 /^profile_mk$/ and return gen_profile_mk();
436         }
437         die <<EOF
438 Available Commands:
439         $0 config [file]                        Target metadata in Kconfig format
440         $0 profile_mk [file] [target]           Profile metadata in makefile format
441
442 EOF
443 }
444
445 parse_command();