Skip to content

Latest commit

Β 

History

History
705 lines (552 loc) Β· 25.7 KB

cmake.md

File metadata and controls

705 lines (552 loc) Β· 25.7 KB

CMake-based PHP build system

This document describes how CMake-based PHP build system in this repository works and how it can be used.

Index

1. Directory structure

CMake-based PHP build system is a collection of various files across the php-src repository:

πŸ“‚ <php-src>
β””β”€πŸ“‚ cmake                     # CMake-based PHP build system files
  β””β”€πŸ“‚ modules                 # Project-specific CMake modules
    β”œβ”€πŸ“‚ PHP                   # PHP utility CMake modules
    β””β”€πŸ“„ Find*.cmake           # Find modules that support the find_package()
  β”œβ”€πŸ“‚ platforms               # Platform-specific configuration
  β”œβ”€πŸ“‚ presets                 # Presets included in CMakePresets.json
  β”œβ”€πŸ“‚ scripts                 # Various CMake command-line scripts
  β”œβ”€πŸ“‚ toolchains              # CMake toolchain files
  β””β”€πŸ“„ *.cmake                 # Various CMake configurations and files
β””β”€πŸ“‚ ext
  β””β”€πŸ“‚ date
    β””β”€πŸ“‚ lib
      β””β”€πŸ“„ CMakeLists.txt      # Timelib's CMake file
  β””β”€πŸ“‚ mbstring
    β””β”€πŸ“‚ libmbfl
      β””β”€πŸ“„ CMakeLists.txt      # libmbfl's CMake file
  β””β”€πŸ“‚ standard
    β””β”€πŸ“‚ cmake                 # Extension's CMake-related files
      β””β”€πŸ“„ config.h.in         # Extension's configuration header template
    β””β”€πŸ“„ CMakeLists.txt        # Extension's CMake file
  β””β”€πŸ“‚ zlib
    β”œβ”€πŸ“‚ cmake
    β”œβ”€πŸ“„ CMakeLists.txt
    β””β”€πŸ“„ php_iconv.def         # Module-definition for building DLL on Windows
β””β”€πŸ“‚ main
  β””β”€πŸ“‚ cmake                   # CMake-related files for main binding
    β””β”€πŸ“„ php_config.h.in       # PHP main configuration header template
  β”œβ”€πŸ“„ CMakeLists.txt          # CMake file for main binding
  β””β”€πŸ“„ internal_functions.c.in # Common template for internal functions files
β””β”€πŸ“‚ pear
  β”œβ”€πŸ“‚ cmake                   # CMake-related files for PEAR
  β””β”€πŸ“„ CMakeLists.txt          # CMake file for PEAR
β””β”€πŸ“‚ sapi
  β””β”€πŸ“‚ fpm
    β””β”€πŸ“‚ cmake                 # SAPI's CMake-related files
      β””β”€πŸ“„ config.h.in         # SAPI's configuration header template
    β””β”€πŸ“„ CMakeLists.txt        # CMake file for PHP SAPI module
β””β”€πŸ“‚ scripts
  β””β”€πŸ“„ CMakeLists.txt          # CMake file for creating scripts
β””β”€πŸ“‚ win32                     # Windows build files
  β””β”€πŸ“‚ build                   # Windows build files
    β””β”€πŸ“„ wsyslog.mc            # Message template file for win32/wsyslog.h
  β””β”€πŸ“„ CMakeLists.txt          # CMake file for Windows build
β””β”€πŸ“‚ Zend
  β””β”€πŸ“‚ cmake                   # CMake-related files for Zend Engine
    β””β”€πŸ“„ zend_config.h.in      # Zend Engine configuration header template
  β””β”€πŸ“„ CMakeLists.txt          # CMake file for Zend Engine
β”œβ”€πŸ“„ CMakeLists.txt            # Root CMake file
β”œβ”€πŸ“„ CMakePresets.json         # Main CMake presets file
β””β”€πŸ“„ CMakeUserPresets.json     # Git ignored local CMake presets overrides

The following diagram briefly displays, how PHP libraries (in terms of a build system) are linked together:

Diagram how PHP libraries are linked together

2. Build system diagram

CMake-based PHP build system diagram

3. Build requirements

Before you can build PHP using CMake, you must first install certain third-party requirements. It's important to note that the names of these requirements may vary depending on your specific system. For the sake of simplicity, we will use generic names here. When building PHP from source, one crucial requirement is a library containing development files. Such libraries are typically packaged under names like libfoo-dev, libfoo-devel, or similar conventions on *nix systems. For instance, to install the libxml2 library, you would look for the libxml2-dev (or libxml2-devel) package.

Required:

  • cmake
  • gcc
  • g++
  • libsqlite3

Optional (if not found on the system, build system tries to download it):

  • libxml2

Additionally required when building from Git repository source code:

  • bison

Optional when building from Git repository source code:

  • re2c

When PHP is built, the development libraries are no longer required to be installed and only libraries without development files are needed to run newly built PHP. In example of ext/libxml extension, the libxml2 package is needed without the libxml2-dev and so on.

4. CMake generators for building PHP

When using CMake to build PHP, you have the flexibility to choose from various build systems through the concept of generators. CMake generators determine the type of project files or build scripts that CMake generates from the CMakeLists.txt files.

4.1. Unix Makefiles (default)

The Unix Makefiles generator is the most commonly used for building projects on Unix-like systems. It generates traditional Makefile that can be processed by the make command. To use the Unix Makefiles generator, you simply specify it as an argument when running CMake in your build directory.

To generate the Makefile for building PHP, create a new directory (often called build or cmake-build) and navigate to it using the terminal. Then, execute the following CMake command:

cmake -G "Unix Makefiles" /path/to/php-src

Replace /path/to/php-src with the actual path to the PHP source code on your system (in case build directory is the same as the source directory, use .). CMake will process the CMakeLists.txt file in the source directory and generate the Makefile in the current build directory.

After the Makefiles are generated, you can build PHP binaries and libraries by running:

cmake --build <build-directory> -j

If you want to speed up the build process, you can use the -j option to enable parallel builds, taking advantage of multiple CPU cores.

Note

On some systems, the -j option requires argument. Number of simultaneous jobs is often the number of available processor threads of the build machine and can be also automatically calculated using the $(nproc) on Linux, or $(sysctl -n hw.ncpu) on macOS and BSD-based systems.

cmake --build <build-directory> -j $(nproc)

The cmake --build is equivalent to running the make command:

make -j $(nproc) # Number of CPUs you want to utilize.

4.2. Ninja

Ninja is another build system supported by CMake and is known for its fast build times due to its minimalistic design. To use the Ninja generator, you need to have Ninja installed on your system. Most package managers on Unix systems offer Ninja as a package, so you can install it easily.

To generate Ninja build files for building PHP, navigate to your build directory in the terminal and run the following CMake command:

cmake -G "Ninja" /path/to/php-src

Again, replace /path/to/php/src with the actual path to the PHP source code. CMake will generate the Ninja build files in the current directory.

To build PHP with Ninja, execute the following command:

cmake --build <build-directory>

Which is equivalent to running ninja command. Ninja will then handle the build process based on the CMake configuration. Ninja by default enables parallel build.

5. Build types

CMake build types dictate compiler and linker flags, as well as the behavior governing the compilation of source code based on the targeted deployment type. Several common build types are pre-configured and readily available:

  • Debug
  • Release
  • MinSizeRel
  • RelWithDebInfo
  • DebugAssertions (custom PHP build type)

The selection of a build type varies depending on the generator in use.

For single configuration generators, such as Unix Makefiles and Ninja, the build type is designated during the configuration phase using the cache variable CMAKE_BUILD_TYPE:

cmake -DCMAKE_BUILD_TYPE=Debug -S ../php-src -B build-directory

Multi configuration generators, like Ninja Multi-Config and Visual Studio, employ the --config build option during the build phase:

cmake -G "Ninja Multi-Config" -S ../php-src -B build-directory
cmake --build build-directory --config Debug -j

Alternatively, multi configuration generators can specify build type in the CMake presets JSON file using the configuration field:

"buildPresets": [
  {
    "...": "...",
    "configuration": "Debug"
  }
],

6. CMake minimum version for PHP

The minimum required version of CMake is defined in the top project file CMakeLists.txt using the cmake_minimum_required(). Picking the minimum required CMake version is a compromise between CMake functionalities and CMake version available on the operating system.

  • 3.17
    • CMAKE_CURRENT_FUNCTION_LIST_DIR variable
  • 3.19
    • check_compiler_flag(), check_source_compiles(), check_source_runs() to generalize the check_<LANG>_...()
    • CMakePresets.json for sharing build configurations
  • 3.20
    • CMAKE_C_BYTE_ORDER, otherwise manual check should be done
    • "version": 2 in CMakePresets.json
    • Intl::Intl IMPORTED target with CMake's FindIntl module
  • 3.21
    • "version": 3 in CMakePresets.json (for the installDir field)
  • 3.22
    • Full condition syntax in cmake_dependent_option()
  • 3.23
    • target_sources(FILE_SET), otherwise install(FILES) should be used when installing files to their destinations
    • "version": 4 in CMakePresets.json (for the include field)
  • 3.24
    • CMAKE_COLOR_DIAGNOSTICS
    • CMAKE_COMPILE_WARNING_AS_ERROR, otherwise INTERFACE library should be used
    • if(PATH_EQUAL)
  • 3.25
    • block() command
    • New try_run signature
    • cmake_language() keyword GET_MESSAGE_LOG_LEVEL
    • return() keyword PROPAGATE
  • 3.27
    • COMPILE_ONLY generator expression
    • INSTALL_PREFIX generator expression in install(CODE)
    • $<LIST:SORT,list[,...]> generator expression
    • <PACKAGENAME>_ROOT variables in addition to <PackageName>_ROOT
  • 3.29
    • CMAKE_LINKER_TYPE
    • if(IS_EXECUTABLE)
  • 3.31
    • add_custom_command() keyword CODEGEN

Currently, the CMake minimum version is set to 3.25 without looking at CMake available version on the current systems out there. This will be updated more properly in the future.

CMake versions scheme across the systems is available at pkgs.org.

Tip

While the CMake version on some systems may be outdated, there are various options available to install the latest version. For instance, on Ubuntu, the most recent CMake version can be installed using snap or through the APT repository.

7. Interface libraries

  • The php_config (aliased PHP::config) holds compilation and link properties, such as flags, definitions, libraries and include directories. All targets that need global PHP compile or link properties should link to this target.

    It is analogous to a global configuration class, where configuration is set during the configuration phase and then linked to targets that need the configuration.

    It can be linked to a given target:

    target_link_libraries(target_name PRIVATE PHP::config)
  • The php_sapi (aliased PHP::sapi) ties all target objects and configuration together. Only PHP SAPI targets should link to it.

    target_link_libraries(<some-php-sapi-target> PRIVATE PHP::sapi)

See also https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html for a high-level overview of the CMake build system concepts.

8. PHP CMake modules

All PHP global CMake utility modules are located in the cmake/modules/PHP directory.

A new module can be added by creating a new CMake file cmake/modules/PHP/NewModule.cmake which can be then included in the CMake files:

include(PHP/NewModule)

Additional CMake modules or other files that are used only inside a certain subdirectory (extension, SAPI, Zend Engine...) are located in the cmake directories where needed:

  • ext/<extension>/cmake/*.cmake - CMake modules related to extension
  • sapi/<sapi>/cmake/*.cmake - CMake modules related to SAPI
  • Zend/cmake/*.cmake - CMake modules related to Zend Engine

A list of PHP CMake modules:

9. Custom CMake properties

  • PHP_ALL_EXTENSIONS

    Global property with a list of all PHP extensions in the ext directory.

  • PHP_ALL_SAPIS

    Global property with a list of all PHP SAPIs in the sapi directory.

  • PHP_ALWAYS_ENABLED_EXTENSIONS

    Global property with a list of always enabled PHP extensions which can be considered part of the core PHP.

  • PHP_CLI

    Target property that designates CMake target of PHP SAPI or extension as CLI-based (usable in a CLI environment). When enabled on a PHP SAPI target, such SAPI will have the main/internal_functions_cli.c object instead of main/internal_functions.c and objects of enabled CLI-based PHP extensions that were built statically.

    When this property is enabled on a PHP extension target, extension will be only listed in the generated main/internal_functions_cli.c file. Other extensions will be listed also in the main/internal_functions.c file. CLI-based extensions will only be enabled on CLI-based SAPIs.

    Examples of CLI-based SAPIs are cgi, cli, phpdbg, and embed. Examples of CLI-based extensions are pcntl and readline.

    For example, to mark some PHP SAPI as CLI-based, set PHP_CLI property to truthy value:

    set_target_properties(php_sapi_cli PROPERTIES PHP_CLI TRUE)

    Basic generator expressions are also supported:

    set_target_properties(
      php_ext_some_extension
      PROPERTIES PHP_CLI $<IF:$<PLATFORM_ID:Windows>,FALSE,TRUE>
    )
  • PHP_EXTENSION_<extension>_DEPS

    Global property set by the PHP/Extensions module.

  • PHP_EXTENSIONS

    Global property with a list of all enabled PHP extensions for the current configuration. Extensions are sorted by their dependencies (extensions added with CMake command add_dependencies()).

  • PHP_SAPIS

    Global property with a list of all enabled PHP SAPIs for the current configuration.

  • PHP_THREAD_SAFETY

    Target property set by the PHP/ThreadSafety module on the PHP::config target, when thread safety is enabled.

  • PHP_ZEND_EXTENSION

    See the PHP/Extensions module.

10. PHP extensions

PHP has several ways to install PHP extensions:

  • Statically linked to PHP

    This is the default way. Extension is built together with PHP SAPI and no enabling is needed in the php.ini configuration.

  • Shared modules

    This installs the extension as dynamically loadable library. Extension to be visible in the PHP SAPI (see php -m) needs to be also manually enabled in the php.ini configuration:

    extension=php_extension_lowercase_name

    This will load the PHP extension module file (shared object) located in the extension directory (the extension_dir INI directive). File can have .so extension on *nix systems, .dll on Windows, and possibly other extensions such as .sl on certain HP-UX systems, or .dylib on macOS.

The following extensions are always enabled and are part of the overall PHP engine source code:

  • ext/date
  • ext/hash
  • ext/json
  • ext/pcre
  • ext/random
  • ext/reflection
  • ext/spl
  • ext/standard

PHP extensions ecosystem also consists of the PECL extensions. These can be installed with a separate tool pecl:

pecl install php_extension_name

PECL tool is a simple shell script wrapper around the PHP code as part of the pear-core repository.

Note

pecl command-line script is also being replaced with a new tool PIE.

To build PHP extensions with CMake, a CMakeLists.txt file needs to be added to the extension's source directory.

Example of CMakeLists.txt for PHP extensions can be found in the ext/skeleton directory.

11. PHP SAPI (Server API) modules

PHP works through the concept of SAPI modules located in the sapi directory.

When running PHP on the command line, the cli SAPI module is used:

/sapi/cli/php -v

There are other SAPI modules located in the ecosystem:

12. Generated files

During the build process, there are several files generated, some of which are also tracked in the Git repository for a smoother workflow:

πŸ“‚ <php-src>
β””β”€πŸ“‚ ext
  β””β”€πŸ“‚ date
    β””β”€πŸ“‚ lib
      β””β”€πŸ“„ timelib_config.h      # Datetime library configuration header
  β””β”€πŸ“‚ mbstring
    β””β”€πŸ“‚ libmbfl
      β””β”€πŸ“„ config.h              # The libmbfl configuration header
  β””β”€πŸ“‚ tokenizer
    β”œβ”€πŸ“„ tokenizer_data_stub.php # Generated by `ext/tokenizer/tokenizer_data_gen.php`
    β””β”€πŸ“„ tokenizer_data.c        # Generated token types data file
β””β”€πŸ“‚ main
  β”œβ”€πŸ“„ internal_functions*.c     # Generated files with all internal functions
  β”œβ”€πŸ“„ config.w32.h              # Main configuration header for Windows
  β”œβ”€πŸ“„ debug_gdb_scripts.c       # Generated by `scripts/gdb/debug_gdb_scripts_gen.php`
  β”œβ”€πŸ“„ php_config.h              # Main configuration header for *nix systems
  β””β”€πŸ“„ php_version.h             # Generated by release managers using `configure`
β””β”€πŸ“‚ scripts
  β”œβ”€πŸ“„ php-config                # PHP configuration helper script
  β””β”€πŸ“„ phpize                    # Build configurator for PHP extensions
β””β”€πŸ“‚ win32                       # Windows build files
  β”œβ”€πŸ“„ cp_enc_map.c              # Generated from win32/cp_enc_map_gen.c
  β””β”€πŸ“„ wsyslog.h                 # Generated by message compiler (mc.exe or windmc)
β””β”€πŸ“‚ Zend
  β”œβ”€πŸ“„ zend_config.h             # Zend Engine configuration header on *nix systems
  β”œβ”€πŸ“„ zend_config.w32.h         # Zend Engine configuration header on Windows
  β”œβ”€πŸ“„ 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`

12.1. Parser and lexer files

So-called parser files are generated with bison tool from *.y source files to C source code and header files.

Lexer files are generated with re2c tool from *.l and *.re source files to C source code and header files.

To use bison and re2c in CMake the FindBison and FindRE2C modules provide bison_target() and re2c_target() commands. FindBison is a CMake built-in module, while FindRE2C is manually created at cmake/modules/FindRE2C.

Files related to bison and re2c:

πŸ“‚ <php-src>
β””β”€πŸ“‚ cmake
  β””β”€πŸ“‚ modules
    β””β”€πŸ“„ FindRE2C.cmake             # re2c CMake find module, bison is found via
                                    # CMake built-in find module
  β””β”€πŸ“„ Requirements.cmake           # Minimum bison and re2c settings
β””β”€πŸ“‚ ext
  β””β”€πŸ“‚ date
    β””β”€πŸ“‚ lib
      β”œβ”€πŸ“„ parse_date.c             # Generated with re2c 0.15.3
      β””β”€πŸ“„ parse_iso_intervals.c    # Generated with re2c 0.15.3
  β””β”€πŸ“‚ ffi
    β””β”€πŸ“„ ffi_parser.c               # Generated by https://github.com/dstogov/llk
  β””β”€πŸ“‚ json
    β”œβ”€πŸ“„ json_parser.tab.c          # Generated with bison
    β”œβ”€πŸ“„ json_parser.tab.h          # Generated with bison
    β”œβ”€πŸ“„ json_parser.y              # Parser source
    β”œβ”€πŸ“„ json_scanner.c             # Generated with re2c
    β”œβ”€πŸ“„ json_scanner.re            # Lexer source
    β””β”€πŸ“„ php_json_scanner_defs.h    # Generated with re2c
  β””β”€πŸ“‚ pdo
    β”œβ”€πŸ“„ pdo_sql_parser.c           # Generated with re2c
    β””β”€πŸ“„ pdo_sql_parser.re          # Source for re2c
  β””β”€πŸ“‚ pdo_mysql
    β”œβ”€πŸ“„ mysql_sql_parser.c         # Generated with re2c
    β””β”€πŸ“„ mysql_sql_parser.re        # Source for re2c
  β””β”€πŸ“‚ pdo_pgsql
    β”œβ”€πŸ“„ pgsql_sql_parser.c         # Generated with re2c
    β””β”€πŸ“„ pgsql_sql_parser.re        # Source for re2c
  β””β”€πŸ“‚ pdo_sqlite
    β”œβ”€πŸ“„ sqlite_sql_parser.c        # Generated with re2c
    β””β”€πŸ“„ sqlite_sql_parser.re       # Source for re2c
  β””β”€πŸ“‚ phar
    β”œβ”€πŸ“„ phar_path_check.c          # Generated with re2c
    β””β”€πŸ“„ phar_path_check.re         # Source for re2c
  β””β”€πŸ“‚ standard
    β”œβ”€πŸ“„ url_scanner_ex.c           # Generated with re2c
    β”œβ”€πŸ“„ url_scanner_ex.re          # Source for re2c
    β”œβ”€πŸ“„ var_unserializer.c         # Generated with re2c
    β””β”€πŸ“„ var_unserializer.re        # Source for re2c
β””β”€πŸ“‚ sapi
  β””β”€πŸ“‚ phpdbg
    β”œβ”€πŸ“„ phpdbg_lexer.c             # Generated with re2c
    β”œβ”€πŸ“„ phpdbg_lexer.l             # Source for re2c
    β”œβ”€πŸ“„ phpdbg_parser.c            # Generated with bison
    β”œβ”€πŸ“„ phpdbg_parser.h            # Generated with bison
    β”œβ”€πŸ“„ phpdbg_parser.y            # Source for bison
    β””β”€πŸ“„ phpdbg_parser.output       # Generated with bison
β””β”€πŸ“‚ Zend
  β”œβ”€πŸ“„ zend_ini_parser.c            # Generated with bison
  β”œβ”€πŸ“„ zend_ini_parser.h            # Generated with bison
  β”œβ”€πŸ“„ zend_ini_parser.output       # Generated with bison
  β”œβ”€πŸ“„ zend_ini_parser.y            # Parser source
  β”œβ”€πŸ“„ zend_ini_scanner.c           # Generated with re2c
  β”œβ”€πŸ“„ zend_ini_scanner.l           # Lexer source
  β”œβ”€πŸ“„ zend_ini_scanner_defs.h      # Generated with re2c
  β”œβ”€πŸ“„ zend_language_parser.c       # Generated with bison
  β”œβ”€πŸ“„ zend_language_parser.h       # Generated with bison
  β”œβ”€πŸ“„ zend_language_parser.output  # Generated with bison
  β”œβ”€πŸ“„ zend_language_parser.y       # Parser source
  β”œβ”€πŸ“„ zend_language_scanner_defs.h # Generated with re2c
  β”œβ”€πŸ“„ zend_language_scanner.c      # Generated with re2c
  β””β”€πŸ“„ zend_language_scanner.l      # Lexer source

When building PHP from the released archives (php-*.tar.gz) from php.net these files are already included in the tarball itself so re2c and bison are not required.

These are generated automatically when building PHP from the Git repository.

To re-generate these files manually apart from the main build itself, a separate CMake target php_generate_files can be used:

cmake -S <source-dir> -B <build-dir>
cmake --build <build-dir> -t php_generate_files

13. Performance

When CMake is doing configuration phase, the profiling options can be used to do build system performance analysis of CMake files.

cmake --profiling-output ./profile.json --profiling-format google-trace ../php-src

CMake profiling

14. Testing

PHP source code tests (*.phpt files) are written in PHP and are executed with run-tests.php script from the very beginning of the PHP development. When building PHP with Autotools the tests are usually run by:

make TEST_PHP_ARGS=-j10 test

CMake ships with a ctest utility that can run PHP tests in a similar way.

To enable testing the enable_testing() is added to the CMakeLists.txt file and the tests are added with add_test().

To run the tests using CMake on the command line:

ctest --progress --verbose

The --progress option displays a progress if there are more tests, and --verbose option outputs additional info to the stdout. In PHP case the --verbose is needed so the output of the run-tests.php script is displayed.

CMake testing also supports presets so configuration can be coded and shared using the CMakePresets.json file and its testPresets field.

ctest --preset all-enabled

15. Windows notes

15.1. Module-definition (.def) files

Module-definition (.def) files are added to certain php-src folders where linker needs them when building DLL.

In CMake they can be simply added to the target sources:

target_sources(php_extension_name php_extension_name.def)