NAME
Module::CAPIMaker - Provide a C API for your XS modules
SYNOPSIS
perl -MModule::CAPIMaker -e make_c_api
DESCRIPTION
If you are the author of a Perl module written using XS. Using Module::CAPIMaker you will be able to provide your module users with an easy and efficient way to access its functionality directly from their own XS modules.
UNDER THE HOOD
The exporting/importing of the functions provided through the C API is completely handled by the support files generated by Module::CAPIMaker, and not the author of the module providing the API, neither the authors of the client modules need really to know how it works but on the other hand it does not harm to understand it and anyway it will probably easy the understanding of the module usage. So, read on :-) ..
Suppose that we have one module Foo::XS
Foo::XS
providing a C API with the help of Module::CAPIMaker and another module Bar
that uses that API.
When Foo::XS
is loaded, the addresses of the functions available through the C API are published on the global hash %Foo::XS::C_API
.
When Bar
loads, first, it ensures that Foo::XS
is loaded (loading it if required) and checks that the versions of the C API supported by the version of Foo::XS
loaded include the version required. Then, it copies the pointers on the %Foo::XS::C_API
hash to C static storage where they can be efficiently accessed without performing a hash look-up every time.
Finally calls on Bar to the C functions from Foo::XS
are transparently routed through these pointers with the help of some wrapping macros.
STRUCTURE OF THE C API
The C API is defined in a file named c_api.decl
. This file may contain the prototypes of the functions that will be available through the C API and several configuration settings.
From this file, Module::CAPIMaker
generates two sets of files, one set contains the files that are used by the module providing the C API in order to support it. The other set is to be used by client modules.
They are as follows:
C API provider support files
On the C API provider side, a file named c_api.h
is generated. It defines the initialization function that populates the %C_API
hash.
Client support files
There are two main files to be used by client modules, one is perl_${c_module_name}.c
containing the definition of the client side C API initialization function.
The second file is perl_${c_module_name}.h
containing the prototypes of the functions made available through the C API and a set of macros to easy their usage.
${c_module_name}
is the module name lower-cased and with every non-alphanumeric sequence replaced by a underscore in order to make in C friendly. For instance, Foo::XS
becomes foo_xs
and the files generated are perl_foo_xs.c
and perl_foo_xs.h
.
A sample/skeleton Sample.xs
file is also generated.
The client files go into the directory c_api_client
where you may also like to place additional files as for instance a typemap
file.
C API DEFINITION
The C API is defined through the file c_api.decl
.
Two types of entries can be included in this file: function prototypes and configuration settings.
Function declarations
Function declarations are identical to those you will use in a C header file (without the semicolon at the end). In example:
int foo(double)
char *bar(void)
Functions that use the THX macros are also accepted:
SV *make_object(pTHX_ double *)
You have to use the prototype variant (pTHX
or pTHX_
) and Module::CAPIMaker will replace it automatically by the correct variant of the macro depending of the usage.
Configuration settings
Configuration settings are of the form key=value
where key must match /^\w+$/ and value can be anything. For instance
module_name = Foo::XS
author = Valentine Michael Smith
A backslash at the end of the line indicates that the following line is a continuation of the current one:
some_words = bicycle automobile \
house duck
Here-docs can also be used:
some_more_words = <<END
car pool tree
disc book
END
The following configuration settings are currently supported by the module:
- module_name
-
Perl name of the module, for instance,
Foo::XS
. - c_module_name = foo_bar
-
C-friendly name of the module, for instance
foo_xs
- module_version
-
Version of the Perl module. This variable should actually be set from the
Makefile.PL
script and is not used internally by the C API support functions. It just appears on the comments of the generated files. -
Name of the module author, to be included on the headers of the generated files.
- min_version
- max_version
- required_version
-
In order to support evolution of the C API a min/max version approach is used.
The
min_version
/max_version
numbers are made available through the%C_API
hash. When the client module loads, it checks that the version it requires lays between these two numbers or otherwise croaks with an error.By default
required_version
is made equal tomax_version
. - client_dir
-
The directory where the client support files are placed. By default
c_api_client
. - module_h_filename
-
Name of the client support header file (i.e.
perl_foo_xs.h
). - module_c_filename
-
Name of the client C file providing the function to initialize the client side of the C API (i.e.
perl_foo_xs.c
). - c_api_h_filename
-
Name of the support file used on the C API provider side. Its default value is
c_api.h
. - module_h_barrier
-
Name of the macro used to avoid multiple loading of the definitions inside
${module_h_filename}
.It defaults to
uc("${c_module_name}_H_INCLUDED")
. For instancePERL_FOO_XS_H_INCLUDED
. - c_api_h_barrier
-
Name of the macro used to avoid multiple loading of the definitions on the header file
c_api.h
. It defaults toC_API_H_INCLUDED
. - export_prefix
-
It's possible to add a prefix to the name of the functions exported through the C API in the client side.
For instance, if the function
bar()
is exported from the moduleFoo::XS
, settingexport_prefix=foo_
will make that function available on the client module asfoo_bar()
. - module_c_beginning
-
The text in this variable is placed inside the file
${module_c_filename}
at some early point. It can be used to inject typedefs and other definitions needed to make the file compile. - module_c_end
-
The text inside this variable is placed at the end of the file
${module_c_filename}
. - module_h_beginning
-
The text inside this variable is placed inside the file
${module_h_filename}
at some early point. - module_h_end
-
The text inside this variable is placed at the end of the file
${module_h_filename}
. - c_api_decl_filename
-
The name of the file with the definition of the C API. Defaults to
c_api.decl
.Obviously this setting can only be set from the command line!
- module_c_template_filename
- module_h_template_filename
- sample_xs_template_filename
- c_api_h_template_filename
-
Internally the module uses Text::Template to generate the support files with a set of default templates. For maximum customizability a different set of templates can be used.
RUNNING THE C API GENERATOR
Once your c_api.decl
file is ready use Module::CAPIMaker
to generate the C API running the companion script make_perl_module_c_api
. This script also accept a list of configuration setting from the command line. For instance:
make_perl_module_c_api module_name=Foo::XS \
author="Valentine Michael Smith"
If you want to do it from some Perl script, you can also use the make_c_api sub
exported by this module.
INITIALIZING THE C API
In order to initialize the C API from the module supporting it you have to perform the following two changes on your XS file:
Include
c_api.h
.Call the macro
INIT_C_API
from theBOOT
section.
For instance,
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
/* your C code goes here */
#include "c_api.h"
MODULE = Foo::XS PACKAGE = Foo::XS
BOOT:
INIT_C_API;
/* your XS function declarations go here */
AUTOMATIC C API GENERATION WITH ExtUtils::MakeMaker
In order to get the C API interface files regenerated every time the file c_api.decl
is changed, add the following lines at the end of your Makefile.PL
script.
package MY;
sub postamble {
my $self = shift;
my $author = $self->{AUTHOR};
$author = join(', ', @$author) if ref $author;
$author =~ s/'/'\''/g;
return <<MAKE_FRAG
c_api.h: c_api.decl
\tmake_perl_module_c_api module_name=\$(NAME) module_version=\$(VERSION) author='$author'
MAKE_FRAG
}
sub init_dirscan {
my $self = shift;
$self->SUPER::init_dirscan(@_);
push @{$self->{H}}, 'c_api.h' unless grep $_ eq 'c_api.h', @{$self->{H}};
}
You may also like to include the generated files into the file MANIFEST
in order to not require your module users to also have Module::CAPIMaker
installed.
EXPORT
The module Module::CAPIMaker
exports the subroutine make_c_api
when loaded. This sub parses module settings from @ARGV and the file a_api.decl
and performs the generation of the C API support files.
USAGE OF THE C API FROM OTHER MODULES
In order to use functions provided by a XS module though a C API generated by Module::CAPIMaker, you have to perform the following steps:
Copy the files from the
c_api_client
directory into your module directory.On your
Makefile.PL
script, tell ExtUtils::MakeMaker to compile and link the C file just copied. That can be attained addingOBJECT => '$(O_FILES)'
arguments to theWriteMakefile
call:WriteMakefile(..., OBJECT => '$(O_FILES)', ...);
Include the header file provided from all the compilation units (usually
.c
and.xs
files) that want to use the functions available through the C API.Initialize the client side of the C API from the BOOT section of your XS module calling the load-or-croak macro. For instance:
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "perl_foo_xs.h" MODULE=Bar PACKAGE=Bar BOOT: PERL_FOO_XS_LOAD_OR_CROAK;
CUSTOMIZING THE C API GENERATION PROCESS
Internally, the module uses Text::Template to generate the support files.
In order to allow for maximum customizability, the set of templates used can be changed.
As an example of a module using a customized set of templates see Math::Int64.
The default set of templates is embedded inside the sub-modules under Module::CAPIMaker::Template, you can use them as an starting point.
Finally, if you find the module limiting in some way don't hesitate to contact me explaining your issued. I originally wrote Module::CAPIMaker to solve my particular problems but I would gladly expand it to make it cover a wider range of problems.
SEE ALSO
Math::Int128, Math::Int64, Tie::Array::Packed are modules providing or using (or both) a C API created with the help of Module::CAPIMaker.
COPYRIGHT AND LICENSE
Copyright (C) 2012 by Salvador Fandiño, <sfandino@yahoo.com>.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.12.4 or, at your option, any later version of Perl 5 you may have available.