File Coverage

blib/lib/Clownfish/CFC/Perl/Build.pm
Criterion Covered Total %
statement 24 290 8.2
branch 0 88 0.0
condition 0 14 0.0
subroutine 8 25 32.0
pod 0 12 0.0
total 32 429 7.4


line stmt bran cond sub pod time code
1             # Licensed to the Apache Software Foundation (ASF) under one or more
2             # contributor license agreements. See the NOTICE file distributed with
3             # this work for additional information regarding copyright ownership.
4             # The ASF licenses this file to You under the Apache License, Version 2.0
5             # (the "License"); you may not use this file except in compliance with
6             # the License. You may obtain a copy of the License at
7             #
8             # http://www.apache.org/licenses/LICENSE-2.0
9             #
10             # Unless required by applicable law or agreed to in writing, software
11             # distributed under the License is distributed on an "AS IS" BASIS,
12             # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13             # See the License for the specific language governing permissions and
14             # limitations under the License.
15              
16 1     1   1395 use strict;
  1         1  
  1         52  
17 1     1   7 use warnings;
  1         2  
  1         76  
18              
19             package Clownfish::CFC::Perl::Build;
20 1     1   8 use base qw( Module::Build );
  1         2  
  1         1121  
21             our $VERSION = '0.006001';
22             $VERSION = eval $VERSION;
23              
24 1     1   104989 use File::Spec::Functions qw( catdir catfile curdir updir abs2rel rel2abs );
  1         823  
  1         152  
25 1     1   22 use File::Path qw( mkpath );
  1         2  
  1         62  
26 1     1   8 use Config;
  1         3  
  1         62  
27 1     1   7 use Carp;
  1         2  
  1         4438  
28              
29             # Add a custom Module::Build hashref property to pass additional build
30             # parameters
31             if ( $Module::Build::VERSION <= 0.30 ) {
32             __PACKAGE__->add_property( clownfish_params => {} );
33             }
34             else {
35             # TODO: add sub for property check
36             __PACKAGE__->add_property(
37             'clownfish_params',
38             default => {},
39             );
40             }
41              
42             # Rationale
43              
44             # When the distribution tarball for the Perl bindings is built, core/, and any
45             # other needed files/directories are copied into the perl/ directory within the
46             # main source directory. Then the distro is built from the contents of the
47             # perl/ directory, leaving out all the files in ruby/, etc. However, during
48             # development, the files are accessed from their original locations.
49              
50             my $IS_CPAN_DIST = -d 'core' || -d 'cfcore';
51             my @BASE_PATH;
52             push(@BASE_PATH, updir()) unless $IS_CPAN_DIST;
53              
54             my $AUTOGEN_DIR = 'autogen';
55             my $LIB_DIR = 'lib';
56             my $BUILDLIB_DIR = 'buildlib';
57              
58             sub new {
59 0     0 0   my $self = shift->SUPER::new( @_ );
60              
61             # TODO: use Charmonizer to determine whether pthreads are userland.
62 0 0 0       if ( $Config{osname} =~ /openbsd/i && $Config{usethreads} ) {
63 0           my $extra_ldflags = $self->extra_linker_flags;
64 0           push @$extra_ldflags, '-lpthread';
65 0           $self->extra_linker_flags(@$extra_ldflags);
66             }
67              
68 0           my $autogen_header = $self->clownfish_params('autogen_header');
69 0 0         if ( !defined($autogen_header) ) {
70 0           $self->clownfish_params( autogen_header => <<'END_AUTOGEN' );
71             ***********************************************
72              
73             !!!! DO NOT EDIT !!!!
74              
75             This file was auto-generated by Build.PL.
76              
77             ***********************************************
78             END_AUTOGEN
79             }
80              
81 0           return $self;
82             }
83              
84             # Return the list of Clownfish include dirs. Uses directories from
85             # - Module::Build parameter
86             # - Environment variable CLOWNFISH_INCLUDE
87             # - Clownfish include directories found in @INC
88             # Note that this function must be called at build time because dependencies
89             # might not be installed yet at configure time.
90             sub cf_include_dirs {
91 0     0 0   my $self = shift;
92              
93 0           my $cf_include = $self->clownfish_params('include');
94 0           my @dirs;
95 0 0         @dirs = ref($cf_include) ? @$cf_include : ( $cf_include )
    0          
96             if defined($cf_include);
97              
98             # Add include dirs from CLOWNFISH_INCLUDE environment variable.
99 0 0         if ($ENV{CLOWNFISH_INCLUDE}) {
100 0           push( @dirs, split( /:/, $ENV{CLOWNFISH_INCLUDE} ) );
101             }
102              
103             # Add include dirs from @INC.
104 0           for my $dir (@INC) {
105 0           my $cf_incdir = catdir( $dir, 'Clownfish', '_include' );
106 0 0         push( @dirs, $cf_incdir ) if -d $cf_incdir;
107             }
108              
109 0           return @dirs;
110             }
111              
112             # Return the list of Clownfish C include dirs.
113             # Note that this function must be called at build time because dependencies
114             # might not be installed yet at configure time.
115             sub cf_c_include_dirs {
116 0     0 0   my $self = shift;
117              
118 0           my $include_dirs = $self->include_dirs;
119 0           my @dirs;
120 0 0         @dirs = ref($include_dirs) ? @$include_dirs : ( $include_dirs )
    0          
121             if defined($include_dirs);
122              
123 0           push( @dirs,
124             curdir(), # for ppport.h
125             catdir( $AUTOGEN_DIR, 'include' ),
126             $self->cf_include_dirs,
127             );
128              
129 0           return @dirs;
130             }
131              
132             sub cf_base_path {
133 0     0 0   my $self_or_class = shift;
134 0           return @BASE_PATH;
135             }
136              
137             sub cf_linker_flags {
138 0     0 0   my $self = shift;
139              
140 0           my $dlext = $Config{dlext};
141             # Only needed on Windows
142 0 0         return () if $dlext !~ /dll$/i;
143              
144             # Link against import library on MSVC
145 0 0         my $ext = $Config{cc} =~ /^cl\b/ ? 'lib' : $dlext;
146              
147 0           my @linker_flags;
148              
149 0           for my $module_name (@_) {
150             # Find library to link against
151 0           my @module_parts = split( '::', $module_name );
152 0           my $class_name = $module_parts[-1];
153 0           my $lib_file;
154             my $found;
155              
156 0           for my $dir ( catdir( $self->blib, 'arch' ), @INC ) {
157 0           $lib_file = catfile(
158             $dir, 'auto', @module_parts, "$class_name.$ext",
159             );
160 0 0         if ( -f $lib_file ) {
161 0           $found = 1;
162 0           last;
163             }
164             }
165              
166 0 0         die("No Clownfish library file found for module $module_name")
167             if !$found;
168              
169 0           push( @linker_flags, $lib_file );
170             }
171              
172 0           return @linker_flags;
173             }
174              
175             sub _cfh_filepaths {
176 0     0     my $self = shift;
177 0           my @paths;
178 0           my $source_dirs = $self->clownfish_params('source');
179 0           for my $source_dir (@$source_dirs) {
180 0 0         next unless -e $source_dir;
181 0           push @paths, @{ $self->rscan_dir( $source_dir, qr/\.cf[hp]$/ ) };
  0            
182             }
183 0           return \@paths;
184             }
185              
186             sub cf_copy_include_file {
187 0     0 0   my ($self, @path) = @_;
188              
189 0           my $dest_dir = catdir( $self->blib, 'arch', 'Clownfish', '_include' );
190 0           for my $include_dir ($self->cf_c_include_dirs) {
191 0           my $file = catfile ( $include_dir, @path );
192 0 0         if ( -e $file ) {
193 0           $self->copy_if_modified(
194             from => $file,
195             to => catfile( $dest_dir, @path ),
196             );
197 0           return;
198             }
199             }
200 0           die( "Clownfish include file " . catfile(@path) . " not found" );
201             }
202              
203             my %hierarchy_cache;
204              
205             sub _compile_clownfish {
206 0     0     my $self = shift;
207              
208 0           require Clownfish::CFC::Model::Hierarchy;
209 0           require Clownfish::CFC::Binding::Perl;
210 0           require Clownfish::CFC::Binding::Perl::Class;
211              
212 0 0         return @hierarchy_cache{ qw( hierarchy binding ) }
213             if %hierarchy_cache;
214              
215             # Compile Clownfish.
216 0           my $hierarchy = Clownfish::CFC::Model::Hierarchy->new(
217             dest => $AUTOGEN_DIR,
218             );
219 0           my $source_dirs = $self->clownfish_params('source');
220 0           for my $source_dir (@$source_dirs) {
221 0           $hierarchy->add_source_dir($source_dir);
222             }
223 0           for my $include_dir ($self->cf_include_dirs) {
224 0           $hierarchy->add_include_dir($include_dir);
225             }
226 0           $hierarchy->build;
227 0           $hierarchy->read_host_data_json;
228              
229             # Process all Binding classes in buildlib.
230 0           my $pm_filepaths = $self->rscan_dir( $BUILDLIB_DIR, qr/\.pm$/ );
231 0           for my $pm_filepath (@$pm_filepaths) {
232 0 0         next unless $pm_filepath =~ /Binding/;
233 0           require $pm_filepath;
234 0           my $package_name = $pm_filepath;
235 0           $package_name =~ s/buildlib\/(.*)\.pm$/$1/;
236 0           $package_name =~ s/\//::/g;
237 0           $package_name->bind_all($hierarchy);
238             }
239              
240 0           my $binding = Clownfish::CFC::Binding::Perl->new(
241             hierarchy => $hierarchy,
242             lib_dir => $LIB_DIR,
243             header => $self->clownfish_params('autogen_header'),
244             footer => '',
245             );
246              
247 0           @hierarchy_cache{ qw( hierarchy binding ) } = ( $hierarchy, $binding );
248              
249 0           return ( $hierarchy, $binding );
250             }
251              
252             # Deprecated.
253             sub ACTION_pod {
254 0     0 0   my $self = shift;
255 0           $self->depends_on('clownfish');
256             }
257              
258             sub ACTION_clownfish {
259 0     0 0   my $self = shift;
260              
261 0           $self->add_to_cleanup($AUTOGEN_DIR);
262              
263 0           my $modules = $self->clownfish_params('modules');
264 0           my @xs_filepaths;
265              
266 0           for my $module (@$modules) {
267 0           my @module_dir = split( '::', $module->{name} );
268 0           my $class_name = pop(@module_dir);
269 0           push @xs_filepaths, catfile( $LIB_DIR, @module_dir, "$class_name.xs" );
270             }
271              
272 0           my $buildlib_pm_filepaths = $self->rscan_dir( $BUILDLIB_DIR, qr/\.pm$/ );
273 0           my $cfh_filepaths = $self->_cfh_filepaths;
274 0           my $log_filepath = catfile( $AUTOGEN_DIR, 'hierarchy.json' );
275              
276             # Don't bother parsing Clownfish files if everything's up to date.
277             return
278 0 0         if $self->up_to_date(
279             [ @$cfh_filepaths, @$buildlib_pm_filepaths ],
280             [ @xs_filepaths, $log_filepath, ]
281             );
282              
283             # Write out all autogenerated files.
284 0           print "Parsing Clownfish files...\n";
285 0           my ( $hierarchy, $perl_binding ) = $self->_compile_clownfish;
286 0           require Clownfish::CFC::Binding::Core;
287 0           my $core_binding = Clownfish::CFC::Binding::Core->new(
288             hierarchy => $hierarchy,
289             header => $self->clownfish_params('autogen_header'),
290             footer => '',
291             );
292 0           print "Writing Clownfish autogenerated files...\n";
293 0           my $inc_dir = catdir( $self->blib, 'arch', 'Clownfish', '_include' );
294 0           my $cfh_modified = $core_binding->write_all_modified;
295 0 0         if ($cfh_modified) {
296 0           unlink('typemap');
297 0           print "Writing typemap...\n";
298 0           $self->add_to_cleanup('typemap');
299 0           $perl_binding->write_xs_typemap;
300 0           $core_binding->copy_headers($inc_dir);
301             }
302              
303             # Rewrite XS if either any .cfh files or relevant .pm files were modified.
304 0           my $buildlib_modified = ! $self->up_to_date(
305             \@$buildlib_pm_filepaths, [ @xs_filepaths, $log_filepath ]
306             );
307              
308 0 0 0       if ( $cfh_modified || $buildlib_modified ) {
309 0           $self->add_to_cleanup(@xs_filepaths);
310 0           $perl_binding->write_host_code;
311 0           $perl_binding->write_hostdefs;
312              
313 0           for my $module (@$modules) {
314             $perl_binding->write_bindings(
315             boot_class => $module->{name},
316             parcels => $module->{parcels},
317 0           );
318             }
319              
320 0           $core_binding->write_host_data_json($inc_dir);
321              
322 0 0         unless ($IS_CPAN_DIST) {
323 0           print "Writing POD...\n";
324 0           my $pod_files = $perl_binding->write_pod;
325 0           $self->add_to_cleanup($_) for @$pod_files;
326             }
327             }
328              
329             # Touch autogenerated files in case the modifications were inconsequential
330             # and didn't trigger a rewrite, so that we won't have to check them again
331             # next pass.
332 0           for my $xs_filepath (@xs_filepaths) {
333 0 0         if (!$self->up_to_date(
334             [ @$cfh_filepaths, @$buildlib_pm_filepaths ], $xs_filepath
335             )
336             )
337             {
338 0           utime( time, time, $xs_filepath ); # touch
339             }
340             }
341              
342 0           $hierarchy->write_log;
343             }
344              
345             # Write ppport.h, which supplies some XS routines not found in older Perls and
346             # allows us to use more up-to-date XS API while still supporting Perls back to
347             # 5.8.3.
348             #
349             # The Devel::PPPort docs recommend that we distribute ppport.h rather than
350             # require Devel::PPPort itself, but ppport.h isn't compatible with the Apache
351             # license.
352             sub ACTION_ppport {
353 0     0 0   my $self = shift;
354 0 0         if ( !-e 'ppport.h' ) {
355 0           require Devel::PPPort;
356 0           $self->add_to_cleanup('ppport.h');
357 0           Devel::PPPort::WriteFile();
358             }
359             }
360              
361             sub ACTION_compile_custom_xs {
362 0     0 0   my $self = shift;
363              
364 0           $self->depends_on('ppport');
365              
366             # Make sure all parcels are read and registered.
367 0           $self->_compile_clownfish();
368              
369 0           my $modules = $self->clownfish_params('modules');
370 0           for my $module (@$modules) {
371 0           $self->_compile_custom_xs($module);
372             }
373             }
374              
375             sub _compile_custom_xs {
376 0     0     my ( $self, $module ) = @_;
377              
378 0           require ExtUtils::CBuilder;
379 0           require ExtUtils::ParseXS;
380              
381 0           my $module_name = $module->{name};
382 0           my @module_parts = split( '::', $module_name );
383 0           my @module_dir = @module_parts;
384 0           my $class_name = pop(@module_dir);
385              
386 0           my $cbuilder = ExtUtils::CBuilder->new( config => $self->config );
387 0           my $libdir = catdir( $LIB_DIR, @module_dir );
388 0           my $archdir = catdir( $self->blib, 'arch', 'auto', @module_parts );
389 0 0         mkpath( $archdir, 0, 0777 ) unless -d $archdir;
390 0           my @objects;
391              
392             # Make objects.
393 0 0         if ($module->{make_target}) {
394 0           my $make_objects = $self->cf_make_objects($module->{make_target});
395 0           push @objects, @$make_objects;
396             }
397              
398             # Compile C source files.
399 0           my $c_files = [];
400 0   0       my $source_dirs = $module->{c_source_dirs} || [];
401 0           for my $source_dir (@$source_dirs) {
402 0           push @$c_files, @{ $self->rscan_dir( $source_dir, qr/\.c$/ ) };
  0            
403             }
404 0           my $autogen_src_dir = catdir( $AUTOGEN_DIR, 'source' );
405 0           for my $parcel_name ( @{ $module->{parcels} } ) {
  0            
406 0           my $parcel = Clownfish::CFC::Model::Parcel->acquire($parcel_name);
407 0           my $prefix = $parcel->get_prefix;
408             # Assume *_parcel.c is built with make.
409             push @$c_files, catfile( $autogen_src_dir, "${prefix}parcel.c" )
410 0 0         if !$module->{make_target};
411 0           push @$c_files, catfile( $autogen_src_dir, "${prefix}perl.c" );
412             }
413 0           my $extra_cflags = $self->clownfish_params('cflags');
414 0           for my $c_file (@$c_files) {
415 0           my $o_file = $c_file;
416 0           my $ccs_file = $c_file;
417 0 0         $o_file =~ s/\.c$/$Config{_o}/ or die "no match";
418 0 0         $ccs_file =~ s/\.c$/.ccs/ or die "no match";
419 0           push @objects, $o_file;
420 0 0         next if $self->up_to_date( $c_file, $o_file );
421 0           $self->add_to_cleanup($o_file);
422 0           $self->add_to_cleanup($ccs_file);
423 0           $cbuilder->compile(
424             source => $c_file,
425             extra_compiler_flags => $extra_cflags,
426             include_dirs => [ $self->cf_c_include_dirs ],
427             object_file => $o_file,
428             );
429             }
430              
431             # .xs => .c
432 0           my $xs_filepath = catfile( $libdir, "$class_name.xs" );
433 0           my $perl_binding_c_file = catfile( $libdir, "$class_name.c" );
434 0           $self->add_to_cleanup($perl_binding_c_file);
435 0 0         if ( !$self->up_to_date( $xs_filepath, $perl_binding_c_file ) ) {
436 0           ExtUtils::ParseXS::process_file(
437             filename => $xs_filepath,
438             prototypes => 0,
439             output => $perl_binding_c_file,
440             );
441             }
442              
443             # .c => .o
444 0           my $version = $self->dist_version;
445 0           my $perl_binding_o_file = catfile( $libdir, "$class_name$Config{_o}" );
446 0           unshift @objects, $perl_binding_o_file;
447 0           $self->add_to_cleanup($perl_binding_o_file);
448 0 0         if ( !$self->up_to_date( $perl_binding_c_file, $perl_binding_o_file ) ) {
449             # Don't use Clownfish compiler flags for XS
450 0           $cbuilder->compile(
451             source => $perl_binding_c_file,
452             extra_compiler_flags => $self->extra_compiler_flags,
453             include_dirs => [ $self->cf_c_include_dirs ],
454             object_file => $perl_binding_o_file,
455             # 'defines' is an undocumented parameter to compile(), so we
456             # should officially roll our own variant and generate compiler
457             # flags. However, that involves writing a bunch of
458             # platform-dependent code, so we'll just take the chance that this
459             # will break.
460             defines => {
461             VERSION => qq|"$version"|,
462             XS_VERSION => qq|"$version"|,
463             },
464             );
465             }
466              
467             # Create .bs bootstrap file, needed by Dynaloader.
468 0           my $bs_file = catfile( $archdir, "$class_name.bs" );
469 0           $self->add_to_cleanup($bs_file);
470 0 0         if ( !$self->up_to_date( $perl_binding_o_file, $bs_file ) ) {
471 0           require ExtUtils::Mkbootstrap;
472 0           ExtUtils::Mkbootstrap::Mkbootstrap($bs_file);
473 0 0         if ( !-f $bs_file ) {
474             # Create file in case Mkbootstrap didn't do anything.
475 0 0         open( my $fh, '>', $bs_file )
476             or confess "Can't open $bs_file: $!";
477             }
478 0           utime( (time) x 2, $bs_file ); # touch
479             }
480              
481             # Clean up after CBuilder under MSVC.
482 0           $self->add_to_cleanup('compilet*');
483 0           $self->add_to_cleanup('*.ccs');
484 0           $self->add_to_cleanup( catfile( $libdir, "$class_name.ccs" ) );
485 0           $self->add_to_cleanup( catfile( $libdir, "$class_name.def" ) );
486 0           $self->add_to_cleanup( catfile( $libdir, "${class_name}_def.old" ) );
487 0           $self->add_to_cleanup( catfile( $libdir, "$class_name.exp" ) );
488 0           $self->add_to_cleanup( catfile( $libdir, "$class_name.lib" ) );
489 0           $self->add_to_cleanup( catfile( $libdir, "$class_name.lds" ) );
490 0           $self->add_to_cleanup( catfile( $libdir, "$class_name.base" ) );
491              
492             # .o => .(a|bundle)
493 0           my $lib_file = catfile( $archdir, "$class_name.$Config{dlext}" );
494 0 0         if ( !$self->up_to_date( [ @objects, $AUTOGEN_DIR ], $lib_file ) ) {
495 0           my $linker_flags = $self->extra_linker_flags;
496 0           my @xs_prereqs = $self->_cf_find_xs_prereqs($module);
497 0           push @$linker_flags, $self->cf_linker_flags(@xs_prereqs);
498 0           $cbuilder->link(
499             module_name => $module_name,
500             objects => \@objects,
501             lib_file => $lib_file,
502             extra_linker_flags => $linker_flags,
503             );
504             # Install .lib file on Windows
505             # TODO: Install .dll.a when building with GCC on Windows?
506 0           my $implib_file = catfile( $libdir, "$class_name.lib" );
507 0 0         if ( -e $implib_file ) {
508 0           $self->copy_if_modified(
509             from => $implib_file,
510             to => catfile( $archdir, "$class_name.lib" ),
511             );
512             }
513             }
514             }
515              
516             sub _cf_find_xs_prereqs {
517 0     0     my ( $self, $module ) = @_;
518              
519 0           my $modules = $self->clownfish_params('modules');
520 0           my @xs_prereqs;
521              
522 0           for my $parcel_name ( @{ $module->{parcels} } ) {
  0            
523 0           my $parcel = Clownfish::CFC::Model::Parcel->acquire($parcel_name);
524              
525 0           for my $prereq_parcel ( @{ $parcel->prereq_parcels } ) {
  0            
526 0           my $prereq_module;
527              
528 0 0         if ($prereq_parcel->included) {
529 0           $prereq_module = $prereq_parcel->get_xs_module;
530             }
531             else {
532 0           my $prereq_parcel_name = $prereq_parcel->get_name;
533              
534 0           for my $candidate (@$modules) {
535             my @matches = grep {
536 0           $_ eq $prereq_parcel_name
537 0           } @{ $candidate->{parcels} };
  0            
538              
539 0 0         if (@matches) {
540 0           $prereq_module = $candidate->{name};
541 0           last;
542             }
543             }
544             }
545              
546 0 0         die("No XS module found for parcel $parcel_name")
547             if !defined($prereq_module);
548             push @xs_prereqs, $prereq_module
549             if $prereq_module ne $module->{name}
550 0 0 0       && !grep { $_ eq $prereq_module } @xs_prereqs;
  0            
551             }
552             }
553              
554 0           return @xs_prereqs;
555             }
556              
557             sub ACTION_code {
558 0     0 0   my $self = shift;
559              
560 0           $self->depends_on(qw(
561             clownfish
562             compile_custom_xs
563             ));
564              
565 0           $self->SUPER::ACTION_code;
566             }
567              
568             sub ACTION_clean {
569 0     0 0   my $self = shift;
570              
571 0 0         if ( $self->can('cf_make_clean') ) {
572 0           $self->cf_make_clean();
573             }
574              
575 0           $self->SUPER::ACTION_clean;
576             }
577              
578             # Monkey patch ExtUtils::CBuilder::Platform::Windows::GCC::format_linker_cmd
579             # to make extensions work on MinGW.
580             #
581             # nwellnhof: The original ExtUtils::CBuilder implementation uses dlltool and a
582             # strange incremental linking scheme. I think this is only needed for ancient
583             # versions of GNU ld. It somehow breaks exporting of symbols via
584             # __declspec(dllexport). Starting with version 2.17, one can pass .def files
585             # to GNU ld directly, which requires only a single command and gets the
586             # exports right.
587             {
588 1     1   11 no warnings 'redefine';
  1         3  
  1         524  
589             require ExtUtils::CBuilder::Platform::Windows::GCC;
590             *ExtUtils::CBuilder::Platform::Windows::GCC::format_linker_cmd = sub {
591 0     0     my ($self, %spec) = @_;
592 0           my $cf = $self->{config};
593              
594             # The Config.pm variable 'libperl' is hardcoded to the full name
595             # of the perl import library (i.e. 'libperl56.a'). GCC will not
596             # find it unless the 'lib' prefix & the extension are stripped.
597 0           $spec{libperl} =~ s/^(?:lib)?([^.]+).*$/-l$1/;
598              
599 0           unshift( @{$spec{other_ldflags}}, '-nostartfiles' )
600 0 0 0       if ( $spec{startup} && @{$spec{startup}} );
  0            
601              
602             # From ExtUtils::MM_Win32:
603             #
604             ## one thing for GCC/Mingw32:
605             ## we try to overcome non-relocateable-DLL problems by generating
606             ## a (hopefully unique) image-base from the dll's name
607             ## -- BKS, 10-19-1999
608 0           File::Basename::basename( $spec{output} ) =~ /(....)(.{0,4})/;
609 0           $spec{image_base} = sprintf( "0x%x0000", unpack('n', $1 ^ $2) );
610              
611             %spec = $self->write_linker_script(%spec)
612 0 0         if $spec{use_scripts};
613              
614 0           foreach my $path ( @{$spec{libpath}} ) {
  0            
615 0           $path = "-L$path";
616             }
617              
618 0           my @cmds; # Stores the series of commands needed to build the module.
619              
620             # split off any -arguments included in ld
621 0           my @ld = split / (?=-)/, $spec{ld};
622              
623 0 0         push @cmds, [ grep {defined && length} (
624             @ld ,
625             '-o', $spec{output} ,
626             "-Wl,--image-base,$spec{image_base}" ,
627 0           @{$spec{lddlflags}} ,
628 0           @{$spec{libpath}} ,
629 0           @{$spec{startup}} ,
630 0           @{$spec{objects}} ,
631 0           @{$spec{other_ldflags}} ,
632             $spec{libperl} ,
633 0           @{$spec{perllibs}} ,
634             $spec{def_file} ,
635 0 0         $spec{map_file} ? ('-Map', $spec{map_file}) : ''
636             ) ];
637              
638 0           return @cmds;
639             };
640             }
641              
642             1;
643              
644             __END__