Home / Alt manpages / xsubpp(1)

  • xsubpp(1)
  • User command
  • linux

Turn a Perl XS File into C with xsubpp

A Perl module with a broken XS build usually fell over at xsubpp, the tool that turns XS glue code into plain C. xsubpp supplies the wiring that lets Perl call XSUBs; a C compiler and the rest of the module build still come afterwards. You will turn a small XS source file into generated C, inspect the result, and keep the original source safe throughout.

  • Time: about 15 minutes for this smoke test, if Perl is already installed.
  • You need: a shell, the perl package, and a writable working directory. None of this needs sudo.
  • Careful: do not run these commands in a source tree that has an uncommitted generated file you cannot afford to lose.

1. Check the installed tool

Start by checking which executable will actually run, and which Perl release owns it:

$ command -v xsubpp
/usr/bin/xsubpp
$ perl -v
This is perl 5, version 38, subversion 2 (v5.38.2)
$ xsubpp -v
xsubpp version 3.51

That output is from the installed perl 5.38.2 package. Other Perl releases can ship a different ExtUtils::ParseXS version, so record this check whenever a generated file needs to be reproducible elsewhere.

Checkpoint

If command -v prints nothing, stop. Install or repair Perl through your normal package management, rather than guessing at an alternate path.

2. Create a minimal XS input

In an empty working directory, save this as sample.xs. The MODULE and PACKAGE lines name the Perl-facing module, and the XSUB itself just adds two integers:

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

MODULE = Demo    PACKAGE = Demo

PROTOTYPES: ENABLE

int
add(int left, int right)
    CODE:
        RETVAL = left + right;
    OUTPUT:
        RETVAL

PROTOTYPES: ENABLE makes the generated binding carry a Perl prototype for this XSUB. Keep this file: it is the thing you review and maintain. The generated C file is just an intermediate build product, not source of truth.

For a real extension, use the XS file and typemap that extension's own build system selects. Do not paste this tiny example into an existing module without first checking its package name and build metadata.

3. Generate C without risking an existing file

Run xsubpp with the XS path as its final argument. With no output option, the generated C goes to standard output, so redirect it to a new, disposable name first:

$ xsubpp sample.xs > sample.c.new
$ test -s sample.c.new
$ mv sample.c.new sample.c

The first command can create or truncate sample.c.new, which is exactly why that name should be one you can lose. The mv only happens once the command and the non-empty check both succeed. If generation fails, inspect the diagnostic and remove the incomplete temporary file once you are sure you do not need it. Never delete an older sample.c as part of a blind recovery attempt.

On this machine, the generated file opens with an automatic-generation notice and includes the original headers. Confirm the expected XSUB wrapper is actually there:

$ rg -n 'XS_Demo_add|#line' sample.c
160:XS_EUPXS(XS_Demo_add); /* prototype to pass -Wmissing-prototypes */
161:XS_EUPXS(XS_Demo_add)

The exact line numbers shift with the input and the installed Perl release. What matters is a generated wrapper for Demo::add, not the specific line it lands on.

4. Understand line directives and output selection

By default, xsubpp adds C preprocessor #line directives. They let later compiler diagnostics point straight back at the XS input, which is handy while debugging. Keep them, unless another tool downstream specifically needs generated C without them.

To write directly to a chosen file, use -output:

$ xsubpp -output sample.c.new sample.xs
$ test -s sample.c.new
$ mv sample.c.new sample.c

To suppress the line directives, add -nolinenumbers:

$ xsubpp -nolinenumbers -output sample-no-lines.c sample.xs
$ test -s sample-no-lines.c
$ rg -n '^#line' sample-no-lines.c || echo 'no #line directives found'
no #line directives found

Do not mistake any of this for compiling the C. xsubpp never links a shared object or installs a Perl module; a normal XS build then hands off to the module's own build rules and a C compiler.

5. Check typemaps before changing options

xsubpp uses typemaps to translate between C arguments and Perl values. It searches for default files in this relative order, with the rightmost match taking precedence:

../../../typemap:../../typemap:../typemap:typemap

It also falls back to Perl's own installed default typemap. A custom typemap file can quietly change how an otherwise identical XS file gets converted. If an argument or return value is not mapped the way you expect, check the module's build directory first, then pass a deliberate file with -typemap PATH:

$ xsubpp -typemap /path/to/project/typemap -output sample.c.new sample.xs

You can repeat -typemap; the last one wins. Check the path before running this, because selecting the wrong typemap produces valid-looking C with the wrong Perl/C conversions baked in.

Common traps

  • Unknown option. Run xsubpp -v and compare the installed tool against the build instructions. Options are version-specific; do not paste a flag from another Perl release without checking first.
  • Unexpected prototype warning. Decide the module's prototype policy and use an XS PROTOTYPES: declaration that matches it. Do not silence the warning by hiding the generated output instead.
  • Missing conversion. Check the selected typemap and the C type before anything else. Adding -noargtypes or -noinout disables recognised syntax; it does not fix a bad mapping.
  • Wrong generated file. Check the working directory, the input path, and the -output value. xsubpp reads the file you name and writes either the requested file or standard output, nothing else.

Options such as -except, -prototypes, -noversioncheck, and -nooptimize all change generated behaviour. Add them only when the module's build instructions actually require them, then read the diff in the generated C to see what changed.

Done means

  • Recorded versions: you noted the installed Perl and xsubpp versions.
  • Source stays authoritative: your XS file is untouched and the generated C is non-empty.
  • Wrapper confirmed: the generated C contains the expected XSUB wrapper.
  • Know your settings: you know whether #line directives and any custom typemap are in play.
  • Safe on failure: a failed conversion cannot overwrite the previous generated file.