Download the PHP package rask/libload without Composer
On this page you can find all versions of the php package rask/libload. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package libload
rask/libload
A small library to help in loading FFI libraries in a straight-forward manner.
Rationale
The vanilla methods of loading dynamic libraries via PHP FFI are simple and understandable:
\FFI::cdef()
allows you to take in a library, and write the library header definition on the fly.\FFI::load()
allows you to take in a library header, inside which residesFFI_LIB
that points to a dynamic library to load.
This is all fine and well, apart from one thing:
You're locked tight into the logic of dlopen(3)
, which is a C function to load dynamic libraries. In essence this means the following:
- You cannot use relative paths for
FFI_LIB
, as those operate on current working directory, which can be whatever - You cannot use absolute paths, as all software is runnable anywhere on any system in any path
- You cannot rely on
LD_LIBRARY_PATH
as it cannot be altered at runtime, and you would require users of your code to set it up properly - You cannot use
/lib
or/usr/lib
, as that would be senseless pollution on the user's system, not to speak of requiring admin privileges
In smaller projects with limited audiences these limitations might not matter. Or maybe the library you intend to use is a well-known and often preinstalled one (e.g. libc
). But once you want to distribute public code that relies on a custom built FFI library, you're in trouble.
So, the only real reason this library exists is to bypass these limitations, and allow you to load a dynamic library in a few different ways.
Features
- Load libraries the
dlopen(3)
way - Load libraries relative to the header file
- Load libraries relative to a custom path
- Load libraries by searching for them inside a directory tree
Example
Where my_lib.h
contains
The example above instantiates a new Loader
, and then we instruct it to load a header file with the relative lookup mode.
So, if a dynamic library exists in /path/to/libs/my_lib.so
it should get loaded and return a regular PHP \FFI
instance for us.
How it works
In a nutshell:
The loader reads your header file, parses the FFI_LIB
definitions, and then just uses \FFI::cdef()
with the header file and a proper path to the library you actually want to load.
A little hacky, yes.
Installation
$ composer require rask/libload
Usage
Using PHP default logic
To use the default \FFI::load()
logic (aka dlopen(3)
logic), you can use the loader as follows:
Loading a library relative to header
If your header file defines an FFI_LIB
that is located relative to the header file itself, you can use
You header file might contain
So $loader
would look for the library in ./path/to/header/subdir/lib.so
.
Using this method fails if the FFI_LIB
definition contains an absolute path.
This method disables the default dlopen(3)
logic.
Loading a library relative to a custom path
If your library is located in a specific directory, you can load it using
You header file might contain
So $loader
would look for the library in /my/awesome/libs/subdir/lib.so
.
Using this method fails if the FFI_LIB
definition contains an absolute path.
This method disables the default dlopen(3)
logic.
Loading a library by searching inside a directory
If you have a directory tree with an arbritary structure but know the name of the library, you can search for it using
And if your directory tree is as follows
And if your header defines
Then $loader
will find /my/awesome/libs/subdir1/lib4.so
. The search will be slower in larger directories.
This method disables the default dlopen(3)
logic.
Multiple library loading and resetting the loader
If you want to use the same loader instance for all kinds of loading needs across your application, you may need to reset it depending on how you want to load various libraries.
You can use resetting as such:
If you have loads of variance in loading types, you can configure the instance to reset after each load:
If you don't use resetting, you can keep using the same loading method for multiple libraries:
Todo
- More ways to load libraries?
- Make it work with headers that provide
FFI_SCOPE
(i.e. make it work with preloading) - Make this package useless, by pestering PHP core devs to add this functionality to the PHP core FFI implementation
Notes
This package might be useless if you do not intend to write FFI code that is to be distributed as a package or something. Also this might be overkill if you can load your FFI instances using pure \FFI::cdef()
instead.
Currently FFI library loading in opcache preloading contexts is confusingly documented, so this package waits for confirmations on how to actually preload FFI libraries in production before making commitments towards preloading-compatibility. Use this for CLI apps for now.
Contributing
Development requirements apart from a PHP CLI installation that supports FFI, you need to have gcc
and make
available, and being able to compile on a system that produces Linux shared object binaries (*.so
). This means you probably cannot run tests on Windows or Mac right now. Some tests require you to have /lib/x86_64-linux-gnu/libc.so.6
available in your system.
We need gcc
and make
so we can build a shared library for testing purposes when running PHPUnit.
Before sending code as a pull request:
- Try to add tests for your changes (
composer test
), or ask for help from the maintainers with it - Run linting and static analysis against your code before commiting (
composer lint
andcomposer stan
)
If you have problems using the package, you can raise issues. Documentation and cleanup contributions very welcome. Feature requests are OK as long as they're not too far from the core purpose of this package: making loading FFI libraries a little simpler/easier/saner/etc.
If you have any questions about how to contribute, you can create an issue and ask for pointers.
License
MIT License, see LICENSE.md.