1package mymm;
2
3use strict;
4use warnings;
5use Config;
6use File::Glob qw( bsd_glob );
7use ExtUtils::MakeMaker ();
8use IPC::Cmd ();
9use lib 'inc';
10use File::Spec;
11use My::BuildConfig;
12use My::ShareConfig;
13
14{
15  my $dh;
16  opendir $dh, 'inc';
17  my @files = map { File::Spec->catfile('inc', $_) } grep /^bad-.*\.pl$/, readdir $dh;
18  close $dh;
19
20  foreach my $badcheck (@files)
21  {
22    system $^X, $badcheck;
23    if($?)
24    {
25      print "bad check $badcheck failed\n";
26      exit;
27    }
28  }
29}
30
31sub vcpkg
32{
33  return unless $Config{ccname} eq 'cl';
34  require Alien::FFI::Vcpkg;
35  !!eval { Alien::FFI::Vcpkg->vcpkg }
36}
37
38sub myWriteMakefile
39{
40  my %args = @_;
41  my $build_config = My::BuildConfig->new;
42  my $share_config = My::ShareConfig->new;
43  my %diag;
44  my %alien;
45
46  ExtUtils::MakeMaker->VERSION('7.12');
47  $build_config->set(version => [ $args{VERSION} =~ /^([0-9]+)\.([0-9]{2})/ ]);
48
49  if(eval { require Alien::FFI; Alien::FFI->VERSION('0.20'); 1 })
50  {
51    print "using already installed Alien::FFI (version @{[ Alien::FFI->VERSION ]})\n";
52    $build_config->set(alien => { class => 'Alien::FFI', mode => 'already-installed' });
53    require Alien::Base::Wrapper;
54    Alien::Base::Wrapper->import( 'Alien::FFI', 'Alien::psapi', '!export' );
55    %alien = Alien::Base::Wrapper->mm_args;
56  }
57  elsif(vcpkg())
58  {
59    print "using vcpkg libffi package\n";
60    $build_config->set(alien => { class => 'Alien::FFI::Vcpkg', mode => 'system' });
61    require Alien::Base::Wrapper;
62    Alien::Base::Wrapper->import( 'Alien::FFI::Vcpkg', '!export');
63    %alien = Alien::Base::Wrapper->mm_args;
64  }
65  else
66  {
67    require Alien::FFI::pkgconfig    if $^O ne 'MSWin32';
68    require Alien::FFI::PkgConfigPP  if $^O eq 'MSWin32';
69
70    my $alien_install_type_unset = !defined $ENV{ALIEN_INSTALL_TYPE};
71
72    if($alien_install_type_unset && $^O eq 'MSWin32' && Alien::FFI::PkgConfigPP->exists)
73    {
74      print "using system libffia via PkgConfigPP\n";
75      $build_config->set(alien => { class => 'Alien::FFI::PkgConfigPP', mode => 'system' });
76      require Alien::Base::Wrapper;
77      Alien::Base::Wrapper->import( 'Alien::FFI::PkgConfigPP', 'Alien::psapi', '!export' );
78      %alien = Alien::Base::Wrapper->mm_args;
79    }
80    elsif($alien_install_type_unset && $^O ne 'MSWin32' && Alien::FFI::pkgconfig->exists)
81    {
82      print "using system libffi via @{[ Alien::FFI::pkgconfig->pkg_config_exe ]}\n";
83      $build_config->set(alien => { class => 'Alien::FFI::pkgconfig', mode => 'system' });
84      require Alien::Base::Wrapper;
85      Alien::Base::Wrapper->import( 'Alien::FFI::pkgconfig', 'Alien::psapi', '!export' );
86      %alien = Alien::Base::Wrapper->mm_args;
87    }
88    else
89    {
90      print "requiring Alien::FFI in fallback mode.\n";
91    $build_config->set(alien => { class => 'Alien::FFI', mode => 'fallback' });
92      %alien = (
93        CC => '$(FULLPERL) -Iinc -MAlien::Base::Wrapper=Alien::FFI,Alien::psapi -e cc --',
94        LD => '$(FULLPERL) -Iinc -MAlien::Base::Wrapper=Alien::FFI,Alien::psapi -e ld --',
95      );
96      $args{BUILD_REQUIRES}->{'Alien::FFI'} = '0.20';
97    }
98  }
99  $alien{INC} = defined $alien{INC} ? "-Iinclude $alien{INC}" : "-Iinclude";
100
101  %args = (%args, %alien);
102
103  if($ENV{FFI_PLATYPUS_DEBUG_FAKE32} || $Config{uvsize} < 8)
104  {
105    $args{BUILD_REQUIRES}->{'Math::Int64'} = '0.34';
106  }
107
108  if($ENV{FFI_PLATYPUS_DEBUG_FAKE32} && $Config{uvsize} == 8)
109  {
110    print "DEBUG_FAKE32:\n";
111    print "  + making Math::Int64 a prereq\n";
112    print "  + Using Math::Int64's C API to manipulate 64 bit values\n";
113    $build_config->set(config_debug_fake32 => 1);
114    $diag{config}->{config_debug_fake32} = 1;
115  }
116  if($ENV{FFI_PLATYPUS_NO_ALLOCA})
117  {
118    print "NO_ALLOCA:\n";
119    print "  + alloca() will not be used, even if your platform supports it.\n";
120    $build_config->set(config_no_alloca => 1);
121    $diag{config}->{config_no_alloca} = 1;
122  }
123
124  delete $args{PM};
125  $args{XSMULTI} = 1;
126  $args{XSBUILD} = {
127    xs => {
128      'lib/FFI/Platypus' => {
129        OBJECT => 'lib/FFI/Platypus$(OBJ_EXT) ' . join(' ', map { s/\.c$/\$(OBJ_EXT)/; $_ } bsd_glob "xs/*.c"),
130        %alien,
131      },
132    },
133  };
134
135  $args{PREREQ_PM}->{'Math::Int64'} = '0.34'
136    if $ENV{FFI_PLATYPUS_DEBUG_FAKE32} || $Config{uvsize} < 8;
137
138  # dlext as understood by MB and MM
139  my @dlext = ($Config{dlext});
140
141  # extra dlext as understood by the OS
142  push @dlext, 'dll'             if $^O =~ /^(cygwin|MSWin32|msys)$/;
143  push @dlext, 'xs.dll'          if $^O =~ /^(MSWin32)$/;
144  push @dlext, 'so'              if $^O =~ /^(cygwin|darwin)$/;
145  push @dlext, 'bundle', 'dylib' if $^O =~ /^(darwin)$/;
146
147  # uniq'ify it
148  @dlext = do { my %seen; grep { !$seen{$_}++ } @dlext };
149
150  $build_config->set(diag => \%diag);
151  $share_config->set(config_dlext => \@dlext);
152
153  ExtUtils::MakeMaker::WriteMakefile(%args);
154}
155
156#package MM;
157#
158#sub init_tools
159#{
160#  my $self = shift;
161#  $self->SUPER::init_tools(@_);
162#
163#  return if !!$ENV{V};
164#
165#  my $noecho = $^O eq 'MSWin32' ? 'REM ' : '@';
166#
167#  foreach my $tool (qw( RM_F RM_RF CP MV ))
168#  {
169#    $self->{$tool} = $noecho . $self->{$tool};
170#  }
171#
172#  return;
173#}
174
175package MY;
176
177use Config;
178
179sub dynamic_lib
180{
181  my($self, @therest) = @_;
182  my $dynamic_lib = $self->SUPER::dynamic_lib(@therest);
183
184  my %h = map { m!include/(.*?)$! && $1 => [$_] } File::Glob::bsd_glob('include/*.h');
185  push @{ $h{"ffi_platypus.h"} }, map { "include/ffi_platypus_$_.h" } qw( config );
186
187  my %targets = (
188    'include/ffi_platypus_config.h' => ['_mm/config'],
189    'lib/FFI/Platypus.c' => [File::Glob::bsd_glob('xs/*.xs'), 'lib/FFI/Platypus.xs', 'lib/FFI/typemap'],
190  );
191
192  foreach my $cfile (File::Glob::bsd_glob('xs/*.c'), 'lib/FFI/Platypus.c')
193  {
194    my $ofile = $cfile;
195    $ofile =~ s/\.c$/\$(OBJ_EXT)/;
196
197    my @deps = ($cfile, '_mm/config');
198
199    if(-d ".git")
200    {
201      # for a development build, lets go ahead and compute the .h
202      # dependencies to make it easier to do a partial rebuild.
203      my $source_file = $cfile;
204      $source_file = 'lib/FFI/Platypus.xs' if $source_file =~ /^lib\/FFI/;
205      my $fh;
206      open $fh, '<', $source_file;
207      while(<$fh>)
208      {
209        if(/^#include [<"](.*?)[>"]/ && $h{$1})
210        {
211          push @deps, @{$h{$1}};
212        }
213      }
214      close $fh;
215    }
216
217    $targets{$ofile} = \@deps;
218  }
219
220  $dynamic_lib .= "\n";
221
222  foreach my $target (sort keys %targets)
223  {
224    $dynamic_lib .= "$target : @{$targets{$target}}\n";
225  }
226
227  $dynamic_lib;
228}
229
230sub postamble {
231  my $postamble = '';
232
233  my $noecho = !!$ENV{V} ? '' : '$(NOECHO) ';
234
235  my $sep = $^O eq 'MSWin32' && $Config{make} eq 'nmake'
236    ? '\\'
237    : '/';
238
239  $postamble .=
240    "flags: _mm${sep}flags\n" .
241    "_mm${sep}flags:\n";
242
243  foreach my $key (qw( cc inc ccflags cccdlflags optimize ld ldflags lddlflags ))
244  {
245    $postamble .=
246      sprintf "\t$noecho\$(FULLPERL) inc${sep}mm-config-set.pl %-20s \$(%s)\n", $key, uc $key;
247  }
248
249  $postamble .=
250    "\t$noecho\$(MKPATH) _mm\n" .
251    "\t$noecho\$(TOUCH) _mm${sep}flags\n\n";
252
253  $postamble .=
254    "probe-runner-builder prb: _mm${sep}probe-builder\n" .
255    "_mm${sep}probe-builder: _mm${sep}flags\n" .
256    "\t$noecho\$(FULLPERL) inc${sep}mm-config-pb.pl\n" .
257    "\t$noecho\$(MKPATH) _mm\n" .
258    "\t$noecho\$(TOUCH) _mm${sep}probe-builder\n\n";
259
260  $postamble .=
261    "config :: _mm${sep}config\n" .
262    "_mm${sep}config: _mm${sep}flags _mm${sep}probe-builder\n" .
263    "\t$noecho\$(FULLPERL) inc${sep}mm-config.pl\n" .
264    "\t$noecho\$(MKPATH) _mm\n" .
265    "\t$noecho\$(TOUCH) _mm${sep}config\n\n";
266
267  $postamble .=
268    "pure_all :: ffi\n" .
269    "ffi: _mm${sep}config\n" .
270    "\t$noecho\$(FULLPERL) inc${sep}mm-build.pl\n\n";
271
272  $postamble .=
273    "subdirs-test_dynamic subdirs-test_static subdirs-test :: ffi-test\n" .
274    "ffi-test : _mm${sep}config\n" .
275    "\t$noecho\$(FULLPERL) inc${sep}mm-test.pl\n\n";
276
277  $postamble .=
278    "clean :: mm-clean\n" .
279    "mm-clean :\n" .
280    "\t$noecho\$(FULLPERL) inc${sep}mm-clean.pl\n" .
281    "\t$noecho\$(RM_RF) _mm ffi-probe-*\n" .
282    "\t$noecho\$(RM_RF) .tmp\n" .
283    "\t$noecho\$(RM_RF) corpus${sep}*${sep}*${sep}tmpbuild*\n\n";
284
285  # Workaround for the tireless testers out there
286  # who want to make -jX a thing.  For some reason.
287  #
288  # When bsd make is passed -jX it turns off compat
289  # mode, even if the Makefile itself turns off
290  # parallel build.  Unfortunately the Makefile
291  # generated by EUMM does not work without compat
292  # mode.  So we:
293  $postamble .=
294    # 1. turn off parallel build using the bsd-only
295    #    faux rule `.NO_PARALLEL` rather than the
296    #    more portable `.NOTPARALLEL`, because this
297    #    will allow parallel build with gmake, which
298    #    does work.
299    ".NO_PARALLEL:\n\n";
300
301  if($^O eq 'MSWin32' && $Config{ccname} eq 'cl')
302  {
303    # nothing.
304  }
305  else
306  {
307    $postamble .=
308      # 2. turn compat mode back on.
309      ".MAKE.MODE=compat\n\n";
310  }
311
312  $postamble;
313}
314
315sub special_targets {
316  my($self, @therest) = @_;
317  my $st = $self->SUPER::special_targets(@therest);
318  $st .= "\n.PHONY: flags probe-runner-builder prb ffi ffi-test\n";
319  $st;
320}
321
3221;
323