23 KiB
title, order
| title | order |
|---|---|
| Extension Maintainers | 3 |
PIE for Extension Maintainers
The PIE build & install steps
Non-Windows (e.g. Linux, OSX, etc.)
PIE follows the usual PHP extension build and install process, namely:
phpizeto set up the PHP API parameters. The person installing the extension may specify--with-phpize-pathifphpizeis not in the path../configureto configure the build parameters and libraries for the specific system. The person installing the extension may specify the configure options that you have specified incomposer.json. See the Configure Options documentation for how to do this.maketo actually build the extension. This will try to detect the number of parallel processes to run automatically, but the person installing may override this with--make-parallel-jobs Nor-jNoptions.make installto install the extension to the configured PHP installation. If PIE does not have permissions to write to the installation location, it will attempt to elevate privileges withsudo.
Note that this does mean the systems you are running PIE on need to have the appropriate build tools installed. A useful resource for building extensions and how PHP's internal works is the PHP Internals Book.
Windows
For Windows systems, extension maintainers must provide pre-built binaries. See the Windows Support section below for details on how to do this in the right way for PIE.
How to add PIE support for your extension
Adding PIE support for your extension is relatively straightforward, and the flow is quite similar to adding a regular PHP package into Packagist.
Extensions already on PECL
If you are a maintainer of an existing PECL extension, here are a few helpful pieces of information for some context:
- For an extension already in PECL, the
package.xmlis no longer needed if you no longer want to publish to PECL. If you want to keep publishing to PECL for now, then you can keeppackage.xmlmaintained. - The
package.xmllists each release explicitly. With PIE, this is no longer necessary, as Packagist will pick up tags or branch aliases in the same way that regular Composer packages do. This means that to release your package, you need to push a tag and release. - In the default setup, the contents of the package are determined by the Git archive for the tag or revision of the release. You can exclude files and paths from the archive with the export-ignore attribute.
Add a composer.json to your extension
The first step to adding PIE support is adding a composer.json to your
extension repository. Most of the typical fields are the same as a regular
Composer package, with a few notable exceptions:
- The
typeMUST be eitherphp-extfor a PHP Module (this will be most extensions), orphp-ext-zendfor a Zend Extension. - An additional
php-extsection MAY exist (see below for the directives that can be withinphp-ext) - The Composer package name (i.e. the top level
namefield) MUST follow the usual Composer package name format, i.e.<vendor>/<package>. - However, please note that the Composer package name for a PIE extension
MUST NOT share the same Composer package name as a regular PHP package, even
if they have different
typefields.
The php-ext definition
extension-name
The extension-name MAY be specified, and MUST conform to the usual extension
name regular expression, which is defined in
\Php\Pie\ExtensionName::VALID_PACKAGE_NAME_REGEX.
If the extension-name is not specified, the extension-name will be derived
from the Composer package name, with the vendor prefix removed. For example,
given a composer.json with:
{
"name": "myvendor/myextension"
}
The extension name would be derived as myextension. The myvendor/ vendor
prefix is removed.
Warning
If your Composer package name would result in an invalid PHP extension name, you MUST specify the
extension-namedirective. For example a Composer package namemyvendor/my-extensionwould result in an invalid PHP extension name, since hypens are not allowed, so you MUST specify a validextension-namefor this Composer package name.
The extension-name SHOULD NOT be prefixed with ext- as is a convention in
Composer when using require.
An example of extension-name being used:
{
"name": "xdebug/xdebug",
"php-ext": {
"extension-name": "xdebug"
}
}
priority
priority forms part of the ini filename to control ordering of extensions,
if the target platform uses the multiple INI files in a directory.
support-zts and support-nts
Indicates whether the extension supports Zend Thread-Safe (ZTS) and non-Thread-
Safe (NTS) modes. Both these flags default to true if not specified, but if
your extension does not support either mode, it MUST be specified, and will
mean the extension will not be installable on the target platform.
Theoretically, it is possible to specify false for both support-zts and
support-nts, but this will mean your package cannot be installed anywhere, so
is not advisable.
configure-options
This is a list of parameters that may be passed to the ./configure command.
Each item of the list is a JSON object with:
name, the parameter name itselfdescription, a helpful description of what the parameter does- optionally,
needs-value, a boolean to tell PIE whether the parameter is a simple flag (typically used for--enable-this-flagtype parameters), or if the parameter should have a value specified (typically used for--with-library-path=...type parameters, where a value must be given by the end user)
When an end user is installing an extension with PIE, they may specify any
defined configure-options that are passed to ./configure. For example, if
an extension defines the following composer.json:
{
"name": "myvendor/myext",
"php-ext": {
"extension-name": "myext",
"configure-options": [
{
"name": "enable-my-flag",
"description": "Should my flag be enabled",
"needs-value": false
},
{
"name": "with-some-lib",
"description": "Specify the path to some-lib",
"needs-value": true
}
]
}
}
Then the pie build or pie install commands may be invoked in the following
ways to achieve the desired configuration:
pie install myvendor/myext- This will simply invoke
./configurewithout any parameters
- This will simply invoke
pie install myvendor/myext --enable-my-flag- This will invoke
./configure --enable-my-flag
- This will invoke
pie install myvendor/myext --with-some-lib=/path/to/somelib- This will invoke
./configure --with-some-lib=/path/to/somelib
- This will invoke
pie install myvendor/myext --enable-my-flag --with-some-lib=/path/to/somelib- This will invoke
./configure --enable-my-flag --with-some-lib=/path/to/somelib
- This will invoke
Note that it is not possible for end users of PIE to specify configuration
options that have not been defined in your extension's configure-options
definition. Using the same example above composer.json, invoking PIE with
an invalid option, such as pie install myvendor/myext --something-else will
result in an error The "--something-else" option does not exist..
If an end user does not specify a flag defined in the configure-options
definition, it will not be passed to ./configure. There is no way to specify
a default value in the configure-options definition. Your config.m4 should
handle this accordingly.
build-path
The build-path setting may be used if your source code is not in the root
of your repository. For example, if your repository structure is like:
/
docs/
src/
config.m4
config.w32
myext.c
...etc
In this case, the actual extension source code would be built in src/, so you
should specify this path in build-path, for example:
{
"name": "myvendor/myext",
"php-ext": {
"extension-name": "myext",
"build-path": "src"
}
}
The build-path may contain some templated values which are replaced:
{version}to be replaced with the package version. For example a package with version 1.2.3 with abuild-pathofmyext-{version}the actual build path would becomemyext-1.2.3.
download-url-method
The download-url-method directive allows extension maintainers to
change the behaviour of downloading the source package. This should be defined
as a list of supported methods, but for backwards compatibility a single
string may be used.
The possible values are:
composer-defaultpre-packaged-sourcepre-packaged-binary
The default value, if nothing is specified is ["composer-default"].
composer-default
Setting this to composer-default, which is the default value if nothing is
specified, will use the default behaviour implemented by Composer, which is
to use the standard ZIP archive from the GitHub API (or other source control
system). PIE will then build and install the extension from source.
pre-packaged-source
Using pre-packaged-source will locate a source code package in the release
assets list based matching one of the following naming conventions:
php_{ExtensionName}-{Version}-src.tgz(e.g.php_myext-1.20.1-src.tgz)php_{ExtensionName}-{Version}-src.zip(e.g.php_myext-1.20.1-src.zip){ExtensionName}-{Version}.tgz(this is intended for backwards compatibility with PECL packages)
This is useful for scenarios where you might need additional dependencies pulled into the source build, which would not be available if you downloaded the ZIP archive from your repository. For example, if your extension uses Git Submodules to include third party libraries statically in the build.
pre-packaged-binary
Caution
If your extension depends on dynamically linked libraries, it is not recommended to use
pre-packaged-binaryoption, as the correct version, or at least compatible linked libraries may not be available on the end user's system. Use with caution!
Using pre-packaged-binary will attempt to locate a Zip (or TGZ) archive in
the release assets list based on matching one of the following naming
conventions:
php_{ExtensionName}-{Version}_php{PhpVersion}-{Arch}-{OS}-{Libc}-{Debug}-{TSMode}.{Format}
The replacements are:
{ExtensionName}the name of your extension, e.g.yourext(hint: this is not your Composer package name!){PhpVersion}the major and minor version of PHP, e.g.8.5{Version}the version of your extension, e.g.1.20.1{Arch}the architecture of the binary, one ofx86,x86_64,arm64{OS}the operating system, one ofwindows,darwin,linux,bsd,solaris,unknown{Libc}the libc flavour, one ofglibc,musl,bsdlibc{Debug}the debug mode, one ofdebug,nodebug(or omitted){TSMode}the thread safety mode, one ofzts,nts(or omitted){Format}the archive format, one ofzip,tgz- note that ZIP is preferred as it means there are fewer dependencies for the end user
Tip
In order to generate pre-built binaries for PIE, you could use the php/pie-ext-binary-builder GitHub Action. This will build and name the assets correctly for you.
Some examples of valid asset names:
php_yourext-4.1_php8.4-x86_64-linux-glibc.zip(orphp_yourext-4.1_php8.4-x86_64-glibc-nts.zip)php_yourext-4.1_php8.4-x86_64-linux-musl.zip(orphp_yourext-4.1_php8.4-x86_64-musl-nts.zip)php_yourext-4.1_php8.4-arm64-linux-glibc.zip(orphp_yourext-4.1_php8.4-arm64-glibc-nts.zip)php_yourext-4.1_php8.4-arm64-linux-musl.zip(orphp_yourext-4.1_php8.4-arm64-musl-nts.zip)php_yourext-4.1_php8.4-x86_64-linux-glibc-zts.zipphp_yourext-4.1_php8.4-x86_64-linux-musl-zts.zipphp_yourext-4.1_php8.4-arm64-linux-glibc-zts.zipphp_yourext-4.1_php8.4-arm64-linux-musl-zts.zipphp_yourext-4.1_php8.4-x86_64-linux-glibc-debug.zipphp_yourext-4.1_php8.4-x86_64-linux-musl-debug.zipphp_yourext-4.1_php8.4-arm64-linux-glibc-debug.zipphp_yourext-4.1_php8.4-arm64-linux-musl-debug.zip
It is recommended that pre-packaged-binary is combined with composer-default
as a fallback mechanism, if a particular combination is supported, but not
pre-packaged on the release, e.g. "download-url-method": ["pre-packaged-binary", "composer-default"].
PIE will try to find a pre-packaged binary asset first, but if it cannot
find an appropriate binary, it will download the source code and build it
in the traditional manner.
{
"name": "myvendor/myext",
"php-ext": {
"download-url-method": ["pre-packaged-binary", "composer-default"]
}
}
os-families restrictions
The os-families and os-families-exclude directive allow extention maintainers
to restrict the Operating System compatibility.
os-familiesAn array of OS families to mark as compatible with the extension. (e.g."os-families": ["windows"]for an extension only available on Windows)os-families-excludeAn array of OS families to mark as incompatible with the extension. (e.g."os-families-exclude": ["windows"]for an extension that cannot be installed available on Windows)
The list of accepted OS families: "windows", "bsd", "darwin", "solaris", "linux", "unknown"
Warning
Only one of
os-familiesandos-families-excludecan be defined.
Extension dependencies
Extension authors may define some dependencies in require, but typically,
most extensions would not need to define dependencies, except for the PHP
versions supported by the extension, and system libraries.
Dependencies on a regular PHP package (such as monolog/monolog) SHOULD NOT be
specified in your extension's require section.
Dependencies on other extensions
Dependencies on other extensions may be defined, for example ext-json.
It is worth noting that if your extension does define a dependency on another dependency, and this is not available, someone installing your extension would receive a message such as:
Cannot use myvendor/myextension's latest version 1.2.3 as it requires
ext-something * which is missing from your platform.
System Library Dependencies
In PIE 1.4.0, the ability for extension authors to define system library dependencies was added, and in some cases, automatically install them.
The following libraries are supported at the moment. If you would like to add a library, please open a discussion in the first instance. Don't just open a PR without discussing first please!
We are adding libraries and improving this feature over time. If the automatic install of a system dependency that is supported below in your package manager is NOT working, then please report a bug.
| Library | Checked by PIE | Auto-installs in |
|---|---|---|
| lib-curl | ✅ | apt, apk, dnf, yum |
| lib-enchant | ✅ | ❌ |
| lib-enchant-2 | ✅ | ❌ |
| lib-sodium | ✅ | apt, apk, dnf, yum |
| lib-ffi | ✅ | apt, apk, dnf, yum |
| lib-xslt | ✅ | apt, apk, dnf, yum |
| lib-zip | ✅ | apt, apk, dnf, yum |
| lib-png | ✅ | ❌ |
| lib-avif | ✅ | ❌ |
| lib-webp | ✅ | ❌ |
| lib-jpeg | ✅ | apt, apk, dnf, yum |
| lib-xpm | ✅ | ❌ |
| lib-freetype2 | ✅ | ❌ |
| lib-gdlib | ✅ | ❌ |
| lib-gmp | ✅ | ❌ |
| lib-sasl | ✅ | ❌ |
| lib-onig | ✅ | ❌ |
| lib-odbc | ✅ | ❌ |
| lib-capstone | ✅ | ❌ |
| lib-pcre | ✅ | ❌ |
| lib-edit | ✅ | ❌ |
| lib-snmp | ✅ | ❌ |
| lib-argon2 | ✅ | ❌ |
| lib-uriparser | ✅ | ❌ |
| lib-exslt | ✅ | ❌ |
Checking the extension will work
First up, you can use composer validate to check your composer.json is
formatted correctly, e.g.:
$ composer validate
./composer.json is valid
You may then use pie install to install your extension while in its directory:
$ cd /path/to/my/extension
$ pie install
🥧 PHP Installer for Extensions (PIE) 1.0.0, from The PHP Foundation
Installing PIE extension from /home/james/workspace/phpf/example-pie-extension
This command may need elevated privileges, and may prompt you for your password.
You are running PHP 8.4.8
Target PHP installation: 8.4.8 nts, on Linux/OSX/etc x86_64 (from /usr/bin/php8.4)
Found package: asgrim/example-pie-extension:dev-main which provides ext-example_pie_extension
Extracted asgrim/example-pie-extension:dev-main source to: /home/james/.config/pie/php8.4_572ee73609adb95bf0b8539fecdc5c0e/vendor/asgrim/example-pie-extension
Build files cleaned up.
phpize complete.
Configure complete.
Build complete: /home/james/.config/pie/php8.4_572ee73609adb95bf0b8539fecdc5c0e/vendor/asgrim/example-pie-extension/modules/example_pie_extension.so
Cannot write to /usr/lib/php/20240924, so using sudo to elevate privileges.
Install complete: /usr/lib/php/20240924/example_pie_extension.so
✅ Extension is enabled and loaded in /usr/bin/php8.4
Building without installing
If you want to just test the build of your application, without installling it to your target PHP version, you will first need to your extension directory as a "path" type repository:
$ cd /path/to/my/extension
$ pie repository:add path .
🥧 PHP Installer for Extensions (PIE) 1.0.0, from The PHP Foundation
You are running PHP 8.4.8
Target PHP installation: 8.4.8 nts, on Linux/OSX/etc x86_64 (from /usr/bin/php8.4)
The following repositories are in use for this Target PHP:
- Path Repository (/home/james/workspace/phpf/example-pie-extension)
- Packagist
Then you may test that it builds with:
$ pie build asgrim/example-pie-extension:*@dev
Tip
Since your extension is not yet published to Packagist, you should specify
*@devas the version constraint, otherwise PIE will not find your extension as the default stability isstable.
Submit the extension to Packagist
Once you have committed your composer.json to your repository, you may then
submit it to Packagist in the same way as any other package.
- Head to https://packagist.org/packages/submit
- Enter the URL of your repository and follow the instructions.
Windows Support
In order to support Windows users, you must publish pre-built DLLs, as PIE does not currently support building DLLs on the fly. The expected workflow for Windows-compatible releases is:
- The release is made on GitHub (only GitHub is supported at the moment)
- A CI pipeline runs to build the release assets, e.g. in a GitHub Action
- The resulting build assets are published to the GitHub release in a ZIP file
The name of the ZIP file, and the DLL contained within must be:
php_{extension-name}-{tag}-{php-maj/min}-{ts|nts}-{compiler}-{arch}.zip- Example:
php_xdebug-3.3.2-8.3-ts-vs16-x86_64.zip
The descriptions of these items:
extension-namethe name of the extension, e.g.xdebugtagfor example3.3.0alpha3- defined by the tag/release you have madephp-maj/min- for example8.3for PHP 8.3.*compiler- usually something likevc6,vs16- fetch from 'PHP Extension Build' flags inphp -its|nts- Thread-safe or non-thread safe.arch- for examplex86_64.- Windows: use a hint from
Architecturefromphp -i(see below) - non-Windows: check
PHP_INT_SIZE- 4 for 32-bit, 8 for 64-bit.
- Windows: use a hint from
Note the architecture name will likely need normalising, since different platforms name architectures differently. PIE expects the following normalised architectures:
x86_64(normalised fromx64,x86_64,AMD64)arm64(normalised fromarm64)x86(any other value)
For the latest map (in case documentation is not up to date), check out
\Php\Pie\Platform\Architecture::parseArchitecture.
Contents of the Windows ZIP
The pre-built ZIP should contain at minimum a DLL named in the same way as the
ZIP itself, for example
php_{extension-name}-{tag}-{php-maj/min}-{ts|nts}-{compiler}-{arch}.dll.
The .dll will be moved into the PHP extensions path, and renamed, e.g.
to C:\path\to\php\ext\php_{extension-name}.dll. The ZIP file may include
additional resources, such as:
php_{extension-name}-{tag}-{php-maj/min}-{ts|nts}-{compiler}-{arch}.pdb- this will be moved alongside theC:\path\to\php\ext\php_{extension-name}.dll*.dll- any other.dllwould be moved alongsideC:\path\to\php\php.exe- Any other file, which would be moved
into
C:\path\to\php\extras\{extension-name}\.
Automation of the Windows publishing
PHP provides a set of GitHub Actions that enable extension maintainers to build and release the Windows compatible assets. An example workflow that uses these actions:
name: Publish Windows Releases
on:
release:
types: [published]
permissions:
contents: write
jobs:
get-extension-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.extension-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get the extension matrix
id: extension-matrix
uses: php/php-windows-builder/extension-matrix@v1
build:
needs: get-extension-matrix
runs-on: ${{ matrix.os }}
strategy:
matrix: ${{fromJson(needs.get-extension-matrix.outputs.matrix)}}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build the extension
uses: php/php-windows-builder/extension@v1
with:
php-version: ${{ matrix.php-version }}
arch: ${{ matrix.arch }}
ts: ${{ matrix.ts }}
release:
runs-on: ubuntu-latest
needs: build
if: ${{ github.event_name == 'release' }}
steps:
- name: Upload artifact to the release
uses: php/php-windows-builder/release@v1
with:
release: ${{ github.event.release.tag_name }}
token: ${{ secrets.GITHUB_TOKEN }}
Source: https://github.com/php/php-windows-builder?tab=readme-ov-file#examples