Add libwx-perl
[pkg-perl] / deb-src / libwx-perl / libwx-perl-0.96 / build / Wx / build / Utils.pm
1 package Wx::build::Utils;
2
3 use strict;
4 use Config;
5 use base 'Exporter';
6 use File::Spec::Functions qw(curdir catdir catfile updir);
7 use File::Find qw(find);
8 use File::Path qw(mkpath);
9 use File::Basename qw(dirname);
10 use Carp;
11
12 use vars qw(@EXPORT @EXPORT_OK);
13 @EXPORT_OK = qw(obj_from_src xs_dependencies write_string
14                 lib_file arch_file arch_auto_file
15                 path_search files_with_overload files_with_constants
16                 pipe_stderr read_file write_file);
17
18 =head1 NAME
19
20 Wx::build::Utils - utility routines
21
22 =head1 SUBROUTINES
23
24 =head2 xs_dependencies
25
26   my %dependencies = xs_dependencies( $mm_object, [ 'dir1', 'dir2' ] );
27
28 =cut
29
30 sub _uniq {
31     my( %x );
32     $x{$_} = 1 foreach @_;
33     return sort keys %x;
34 }
35
36 sub xs_dependencies {
37   my( $this, $dirs, $top_dir ) = @_;
38
39   my( %depend );
40   my( $c, $o, $cinclude, $xsinclude );
41
42   foreach ( keys %{ $this->{XS} } ) {
43     ( $cinclude, $xsinclude ) = scan_xs( $_, $dirs, $top_dir );
44
45     $c = $this->{XS}{$_};
46     $o = obj_from_src( $c );
47
48     $depend{$c} = $_ . ' ' . join( ' ', _uniq( @$xsinclude ) );
49     $depend{$o} = $c . ' ' . join( ' ', _uniq( @$cinclude ) );
50   }
51
52   return %depend;
53 }
54
55 =head2 obj_from_src
56
57   my @obj_files = obj_from_src( 'Foo.xs', 'bar.c', 'cpp/bar.cpp' );
58
59 Calculates the object file name from the source file name.
60 In scalar context returns the first file.
61
62 =cut
63
64 sub obj_from_src {
65   my @xs = @_;
66   my $obj_ext = $Config{obj_ext} || $Config{_o};
67
68   foreach ( @xs ) { s[\.(?:xs|c|cc|cpp)$][$obj_ext] }
69
70   return wantarray ? @xs : $xs[0];
71 }
72
73 sub src_dir {
74   my( $file ) = @_;
75   my $d = curdir;
76
77   for ( 1 .. 5 ) {
78     return $d if -f catfile( $d, $file );
79     $d = catdir( updir, $d );
80   }
81
82   confess "Unable to find top level directory ($file)";
83 }
84
85 #
86 # quick and dirty method for creating dependencies:
87 # considers files included via #include "..." or INCLUDE: ...
88 # (not #include <...>) and does not take into account preprocessor directives
89 #
90 sub scan_xs($$$);
91
92 sub scan_xs($$$) {
93   my( $xs, $incpath, $top_dir ) = @_;
94
95   local( *IN, $_ );
96   my( @cinclude, @xsinclude );
97
98   open IN, $xs;
99
100   my $file;
101   my $arr;
102
103   while( defined( $_ = <IN> ) ) {
104     undef $file;
105
106     m/^\#\s*include\s+"([^"]*)"\s*$/ and $file = $1 and $arr = \@cinclude;
107     m/^\s*INCLUDE:\s+(.*)$/ and $file = $1 and $arr = \@xsinclude;
108     m/^\s*INCLUDE:\s+.*\s(\S+\.xsp?)\s*\|/ and $file = $1 and
109       $arr = \@xsinclude;
110
111     if( defined $file ) {
112       $file = catfile( split '/', $file );
113
114       foreach my $dir ( @$incpath ) {
115         my $f = $dir eq curdir() ? $file : catfile( $dir, $file );
116         if( -f $f ) {
117           push @$arr, $f;
118           my( $cinclude, $xsinclude ) = scan_xs( $f, $incpath, $top_dir );
119           push @cinclude, @$cinclude;
120           push @xsinclude, @$xsinclude;
121           last;
122         } elsif(    $file =~ m/ovl_const\.(?:cpp|h)/i
123                  || $file =~ m/v_cback_def\.h/i
124                  || $file =~ m/ItemContainer(?:Immutable)?\.xs/i
125                  || $file =~ m/Var[VH]{0,2}ScrollHelper(?:Base)?\.xs/i ) {
126           push @$arr, ( ( $top_dir eq curdir() ) ?
127                         $file :
128                         catfile( $top_dir, $file ) );
129         }
130       }
131     }
132   }
133
134   close IN;
135
136   ( \@cinclude, \@xsinclude );
137 }
138
139 =head2 write_string, write_file
140
141   write_string( 'file', $scalar );
142   write_file( 'file', $scalar );
143
144 Like File::Slurp.
145
146 =head2 read_file
147
148   my $string = read_file( 'file' );
149
150 =cut
151
152 *write_string = \&write_file;
153
154 sub write_file {
155   my( $file, $string ) = @_;
156
157   mkpath( dirname( $file ) ) if dirname( $file );
158   open my $fh, ">", $file or die "open '$file': $!";
159   binmode $fh;
160   print $fh $string or die "print '$file': $!";
161   close $fh or die "close '$file': $!";
162 }
163
164 sub read_file {
165   my( $file ) = @_;
166
167   local $/ = wantarray ? $/ : undef;;
168   open my $fh, "<", $file or die "open '$file': $!";
169   binmode $fh;
170
171   return <$fh>;
172 }
173
174 =head2 lib_file, arch_file, arch_auto_file
175
176   my $file = lib_file( 'Foo.pm' );          # blib/lib/Foo.pm     on *nix
177   my $file = lib_file( 'Foo/Bar.pm' );      # blib\lib\Foo\Bar.pm on Win32
178   my $file = arch_auto_file( 'My\My.dll' ); # blib\arch\auto\My\My.dll
179
180 All input paths must be relative, output paths may be absolute.
181
182 =cut
183
184 sub _split {
185   require File::Spec::Unix;
186
187   my $path = shift;
188   my( $volume, $dir, $file ) = File::Spec::Unix->splitpath( $path );
189   my @dirs = File::Spec::Unix->splitdir( $dir );
190
191   return ( @dirs, $file );
192 }
193
194 sub lib_file {
195   my @split = _split( shift );
196
197   return File::Spec->catfile( 'blib', 'lib', @split );
198 }
199
200 sub arch_file {
201   my @split = _split( shift );
202
203   return File::Spec->catfile( 'blib', 'arch', @split );
204 }
205
206 sub arch_auto_file {
207   my @split = _split( shift );
208
209   return File::Spec->catfile( 'blib', 'arch', 'auto', @split );
210 }
211
212 =head2 path_search
213
214   my $file = path_search( 'foo.exe' );
215
216 Searches PATH for the given executable.
217
218 =cut
219
220 sub path_search {
221   my $file = shift;
222
223   foreach my $d ( File::Spec->path ) {
224     my $full = File::Spec->catfile( $d, $file );
225     return $full if -f $full;
226   }
227
228   return;
229 }
230
231 =head2 files_with_constants
232
233   my @files = files_with_constants;
234
235 Finds files containing constants
236
237 =cut
238
239 sub files_with_constants {
240   my @files;
241
242   my $wanted = sub {
243     my $name = $File::Find::name;
244
245     m/\.(?:pm|xsp?|cpp|h)$/i && do {
246       local *IN;
247       my $line;
248
249       open IN, "< $_" || warn "unable to open '$_'";
250       while( defined( $line = <IN> ) ) {
251         $line =~ m/^\W+\!\w+:/ && do {
252           push @files, $name;
253           return;
254         };
255       };
256     };
257   };
258
259   find( $wanted, curdir );
260
261   return @files;
262 }
263
264 =head2 files_with_overload
265
266   my @files = files_with_overload;
267
268 Finds files containing overloaded XS/Perl subroutines
269
270 =cut
271
272 sub files_with_overload {
273   my @files;
274
275   my $wanted = sub {
276     my $name = $File::Find::name;
277
278     m/\.pm$/i && do {
279       my $line;
280       local *IN;
281
282       open IN, "< $_" || warn "unable to open '$_'";
283       while( defined( $line = <IN> ) ) {
284         $line =~ m/Wx::_match/ && do {
285           push @files, $name;
286           return;
287         };
288       }
289     };
290
291     m/\.xsp?$/i && do {
292       my $line;
293       local *IN;
294
295       open IN, "< $_" || warn "unable to open '$_'";
296       while( defined( $line = <IN> ) ) {
297         $line =~ m/wxPli_match_arguments|BEGIN_OVERLOAD\(\)/ && do {
298           push @files, $name;
299           return;
300         };
301       }
302     };
303   };
304
305   find( $wanted, curdir );
306
307   return @files;
308 }
309
310 sub pipe_stderr {
311   my( $cmd ) = @_;
312   my $pipe = File::Spec->catfile( 'script', 'pipe.pl' );
313
314   if( -f $pipe ) {
315     return qx{$^X $pipe $cmd};
316   } else {
317     # fix quoting later if necessary
318     return qx[$^X -e "open STDERR, q{>&STDOUT}; exec q{$cmd}"];
319   }
320 }
321
322 1;
323
324 # local variables:
325 # mode: cperl
326 # end: