build: implement support for selecting multiple device profiles
[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                 /ubifs/ and $ret .= "\tselect USES_UBIFS\n";
31                 /fpu/ and $ret .= "\tselect HAS_FPU\n";
32                 /spe_fpu/ and $ret .= "\tselect HAS_SPE_FPU\n";
33                 /ramdisk/ and $ret .= "\tselect USES_INITRAMFS\n";
34                 /powerpc64/ and $ret .= "\tselect powerpc64\n";
35                 /nommu/ and $ret .= "\tselect NOMMU\n";
36                 /mips16/ and $ret .= "\tselect HAS_MIPS16\n";
37                 /rfkill/ and $ret .= "\tselect RFKILL_SUPPORT\n";
38                 /low_mem/ and $ret .= "\tselect LOW_MEMORY_FOOTPRINT\n";
39                 /nand/ and $ret .= "\tselect NAND_SUPPORT\n";
40         }
41         return $ret;
42 }
43
44 sub target_name($) {
45         my $target = shift;
46         my $parent = $target->{parent};
47         if ($parent) {
48                 return $target->{parent}->{name}." - ".$target->{name};
49         } else {
50                 return $target->{name};
51         }
52 }
53
54 sub kver($) {
55         my $v = shift;
56         $v =~ tr/\./_/;
57         if (substr($v,0,2) eq "2_") {
58                 $v =~ /(\d+_\d+_\d+)(_\d+)?/ and $v = $1;
59         } else {
60                 $v =~ /(\d+_\d+)(_\d+)?/ and $v = $1;
61         }
62         return $v;
63 }
64
65 sub print_target($) {
66         my $target = shift;
67         my $features = target_config_features(@{$target->{features}});
68         my $help = $target->{desc};
69         my $confstr;
70
71         chomp $features;
72         $features .= "\n";
73         if ($help =~ /\w+/) {
74                 $help =~ s/^\s*/\t  /mg;
75                 $help = "\thelp\n$help";
76         } else {
77                 undef $help;
78         }
79
80         my $v = kver($target->{version});
81         if (@{$target->{subtargets}} == 0) {
82         $confstr = <<EOF;
83 config TARGET_$target->{conf}
84         bool "$target->{name}"
85         select LINUX_$v
86 EOF
87         }
88         else {
89                 $confstr = <<EOF;
90 config TARGET_$target->{conf}
91         bool "$target->{name}"
92 EOF
93         }
94         if ($target->{subtarget}) {
95                 $confstr .= "\tdepends on TARGET_$target->{boardconf}\n";
96         }
97         if (@{$target->{subtargets}} > 0) {
98                 $confstr .= "\tselect HAS_SUBTARGETS\n";
99                 grep { /broken/ } @{$target->{features}} and $confstr .= "\tdepends on BROKEN\n";
100         } else {
101                 $confstr .= $features;
102                 if ($target->{arch} =~ /\w/) {
103                         $confstr .= "\tselect $target->{arch}\n";
104                 }
105                 if ($target->{has_devices}) {
106                         $confstr .= "\tselect HAS_DEVICES\n";
107                 }
108         }
109
110         foreach my $dep (@{$target->{depends}}) {
111                 my $mode = "depends on";
112                 my $flags;
113                 my $name;
114
115                 $dep =~ /^([@\+\-]+)(.+)$/;
116                 $flags = $1;
117                 $name = $2;
118
119                 next if $name =~ /:/;
120                 $flags =~ /-/ and $mode = "deselect";
121                 $flags =~ /\+/ and $mode = "select";
122                 $flags =~ /@/ and $confstr .= "\t$mode $name\n";
123         }
124         $confstr .= "$help\n\n";
125         print $confstr;
126 }
127
128 sub merge_package_lists($$) {
129         my $list1 = shift;
130         my $list2 = shift;
131         my @l = ();
132         my %pkgs;
133
134         foreach my $pkg (@$list1, @$list2) {
135                 $pkgs{$pkg} = 1;
136         }
137         foreach my $pkg (keys %pkgs) {
138                 push @l, $pkg unless ($pkg =~ /^-/ or $pkgs{"-$pkg"});
139         }
140         return sort(@l);
141 }
142
143 sub gen_target_config() {
144         my $file = shift @ARGV;
145         my @target = parse_target_metadata($file);
146         my %defaults;
147
148         my @target_sort = sort {
149                 target_name($a) cmp target_name($b);
150         } @target;
151
152
153         print <<EOF;
154 choice
155         prompt "Target System"
156         default TARGET_ar71xx
157         reset if !DEVEL
158         
159 EOF
160
161         foreach my $target (@target_sort) {
162                 next if $target->{subtarget};
163                 print_target($target);
164         }
165
166         print <<EOF;
167 endchoice
168
169 choice
170         prompt "Subtarget" if HAS_SUBTARGETS
171 EOF
172         foreach my $target (@target) {
173                 next unless $target->{def_subtarget};
174                 print <<EOF;
175         default TARGET_$target->{conf}_$target->{def_subtarget} if TARGET_$target->{conf}
176 EOF
177         }
178         print <<EOF;
179
180 EOF
181         foreach my $target (@target) {
182                 next unless $target->{subtarget};
183                 print_target($target);
184         }
185
186 print <<EOF;
187 endchoice
188
189 choice
190         prompt "Target Profile"
191
192 EOF
193         foreach my $target (@target) {
194                 my $profile = $target->{profiles}->[0];
195                 $profile or next;
196                 print <<EOF;
197         default TARGET_$target->{conf}_$profile->{id} if TARGET_$target->{conf}
198 EOF
199         }
200
201         print <<EOF;
202
203 config TARGET_MULTI_PROFILE
204         bool "Multiple devices"
205         depends on HAS_DEVICES
206
207 EOF
208
209         foreach my $target (@target) {
210                 my $profiles = $target->{profiles};
211                 foreach my $profile (@{$target->{profiles}}) {
212                         print <<EOF;
213 config TARGET_$target->{conf}_$profile->{id}
214         bool "$profile->{name}"
215         depends on TARGET_$target->{conf}
216 EOF
217                         my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
218                         foreach my $pkg (@pkglist) {
219                                 print "\tselect DEFAULT_$pkg\n";
220                                 $defaults{$pkg} = 1;
221                         }
222                         my $help = $profile->{desc};
223                         if ($help =~ /\w+/) {
224                                 $help =~ s/^\s*/\t  /mg;
225                                 $help = "\thelp\n$help";
226                         } else {
227                                 undef $help;
228                         }
229                         print "$help\n";
230                 }
231         }
232
233         print <<EOF;
234 endchoice
235
236 menu "Target Devices"
237         depends on TARGET_MULTI_PROFILE
238
239 EOF
240         foreach my $target (@target) {
241                 my $profiles = $target->{profiles};
242                 foreach my $profile (@{$target->{profiles}}) {
243                         next unless $profile->{id} =~ /^DEVICE_/;
244                         print <<EOF;
245 config TARGET_DEVICE_$target->{conf}_$profile->{id}
246         bool "$profile->{name}"
247         depends on TARGET_$target->{conf}
248 EOF
249                         my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
250                         foreach my $pkg (@pkglist) {
251                                 print "\tselect DEFAULT_$pkg\n";
252                                 $defaults{$pkg} = 1;
253                         }
254                 }
255         }
256
257         print <<EOF;
258
259 endmenu
260
261 config HAS_SUBTARGETS
262         bool
263
264 config HAS_DEVICES
265         bool
266
267 config TARGET_BOARD
268         string
269
270 EOF
271         foreach my $target (@target) {
272                 $target->{subtarget} or print "\t\tdefault \"".$target->{board}."\" if TARGET_".$target->{conf}."\n";
273         }
274         print <<EOF;
275 config TARGET_SUBTARGET
276         string
277         default "generic" if !HAS_SUBTARGETS
278
279 EOF
280
281         foreach my $target (@target) {
282                 foreach my $subtarget (@{$target->{subtargets}}) {
283                         print "\t\tdefault \"$subtarget\" if TARGET_".$target->{conf}."_$subtarget\n";
284                 }
285         }
286         print <<EOF;
287 config TARGET_PROFILE
288         string
289 EOF
290         foreach my $target (@target) {
291                 my $profiles = $target->{profiles};
292                 foreach my $profile (@$profiles) {
293                         print "\tdefault \"$profile->{id}\" if TARGET_$target->{conf}_$profile->{id}\n";
294                 }
295         }
296
297         print <<EOF;
298
299 config TARGET_ARCH_PACKAGES
300         string
301         
302 EOF
303         foreach my $target (@target) {
304                 next if @{$target->{subtargets}} > 0;
305                 print "\t\tdefault \"".($target->{arch_packages} || $target->{board})."\" if TARGET_".$target->{conf}."\n";
306         }
307         print <<EOF;
308
309 config DEFAULT_TARGET_OPTIMIZATION
310         string
311 EOF
312         foreach my $target (@target) {
313                 next if @{$target->{subtargets}} > 0;
314                 print "\tdefault \"".$target->{cflags}."\" if TARGET_".$target->{conf}."\n";
315         }
316         print "\tdefault \"-Os -pipe -funit-at-a-time\"\n";
317         print <<EOF;
318
319 config CPU_TYPE
320         string
321 EOF
322         foreach my $target (@target) {
323                 next if @{$target->{subtargets}} > 0;
324                 print "\tdefault \"".$target->{cputype}."\" if TARGET_".$target->{conf}."\n";
325         }
326         print "\tdefault \"\"\n";
327
328         my %kver;
329         foreach my $target (@target) {
330                 my $v = kver($target->{version});
331                 next if $kver{$v};
332                 $kver{$v} = 1;
333                 print <<EOF;
334
335 config LINUX_$v
336         bool
337
338 EOF
339         }
340         foreach my $def (sort keys %defaults) {
341                 print "\tconfig DEFAULT_".$def."\n";
342                 print "\t\tbool\n\n";
343         }
344 }
345
346 sub gen_profile_mk() {
347         my $file = shift @ARGV;
348         my $target = shift @ARGV;
349         my @targets = parse_target_metadata($file);
350         foreach my $cur (@targets) {
351                 next unless $cur->{id} eq $target;
352                 print "PROFILE_NAMES = ".join(" ", map { $_->{id} } @{$cur->{profiles}})."\n";
353                 foreach my $profile (@{$cur->{profiles}}) {
354                         print $profile->{id}.'_NAME:='.$profile->{name}."\n";
355                         print $profile->{id}.'_PACKAGES:='.join(' ', @{$profile->{packages}})."\n";
356                 }
357         }
358 }
359
360 sub parse_command() {
361         GetOptions("ignore=s", \@ignore);
362         my $cmd = shift @ARGV;
363         for ($cmd) {
364                 /^config$/ and return gen_target_config();
365                 /^profile_mk$/ and return gen_profile_mk();
366         }
367         die <<EOF
368 Available Commands:
369         $0 config [file]                        Target metadata in Kconfig format
370         $0 profile_mk [file] [target]           Profile metadata in makefile format
371
372 EOF
373 }
374
375 parse_command();