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