1#!/usr/bin/perl 2use FindBin; 3use lib "$FindBin::Bin"; 4use strict; 5use metadata; 6 7my %board; 8 9sub confstr($) { 10 my $conf = shift; 11 $conf =~ tr#/\.\-/#___#; 12 return $conf; 13} 14 15sub parse_target_metadata() { 16 my $file = shift @ARGV; 17 my ($target, @target, $profile); 18 my %target; 19 20 open FILE, "<$file" or do { 21 warn "Can't open file '$file': $!\n"; 22 return; 23 }; 24 while (<FILE>) { 25 chomp; 26 /^Target:\s*(.+)\s*$/ and do { 27 my $name = $1; 28 $target = { 29 id => $name, 30 board => $name, 31 boardconf => confstr($name), 32 conf => confstr($name), 33 profiles => [], 34 features => [], 35 depends => [], 36 subtargets => [] 37 }; 38 push @target, $target; 39 $target{$name} = $target; 40 if ($name =~ /([^\/]+)\/([^\/]+)/) { 41 push @{$target{$1}->{subtargets}}, $2; 42 $target->{board} = $1; 43 $target->{boardconf} = confstr($1); 44 $target->{subtarget} = 1; 45 $target->{parent} = $target{$1}; 46 } 47 }; 48 /^Target-Kernel:\s*(\d+\.\d+)\s*$/ and $target->{kernel} = $1; 49 /^Target-Name:\s*(.+)\s*$/ and $target->{name} = $1; 50 /^Target-Path:\s*(.+)\s*$/ and $target->{path} = $1; 51 /^Target-Arch:\s*(.+)\s*$/ and $target->{arch} = $1; 52 /^Target-Features:\s*(.+)\s*$/ and $target->{features} = [ split(/\s+/, $1) ]; 53 /^Target-Depends:\s*(.+)\s*$/ and $target->{depends} = [ split(/\s+/, $1) ]; 54 /^Target-Description:/ and $target->{desc} = get_multiline(*FILE); 55 /^Linux-Version:\s*(.+)\s*$/ and $target->{version} = $1; 56 /^Linux-Release:\s*(.+)\s*$/ and $target->{release} = $1; 57 /^Linux-Kernel-Arch:\s*(.+)\s*$/ and $target->{karch} = $1; 58 /^Default-Packages:\s*(.+)\s*$/ and $target->{packages} = [ split(/\s+/, $1) ]; 59 /^Target-Profile:\s*(.+)\s*$/ and do { 60 $profile = { 61 id => $1, 62 name => $1, 63 packages => [] 64 }; 65 push @{$target->{profiles}}, $profile; 66 }; 67 /^Target-Profile-Name:\s*(.+)\s*$/ and $profile->{name} = $1; 68 /^Target-Profile-Packages:\s*(.*)\s*$/ and $profile->{packages} = [ split(/\s+/, $1) ]; 69 /^Target-Profile-Description:\s*(.*)\s*/ and $profile->{desc} = get_multiline(*FILE); 70 /^Target-Profile-Config:/ and $profile->{config} = get_multiline(*FILE, "\t"); 71 /^Target-Profile-Kconfig:/ and $profile->{kconfig} = 1; 72 } 73 close FILE; 74 foreach my $target (@target) { 75 next if @{$target->{subtargets}} > 0; 76 @{$target->{profiles}} > 0 or $target->{profiles} = [ 77 { 78 id => 'Default', 79 name => 'Default', 80 packages => [] 81 } 82 ]; 83 } 84 return @target; 85} 86 87sub gen_kconfig_overrides() { 88 my %config; 89 my %kconfig; 90 my $package; 91 my $pkginfo = shift @ARGV; 92 my $cfgfile = shift @ARGV; 93 94 # parameter 2: build system config 95 open FILE, "<$cfgfile" or return; 96 while (<FILE>) { 97 /^(CONFIG_.+?)=(.+)$/ and $config{$1} = 1; 98 } 99 close FILE; 100 101 # parameter 1: package metadata 102 open FILE, "<$pkginfo" or return; 103 while (<FILE>) { 104 /^Package:\s*(.+?)\s*$/ and $package = $1; 105 /^Kernel-Config:\s*(.+?)\s*$/ and do { 106 my @config = split /\s+/, $1; 107 foreach my $config (@config) { 108 my $val = 'm'; 109 my $override; 110 if ($config =~ /^(.+?)=(.+)$/) { 111 $config = $1; 112 $override = 1; 113 $val = $2; 114 } 115 if ($config{"CONFIG_PACKAGE_$package"} and ($config ne 'n')) { 116 $kconfig{$config} = $val; 117 } elsif (!$override) { 118 $kconfig{$config} or $kconfig{$config} = 'n'; 119 } 120 } 121 }; 122 }; 123 close FILE; 124 125 foreach my $kconfig (sort keys %kconfig) { 126 if ($kconfig{$kconfig} eq 'n') { 127 print "# $kconfig is not set\n"; 128 } else { 129 print "$kconfig=$kconfig{$kconfig}\n"; 130 } 131 } 132} 133 134sub merge_package_lists($$) { 135 my $list1 = shift; 136 my $list2 = shift; 137 my @l = (); 138 my %pkgs; 139 140 foreach my $pkg (@$list1, @$list2) { 141 $pkgs{$pkg} = 1; 142 } 143 foreach my $pkg (keys %pkgs) { 144 push @l, $pkg unless ($pkg =~ /^-/ or $pkgs{"-$pkg"}); 145 } 146 return sort(@l); 147} 148 149sub target_config_features(@) { 150 my $ret; 151 152 while ($_ = shift @_) { 153 /broken/ and $ret .= "\tdepends BROKEN\n"; 154 /display/ and $ret .= "\tselect DISPLAY_SUPPORT\n"; 155 /gpio/ and $ret .= "\tselect GPIO_SUPPORT\n"; 156 /pci/ and $ret .= "\tselect PCI_SUPPORT\n"; 157 /usb/ and $ret .= "\tselect USB_SUPPORT\n"; 158 /pcmcia/ and $ret .= "\tselect PCMCIA_SUPPORT\n"; 159 /squashfs/ and $ret .= "\tselect USES_SQUASHFS\n"; 160 /jffs2/ and $ret .= "\tselect USES_JFFS2\n"; 161 /ext2/ and $ret .= "\tselect USES_EXT2\n"; 162 /tgz/ and $ret .= "\tselect USES_TGZ\n"; 163 /cpiogz/ and $ret .= "\tselect USES_CPIOGZ\n"; 164 /fpu/ and $ret .= "\tselect HAS_FPU\n"; 165 } 166 return $ret; 167} 168 169sub target_name($) { 170 my $target = shift; 171 my $parent = $target->{parent}; 172 if ($parent) { 173 return $target->{parent}->{name}." - ".$target->{name}; 174 } else { 175 return $target->{name}; 176 } 177} 178 179sub kver($) { 180 my $v = shift; 181 $v =~ tr/\./_/; 182 $v =~ /(\d+_\d+_\d+)(_\d+)?/ and $v = $1; 183 return $v; 184} 185 186sub print_target($) { 187 my $target = shift; 188 my $features = target_config_features(@{$target->{features}}); 189 my $help = $target->{desc}; 190 my $kernel = $target->{kernel}; 191 my $confstr; 192 $kernel =~ tr/./_/; 193 194 chomp $features; 195 $features .= "\n"; 196 if ($help =~ /\w+/) { 197 $help =~ s/^\s*/\t /mg; 198 $help = "\thelp\n$help"; 199 } else { 200 undef $help; 201 } 202 203 my $v = kver($target->{version}); 204 $confstr = <<EOF; 205config TARGET_$target->{conf} 206 bool "$target->{name}" 207 select LINUX_$kernel 208 select LINUX_$v 209EOF 210 if ($target->{subtarget}) { 211 $confstr .= "\tdepends TARGET_$target->{boardconf}\n"; 212 } 213 if (@{$target->{subtargets}} > 0) { 214 $confstr .= "\tselect HAS_SUBTARGETS\n"; 215 } else { 216 $confstr .= "\tselect $target->{arch}\n"; 217 foreach my $dep (@{$target->{depends}}) { 218 my $mode = "depends"; 219 my $flags; 220 my $name; 221 222 $dep =~ /^([@\+\-]+)(.+)$/; 223 $flags = $1; 224 $name = $2; 225 226 $flags =~ /-/ and $mode = "deselect"; 227 $flags =~ /\+/ and $mode = "select"; 228 $flags =~ /@/ and $confstr .= "\t$mode $name\n"; 229 } 230 $confstr .= $features; 231 } 232 233 $confstr .= "$help\n\n"; 234 print $confstr; 235} 236 237sub gen_target_config() { 238 my @target = parse_target_metadata(); 239 240 my @target_sort = sort { 241 target_name($a) cmp target_name($b); 242 } @target; 243 244 245 print <<EOF; 246choice 247 prompt "Target System" 248 default TARGET_brcm_2_4 249 reset if !DEVEL 250 251EOF 252 253 foreach my $target (@target_sort) { 254 next if $target->{subtarget}; 255 print_target($target); 256 } 257 258 print <<EOF; 259endchoice 260 261choice 262 prompt "Subtarget" if HAS_SUBTARGETS 263 264EOF 265 foreach my $target (@target) { 266 next unless $target->{subtarget}; 267 print_target($target); 268 } 269 270print <<EOF; 271endchoice 272 273choice 274 prompt "Target Profile" 275 276EOF 277 278 foreach my $target (@target) { 279 my $profiles = $target->{profiles}; 280 281 foreach my $profile (@$profiles) { 282 print <<EOF; 283config TARGET_$target->{conf}_$profile->{id} 284 bool "$profile->{name}" 285 depends TARGET_$target->{conf} 286$profile->{config} 287EOF 288 $profile->{kconfig} and print "\tselect PROFILE_KCONFIG\n"; 289 my @pkglist = merge_package_lists($target->{packages}, $profile->{packages}); 290 foreach my $pkg (@pkglist) { 291 print "\tselect DEFAULT_$pkg\n"; 292 } 293 print "\n"; 294 } 295 } 296 297 print <<EOF; 298endchoice 299 300config HAS_SUBTARGETS 301 bool 302 303config TARGET_BOARD 304 string 305 306EOF 307 foreach my $target (@target) { 308 $target->{subtarget} or print "\t\tdefault \"".$target->{board}."\" if TARGET_".$target->{conf}."\n"; 309 } 310 311 my %kver; 312 foreach my $target (@target) { 313 my $v = kver($target->{version}); 314 next if $kver{$v}; 315 $kver{$v} = 1; 316 print <<EOF; 317config LINUX_$v 318 bool 319EOF 320 } 321} 322 323my %dep_check; 324sub __find_package_dep($$) { 325 my $pkg = shift; 326 my $name = shift; 327 my $deps = ($pkg->{vdepends} or $pkg->{depends}); 328 329 return 0 unless defined $deps; 330 foreach my $dep (@{$deps}) { 331 next if $dep_check{$dep}; 332 $dep_check{$dep} = 1; 333 return 1 if $dep eq $name; 334 return 1 if ($package{$dep} and (__find_package_dep($package{$dep},$name) == 1)); 335 } 336 return 0; 337} 338 339# wrapper to avoid infinite recursion 340sub find_package_dep($$) { 341 my $pkg = shift; 342 my $name = shift; 343 344 %dep_check = (); 345 return __find_package_dep($pkg, $name); 346} 347 348sub package_depends($$) { 349 my $a = shift; 350 my $b = shift; 351 my $ret; 352 353 return 0 if ($a->{submenu} ne $b->{submenu}); 354 if (find_package_dep($a, $b->{name}) == 1) { 355 $ret = 1; 356 } elsif (find_package_dep($b, $a->{name}) == 1) { 357 $ret = -1; 358 } else { 359 return 0; 360 } 361 return $ret; 362} 363 364sub mconf_depends($$) { 365 my $depends = shift; 366 my $only_dep = shift; 367 my $res; 368 my $dep = shift; 369 $dep or $dep = {}; 370 371 $depends or return; 372 my @depends = @$depends; 373 foreach my $depend (@depends) { 374 my $m = "depends"; 375 $depend =~ s/^([@\+]+)//; 376 my $flags = $1; 377 my $vdep; 378 379 if ($vdep = $package{$depend}->{vdepends}) { 380 $depend = join("||", map { "PACKAGE_".$_ } @$vdep); 381 } else { 382 $flags =~ /\+/ and do { 383 next if $only_dep; 384 $m = "select"; 385 386 # Menuconfig will not treat 'select FOO' as a real dependency 387 # thus if FOO depends on other config options, these dependencies 388 # will not be checked. To fix this, we simply emit all of FOO's 389 # depends here as well. 390 $package{$depend} and mconf_depends($package{$depend}->{depends}, 1, $dep); 391 }; 392 $flags =~ /@/ or $depend = "PACKAGE_$depend"; 393 } 394 $dep->{$depend} =~ /select/ or $dep->{$depend} = $m; 395 } 396 foreach my $depend (keys %$dep) { 397 my $m = $dep->{$depend}; 398 $res .= "\t\t$m $depend\n"; 399 } 400 return $res; 401} 402 403sub print_package_config_category($) { 404 my $cat = shift; 405 my %menus; 406 my %menu_dep; 407 408 return unless $category{$cat}; 409 410 print "menu \"$cat\"\n\n"; 411 my %spkg = %{$category{$cat}}; 412 413 foreach my $spkg (sort {uc($a) cmp uc($b)} keys %spkg) { 414 foreach my $pkg (@{$spkg{$spkg}}) { 415 my $menu = $pkg->{submenu}; 416 if ($menu) { 417 $menu_dep{$menu} or $menu_dep{$menu} = $pkg->{submenudep}; 418 } else { 419 $menu = 'undef'; 420 } 421 $menus{$menu} or $menus{$menu} = []; 422 push @{$menus{$menu}}, $pkg; 423 print "\tconfig DEFAULT_".$pkg->{name}."\n"; 424 print "\t\tbool\n\n"; 425 } 426 } 427 my @menus = sort { 428 ($a eq 'undef' ? 1 : 0) or 429 ($b eq 'undef' ? -1 : 0) or 430 ($a cmp $b) 431 } keys %menus; 432 433 foreach my $menu (@menus) { 434 my @pkgs = sort { 435 package_depends($a, $b) or 436 ($a->{name} cmp $b->{name}) 437 } @{$menus{$menu}}; 438 if ($menu ne 'undef') { 439 $menu_dep{$menu} and print "if $menu_dep{$menu}\n"; 440 print "menu \"$menu\"\n"; 441 } 442 foreach my $pkg (@pkgs) { 443 my $title = $pkg->{name}; 444 my $c = (72 - length($pkg->{name}) - length($pkg->{title})); 445 if ($c > 0) { 446 $title .= ("." x $c). " ". $pkg->{title}; 447 } 448 print "\t"; 449 $pkg->{menu} and print "menu"; 450 print "config PACKAGE_".$pkg->{name}."\n"; 451 print "\t\t".($pkg->{tristate} ? 'tristate' : 'bool')." \"$title\"\n"; 452 print "\t\tdefault y if DEFAULT_".$pkg->{name}."\n"; 453 foreach my $default (split /\s*,\s*/, $pkg->{default}) { 454 print "\t\tdefault $default\n"; 455 } 456 print mconf_depends($pkg->{depends}, 0); 457 print "\t\thelp\n"; 458 print $pkg->{description}; 459 print "\n"; 460 461 $pkg->{config} and print $pkg->{config}."\n"; 462 } 463 if ($menu ne 'undef') { 464 print "endmenu\n"; 465 $menu_dep{$menu} and print "endif\n"; 466 } 467 } 468 print "endmenu\n\n"; 469 470 undef $category{$cat}; 471} 472 473sub gen_package_config() { 474 parse_package_metadata($ARGV[0]) or exit 1; 475 foreach my $preconfig (keys %preconfig) { 476 foreach my $cfg (keys %{$preconfig{$preconfig}}) { 477 my $conf = $preconfig{$preconfig}->{$cfg}->{id}; 478 $conf =~ tr/\.-/__/; 479 } 480 } 481 print_package_config_category 'Base system'; 482 foreach my $cat (keys %category) { 483 print_package_config_category $cat; 484 } 485} 486 487sub gen_package_mk() { 488 my %conf; 489 my %dep; 490 my %done; 491 my $line; 492 493 parse_package_metadata($ARGV[0]) or exit 1; 494 foreach my $name (sort {uc($a) cmp uc($b)} keys %package) { 495 my $config; 496 my $pkg = $package{$name}; 497 my @srcdeps; 498 499 next if defined $pkg->{vdepends}; 500 501 if ($ENV{SDK}) { 502 $conf{$pkg->{src}} or do { 503 $config = 'm'; 504 $conf{$pkg->{src}} = 1; 505 }; 506 } else { 507 $config = "\$(CONFIG_PACKAGE_$name)" 508 } 509 if ($config) { 510 print "package-$config += $pkg->{subdir}$pkg->{src}\n"; 511 $pkg->{prereq} and print "prereq-$config += $pkg->{subdir}$pkg->{src}\n"; 512 } 513 514 next if $done{$pkg->{src}}; 515 $done{$pkg->{src}} = 1; 516 517 foreach my $spkg (@{$srcpackage{$pkg->{src}}}) { 518 foreach my $dep (@{$spkg->{depends}}, @{$spkg->{builddepends}}) { 519 $dep =~ /@/ or do { 520 $dep =~ s/\+//g; 521 push @srcdeps, $dep; 522 }; 523 } 524 } 525 526 my $hasdeps = 0; 527 my $depline = ""; 528 foreach my $deps (@srcdeps) { 529 my $idx; 530 my $pkg_dep = $package{$deps}; 531 my @deps; 532 533 if ($pkg_dep->{vdepends}) { 534 @deps = @{$pkg_dep->{vdepends}}; 535 } else { 536 @deps = ($deps); 537 } 538 539 foreach my $dep (@deps) { 540 $pkg_dep = $package{$deps}; 541 if (defined $pkg_dep->{src}) { 542 ($pkg->{src} ne $pkg_dep->{src}) and $idx = $pkg_dep->{subdir}.$pkg_dep->{src}; 543 } elsif (defined($srcpackage{$dep})) { 544 $idx = $subdir{$dep}.$dep; 545 } 546 undef $idx if $idx =~ /^(kernel)|(base-files)$/; 547 if ($idx) { 548 next if $pkg->{src} eq $pkg_dep->{src}; 549 next if $dep{$pkg->{src}."->".$idx}; 550 next if $dep{$pkg->{src}."->($dep)".$idx}; 551 if ($pkg_dep->{vdepends}) { 552 $depline .= " \$(if \$(CONFIG_PACKAGE_$dep),\$(curdir)/$idx/compile)"; 553 $dep{$pkg->{src}."->($dep)".$idx} = 1; 554 } else { 555 $depline .= " \$(curdir)/$idx/compile"; 556 $dep{$pkg->{src}."->".$idx} = 1; 557 } 558 } 559 } 560 } 561 if ($depline) { 562 $line .= "\$(curdir)/".$pkg->{subdir}."$pkg->{src}/compile += $depline\n"; 563 } 564 } 565 566 if ($line ne "") { 567 print "\n$line"; 568 } 569 foreach my $preconfig (keys %preconfig) { 570 my $cmds; 571 foreach my $cfg (keys %{$preconfig{$preconfig}}) { 572 my $conf = $preconfig{$preconfig}->{$cfg}->{id}; 573 $conf =~ tr/\.-/__/; 574 $cmds .= "\techo \"uci set '$preconfig{$preconfig}->{$cfg}->{id}=\$(subst \",,\$(CONFIG_UCI_PRECONFIG_$conf))'\"; \\\n"; 575 } 576 next unless $cmds; 577 print <<EOF 578 579\$(TARGET_DIR)/etc/uci-defaults/$preconfig: FORCE 580 ( \\ 581$cmds \\ 582 ) > \$@ 583 584ifneq (\$(UCI_PRECONFIG)\$(CONFIG_UCI_PRECONFIG),) 585 package/preconfig: \$(TARGET_DIR)/etc/uci-defaults/$preconfig 586endif 587EOF 588 } 589} 590 591 592sub parse_command() { 593 my $cmd = shift @ARGV; 594 for ($cmd) { 595 /^target_config$/ and return gen_target_config(); 596 /^package_mk$/ and return gen_package_mk(); 597 /^package_config$/ and return gen_package_config(); 598 /^kconfig/ and return gen_kconfig_overrides(); 599 } 600 print <<EOF 601Available Commands: 602 $0 target_config [file] Target metadata in Kconfig format 603 $0 package_mk [file] Package metadata in makefile format 604 $0 package_config [file] Package metadata in Kconfig format 605 $0 kconfig [file] [config] Kernel config overrides 606 607EOF 608} 609 610parse_command(); 611