summaryrefslogtreecommitdiff
path: root/make_ext.pl
blob: ce63523dce0109c770a36bb503618f69bf1a92dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#!./miniperl
use strict;
use warnings;
use Config;

# This script acts as a simple interface for building extensions.
# It primarily used by the perl Makefile:
#
# d_dummy $(dynamic_ext): miniperl preplibrary FORCE
# 	@$(RUN) ./miniperl make_ext.pl --target=dynamic $@ MAKE=$(MAKE) LIBPERL_A=$(LIBPERL)
#
# It may be deleted in a later release of perl so try to
# avoid using it for other purposes.

my (%excl, %incl, %opts, @extspec, @passthrough);

foreach (@ARGV) {
    if (/^!(.*)$/) {
	$excl{$1} = 1;
    } elsif (/^\+(.*)$/) {
	$incl{$1} = 1;
    } elsif (/^--([\w\-]+)$/) {
	$opts{$1} = 1;
    } elsif (/^--([\w\-]+)=(.*)$/) {
	$opts{$1} = $2;
    } elsif (/^--([\w\-]+)=(.*)$/) {
	$opts{$1} = $2;
    } elsif (/=/) {
	push @passthrough, $_;
    } else {
	push @extspec, $_;
    }
}

my $target   = $opts{target};
my $extspec  = $extspec[0];
my $makecmd  = shift @passthrough; # Should be something like MAKE=make
my $passthru = join ' ', @passthrough; # allow extra macro=value to be passed through
print "\n";

# Previously, $make was taken from config.sh.  However, the user might
# instead be running a possibly incompatible make.  This might happen if
# the user types "gmake" instead of a plain "make", for example.  The
# correct current value of MAKE will come through from the main perl
# makefile as MAKE=/whatever/make in $makecmd.  We'll be cautious in
# case third party users of this script (are there any?) don't have the
# MAKE=$(MAKE) argument, which was added after 5.004_03.
my $make;
if (defined($makecmd) and $makecmd =~ /^MAKE=(.*)$/) {
	$make = $1;
}
else {
	print "ext/util/make_ext:  WARNING:  Please include MAKE=\$(MAKE)\n";
	print "\tin your call to make_ext.  See ext/util/make_ext for details.\n";
	exit(1);
}

# fallback to config.sh's MAKE
$make ||= $Config{make} || $ENV{MAKE};
my $run = $Config{run};
$run = '' if not defined $run;
$run .= ' ' if $run ne '';;

if (!defined($extspec) or $extspec eq '')  {
	print "make_ext: no extension specified\n";
	exit(1);
}

# The Perl Makefile.SH will expand all extensions to
#	lib/auto/X/X.a  (or lib/auto/X/Y/Y.a if nested)
# A user wishing to run make_ext might use
#	X (or X/Y or X::Y if nested)

# canonise into X/Y form (pname)

my $pname = $extspec;
if ($extspec =~ /^lib/) {
	# Remove lib/auto prefix and /*.* suffix
	$pname =~ s{^lib/auto/}{};
	$pname =~ s{[^/]*\.[^/]*$}{};
}
elsif ($extspec =~ /^ext/) {
	# Remove ext/ prefix and /pm_to_blib suffix
	$pname =~ s{^ext/}{};
	$pname =~ s{/pm_to_blib$}{};
}
elsif ($extspec =~ /::/) {
	# Convert :: to /
	$pname =~ s{::}{\/}g;
}
elsif ($extspec =~ /\..*o$/) {
	$pname =~ s/\..*o//;
}

my $mname = $pname;
$mname =~ s!/!::!g;
my $depth = $pname;
$depth =~ s![^/]+!..!g;
my $makefile = "Makefile";
my $makeargs = '';
my $makeopts = '';

if (not -d "ext/$pname") {
	print "\tSkipping $extspec (directory does not exist)\n";
	exit(0); # not an error ?
}

if ($Config{osname} eq 'catamount') {
	# Snowball's chance of building extensions.
	print "This is $Config{osname}, not building $mname, sorry.\n";
	exit(0);
}

print "\tMaking $mname ($target)\n";

chdir("ext/$pname");

# check link type and do any preliminaries.  Valid link types are
# 'dynamic', 'static', and 'static_pic' (the last one respects
# CCCDLFLAGS such as -fPIC -- see static_target in the main Makefile.SH)
if ($target eq 'dynamic') {
	$makeargs = "LINKTYPE=dynamic";
	$target   = 'all';
}
elsif ($target eq 'static') {
	$makeargs = "LINKTYPE=static CCCDLFLAGS=";
	$target   = 'all';
}
elsif ($target eq 'static_pic') {
	$makeargs = "LINKTYPE=static";
	$target   = 'all';
}
elsif ($target eq 'nonxs') {
	$makeargs = "";
	$target   = 'all';
}
elsif ($target =~ /clean$/) {
	# If Makefile has been moved to Makefile.old by a make clean
	# then use Makefile.old for realclean rather than rebuild it
	if (! -f $makefile and -f "Makefile.old") {
		$makefile = "Makefile.old";
		$makeopts = "-f $makefile";
		print "Note: Using Makefile.old\n";
	}
}
elsif ($target eq '') {
	print "make_ext: no make target specified (eg static or dynamic)\n";
	exit(1);
}
else {
	# for the time being we are strict about what make_ext is used for
	print "make_ext: unknown make target '$target'\n";
	exit(1);
}


if (not -f $makefile) {
	if (-f "Makefile.PL") {
		my $cross = $opts{cross} ? ' -MCross' : '';
		system("${run}../$depth/miniperl -I../$depth/lib$cross Makefile.PL INSTALLDIRS=perl INSTALLMAN3DIR=none PERL_CORE=1 $passthru");
	}
	# Right. The reason for this little hack is that we're sitting inside
	# a program run by ./miniperl, but there are tasks we need to perform
	# when the 'realclean', 'distclean' or 'veryclean' targets are run.
	# Unfortunately, they can be run *after* 'clean', which deletes
	# ./miniperl
	# So we do our best to leave a set of instructions identical to what
	# we would do if we are run directly as 'realclean' etc
	# Whilst we're perfect, unfortunately the targets we call are not, as
	# some of them rely on a $(PERL) for their own distclean targets.
	# But this always used to be a problem with the old /bin/sh version of
	# this.
	my $suffix = '.sh';
	foreach my $clean_target ('realclean', 'veryclean') {
		my $file = "../$depth/$clean_target$suffix";
		open my $fh, '>>', $file or die "open $file: $!";
		# Quite possible that we're being run in parallel here.
		# Can't use Fcntl this early to get the LOCK_EX
		flock $fh, 2 or warn "flock $file: $!";
		if ($^O eq 'VMS') {
			# Write out DCL here
		} elsif ($^O eq 'MSWin32') {
			# Might not need anything here.
		} else {
			print $fh <<"EOS";
chdir ext/$pname
if test ! -f $makefile -a -f Makefile.old; then
    echo "Note: Using Makefile.old"
    make -f Makefile.old $clean_target MAKE=$make $passthru
else
    if test ! -f $makefile ; then
	echo "Warning: No Makefile!"
    fi
    make $clean_target MAKE=$make $passthru
fi
chdir ../$depth
EOS
		}
		close $fh or die "close $file: $!";
	}
}

if (not -f $makefile) {
	print "Warning: No Makefile!\n";
}

if ($target eq 'clean') {
}
elsif ($target eq 'realclean') {
}
else {
	# Give makefile an opportunity to rewrite itself.
	# reassure users that life goes on...
	system( "$run$make config MAKE=$make $passthru" )
	  and print "$make config failed, continuing anyway...\n";
}

system(
	"$run$make $target MAKE=$make $makeargs $passthru"
) or exit();

exit($?);