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