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