slim-pkg-config 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use Getopt::Long;
  4. my $persistence_support;
  5. eval ( "use Tie::Persistent;" );
  6. if ( !defined($@) || (length($@) == 0) ) {
  7. $persistence_support = 1;
  8. } else {
  9. $persistence_support = 0;
  10. }
  11. my $defaultsearchpaths = "/usr/lib/pkgconfig:/usr/lib64/pkgconfig";
  12. ####### search_pc_files () // code date : 21.07.09 ######
  13. sub search_pc_files
  14. {
  15. my $search_paths = $ENV{'PKG_CONFIG_PATH'};
  16. if (!defined($search_paths)) {
  17. $search_paths = $defaultsearchpaths;
  18. }
  19. $search_paths .= ":.";
  20. my @paths = split /:+/, $search_paths;
  21. my $pc_locations;
  22. for my $path ( @paths )
  23. {
  24. my @pcfiles = glob ("$path/*.pc");
  25. for my $pcfile (@pcfiles)
  26. {
  27. chomp $pcfile;
  28. my ($pcname) = ($pcfile =~ /([^\/]+)\.pc$/);
  29. if ( !defined($pcname) ) {
  30. die ("unable to parse filename: $pcfile\n");
  31. }
  32. # print "$pcname -> $pcfile\n";
  33. $pc_locations->{$pcname} = "$pcfile";
  34. }
  35. }
  36. return $pc_locations;
  37. }
  38. ####### parse_pc_file () // code date : 21.07.09 ######
  39. sub parse_pc_file
  40. {
  41. my $pc_file = shift @_;
  42. my $data;
  43. my %vars;
  44. open ( FILE, "<$pc_file" ) or die ("$pc_file: $!\n");
  45. while (<FILE>)
  46. {
  47. chomp;
  48. # TODO: If a line contains "Cflags:-DVARIABLE=1 -I...", then this line is erroneously interpreted as a variable definition.
  49. # Hopefully for the grammar designers of pkg-config files, this case was forbidden, requiring a whitespace after each ":" and "="
  50. if ( /^(\S+?) *= *(.+?)$/ ) {
  51. my $key = $1;
  52. my $value = $2;
  53. for my $var ( keys %vars )
  54. {
  55. $value =~ s/\$\{$var\}/$vars{$var}/g;
  56. }
  57. $vars{$key} = $value;
  58. } elsif ( /^(\S+?) *: *(.+?)$/ ) {
  59. my $key = $1;
  60. my $value = $2;
  61. for my $var ( keys %vars )
  62. {
  63. $value =~ s/\$\{$var\}/$vars{$var}/g;
  64. }
  65. $data->{$key} = $value;
  66. }
  67. }
  68. close (FILE);
  69. return $data;
  70. }
  71. ####### print_pc_file () // code date : 21.07.09 ######
  72. sub print_pc_file
  73. {
  74. my $data = shift;
  75. for my $key ( keys %{$data} ) {
  76. my $value = $data->{$key};
  77. print "$key = $value\n";
  78. }
  79. }
  80. ####### get_pc_data () // code date : 21.07.09 ######
  81. sub get_pc_data
  82. {
  83. my $pkg = shift @_;
  84. my $file;
  85. if ( $pkg =~ /\.pc$/ ) {
  86. $file = $pkg;
  87. } else {
  88. my $pc_locations = shift @_;
  89. $file = $pc_locations->{$pkg};
  90. }
  91. if ( !defined($file) || !-f $file ) {
  92. print <<PKGNOTFOUND;
  93. Package $pkg was not found in the pkg-config search path.
  94. Perhaps you should add the directory containing \`$pkg.pc\'
  95. to the PKG_CONFIG_PATH environment variable
  96. No package '$pkg' found
  97. PKGNOTFOUND
  98. return undef;
  99. }
  100. my $data = parse_pc_file ($file);
  101. return $data;
  102. }
  103. ####### build_dependency_graph () // code date : 21.07.09 ######
  104. sub build_dependency_graph
  105. {
  106. my $pkg = shift @_;
  107. my $deptree = shift @_;
  108. my $pc_locations = shift @_;
  109. if ( exists $deptree->{$pkg} ) {
  110. # already included in dependency graph
  111. } else {
  112. my $data = get_pc_data ( $pkg, $pc_locations );
  113. $deptree->{$pkg}->{'data'} = $data;
  114. my $children = undef;
  115. if ( exists $data->{'Requires'} ) {
  116. my @pkg_childs = split /[\s\,]+/, $data->{'Requires'};
  117. for my $pkg_child ( @pkg_childs )
  118. {
  119. my $childnode = build_dependency_graph ( $pkg_child, $deptree, $pc_locations );
  120. push @{ $children }, $pkg_child;
  121. }
  122. }
  123. $deptree->{$pkg}->{'children'} = $children;
  124. $deptree->{$pkg}->{'childrencount'} = defined($children) ? scalar @{$children} : 0;
  125. }
  126. return $deptree->{$pkg};
  127. }
  128. ####### get_all_packages () // code date : 21.07.09 ######
  129. sub get_all_packages
  130. {
  131. my $pkg = shift @_;
  132. my $deptree = shift @_;
  133. my $pkglist = shift @_;
  134. my $pkghash = shift @_;
  135. if ( !exists( $deptree->{$pkg} ) ) {
  136. die ( "$pkg not found in the dependency graph\n" );
  137. }
  138. push @{$pkglist}, $pkg;
  139. $pkghash->{$pkg} = 1;
  140. my $children = $deptree->{$pkg}->{'children'};
  141. my $count = $deptree->{$pkg}->{'childrencount'};
  142. # print "pkg $pkg ($count)\n";
  143. if ( defined($children) ) {
  144. for my $child ( @{ $children } )
  145. {
  146. # if ( !exists $pkghash->{$child} ) {
  147. ($pkglist, $pkghash) = get_all_packages ( $child, $deptree, $pkglist, $pkghash );
  148. # }
  149. }
  150. }
  151. return ($pkglist, $pkghash);
  152. }
  153. ####### uniquify () // code date : 21.07.09 ######
  154. sub uniquify
  155. {
  156. my $pkg_list = shift @_;
  157. my @new_list;
  158. my %hash;
  159. for (my $i = scalar(@{$pkg_list})-1 ; $i >= 0 ; $i-- )
  160. {
  161. my $val = $pkg_list->[$i];
  162. next if ( exists $hash{$val} );
  163. $hash{$val} = 1;
  164. unshift @new_list, $val;
  165. }
  166. return @new_list;
  167. }
  168. ####### print_options () // code date : 21.07.09 ######
  169. sub print_options
  170. {
  171. my $root_packages = shift @_;
  172. my $deptree = shift @_;
  173. my $new_pkg_list = shift @_;
  174. my $options = shift @_;
  175. my $parameters = ""; # all parameters in a string :)
  176. my @plist_duplicates;
  177. for my $opt ( keys %{$options} )
  178. {
  179. next if ( $options->{$opt} != 1 );
  180. for my $deppkg ( @{$new_pkg_list} )
  181. {
  182. if($deptree->{$deppkg}->{'data'}->{$opt})
  183. {
  184. my @para = split /\s+/, $deptree->{$deppkg}->{'data'}->{$opt};
  185. push @plist_duplicates, @para;
  186. }
  187. }
  188. }
  189. my @plist = uniquify ( \@plist_duplicates );
  190. return join (' ', @plist);
  191. }
  192. ######################## handle conflicting libs
  193. ####### handle_known_permutation_difficulties () // code date : 27.01.10 ######
  194. sub handle_known_permutation_difficulties
  195. {
  196. my $options = shift @_;
  197. # WORKAROUND 1: CUDA and pthread
  198. if ( $options =~ /-lpthread.+?-lcuda/ )
  199. {
  200. $options =~ s/-lpthread//g;
  201. $options = $options . " " . "-lpthread";
  202. }
  203. return $options;
  204. }
  205. ################################### MAIN
  206. my $print_cflags = 0;
  207. my $print_libs = 0;
  208. my $print_modversion = 0;
  209. my $eval_exists = 0;
  210. my $print_version = 0;
  211. my $print_all_packages = 0;
  212. my ( $cache, $use_cache, $rebuild_cache ) = ( "", 0, 0);
  213. my $result = GetOptions ("libs" => \$print_libs,
  214. "cflags" => \$print_cflags,
  215. "cppflags" => \$print_cflags,
  216. "cxxflags" => \$print_cflags,
  217. "list-all" => \$print_all_packages,
  218. "modversion" => \$print_modversion,
  219. "exists" => \$eval_exists,
  220. "version" => \$print_version,
  221. "cache=s" => \$cache,
  222. "usecache" => \$use_cache );
  223. if ( $print_version )
  224. {
  225. print "slim-pkg-config 0.2 (c) Erik Rodner\n";
  226. exit;
  227. }
  228. my @root_packages = @ARGV;
  229. my %data;
  230. if ( !$persistence_support )
  231. {
  232. $use_cache = 0;
  233. }
  234. if ( $use_cache ) {
  235. if ( -f $cache ) {
  236. # read cache
  237. tie %data, 'Tie::Persistent', $cache, 'r';
  238. } else {
  239. $rebuild_cache = 1;
  240. tie %data, 'Tie::Persistent', $cache, 'rw';
  241. }
  242. }
  243. if ( !$use_cache || $rebuild_cache ) {
  244. $data{'locations'} = search_pc_files ();
  245. }
  246. if ( $eval_exists ) {
  247. for my $pkg ( @root_packages )
  248. {
  249. my $is_a_file = ( -f $pkg );
  250. if ( (!$is_a_file) && (! exists $data{'locations'}->{$pkg}) ) {
  251. #warn("$pkg does not exist.");
  252. exit(-1);
  253. }
  254. }
  255. exit(0);
  256. }
  257. if ( $print_all_packages )
  258. {
  259. print "Package list\n";
  260. for my $pkg ( keys %{ $data{'locations'} } )
  261. {
  262. my $pcdata = parse_pc_file($data{'locations'}->{$pkg});
  263. my $d = "";
  264. if ( exists($pcdata->{'Description'}) )
  265. {
  266. $d = $pcdata->{'Description'};
  267. }
  268. printf ("%-40s %-60s %s\n", $pkg, $d, $data{'locations'}->{$pkg});
  269. }
  270. exit(0);
  271. }
  272. # dummy to initialize memory
  273. $data{'deptree'}->{'_'} = 1;
  274. if ( !$use_cache || $rebuild_cache ) {
  275. for my $pkg ( @root_packages )
  276. {
  277. build_dependency_graph ( $pkg, $data{'deptree'}, $data{'locations'} );
  278. }
  279. }
  280. if ( $print_modversion ) {
  281. for my $pkg ( @root_packages )
  282. {
  283. print "$data{'deptree'}->{$pkg}->{'data'}->{'Version'}\n";
  284. }
  285. }
  286. if ( $print_cflags || $print_libs )
  287. {
  288. my $pkg_list;
  289. my $pkg_hash;
  290. for my $pkg ( @root_packages )
  291. {
  292. ($pkg_list, $pkg_hash) = get_all_packages ( $pkg, $data{'deptree'}, $pkg_list, $pkg_hash );
  293. }
  294. my @new_pkg_list = uniquify ( $pkg_list );
  295. my %options;
  296. $options{'Cflags'} = ($print_cflags);
  297. $options{'Libs'} = ($print_libs);
  298. my $options = print_options ( \@root_packages, $data{'deptree'}, \@new_pkg_list, \%options );
  299. if ( $print_libs )
  300. {
  301. $options = handle_known_permutation_difficulties ( $options );
  302. }
  303. print $options;
  304. print "\n";
  305. }
  306. if ( $rebuild_cache ) {
  307. # save tree
  308. (tied %data)->sync();
  309. }
  310. if ( $use_cache ) {
  311. untie %data;
  312. }