This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Refactor ExtUtils::Miniperl to use ExtUtils::Embed.
[perl5.git] / lib / ExtUtils / Embed.pm
CommitLineData
a2c6f8f1 1require 5.002;
2
3package ExtUtils::Embed;
4require Exporter;
a2c6f8f1 5use Config;
566e3efe 6require File::Spec;
a2c6f8f1 7
8#Only when we need them
9#require ExtUtils::MakeMaker;
10#require ExtUtils::Liblist;
11
12use vars qw(@ISA @EXPORT $VERSION
13 @Extensions $Verbose $lib_ext
14 $opt_o $opt_s
15 );
16use strict;
17
7975e7c1 18# This is not a dual-life module, so no need for development version numbers
566e3efe 19$VERSION = '1.31';
a2c6f8f1 20
21@ISA = qw(Exporter);
22@EXPORT = qw(&xsinit &ldopts
23 &ccopts &ccflags &ccdlflags &perl_inc
24 &xsi_header &xsi_protos &xsi_body);
25
a2c6f8f1 26$Verbose = 0;
27$lib_ext = $Config{lib_ext} || '.a';
28
7e24002c
DM
29sub is_cmd { $0 eq '-e' }
30
31sub my_return {
32 my $val = shift;
33 if(is_cmd) {
34 print $val;
35 }
36 else {
37 return $val;
38 }
39}
40
a2c6f8f1 41sub xsinit {
42 my($file, $std, $mods) = @_;
43 my($fh,@mods,%seen);
44 $file ||= "perlxsi.c";
acfe0abc 45 my $xsinit_proto = "pTHX";
a2c6f8f1 46
47 if (@_) {
48 @mods = @$mods if $mods;
49 }
50 else {
566e3efe
NC
51 require Getopt::Std;
52 Getopt::Std::getopts('o:s:');
a2c6f8f1 53 $file = $opt_o if defined $opt_o;
54 $std = $opt_s if defined $opt_s;
55 @mods = @ARGV;
56 }
57 $std = 1 unless scalar @mods;
58
59 if ($file eq "STDOUT") {
60 $fh = \*STDOUT;
61 }
62 else {
566e3efe
NC
63 open $fh, '>', $file
64 or die "Can't open '$file': $!";
a2c6f8f1 65 }
66
67 push(@mods, static_ext()) if defined $std;
68 @mods = grep(!$seen{$_}++, @mods);
69
70 print $fh &xsi_header();
5ec3aaed 71 print $fh "\nEXTERN_C void xs_init ($xsinit_proto);\n\n";
a2c6f8f1 72 print $fh &xsi_protos(@mods);
73
8bdb6b78 74 print $fh "\nEXTERN_C void\nxs_init($xsinit_proto)\n{\n";
a2c6f8f1 75 print $fh &xsi_body(@mods);
76 print $fh "}\n";
77
78}
79
80sub xsi_header {
81 return <<EOF;
5ec3aaed
NC
82#include "EXTERN.h"
83#include "perl.h"
84#include "XSUB.h"
a2c6f8f1 85EOF
86}
87
88sub xsi_protos {
89 my(@exts) = @_;
90 my(@retval,%seen);
acfe0abc 91 my $boot_proto = "pTHX_ CV* cv";
a2c6f8f1 92 foreach $_ (@exts){
93 my($pname) = canon('/', $_);
94 my($mname, $cname);
95 ($mname = $pname) =~ s!/!::!g;
96 ($cname = $pname) =~ s!/!__!g;
20ce7b12 97 my($ccode) = "EXTERN_C void boot_${cname} ($boot_proto);\n";
a2c6f8f1 98 next if $seen{$ccode}++;
99 push(@retval, $ccode);
100 }
101 return join '', @retval;
102}
103
104sub xsi_body {
105 my(@exts) = @_;
106 my($pname,@retval,%seen);
107 my($dl) = canon('/','DynaLoader');
5ec3aaed
NC
108 push(@retval, " static const char file[] = __FILE__;\n")
109 if @exts;
110 push(@retval, " dXSUB_SYS;\n");
111 push(@retval, " PERL_UNUSED_CONTEXT;\n");
112 push(@retval, "\n")
113 if @exts;
a2c6f8f1 114
115 foreach $_ (@exts){
116 my($pname) = canon('/', $_);
117 my($mname, $cname, $ccode);
118 ($mname = $pname) =~ s!/!::!g;
119 ($cname = $pname) =~ s!/!__!g;
120 if ($pname eq $dl){
121 # Must NOT install 'DynaLoader::boot_DynaLoader' as 'bootstrap'!
122 # boot_DynaLoader is called directly in DynaLoader.pm
5ec3aaed 123 $ccode = " /* DynaLoader is a special case */\n newXS(\"${mname}::boot_${cname}\", boot_${cname}, file);\n";
a2c6f8f1 124 push(@retval, $ccode) unless $seen{$ccode}++;
125 } else {
5ec3aaed 126 $ccode = " newXS(\"${mname}::bootstrap\", boot_${cname}, file);\n";
a2c6f8f1 127 push(@retval, $ccode) unless $seen{$ccode}++;
128 }
129 }
130 return join '', @retval;
131}
132
133sub static_ext {
134 unless (scalar @Extensions) {
d0cbb09d
RU
135 my $static_ext = $Config{static_ext};
136 $static_ext =~ s/^\s+//;
137 @Extensions = sort split /\s+/, $static_ext;
a2c6f8f1 138 unshift @Extensions, qw(DynaLoader);
139 }
140 @Extensions;
141}
142
03f2ffd8
JH
143sub _escape {
144 my $arg = shift;
0ab03fee 145 return $$arg if $^O eq 'VMS'; # parens legal in qualifier lists
03f2ffd8
JH
146 $$arg =~ s/([\(\)])/\\$1/g;
147}
148
f0595bdd
JH
149sub _ldflags {
150 my $ldflags = $Config{ldflags};
03f2ffd8 151 _escape(\$ldflags);
f0595bdd
JH
152 return $ldflags;
153}
154
155sub _ccflags {
156 my $ccflags = $Config{ccflags};
03f2ffd8 157 _escape(\$ccflags);
f0595bdd
JH
158 return $ccflags;
159}
160
161sub _ccdlflags {
162 my $ccdlflags = $Config{ccdlflags};
03f2ffd8 163 _escape(\$ccdlflags);
f0595bdd
JH
164 return $ccdlflags;
165}
166
a2c6f8f1 167sub ldopts {
168 require ExtUtils::MakeMaker;
169 require ExtUtils::Liblist;
170 my($std,$mods,$link_args,$path) = @_;
171 my(@mods,@link_args,@argv);
172 my($dllib,$config_libs,@potential_libs,@path);
173 local($") = ' ' unless $" eq ' ';
a2c6f8f1 174 if (scalar @_) {
175 @link_args = @$link_args if $link_args;
176 @mods = @$mods if $mods;
177 }
178 else {
179 @argv = @ARGV;
180 #hmm
181 while($_ = shift @argv) {
182 /^-std$/ && do { $std = 1; next; };
183 /^--$/ && do { @link_args = @argv; last; };
184 /^-I(.*)/ && do { $path = $1 || shift @argv; next; };
185 push(@mods, $_);
186 }
187 }
188 $std = 1 unless scalar @link_args;
9bbedd82
JH
189 my $sep = $Config{path_sep} || ':';
190 @path = $path ? split(/\Q$sep/, $path) : @INC;
a2c6f8f1 191
192 push(@potential_libs, @link_args) if scalar @link_args;
9bbedd82
JH
193 # makemaker includes std libs on windows by default
194 if ($^O ne 'MSWin32' and defined($std)) {
195 push(@potential_libs, $Config{perllibs});
196 }
a2c6f8f1 197
198 push(@mods, static_ext()) if $std;
199
200 my($mod,@ns,$root,$sub,$extra,$archive,@archives);
201 print STDERR "Searching (@path) for archives\n" if $Verbose;
202 foreach $mod (@mods) {
3ab83790 203 @ns = split(/::|\/|\\/, $mod);
a2c6f8f1 204 $sub = $ns[-1];
56c2fb36 205 $root = File::Spec->catdir(@ns);
a2c6f8f1 206
207 print STDERR "searching for '$sub${lib_ext}'\n" if $Verbose;
208 foreach (@path) {
56c2fb36 209 next unless -e ($archive = File::Spec->catdir($_,"auto",$root,"$sub$lib_ext"));
a2c6f8f1 210 push @archives, $archive;
56c2fb36 211 if(-e ($extra = File::Spec->catdir($_,"auto",$root,"extralibs.ld"))) {
a2c6f8f1 212 local(*FH);
213 if(open(FH, $extra)) {
214 my($libs) = <FH>; chomp $libs;
215 push @potential_libs, split /\s+/, $libs;
216 }
217 else {
218 warn "Couldn't open '$extra'";
219 }
220 }
221 last;
222 }
223 }
224 #print STDERR "\@potential_libs = @potential_libs\n";
225
9bbedd82
JH
226 my $libperl;
227 if ($^O eq 'MSWin32') {
228 $libperl = $Config{libperl};
229 }
2f3efc97
JH
230 elsif ($^O eq 'os390' && $Config{usedl}) {
231 # Nothing for OS/390 (z/OS) dynamic.
232 } else {
9720141b
MR
233 $libperl = (grep(/^-l\w*perl\w*$/, @link_args))[0]
234 || ($Config{libperl} =~ /^lib(\w+)(\Q$lib_ext\E|\.\Q$Config{dlext}\E)$/
235 ? "-l$1" : '')
2f3efc97 236 || "-lperl";
9bbedd82 237 }
af248097 238
9bbedd82
JH
239 my $lpath = File::Spec->catdir($Config{archlibexp}, 'CORE');
240 $lpath = qq["$lpath"] if $^O eq 'MSWin32';
a2c6f8f1 241 my($extralibs, $bsloadlibs, $ldloadlibs, $ld_run_path) =
5de3f0da 242 MM->ext(join ' ', "-L$lpath", $libperl, @potential_libs);
a2c6f8f1 243
244 my $ld_or_bs = $bsloadlibs || $ldloadlibs;
245 print STDERR "bs: $bsloadlibs ** ld: $ldloadlibs" if $Verbose;
f0595bdd
JH
246 my $ccdlflags = _ccdlflags();
247 my $ldflags = _ldflags();
248 my $linkage = "$ccdlflags $ldflags @archives $ld_or_bs";
a2c6f8f1 249 print STDERR "ldopts: '$linkage'\n" if $Verbose;
250
251 return $linkage if scalar @_;
7e24002c 252 my_return("$linkage\n");
a2c6f8f1 253}
254
255sub ccflags {
f0595bdd
JH
256 my $ccflags = _ccflags();
257 my_return(" $ccflags ");
a2c6f8f1 258}
259
260sub ccdlflags {
f0595bdd
JH
261 my $ccdlflags = _ccdlflags();
262 my_return(" $ccdlflags ");
a2c6f8f1 263}
264
265sub perl_inc {
9bbedd82
JH
266 my $dir = File::Spec->catdir($Config{archlibexp}, 'CORE');
267 $dir = qq["$dir"] if $^O eq 'MSWin32';
268 my_return(" -I$dir ");
a2c6f8f1 269}
270
271sub ccopts {
7e24002c 272 ccflags . perl_inc;
a2c6f8f1 273}
274
275sub canon {
276 my($as, @ext) = @_;
277 foreach(@ext) {
278 # might be X::Y or lib/auto/X/Y/Y.a
279 next if s!::!/!g;
280 s:^(lib|ext)/(auto/)?::;
281 s:/\w+\.\w+$::;
282 }
f84167b3 283 map(s:/:$as:, @ext) if ($as ne '/');
a2c6f8f1 284 @ext;
285}
286
287__END__
288
289=head1 NAME
290
291ExtUtils::Embed - Utilities for embedding Perl in C/C++ applications
292
293=head1 SYNOPSIS
294
295
296 perl -MExtUtils::Embed -e xsinit
9bbedd82 297 perl -MExtUtils::Embed -e ccopts
a2c6f8f1 298 perl -MExtUtils::Embed -e ldopts
299
300=head1 DESCRIPTION
301
302ExtUtils::Embed provides utility functions for embedding a Perl interpreter
303and extensions in your C/C++ applications.
304Typically, an application B<Makefile> will invoke ExtUtils::Embed
305functions while building your application.
306
307=head1 @EXPORT
308
309ExtUtils::Embed exports the following functions:
a6006777 310
4e864201
JM
311xsinit(), ldopts(), ccopts(), perl_inc(), ccflags(),
312ccdlflags(), xsi_header(), xsi_protos(), xsi_body()
a2c6f8f1 313
314=head1 FUNCTIONS
315
bbc7dcd2 316=over 4
2ae324a7 317
a2c6f8f1 318=item xsinit()
319
4e864201 320Generate C/C++ code for the XS initializer function.
a2c6f8f1 321
322When invoked as C<`perl -MExtUtils::Embed -e xsinit --`>
323the following options are recognized:
324
4e864201 325B<-o> E<lt>output filenameE<gt> (Defaults to B<perlxsi.c>)
a2c6f8f1 326
327B<-o STDOUT> will print to STDOUT.
328
329B<-std> (Write code for extensions that are linked with the current Perl.)
330
331Any additional arguments are expected to be names of modules
332to generate code for.
333
334When invoked with parameters the following are accepted and optional:
335
336C<xsinit($filename,$std,[@modules])>
337
338Where,
339
340B<$filename> is equivalent to the B<-o> option.
341
342B<$std> is boolean, equivalent to the B<-std> option.
343
344B<[@modules]> is an array ref, same as additional arguments mentioned above.
345
346=item Examples
347
a6006777 348
a2c6f8f1 349 perl -MExtUtils::Embed -e xsinit -- -o xsinit.c Socket
350
351
352This will generate code with an B<xs_init> function that glues the perl B<Socket::bootstrap> function
a7665c5e 353to the C B<boot_Socket> function and writes it to a file named F<xsinit.c>.
a2c6f8f1 354
355Note that B<DynaLoader> is a special case where it must call B<boot_DynaLoader> directly.
356
357 perl -MExtUtils::Embed -e xsinit
358
359
360This will generate code for linking with B<DynaLoader> and
361each static extension found in B<$Config{static_ext}>.
362The code is written to the default file name B<perlxsi.c>.
363
364
365 perl -MExtUtils::Embed -e xsinit -- -o xsinit.c -std DBI DBD::Oracle
366
367
368Here, code is written for all the currently linked extensions along with code
369for B<DBI> and B<DBD::Oracle>.
370
371If you have a working B<DynaLoader> then there is rarely any need to statically link in any
372other extensions.
373
374=item ldopts()
375
376Output arguments for linking the Perl library and extensions to your
377application.
378
379When invoked as C<`perl -MExtUtils::Embed -e ldopts --`>
380the following options are recognized:
381
382B<-std>
383
384Output arguments for linking the Perl library and any extensions linked
385with the current Perl.
386
4e864201 387B<-I> E<lt>path1:path2E<gt>
a2c6f8f1 388
389Search path for ModuleName.a archives.
390Default path is B<@INC>.
391Library archives are expected to be found as
392B</some/path/auto/ModuleName/ModuleName.a>
393For example, when looking for B<Socket.a> relative to a search path,
394we should find B<auto/Socket/Socket.a>
395
396When looking for B<DBD::Oracle> relative to a search path,
397we should find B<auto/DBD/Oracle/Oracle.a>
398
a7665c5e 399Keep in mind that you can always supply B</my/own/path/ModuleName.a>
a2c6f8f1 400as an additional linker argument.
401
4e864201 402B<--> E<lt>list of linker argsE<gt>
a2c6f8f1 403
404Additional linker arguments to be considered.
405
406Any additional arguments found before the B<--> token
407are expected to be names of modules to generate code for.
408
409When invoked with parameters the following are accepted and optional:
410
411C<ldopts($std,[@modules],[@link_args],$path)>
412
a7665c5e 413Where:
a2c6f8f1 414
415B<$std> is boolean, equivalent to the B<-std> option.
416
417B<[@modules]> is equivalent to additional arguments found before the B<--> token.
418
419B<[@link_args]> is equivalent to arguments found after the B<--> token.
420
421B<$path> is equivalent to the B<-I> option.
422
423In addition, when ldopts is called with parameters, it will return the argument string
424rather than print it to STDOUT.
425
426=item Examples
427
428
429 perl -MExtUtils::Embed -e ldopts
430
431
a90be013 432This will print arguments for linking with B<libperl> and
a2c6f8f1 433extensions found in B<$Config{static_ext}>. This includes libraries
434found in B<$Config{libs}> and the first ModuleName.a library
435for each extension that is found by searching B<@INC> or the path
de592821 436specified by the B<-I> option.
a2c6f8f1 437In addition, when ModuleName.a is found, additional linker arguments
438are picked up from the B<extralibs.ld> file in the same directory.
439
440
441 perl -MExtUtils::Embed -e ldopts -- -std Socket
a6006777 442
a2c6f8f1 443
444This will do the same as the above example, along with printing additional arguments for linking with the B<Socket> extension.
445
a2c6f8f1 446 perl -MExtUtils::Embed -e ldopts -- -std Msql -- -L/usr/msql/lib -lmsql
447
a2c6f8f1 448Any arguments after the second '--' token are additional linker
449arguments that will be examined for potential conflict. If there is no
450conflict, the additional arguments will be part of the output.
451
452
453=item perl_inc()
454
455For including perl header files this function simply prints:
456
36477c24 457 -I$Config{archlibexp}/CORE
a2c6f8f1 458
459So, rather than having to say:
460
36477c24 461 perl -MConfig -e 'print "-I$Config{archlibexp}/CORE"'
a2c6f8f1 462
463Just say:
464
465 perl -MExtUtils::Embed -e perl_inc
466
467=item ccflags(), ccdlflags()
468
469These functions simply print $Config{ccflags} and $Config{ccdlflags}
470
471=item ccopts()
472
473This function combines perl_inc(), ccflags() and ccdlflags() into one.
474
475=item xsi_header()
476
477This function simply returns a string defining the same B<EXTERN_C> macro as
478B<perlmain.c> along with #including B<perl.h> and B<EXTERN.h>.
479
480=item xsi_protos(@modules)
481
482This function returns a string of B<boot_$ModuleName> prototypes for each @modules.
483
484=item xsi_body(@modules)
485
486This function returns a string of calls to B<newXS()> that glue the module B<bootstrap>
487function to B<boot_ModuleName> for each @modules.
488
022735b4 489B<xsinit()> uses the xsi_* functions to generate most of its code.
a2c6f8f1 490
2ae324a7 491=back
492
a2c6f8f1 493=head1 EXAMPLES
494
495For examples on how to use B<ExtUtils::Embed> for building C/C++ applications
0325b4c4 496with embedded perl, see L<perlembed>.
a6006777 497
a2c6f8f1 498=head1 SEE ALSO
499
4e864201 500L<perlembed>
a2c6f8f1 501
502=head1 AUTHOR
503
4e864201 504Doug MacEachern E<lt>F<dougm@osf.org>E<gt>
a2c6f8f1 505
4e864201
JM
506Based on ideas from Tim Bunce E<lt>F<Tim.Bunce@ig.co.uk>E<gt> and
507B<minimod.pl> by Andreas Koenig E<lt>F<k@anna.in-berlin.de>E<gt> and Tim Bunce.
a2c6f8f1 508
509=cut
510