Merged patches from Curtis Jewell <csjewell@cpan.org> for win32 fixes.
[p5sagit/local-lib.git] / lib / local / lib.pm
CommitLineData
b5cc15f7 1use strict;
2use warnings;
3
4package local::lib;
5
c1441fb6 6use 5.008001; # probably works with earlier versions but I'm not supporting them
7 # (patches would, of course, be welcome)
b5cc15f7 8
9use File::Spec ();
10use File::Path ();
11use Carp ();
12use Config;
13
53699c99 14our $VERSION = '1.004002'; # 1.4.2
b5cc15f7 15
16sub import {
0fb70b9a 17 my ($class, @args) = @_;
18
e4892f2b 19 # Remember what PERL5LIB was when we started
20 my $perl5lib = $ENV{PERL5LIB};
21
0fb70b9a 22 # The path is required, but last in the list, so we pop, not shift here.
23 my $path = pop @args;
b5cc15f7 24 $path = $class->resolve_path($path);
25 $class->setup_local_lib_for($path);
0fb70b9a 26
27 # Handle the '--self-contained' option
28 my $flag = shift @args;
29 no warnings 'uninitialized'; # the flag is optional
d4dbe584 30 # make sure fancy dashes cause an error
31 if ($flag =~ /−/) {
32 die <<'DEATH';
33WHOA THERE! It looks like you've got some fancy dashes in your commandline!
34These are *not* the traditional -- dashes that software recognizes. You
35probably got these by copy-pasting from the perldoc for this module as
36rendered by a UTF8-capable formatter. This most typically happens on an OS X
37terminal, but can happen elsewhere too. Please try again after replacing the
38dashes with normal minus signs.
39DEATH
40 }
0fb70b9a 41 if ($flag eq '--self-contained') {
42 # The only directories that remain are those that we just defined and those where core modules are stored.
e4892f2b 43 # We put PERL5LIB first, so it'll be favored over privlibexp and archlibexp
53699c99 44 @INC = ($Config::Config{privlibexp}, $Config::Config{archlibexp}, split $Config{path_sep}, $ENV{PERL5LIB});
45 @INC = (
46 $class->install_base_perl_path($path),
47 $class->install_base_arch_path($path),
48 split( $Config{path_sep}, $perl5lib ),
49 $Config::Config{privlibexp},
50 $Config::Config{archlibexp}
51 );
e4892f2b 52
53 # We explicitly set PERL5LIB here (back to what it was originally) to prevent @INC from growing with each invocation
54 $ENV{PERL5LIB} = $perl5lib;
0fb70b9a 55 }
56 elsif (defined $flag) {
57 die "unrecognized import argument: $flag";
58 }
59
6e5079df 60 for (@INC) { # Untaint @INC
61 next if ref; # Skip entry if it is an ARRAY, CODE, blessed, etc.
62 m/(.*)/ and $_ = $1;
63 }
b5cc15f7 64}
65
5b94dce5 66sub pipeline;
b5cc15f7 67
5b94dce5 68sub pipeline {
b5cc15f7 69 my @methods = @_;
70 my $last = pop(@methods);
71 if (@methods) {
72 \sub {
73 my ($obj, @args) = @_;
5b94dce5 74 $obj->${pipeline @methods}(
b5cc15f7 75 $obj->$last(@args)
76 );
77 };
78 } else {
79 \sub {
80 shift->$last(@_);
81 };
82 }
83}
84
275c9dae 85=begin testing
86
87#:: test pipeline
b5cc15f7 88
89package local::lib;
90
91{ package Foo; sub foo { -$_[1] } sub bar { $_[1]+2 } sub baz { $_[1]+3 } }
92my $foo = bless({}, 'Foo');
4c375968 93Test::More::ok($foo->${pipeline qw(foo bar baz)}(10) == -15);
b5cc15f7 94
275c9dae 95=end testing
96
b5cc15f7 97=cut
98
99sub resolve_path {
100 my ($class, $path) = @_;
5b94dce5 101 $class->${pipeline qw(
b5cc15f7 102 resolve_relative_path
103 resolve_home_path
104 resolve_empty_path
105 )}($path);
106}
107
108sub resolve_empty_path {
109 my ($class, $path) = @_;
110 if (defined $path) {
111 $path;
112 } else {
113 '~/perl5';
114 }
115}
116
275c9dae 117=begin testing
118
119#:: test classmethod setup
b5cc15f7 120
121my $c = 'local::lib';
122
275c9dae 123=end testing
124
125=begin testing
b5cc15f7 126
275c9dae 127#:: test classmethod
b5cc15f7 128
129is($c->resolve_empty_path, '~/perl5');
130is($c->resolve_empty_path('foo'), 'foo');
131
275c9dae 132=end testing
133
b5cc15f7 134=cut
135
136sub resolve_home_path {
137 my ($class, $path) = @_;
138 return $path unless ($path =~ /^~/);
139 my ($user) = ($path =~ /^~([^\/]+)/); # can assume ^~ so undef for 'us'
140 my $tried_file_homedir;
141 my $homedir = do {
142 if (eval { require File::HomeDir } && $File::HomeDir::VERSION >= 0.65) {
143 $tried_file_homedir = 1;
144 if (defined $user) {
145 File::HomeDir->users_home($user);
146 } else {
dc8ddd06 147 File::HomeDir->my_home;
b5cc15f7 148 }
149 } else {
150 if (defined $user) {
151 (getpwnam $user)[7];
152 } else {
153 if (defined $ENV{HOME}) {
154 $ENV{HOME};
155 } else {
156 (getpwuid $<)[7];
157 }
158 }
159 }
160 };
161 unless (defined $homedir) {
162 Carp::croak(
163 "Couldn't resolve homedir for "
164 .(defined $user ? $user : 'current user')
165 .($tried_file_homedir ? '' : ' - consider installing File::HomeDir')
166 );
167 }
168 $path =~ s/^~[^\/]*/$homedir/;
169 $path;
170}
171
172sub resolve_relative_path {
173 my ($class, $path) = @_;
53699c99 174 $path = File::Spec->rel2abs($path);
b5cc15f7 175}
176
275c9dae 177=begin testing
178
179#:: test classmethod
b5cc15f7 180
181local *File::Spec::rel2abs = sub { shift; 'FOO'.shift; };
182is($c->resolve_relative_path('bar'),'FOObar');
183
275c9dae 184=end testing
185
b5cc15f7 186=cut
187
188sub setup_local_lib_for {
189 my ($class, $path) = @_;
53699c99 190 $path = $class->ensure_dir_structure_for($path);
b5cc15f7 191 if ($0 eq '-') {
192 $class->print_environment_vars_for($path);
193 exit 0;
194 } else {
195 $class->setup_env_hash_for($path);
53699c99 196 unshift(@INC, split($Config{path_sep}, $ENV{PERL5LIB}));
b5cc15f7 197 }
198}
199
200sub modulebuildrc_path {
201 my ($class, $path) = @_;
202 File::Spec->catfile($path, '.modulebuildrc');
203}
204
205sub install_base_bin_path {
206 my ($class, $path) = @_;
207 File::Spec->catdir($path, 'bin');
208}
209
210sub install_base_perl_path {
211 my ($class, $path) = @_;
212 File::Spec->catdir($path, 'lib', 'perl5');
213}
214
215sub install_base_arch_path {
216 my ($class, $path) = @_;
217 File::Spec->catdir($class->install_base_perl_path($path), $Config{archname});
218}
219
220sub ensure_dir_structure_for {
221 my ($class, $path) = @_;
222 unless (-d $path) {
223 warn "Attempting to create directory ${path}\n";
224 }
225 File::Path::mkpath($path);
53699c99 226 # Need to have the path exist to make a short name for it, so
227 # converting to a short name here.
228 $path = Win32::GetShortPathName($path) if $^O eq 'MSWin32';
b5cc15f7 229 my $modulebuildrc_path = $class->modulebuildrc_path($path);
230 if (-e $modulebuildrc_path) {
231 unless (-f _) {
232 Carp::croak("${modulebuildrc_path} exists but is not a plain file");
233 }
234 } else {
235 warn "Attempting to create file ${modulebuildrc_path}\n";
236 open MODULEBUILDRC, '>', $modulebuildrc_path
237 || Carp::croak("Couldn't open ${modulebuildrc_path} for writing: $!");
18bb63e0 238 print MODULEBUILDRC qq{install --install_base ${path}\n}
b5cc15f7 239 || Carp::croak("Couldn't write line to ${modulebuildrc_path}: $!");
240 close MODULEBUILDRC
241 || Carp::croak("Couldn't close file ${modulebuildrc_path}: $@");
242 }
53699c99 243
244 return $path;
b5cc15f7 245}
246
c2447f35 247sub INTERPOLATE_ENV () { 1 }
248sub LITERAL_ENV () { 0 }
b5cc15f7 249
250sub print_environment_vars_for {
251 my ($class, $path) = @_;
c2447f35 252 my @envs = $class->build_environment_vars_for($path, LITERAL_ENV);
b5cc15f7 253 my $out = '';
1bc71e56 254
0353dbc0 255 # rather basic csh detection, goes on the assumption that something won't
256 # call itself csh unless it really is. also, default to bourne in the
257 # pathological situation where a user doesn't have $ENV{SHELL} defined.
258 # note also that shells with funny names, like zoid, are assumed to be
259 # bourne.
260 my $shellbin = 'sh';
261 if(defined $ENV{'SHELL'}) {
262 my @shell_bin_path_parts = File::Spec->splitpath($ENV{'SHELL'});
263 $shellbin = $shell_bin_path_parts[-1];
264 }
1bc71e56 265 my $shelltype = do {
266 local $_ = $shellbin;
b42496e0 267 if(/csh/) {
1bc71e56 268 'csh'
b42496e0 269 } else {
1bc71e56 270 'bourne'
271 }
272 };
273
53699c99 274 # Win32 uses this variable.
275 if (defined $ENV{'COMSPEC'}) {
276 my @shell_bin_path_parts = File::Spec->splitpath($ENV{'COMSPEC'});
277 $shellbin = $shell_bin_path_parts[-1];
278 $shelltype = do {
279 local $_ = $shellbin;
280 if(/command\.com/) {
281 'win32'
282 } elsif(/cmd\.exe/) {
283 'win32'
284 } elsif(/4nt\.exe/) {
285 'win32'
286 } else {
287 $shelltype
288 }
289 };
290 }
291
b5cc15f7 292 while (@envs) {
293 my ($name, $value) = (shift(@envs), shift(@envs));
294 $value =~ s/(\\")/\\$1/g;
1bc71e56 295 $out .= $class->${\"build_${shelltype}_env_declaration"}($name, $value);
b5cc15f7 296 }
297 print $out;
298}
299
1bc71e56 300# simple routines that take two arguments: an %ENV key and a value. return
301# strings that are suitable for passing directly to the relevant shell to set
302# said key to said value.
303sub build_bourne_env_declaration {
304 my $class = shift;
305 my($name, $value) = @_;
306 return qq{export ${name}="${value}"\n};
307}
308
309sub build_csh_env_declaration {
310 my $class = shift;
311 my($name, $value) = @_;
312 return qq{setenv ${name} "${value}"\n};
313}
314
53699c99 315sub build_win32_env_declaration {
316 my $class = shift;
317 my($name, $value) = @_;
318 return qq{set ${name}=${value}\n};
319}
320
b5cc15f7 321sub setup_env_hash_for {
322 my ($class, $path) = @_;
c2447f35 323 my %envs = $class->build_environment_vars_for($path, INTERPOLATE_ENV);
b5cc15f7 324 @ENV{keys %envs} = values %envs;
325}
326
327sub build_environment_vars_for {
328 my ($class, $path, $interpolate) = @_;
329 return (
330 MODULEBUILDRC => $class->modulebuildrc_path($path),
331 PERL_MM_OPT => "INSTALL_BASE=${path}",
53699c99 332 PERL5LIB => join($Config{path_sep},
b5cc15f7 333 $class->install_base_perl_path($path),
334 $class->install_base_arch_path($path),
c2447f35 335 ($ENV{PERL5LIB} ?
336 ($interpolate == INTERPOLATE_ENV
337 ? ($ENV{PERL5LIB})
53699c99 338 : (($^O ne 'MSWin32') ? '$PERL5LIB' : '%PERL5LIB%' ))
c2447f35 339 : ())
b5cc15f7 340 ),
53699c99 341 PATH => join($Config{path_sep},
b5cc15f7 342 $class->install_base_bin_path($path),
c2447f35 343 ($interpolate == INTERPOLATE_ENV
b5cc15f7 344 ? $ENV{PATH}
53699c99 345 : (($^O ne 'MSWin32') ? '$PATH' : '%PATH%' ))
b5cc15f7 346 ),
347 )
348}
349
275c9dae 350=begin testing
351
352#:: test classmethod
b5cc15f7 353
354File::Path::rmtree('t/var/splat');
355
4c375968 356$c->ensure_dir_structure_for('t/var/splat');
b5cc15f7 357
358ok(-d 't/var/splat');
359
360ok(-f 't/var/splat/.modulebuildrc');
361
275c9dae 362=end testing
363
b5cc15f7 364=head1 NAME
365
366local::lib - create and use a local lib/ for perl modules with PERL5LIB
367
368=head1 SYNOPSIS
369
370In code -
371
372 use local::lib; # sets up a local lib at ~/perl5
373
374 use local::lib '~/foo'; # same, but ~/foo
375
1bc71e56 376 # Or...
377 use FindBin;
378 use local::lib "$FindBin::Bin/../support"; # app-local support library
379
b5cc15f7 380From the shell -
381
0fb70b9a 382 # Install LWP and it's missing dependencies to the 'my_lwp' directory
383 perl -MCPAN -Mlocal::lib=my_lwp -e 'CPAN::install(LWP)'
384
385 # Install LWP and *all non-core* dependencies to the 'my_lwp' directory
386 perl -MCPAN -Mlocal::lib=--self-contained,my_lwp -e 'CPAN::install(LWP)'
387
388 # Just print out useful shell commands
b5cc15f7 389 $ perl -Mlocal::lib
390 export MODULEBUILDRC=/home/username/perl/.modulebuildrc
391 export PERL_MM_OPT='INSTALL_BASE=/home/username/perl'
392 export PERL5LIB='/home/username/perl/lib/perl5:/home/username/perl/lib/perl5/i386-linux'
393 export PATH="/home/username/perl/bin:$PATH"
394
bc30e1d5 395To bootstrap if you don't have local::lib itself installed -
396
e423efce 397 <download local::lib tarball from CPAN, unpack and cd into dir>
715c31a0 398
bc30e1d5 399 $ perl Makefile.PL --bootstrap
400 $ make test && make install
715c31a0 401
dc8ddd06 402 $ echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >>~/.bashrc
715c31a0 403
618272fe 404 # Or for C shells...
715c31a0 405
618272fe 406 $ /bin/csh
407 % echo $SHELL
408 /bin/csh
409 % perl -I$HOME/perl5/lib/perl5 -Mlocal::lib >> ~/.cshrc
dc8ddd06 410
53699c99 411You can also pass --bootstrap=~/foo to get a different location -
8b1e8e69 412
413 $ perl Makefile.PL --bootstrap=~/foo
414 $ make test && make install
415
416 $ echo 'eval $(perl -I$HOME/foo/lib/perl5 -Mlocal::lib=$HOME/foo)' >>~/.bashrc
618272fe 417
977a9ca3 418If you want to install multiple Perl module environments, say for application evelopment,
419install local::lib globally and then:
420
421 $ cd ~/mydir1
422 $ perl -Mlocal::lib=./
423 $ eval $(perl -Mlocal::lib=./) ### To set the environment for this shell alone
424 $ printenv ### You will see that ~/mydir1 is in the PERL5LIB
425 $ perl -MCPAN -e install ... ### whatever modules you want
426 $ cd ../mydir2
427 ... REPEAT ...
428
429For multiple environments for multiple apps you may need to include a modified version of
430the C<< use FindBin >> instructions in the "In code" sample above. If you did something like
431the above, you have a set of Perl modules at C<< ~/mydir1/lib >>. If you have a script at
432C<< ~/mydir1/scripts/myscript.pl >>, you need to tell it where to find the modules you installed
c4dbb66c 433for it at C<< ~/mydir1/lib >>.
977a9ca3 434
435In C<< ~/mydir1/scripts/myscript.pl >>:
436
437 use strict;
438 use warnings;
439 use local::lib "$FindBin::Bin/.."; ### points to ~/mydir1 and local::lib finds lib
440 use lib "$FindBin::Bin/../lib"; ### points to ~/mydir1/lib
441
442Put this before any BEGIN { ... } blocks that require the modules you installed.
443
53699c99 444=head2 Differences when using this module under Win32
445
446 C:\>perl -Mlocal::lib
447 set MODULEBUILDRC=C:\DOCUME~1\ADMINI~1\perl5\.modulebuildrc
448 set PERL_MM_OPT=INSTALL_BASE=C:\DOCUME~1\ADMINI~1\perl5
449 set PERL5LIB=C:\DOCUME~1\ADMINI~1\perl5\lib\perl5;C:\DOCUME~1\ADMINI~1\perl5\lib\perl5\MSWin32-x86-multi-thread
450 set PATH=C:\DOCUME~1\ADMINI~1\perl5\bin;%PATH%
451
452 ### To set the environment for this shell alone
453 C:\>perl -Mlocal::lib > %TEMP%\tmp.bat && %TEMP%\tmp.bat && del %TEMP%\temp.bat
454 ### instead of $(perl -Mlocal::lib=./)
455
456If you want the environment entries to persist, you'll need to add then to the
457Control Panel's System applet yourself at the moment.
458
459The "~" is translated to the user's profile directory (the directory named for
460the user under "Documents and Settings" (Windows XP or earlier) or "Users"
461(Windows Vista or later) unless $ENV{HOME} exists. After that, the home
462directory is translated to a short name (which means the directory must exist)
463and the subdirectories are created.
464
618272fe 465=head1 DESCRIPTION
466
467This module provides a quick, convenient way of bootstrapping a user-local Perl
468module library located within the user's home directory. It also constructs and
469prints out for the user the list of environment variables using the syntax
470appropriate for the user's current shell (as specified by the C<SHELL>
471environment variable), suitable for directly adding to one's shell configuration
472file.
dc8ddd06 473
1bc71e56 474More generally, local::lib allows for the bootstrapping and usage of a directory
475containing Perl modules outside of Perl's C<@INC>. This makes it easier to ship
476an application with an app-specific copy of a Perl module, or collection of
477modules. Useful in cases like when an upstream maintainer hasn't applied a patch
478to a module of theirs that you need for your application.
479
480On import, local::lib sets the following environment variables to appropriate
481values:
482
483=over 4
484
485=item MODULEBUILDRC
486
487=item PERL_MM_OPT
488
489=item PERL5LIB
490
491=item PATH
492
493PATH is appended to, rather than clobbered.
494
495=back
496
497These values are then available for reference by any code after import.
498
480e6e85 499=head1 METHODS
500
501=head2 ensure_directory_structure_for
502
503=over 4
504
505=item Arguments: path
506
507=back
508
509Attempts to create the given path, and all required parent directories. Throws
510an exception on failure.
511
512=head2 print_environment_vars_for
513
514=over 4
515
516=item Arguments: path
517
518=back
519
520Prints to standard output the variables listed above, properly set to use the
521given path as the base directory.
522
523=head2 setup_env_hash_for
524
525=over 4
526
527=item Arguments: path
528
529=back
530
531Constructs the C<%ENV> keys for the given path, by calling
532C<build_environment_vars_for>.
533
534=head2 install_base_perl_path
535
536=over 4
537
538=item Arguments: path
539
540=back
541
542Returns a path describing where to install the Perl modules for this local
543library installation. Appends the directories C<lib> and C<perl5> to the given
544path.
545
546=head2 install_base_arch_path
547
548=over 4
549
550=item Arguments: path
551
552=back
553
554Returns a path describing where to install the architecture-specific Perl
555modules for this local library installation. Based on the
556L</install_base_perl_path> method's return value, and appends the value of
557C<$Config{archname}>.
558
559=head2 install_base_bin_path
560
561=over 4
562
563=item Arguments: path
564
565=back
566
567Returns a path describing where to install the executable programs for this
568local library installation. Based on the L</install_base_perl_path> method's
569return value, and appends the directory C<bin>.
570
571=head2 modulebuildrc_path
572
573=over 4
574
575=item Arguments: path
576
577=back
578
579Returns a path describing where to install the C<.modulebuildrc> file, based on
580the given path.
581
582=head2 resolve_empty_path
583
584=over 4
585
586=item Arguments: path
587
588=back
589
590Builds and returns the base path into which to set up the local module
591installation. Defaults to C<~/perl5>.
592
593=head2 resolve_home_path
594
595=over 4
596
597=item Arguments: path
598
599=back
600
601Attempts to find the user's home directory. If installed, uses C<File::HomeDir>
602for this purpose. If no definite answer is available, throws an exception.
603
604=head2 resolve_relative_path
605
606=over 4
607
608=item Arguments: path
609
610=back
611
612Translates the given path into an absolute path.
613
614=head2 resolve_path
615
616=over 4
617
618=item Arguments: path
619
620=back
621
622Calls the following in a pipeline, passing the result from the previous to the
623next, in an attempt to find where to configure the environment for a local
624library installation: L</resolve_empty_path>, L</resolve_home_path>,
625L</resolve_relative_path>. Passes the given path argument to
626L</resolve_empty_path> which then returns a result that is passed to
627L</resolve_home_path>, which then has its result passed to
628L</resolve_relative_path>. The result of this final call is returned from
629L</resolve_path>.
630
0fb70b9a 631=head1 A WARNING ABOUT UNINST=1
632
633Be careful about using local::lib in combination with "make install UNINST=1".
634The idea of this feature is that will uninstall an old version of a module
635before installing a new one. However it lacks a safety check that the old
636version and the new version will go in the same directory. Used in combination
637with local::lib, you can potentially delete a globally accessible version of a
381738d7 638module while installing the new version in a local place. Only combine "make
0fb70b9a 639install UNINST=1" and local::lib if you understand these possible consequences.
640
dc8ddd06 641=head1 LIMITATIONS
642
618272fe 643Rather basic shell detection. Right now anything with csh in its name is
644assumed to be a C shell or something compatible, and everything else is assumed
53699c99 645to be Bourne, except on Win32 systems. If the C<SHELL> environment variable is
646not set, a Bourne-compatible shell is assumed.
dc8ddd06 647
648Bootstrap is a hack and will use CPAN.pm for ExtUtils::MakeMaker even if you
649have CPANPLUS installed.
650
651Kills any existing PERL5LIB, PERL_MM_OPT or MODULEBUILDRC.
652
e423efce 653Should probably auto-fixup CPAN config if not already done.
654
dc8ddd06 655Patches very much welcome for any of the above.
bc30e1d5 656
53699c99 657On Win32 systems, does not have a way to write the created environment variables
658to the registry, so that they can persist through a reboot.
659
9a021b2b 660=head1 TROUBLESHOOTING
661
662If you've configured local::lib to install CPAN modules somewhere in to your
663home directory, and at some point later you try to install a module with C<cpan
664-i Foo::Bar>, but it fails with an error like: C<Warning: You do not have
665permissions to install into /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux at
666/usr/lib64/perl5/5.8.8/Foo/Bar.pm> and buried within the install log is an
667error saying C<'INSTALL_BASE' is not a known MakeMaker parameter name>, then
668you've somehow lost your updated ExtUtils::MakeMaker module.
669
670To remedy this situation, rerun the bootstrapping procedure documented above.
671
672Then, run C<rm -r ~/.cpan/build/Foo-Bar*>
673
674Finally, re-run C<cpan -i Foo::Bar> and it should install without problems.
675
618272fe 676=head1 ENVIRONMENT
677
678=over 4
679
680=item SHELL
681
53699c99 682=item COMSPEC
683
618272fe 684local::lib looks at the user's C<SHELL> environment variable when printing out
685commands to add to the shell configuration file.
686
53699c99 687On Win32 systems, C<COMSPEC> is also examined.
688
618272fe 689=back
690
b5cc15f7 691=head1 AUTHOR
692
693Matt S Trout <mst@shadowcat.co.uk> http://www.shadowcat.co.uk/
694
d6b71a2d 695auto_install fixes kindly sponsored by http://www.takkle.com/
696
b5c1154d 697=head1 CONTRIBUTORS
698
699Patches to correctly output commands for csh style shells, as well as some
700documentation additions, contributed by Christopher Nehren <apeiron@cpan.org>.
701
0fb70b9a 702'--self-contained' feature contributed by Mark Stosberg <mark@summersault.com>.
703
c4dbb66c 704Doc patches for a custom local::lib directory contributed by Torsten Raudssus
8b1e8e69 705<torsten@raudssus.de>.
706
be160790 707Hans Dieter Pearcey <hdp@cpan.org> sent in some additional tests for ensuring
9a021b2b 708things will install properly, submitted a fix for the bug causing problems with
709writing Makefiles during bootstrapping, contributed an example program, and
710submitted yet another fix to ensure that local::lib can install and bootstrap
711properly. Many, many thanks!
712
713pattern of Freenode IRC contributed the beginnings of the Troubleshooting
714section. Many thanks!
be160790 715
53699c99 716Patch to add Win32 support contributed by Curtis Jewell <csjewell@cpan.org>.
717
b5cc15f7 718=head1 LICENSE
719
53699c99 720This library is free software under the same license as perl itself.
b5cc15f7 721
722=cut
723
7241;