fix duplicate dependencies
[openwrt/staging/yousong.git] / scripts / metadata.pl
index fe135418ca1becae3ca613353f061a51bca7f3b3..4fa7be0412dba3d86737ab024d01bba6be06e2e8 100755 (executable)
@@ -1,43 +1,47 @@
 #!/usr/bin/perl
+use FindBin;
+use lib "$FindBin::Bin";
 use strict;
-my %preconfig;
-my %package;
-my %srcpackage;
-my %category;
-my %subdir;
-
-sub get_multiline {
-       my $prefix = shift;
-       my $str;
-       while (<>) {
-               last if /^@@/;
-               s/^\s*//g;
-               $str .= (($_ and $prefix) ? $prefix . $_ : $_);
-       }
+use metadata;
+
+my %board;
 
-       return $str;
+sub confstr($) {
+       my $conf = shift;
+       $conf =~ tr#/\.\-/#___#;
+       return $conf;
 }
 
 sub parse_target_metadata() {
-       my ($target, @target, $profile);        
-       while (<>) {
+       my $file = shift @ARGV;
+       my ($target, @target, $profile);
+       open FILE, "<$file" or do {
+               warn "Can't open file '$file': $!\n";
+               return;
+       };
+       while (<FILE>) {
                chomp;
                /^Target:\s*(.+)\s*$/ and do {
-                       my $conf = uc $1;
-                       $conf =~ tr/\.-/__/;
                        $target = {
-                               conf => $conf,
-                               board => $1,
-                               profiles => []
+                               id => $1,
+                               conf => confstr($1),
+                               profiles => [],
+                               features => [],
+                               depends => []
                        };
                        push @target, $target;
                };
+               /^Target-Board:\s*(.+)\s*$/ and do {
+                       $target->{board} = $1;
+                       $target->{boardconf} = confstr($1);
+               };
                /^Target-Kernel:\s*(\d+\.\d+)\s*$/ and $target->{kernel} = $1;
                /^Target-Name:\s*(.+)\s*$/ and $target->{name} = $1;
                /^Target-Path:\s*(.+)\s*$/ and $target->{path} = $1;
                /^Target-Arch:\s*(.+)\s*$/ and $target->{arch} = $1;
                /^Target-Features:\s*(.+)\s*$/ and $target->{features} = [ split(/\s+/, $1) ];
-               /^Target-Description:/ and $target->{desc} = get_multiline();
+               /^Target-Depends:\s*(.+)\s*$/ and $target->{depends} = [ split(/\s+/, $1) ];
+               /^Target-Description:/ and $target->{desc} = get_multiline(*FILE);
                /^Linux-Version:\s*(.+)\s*$/ and $target->{version} = $1;
                /^Linux-Release:\s*(.+)\s*$/ and $target->{release} = $1;
                /^Linux-Kernel-Arch:\s*(.+)\s*$/ and $target->{karch} = $1;
@@ -52,10 +56,11 @@ sub parse_target_metadata() {
                };
                /^Target-Profile-Name:\s*(.+)\s*$/ and $profile->{name} = $1;
                /^Target-Profile-Packages:\s*(.*)\s*$/ and $profile->{packages} = [ split(/\s+/, $1) ];
-               /^Target-Profile-Description:\s*(.*)\s*/ and $profile->{desc} = get_multiline();
-               /^Target-Profile-Config:/ and $profile->{config} = get_multiline("\t");
+               /^Target-Profile-Description:\s*(.*)\s*/ and $profile->{desc} = get_multiline(*FILE);
+               /^Target-Profile-Config:/ and $profile->{config} = get_multiline(*FILE, "\t");
                /^Target-Profile-Kconfig:/ and $profile->{kconfig} = 1;
        }
+       close FILE;
        foreach my $target (@target) {
                @{$target->{profiles}} > 0 or $target->{profiles} = [
                        {
@@ -68,74 +73,6 @@ sub parse_target_metadata() {
        return @target;
 }
 
-sub parse_package_metadata() {
-       my $pkg;
-       my $makefile;
-       my $preconfig;
-       my $subdir;
-       my $src;
-       while (<>) {
-               chomp;
-               /^Source-Makefile: \s*((.+\/)([^\/]+)\/Makefile)\s*$/ and do {
-                       $makefile = $1;
-                       $subdir = $2;
-                       $src = $3;
-                       $subdir =~ s/^package\///;
-                       $subdir{$src} = $subdir;
-                       $srcpackage{$src} = [];
-                       undef $pkg;
-               };
-               /^Package:\s*(.+?)\s*$/ and do {
-                       $pkg = {};
-                       $pkg->{src} = $src;
-                       $pkg->{makefile} = $makefile;
-                       $pkg->{name} = $1;
-                       $pkg->{default} = "m if ALL";
-                       $pkg->{depends} = [];
-                       $pkg->{builddepends} = [];
-                       $pkg->{subdir} = $subdir;
-                       $package{$1} = $pkg;
-                       push @{$srcpackage{$src}}, $pkg;
-               };
-               /^Version: \s*(.+)\s*$/ and $pkg->{version} = $1;
-               /^Title: \s*(.+)\s*$/ and $pkg->{title} = $1;
-               /^Menu: \s*(.+)\s*$/ and $pkg->{menu} = $1;
-               /^Submenu: \s*(.+)\s*$/ and $pkg->{submenu} = $1;
-               /^Submenu-Depends: \s*(.+)\s*$/ and $pkg->{submenudep} = $1;
-               /^Default: \s*(.+)\s*$/ and $pkg->{default} = $1;
-               /^Provides: \s*(.+)\s*$/ and do {
-                       my @vpkg = split /\s+/, $1;
-                       foreach my $vpkg (@vpkg) {
-                               $package{$vpkg} or $package{$vpkg} = { vdepends => [] };
-                               push @{$package{$vpkg}->{vdepends}}, $pkg->{name};
-                       }
-               };
-               /^Depends: \s*(.+)\s*$/ and $pkg->{depends} = [ split /\s+/, $1 ];
-               /^Build-Depends: \s*(.+)\s*$/ and $pkg->{builddepends} = [ split /\s+/, $1 ];
-               /^Category: \s*(.+)\s*$/ and do {
-                       $pkg->{category} = $1;
-                       defined $category{$1} or $category{$1} = {};
-                       defined $category{$1}->{$src} or $category{$1}->{$src} = [];
-                       push @{$category{$1}->{$src}}, $pkg;
-               };
-               /^Description: \s*(.*)\s*$/ and $pkg->{description} = "\t\t $1\n". get_multiline("\t\t ");
-               /^Config: \s*(.*)\s*$/ and $pkg->{config} = "$1\n".get_multiline();
-               /^Prereq-Check:/ and $pkg->{prereq} = 1;
-               /^Preconfig:\s*(.+)\s*$/ and do {
-                       my $pkgname = $pkg->{name};
-                       $preconfig{$pkgname} or $preconfig{$pkgname} = [];
-                       $preconfig = {
-                               id => $1
-                       };
-                       push @{$preconfig{$pkgname}}, $preconfig;
-               };
-               /^Preconfig-Type:\s*(.*?)\s*$/ and $preconfig->{type} = $1;
-               /^Preconfig-Label:\s*(.*?)\s*$/ and $preconfig->{label} = $1;
-               /^Preconfig-Default:\s*(.*?)\s*$/ and $preconfig->{default} = $1;
-       }
-       return %category;
-}
-
 sub gen_kconfig_overrides() {
        my %config;
        my %kconfig;
@@ -198,45 +135,6 @@ sub merge_package_lists($$) {
        return sort(@l);
 }
 
-sub gen_target_mk() {
-       my @target = parse_target_metadata();
-       
-       @target = sort {
-               $a->{board} cmp $b->{board}
-       } @target;
-       
-       foreach my $target (@target) {
-               my ($profiles_def, $profiles_eval);
-
-               foreach my $profile (@{$target->{profiles}}) {
-                       $profiles_def .= "
-  define Profile/$target->{conf}\_$profile->{id}
-    ID:=$profile->{id}
-    NAME:=$profile->{name}
-    PACKAGES:=".join(" ", merge_package_lists($target->{packages}, $profile->{packages}))."\n";
-                       $profile->{kconfig} and $profiles_def .= "    KCONFIG:=1\n";
-                       $profiles_def .= "  endef";
-                       $profiles_eval .= "
-\$(eval \$(call AddProfile,$target->{conf}\_$profile->{id}))"
-               }
-               print "
-ifeq (\$(CONFIG_TARGET_$target->{conf}),y)
-  define Target
-    KERNEL:=$target->{kernel}
-    BOARD:=$target->{board}
-    BOARDNAME:=$target->{name}
-    LINUX_VERSION:=$target->{version}
-    LINUX_RELEASE:=$target->{release}
-    LINUX_KARCH:=$target->{karch}
-    DEFAULT_PACKAGES:=".join(" ", @{$target->{packages}})."
-  endef$profiles_def
-endif$profiles_eval
-
-"
-       }
-       print "\$(eval \$(call Target))\n";
-}
-
 sub target_config_features(@) {
        my $ret;
 
@@ -265,7 +163,7 @@ sub gen_target_config() {
        print <<EOF;
 choice
        prompt "Target System"
-       default TARGET_BRCM_2_4
+       default TARGET_brcm_2_4
        reset if !DEVEL
        
 EOF
@@ -285,19 +183,52 @@ EOF
                        undef $help;
                }
        
-               print <<EOF
+               print <<EOF;
 config TARGET_$target->{conf}
        bool "$target->{name}"
        select $target->{arch}
        select LINUX_$kernel
-$features$help
-
 EOF
+               if ($target->{id} ne $target->{board}) {
+                       print "\tselect TARGET_".$target->{boardconf}."\n";
+               }
+               foreach my $dep (@{$target->{depends}}) {
+                       my $mode = "depends";
+                       my $flags;
+                       my $name;
+
+                       $dep =~ /^([@\+\-]+)(.+)$/;
+                       $flags = $1;
+                       $name = $2;
+
+                       $flags =~ /-/ and $mode = "deselect";
+                       $flags =~ /\+/ and $mode = "select";
+                       $flags =~ /@/ and print "\t$mode $name\n";
+               }
+               
+               print "$features$help\n\n"
        }
 
        print <<EOF;
 endchoice
 
+config TARGET_BOARD
+       string
+EOF
+       foreach my $target (@target) {
+               print "\t\tdefault \"".$target->{board}."\" if TARGET_".$target->{conf}."\n";
+       }
+
+       # add hidden target config options 
+       foreach my $target (@target) {
+               next if $board{$target->{board}};
+               if ($target->{id} ne $target->{board}) {
+                       print "\nconfig TARGET_".$target->{boardconf}."\n\tbool\n";
+                       $board{$target->{board}} = 1;
+               }
+       }
+       print <<EOF;
+
 choice
        prompt "Target Profile"
 
@@ -325,20 +256,31 @@ EOF
        print "endchoice\n";
 }
 
-
-sub find_package_dep($$) {
+my %dep_check;
+sub __find_package_dep($$) {
        my $pkg = shift;
        my $name = shift;
        my $deps = ($pkg->{vdepends} or $pkg->{depends});
 
        return 0 unless defined $deps;
        foreach my $dep (@{$deps}) {
+               next if $dep_check{$dep};
+               $dep_check{$dep} = 1;
                return 1 if $dep eq $name;
-               return 1 if ($package{$dep} and (find_package_dep($package{$dep},$name) == 1));
+               return 1 if ($package{$dep} and (__find_package_dep($package{$dep},$name) == 1));
        }
        return 0;
 }
 
+# wrapper to avoid infinite recursion
+sub find_package_dep($$) {
+       my $pkg = shift;
+       my $name = shift;
+
+       %dep_check = ();
+       return __find_package_dep($pkg, $name);
+}
+
 sub package_depends($$) {
        my $a = shift;
        my $b = shift;
@@ -359,6 +301,8 @@ sub mconf_depends($$) {
        my $depends = shift;
        my $only_dep = shift;
        my $res;
+       my $dep = shift;
+       $dep or $dep = {};
 
        $depends or return;
        my @depends = @$depends;
@@ -379,10 +323,14 @@ sub mconf_depends($$) {
                                # thus if FOO depends on other config options, these dependencies
                                # will not be checked. To fix this, we simply emit all of FOO's
                                # depends here as well.
-                               $package{$depend} and $res .= mconf_depends($package{$depend}->{depends}, 1);
+                               $package{$depend} and mconf_depends($package{$depend}->{depends}, 1, $dep);
                        };
                        $flags =~ /@/ or $depend = "PACKAGE_$depend";
                }
+               $dep->{$depend} =~ /select/ or $dep->{$depend} = $m;
+       }
+       foreach my $depend (keys %$dep) {
+               my $m = $dep->{$depend};
                $res .= "\t\t$m $depend\n";
        }
        return $res;
@@ -436,7 +384,7 @@ sub print_package_config_category($) {
                        print "\t";
                        $pkg->{menu} and print "menu";
                        print "config PACKAGE_".$pkg->{name}."\n";
-                       print "\t\ttristate \"$title\"\n";
+                       print "\t\t".($pkg->{tristate} ? 'tristate' : 'bool')." \"$title\"\n";
                        print "\t\tdefault y if DEFAULT_".$pkg->{name}."\n";
                        foreach my $default (split /\s*,\s*/, $pkg->{default}) {
                                print "\t\tdefault $default\n";
@@ -459,17 +407,17 @@ sub print_package_config_category($) {
 }
 
 sub gen_package_config() {
-       parse_package_metadata();
+       parse_package_metadata($ARGV[0]) or exit 1;
        print "menuconfig UCI_PRECONFIG\n\tbool \"Image configuration\"\n";
        foreach my $preconfig (keys %preconfig) {
-               foreach my $cfg (@{$preconfig{$preconfig}}) {
-                       my $conf = $cfg->{id};
+               foreach my $cfg (keys %{$preconfig{$preconfig}}) {
+                       my $conf = $preconfig{$preconfig}->{$cfg}->{id};
                        $conf =~ tr/\.-/__/;
                        print <<EOF
        config UCI_PRECONFIG_$conf
-               string "$cfg->{label}" if UCI_PRECONFIG
+               string "$preconfig{$preconfig}->{$cfg}->{label}" if UCI_PRECONFIG
                depends PACKAGE_$preconfig
-               default "$cfg->{default}"
+               default "$preconfig{$preconfig}->{$cfg}->{default}"
 
 EOF
                }
@@ -485,7 +433,7 @@ sub gen_package_mk() {
        my %dep;
        my $line;
 
-       parse_package_metadata();
+       parse_package_metadata($ARGV[0]) or exit 1;
        foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
                my $config;
                my $pkg = $package{$name};
@@ -535,10 +483,10 @@ sub gen_package_mk() {
        }
        foreach my $preconfig (keys %preconfig) {
                my $cmds;
-               foreach my $cfg (@{$preconfig{$preconfig}}) {
-                       my $conf = $cfg->{id};
+               foreach my $cfg (keys %{$preconfig{$preconfig}}) {
+                       my $conf = $preconfig{$preconfig}->{$cfg}->{id};
                        $conf =~ tr/\.-/__/;
-                       $cmds .= "\techo \"uci set '$cfg->{id}=\$(subst \",,\$(CONFIG_UCI_PRECONFIG_$conf))'\"; \\\n";
+                       $cmds .= "\techo \"uci set '$preconfig{$preconfig}->{$cfg}->{id}=\$(subst \",,\$(CONFIG_UCI_PRECONFIG_$conf))'\"; \\\n";
                }
                next unless $cmds;
                print <<EOF
@@ -559,7 +507,6 @@ EOF
 sub parse_command() {
        my $cmd = shift @ARGV;
        for ($cmd) {
-               /^target_mk$/ and return gen_target_mk();
                /^target_config$/ and return gen_target_config();
                /^package_mk$/ and return gen_package_mk();
                /^package_config$/ and return gen_package_config();
@@ -567,7 +514,6 @@ sub parse_command() {
        }
        print <<EOF
 Available Commands:
-       $0 target_mk [file]             Target metadata in makefile format
        $0 target_config [file]         Target metadata in Kconfig format
        $0 package_mk [file]            Package metadata in makefile format
        $0 package_config [file]        Package metadata in Kconfig format