The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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.

author = Valentine M. Smith <vmsmith@cpan.org>

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 to max_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 instance PERL_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 to C_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 module Foo::XS, setting export_prefix=foo_ will make that function available on the client module as foo_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.

See "Customizing the C API generation process".

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:

  1. Include c_api.h.

  2. Call the macro INIT_C_API from the BOOT 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:

  1. Copy the files from the c_api_client directory into your module directory.

  2. On your Makefile.PL script, tell ExtUtils::MakeMaker to compile and link the C file just copied. That can be attained adding OBJECT => '$(O_FILES)' arguments to the WriteMakefile call:

      WriteMakefile(...,
                    OBJECT        => '$(O_FILES)',
                    ...);
  3. 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.

  4. 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.