Files
static-php-cli/docs/en/develop/package-model.md

15 KiB

Package Model

Package Definition

A Package is the core concept in StaticPHP's build system, representing a buildable/installable unit such as a PHP extension, library, or build target.

Each Package contains build information, dependencies, and build logic, forming StaticPHP's build model. Package definitions are primarily implemented through YAML/JSON configuration files. The package configuration files for the core registry are located in the config/pkg/ directory, and optional recipe classes are in the corresponding subdirectories of src/Package/.

Packages are divided into five types:

  • php-extension: A PHP extension package containing build information and logic for a PHP extension.
  • library: A dependency library package, usually installed into buildroot/ for other packages to compile and link against.
  • target: A build target package representing the final build artifact, such as a PHP binary or curl binary. Inherits from the library package type.
  • virtual-target: A virtual build target package representing an abstract build target that doesn't directly correspond to a build artifact, primarily used for dependency management and build scheduling.
  • tool: A host-side build tool package, installed separately under pkgroot/ and not treated as a link-time library dependency.
{pkg-name}:
  type: {pkg-type}
  ...

Artifact Definition

An Artifact is a definition independent of Packages. It contains the source archive file or pre-built binary for building packages. Each Artifact defines download URLs, extraction methods, and build artifact file paths. A Package can reference one Artifact via the artifact field to obtain the source or binary needed for building.

In simple terms, by default one Package corresponds to one Artifact; if multiple Packages share the same source, you can define a single Artifact for multiple Packages to reference. Artifact definitions are located in the config/artifact/ directory, and the corresponding custom download/extract logic classes are in the src/Package/Artifact/ directory. For special package types like virtual targets and PHP built-in extensions, a Package may also omit the Artifact field entirely.

Assuming example-library-package is a dependency library whose source archive is hosted at https://example.com/example-library.tar.gz, its Package and Artifact definitions would look like this:

example-library-package:
  type: library
  artifact:
    source:
      type: url
      url: 'https://example.com/example-library.tar.gz'

For more on Artifact definitions, see the Artifact Model chapter.

php-extension Package Type

A php-extension package represents a PHP extension. Its configuration file is located in the config/pkg/ext/ directory. Optional recipe classes are normally placed in src/Package/Extension/, registered with #[Extension], and receive the corresponding PhpExtensionPackage through callback context. Inheriting from PhpExtensionPackage is supported but is not required by the current core recipes.

ext-lz4:
  type: php-extension
  artifact:
    source:
      type: git
      url: 'https://github.com/kjdev/php-ext-lz4.git'
      rev: master
      extract: php-src/ext/lz4
    metadata:
      license-files: [LICENSE]
      license: MIT
  depends:
    - liblz4
  php-extension:
    arg-type@unix: '--enable-lz4@shared_suffix@ --with-lz4-includedir=@build_root_path@'
    arg-type@windows: '--enable-lz4'

Allowed fields for php-extension:

ext-{ext-name}:          # Package name must start with ext- prefix
  type: php-extension

  # ── Common Fields ────────────────────────────────────────────────────────
  description: '..'       # Optional, human-readable package description
  lang: c                 # Optional, implementation language of the extension (c / c++ etc.)
  frameworks: []          # Optional, list of related macOS framework dependencies

  artifact: '{artifact-name}'  # Optional; when a string, references the named Artifact definition;
                               # when an object, it is an inline Artifact
                               # (built-in extensions don't need this field)

  # depends / suggests / tools support @windows / @unix / @linux / @macos suffixes
  depends: []             # Optional, hard dependency list (library names as-is, PHP extensions need ext- prefix)
  depends@unix: []        # Optional, hard dependencies only effective on Unix platforms
  depends@windows: []     # Optional, hard dependencies only effective on Windows platforms
  suggests: []            # Optional, optional dependency list (same format as depends)
  suggests@unix: []
  tools: []               # Optional, host-side build tool dependencies; resolved separately
  tools@windows: []       # Optional, platform-specific tool dependencies

  # ── php-extension Specific Fields (nested under php-extension: object) ────
  php-extension:
    # arg-type determines the form of arguments passed to ./configure, supports platform suffixes
    # Supported platform suffixes: @unix (Linux + macOS), @linux, @macos, @windows
    # Priority (using Linux as example): arg-type@linux > arg-type@unix > arg-type (no suffix)
    # Built-in keywords:
    #   enable      → --enable-{extname} (default value, used when not configured)
    #   enable-path → --enable-{extname}={buildroot}
    #   with        → --with-{extname}
    #   with-path   → --with-{extname}={buildroot}
    #   custom/none → Pass no arguments (handled by the #[CustomPhpConfigureArg] method in the PHP class)
    # You can also write the full argument string directly, supporting the following placeholders:
    #   @build_root_path@      → BUILD_ROOT_PATH (absolute path of buildroot)
    #   @shared_suffix@        → Expands to =shared in shared builds, empty in static builds
    #   @shared_path_suffix@   → Expands to =shared,{buildroot} in shared builds,
    #                            expands to ={buildroot} in static builds
    arg-type: enable
    arg-type@unix: '--enable-my-extension@shared_suffix@'
    arg-type@windows: with-path

    zend-extension: false   # Optional, true indicates this is a Zend extension (e.g., opcache, xdebug)
    build-shared: true      # Optional, whether building as a shared extension (.so) is allowed, default true
    build-static: true      # Optional, whether inline static building (compiled into PHP) is allowed, default true
    build-with-php: true    # Optional, true means the extension is built together via the PHP source tree
                            # (used for built-in extensions)

    # display-name affects the php --ri argument in smoke tests and the license export display name
    # If not set, defaults to the extension name (the part after ext-); if set to empty string, skips --ri check
    display-name: 'My Extension'

    # os restricts the extension to be available only on specified platforms;
    # platforms not in the list will be rejected for building
    # Allowed values: Linux, Darwin, Windows
    os: [Linux, Darwin]

library Package Type

A library package represents a dependency library, such as openssl or zlib, installed from source or a pre-built binary. Its configuration file is located in the config/pkg/lib/ directory. Optional recipe classes are normally placed in src/Package/Library/, registered with #[Library], and receive a LibraryPackage through callback context; they do not need to inherit from it.

Taking openssl as an example:

openssl:
  type: library
  artifact:
    source:
      type: ghrel
      repo: openssl/openssl
      match: openssl.+\.tar\.gz
      prefer-stable: true
    binary: hosted
    metadata:
      license-files: [LICENSE.txt]
      license: OpenSSL
  depends:
    - zlib
  depends@windows:
    - zlib
    - jom
  headers:
    - openssl
  static-libs@unix:
    - libssl.a
    - libcrypto.a
  static-libs@windows:
    - libssl.lib
    - libcrypto.lib

Allowed fields for library:

{lib-name}:
  type: library           # library or target (target inherits all fields from library)

  # ── Common Fields ─────────────────────────────────────────────────────────
  description: '..'       # Optional, human-readable package description
  license:                # Optional, license material copied after a source build
    type: file            # type is file or text; a list of entries is also accepted
    path: LICENSE
  lang: c                 # Optional, implementation language of the library (c / c++ etc.)
  frameworks: []          # Optional, list of related framework tags

  artifact: '{artifact-name}'  # Required; when a string, references the named Artifact definition;
                               # when an object, it is an inline Artifact

  # depends / suggests / tools support @windows / @unix / @linux / @macos suffixes
  depends: []             # Optional, hard dependency list (library names or PHP extension names with ext- prefix)
  depends@unix: []
  depends@windows: []
  suggests: []            # Optional, optional dependency list (same format as depends)
  tools: []               # Optional, ToolPackage names required only while building
  tools@windows: []

  # ── library / target Specific Fields ───────────────────────────────────────
  # The following fields are used to verify that artifacts have been correctly
  # installed after the build. headers, static-libs, and static-bins support
  # @unix / @windows / @linux / @macos suffixes.

  # Verify that specified header files or directories exist under buildroot/include/
  # Relative paths are based on buildroot/include/, absolute paths are used directly
  headers:
    - openssl             # Corresponds to buildroot/include/openssl/
    - zlib.h              # Corresponds to buildroot/include/zlib.h
  headers@unix:
    - ffi.h

  # Verify that specified static library files exist under buildroot/lib/
  # Relative paths are based on buildroot/lib/, absolute paths are used directly
  static-libs@unix:
    - libssl.a
  static-libs@windows:
    - libssl.lib

  # Verify that specified .pc files exist under buildroot/lib/pkgconfig/
  # Only checked on non-Windows platforms (pkg-config is not applicable on Windows)
  pkg-configs:
    - openssl             # Corresponds to buildroot/lib/pkgconfig/openssl.pc
    - libssl              # Auto-completes .pc suffix

  # Verify that specified executable files exist under buildroot/bin/
  # Relative paths are based on buildroot/bin/, absolute paths are used directly
  static-bins:
    - my-tool

  # List of directories injected into the global PATH after the package is installed.
  # Path placeholders are supported (see below for details).
  path:
    - '{pkg_root_path}/rust/bin'

  # Environment variables set after the package is installed (overwrites existing values).
  # Path placeholders are supported.
  env:
    MY_VAR: '{build_root_path}/lib'

  # Values appended to the end of existing environment variables after the package is installed.
  # Path placeholders are supported.
  append-env:
    CFLAGS: ' -I{build_root_path}/include'

The following path placeholders are supported in string values of the path, env, and append-env fields:

Placeholder Actual Path
{build_root_path} buildroot directory (buildroot/)
{pkg_root_path} pkgroot directory (pkgroot/)
{working_dir} Working directory (project root)
{download_path} Download cache directory (downloads/)
{source_path} Extracted source directory (source/)
{spc_msys2_path} MSYS2 root directory (msys64/) — Windows only

tool Package Type

A tool package represents an executable needed while building another package, rather than a library linked into the final target. Tool packages may use a pre-built binary or build from source, and install under pkgroot/ by default, using either a shared bin/ directory or a configured subdirectory. Packages request them through the top-level tools field; this dependency set is resolved independently of depends and suggests.

nasm:
  type: tool
  artifact:
    binary:
      windows-x86_64:
        type: url
        url: 'https://example.com/nasm-win64.zip'
        extract:
          nasm.exe: '{pkg_root_path}/bin/nasm.exe'
          ndisasm.exe: '{pkg_root_path}/bin/ndisasm.exe'
  tool:
    provides: [nasm.exe, ndisasm.exe]
    binary-subdir: bin
    min-version: '2.16'

The nested tool object supports:

Field Required Meaning
provides Yes Executable filenames used to decide whether the tool is installed
binary-subdir No Directory below install-root containing the executables; defaults to the install root
install-root No Installation root; defaults to PKG_ROOT_PATH and supports path placeholders
min-version No Declared minimum version metadata exposed by ToolPackage; the installer does not currently enforce it

Fields inside tool may use @windows, @unix, @linux, and @macos suffixes. For example, provides@windows can list .exe names while provides@unix lists Unix names.

target Package Type

A target package represents a final build artifact. It inherits from library, so it includes all definition fields of library. Its configuration file is located in config/pkg/target/. Optional recipe classes are normally placed in src/Package/Target/, registered with #[Target], and receive a TargetPackage; inheriting from TargetPackage is optional.

The only difference from library is that a target package can be registered as a build target and automatically registers the build command spc build:{target-name}.

virtual-target Package Type

Unlike target, a virtual-target may omit artifact, meaning it doesn't directly correspond to a buildable entity but is instead an abstract build target, primarily used for dependency management and build scheduling. Its configuration and optional recipe classes use the same directories and #[Target] registration mechanism as target. Its definition is otherwise essentially the same, but the artifact field is optional and typically not set. virtual-target is primarily used in the following scenarios:

  • Defining an abstract build target for other packages to depend on, without directly corresponding to a buildable entity.
  • Serving as a common dependency for multiple target packages, simplifying dependency management.

Typical examples are the php-cli and php-fpm build targets. They have no independent source and depend on the php target, whose Artifact is php-src; build scheduling determines whether the CLI or FPM binary is produced.