Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:31:48

0001 #!/usr/bin/env perl
0002 use File::Basename;
0003 use lib dirname($0);
0004 use SCRAMGenUtils;
0005 use Getopt::Long;
0006 
0007 my $pwd=`/bin/pwd`; chomp $pwd; $pwd=&SCRAMGenUtils::fixPath($pwd);
0008 my $scriptDir=dirname($0);
0009 if ($scriptDir!~/^\//){$scriptDir="${pwd}/${scriptDir}";}
0010 
0011 #get the command-line options
0012 if(&GetOptions(
0013            "--release=s",\$dir,
0014            "--tool=s",\@itools,
0015            "--product=s",\@iproducts,
0016            "--detail",\$detail,
0017            "--dependency=s",\$dependency,
0018            "--clean",\$clean,
0019            "--recursive",\$full,
0020            "--cppfilt",\$cppfilt,
0021            "--graph",\$graph,
0022            "--help",\$help,
0023               ) eq ""){print STDERR "#Wrong arguments.\n"; &usage_msg();}
0024 
0025 my %systemsym=();
0026 $systemsym{"__cxa_.+"}=1;
0027 $systemsym{"__gxx_.+"}=1;
0028 $systemsym{_fini}=1;
0029 $systemsym{_init}=1;
0030 $systemsym{fclose}=1;
0031 $systemsym{fopen}=1;
0032 $systemsym{"pthread_cond_.+"}=1;
0033 $systemsym{regexec}=1;
0034 $systemsym{".+\@\@GLIBCXX.*"}=1;
0035 $systemsym{".+\@\@GCC.*"}=1;
0036 $systemsym{".+\@\@CXXABI.*"}=1;
0037 $systemsym{__fxstat64}=1;
0038 $systemsym{__lxstat64}=1;
0039 $systemsym{__xstat64}=1;
0040 $systemsym{_dl_argv}=1;
0041 $systemsym{_r_debug}=1;
0042 $systemsym{getrlimit64}=1;
0043 $systemsym{pthread_create}=1;
0044 $systemsym{readdir64}=1;
0045 
0046 my $symDefine="T|R|V|W|B|D";
0047 my $symUnDefine="U";
0048 
0049 if(defined $help){&usage_msg();}
0050 
0051 if(defined  $detail){$detail=1;}
0052 else{$detail=0;}
0053 
0054 if(defined  $cppfilt){$cppfilt=1;}
0055 else{$cppfilt=0;}
0056 
0057 if(defined  $full){$full=1;}
0058 else{$full=0;}
0059 
0060 if(defined  $graph){$graph=1;}
0061 else{$graph=0;}
0062 
0063 if (!defined $dir){$dir=$pwd;}
0064 my $release=&SCRAMGenUtils::scramReleaseTop($dir);
0065 if($release eq ""){print STDERR "ERROR: Please run this script from a SCRAM-based area.\n"; exit 1;}
0066 &SCRAMGenUtils::init ($release);
0067 my $releaseTop=&SCRAMGenUtils::getFromEnvironmentFile("RELEASETOP",$release);
0068 $SCRAMGenUtils::CacheType=0;
0069 
0070 my $scramarch=&SCRAMGenUtils::getScramArch();
0071 my $cachedir="${pwd}/Cache";
0072 my $symboldir="${cachedir}/Symbols";
0073 my $data={};
0074 my $xjobs=10;
0075 
0076 my %utools=();
0077 if ($dependency eq "")
0078 {
0079   foreach my $t (@itools)
0080   {
0081     my $lt=lc($t);
0082     if (-f "${release}/.SCRAM/${scramarch}/timestamps/${lt}"){$utools{TOOLS}{$lt}=1;}
0083     else{$utools{TOOLS}{$t}=1;}
0084   }
0085   foreach my $t (@iproducts){$utools{SELF}{$t}=1;}
0086   if (scalar(keys %utools)==0){print STDERR "Missing tool/product name.\n"; &usage_msg();}
0087 }
0088 
0089 if (defined  $clean){system("rm -rf $symboldir");}
0090 system("mkdir -p $symboldir ${cachedir}/Dot");
0091 
0092 print "Reading external tools symbols info ....";
0093 system("mkdir -p ${symboldir}/TOOLS ${symboldir}/SYSTEM");
0094 my $cf="${release}/.SCRAM/${scramarch}/ToolCache.db.gz";
0095 if (-f $cf){&addToolDep(&SCRAMGenUtils::readCache($cf),"TOOLS");}
0096 &SCRAMGenUtils::waitForChild();
0097 print STDERR "\n";
0098 $data->{SYSTEM_SYMBOLS_DEF}=&SCRAMGenUtils::mergeSymbols("${symboldir}/SYSTEM","",$symDefine);
0099 
0100 $data->{paths}{0}="lib/${scramarch}";
0101 $data->{paths}{1}="bin/${scramarch}";
0102 $data->{paths}{2}="test/${scramarch}";
0103 
0104 my $prodfile="${release}/src/ReleaseProducts.list";
0105 if (!-f $prodfile)
0106 {
0107   my $rdir=$release;
0108   if ($releaseTop ne "")
0109   {
0110     $prodfile="${release}/src/ReleaseProducts.list";
0111     $rdir=$releaseTop;
0112   }
0113   if (!-f $prodfile)
0114   {
0115     $prodfile="${cachedir}/ReleaseProducts.list";
0116     if (!-f $prodfile){system("${scriptDir}/RelProducts.pl $rdir > $prodfile");}
0117   }
0118 }
0119 
0120 foreach my $line (`cat $prodfile`)
0121 {
0122   chomp $line;
0123   my ($pack,$prods)=split(":",$line,2);
0124   $data->{pack}{$pack}={};
0125   my @types=split('\\|',$prods,4);
0126   for(my $i=0;$i<1;$i++)
0127   {
0128     foreach my $prod (split(",",$types[$i]))
0129     {
0130       if ($prod eq ""){next;}
0131       $data->{pack}{$pack}{$prod}=1;
0132       $data->{prod}{$prod}{pack}=$pack;
0133       $data->{prod}{$prod}{path}=$i;
0134     }
0135   }
0136 }
0137 
0138 print "Reading local libraries symbols info ....";
0139 system("mkdir -p ${symboldir}/SELF");
0140 foreach my $prod (keys %{$data->{prod}})
0141 {
0142   my $p=$data->{paths}{$data->{prod}{$prod}{path}};
0143   my $f="${release}/${p}/${prod}";
0144   if ((!-f $f) && ($releaseTop ne "")){$f="${releaseTop}/${p}/${prod}";}
0145   if ($prod=~/^lib.+\.so$/){$data->{PRODUCT_MAP}{$prod}=$data->{prod}{$prod}{pack};}
0146   if (-f $f)
0147   {
0148     &SCRAMGenUtils::symbolCacheFork($f,"cmssw","${symboldir}/SELF",$xjobs);
0149     print STDERR ".";
0150   }
0151   else{print STDERR "ERROR: Missing file: $f\n";}
0152 }
0153 &SCRAMGenUtils::waitForChild();
0154 print STDERR "\n";
0155 &SCRAMGenUtils::writeHashCache($data->{PRODUCT_MAP},"${symboldir}/Lib2Package.db");
0156 &SCRAMGenUtils::writeHashCache($data->{TOOL_TYPE},"${symboldir}/LibTypes.db");
0157 
0158 if ($dependency ne "")
0159 {
0160   $data->{PRODUCT_MAP} = &SCRAMGenUtils::readHashCache("${symboldir}/Lib2Package.db");
0161   $data->{TOOL_TYPE} = &SCRAMGenUtils::readHashCache("${symboldir}/LibTypes.db");
0162   $data->{SELF_SYMBOLS_DEF}=&SCRAMGenUtils::mergeSymbols("${symboldir}/SELF","",$symDefine);
0163   $data->{TOOLS_SYMBOLS_DEF}=&SCRAMGenUtils::mergeSymbols("${symboldir}/TOOLS","",$symDefine);
0164   &doDependency($dependency);
0165   exit 0;
0166 }
0167 else
0168 {
0169   delete $data->{SELF_SYMBOLS_DEF};
0170   delete $data->{TOOLS_SYMBOLS_DEF};
0171   delete $data->{PRODUCT_MAP};
0172   delete $data->{TOOL_TYPE}; 
0173 }
0174 
0175 $data->{SELF_SYMBOLS_UNDEF}=&SCRAMGenUtils::mergeSymbols("${symboldir}/SELF","",$symUnDefine);
0176 
0177 my $toolsym={};
0178 &findDefinedSyms(\%utools,$symDefine,$toolsym);
0179 
0180 my %deps=();
0181 $deps{direct}=&findSymbolDependency($toolsym);
0182 if($detail){&detailDepInfo("direct",\%deps);}
0183 if($full){&processSelfDependency("direct",\%deps);}
0184 
0185 my %packs=();
0186 foreach my $lib (keys %deps)
0187 {
0188   if (exists $data->{prod}{$lib}){$packs{$data->{prod}{$lib}{pack}}{$lib}=1;}
0189   foreach my $dep (keys %{$deps{$lib}})
0190   {
0191     if(exists $data->{prod}{$dep}){$packs{$data->{prod}{$dep}{pack}}{$dep}=1;}
0192   }
0193 }
0194 
0195 print "\n##################################\nALL DEPS\n";
0196 foreach my $pk (sort keys %packs)
0197 {
0198   my $direct="";
0199   foreach my $x (keys %{$packs{$pk}})
0200   {if(exists  $deps{direct}{$x}){$direct="*"; last;}}
0201   print "${direct}${pk}:\n";
0202   foreach my $p (sort keys %{$packs{$pk}}){print "    $p\n";}
0203   print "\n";
0204 }
0205 
0206 sub usage_msg()
0207 {
0208   my $s=basename($0);
0209   print "Usage: \n$s --release <path> --tool <tool>|--product <product>|--dependnecy <library>\n",
0210         "            [--recursive] [--cppfilt] [--clean] [--detail] [--help]\n\n",
0211         " Script can find out actual binary dependency of a cmssw products\n",
0212     " (lib/exe/plugin) OR it can be used to find out which cmssw packages/products\n",
0213     " are dependening on an external tool or cmssw product e.g.\n",
0214     " * To find out the actual binary dependency of sub-system/package/individual\n";
0215     "   products(lib/exe/plugin)\n",
0216     "    $s --rel <path> --dependnecy FWCore\n",
0217     "    $s --rel <path> --dependnecy FWCore/Framework\n",
0218     "    $s --rel <path> --dependnecy pluginFWCorePrescaleServicePlugin.so\n",
0219     "    $s --rel <path> --dependnecy libFWCoreFramework.so\n\n",
0220     " * To find out which product(s) of CMSSW actually need a tool/product\n",
0221     "    $s --rel <path> --tool oracle --tool oracleocci --tool oracle\n",
0222     "    $s --rel <path> --tool xdaq --full\n",
0223     "    $s --rel <path> --product libFWCoreFramework.so [--recursive]\n",
0224     "   when --recursive option is specified then it will show all the products which\n",
0225     "   directly/in-directly depending on this tool/product\n";
0226   exit 0;
0227 }
0228 
0229 ##############################################################################
0230 
0231 sub findDefinedSyms()
0232 {
0233   my ($c,$type,$syms)=@_;
0234   foreach my $x (keys %$c)
0235   {
0236     foreach my $t (keys %{$c->{$x}})
0237     {
0238       my $fil="lib*.$t";
0239       if ($x eq "SELF"){$fil="$t.cmssw";}
0240       foreach my $f (`find ${symboldir}/${x} -name '$fil' -type f`)
0241       {
0242         chomp $f;
0243     &accSymbolsFromFile($f,$syms,$type);
0244       }
0245     }
0246   }
0247   foreach my $s (keys %$syms){if (&isSystemSymbol($s)==1){delete $syms->{$s};}}
0248 }
0249 
0250 sub accSymbolsFromFile()
0251 {
0252   my ($file,$syms,$type,$system)=@_;
0253   print "Reading File: $file\n";
0254   my $s=&SCRAMGenUtils::readHashCache($file);
0255   foreach my $x (keys %$s)
0256   {
0257     foreach my $l (keys %{$s->{$x}})
0258     {
0259       foreach my $ty (keys %{$s->{$x}{$l}})
0260       {
0261         if ($ty=~/^$type$/){foreach my $s (keys %{$s->{$x}{$l}{$ty}}){$syms->{$s}=1;}}
0262       }
0263     }
0264   }
0265   if (defined $system){foreach my $s (keys %$syms){if (&isSystemSymbol($s)==1){delete $syms->{$s};}}}
0266 }
0267 
0268 sub detailDepInfo()
0269 {
0270   my $prod=shift;
0271   my $cache=shift;
0272   print "DEPS:$prod\n";
0273   foreach my $x (sort keys %{$cache->{$prod}})
0274   {
0275     print "  $x\n";
0276     foreach my $s (sort keys %{$cache->{$prod}{$x}})
0277     {
0278       if ($cppfilt){$s=&SCRAMGenUtils::cppFilt($s);}
0279       print "    $s\n";
0280     }
0281   }
0282   print "\n";
0283 }
0284 
0285 sub processSelfDependency()
0286 {
0287   my $prod=shift;
0288   my $cache=shift;
0289   foreach my $d (keys %{$cache->{$prod}})
0290   {
0291     if (exists $cache->{$d}){next;}
0292     $cache->{$d}={};
0293     if ($d!~/^lib.+\.so$/){next;}
0294     my $c="${symboldir}/SELF/${d}.cmssw";
0295     if (!-f $c){print STDERR "ERROR: Missing symbol cache file: $c\n";}
0296     else
0297     {
0298       my $syms={};
0299       &accSymbolsFromFile($c,$syms,$symDefine,1);
0300       $cache->{$d}=&findSymbolDependency($syms);
0301       if ($detail){&detailDepInfo($d,$cache);}
0302       &processSelfDependency($d,$cache);
0303     }
0304   }
0305 }
0306 
0307 sub findSymbolDependency()
0308 {
0309   my ($syms)=@_;
0310   my $d={};
0311   foreach my $sym (keys %$syms)
0312   {
0313     if (exists $data->{SELF_SYMBOLS_UNDEF}{$sym})
0314     {
0315       foreach my $l (keys %{$data->{SELF_SYMBOLS_UNDEF}{$sym}{cmssw}}){$d->{$l}{$sym}=1;}
0316     }
0317   }
0318   return $d;
0319 }
0320 
0321 sub getLibMap()
0322 {
0323   my $cache=shift;
0324   my $map={};
0325   foreach my $dir (keys %{$cache->{BUILDTREE}})
0326   {
0327     my $c=$cache->{BUILDTREE}{$dir};
0328     my $suffix=$c->{SUFFIX};
0329     if($suffix ne ""){next;}
0330     my $class=$c->{CLASS};
0331     my $name=$c->{NAME};
0332     if($class=~/^(LIBRARY|CLASSLIB|SEAL_PLATFORM)$/){$map->{$c->{PARENT}}=$c->{NAME};}
0333   }
0334   return $map;
0335 }
0336 
0337 sub addToolDep ()
0338 {
0339   my ($tools,$symdir,$t)=@_;
0340   if (!defined $t)
0341   {
0342     foreach $t (&SCRAMGenUtils::getOrderedTools($tools)){&addToolDep($tools,$symdir,$t);}
0343     return;
0344   }
0345   if (exists $tools->{TOOLSDONE}{$t}{deps}){return;}
0346   $tools->{TOOLSDONE}{$t}{deps}={};
0347   my $c=$tools->{TOOLSDONE}{$t}{deps};
0348   if ($t ne "self")
0349   {
0350     if ($tools->{SETUP}{$t}{SCRAM_PROJECT} == 1)
0351     {
0352       my $bv=uc($t)."_BASE";
0353       my $sbase=$tools->{SETUP}{$t}{$bv};
0354       my $spfile="${sbase}/.SCRAM/${scramarch}/ProjectCache.db.gz";
0355       if (-f $spfile)
0356       {
0357         my $libmap=&getLibMap(&SCRAMGenUtils::readCache($spfile));
0358         &SCRAMGenUtils::scramToolSymbolCache($tools,$t,"${symboldir}/${symdir}",$xjobs,$libmap);
0359     foreach my $p (keys %$libmap)
0360     {
0361       my $l=$libmap->{$p};
0362       $data->{PRODUCT_MAP}{"lib${l}.so"}=$p;
0363       $data->{TOOL_TYPE}{"lib${l}.so"}="TOOLS";
0364     }
0365       }
0366       next;
0367     }
0368     elsif ($t eq "cxxcompiler")
0369     {
0370       my $sbase=$tools->{SETUP}{$t}{GCC_BASE};
0371       if (-d "${sbase}/lib")
0372       {
0373         foreach my $l ("stdc++","gcc_s","gfortran","ssp")
0374     {
0375       my $lib="${sbase}/lib/lib${l}.so";
0376           if(-f $lib)
0377       {
0378         $data->{PRODUCT_MAP}{"lib${l}.so"}="system";
0379         &SCRAMGenUtils::symbolCacheFork($lib,"cxxcompiler","${symboldir}/SYSTEM",$xjobs);
0380       }
0381       else{print STDERR "No such file: $lib\n";}
0382     }
0383       }
0384       foreach my $l ("m","util","rt")
0385       {
0386     my $f=0;
0387     foreach my $d ("/lib","/usr/lib")
0388         {
0389       my $lib="${d}/lib${l}.so";
0390           if(-f $lib)
0391       {
0392         &SCRAMGenUtils::symbolCacheFork($lib,"system","${symboldir}/SYSTEM",$xjobs);
0393         $data->{PRODUCT_MAP}{"lib${l}.so"}="system";
0394         $f=1;
0395         last;
0396       }
0397     }
0398     if (!$f){print STDERR "No such file: lib$l.so\n";}
0399       }
0400       foreach my $lib ("/lib/libpthread.so.0","/lib/libc.so.6")
0401       {
0402     if(-f $lib)
0403     {
0404       &SCRAMGenUtils::symbolCacheFork($lib,"system","${symboldir}/SYSTEM",$xjobs);
0405       my $l=basename($lib);
0406       $data->{PRODUCT_MAP}{"lib${l}.so"}="system";
0407     }
0408     else{print STDERR "No such file: $lib\n";}
0409       }
0410     }
0411     else
0412     {
0413       &SCRAMGenUtils::toolSymbolCache($tools,$t,"${symboldir}/TOOLS",$xjobs);
0414       if (exists $tools->{SETUP}{$t}{LIB})
0415       {
0416         foreach my $l (@{$tools->{SETUP}{$t}{LIB}})
0417     {
0418       $data->{PRODUCT_MAP}{"lib${l}.so"}=$t;
0419       $data->{TOOL_TYPE}{"lib${l}.so"}="TOOLS";
0420     }
0421       }
0422     }
0423     if (!exists $tools->{SETUP}{$t}{USE}){return;}
0424     foreach my $u (@{$tools->{SETUP}{$t}{USE}})
0425     {
0426       $u=lc($u);
0427       if(exists $tools->{SETUP}{$u})
0428       {
0429         &addToolDep($tools,$u);
0430         $c->{$u}=1;
0431         foreach my $k (keys %{$tools->{TOOLSDONE}{$t}{deps}}){$c->{$k}=1;}
0432       }
0433     }
0434   }
0435 }
0436 
0437 sub isSystemSymbol()
0438 {
0439   my $sym=shift;
0440   if (exists $data->{SYSTEM_SYMBOLS_DEF}{$sym}){return 1;}
0441   foreach my $r (keys %systemsym){if($sym=~/^$r$/){return 1;}}
0442   return 0;
0443 }
0444 
0445 ##############################################################
0446 # Library Dependecy
0447 ##############################################################
0448 sub readSyms()
0449 {
0450   my ($lib,$type)=@_;
0451   my $sfile="${symboldir}/${type}";
0452   my $tool="cmssw";
0453   if (($type ne "SELF") && (exists $data->{PRODUCT_MAP}{$lib})){$tool=$data->{PRODUCT_MAP}{$lib};}
0454   my $sfile="${symboldir}/${type}/${lib}.${tool}";
0455   if (-f $sfile)
0456   {
0457     my $c=&SCRAMGenUtils::readHashCache($sfile);
0458     if (exists $c->{$tool}{$lib}){return $c->{$tool}{$lib};}
0459   }
0460   print STDERR "ERROR: Symbols not found for library: $lib\n";
0461   return {};
0462 }
0463 
0464 sub sym2Lib()
0465 {
0466   my $lib=shift;
0467   my $graph=shift;
0468   my $cache=shift || {};
0469   my $tab=shift || "";
0470   my $parent=shift || "";
0471   my $depth=1+(length($tab)/2);
0472   if (exists $cache->{$lib}){return;}
0473   $cache->{$lib}=1;
0474   my $ltype="SELF";
0475   if (exists $data->{TOOL_TYPE}{$lib}){$ltype=$data->{TOOL_TYPE}{$lib};}
0476   my %syms=();
0477   my $deps={};
0478   if (!exists $data->{LIBDEPS}{$lib})
0479   {
0480     my $xsyms=&readSyms($lib,$ltype);
0481     foreach my $sym (keys %{$xsyms->{U}})
0482     {
0483       if (&isSystemSymbol($sym)==1){next;}
0484       $syms{$sym}=1;
0485     }
0486     foreach my $sym (keys %syms)
0487     {
0488       my $c=undef;
0489       if ($ltype eq "SELF")
0490       {
0491         if (exists $data->{SELF_SYMBOLS_DEF}{$sym}){$c=$data->{SELF_SYMBOLS_DEF}{$sym};}
0492         elsif(exists $data->{TOOLS_SYMBOLS_DEF}{$sym}){$c=$data->{TOOLS_SYMBOLS_DEF}{$sym};}
0493       }
0494       elsif(exists $data->{TOOLS_SYMBOLS_DEF}{$sym}){$c=$data->{TOOLS_SYMBOLS_DEF}{$sym};}
0495       if (defined $c)
0496       {
0497         foreach my $t (keys %{$c})
0498         {
0499           foreach my $l (keys %{$c->{$t}})
0500       {
0501         my $p=$l;
0502         if (exists $data->{PRODUCT_MAP}{$l}){$p=$data->{PRODUCT_MAP}{$l};}
0503         if (!exists $deps->{$p}){$deps->{$p}{c}=0;}
0504         $deps->{$p}{c}+=1;
0505         $deps->{$p}{l}{$l}=1;
0506       }
0507         }
0508       }
0509       elsif ($ltype eq "SELF"){$data->{UNKNOWN_SYM}{$sym}=1;}
0510     }
0511     $data->{LIBDEPS}{$lib}=$deps;
0512     if ($full)
0513     {
0514       foreach my $p (sort keys %$deps)
0515       {
0516         foreach my $l (keys %{$deps->{$p}{l}}){if (!exists $data->{LIBDEPS}{$l}){&sym2Lib($l,$graph);}}
0517       }
0518     }
0519   }
0520   else{$deps=$data->{LIBDEPS}{$lib};}
0521   my $mp=$lib;
0522   if ($depth>1){$mp=$data->{PRODUCT_MAP}{$lib};}
0523   if (($detail) && ($depth==1)){print "#######################################\n$lib:\n";}
0524   if ($depth<10){$depth="0$depth";}
0525   foreach my $p (sort keys %$deps)
0526   {
0527     if ($graph){$cache->{GRAPH}{DEPS}{$mp}{$p}=1;}
0528     if ($p eq "system"){next;}
0529     if (($detail) && ($p ne $parent))
0530     {
0531       my $ls=join(",",sort keys %{$deps->{$p}{l}});
0532       print "$depth.${tab}  $p (",$deps->{$p}{c},": $ls)\n";
0533     }
0534     foreach my $l (keys %{$deps->{$p}{l}}){&sym2Lib($l,$graph,$cache,"$tab  ",$p);}
0535   }
0536   if ($depth==1)
0537   {
0538     if (!$detail){print "\n###########################\n$lib:\n";}
0539     my %p=();
0540     my $pk="";
0541     foreach my $l (keys %$cache)
0542     {
0543       if (exists $data->{PRODUCT_MAP}{$l})
0544       {
0545         $pk=$data->{PRODUCT_MAP}{$l};
0546     if ($pk ne "system"){$p{$pk}=1;}
0547       }
0548     }
0549     if (exists $data->{PRODUCT_MAP}{$lib}){delete $p{$data->{PRODUCT_MAP}{$lib}};}
0550     my @ds=sort keys %p;
0551     if ($graph)
0552     {
0553       $cache->{GRAPH}{NODES}{$lib}=1;
0554       foreach my $x (@ds){$cache->{GRAPH}{NODES}{$x}=1;}
0555       &generateGraph($lib,$cache->{GRAPH});
0556     }
0557     print " * Direct dependencies:\n";
0558     foreach my $x (@ds){if (exists $deps->{$x}){print "  $x\n";}}
0559     print " * Indirect dependencies:\n";
0560     foreach my $x (@ds){if (!exists $deps->{$x}){print "  $x\n";}}
0561   }
0562 }
0563 
0564 sub generateGraph()
0565 {
0566   my $l=shift;
0567   my $data=shift;
0568   my $ref;
0569   if (open($ref,">${cachedir}/Dot/${l}.dot"))
0570   {
0571     print $ref "digraph Dependencies {\n",
0572                '  fontname="Helvetica"; fontsize=12; center=true; ratio=auto;concentrate=true;',"\n",
0573                '  label="\n',$l,'\n"',"\n",
0574                '  node [shape=ellipse, fontname="Helvetica-Bold", fontsize=12, style=filled, color="0.9 1.0 1.0", fontcolor="0 0 1" ]',"\n",
0575                '  edge [fontname="Helvetica", fontsize=12 ]',"\n\n";
0576     foreach my $n (keys %{$data->{NODES}}){print $ref "  \"$n\" []\n";}
0577     foreach my $n (keys %{$data->{DEPS}})
0578     {
0579       foreach my $d (keys %{$data->{DEPS}{$n}}) {print $ref "  \"$n\" -> \"$d\" []\n";}
0580     }
0581     print $ref "}\n";
0582     close($ref);
0583   }
0584   else{print STDERR "ERROR: Can not open file for writing: ${l}.dot\n";}
0585 }
0586 
0587 sub doDependency()
0588 {
0589   my $dependency=shift;
0590   my @prods=();
0591   if (exists $data->{prod}{$dependency}){$prods[0]=$dependency;}
0592   else
0593   {
0594     foreach my $pk (sort keys %{$data->{pack}})
0595     {
0596       if ($pk=~/^$dependency(\/.+|)$/o){foreach my $p (keys %{$data->{pack}{$pk}}){push @prods,$p;}}
0597     }
0598   }
0599   foreach my $lib (@prods){&sym2Lib($lib,$graph);}
0600   if ($detail && (exists $data->{UNKNOWN_SYM}))
0601   {
0602     print "SYMBOLS UNKNOWN:\n";
0603     foreach my $s (sort keys %{$data->{UNKNOWN_SYM}})
0604     {
0605       if ($cppfilt){$s=&SCRAMGenUtils::cppFilt($s);}
0606       print "$s\n";
0607     }
0608   }
0609 }