Why not adopt me?
NAME
Panda::Install - ExtUtils::MakeMaker based module installer for XS modules.
DESCRIPTION
Panda::Install makes it much easier to write MakeMaker's makefiles especially for XS modules. It provides dependecies support between XS modules, so that one could easily use header files, code, compilation options, ...etc of another. Panda::Install also lets you put source files in subdirectories any level deep (MakeMaker doesn't handle that) and easily compile-in external C libraries.
The params for Panda::Install are compatible with MakeMaker with some additions.
Also it greatly extends typemap functionality and adds C-like XS synopsis.
SYNOPSIS
# Makefile.PL
use Panda::Install;
write_makefile(
NAME => 'My::XS',
INC => '-Isrc -I/usr/local/libevent/include',
LIBS => '-levent',
SRC => 'src', # all source files (code,header,xs) under 'src' are included in build
C => 'src2/foo.cc src2/bar.cc src3/baz/*.c', # plus src2/foo.cc, src2/bar.cc, and first-level c files in src3/baz/
CPLUS => 1,
PAYLOAD => {
# implements File::ShareDir functionality
'data.txt' => '/data.txt',
'list.txt' => '/',
'abc.dat' => '/mydir/bca.dat',
'payloaddir' => '/',
},
BIN_DEPS => ['XS::Module1', 'XS::Module2'],
BIN_SHARE => {
# modules that depend on My::XS will compile with this INC, LIBS, etc set.
TYPEMAPS => {'typemap1.map' => '/typemap.map'},
INC => '-I/usr/local/libevent/include',
INCLUDE => {'src' => '/'},
LIBS => '-levent',
DEFINE => '-DHELLO_FROM_MYXS',
CCFLAGS => 'something',
},
postamble => 'mytarget: blah-blah; echo "hello"',
CLIB => [{
DIR => 'libuv',
FILE => 'libuv.a',
TARGET => 'libuv.a',
FLAGS => 'CFLAGS="-fPIC -O2"',
}],
);
LOADING XS MODULE SYNOPSIS
package MyXSModule;
use Panda::XSLoader;
our $VERSION = '1.0.0';
Panda::XSLoader::load(); # same as Panda::XSLoader::load('MyXSModule', $VERSION, 0x01);
see Panda::XSLoader
TYPEMAP INHERITANCE SYNOPSIS
T_TYPE1
mycode1;
T_TYPE2 : T_TYPE1
mycode2;
C-LIKE XS SYNOPSIS
char* my_xs_sub (SV* sv) { // CODE
if (badsv(sv)) XSRETURN_UNDEF;
RETVAL = process(sv);
}
void other_xs_sub (SV* sv) : ALIAS(other_name=1, yet_another=2) { // PPCODE
xPUSHi(1);
xPUSHi(2);
}
GETTING PAYLOAD SYNOPSIS
my $payload_dir = Panda::Install::Payload::payload_dir('My::Module');
TYPEMAP CAST SYNOPSIS
bool
filter (AV* users, const char* what)
CODE:
for (int i = 0; i <= av_len(users); ++i) {
User* user = typemap_incast<User*>(av_fetch(users, i, 0));
if (...) XSRETURN_TRUE;
}
XSRETURN_FALSE;
OUTPUT:
RETVAL
AV*
MyStorage::get_sites ()
CODE:
RETVAL = newAV();
for (int i = 0; i < THIS->urls.length(); ++i) {
SV* uri_perl_obj = typemap_outcast<URI*, const char* CLASS>(THIS->urls[i], "My::URI");
av_push(RETVAL, uri_perl_obj);
}
OUTPUT:
RETVAL
FUNCTIONS
write_makefile(%params)
Same as WriteMakefile(makemaker_args(%params))
makemaker_args(%params)
Processes %params, does all the neccessary job and returns final parameters for passing to MakeMaker's WriteMakefile.
PARAMETERS
Only differences from MakeMaker params are listed.
- ALL_FROM [default: NAME]
-
Sets ABSTRACT_FROM and VERSION_FROM to value of ALL_FROM.
If not defined, defaults to NAME. That means that if you have version and abstract in your module's main package, then you don't need to define anything.
- XS [*.xs]
-
Sets source files for xsubpp. If you define this param, defaults are aborted.
XS => 'myxs/*.xs' XS => 'file1.xs folder/file2.xs folder2/*.xs' XS => ['file1.xs', 'folder/file2.xs folder2/*.xs']
- C [*.c, *.cc, *.cxx, *.cpp, <xsubpp's output files>]
-
Sets source files to compile. If you define this param, defaults are aborted, however C files created by xsubpp are still included.
Usage: see "XS".
- H [*.h *.hh *.hxx *.hpp]
-
Sets header files for makefile's dependencies (forces module to recompile if any of these changes). Useful during development. If you define this param, defaults are aborted.
Usage: see "XS".
- SRC
-
Scans specified folder(s), finds all XS, C and H files and includes them in build. No matter whether you define XS/C/H parameters or not, SRCs are always added to them.
SRC => 'src' SRC => 'src src2 src3', SRC => ['src src2', 'src3'],
- CPLUS
-
If true, will use c++ to build current extension.
- postamble
-
Passed unchanged to Makefile. Can be HASHREF for your convenience, in which case keys are ignored, values are concatenated.
postamble => 'sayhello: ; echo "hello"' postamble => { memd_dep => 'linkext:: libmemd/libmemd.a; cd libmemd && $(MAKE) static', memd_clean => 'clean:: ; cd libmemd && $(MAKE) clean', }
- MIN_PERL_VERSION [5.10.0]
-
Is set to 5.10.0 if you don't provide it.
- PAYLOAD
-
Implements File::ShareDir functionality. Specified files are installed together with module and can later be accessed at runtime by the module itself or by other modules (via Panda::Install::Payload's payload_dir()).
Value is a HASHREF where key is a file or directory path relative to module's dist dir and value is relative to payload's installation dir. If key is a directory then all content of that directory is installed to the destination path. If value is not specified (undef, '') then dest path is the same as source path.
Examples (given that $payload is a directory where payload is installed and $dist is a module's dist dir):
'file.txt' => '' # $dist/file.txt => $payload/file.txt 'file.txt' => 'a.txt' # $dist/file.txt => $payload/a.txt 'mydir' => '', # $dist/mydir => $payload/mydir 'mydir' => 'a/b/c', # $dist/mydir/* => $payload/a/b/c/* 'mydir' => '/', # $dist/mydir/* => $payload/*
- BIN_DEPS
-
List of modules current module binary depends on. That means all that those modules specified in BIN_SHARE section will be applied while building current module. It also adds those modules to CONFIGURE_REQUIRES and PREREQ_PM sections.
Also if your module has BIN_SHARE section then all modules in BIN_DEPS goes to BIN_SHARE/PASSTHROUGH unless module name is prefixed with '-' (minus).
Examples:
BIN_DEPS => 'Module1' BIN_DEPS => ['Module1', '-Module2']
- BIN_SHARE
-
In this section you put values that you want to be applied to any module which specified your module as a dependency.
- BIN_SHARE/TYPEMAPS
-
Installs specified typemaps and also adds it to the list of typemaps when building descendant modules.
Receives HASHREF, format is the same as for PAYLOAD, the only difference is that it scans folders for *.map files only.
- BIN_SHARE/INC
-
Adds include file dirs to INC when building descendant modules.
- BIN_SHARE/INCLUDE
-
Installs specified include files/dirs into module's installation include directory and adds that directory to INC when building descendant modules.
Receives HASHREF, format is the same as for PAYLOAD, the only difference is that it scans folders for header files only.
- BIN_SHARE/LIBS
-
Added to LIBS when building descendant modules.
- BIN_SHARE/DEFINE
-
Added to DEFINE when building descendant modules.
- BIN_SHARE/CCFLAGS
-
Added to CCFLAGS when building descendant modules.
- BIN_SHARE/XSOPT
-
Added to XSOPT when building descendant modules.
- BIN_SHARE/PASSTHROUGH
-
Merge 'BIN_SHARE' of this module with 'BIN_SHARE' of specified modules. Everything gets concatenated (strings, arrays, etc) while merging. You don't need to manually manage this setting as it's managed automatically (see BIN_DEPS section).
- CLIB
-
List of external C libraries that need to be built and compiled into the extension.
- CLIB/DIR
-
Directory where external library is. Makefile must present in that directory!
- CLIB/FILE
-
Static library file which is built by the library (relative to CLIB/DIR).
- CLIB/TARGET
-
Name of the target for Makefile to built static library.
- CLIB/FLAGS
-
Flags to build external library with.
TYPEMAP FEATURES
TYPEMAP INHERITANCE
Output typemaps
T_TYPE1
mycode1;
T_TYPE2 : T_TYPE1
mycode2;
T_TYPE2 will have mycode1 inserted after mycode2 as if it was written
T_TYPE2
mycode2;
mycode1;
Input typemaps
T_TYPE1
mycode1;
T_TYPE2 : T_TYPE1
mycode2;
T_TYPE2 will have mycode1 inserted before mycode2 as if it was written
T_TYPE2
mycode1;
mycode2;
Passing params
You can pass params when inheriting typemaps. These params can be accessed in parent typemap.
T_TYPE1
int $varname = 150;
mycode1;
$expr;
T_TYPE2 : T_TYPE1(varname=myvar, expr="myvar = a + b")
mycode2;
will result in (for input typemap)
T_TYPE2
int myvar = 150;
mycode1;
myvar = a + b;
mycode2;
TYPEMAP INIT BLOCKS
In OUTPUT typemaps you can use INIT { block }
expressions. These blocks later will be moved to the top of the XS function like INIT:
section of XS function itself. It is useful for typemaps which want to predefine some variable, so that user has a chance to change it. Such typemaps then use this variable in its code. For example:
TYPEMAP
int MY_TYPE
OUTPUT
MY_TYPE
INIT {
int lolo = 0;
// something else
}
sv_setiv($arg, $var + lolo);
#XS
int
myfunc ()
CODE:
lolo = 10;
RETVAL = 20; // returns 30
OUTPUT:
RETVAL;
INIT
blocks are not evaled by typemaps and goes through as-is, so that you cannot use $arg
, $var
, etc inside its code.
TYPEMAP INIT_OUTPUT BLOCKS
In OUTPUT typemaps you can use INIT_OUTPUT { block }
expressions. These blocks later will be moved to the top of the resulting output typemap code (after all inheritances). The are concatenated in reverse order, i.e. the most-base typemap's first. INIT_OUTPUT
is useful for example when you want to cancel all output-related typemap code and return something different. As an example, Panda::XS backreferencing technique use it. These blocks are evaled normally.
TYPEMAP DESTROY BLOCKS
In INPUT typemaps you can use DESTROY { block }
expressions. These expressions are inserted into DESTROY
function, before any user-defined code in DESTROY
method is executed, and after input typemap runs, so that THIS
is visible. Blocks are inserted in order from derived to parent. These blocks are evaled normally.
TYPEMAP CAST
Sometimes the type of data you receive or return depends on something and therefore you cannot use certain input or output typemap. To help you dealing with this, there are typemap input and output cast operators (for XS code).
template <class T> T typemap_incast (SV* input)
Does what INPUT typemap "T" would do. Returns T.
Can ONLY be used inside XS functions.
template <class T> SV* typemap_outcast (T output)
Does what OUTPUT typemap "T" would do. Returns SV*.
Can ONLY be used inside XS functions.
template <class T, arg def1, arg def2, ...> SV* typemap_outcast (T output, arg1, arg2, ...)
This is an extended version of typemap_outcast, which is useful if typemap "T" requires additional variables to be predefined. For example, typemaps which create objects, often require "const char* CLASS = ..." variable to be defined. In this case you need to define these variables right after typemap type and pass all of them as a parameters to typemap cast function:
... = typemap_outcast<MyClass*, const char* CLASS, bool do_checks, SV* extra>(new MyClass(), "My::Class", true, myextra);
C-LIKE XS
If you're using Panda::Install then all of your XS files support C-like XS. It means that code
char* my_xs_sub (SV* sv) { // CODE
if (badsv(sv)) XSRETURN_UNDEF;
RETVAL = process(sv);
}
void other_xs_sub (SV* sv) : ALIAS(other_name=1, yet_another=2) { // PPCODE
xPUSHi(1);
xPUSHi(2);
}
is replaced with code
char*
my_xs_sub (SV* sv)
CODE:
if (badsv(sv)) XSRETURN_UNDEF;
RETVAL = process(sv);
OUTPUT:
RETVAL
void
other_xs_sub (SV* sv)
ALIAS:
other_name=1
yet_another=2
PPCODE:
xPUSHi(1);
xPUSHi(2);
Note that writing
int myfunc (int a)
will result in default ParseXS behaviour (calling C function myfunc(a) and returning its result). That's because it has no body.
However this function has a body (empty) and therefore prevents default behaviour
int myfunc (int a) {}
AUTHOR
Pronin Oleg <syber@crazypanda.ru>, Crazy Panda, CP Decision LTD
LICENSE
You may distribute this code under the same terms as Perl itself.