-->>舉例說明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)$/;語句