perl -c -MModule::Inline::C=PACKAGE blib/lib/Foo/Bar.pm # (or similar) #### package Foo::Bar; use 5.006; use strict; use warnings; our $VERSION = '0.01'; use Module::Inline::C <<'HERE'; int fac (int x) { if (x <= 0) return(1); return(x*fac(x-1)); } HERE # ordinary perl code and more inlined C here # This is for triggering the XS generation if applicable: use Module::Inline::C 'END'; 1; __END__ =head1 NAME Foo::Bar - Perl extension for blah blah blah =cut #### package Module::Inline::C; use strict; use warnings; # Should work for *one Inline::C-using package per distribution only* # right now! our @INLINE_ARGS; our $PACKAGE = 0; sub import { my $class = shift; my @args = @_; if (@args==1 and $args[0] eq 'PACKAGE') { warn 'Setting PACKAGE option'; # trigger packaging/XS generation mode $PACKAGE = 1; return 1; } elsif (@args == 1 and $args[0] eq 'END') { # All C code was received. Generate XS. return unless $PACKAGE; _generate(); } elsif ($PACKAGE == 1) { warn 'Saving arguments to Inline because we\'re in PACKAGE mode'; # Write out C code my ($pkg) = caller(0); push @INLINE_ARGS, {pkg => $pkg, args => \@args}; } else { # try to load dll/so first (user mode) warn 'Trying to load shared obj file'; my ($pkg) = caller(0); require XSLoader; eval { XSLoader::load($pkg); }; return 1 if not $@; # Compile using Inline::C (author mode) warn 'failed to load shared obj file, resorting to inline'; eval "package $pkg; require Inline; Inline->import('C', \@args);"; die $@ if $@; return 1; } } sub _generate { require File::Spec; require Inline::C2XS; mkdir('src'); foreach my $call (@INLINE_ARGS) { my $pkg = $call->{pkg}; if (@{$call->{args}} != 1) { require Data::Dumper; warn "Skipping Inline C call from package $pkg with arguments: ".Dumper($call->{args}); next; } my $file = $pkg; $file =~ s/^(?:[^:]*::)*([^:]+)$/$1/; $file .= '.c'; open my $fh, '>>', File::Spec->catfile('src', $file) or die $!; print $fh "\n".$call->{args}[0]; close $fh; Inline::C2XS::c2xs($pkg, $pkg); } } 1;