關於Openwrt metadata.pl腳本的幾個函數說明_part2

-->>舉例說明mconf_depends

接下來看一下對這個片段的具體使用,即mconf_depends

提取出關鍵元素

$pkg->{depends}=+libc+USE_EGLIBC:librt +USE_EGLIBC:libpthread

處理+libc

第一次進入mconf_depends

my $pkgname=shift;$pkg->{name},即libpcap

my$depends=shift;$pkg->{depends}

my$only_dep = 0;

$dep= {};

$seen={};

$depend=libc

$flag=’+’

$package{$depend}and mconf_depends($pkgname, $package{$depend}->{depends}, 1, $dep, $seen,$condition);

$package{libc}存在然後mconf_depends{libpcap,$package{libc}->{depends}, 1, {}, {}, $condition}

第二次進入mconf_depends

my$pkgname=shift;即$pkgname=libpcap

my$depends=shift;$depends=${package{libc}->{depends}}

my$only_dep=shift;$only_dep=1

my$dep=shift;$dep={}

my $seen=shift;$seen={}

my$parent_condition=shift;undef

$depnd=libgcc

$flag=+

$package{libgcc}and mconf_depends{libpcap, $package{libgcc}->{depends}, 1, {}, {},$condition}

第三次進入mconf_depends

發現${package{libgcc}->{depends}}爲空,故直接返回;

然後回到上一次,也就是第二次執行mconf_depends

$m=”select”

nextif $only_dep;跳出該次循環

由於$dep爲空,返回$res爲空

然後回到第一次進入

$m=”select”

由於$package{libc}->{vdepends}爲空,

$flags=~ /@/ or $depend = "PACKAGE_$depend";

$depend=”PACKAGE_libc”

$condition爲空,故直接執行

$dep->{$depend}=~ /select/ or $dep->{$depend} = $m;

$dep->{PACKAGE_libc}=”select”

最後在輸出的時候應該是$res.=”\t\tselect PACKAGE_libc\n”

 

然後開始處理+USE_EGLIBC:librt

$depend= USE_EGLIBC:librt

$flag=’+’

進入到if($depend =~ /^(.+):(.+)$/)條件內

$condition=”USE_EGLIBC”

$depend=librt

進入到$flags=~ /\+/ and do {……}

$package{librt}and mconf_depends{libpcap, $package{librt}->{depends}, 1, {}, {}, “USE_EGLIBC”}

第二次進入mconf_depend

$pkgname=libpcap

$depends=$package{librt}->{depends}

$only_dep=1

$parent_condition=”USE_EGLIBC”

$depend=”libpthread”

$flag=’+’

$condition=”USE_EGLIBC”

$seen->{“USE_EGLIBC:libpthread”}=1

然後進入

$flags=~ /\+/ and do {……}

$packge{“libpthread”}and mconf_depends{“libpcap”, $package{“libpthread”}->{depends}, 1, {}, {}, “USE_EGLIBC”}

第三次進入mconf_depends

由於$package{“libpthread”}->{depends}爲空,故直接返回

返回到第二次

$m =“select”

返回$res爲空

返回到第一次

$depend= “PACKAGE_librt if USE_EGLIBC”

$dep->{PACKAGE_libbrt} = “select”;

$res.=”\t\tselectPACKAGE_librt if USE_EGLIBC\n”

 

處理+USE_EGLIBC:libpthread

$depends=”USE_EGLIBC:libpthread”

$flag=’+’

$condition=”USE_EGLIBC”

$depend=libpthread

$package{libpthread}and mconf_depends{libpcap, $package{libpthread}->{depends}, 1, {}, {}, “USE_EGLIBC”}

第二次進入

$pkgname=libpcap

$depends=$package{libpthread}->{depends}

$only_dep=1

$parent_condition=”USE_GLIBC”

$depend=”libgcc”

$flag=’+’

$condition=”USE_GLIBC”

$seen->{“USE_GLIBC”:”libgcc”}=1

$package{libgcc}and mconf_depends{libpcap, $package{libgcc}->{depends}, 1, {}, {},$condition}

第三次進入

由於$package{libgcc}->{depends}爲空,直接返回

$m=”select”

返回$res爲空

返回到第一次

$m=”select”

$depend=”PACKAGE_libthread if USE_GLIBC”

$dep->{PACKAGE_libthread} = “select”;

$res.=”\t\tslectPACKAGE_libthread if USE_GLIBC\n”

 

下面再舉一個$res返回depends的情況

Package:kmod-ipsec4

Submenu:Network Support

Version:<LINUX_VERSION>-

Depends:kmod-ipsec +kmod-iptunnel4

Menu-Depends:

Provides:

Section:kernel

Category:Kernel modules

Title:IPsec related modules (IPv4)

Maintainer:OpenWrt Developers Team <[email protected]>

Source:

Type:ipkg

Kernel-Config:CONFIG_INET_AH CONFIG_INET_ESP CONFIG_INET_IPCOMP CONFIG_INET_XFRM_MODE_BEETCONFIG_INET_XFRM_MODE_TRANSPORT CONFIG_INET_XFRM_MODE_TUNNELCONFIG_INET_XFRM_TUNNEL

Description:  Kernel modules for IPsec support in IPv4.

 Includes:

 - ah4

 - esp4

 - ipcomp4

 - xfrm4_mode_beet

 - xfrm4_mode_transport

 - xfrm4_mode_tunnel

 - xfrm4_tunnel

OpenWrtDevelopers Team <[email protected]>

@@

 

mconf_depends(“kmod-ipsec4”,$pkg->{depends}, 0)

$pkgname=”kmod-ipsec4”

$depends=”kmod-ipsec +kmod-iptunnel4

$only_dep=0

先處理kmod-ipsec

$depend=”kmod-ipsec”

$flag=””

$depend=”PACKAGE_kmod-ipsec4”

$dep->{“PACKAGE_kmod-ipsec4”}=”depends”

輸出$res=”\t\tdepends PACKGE_kmod-ipsec”

故當Depends後面的依賴XXX前面沒有跟任何符號時,其轉義到.Config-package.in是depends XXX

 

mconf_depends的整體來看,Depends:的依賴關係即$pkg->{depends}數組,只要其中的元素XXX前綴是‘+’,則轉義到.config-package.in文件中就是select,其他都是depends

 

mconf_depends($pkg->{name},$pkg->{depends}, 0);

mconf_depends($pkg->{name},$pkg->{mdepends}, 0);

mconf_depends($pkgname,$package{$depend}->{depends}, 1, $dep, $seen, $condition);


-->>mconf_depends

現在來插播一下mconf_depends函數;

         my$pkgname = shift;

         my$depends = shift;

         my$only_dep = shift;

         my$res;

         my$dep = shift;

         my$seen = shift;

         my$parent_condition = shift;

         $depor $dep = {};

         $seenor $seen = {};

 

最前面三句,主要是取參數值。

$depends orreturn;

         my@depends = @$depends;

         foreachmy $depend (@depends) {……}

如果$depends爲空,直接返回。

“my @depends = @$depends;”從這條語句也可以看出傳進來的$depends參數應該是一個數組。接下來的foreach語句,就是遍歷該數組的每個成員。

來看一下foreach的body:

my $m = "depends";

                   my$flags = "";

                   $depend=~ s/^([@\+]+)// and $flags = $1;

                   my$vdep;

                   my$condition = $parent_condition;

定義一些局部變量;從“$depend =~ s/^([@\+]+)// and $flags = $1;”可以看出$flags爲‘+’或者‘@+’;“my$condition = $parent_condition;”當前2次調用mconf_depends時,$parent_condition未定義undef;

                   nextif $condition eq $depend;

                   nextif $seen->{"$parent_condition:$depend"};

                   $seen->{"$parent_condition:$depend"}= 1;

前2句是符合條件則跳出此次循環,可惜的是第一次進入都達不到要求,直接對$seen設置,注意:$seen設置也要$parent_conditino$depend同時存在纔可以設置

if ($depend =~/^(.+):(.+)$/) {

                            if($1 ne "PACKAGE_$pkgname") {

                                     if($condition) {

                                               $condition= "$condition && $1";

                                     }else {

                                               $condition= $1;

                                     }

                            }

                            $depend= $2;

                            if($condition =~ /PACKAGE_(.+)/) {

                                     my$name = $1;

                                     my$vdep;

                                     if($vdep = $package{$name}->{vdepends}) {

                                               my$providers = join("||", map { "PACKAGE_".$_ } @$vdep);

                                               $condition=~ s/(PACKAGE_$name)/(\1||$providers)/;

                                     }

                   }

明顯該if判斷是取$depends數組中存在依賴關係的元素,即有“$1:$2”的;如果符合,則繼續判斷,如果$1不等於PACKAGE_$pkgname,即不爲當前的package(普遍都是這種情況),則對$condition進行設置,在前2次調用mconf_depends時都進入$condition=$1;接着,$depend爲S2,後面判斷如果$condition符合“PACKAGE_*”形式,則判斷$package{$name}->{vdepends}是否爲真(注意,該處的$package實際上就是引用的metadata.pm中的全局變量),如果爲真的情況下,則對$condition賦值;

注意:Perl中,map的作用是提取 @$vdep的元素,然後給{……}處理,處理的結果仍是數組,由map返回;

join的作用是將後面的數組元素以特定的分隔符連接。

         nextif $package{$depend} and $package{$depend}->{buildonly};

                   if($package{$depend}->{virtual} and $vdep = $package{$depend}->{vdepends}){

                            $depend= join("||", map { "PACKAGE_".$_ } @$vdep);

                   }else {……}

如果$package{$depend}存在且爲真,且$package{$depend}->{buildonly}爲真,則跳出循環,可以看出$package{$depend}是 一個hash數組;

接下來的if語句就不多說了。

else分支:

首先

$flags =~ /\+/ and do {

                                     #Menuconfig will not treat 'select FOO' as a real dependency

                                     #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 mconf_depends($pkgname, $package{$depend}->{depends}, 1, $dep, $seen,$condition);

 

                                     $m= "select";

                                     nextif $only_dep;

                            };

判斷$flag是‘+’,然後如果$package{$depend}存在,則調用mconf_depends本身;

if ($vdep =$package{$depend}->{vdepends}) {……}

該if語句不多說。

$flags =~ /@/ or $depend ="PACKAGE_$depend";

判斷如果$flag是否是‘@’,如果不是則對$depend賦值爲”PACKAGE_$depend”

if ($condition) {……}不多說。

$dep->{$depend} =~ /select/ or$dep->{$depend} = $m;

 

foreach my $depend (keys %$dep) {

                   my$m = $dep->{$depend};

                   $res.= "\t\t$m $depend\n";

         }

foreach語句遍歷%$dep,然後返回對應的字符串;

 

現在讓我們從頭到尾梳理一遍:

第一次進入mconf_depends函數的處理路徑,

mconf_depends($pkg->{name},$pkg->{depends}, 0);

$pkgname = $pkg->{name};

$depends = $pkg->{depends};

$only_dep = 0;

$dep = {};

$seen = {};

 

以Depends: +libc +USE_EGLIBC:librt +USE_EGLIBC:libpthread+PACKAGE_kmod-mac80211:libnl-tiny+PACKAGE_kmod-qca-wifi-perf:kmod-qca-wifi-perf+CONFIG_PACKAGE_kmod-qca-wifi-akronite-perf:kmod-qca-wifi-akronite-perf爲例

$depend =~ s/^([@\+]+)// and $flags =$1;該句將’+’或者’@’去掉,並將其’+’或’@’賦給$flag

遇到“$1:$2”,判斷$1是否等於“PACKAGE_$pkgname”,一般不等,進入$condition=$1;

然後$depend=$2;

如果$condition爲“PACKAGE_$1”格式,則

接下來的if(){} else {}一般都會進入else語句;

如果$flag爲‘+’,則$m = “select”爲後面的輸出做準備,

$flags =~ /@/ or $depend = "PACKAGE_$depend";這句話表示如果$flag不是’@’,則將$depend重新賦值成“PACKAGE_$depend”的形式

接下來如果$m = “select”,則$depend = “$depend if $condition”;否則$depend = “!($condition)|| $depend”

 

最後則是判斷$dep->{$depnd}是否爲”select”,否則$dep->{$depend} = $m;而$m的初始值爲”depends”。

 

 -->>gen_package_mk

分析make menuconfig時的調用,include/toplevel.mk中,./scripts/metadata.pl package_mk tmp/.packageinfo >tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }

即最終的生成產物輸出在tmp/.packagedeps文件中。

 

首先還是看一下函數body

parse_package_metadata($ARGV[0]) or exit1; 調用parse_package_metadata函數遍歷文件,實際上就是tmp/.pacakageinfo文件,parese_package_metadata函數這裏不再贅述

foreach my $name (sort {uc($a) cmpuc($b)} keys %package) {……}

注意,在perl中,uc是將小寫字母轉換成大寫字母,sort cmp是比較,以ACSII順序進行排列

 

if ($ENV{SDK}) {…..} else {……}

可以看到SDK是在target/sdk/files/Makefile中定義並export的;這裏暫且不管什麼時候引入sdk目錄吧。當編譯一個完整軟件的時候,都應該定義該變量吧。

if爲真的情況下,$conf{$pkg->{src}}第一次進入的時候都應該爲空,即my %conf函數局部變量。

else內,$config ="\$(CONFIG_PACKAGE_$name)"

 

if ($config) {……}

看樣子始終都會進入if內,

if內的語句:

$pkg->{buildonly} and $config ="";檢查“/^Build-Only: \s*(.+)\s*$/”,當buildonly爲真的時候,將$config置空

print "package-$config +=$pkg->{subdir}$pkg->{src}\n";

打印出類似“package-$(CONFIG_PACKAGE_6in4) += 6in4”這樣的語句

                            if($pkg->{variant}) {

                                     if(!defined($done{$pkg->{src}})) {

                                               print"\$(curdir)/$pkg->{subdir}$pkg->{src}/default-variant :=$pkg->{variant}\n";

                                     }

                                     print"\$(curdir)/$pkg->{subdir}$pkg->{src}/variants += \$(if$config,$pkg->{variant})\n"

                            }

該語句檢查“/^Build-Variant: \s*([\w\-]+)\s*/”,if(!defined($done{$pkg->{src}})) {……}第一次肯定不會進去

$pkg->{prereq} and print"prereq-$config += $pkg->{subdir}$pkg->{src}\n";

這句話,是檢查prereq,即Makefile中“/^Prereq-Check:/”是否存在,如果存在,則打印出類似“prereq-$(CONFIG_PACKAGE_grub) += grub”這樣的字符串

 

next if $done{$pkg->{src}};如果對$done{$pkg->{src}};進行了設置,則跳出此次循環

$done{$pkg->{src}} = 1;這裏對$done{$pkg->{src}}進行設置,即對%done進行賦值;

 

if (@{$pkg->{buildtypes}} > 0) {

                            print"buildtypes-$pkg->{subdir}$pkg->{src} = ".join(' ',@{$pkg->{buildtypes}})."\n";

                   }

檢查buildtypes的元素個數,即/^Build-Types:\s*(.+)\s*$/ and $pkg->{buildtypes} = [ split/\s+/, $1 ];如果大於0,則打印出來,類似“buildtypes-grub = host”這樣的字符串

注意,在Perl中,$#數組名,表示數組中最後一個元素的下標,等於元素個數減1@數組名,表示數組中元素的個數;$標量=@數組名,表示將一個數組賦值給一個標量變量,標量得到的是這個數組的元素個數;$數組名[數組下標],表示去除數組中相應的元素

 

foreach my $spkg(@{$srcpackage{$pkg->{src}}}) {……}

foreach my $dep (@{$spkg->{depends}},@{$spkg->{builddepends}}) {……}即取/^Depends: \s*(.+)\s*$/ and $pkg->{depends} = [ split /\s+/, $1]; 和 /^Build-Depends: \s*(.+)\s*$/ and $pkg->{builddepends} = [ split/\s+/, $1 ];

$dep =~ /@/ or do {……} 即取depends和builddepends數組中不是@的,然後將’+’字符去掉,然後壓入@srcdeps數組。

 

foreach my $type(@{$pkg->{buildtypes}}) {……}

next unless$pkg->{"builddepends/$type"}; 如果$pkg->{“builddenpends/$type”}爲空則跳出此次循環,即/^Build-Depends\/(\w+):\s*(.+)\s*$/ and $pkg->{"builddepends/$1"} = [ split /\s+/, $2 ];在tmp/.packageinfo文件中發現符合這樣正則表達式的字符很少,故一般直接跳出此次循環。

對foreach my $dep (@{$pkg->{"builddepends/$type"}}) {…..}不做說明

 

foreach my $deps (@srcdeps) {……}

if ($deps =~ /^(.+):(.+)/) {

                                     $condition= $1;

                                     $deps= $2;

                            }

即在tmp/.packageinfo文件中Depends和Build-Depends字段中形如“PACKAGE_kmod-madwifi:madwifi”,$condition=PACKAGE_kmod-madwifi,$deps=madwifi

                            if ($deps =~ /^(.+)(\/.+)/) {

                                     $deps= $1;

                                     $suffix= $2;

                            }

即” toolchain/compile”這樣的字符串,但是很少看到,$deps=toolchain,$suffix=compile

後面的講述我們只就第一種即“if ($deps =~ /^(.+):(.+)/)”這種情況介紹;

my $pkg_dep = $package{$deps};即my$pkg_dep=$package{madwifi}

if (!defined $pkg_dep->{virtual}) {

                                     @deps= ($deps);

                            }

 

                            if($pkg_dep->{vdepends}) {

                                     @deps= (@deps, @{$pkg_dep->{vdepends}});

                            }

 

即檢查/^Provides: \s*(.+)\s*$/,一般都不會存在,即會進入@dep=($deps),不會進入@dep=(@deps,@{$pkg_dep->{vdepends}})

 

foreach my $dep (@deps) {……}

期間的內容不再具體分析了,

($pkg->{src} ne $pkg_dep->{src}.$suffix) and$idx = $pkg_dep->{subdir}.$pkg_dep->{src};有這樣用‘.’連接的語句,注意在Perl中,’.’是字符串連接的作用,沒有在c中所謂的引用的作用。

最後生成“$line .="\$(curdir)/".$pkg->{subdir}."$pkg->{src}/compile +=$depline\n";”形如“$(curdir)/6in4/compile += $(curdir)/toolchain/compile $(if$(CONFIG_USE_EGLIBC),$(curdir)/toolchain/compile)”這樣的字符串,然後打印出來

 

-->>示例說明

舉個例子吧

         以

package-$(CONFIG_PACKAGE_6in4) += 6in4

$(curdir)/6in4/compile +=$(curdir)/toolchain/compile $(if$(CONFIG_USE_EGLIBC),$(curdir)/toolchain/compile)

的打印輸出爲例

 

先看一下tmp/.packageinfo源文件中的相關makefile段落

Source-Makefile: package/6in4/Makefile

Package: 6in4

Version: 11-1

Depends: +libc +USE_EGLIBC:librt +USE_EGLIBC:libpthread+kmod-ipv6 +kmod-sit

Menu-Depends:

Provides:

Section: ipv6

Category: IPv6

Title: IPv6-in-IPv4 configurationsupport

Maintainer: Jo-Philipp Wich<[email protected]>

Source:

Type: ipkg

Description: Provides support for 6in4tunnels in /etc/config/network.

Refer tohttp://wiki.openwrt.org/doc/uci/network for

configuration details.

Jo-Philipp Wich <[email protected]>

@@

 

通過parse_package_metadata可以得出:

$package{6in4}

$package{6in4}->{src}=”6in4”

$package{6in4}->{makefile}=”package/6in4/Makefile”

$package{6in4}->{name}=”6in4”

$package{6in4}->{default}=”m if ALL”

$package{6in4}->{depends}=(“+libc”,”+USE_EGLIBC:librt”,”+USE_EGLIBC:libpthread”,”+kmod-ipv6”,”+kmod-sit”)

$package{6in4}->{mdepends}=

$package{6in4}->{vdepends}=

$package{6in4}->{builddepends}=

$package{6in4}->{buildtypes}=

$package{6in4}->{subdir}=””

$package{6in4}->{tristate}=1

$package{6in4}->{version}=”11-1”

$package{6in4}->{title}=

$package{6in4}->{menu}=

$package{6in4}->{submenu}=

$package{6in4}->{submenudep}=

$package{6in4}->{source}=

$package{6in4}->{hidden}=

$package{6in4}->{variant}=

$package{6in4}->{buildonly}=

$package{6in4}->{builddepends}=

$package{6in4}->{builddepends/$1}=

$package{6in4}->{buildtypes}=

$package{6in4}->{category}=”IPv6”

$package{6in4}->{config}=

$package{6in4}->{prereq}=

$srcpackage{6in4}=$package{6in4}

可以發現,首先進入$config = "\$(CONFIG_PACKAGE_$name)",然後打印出print"package-$config += $pkg->{subdir}$pkg->{src}\n";即package-$(CONFIG_PACKAGE_6in4)+= 6in4

$done{$pkg->{src}} = 1;即$done{6in4}=1

if (@{$pkg->{buildtypes}} > 0) {…..}跳過

進入foreach my $spkg (@{$srcpackage{$pkg->{src}}}) {……},之後得到srcdeps=(“libc”,”USE_EGLIBC:librt”,”USE_EGLIBC:libpthread”,”kmod-ipv6”,”kmod-sit”)

foreach my $type(@{$pkg->{buildtypes}}) {……} 跳過

進入foreach my $deps (@srcdeps) {……}

         首先”libc”,

直接進入my $pkg_dep =$package{$deps};即$pkg_dep=$package{libc},

         進入if(!defined $pkg_dep->{virtual}) {……},即@deps={libc}

if($pkg_dep->{vdepends}) {……}跳過

進入foreach my $dep(@deps) {……}

$pkg_dep =$package{$deps};即$pkg_dep=$package{libc}

進入if (defined $pkg_dep->{src}{},執行($pkg->{src}ne $pkg_dep->{src}.$suffix) and $idx =$pkg_dep->{subdir}.$pkg_dep->{src};得到$idx=$packge{libc}->{subdir}.$package{libc}->{src},即$idx=toolchain

進入if($pkg_dep->{vdepends}) {……} else {……}的else,即$depstr=”$(curdir)/toolchain/compile”,$dep{6in4->libc}=1

進入if ($depline) {……},得到$depline=” $(curdir)/toolchain/compile”

 

在看USE_EGLIBC:librt

$condition=”USE_EGLIBC”

$deps=”librt”

$package{librt}->src=”toolchain”,所以$idx=”toolchain”

進入 if ($pkg_dep->{vdepends}) {……} else {……}的else分支,即$depstr=”$(curdir)/toolchain/compile”

$subdeplines{$depstr}++;即$subdeplines{”$(curdir)/toolchain/compile”}++

進入if ($depline) {……};即$depline = get_conditional_dep($condition, $depline);,得到$depline=”$(if \$(CONFIG_$condtion),$depstr)”即”$(if$CONFIG_USE_EGLIBC, $(curdir)/toolchain/compile)”

 

USE_EGLIBC:libpthread

最終得到”$(if $CONFIG_USE_EGLIBC, $(curdir)/toolchain/compile)”

 

kmod-ipv6

$package{kmod-ipv6}->{src}=”kernel”

進入到undef $idx if $idx =~ /^(kernel)|(base-files)$/;語句

 

kmod-sit

$package{ kmod-sit }=”kernel”

進入到undef $idx if $idx =~ /^(kernel)|(base-files)$/;語句

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章