slim-pkg-config 7.6 KB

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