Inline::CPP(3)

πŸ“¦
version 0.80 Β· 3 versions
, in fedora 43

πŸ’– NAME πŸ’–

okay so bestie, welcome to the Inline::CPP(3) manual page πŸ’… β€” this is the one about Inline::CPP, and what it does is let you write Perl subroutines and classes in C++. that's the whole pitch. no cap.


πŸ¦‹ SYNOPSIS πŸ¦‹

like, look how easy this is:

use Inline CPP;

print "9 + 16 = ", add(9, 16), "\n";
print "9 - 16 = ", subtract(9, 16), "\n";

__END__
__CPP__

int add(int x, int y) {
  return x + y;
}

int subtract(int x, int y) {
  return x - y;
}

that's it. that's the whole thing. C++ in your Perl. iconic. ✨


🌸 DESCRIPTION 🌸

so the Inline::CPP module lets you drop C++ source code directly "inline" inside a Perl script or a Perl module. you write your classes or your functions in C++, and then you just… use them, as if they'd been written in Perl the whole time. no separate build step you have to babysit, no nothing. 🫢


πŸ”₯ RATIONALE πŸ”₯

okay so let's talk about why you'd even want this, because someone definitely asked.

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified" -- Donald Knuth

Inline::CPP is about that critical 3%.

Tom "Duff's Device" Duff once wrote the following: "The alternative to genuflecting before the god of code-bumming is finding a better algorithm... ...If your code is too slow, you must make it faster. If no better algorithm is available, you must trim cycles."

so here's the tea: often, well written Perl is fast enough. genuinely. but sometimes you hit a situation where performance just isn't fast enough, and there's no better algorithm to be found β€” and in that case, getting closer to the metal is one way to trim cycles, assuming it's done well. and that's the part Inline::CPP helps with: it minimizes the pain of binding C++ code to Perl via XS. 😭 (because XS pain is real pain)

performance can also be looked at in terms of memory requirements, which honestly nobody thinks about until it's too late. Perlish datastructures are beautifully simple to use, and quite powerful. but that beauty and power? it comes at the cost of memory and speed. so if you're finding that it's too memory-expensive to hold your data in a Perl array, and a disk-based solution is, for whatever reason, not an option, then the memory burden can be aleviated to some degree by holding the data in a C++ data type. πŸ’œ

and yes, this can only go so far. but the common saying is that if you consider a reasonable amount of memory to hold a data structure, double it, and then multiply by ten, you'll have a pretty good feel for how much memory Perl needs to hold it. Inline::CPP can facilitate a leaner alternative. slay.

"The standard library saves programmers from having to reinvent the wheel." -- Bjarne Stroustrup

Inline::CPP is also about not reinventing the wheel.

there are SO many C and C++ libraries already in existence that provide functionality that is well tested, well debuged, and well understood. and there is often no great benefit β€” aside from portability β€” in rewriting such libraries in pure Perl. even re-writing them in XS is cumbersome and prone to bugs. so use Inline::CPP to quickly develop Perl bindings to existing C++ libraries instead. ✨

"Brian Ingerson got fed up with writing XS and ended up writing a very clever Perl module called Inline to do it for him."

face it: XS has a big fat learning curve, lots of boilerplate, and it is so easy to botch it up in difficult to find ways. πŸ’€ Inline::CPP exists to make that process easier. by lightening the cognative load and the boilerplate drudgery associated with pure XS, Inline::CPP can aid the developer in producing less buggy extension code. it won't shield you entirely from "perlguts", but it will take the edge off of it. πŸŽ€

🧚 Choosing a C++ Compiler 🧚

Inline::CPP just parses the subroutine and class signatures within your C++ code and creates bindings to them. like Inline::C, you will need a suitable compiler the first time you run the script.

if you're one of the fortunate majority, you will just accept the defaults as you install Inline::CPP, and the correct C++ compiler and standard libraries will be configured for you. 🫢 if you're one of the unfortunate (and shrinking) minority… read on, bestie.

here's the rule: use a C++ compiler that's compatible with the compiler which built perl. for instance, if perl was built with gcc, use g++. if you're on a Sun or an IRIX box and the system C compiler cc built perl, then use the system C++ compiler, CC.

some compilers actually compile both C and C++ with the same compiler. Microsoft's cl.exe is one such compiler β€” you pass it the <-TP> flag to convince it that you want C++ mode. hopefully this will be deduced by default at install time. 🀞

and if you're using the GNU C++ compiler, make sure that you actually have the g++ front end installed (some Linux distros don't install it by default, but they do provide it via their package management utilities). not me finding that out the hard way πŸ™ˆ

πŸ’… Using Inline::CPP πŸ’…

Inline::CPP is very similar to Inline::C, and in most cases it can be used in place of Inline::C without changing a single line of Perl or C code. so if you haven't done so already, you should stop reading right now and go read the documentation for Inline::C, including the Inline::C-Cookbook. seriously, go. i'll wait. πŸ’–

this module uses a grammar to parse your C++ code, and binds to functions or classes which are recognized. if a function is recognized, it will be available from Perl space. if the function's signature is not recognized, it will not be available from Perl β€” but it will still be available from other functions or classes within the C++ code. iykyk.

the following example shows how C++ snippets map to Perl:

Example 1:

use Inline CPP => <<'END';

using namespace std;

int doodle() { }

class Foo {
 public:
   Foo();
   ~Foo();

   int get_data() { return data; }
   void set_data(int a) { data = a; }
 private:
   int data;
};

Foo::Foo() { cout << "creating a Foo()" << endl; }
Foo::~Foo() { cout << "deleting a Foo()" << endl; }

END

after running the code above, your Perl runtime would look similar to if following code had been run:

sub main::doodle { }

package main::Foo;

sub new { print "creating a Foo()\n"; bless {}, shift }
sub DESTROY { print "deleting a Foo()\n" }

sub get_data { my $o=shift; $o->{data} }
sub set_data { my $o=shift; $o->{data} = shift }

the difference, of course, is that in the latter, Perl does the work. in the Inline::CPP example, all function calls get sent off to your C++ code. which means things like this won't work:

my $obj = new Foo;
$obj->{extrafield} = 10;

it doesn't work because $obj is not a blessed hash. it's a blessed reference to a C++ object. 🫠 that's just how it is, bestie.

🌈 C++ Compilation Phase 🌈

the first time you run a program that uses Inline::CPP, the C++ code will be compiled into an _Inline/ or .Inline/ folder within the working directory. that first run will incur a startup time penalty associated with compiling C++ code. 😩

however β€” the compiled code is cached, and assuming it's not modified, subsequent runs will skip the C++ compilation entirely, and startup time will be fast. ⭐ main character energy, honestly.

πŸ“ Where to put C++ code πŸ“

your inline C++ code can reside just about anywhere you want within your Perl code. a lot of this is documented more fully in the Inline POD, but here are some basics:

use Inline CPP => 'DATA';

# Perl code here

__DATA__
__CPP__

// C++ code here.

or….

use Inline CPP => <<'END_CPP';
    // C++ code here.
END_CPP

and structurally, where does it belong? for simple one-off scripts, just put it anywhere you want. 🀷 but in the spirit of code reusability, it's often better to simply create a module that houses the functionality build upon C++ code:

# Foo/Bar.pm
package Foo::Bar;
use Inline CPP => 'DATA';

# Perl code here, including Exporter mantra, if needed.

__DATA__
__CPP__
// C++ here.....

where you place your module's file(s) follows the same rules as plain old Perl, which is beyond the scope of this POD, but fortunatly no different from what you're used to (assuming you're used to writing Perl modules). ✨

and of course, modules can be shared by multiple scripts while only incurring that compilation startup penalty one time, ever. obsessed. πŸ’…

πŸ‘‘ Basing (CPAN) Distributions on Inline::CPP πŸ‘‘

taking the concept of code-reuse one step further β€” it is entirely possible to package a distribution with an Inline::CPP dependency. πŸŽ€ when the user installs the distribution (aka, the module), the C++ code will be compiled during module build time, and never again (unless the user upgrades the module). so the user will never see the startup lag associated with C++ code compilation. literally the dream.

an example and proof-of-concept for this approach can be found in the CPAN module Math::Prime::FastSieve.

this approach involves using Inline::MakeMaker, and it's well documented in the Inline POD under the heading Writing Modules with Inline (http://search.cpan.org/perldoc?Inline#Writing_Modules_with_Inline).

however β€” you may wish to remove the Inline::CPP dependency altogether from the code that you bundle into a distribution. this can be done using InlineX::CPP2XS, which converts the Inline::CPP generated code to Perl XS code, fit for distribution without the Inline::CPP dependency. InlineX::CPP2XS includes an example/ directory that actually converts Math::Prime::FastSieve to pure XS. πŸ”₯

some extension authors choose to implement first in Inline::CPP, and then manually tweak, then copy and paste the resulting XS file into their own distribution, with similar effect (and possibly a little finer-grained control) to the CPP2XS approach.

🌈 Perl Namespaces 🌈

let's say you use Inline::CPP like this:

package Some::Foo;
use Inline CPP => <<'END_CPP';

#include <iostream>
using namespace std;

class Foo {
  private:
    int data;
  public:
    Foo()  { cout << "creating a Foo()" << endl; }
    ~Foo() { cout << "deleting a Foo()" << endl; }
};

END_CPP
1;

the issue is that the C++ class, "Foo" will be mapped to Perl below the Some::Foo namespace, as Some::Foo::Foo, and would need to be instantiated like this: my $foo = Some::Foo::Foo->new(). and that probably isn't what the user intended. 😭 use the namespace configuration option to set your base namespace:

use Inline CPP => config => namespace => 'Some';

now, Foo falls under the Some heirarchy: Some::Foo, and can be instantiated as my $foo = Some::Foo->new(). this probably is what the user intended. πŸ’–

πŸ’œ C++ Configuration Options πŸ’œ

for information on how to specify Inline configuration options, see Inline. this section describes each of the configuration options available for C/C++. most of the options correspond either to the MakeMaker or XS options of the same name. see ExtUtils::MakeMaker and perlxs.

okay so real quick, before we get into the actual config options: every configuration option is case insensitive, including the word config itself. but CPP and DATA? those are NOT configuration options, and they are NOT insensitive to case. so don't try to lowercase those, bestie, it's giving chaos. πŸ’…


✨ altlibs ✨

Adds a new entry to the end of the list of alternative libraries to bind with. MakeMaker will search through this list and use the first entry where all the libraries are found.

use Inline CPP => config => altlibs => '-L/my/other/lib -lfoo';

Also peek at the libs config option β€” it appends to the last entry in the list. πŸ‘‘


✨ auto_include ✨

Specifies extra statements to be automatically included. They get added on to the defaults. A newline char will automatically be added. so convenient.

use Inline CPP => config => auto_include => '#include "something.h"';

✨ boot ✨

Specifies code to be run when your code is loaded. May not contain any blank lines. See perlxs for more info, bestie.

use Inline CPP => config => boot => 'foo();';

✨ cc ✨

Specifies which compiler to use. In most cases the configuration default is adequate. don't overthink it.

use Inline CPP => config => cc => '/usr/bin/g++-4.6';

✨ ccflags ✨

Specifies extra compiler flags. Corresponds to the MakeMaker option.

use Inline CPP => config => ccflags => '-std=c++11';

✨ classes ✨

use Inline CPP => config =>
    classes => { 'CPPFoo' => 'PerlFoo', 'CPPBar' => 'PerlBar' };

use Inline CPP => config =>
    namespace => 'Qux' =>
    classes => { 'CPPFoo' => 'PerlFoo', 'CPPBar' => 'PerlBar' };

use Inline CPP => config =>
    classes => sub {
        my $cpp_class = shift;
        ...
        return($perl_package);
    };

Override C++ class name. πŸŽ€

Under default behavior, a C++ class naming conflict will arise by attempting to implement the C++ classes Foo::Bar::MyClass and Foo::Qux::MyClass which depend upon one another in some way, because C++ sees both classes as named only MyClass. We are unable to solve this C++ conflict by using just the namespace config option, because namespace is only applied to the Perl package name, not the C++ class name.

In the future, this issue may be solved via Inline::CPP support for the native C++ namespace operator and/or C++ class names which contain the :: double-colon scope token.

For now, this issue is solved by using the classes config option, which accepts either a hash reference or a code reference. When a hash reference is provided, each hash key is a C++ class name, and each hash value is a corresponding Perl class name. This hash reference serves as a C++-to-Perl class name mapping mechanism, and may be used in combination with the namespace config option to exercise full control over class and package naming.

When a code reference is provided, it must accept as its sole argument the C++ class name, and return a single string value containing the generated Perl package name. When a code reference is provided for the classes config option, the value of the namespace config option is ignored.

The hash reference may be considered a manual mapping method, and the code reference an automatic mapping method.

Example file /tmp/Foo__Bar__MyClass.c:

class MyClass {
  private:
    int a;
  public:
    MyClass() :a(10) {}
    int fetch () { return a; }
};

Example file /tmp/Foo__Qux__MyClass.c:

#include "/tmp/Foo__Bar__MyClass.c"
class MyClass {
  private:
    int a;
  public:
    MyClass() :a(20) {}
    int fetch () { return a; }
    int other_fetch () { MyClass mybar; return mybar.fetch(); }
};

We encounter the C++ class naming conflict when we

use Inline CPP => '/tmp/Foo__Qux__MyClass.c' => namespace => 'Foo::Qux';

The C++ compiler sees two MyClass classes and gives a redefinition error:

_08conflict_encounter_t_9d68.xs:25:7: error: redefinition of β€˜class MyClass’
 class MyClass {
       ^
In file included from _08conflict_encounter_t_9d68.xs:24:0:
/tmp/Foo__Bar__MyClass.c:1:7: error: previous definition of β€˜class MyClass’
 class MyClass {
       ^

The solution is to rename each MyClass to utilize unique class names, such as Foo__Bar__MyClass and Foo__Qux__MyClass, and use the classes config option.

Updated example file /tmp/Foo__Bar__MyClass.c:

class Foo__Bar__MyClass {
  private:
    int a;
  public:
    Foo__Bar__MyClass() :a(10) {}
    int fetch () { return a; }
};

Updated example file /tmp/Foo__Qux__MyClass.c:

#include "/tmp/Foo__Bar__MyClass.c"
class Foo__Qux__MyClass {
  private:
    int a;
  public:
    Foo__Qux__MyClass() :a(20) {}
    int fetch () { return a; }
    int other_fetch () { Foo__Bar__MyClass mybar; return mybar.fetch(); }
};

First, consider the following updated call to Inline using the hash reference method to manually map the namespace and class names. This example does not give any C++ errors, and runs correctly in both C++ and Perl:

use Inline  CPP => '/tmp/Foo__Qux__MyClass.c' =>
            namespace => 'Foo' =>
            classes => { 'Foo__Bar__MyClass' => 'Bar::MyClass',
                         'Foo__Qux__MyClass' => 'Qux::MyClass' };

Next, consider another updated call to Inline using the code reference method to automatically map the namespace and class names, which may be deployed across more complex codebases. This example automates the mapping of the __ double-underscore to the :: double-colon scope token.

use Inline CPP => config =>
    classes => sub { join('::', split('__', shift)); };

For more information, please see the runnable examples: t/classes/07conflict_avoid.t t/classes/08auto.t t/classes/09auto_mixed.t


✨ filters ✨

Specifies one (or more, in an array ref) filter which is to be applied to the code just prior to parsing. The filters are executed one after another, each operating on the output of the previous one. You can pass in a code reference or the name of a prepackaged filter.

use Inline CPP => config => filters => [Strip_POD => \&myfilter];
use Inline CPP => config => filters => 'Preprocess';  # Inline::Filters

The filter may do anything. The code is passed as the first argument, and it returns the filtered code. For a set of prefabricated filters, consider using Inline::Filters. πŸ¦‹


✨ inc ✨

Specifies extra include directories. Corresponds to the MakeMaker parameter.

use Inline CPP => config => inc => '-I/my/path';

✨ ld ✨

Specifies the linker to use.


✨ lddlflags ✨

Specifies which linker flags to use.

NOTE: These flags will completely override the existing flags, instead of just adding to them. So if you need to use those too, you must respecify them here. no cap, this one bites. πŸ’€

✨ libs ✨

Specifies external libraries that should be linked into your code. Corresponds to the MakeMaker parameter.

use Inline CPP => config => libs => '-L/your/path -lyourlib';

Unlike the libs configuration parameter used in Inline::C, successive calls to libs append to the previous calls. For example,

use Inline CPP => config => libs => '-L/my/path', libs => '-lyourlib';

will work correctly, if correct is for both libs to be in effect. If you want to add a new element to the list of possible libraries to link with, use the Inline::CPP configuration altlibs.


✨ make ✨

Specifies the name of the '"make"' utility to use.


✨ myextlib ✨

Specifies a user compiled object that should be linked in. Corresponds to the MakeMaker parameter.

use Inline CPP => config => myextlib => '/your/path/something.o';

✨ namespace ✨

use Inline CPP => config => namespace => 'Foo';
use Inline CPP => config => namespace => 'main';
use Inline CPP => config => namespace => q{};

Override default base namespace. πŸ‘‘

Under default behavior, a C++ class Foo created by invoking Inline::CPP from package Bar will result in the C++ Foo class being accessible from Perl as Bar::Foo. While this default behavior may be desirable in some cases, it might be undesirable in others. An example would be creating a Foo class while invoking Inline::CPP from package Foo. The resulting class will bind to Perl as Foo::Foo, which is probably not what was intended.

This default behavior can be overridden by specifying an alternate base namespace. Examples are probably the best way to explain this:

package Foo;
use Inline CPP => config => namespace => 'Bar';
use Inline CPP => <<'EOCPP';

class Baz {
  private:
    int a;
  public:
    Baz() :a(20) {}
    int fetch () { return a; }
};
EOCPP

package main;
my $b = Bar::Baz->new();
print $b->fetch, "\n"; # 20.

As demonstrated here, the namespace in which Baz resides can now be made independent of the package from which Inline::CPP has been invoked. Consider instead the default behavior:

package Foo;
use Inline CPP => <<'EOCPP';
class Foo {
  private:
    int a;
  public:
    Baz() :a(20) {}
    int fetch () { return a; }
};
EOCPP

package main;
my $b = Foo::Foo->new();
print $b->fetch, "\n"; # 20.

It is probably, in this case, undesirable for the C++ class Foo to reside in the Perl Foo::Foo namespace. We can fix this by adding our own namespace configuration:

package Foo;
use Inline CPP => config => namespace => q{};  # Disassociate from
                                               # calling package.
use Inline CPP => <<'EOCPP';

class Baz {
  private:
    int a;
  public:
    Baz() :a(20) {}
    int fetch () { return a; }
};
EOCPP

package main;
my $b = Foo->new();
print $b->fetch, "\n"; # 20.

✨ prefix ✨

Specifies a prefix that will automatically be stripped from C++ functions when they are bound to Perl. Less useful than in C, because C++ mangles its function names to facilitate function overloading.

use Inline CPP config => prefix => 'ZLIB_';

This only affects C++ function names, not C++ class names or methods.


✨ preserve_ellipsis ✨

By default, Inline::CPP replaces ... in bound functions with three spaces, since the arguments are always passed on the Perl Stack, not on the C stack. This is usually desired, since it allows functions with no fixed arguments (most compilers require at least one fixed argument).

...the example of why preserve_ellipsis is normally not needed is down in the examples section, bestie. ✨

πŸŽ€ std_iostream πŸŽ€

By default, Inline::CPP drops the standard iostream header at the very top of your code. And it's gonna try to make the proper selection for you β€” between "iostream.h" (for older compilers) and "iostream" (for newer "Standard compliant" compilers). πŸ’…

This option makes sure "iostream" (no .h, the ANSI-compliant version of the header) is the one included. For most compilers you genuinely don't need this anymore, because detection happens at module install time. It's only still here to maintain backward compatibility with code that used to need it. 🫢

use Inline CPP => config => enable => 'std_iostream';

✨ structs ✨

Specifies whether to bind C structs into Perl using Inline::Struct.

NOTE: Support for this option is experimental. πŸ‘€

Okay so here's the tea: Inline::CPP already binds to structs defined in your code. In C++, structs and classes are treated the same, except a struct's initial scope is public, not private. Inline::Struct is the glow-up β€” it provides autogenerated get/set methods, an overloaded constructor, and several other features that just aren't available in Inline::CPP. 😭

You can invoke structs in several ways:

use Inline CPP config => structs => 'Foo';

or

use Inline CPP config => structs => ['Bar', 'Baz'];

Binds the named structs to Perl. Emits warnings if a struct was requested but could not be bound for some reason. πŸ’€

use Inline CPP config => enable => 'structs';

or

use Inline CPP config => structs => 1;

Enables binding structs to Perl. All structs which can be bound, will. This parameter overrides all requests for particular structs. periodt. πŸ‘‘

use Inline CPP config => disable => 'structs';

or

use Inline CPP config => structs => 0;

Disables binding structs to Perl. Overrides any other settings.

See Inline::Struct for more details about how Inline::Struct binds C structs to Perl. 🌸

πŸ¦‹ typemaps πŸ¦‹

Specifies extra typemap files to use. These types will modify the behaviour of C++ parsing. Corresponds to the MakeMaker parameter.

use Inline CPP config => typemaps => '/your/path/typemap';

πŸ’– C++-Perl Bindings πŸ’–

This section describes how the Perl variables get mapped to C++ variables and back again. πŸ”

Perl uses a stack to pass arguments back and forth to subroutines. When a sub is called, it pops off all its arguments from the stack; when it's done, it pushes its return values back onto the stack.

XS (Perl's language for creating C or C++ extensions for Perl) uses typemaps to turn SVs into C types and back again. This is done through various XS macro calls, casts, and the Perl API. XS also allows you to define your own mappings.

Inline::CPP uses a much simpler approach. It parses the system's typemap files and only binds to functions with supported types. You can tell Inline::CPP about custom typemap files too. πŸ’…

If you have non-trivial data structures in either C++ or Perl, you should probably just pass them as an SV* and do the conversion yourself in your C++ function. fr fr, don't overcomplicate it.

In C++, a struct is a class whose default scope is public, not private. Inline::CPP binds to structs with this in mind -- get/set methods are not yet auto-generated (although this feature may be added to an upcoming release).

If you have a C struct, you can use Inline::Struct to allow Perl complete access to the internals of the struct. You can create and modify structs from inside Perl, as well as pass structs into C++ functions and return them from functions. Please note that Inline::Struct does not understand any C++ features, so constructors and member functions are not supported. See Inline::Struct for more details.

🌈 Example 🌈

Say you want to use a C++ standard string type. A C++ method that takes or returns such will be ignored unless you tell Perl how to map it to and from Perl data types. πŸ™ˆ

Put this in a file called typemap:

TYPEMAP
string  T_CPPSTRING

INPUT

T_CPPSTRING
        $var = ($type)SvPV_nolen($arg)

OUTPUT

T_CPPSTRING
        sv_setpv((SV*)$arg, $var.c_str());

Then this script will work:

use Inline CPP => config => typemaps => "typemap";
use Inline CPP => <<'END';

#ifdef __INLINE_CPP_STANDARD_HEADERS
#include <string>
#else
#include <string.h>
#endif

#ifdef __INLINE_CPP_NAMESPACE_STD
using namespace std;
#endif

class Abstract {
  public:
        virtual string greet2() {
            string retval = "yo";
            return retval;
        }
};

class Impl : public Abstract {
  public:
    Impl() {}
    ~Impl() {}
};
END

my $o = Impl->new;
print $o->greet2, "\n";

See t/grammar/09purevt.t for this within the test suite. πŸŽ€


πŸ‘‘ <iostream>, Standard Headers, C++ Namespaces, and Portability Solutions πŸ‘‘

Inline::CPP automatically includes <iostream>, or <iostream.h>, depending on the preference of the target compiler. This distinction illustrates a potential problem when trying to write portable code in C++. Legacy C++ (pre-ANSI-Standard) used headers named, for example, <iostream.h>. As legacy C++ didn't support namespaces, these standard tools were not segregated into a separate namespace.

ANSI Standard C++ changed that. Headers were renamed without the .h suffix, and standard tools were placed in the "std" namespace. The using namespace std and using std::string constructs were also added to facilitate working with namespaces.

So pre-Standard (Legacy) C++ code might look like this:

#include <iostream.h>
int main() {
    cout << "Hello world.\n";
    return 0;
}

Modern ANSI Standard C++ compilers would require code like this:

#include <iostream>
using namespace std;
int main() {
    cout << "Hello world.\n";
    return 0;
}

... or ...

#include <iostream>
int main() {
    std::cout << "Hello world.\n";
    return 0;
}

... or even ...

#include <iostream>
int main() {
    using std::cout;
    cout << "Hello world.\n";
    return 0;
}

The first snippet is going to be completely incompatible with the second, third or fourth snippets. That's no problem for a C++ developer who knows his target compiler. But Perl runs just about everywhere. If similar portability (including backward compatibility) is a design goal, Inline::CPP helps by providing two #define constants that may be checked to ascertain which style of headers are being used. The constants are:

__INLINE_CPP_STANDARD_HEADERS
__INLINE_CPP_NAMESPACE_STD

__INLINE_CPP_STANDARD_HEADERS will be defined if the target compiler accepts ANSI Standard headers, such as <iostream>. __INLINE_CPP_NAMESPACE_STD will be defined if the target compiler supports namespaces. Realistically the two are synonymous; ANSI Standard C++ uses namespaces, places standard library tools in the std namespace, and invokes headers with the modern (no .h suffix) naming convention. So if one is defined they both should be.

They can be used as follows:

use Inline CPP => 'DATA';

greet();

__DATA__
__CPP__

#ifdef __INLINE_CPP_STANDARD_HEADERS
#include <string>
#else
#include <string.h>
#endif

#ifdef __INLINE_CPP_NAMESPACE_STD
using namespace std;
#endif

void greet() {
    string mygreeting = "Hello world!\n";
    cout << mygreeting;
}

You may decide that you don't care about maintaining portability with compilers that lock you in to pre-Standard C++ -- more than a decade behind us. But if you do care (maybe you're basing a CPAN module on Inline::CPP), use these preprocessor definitions as a tool in building a widely portable solution. 🫢

If you wish, you may #undef either of those defs. The definitions are defined before any auto_includes -- even <iostream>. Consequently, you may even list #undef __INLINE_CPP_.... within an auto_include configuration directive. I'm not sure why it would be necessary, but could be useful in testing.

Regardless of the header type, Inline::CPP will create the following definition in all code it generates:

#define __INLINE_CPP 1

This can be useful in constructing preprocessor logic that behaves differently under Inline::CPP than under a non-Inline::CPP environment. πŸ’œ

✨ EXAMPLES ✨

Okay bestie, this is the fun part. Here's where we actually see the thing do stuff. Buckle up. πŸŽ€


🚜 Example 1 - Farmer Bob

So this one shows you how to use a simple class (his name is Farmer, and he's having a rough time) straight from Perl. And the ✨ new hotness ✨ here in Inline::CPP? Binding to classes that have their method definitions written inline. Slay.

use Inline CPP;

my $farmer = new Farmer("Ingy", 42);
my $slavedriver = 1;
while($farmer->how_tired < 420) {
  $farmer->do_chores($slavedriver);
  $slavedriver <<= 1;
}

print "Wow! The farmer worked ", $farmer->how_long, " hours!\n";

__END__
__CPP__

class Farmer {
public:
  Farmer(char *name, int age);
  ~Farmer();

  int how_tired() { return tiredness; }
  int how_long() { return howlong; }
  void do_chores(int howlong);

private:
  char *name;
  int age;
  int tiredness;
  int howlong;
};

Farmer::Farmer(char *name, int age) {
  this->name = strdup(name);
  this->age = age;
  tiredness = 0;
  howlong = 0;
}

Farmer::~Farmer() {
  free(name);
}

void Farmer::do_chores(int hl) {
  howlong += hl;
  tiredness += (age * hl);
}

Bob is literally fighting for his life in there but the code is clean, no cap. πŸ’…


✈️ Example 2 - Plane and Simple

This one is showing off some more new features: inheritance and abstract classes. The defined methods of the abstract class Object get bound to Perl, but guess what β€” there's no constructor and no destructor, which means you cannot instantiate an Object. It's giving "concept, not a vibe you can touch." 😌

The Airplane though? Fully-bound class. You can create it and mess with it from Perl all day.

use Inline 'CPP';

my $plane = new Airplane;
$plane->print;
if ($plane->isa("Object")) { print "Plane is an Object!\n"; }
unless ($plane->can("fly")) { print "This plane sucks!\n"; }

__END__
__CPP__

using namespace std;

/* Abstract class (interface) */
class Object {
public:
  virtual void print() { cout << "Object (" << this << ")" << endl; }
  virtual void info() = 0;
  virtual bool isa(char *klass) = 0;
  virtual bool can(char *method) = 0;
};

class Airplane : public Object {
public:
  Airplane() {}
  ~Airplane() {}

  virtual void info() { print(); }
  virtual bool isa(char *klass) { return strcmp(klass, "Object")==0; }
  virtual bool can(char *method) {
    bool yes = false;
    yes |= strcmp(method, "print")==0;
    yes |= strcmp(method, "info")==0;
    yes |= strcmp(method, "isa")==0;
    yes |= strcmp(method, "can")==0;
    return yes;
  }
};

πŸŒ€ Example 3 - The Ellipsis Abridged

Okay so one of the BIGGEST advantages Perl has over C or C++ is that you can pass literally any number of arguments to a subroutine. Sure, you can do it in C, but it's messy and honestly so hard to get right. And all that mess exists because C doesn't hand the programmer access to the stack. Perl? Perl gives you everything. πŸ‘‘

Here's a useful function written in Perl. It is, lowkey, relatively slow:

sub average {
   my $average = 0;
   for (my $i=0; $i<@_; $i++) {
      $average *= $i;
      $average += $_[$i];
      $average /= $i + 1;
   }
   return $average;
}

And here's that same function written in C:

double average() {
   Inline_Stack_Vars;
   double avg = 0.0;
   for (int i=0; i<Inline_Stack_Items; i++) {
      avg *= i;
      avg += SvNV(Inline_Stack_Item(i));
      avg /= i + 1;
   }
   return avg;
}

And here's a benchmark program that tests which one is faster:

use Inline 'CPP';
my @numbers = map { rand } (1 .. 10000);
my ($a, $stop);
$stop = 200;
if (@ARGV) {
  $a = avg(@numbers) while $stop--;
}
else {
  $a = average(@numbers) while $stop--;
}
print "The average of 10000 random numbers is: ", $a, "\n";

sub average {
   my $average = 0;
   for (my $i=0; $i<@_; $i++) {
       $average *= $i;
       $average += $_[$i];
       $average /= $i + 1;
   }
   return $average;
}

__END__
__CPP__

double avg(...) {
   Inline_Stack_Vars;
   double avg = 0.0;
   for (int i=0; i<items; i++) {
       avg *= i;
       avg += SvNV(ST(i));
       avg /= i + 1;
   }
   return avg;
}

Now look at that function declaration real close:

double avg(...)

Why did we not need to use varargs macros to get at the arguments?? Why did the compiler not complain that there were no required arguments?? πŸ€”

Because Inline::C++ actually compiled this:

double avg(   )

When it bound to the function, it noticed the ellipsis and decided to get rid of it. Any function bound to Perl that has an ellipsis in it will have its arguments passed via the Perl stack, not the C stack. Which means if you write a function like this:

void myprintf(char *format, ...);

then bestie, you'd better be reading things from the Perl stack. If you aren't, then specify the PRESERVE_ELLIPSIS option in your script. That will leave the ellipsis in the code for the compiler to whine about. :)


πŸ₯ž Example 4 - Stacks and Queues

Everyone who learns to program in C++ writes a stack class and a queue class sooner or later. It's a rite of passage, honestly. So might as well try it from Inline. But like... why reinvent the wheel? πŸ›ž Perl has a perfectly good Array type, and it can easily implement both a Queue and a Stack.

This example implements a Queue and a Stack class, and shows off just a few more new features of Inline::CPP: default values to arguments,

use Inline 'CPP';

my $q = new Queue;
$q->q(50);
$q->q("Where am I?");
$q->q("In a queue.");
print "There are ", $q->size, " items in the queue\n";
while($q->size) {
    print "About to dequeue:  ", $q->peek, "\n";
    print "Actually dequeued: ", $q->dq, "\n";
}

my $s = new Stack;
$s->push(42);
$s->push("What?");
print "There are ", $s->size, " items on the stack\n";
while($s->size) {
    print "About to pop:    ", $s->peek, "\n";
    print "Actually popped: ", $s->pop, "\n";
}

__END__
__CPP__

class Queue {
  public:
    Queue(int sz=0) { q = newAV(); if (sz) av_extend(q, sz-1); }
    ~Queue() { av_undef(q); }

    int size() {return av_len(q) + 1; }

    int q(SV *item) { av_push(q, SvREFCNT_inc(item)); return av_len(q)+1; }
    SV *dq() { return av_shift(q); }
    SV *peek() { return size() ? SvREFCNT_inc(*av_fetch(q,0,0)): &PL_sv_undef;}

  private:
    AV *q;
};

class Stack {
  public:
    Stack(int sz=0) { s = newAV(); if (sz) av_extend(s, sz-1); }
    ~Stack() { av_undef(s); }

    int size() { return av_len(s) + 1; }

    int push(SV *i) { av_push(s, SvREFCNT_inc(i)); return av_len(s)+1; }
    SV *pop() { return av_pop(s); }
    SV *peek() { return size() ? SvREFCNT_inc(*av_fetch(s,size()-1,0)) : &PL_sv_undef; }

  private:
    AV *s;
};

🌟 Example 5 - Elipses Revisited (and Overloading or Templates)

This one, about how to use elipses, is adapted from a discussion over on Perl Monks. The ✨ issue ✨ was that somebody wanted to call overloaded functions. But plot twist: Perl doesn't understand C++'s overloading rules, and C++ has absolutely no idea how Perl intends to call the functions here. So the move is β€” we write a wrapper and take control ourselves. Main character energy. πŸ’…

use Inline CPP => 'DATA';

say multiadd( 1 );          # No dispatch; just return the value.
say multiadd( 1, 2 );       # Dispatch add( int, int ).
say multiadd( 1, 2, 3 );    # Dispatch add( int, int, int ).
say multiadd( 1, 2, 3, 4 ); # No dispatch; throw an exception.
__DATA__
__CPP__

#include <stdexcept>

// Inline::CPP won't create predictable bindings to overloaded functions.

int add ( int a, int b ) {
  return a + b;
}

int add ( int a, int b, int c ) {
  return a + b + c;
}

// But a function call with elipses can dispatch to overloaded functions since
// no Perl binding is required in reaching those functions.
int multiadd ( SV * a, ... ) {
  dXSARGS;  // Creates a variable 'items' that contains a paramater count.
  try{
    switch ( items ) {
      case 1:  return SvIV(ST(0));
      case 2:  return add( SvIV(ST(0)), SvIV(ST(1)) );
      case 3:  return add( SvIV(ST(0)), SvIV(ST(1)), SvIV(ST(2)) );
      default: throw std::runtime_error(
        "multiadd() - Too many args in function call"
      );
    }
  }
  catch ( std::runtime_error msg ) {
    croak( msg.what() );  // Perl likes croak for exceptions.
  }
}

Technically, one of the versions of add() will bind to Perl, but using it is fragile, because the rules for which one binds are undefined. πŸ™ˆ This example sidesteps the whole "Perl/XS doesn't understand overloading" problem by simply wrapping the calls to the overloaded functions inside a function that does understand. And we use elipses to deal with a variable number of arguments. This same approach can be applied to calling template-generated code too. 🧚


🫢 Minimum Perl version requirements

So, Inline currently requires Perl 5.8.1 or later. And since Inline::CPP depends on Inline, that means Perl 5.8.1 is also required for Inline::CPP. Periodt.

It's hard to imagine anyone still using a Perl older than 5.8.1 who also wants to interface with C++... but if you're in that camp, bestie, you'll need to roll back Inline and Inline::CPP to older versions through the magic of backpan. πŸͺ„

Fun fact: Inline::CPP version 0.25 was still compatible with Perl 5.005_03.

Review the Changes file from the Inline distribution to decide which Inline version is appropriate for your pre-5.8.1 Perl. πŸ’–

✨ C++11 Standard ✨

okay so is Inline::CPP ready for the C++11 standard? short answer: "Mostly, to the extent that your compiler is C++11 standard compliant." πŸ’…

There are two issues to consider. First, what is your compiler capable of (and how do you enable those capabilities), and second, what does Perl need to care about. πŸ¦‹

Taking the first question first (because it's the easiest): Use the ccflags option shown above to pass the proper flag to your compiler to enable C++11 features. Most of what your compiler will support, Inline::CPP will deal with. ✨

You also may need to use the cc flag to specify a newer version of the compiler, if you happen to have more than one installed β€” one that handles C++11 and one that doesn't. 😭

Now for the question of what Perl needs to care about: Inline::CPP doesn't look inside of functions or methods. That code is treated as a black box that passes directly through to your compiler. So inside of your functions and methods, feel free to use whatever C++11 features you want. πŸ‘‘

The critical areas are function headers, class definitions, and code that falls outside of functions or classes. Take Enums for example:

enum Colors { RED, GREEN, BLUE };

How should this map to Perl? There's no clear answer. C++11 adds the concept of scope to enums:

enum class Colors { RED, GREEN, BLUE };

How this should bind to Perl becomes even more difficult. The fact is that Inline::CPP won't bind either to Perl. And you're probably better off with that approach than suddenly having $Colors::RED = 0; showing up in your Perl code. Do keep in mind, however, the construct is passed directly through to your C++ compiler, so feel free to use it within the C++ code. It just won't leak out into your Perl namespaces. 🚫

At the moment the most glaring omission from Inline::CPP of valid C++11 syntax is the new "late return type" syntax. C++11 introduced the following legal syntax:

auto add ( int x, int y ) -> int { return x + y; }

This omission is only going to be a factor for functions that you want to bind to Perl. If you don't need the function to bind to Perl, the syntax is fine; Inline::CPP just ignores the function. It's important to note that the most common uses of this syntax involve templates and lambdas. Templates don't make sense to Inline::CPP anyway. And lambdas are still fine, because they take place inside of functions, so Inline::CPP doesn't see them anyway. For now, just don't use the late return type syntax in the header of functions that need to bind to Perl. This may get fixed in future revisions to the grammar. πŸ› οΈ

Another issue is constexpr:

constexpr int multiply ( int x, int y ) { return x * y; }

constexpr isn't recognized by Inline::CPP, so this function won't bind to Perl. I don't think that constexpr functions can even generate external bindings, because they're resolved to a constant at compile-time. They really don't make sense for external use (the compiler can't know how you will call them). Consequently, they'll be ignored by Inline::CPP (and will pass through to your compiler, so they will work within your C++ code). πŸ’€

And finally, Rvalue references:

Inline::CPP doesn't (yet) understand this:

int x = 100;

int getInt ()
{
    return x;
}

int && getRvalueInt ()
{
    return std::move( x );
}

The getInt() function will bind to Perl, but the && syntax isn't recognized by Inline::CPP, and won't result in a binding being generated. So getRvalueInt() will be invisible to Perl. However, it is perfectly legal to use within your C++ code as long as you don't need it to bind to Perl. πŸ™ˆ

Aside from that (as far as I know), you're good to go! Go ahead and use the new version of for( auto it: x ) {...}, or even...

for_each( v.begin(), v.end(), [] (int val) { std::cout << val; } );

The beauty of Inline::CPP is that what goes on inside the black boxes of functions or methods is irrelevant to the binding process. These examples will "just work", assuming your C++ compiler understands them. πŸ”₯


πŸ› BUGS AND DEFICIENCIES πŸ›

There are bound to be bugs in code this uncivilized. If you find one, please file a bug report. Patches are even better. Patches accompanied by tests are like the holy grail. πŸ‘‘

When reporting a bug, please do the following:

  • If possible, create a brief stand-alone snippet of code that demonstrates the issue.
  • Use L<Github Issues|https://github.com/daoswald/Inline-CPP/issues> to file your bug report.
  • Patches are always welcome, as are tests that tickle a newfound bug.
  • Pull requests should avoid touching irrelevant sections of code/POD, and tests are required before they can be considered for merge.

...or...

  • Put "use Inline REPORTBUG;" at the top of your code, or use the command line option "perl -MInline=REPORTBUG ...".
  • Run your code.
  • Follow the printed instructions.

Get involved! Module development is being tracked on a github repository: https://github.com/daoswald/Inline-CPP. πŸ’–

The master branch should always be buildable and usable. ✨

Official releases have version numbers in the following format: 'x.xx', and are usually tagged with the CPAN release number.

Various development branches will hold a combination of minor commits and CPAN "Developer" releases (these may have a version number formatted as: 'x.xx_xxx' to designate a developer-only CPAN release).

Most discussion relating to this module (user or developer) occurs on the Inline mailing list, inline.perl.org, and in "#inline" on "irc.perl.org". See http://lists.perl.org/list/inline.html for details on subscribing.

Here are some things to watch out for:

The grammar used for parsing C++ is still quite simple, and does not allow several features of C++:

  • Templates: You may use template libraries in your code, but Inline::CPP won't know how to parse and bind template definitions. The core problem is that the C++ compiler has no idea how a dynamic language like Perl intends to invoke template-generated code, and thus, cannot know what code to generate from the templates. Keep the templates encapsulated away from the interface that will be exposed to Perl by wrapping calls in functions that will give the compiler a type to work with.
  • Operator overloading
  • Function overloading β€” This is a similar issue to the template problem. Perl doesn't know about C++'s function overload resolution rules. And C++ doesn't know about Perl. XS was never designed to deal with this sort of mismatch. This prevents implementing the Rule of Three for code that is intended to bind with Perl, but because Perl handles your bindings, that's probably not an issue.
These three issues (Templates, Operator Overloading, and Function Overloading) are situations where the C++ language and the Perl language simply do not map well to one another. The sooner you get used to this disconnect, the sooner you'll get a feel for what is going to work and what isn't. Templates are how a static language like C++ deals with the concept of generic programming. Perl is such a dynamic language, that templates (which are resolved entirely at compile time) cannot be resolved when called by Perl. Perl's concept of parameter passing is so dynamic that function signatures (which C++ uses in resolving overloads) also can't be mapped meaningfully. There will be other features of C++ don't map into Perl, and vice versa. Consider C++ enums. Should Perl treat them as constants by mapping them via the constant pragma? The answer is unclear, and the fact is they won't be bound into Perl at all.
  • Multiple inheritance doesn't work right (yet).
  • Multi-dimensional arrays as member data aren't implemented (yet).
  • Declaring a paramater type of void isn't implemented. Just use int myfunc(); instead of int myfunc(void);. This is C++, not C. It's ok, really.
  • Exceptions: While it's ok to throw an exception using 'throw', Perl won't know how to recover from it, and you'll get a core-dump instead of a Perlish death. The solution is simple, croak("Message"). Perl will treat that as a call to die. The fifth example above demonstrates how to get the best of both worlds: C++'s rich exception handling, and Perl's die.
The gist of it is this: Catch your throws. And anything that can't be dealt with gracefully, re-throw back to Perl using croak.

Other grammar problems will probably be discovered. This is Perl, C++, and XS all sealed into one can of worms. But it can be fun, which is a description never applicable to raw XS. πŸ˜­πŸ’…


πŸ‘€ SEE ALSO πŸ‘€

For general information about how Inline binds code to Perl, see Inline.

For information on using C with Perl, see Inline::C and Inline::C-Cookbook. For WMTYEWTK, see perlguts, perlxs, perlxstut, perlapi, and perlcall. The literature for Inline::C (including the cookbook) is relevant and useful in learning Inline::CPP too; just about everything that works for Inline::C will work for Inline::CPP. Rather than reiterate all those great examples here, it's better to just refer the reader to Inline::C and Inline::C-Cookbook's documentation. πŸ“š

For converting an Inline::CPP module to pure XS (for simpler distribution), see InlineX::CPP2XS. This method is usually preferable to distributing with an Inline::CPP dependency, however, if you want to do that, read on... πŸ‘€

Math::Prime::FastSieve is a module based on Inline::CPP (using Inline::CPP and Inline::MakeMaker as dependencies). It serves as a proof of concept, another example of Inline::CPP at work, and a working example of basing a CPAN distribution on Inline::CPP. πŸ”₯

User and development discussion for Inline modules, including Inline::CPP occurs on the inline.perl.org mailing list. See http://lists.perl.org/list/inline.html to learn how to subscribe. πŸ’Œ

The maintainer has found Advanced Perl Programming, 2nd Edition (O'Reilly) helpful, although its discussion is focused on Inline::C.


πŸ’– AUTHOR πŸ’–

Neil Watkiss <NEILW@cpan.org> was the original author. πŸ‘‘

David Oswald <DAVIDO@cpan.org> is the current maintainer. David Oswald's Inline::CPP GitHub repo is: https://github.com/daoswald/Inline-CPP πŸ¦‹

Ingy dât Net <INGY@cpan.org> is the author of "Inline", and "Inline::C". ✨

🌟 CONTRIBUTING 🌟

okay so bestie, you wanna help out? iconic. here's the vibe πŸ’–

Issues are tracked, and you can totally report them at the distribution's GitHub issue tracker β€” it lives at https://github.com/daoswald/Inline-CPP/issues. that's the spot. ✨

  • Contributors may also fork the repo and issue pull requests. yes, go off. πŸ‘‘
  • Tests should accompany pull requests. fr fr, bring the tests, don't just drop code and dip. πŸ§ͺ
  • Effort should be made to minimize the scope of any single pull request. like, one thing at a time, bestie, keep it cute and reviewable. πŸŽ€
🚩 Pull requests should not add author names. nope. not the move.

Non-trivial contributions generally warrant attribution in the log maintained in the Changes file β€” though the decision to do so is at the discretion of the maintainers. so like, if you did real work, you'll probably get your lil shoutout in Changes, but that call belongs to the maintainers, no cap. πŸ’…

Please refer to the Artistic 2.0 license, contained in the LICENSE file, included with this distribution, for further explanation. it's right there in the distro, go read it. πŸ“œ


Copyright (c) 2000 - 2003 Neil Watkiss. Copyright (c) 2011 - 2014 David Oswald.

All Rights Reserved. This module is free software, licensed under the Artistic license, version 2.0. πŸ¦‹

See http://www.perlfoundation.org/artistic_license_2_0


and that's a wrap on the whole page, bestie 🫢 this version of Inline::CPP(3) is from perl v5.42.0, dated 2025-07-25 β€” so if you're reading this way later, maybe go check for a glow-up. anyway. slay, go write some C++ in your Perl, you got this πŸ’–βœ¨πŸŒˆ

πŸ“¦ where this page comes from