Skip to content

Carefully crafted, CMake-based PHP build system

Notifications You must be signed in to change notification settings

petk/php-build-system

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3,451 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

PHP build system

PHP version CMake version C11

This repository delves into the core of the PHP build system, elucidating the intricacies of how to build PHP with CMake.

ElePHPant

Quick usage - TL;DR

Step 1 - Install prerequisites

# Prerequisites for Debian-based distributions:
sudo apt install cmake gcc g++ libsqlite3-dev

# Prerequisites for Fedora-based distributions:
sudo dnf install cmake gcc gcc-c++ sqlite-devel
Click here for more platforms
# Prerequisites for macOS:
xcode-select --install   # XCode command line tools
brew install cmake # See https://brew.sh how to install Homebrew

# Prerequisites for Alpine Linux:
sudo apk add --no-cache cmake make gcc g++ musl-dev sqlite-dev

# Prerequisites for BSD-based systems:
sudo pkg install cmake sqlite3

# Prerequisites for Haiku:
pkgman install cmake sqlite_devel

# Prerequisites for Solaris/illumos-based systems:
sudo pkg install cmake sqlite-3

Step 2 - Clone this repository

git clone https://github.com/petk/php-build-system

cd php-build-system

Step 3 - Generate build system to a build directory

cmake -B php-build

Step 4 - Build PHP in parallel

cmake --build php-build -j

After build is complete, a PHP binary should be available to run:

./php-build/php/sapi/cli/php -v

Introduction

PHP developers typically opt for convenient methods to set up PHP on their machines, such as utilizing prebuilt Linux packages available in their Linux distribution repositories, deploying Docker images, or relying on user-friendly stacks that bundle PHP, its extensions, web server, and database into a unified installation package.

# Debian-based distributions:
sudo apt install php...

# Fedora-based distributions:
sudo dnf install php...

In contrast, the practice of building PHP from source code is primarily reserved for specific purposes, such as PHP source code development or extensive customization of PHP configurations on a particular system. This approach is less commonly employed by everyday PHP developers due to its intricate and time-consuming nature.

In the realm of software development, a build system is a collection of tools and files that automate the process of compiling, linking, and assembling the project's source code into its final form, ready to be executed. It helps developers with repetitive tasks and ensures consistency and correctness in the build process for various platforms and hardware out there.

A key function of a build system in the context of C/C++ software development is to establish a structured framework that guides how code should be written. Beyond its primary role of compiling source files into executable programs, the build system plays a pivotal educational role, imparting best practices and coding standards to developers. By enforcing consistency and adherence to coding conventions, it fosters the creation of high-quality code, ultimately enhancing software maintainability and reliability.

Additionally, the build system aims to enable developers to work efficiently by abstracting away system-specific details, allowing them to focus on the logic and usability of their code. When adding a new source file or making minor modifications, developers shouldn't have to delve into the inner workings of the build system, sift through extensive build system documentation or extensively explore the complexities of the underlying system.

There are numerous well-known build systems available, ranging from the veteran GNU Autotools and the widely adopted CMake, to the efficient Ninja, versatile SCons, adaptable Meson, nimble xmake, cutting-edge Zig build system, and even the simplest manual usage of Make.

PHP directory structure

To understand the PHP source code better, it would be beneficial to grasp its directory structure. PHP is developed at the php-src GitHub repository.

After cloning the repository:

git clone https://github.com/php/php-src
cd php-src

there is a large monolithic repository consisting of C source code files, PHP tests and other associated files:

πŸ“‚ <php-src>
β”œβ”€πŸ“‚ .git                        # Git configuration and source directory
β”œβ”€πŸ“‚ benchmark                   # Benchmark some common applications in CI
β”œβ”€πŸ“‚ build                       # *nix build system files
β”œβ”€πŸ“‚ docs                        # PHP internals documentation
β””β”€πŸ“‚ ext                         # PHP core extensions
  β””β”€πŸ“‚ bcmath                    # The bcmath PHP extension
    β”œβ”€πŸ“‚ libbcmath               # The bcmath library forked and maintained in php-src
    β”œβ”€πŸ“‚ tests                   # *.phpt test files for extension
    β”œβ”€πŸ“„ bcmath.stub.php         # A stub file for the bcmath extension functions
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ curl                      # The curl PHP extension
    β”œβ”€πŸ“„ sync-constants.php      # The curl symbols checker
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ date                      # The date/time PHP extension
    β””β”€πŸ“‚ lib                     # Bundled datetime library https://github.com/derickr/timelib
      β””β”€πŸ“„ ...
    β””β”€πŸ“„ ...
  β”œβ”€πŸ“‚ dl_test                   # Extension for testing dl()
  β””β”€πŸ“‚ ffi                       # The FFI PHP extension
    β”œβ”€πŸ“„ ffi_parser.c            # Generated by https://github.com/dstogov/llk
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ fileinfo                  # The fileinfo PHP extension
    β”œβ”€πŸ“‚ libmagic                # Modified libmagic https://github.com/file/file
    β”œβ”€πŸ“„ data_file.c             # Generated by `ext/fileinfo/create_data_file.php`
    β”œβ”€πŸ“„ libmagic.patch          # Modifications patch from upstream libmagic
    β”œβ”€πŸ“„ magicdata.patch         # Modifications patch from upstream libmagic
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ gd                        # The GD PHP extension
    β”œβ”€πŸ“‚ libgd                   # Bundled and modified GD library https://github.com/libgd/libgd
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ lexbor
    β”œβ”€πŸ“‚ lexbor                  # https://github.com/lexbor/lexbor
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ mbstring                  # The Multibyte string PHP extension
    β”œβ”€πŸ“‚ libmbfl                 # Forked and maintained in php-src
    β”œβ”€πŸ“„ unicode_data.h          # Generated by `ext/mbstring/ucgendat/ucgendat.php`
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ opcache                   # The OPcache PHP extension
    β””β”€πŸ“‚ jit                     # OPcache Jit
      β””β”€πŸ“‚ ir                    # Bundled part of IR framework https://github.com/dstogov/ir
        β””β”€πŸ“‚ dynasm              # DynASM encoding engine
          β”œβ”€πŸ“„ minilua.c         # Customized Lua scripting language to build LuaJIT
          β””β”€πŸ“„ ...
        β”œβ”€πŸ“„ gen_ir_fold_hash    # IR folding engine generator created at build
        β”œβ”€πŸ“„ ir_emit_<arch>.h    # IR folding engine rules generated by minilua
        β”œβ”€πŸ“„ minilua             # Executable tool created at build
        β””β”€πŸ“„ ...
  β””β”€πŸ“‚ pcre                      # The PCRE PHP extension
    β”œβ”€πŸ“‚ pcre2lib                # https://www.pcre.org/
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ phar                      # The Phar (PHP Archive) PHP extension
    β”œβ”€πŸ“„ stub.h                  # Generated by `ext/phar/{makestub,shortarc}.php`
    β””β”€πŸ“„ ...
  β”œβ”€πŸ“‚ skeleton                  # Skeleton for new extensions using `ext/ext_skel.php`
  β””β”€πŸ“‚ standard                  # Always enabled core extension
    β””β”€πŸ“‚ html_tables
      β”œβ”€πŸ“‚ mappings              # https://www.unicode.org/Public/MAPPINGS/
      β””β”€πŸ“„ ...
    β”œβ”€πŸ“„ credits_ext.h           # Generated by `scripts/dev/credits`
    β”œβ”€πŸ“„ credits_sapi.h          # Generated by `scripts/dev/credits`
    β”œβ”€πŸ“„ html_tables.h           # Generated by `ext/standard/html_tables/html_table_gen.php`
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ tokenizer                 # The tokenizer PHP extension
    β”œβ”€πŸ“„ tokenizer_data.c        # Generated by `ext/tokenizer/tokenizer_data_gen.php`
    β”œβ”€πŸ“„ tokenizer_data_stub.php # Generated by `ext/tokenizer/tokenizer_data_gen.php`
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ uri
    β”œβ”€πŸ“‚ uriparser               # https://github.com/uriparser/uriparser
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ zend_test                 # For testing internal APIs. Not needed for regular builds
    β””β”€πŸ“„ ...
  β””β”€πŸ“‚ zip/                      # Bundled https://github.com/pierrejoye/php_zip
    β””β”€πŸ“„ ...
  β”œβ”€πŸ“‚ ...
  β””β”€πŸ“„ ext_skel.php              # Helper script that creates a new PHP extension
β””β”€πŸ“‚ main                        # Binding that ties extensions, SAPIs, and Zend Engine together
  β”œβ”€πŸ“‚ streams                   # Streams layer subsystem
  β”œβ”€πŸ“„ debug_gdb_scripts.c       # Generated by `scripts/gdb/debug_gdb_scripts_gen.php`
  β””β”€πŸ“„ ...
β”œβ”€πŸ“‚ modules                     # Shared libraries, created when building PHP
β”œβ”€πŸ“‚ pear                        # PEAR installation
β””β”€πŸ“‚ sapi                        # PHP SAPI (Server API) modules
  β””β”€πŸ“‚ cli                       # Command-line PHP SAPI module
    β”œβ”€πŸ“„ mime_type_map.h         # Generated by `sapi/cli/generate_mime_type_map.php`
    β””β”€πŸ“„ ...
  β””β”€πŸ“„ ...
β”œβ”€πŸ“‚ scripts                     # php-config, phpize and internal development scripts
β”œβ”€πŸ“‚ tests                       # Core features tests
β”œβ”€πŸ“‚ TSRM                        # Thread Safe Resource Manager
β””β”€πŸ“‚ Zend                        # Zend Engine
  β”œβ”€πŸ“‚ asm                       # Bundled from src/asm in https://github.com/boostorg/context
  β”œβ”€πŸ“‚ Optimizer                 # For faster PHP execution through opcode caching and optimization
  β”œβ”€πŸ“‚ tests                     # PHP tests *.phpt files for Zend Engine
  β”œβ”€πŸ“„ zend_vm_execute.h         # Generated by `Zend/zend_vm_gen.php`
  β”œβ”€πŸ“„ zend_vm_opcodes.c         # Generated by `Zend/zend_vm_gen.php`
  β”œβ”€πŸ“„ zend_vm_opcodes.h         # Generated by `Zend/zend_vm_gen.php`
  β””β”€πŸ“„ ...
β”œβ”€πŸ“‚ win32                       # Windows build files
β””β”€πŸ“„ ...

Why CMake?

At the time of writing, CMake is actively maintained, with new features being introduced slowly and conservatively. Despite its limitations, it remains one of the most widely adopted build systems, offering solid support across all major platforms. Many developers are already familiar with CMake, which can help lower the barrier for contributors working with the PHP codebase. IDEs and editors provide reasonably good CMake integration for C/C++ projects.

PHP native and CMake-based build system differences

How CMake-based PHP build system differs compared to its Autotools and Windows build system:

Enhancement differences

The following features are only available in CMake:

  • re2c tool can be automatically downloaded, when not found on the system

  • Added pkg-config .pc files

    Once installed, there are three .pc files available in system pkgconfig directory:

    • php.pc - for building PHP extensions

    • php-embed.pc - for embedding PHP into application

    • phpdbg.pc - for PHP Debugger SAPI module library.

      These can be then used with the pkg-config (pkgconf) tool:

      pkg-config --cflags php
      pkg-config --cflags-only-I php
      pkg-config --libs php
      pkg-config --mod-version php
      pkg-config --print-variables php
      pkg-config --variable=php_vernum php

      Upstream Autotools-based draft: php/php-src#13755

  • CMake presets simplify the build configurations. The native PHP Autotools build system has issues with the --enable-all option, where certain configuration options are set but they also set additional variables (e.g., ext_shared) where they shouldn't. PHP Windows build system has similar configure option --enable-snapshot-build (and --disable-all).

  • Better cross-compiling support with CMake toolchain files and ability to set the cross-compiling emulator.

  • Additional configuration options:

    • PHP_CONFIGURE_COMMAND

Behavior differences

  • sapi/phpdbg readline support works more intuitively regardless of the readline extension being enabled during the build.

  • sapi/phpdbg shared library name on Windows is synced with *nix systems (libphpdbg).

  • ext/session can be built as shared on Windows (in testing phase).

  • Obsolete check whether the dlsym() requires a leading underscore in symbol name is removed in CMake. See: php/php-src#13655

  • Compiler shipped with Oracle Developer Studio is not supported. See: php/php-src#15272

  • ext/phar doesn't have native SSL support anymore in favor of SSL through the PHP openssl extension: See: php/php-src#15574

  • ext/ldap in CMake has configuration option (following Autotools) to explicitly enable SASL support on both platform types (*nix and Windows), while Windows JScript build system has SASL support always unconditionally enabled.

  • ext/mysqli and ext/pdo_mysql have each separate configuration options for setting the Unix socket pointer. In Autotools, there is a single --with-mysql-socket configure option that is used by both extensions. This is done on the expense of more complex configuration while being more intuitive and logical configuration similar to the PHP INI directives of mysqli.default_socket and pdo_mysql.default_socket. In Autotools, default socket paths are in some cases defined in a hacky way. The pdo_mysql extension has default set to /tmp/mysql.sock, without possibility to be set to NULL.

  • The _XOPEN_SOURCE compile definition to use ucontext.h on macOS when needed is only defined for the Zend/zend_fibers.c file. Duplicate inconsistent _XOPEN_SOURCE definition in the php_config.h is also removed with this.

  • In CMake the install prefix can be also changed during the installation phase using the cmake --install <build-dir> --prefix <install-prefix>. In PHP native Autotools-based build system, installation prefix can be only set at the configure phase using the ./configure --prefix=<install-prefix>, which is a regression for the main/build-defs.h and main/php_config.h files, where the installation prefix in PHP is hardcoded during the build phase and cannot be changed during the installation phase. For the generated files (php-config, pkg-config .pc, etc.) workaround is already done in CMake but not yet for the header files. See: #4

  • CMake configuration mostly follows Autotools defaults aiming to be consistent. In native PHP build system there are various extensions by default inconsistently enabled or disabled between Autotools and Windows.

    For example:

    • ext/bcmath (Windows: enabled, Autotools: disabled, CMake: disabled)
    • ext/calendar (Windows: enabled, Autotools: disabled, CMake: disabled)

    See Configuration documentation for more info.

  • In CMake, shared extensions built in php-src and as standalone (a.k.a. in the phpize mode) are built in both ways with the hidden visibility preset. See: php/php-src#21238

  • Installation

    • The installation include directory (/usr/local/include/php) can be adjusted with the PHP_INCLUDE_PREFIX CMake cache variable to support multiple PHP versions. For example, /usr/local/include/php/8.6.

    • The installation lib directory (/usr/local/lib/php) can be adjusted with the PHP_LIB_PREFIX CMake cache variable to support multiple PHP versions. For example, /usr/local/lib/php/8.6.

    • The PHP Autotools layout configuration option --with-layout=[PHP|GNU] is in CMake removed and not implemented in favor of the GNU standard directory layout.

    • PEAR installation writes less dot and temporary files outside of the staging installation directory (INSTALL_ROOT/DESTDIR). PEAR temporary directory can be adjusted with the PHP_PEAR_TEMP_DIR CMake cache variable.

  • Parser and lexer files

    • When generating parser (Bison) and lexer (re2c) files with command-line script cmake/scripts/GenerateGrammar.cmake, Bison report files (*.output) are not generated.

    • For the Release and MinSizeRel CMake build types, the Bison --no-lines (-l) and re2c --no-debug-info (-i) options are added.

  • HP-UX platform is not supported in CMake-based build system anymore. See: php/php-src#21280

  • On Windows, there is also main/build-defs.h header added and included in the main/config.w32.h to be synced with *nix configuration.

Bugs fixed in CMake

  • Building inside folder with spaces. See: https://bugs.php.net/49270

  • Detecting GNU libiconv. See: php/php-src#12213

  • Oracle Instant Client integration in ldap extension is removed in CMake due to missing LDAP features causing build errors. See: php/php-src#15051

  • The phpdbg prompt with libedit integration is colored. See: php/php-src#15722

  • GPL 3 licensed dependencies are removed as they are not compatible with PHP license. When such dependencies are linked statically or dynamically, PHP should be relicensed as GPL 3 (which is unrealistic), or it shouldn't be distributed (which makes it unusable in server environments or package repositories). As this is a gray area, removal of these dependencies improves user experience and prevents misconfiguration.

  • Build with Clang on 32-bit systems. See: php/php-src#14467

  • Zend/zend_vm_gen.php deprecation warnings on 32-bit systems. See: php/php-src#15899

  • The chroot() PHP function is enabled/disabled based on the SAPI type. See: php/php-src#11984

  • The libmbfl configuration header (config.h). See: php/php-src#13713

  • Building with large number of CPU cores might emit errors.

    When building PHP with Autotools in parallel with large number of CPU cores (make -j32) there might happen error like this with very small reproducibility:

    ...tokenizer_data.c:22:10: fatal error: zend_language_parser.h: No such file
    or directory
    

    There might be some misconfigured dependencies between some files in Makefile. For example, the Zend/zend_language_parser.h and all other Zend language parser files must be generated before the ext/tokenizer files start to build, otherwise error happens because Bison might generate header with slight delay.

    In CMake, this is bypassed by having entire extension dependent on the PHP::Zend target (which also includes the parser and scanner).

  • The zlib extension can be built as shared and SWC files are supported. See: php/php-src#20868

  • The intl extension can be built with undefined sanitizer enabled. CMake picks C or C++ linker for SAPIs based on the objects being linked. Autotools would need a workaround using libtool tags. See: php/php-src#20992

Documentation

About

Carefully crafted, CMake-based PHP build system

Topics

Resources

Contributing

Stars

Watchers

Forks

Contributors

Languages