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