Hello, This lecture is about using Shared Libraries (in Linux) with the Perl language. While I over simplified things in this lecture, shared libraries, and libraries in general, are much more complex issue. Specially compiled ones.
1. Interface as (API and ABI [in compiled version] 2. The code does not change, like the idea of files VS RAM. 4. The binary format does not have execution block
In a whole, there are only two types of libraries. 2. There are more then one way to call Shared Library, such as: - static linking – the function always points to the same location inside executable file, and if the address or ABI changes, it will fail. - dynamic linking – calling the OS API to load the function in run-time. The address of the function is not of any interest of us (that is, if it changed or not), but the ABI change is of interest of us. ** Mac OS X for example have two types of dynamic libraries (normal unix .so, and .dylib)
Why would we want to use shard libraries with our Perl application (in the first place) ? A. Using an already existed systems such as Qt and KDE libraries to develop KDE plugins for example. B. inotify is just an example of user space kernel calls that are external and can be used. C. You know your reasons, no need to explain it to you :)
There is a problem with the Unix and Linux world: It is built to be a C world only. Everything is written to support C, and you must make yourself C compatible or die. But the C world, is usually ugly, long, and take too much man power to do something, and usually the syntax itself hides some bugs due to the amount of work and ambiguous syntax. It contains so many tools to ease the pain (auto tools, make scripts, pre-processors etc...), yet the basic is still problematic, and co But lucky for us It's not the only way ...
So according to Gematria Experts, Google result is the same as “life universe and everything”, and that's usually my type of “Hello World” example, so brace yourself, and see
Here is the C way. It's ugly, and I removed code such as defines and ifdef that are there to make sure that there is no loading duplication of code, because the compiler never know such things.
Now that we have C code, we first create a binary object file, with instructions with PIC calls. It Stand for Position Independent Code. That is the code is not executable but a library of some sort. Then we create with the shared library itself. We need to register the library with ld.so.conf(.d ). that is the Path of library, that will be accessible to our system. When we are finished, we use ldconfig again to register the position into cache that linker can find it. Then we can compile our program itself normally, and telling it to use the newly created shared library.
This is Pascal ! Yes PASCAL. The header explain the compiler we are creating a library. I created C like ABI, and even told it to use parameters loading order of C (usually used in Unix and Unix like systems). Then returning the a value, and telling the compiler that this code is exported. Then we compile the code, and the compiler by default understand we want shared library, (and not static one), so compile it accordingly. Then we continue doing the same work as with C: registering the library, and using it with any program out there.
We had fun with creating our own shared library, but how do we use it with Perl ? There are several ways to do it. The old way of DynaLoader – Still default for Windows btw, but on my Linux machine, it is not supported anymore The replacement of DynaLoader – XSLoader They both work with external so file, that is built in C, and translate C level into Perl, and equal in it's name to a package written in Perl, that the code bind both of them. It is highly recommended to support fallback from XSLoader to DynaLoader in the Perl package code. There is FFI::Raw that I'm going to expand shortly Ctypes – Still in development and unsupported properly. Inline – Write C/Java etc.. code inside Perl, and execute it externally like it was Perl code. Not a Dynamic Library binding per-se
I'm going to use FFI::Raw. It's very simple to use No Perl shared library is needed, or building instructions. However, at least now, it lack support for few things, such as using Struct/record
The code almost speak for itself: We use FFI::Raw Bind a variable as an object for a call. In this example I'm loading the function of life_universe_and_everything from the Pascal shard library. The 3 rd parameter is always the return type, while the parameters that will arrive after, are the parameters to use inside the “call” method. We use the object using the call method to actually execute the code.
As you can see, it was harder to write shared library then to use it. Here is a place to learn more about shared libraries in a whole. Any questions ?
Working with Shared Libraries in Perl
Working withShared Libraries In Perl
What is a Library ?● An interface that allow you to access existed functionality without writing it over and over again● Considered non volatile tool● Usually Written by compiled languages such as C, C++ and Pascal● Not executable on its own
There are two types of libraries● Static library – Compiled* inside your code like it was written for that application● Shared Library – Compiled once, resident in memory, (usually**) providing a map table for all its shared functions* Your cpan modules considered static library.** Depends on the file format and OS
Why ? (Perl vs Shared Libraries)● Accessing user environment tools. For example: – Qt/GTK – Xlib/XCB – Libc, libstdc++ – Databases (Firebird, PostgreSQL) – etc...● Using lower level tasks with a system (inotify ...)● ...
(In Linux) There are two ways to write one● The wrong, long way that (almost) everyone use● The short, readable, easier to maintain, less buggy way, that (almost) no one use.
The wrong way ...# make it support PIC$ gcc -c -Wall -Werror -fpic ac.c# Create the shared library$ gcc -shared -o libac.so ac.c# Register the library with ld.so.conf and refresh path and cache$ sudo ldconfig# Linking$ gcc -Wall -o test main.c -lac
The right and easy waylibrary apas;function google : Byte; cdecl;begin google := 42;End;exports google;end.$ fpc apas.pas$ ls *apas*# libapas.so# Register the library with ld.so.conf and refresh path and cache$ sudo ldconfig # use the lib
How to load Shared libraries in Perl● DynaLoader – The old way● XSLoader – The new way● FFI::Raw – External way (very simplified)● Ctypes – Still in development, unstable support● Inline – Writing C/Java etc inside Perl
FFI::Raw● It is very simple● No need for .XS file (shard library for Perl ABI)● No requirement for Makefile.PL● But, lack support for few features such as struct :(