Loading C libraries

You can compile C code to a library and then export the connections to be loaded by Perl. I have only messed around with this so it will take some time for me to get around to making an example.

More to come.

Download this as a working example Perl2C++
This is some raw notes and a test project I created. I will try to clean this up in the future.

Okay so I have some cool C++ objects that I have written and I want to use them from Perl without rewriting the entire thing.
To do this I found that I need to use DynaLoader to load C libraries from Perl. Sound easy, well it's not.
First of all the documentation for DynaLoader says that it is useless for this purpose because it provides almost no Perl-to-C 'glue'. There is, for example, no mechanism for calling a C library function or supplying arguments.

So after banging my head against a wall for a while and reading the source code for dozens of apps that I know use Perl and load C libraries I came across Xsubs and the online version of chapter 21 from the Programming Perl book from Orelly. It walked me through step by step how to write an xs file and Makefile.PL. Then you run h2xs and dozens of files are created. I don't fully understand how all of them work together or what they do but I think I am getting a good idea of what needs to be done.

If you have ever worked with C libraries and used the dl library to load libs at run time then you should be able to relate to this. Basically Perl cannot use native C libraries but you can create a bridge library that Perl can load and that it can link to other C libraries. That is what h2xs does for you in a few easy steps, it creates the source code to compile a bridge library and gives you the Perl module that is able to load it.

So back to my problem, I need C++ libraries in Perl. The Perl bridge library that is generated by h2xs will not let me use objects so I cannot use C++ operators like new and delete nor can it link to a library that contains only an object. It just does not know how to compile that. It is after all a Perl-to-C bridge compiler and not a C++ compiler.

No problem, just need to add a few extra steps.

So this is what you will find here. In order of dependencies.

CppObjectLib # This is the C++ object lib.
C2cppLibControl # This is a bridge from the Perl bridge to the C++ object lib.
test1 # This tests if the C2cppLibControl is working.
Perl2C # This is the Perl to C bridge created by h2xs
PerlObjectControl # This is that Perl object library used by FinalApp
FinalApp # This is the final user app that will use the C++ object from Perl.
Makefile # This is a make file to compile it all.
lib # This is just a common place for me to put the C & C++ libs

If you want to run the test app test1 you will need to tell the OS where to find the libs in the ./lib directory.
Do this by setting the LD_LIBRARY_PATH variable like so

cd ~
export LD_LIBRARY_PATH=~/lib
cd test1
./test1.elf

CppObjectLib/CppObjectLib.h

#ifndef included_CppObjectLib
#define included_CppObjectLib
 
class CppObjectLib
{
        public:
                CppObjectLib();
                ~CppObjectLib();
                int SomeCalc(int GivenNumber);
                void SetMultiplyer(int NewMulti);
                int GetMultiplyer();
 
        private:
                int Multiplyer;
};
 
#endif

CppObjectLib/CppObjectLib.cpp

#include "CppObjectLib.h"
#include <stdio.h>
 
CppObjectLib::CppObjectLib()
{
        printf("This is the object constructor\n");
        Multiplyer = 3;
}
 
CppObjectLib::~CppObjectLib()
{
        printf("This is the object destructor\n");
}
 
void CppObjectLib::SetMultiplyer(int NewMulti)
{
        Multiplyer = NewMulti;
}
 
int CppObjectLib::GetMultiplyer()
{
        return(Multiplyer);
}
 
int CppObjectLib::SomeCalc(int GivenNumber)
{
        printf("int CppObjectLib::SomeCalc(%d)\n",GivenNumber);
        return(Multiplyer * GivenNumber);
}

C2cppLibControl/C2cppLibControl.h

#ifndef included_C2cppLibControl
#define included_C2cppLibControl
 
#ifdef __cplusplus
extern    "C"
{
#endif
   // Creates a new object and returns the pointer to it.
        int Constructor();
 
   // Destroys an object that the given pointer points to.
   void Destructor(int ObjectPointer);
 
        void SetMultiplyer(int ObjectPointer, int NewMulti);
 
        int GetMultiplyer(int ObjectPointer);
 
        int SomeCalc(int ObjectPointer, int GivenNumber);
#ifdef __cplusplus
};
#endif
 
#endif

C2cppLibControl/C2cppLibControl.c

#include "C2cppLibControl.h"
#include <CppObjectLib.h>
 
/* This may not be the best way to do this. Perl DynaLoader can only load libraries like dl does so it cannot use objects.
Object control must be done in Perl because the C wrapper cannot control the construction and destruction of objects. */
 
int Constructor()
{
        CppObjectLib *ObjectPointer = new CppObjectLib();
        return((int)ObjectPointer);
}
 
void Destructor(int ObjectPointer)
{
        CppObjectLib *GivenPointer = (CppObjectLib *)ObjectPointer;
        delete GivenPointer;
}
 
void SetMultiplyer(int ObjectPointer, int NewMulti)
{
        ((CppObjectLib *)ObjectPointer)->SetMultiplyer(NewMulti);
}
 
int GetMultiplyer(int ObjectPointer)
{
        return(((CppObjectLib *)ObjectPointer)->GetMultiplyer());
}
 
int SomeCalc(int ObjectPointer, int GivenNumber)
{
        //ExampleLibrary *LocalPointer = (ExampleLibrary *)ObjectPointer;
        //return(LocalPointer->SomeCalc(GivenNumber));
        return(((CppObjectLib *)ObjectPointer)->SomeCalc(GivenNumber));
}

test1/test1.c

#include <C2cppLibControl.h>
#include <stdio.h>
 
int main(int argc, char **argv)
{
        int ObjectPointer;
        int Answer;
 
        printf("here we are 1\n");
        ObjectPointer = Constructor();
        printf("here we are 2\n");
        Answer = SomeCalc(ObjectPointer, 3);
        printf("here we are 3\n");
        printf("Answer is %d\n", Answer);
        Destructor(ObjectPointer);
        return(0);
}

Perl2C/Perl2C.xs

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
 
#include "ppport.h"
 
MODULE = Perl2C         PACKAGE = Perl2C
 
#include <C2cppLibControl.h>
 
int PConstructor()
   CODE:
      RETVAL = Constructor();
   OUTPUT:
      RETVAL
 
void PDestructor(ObjectPointer)
      int ObjectPointer
   CODE:
      Destructor(ObjectPointer);
 
void PSetMultiplyer(ObjectPointer, NewMulti)
      int ObjectPointer
                int NewMulti
   CODE:
      SetMultiplyer(ObjectPointer, NewMulti);
 
int PGetMultiplyer(ObjectPointer)
      int ObjectPointer
   CODE:
      RETVAL = GetMultiplyer(ObjectPointer);
        OUTPUT:
                RETVAL
 
int PSomeCalc(ObjectPointer, GivenNumber)
      int ObjectPointer
      int GivenNumber
   CODE:
      RETVAL = SomeCalc(ObjectPointer, GivenNumber);
   OUTPUT:
      RETVAL
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License