From 901235f8a41a9f89d4bba36cfd46b431d3240ede Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Sat, 21 Dec 2024 22:58:56 +0100 Subject: [PATCH 01/15] Add lexer and parser generator script This improves usability to simply call: cmake -P cmake/scripts/GenerateLexersParsers.cmake instead of doing the entire CMake configuration phase and then executing some target to generate files. --- cmake/Zend/CMakeLists.txt | 6 +- cmake/cmake/Bootstrap.cmake | 4 - cmake/cmake/Configuration.cmake | 7 - cmake/cmake/Requirements.cmake | 2 - cmake/cmake/modules/FindBISON.cmake | 83 +++++++++ cmake/cmake/modules/FindRE2C.cmake | 158 ++++++++++++------ .../cmake/scripts/GenerateLexersParsers.cmake | 141 ++++++++++++++++ cmake/ext/json/CMakeLists.txt | 4 +- cmake/ext/pdo/CMakeLists.txt | 1 + cmake/ext/phar/CMakeLists.txt | 1 + cmake/ext/standard/CMakeLists.txt | 2 + cmake/sapi/phpdbg/CMakeLists.txt | 4 +- 12 files changed, 342 insertions(+), 71 deletions(-) create mode 100644 cmake/cmake/modules/FindBISON.cmake create mode 100755 cmake/cmake/scripts/GenerateLexersParsers.cmake diff --git a/cmake/Zend/CMakeLists.txt b/cmake/Zend/CMakeLists.txt index 82f3fcdd..b98286e4 100644 --- a/cmake/Zend/CMakeLists.txt +++ b/cmake/Zend/CMakeLists.txt @@ -536,9 +536,6 @@ if(BISON_FOUND) DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h ) - add_custom_target(zend_ini_parser DEPENDS ${BISON_TARGET_outputs}) - add_dependencies(php_generate_files zend_ini_parser) - bison_target( zend_language_parser zend_language_parser.y @@ -605,7 +602,6 @@ if(BISON_FOUND) ) add_dependencies(zend zend_patch_language_parser) - add_dependencies(php_generate_files zend_patch_language_parser) endif() if(RE2C_FOUND) @@ -615,6 +611,7 @@ if(RE2C_FOUND) ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h OPTIONS --case-inverted -cbdF + CODEGEN ) re2c_target( @@ -623,6 +620,7 @@ if(RE2C_FOUND) ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h OPTIONS --case-inverted -cbdF + CODEGEN ) endif() diff --git a/cmake/cmake/Bootstrap.cmake b/cmake/cmake/Bootstrap.cmake index 2f7792fb..728531fe 100644 --- a/cmake/cmake/Bootstrap.cmake +++ b/cmake/cmake/Bootstrap.cmake @@ -48,10 +48,6 @@ add_library(php_sapi INTERFACE) add_library(PHP::sapi ALIAS php_sapi) target_link_libraries(php_sapi INTERFACE PHP::config) -# Create a custom target for generating files (parsers, lexers, etc.) manually: -# cmake --build -t php_generate_files -add_custom_target(php_generate_files) - # Configure build types. include(cmake/BuildTypes.cmake) diff --git a/cmake/cmake/Configuration.cmake b/cmake/cmake/Configuration.cmake index 2bbabe3f..69df59ad 100644 --- a/cmake/cmake/Configuration.cmake +++ b/cmake/cmake/Configuration.cmake @@ -213,13 +213,6 @@ set(PHP_ZLIB_MIN_VERSION 1.2.0.4) set(PHP_BZIP2_MIN_VERSION 1.0.0) # Additional metadata for external packages to avoid duplication. -set_package_properties( - BISON - PROPERTIES - URL "https://www.gnu.org/software/bison/" - DESCRIPTION "General-purpose parser generator" -) - set_package_properties( BZip2 PROPERTIES diff --git a/cmake/cmake/Requirements.cmake b/cmake/cmake/Requirements.cmake index 4ea0926e..718985a5 100644 --- a/cmake/cmake/Requirements.cmake +++ b/cmake/cmake/Requirements.cmake @@ -112,8 +112,6 @@ if( TYPE REQUIRED PURPOSE "Necessary to generate PHP lexer files." ) - - add_dependencies(php_generate_files re2c_generate_files) endif() ################################################################################ diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake new file mode 100644 index 00000000..89b7191b --- /dev/null +++ b/cmake/cmake/modules/FindBISON.cmake @@ -0,0 +1,83 @@ +#[=============================================================================[ +# FindBISON + +Find the bison utility. + +See: https://cmake.org/cmake/help/latest/module/FindBISON.html + +This module overrides the upstream CMake `FindBISON` module with few +customizations. + +A new `bison_generate()` function is added to be able to use it in command-line +scripts. + +```cmake +bison_generate( + + + + [COMPILE_OPTIONS ] + [DEFINES_FILE ] + [VERBOSE [REPORT_FILE ]] +) +``` +#]=============================================================================] + +include(FeatureSummary) + +set_package_properties( + BISON + PROPERTIES + URL "https://www.gnu.org/software/bison/" + DESCRIPTION "General-purpose parser generator" +) + +# Find package with upstream CMake module; override CMAKE_MODULE_PATH to prevent +# the maximum nesting/recursion depth error on some systems, like macOS. +set(_php_cmake_module_path ${CMAKE_MODULE_PATH}) +unset(CMAKE_MODULE_PATH) +include(FindBISON) +set(CMAKE_MODULE_PATH ${_php_cmake_module_path}) +unset(_php_cmake_module_path) + +if(NOT BISON_FOUND) + return() +endif() + +function(bison_generate) + cmake_parse_arguments( + PARSE_ARGV + 3 + parsed # prefix + "VERBOSE" # options + "DEFINES_FILE;REPORT_FILE" # one-value keywords + "COMPILE_OPTIONS" # multi-value keywords + ) + + if(parsed_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Bad arguments: ${parsed_UNPARSED_ARGUMENTS}") + endif() + + if(parsed_KEYWORDS_MISSING_VALUES) + message(FATAL_ERROR "Missing values for: ${parsed_KEYWORDS_MISSING_VALUES}") + endif() + + set(input ${ARGV1}) + if(NOT IS_ABSOLUTE "${input}") + set(input ${CMAKE_CURRENT_SOURCE_DIR}/${input}) + endif() + + set(output ${ARGV2}) + if(NOT IS_ABSOLUTE "${output}") + set(output ${CMAKE_CURRENT_BINARY_DIR}/${output}) + endif() + + set(options ${parsed_OPTIONS}) + + message( + STATUS + "[BISON][${ARGV0}] Generating parser with bison ${BISON_VERSION}" + ) + + execute_process(COMMAND ${BISON_EXECUTABLE} ${options} -o ${output} ${input}) +endfunction() diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index 7f4ebead..ba5ddbed 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -14,22 +14,9 @@ syntax, e.g. 'find_package(RE2C 0.15.3)'. ## Cache variables * `RE2C_EXECUTABLE` - Path to the re2c program. When RE2C is downloaded and - built from source as part of the built (using below ExternalProject), this - path will not exist until the built phase. - -Custom target: - -* `re2c_generate_files` - A custom target for generating lexer files: - - ```sh - cmake --build -t re2c_generate_files - ``` - - or to add it as a dependency to other targets: - - ```cmake - add_dependencies(some_target re2c_generate_files) - ``` + built from source as part of the built (using the `ExternalProject` CMake + module), this path will be autofilled to the built re2c and will not exist + until the build phase. ## Hints @@ -61,22 +48,82 @@ re2c_target( [DEPENDS ...] [NO_DEFAULT_OPTIONS] [NO_COMPUTED_GOTOS] + [CODEGEN] ) ``` -* `` - Target name. -* `` - The re2c template file input. Relative source file path is - interpreted as being relative to the current source directory. -* `` - The output file. Relative output file path is interpreted as - being relative to the current binary directory. -* `HEADER` - Generate a
file. Relative header file path is interpreted - as being relative to the current binary directory. -* `OPTIONS` - List of additional options to pass to re2c command-line tool. -* `DEPENDS` - Optional list of dependent files to regenerate the output file. +This will add a custom command and a custom target `` that generates lexer +file `` from the given `` re2c template file using the re2c +utility. Relative source file path ` is interpreted as being relative to +the current source directory. Relative `` file path is interpreted as +being relative to the current binary directory. + +### Options + +* `HEADER
` - Generate a given `
` file. Relative header file + path is interpreted as being relative to the current binary directory. + +* `OPTIONS ...` - List of additional options to pass to re2c + command-line tool. + +* `DEPENDS ...` - Optional list of dependent files to regenerate the + output file. + * `NO_DEFAULT_OPTIONS` - If specified, then the options from `RE2C_DEFAULT_OPTIONS` are not passed to the re2c invocation. + * `NO_COMPUTED_GOTOS` - If specified when using the `RE2C_USE_COMPUTED_GOTOS`, then the computed gotos option is not passed to the re2c invocation. + +* `CODEGEN` - adds the `CODEGEN` option to the re2c's `add_custom_command()` + call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which + provides a global CMake `codegen` target for convenience to call only the + code-generation-related targets and skips the majority of the build: + + ```sh + cmake --build --target codegen + ``` + +## Examples + +The `re2c_target()` also creates a custom target called `` that can be +used in more complex scenarios, like defining dependencies to other targets: + +```cmake +# CMakeLists.txt + +find_package(RE2C) + +if(RE2C_FOUND) + re2c_target(foo_lexer lexer.re lexer.c) + add_dependencies(some_target foo_lexer) +endif() +``` + +Or to run only the specific `foo_lexer` target, which generates the lexer. + +```sh +cmake --build --target foo_lexer +``` + +When running in script mode: + +```sh +cmake -P script.cmake +``` + +The generated file is created right away for convenience and custom target is +not created: + +```cmake +# script.cmake + +find_package(RE2C) + +if(RE2C_FOUND) + re2c_target(foo_lexer lexer.re lexer.c) +endif() +``` #]=============================================================================] include(CheckSourceCompiles) @@ -91,10 +138,6 @@ set_package_properties( DESCRIPTION "Free and open-source lexer generator" ) -if(NOT TARGET re2c_generate_files) - add_custom_target(re2c_generate_files) -endif() - find_program( RE2C_EXECUTABLE NAMES re2c @@ -103,12 +146,12 @@ find_program( mark_as_advanced(RE2C_EXECUTABLE) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) - set(_re2cCondition IS_EXECUTABLE ${RE2C_EXECUTABLE}) + set(_re2cTest IS_EXECUTABLE) else() - set(_re2cCondition EXISTS ${RE2C_EXECUTABLE}) + set(_re2cTest EXISTS) endif() -if(${_re2cCondition}) +if(${_re2cTest} ${RE2C_EXECUTABLE}) execute_process( COMMAND ${RE2C_EXECUTABLE} --vernum OUTPUT_VARIABLE RE2C_VERSION_NUM @@ -201,9 +244,9 @@ find_package_handle_standard_args( REASON_FAILURE_MESSAGE "re2c not found. Please install re2c." ) -unset(_re2cCondition) unset(_re2cMsg) unset(_re2cRequiredVars) +unset(_re2cTest) unset(_re2cVersionValid) if(NOT RE2C_FOUND) @@ -241,10 +284,10 @@ function(re2c_target) cmake_parse_arguments( PARSE_ARGV 3 - parsed # prefix - "NO_DEFAULT_OPTIONS;NO_COMPUTED_GOTOS" # options - "HEADER" # one-value keywords - "OPTIONS;DEPENDS" # multi-value keywords + parsed # prefix + "NO_DEFAULT_OPTIONS;NO_COMPUTED_GOTOS;CODEGEN" # options + "HEADER" # one-value keywords + "OPTIONS;DEPENDS" # multi-value keywords ) if(parsed_UNPARSED_ARGUMENTS) @@ -289,14 +332,15 @@ function(re2c_target) list(APPEND outputs ${header}) - # When header option is used before version 1.2, also the '-c' option is - # required. Before 1.1 -c long variant is '--start-conditions' and after 1.1 - # '--conditions'. + # When header option is used before re2c version 1.2, also the '-c' option + # is required. Before 1.1 '-c' long variant is '--start-conditions' and + # after 1.1 '--conditions'. if(RE2C_VERSION VERSION_LESS_EQUAL 1.2) list(APPEND options -c) endif() - # Since version 3.0, --header is the new alias option for --type-header. + # Since re2c version 3.0, '--header' is the new alias option for the + # '--type-header' option. if(RE2C_VERSION VERSION_GREATER_EQUAL 3.0) list(APPEND options --header ${header}) else() @@ -304,16 +348,36 @@ function(re2c_target) endif() endif() + set(message "[RE2C][${ARGV0}] Generating lexer with re2c ${RE2C_VERSION}") + set(command ${RE2C_EXECUTABLE} ${options} --output ${output} ${input}) + + if(CMAKE_SCRIPT_MODE_FILE) + message(STATUS "${message}") + execute_process(COMMAND ${command}) + return() + endif() + + set(codegen "") + if( + parsed_CODEGEN + AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 + AND POLICY CMP0171 + ) + cmake_policy(GET CMP0171 cmp0171) + + if(cmp0171 STREQUAL "NEW") + set(codegen CODEGEN) + endif() + endif() + add_custom_command( OUTPUT ${outputs} - COMMAND ${RE2C_EXECUTABLE} - ${options} - --output ${output} - ${input} + COMMAND ${command} DEPENDS ${input} ${parsed_DEPENDS} $ - COMMENT "[RE2C][${ARGV0}] Building lexer with re2c ${RE2C_VERSION}" + COMMENT "${message}" VERBATIM COMMAND_EXPAND_LISTS + ${codegen} ) add_custom_target( @@ -322,6 +386,4 @@ function(re2c_target) DEPENDS ${outputs} COMMENT "[RE2C] Building lexer with re2c ${RE2C_VERSION}" ) - - add_dependencies(re2c_generate_files ${ARGV0}) endfunction() diff --git a/cmake/cmake/scripts/GenerateLexersParsers.cmake b/cmake/cmake/scripts/GenerateLexersParsers.cmake new file mode 100755 index 00000000..d3ce933d --- /dev/null +++ b/cmake/cmake/scripts/GenerateLexersParsers.cmake @@ -0,0 +1,141 @@ +#!/usr/bin/env -S cmake -P +# +# Command-line script to generate the lexer and parser files using re2c and +# bison. +# +# Run as: `cmake -P cmake/scripts/GenerateLexersParsers.cmake` +# +# re2c and bison options must be manually synced with those used in the +# CMakeLists.txt files. +# +# TODO 1: Should the Bison-generated report files (*.output) really be also +# created by this script (the `VERBOSE REPORT_FILE ` options)? PHP still +# packages these reports also in the archive release files?! +# +# TODO 2: Add patching for Zend/zend_language_parser.{h,c} files +# +# TODO 3: Use Configuration.cmake for versions and default flags. +# +# TODO 4: Add remaining missing features to FindBISON.cmake module. + +cmake_minimum_required(VERSION 3.25...3.31) + +if(NOT CMAKE_SCRIPT_MODE_FILE) + message(FATAL_ERROR "This is a command-line script.") +endif() + +set(PHP_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../) + +if(NOT EXISTS ${PHP_SOURCE_DIR}/main/php_version.h) + message(FATAL_ERROR "This script should be run inside the php-src repository") +endif() + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../modules) + +include(${CMAKE_CURRENT_LIST_DIR}/../Configuration.cmake) + +set( + RE2C_DEFAULT_OPTIONS + --no-generation-date # Suppress date output in the generated file. + -i # Do not output line directives. +) + +set(RE2C_DISABLE_DOWNLOAD TRUE) + +find_package(BISON 3.0.0 REQUIRED) +find_package(RE2C 1.0.3 REQUIRED) + +# ext/json +bison_generate( + php_ext_json_parser + ${PHP_SOURCE_DIR}/ext/json/json_parser.y + ${PHP_SOURCE_DIR}/ext/json/json_parser.tab.c + COMPILE_OPTIONS -Wall -l + VERBOSE REPORT_FILE ${PHP_SOURCE_DIR}/ext/json/json_parser.tab.output + DEFINES_FILE ${PHP_SOURCE_DIR}/ext/json/json_parser.tab.h +) +re2c_target( + php_ext_json_scanner + ${PHP_SOURCE_DIR}/ext/json/json_scanner.re + ${PHP_SOURCE_DIR}/ext/json/json_scanner.c + HEADER ${PHP_SOURCE_DIR}/ext/json/php_json_scanner_defs.h + OPTIONS -bc +) + +# ext/pdo +re2c_target( + php_ext_pdo_sql_parser + ${PHP_SOURCE_DIR}/ext/pdo/pdo_sql_parser.re + ${PHP_SOURCE_DIR}/ext/pdo/pdo_sql_parser.c +) + +# ext/phar +re2c_target( + php_ext_phar_path_check + ${PHP_SOURCE_DIR}/ext/phar/phar_path_check.re + ${PHP_SOURCE_DIR}/ext/phar/phar_path_check.c + OPTIONS -b +) + +# ext/standard +re2c_target( + php_ext_standard_var_unserializer + ${PHP_SOURCE_DIR}/ext/standard/var_unserializer.re + ${PHP_SOURCE_DIR}/ext/standard/var_unserializer.c + OPTIONS -b +) +re2c_target( + php_ext_standard_url_scanner_ex + ${PHP_SOURCE_DIR}/ext/standard/url_scanner_ex.re + ${PHP_SOURCE_DIR}/ext/standard/url_scanner_ex.c + OPTIONS -b +) + +# sapi/phpdbg +bison_generate( + php_sapi_phpdbg_parser + ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.y + ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.c + COMPILE_OPTIONS -Wall -l + VERBOSE REPORT_FILE ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.output + DEFINES_FILE ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.h +) +re2c_target( + php_sapi_phpdbg_lexer + ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_lexer.l + ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_lexer.c + OPTIONS -cbdF +) + +# Zend +bison_generate( + zend_ini_parser + ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.y + ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.c + COMPILE_OPTIONS -Wall -l + VERBOSE REPORT_FILE ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.output + DEFINES_FILE ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.h +) +# TODO: Also patch the file here: +bison_generate( + zend_language_parser + ${PHP_SOURCE_DIR}/Zend/zend_language_parser.y + ${PHP_SOURCE_DIR}/Zend/zend_language_parser.c + COMPILE_OPTIONS -Wall -l + VERBOSE REPORT_FILE ${PHP_SOURCE_DIR}/Zend/zend_language_parser.output + DEFINES_FILE ${PHP_SOURCE_DIR}/Zend/zend_language_parser.h +) +re2c_target( + zend_language_scanner + ${PHP_SOURCE_DIR}/Zend/zend_language_scanner.l + ${PHP_SOURCE_DIR}/Zend/zend_language_scanner.c + HEADER ${PHP_SOURCE_DIR}/Zend/zend_language_scanner_defs.h + OPTIONS --case-inverted -cbdF +) +re2c_target( + zend_ini_scanner + ${PHP_SOURCE_DIR}/Zend/zend_ini_scanner.l + ${PHP_SOURCE_DIR}/Zend/zend_ini_scanner.c + HEADER ${PHP_SOURCE_DIR}/Zend/zend_ini_scanner_defs.h + OPTIONS --case-inverted -cbdF +) diff --git a/cmake/ext/json/CMakeLists.txt b/cmake/ext/json/CMakeLists.txt index 6cb2ac28..8201e10a 100644 --- a/cmake/ext/json/CMakeLists.txt +++ b/cmake/ext/json/CMakeLists.txt @@ -49,9 +49,6 @@ if(BISON_FOUND) VERBOSE REPORT_FILE json_parser.tab.output DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h ) - - add_custom_target(php_ext_json_parser DEPENDS ${BISON_TARGET_outputs}) - add_dependencies(php_generate_files php_ext_json_parser) endif() if(RE2C_FOUND) @@ -61,6 +58,7 @@ if(RE2C_FOUND) ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h OPTIONS -bc + CODEGEN ) endif() diff --git a/cmake/ext/pdo/CMakeLists.txt b/cmake/ext/pdo/CMakeLists.txt index 8ab05703..e3273429 100644 --- a/cmake/ext/pdo/CMakeLists.txt +++ b/cmake/ext/pdo/CMakeLists.txt @@ -80,5 +80,6 @@ if(RE2C_FOUND) php_ext_pdo_sql_parser pdo_sql_parser.re ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c + CODEGEN ) endif() diff --git a/cmake/ext/phar/CMakeLists.txt b/cmake/ext/phar/CMakeLists.txt index 9758da65..ba81e286 100644 --- a/cmake/ext/phar/CMakeLists.txt +++ b/cmake/ext/phar/CMakeLists.txt @@ -94,6 +94,7 @@ if(RE2C_FOUND) phar_path_check.re ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c OPTIONS -b + CODEGEN ) endif() diff --git a/cmake/ext/standard/CMakeLists.txt b/cmake/ext/standard/CMakeLists.txt index 1b15199c..411e3e0f 100644 --- a/cmake/ext/standard/CMakeLists.txt +++ b/cmake/ext/standard/CMakeLists.txt @@ -235,6 +235,7 @@ if(RE2C_FOUND) var_unserializer.re ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c OPTIONS -b + CODEGEN ) re2c_target( @@ -242,6 +243,7 @@ if(RE2C_FOUND) url_scanner_ex.re ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c OPTIONS -b + CODEGEN ) endif() diff --git a/cmake/sapi/phpdbg/CMakeLists.txt b/cmake/sapi/phpdbg/CMakeLists.txt index 3ee776ad..d77b802c 100644 --- a/cmake/sapi/phpdbg/CMakeLists.txt +++ b/cmake/sapi/phpdbg/CMakeLists.txt @@ -254,9 +254,6 @@ if(BISON_FOUND) VERBOSE REPORT_FILE phpdbg_parser.output DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.h ) - - add_custom_target(php_sapi_phpdbg_parser DEPENDS ${BISON_TARGET_outputs}) - add_dependencies(php_generate_files php_sapi_phpdbg_parser) endif() if(RE2C_FOUND) @@ -265,6 +262,7 @@ if(RE2C_FOUND) phpdbg_lexer.l ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c OPTIONS -cbdF + CODEGEN ) endif() From 78c2c604a44bc77a7fdbb71aadc03bc3caa75e0c Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 23 Dec 2024 19:33:45 +0100 Subject: [PATCH 02/15] RE2C: Also create output directories if they don't yet exist - Updated docs --- cmake/cmake/modules/FindRE2C.cmake | 54 +++++++++++++------ .../cmake/scripts/GenerateLexersParsers.cmake | 6 ++- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index ba5ddbed..1b84e6b7 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -14,20 +14,20 @@ syntax, e.g. 'find_package(RE2C 0.15.3)'. ## Cache variables * `RE2C_EXECUTABLE` - Path to the re2c program. When RE2C is downloaded and - built from source as part of the built (using the `ExternalProject` CMake - module), this path will be autofilled to the built re2c and will not exist - until the build phase. + built from source as part of the build (using the `ExternalProject` CMake + module), this path will be autofilled to point to the built re2c. Note, that + re2c built from source will not exist until the build phase. ## Hints -* `RE2C_DEFAULT_OPTIONS` - A `;-`list of default global options to pass to re2c - for all `re2c_target()` invocations. Set before calling the - `find_package(RE2C)`. Options are prepended to additional options passed with - `re2c_target()` arguments. +* `RE2C_DEFAULT_OPTIONS` - A semicolon-separated list of default global options + to pass to re2c for all `re2c_target()` invocations. Set before calling the + `find_package(RE2C)`. These options are prepended to additional options passed + as `re2c_target()` arguments. * `RE2C_DISABLE_DOWNLOAD` - This module can also download and build re2c from its Git repository using the `ExternalProject` module. Set to `TRUE` to - disable downloading re2c, when it is not found on the system or system version + disable downloading re2c, when it is not found on the system or found version is not suitable. * `RE2C_USE_COMPUTED_GOTOS` - Set to `TRUE` before calling `find_package(RE2C)` @@ -52,7 +52,7 @@ re2c_target( ) ``` -This will add a custom command and a custom target `` that generates lexer +This adds a custom target `` and a custom command that generates lexer file `` from the given `` re2c template file using the re2c utility. Relative source file path ` is interpreted as being relative to the current source directory. Relative `` file path is interpreted as @@ -63,19 +63,19 @@ being relative to the current binary directory. * `HEADER
` - Generate a given `
` file. Relative header file path is interpreted as being relative to the current binary directory. -* `OPTIONS ...` - List of additional options to pass to re2c - command-line tool. +* `OPTIONS ...` - Optional list of additional options to pass to the + re2c command-line tool. * `DEPENDS ...` - Optional list of dependent files to regenerate the output file. * `NO_DEFAULT_OPTIONS` - If specified, then the options from - `RE2C_DEFAULT_OPTIONS` are not passed to the re2c invocation. + `RE2C_DEFAULT_OPTIONS` are not added to current re2c invocation. * `NO_COMPUTED_GOTOS` - If specified when using the `RE2C_USE_COMPUTED_GOTOS`, - then the computed gotos option is not passed to the re2c invocation. + then the computed gotos option is not added to the current re2c invocation. -* `CODEGEN` - adds the `CODEGEN` option to the re2c's `add_custom_command()` +* `CODEGEN` - Adds the `CODEGEN` option to the re2c's `add_custom_command()` call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which provides a global CMake `codegen` target for convenience to call only the code-generation-related targets and skips the majority of the build: @@ -87,7 +87,7 @@ being relative to the current binary directory. ## Examples The `re2c_target()` also creates a custom target called `` that can be -used in more complex scenarios, like defining dependencies to other targets: +used in more complex scenarios, such as defining dependencies: ```cmake # CMakeLists.txt @@ -247,6 +247,8 @@ find_package_handle_standard_args( unset(_re2cMsg) unset(_re2cRequiredVars) unset(_re2cTest) +unset(_re2cVersionError) +unset(_re2cVersionResult) unset(_re2cVersionValid) if(NOT RE2C_FOUND) @@ -351,9 +353,28 @@ function(re2c_target) set(message "[RE2C][${ARGV0}] Generating lexer with re2c ${RE2C_VERSION}") set(command ${RE2C_EXECUTABLE} ${options} --output ${output} ${input}) + # RE2C cannot create output directories. Ensure any required directories + # for the generated files are created if they don't already exist. + set(makeDirectoryCommand "") + foreach(output IN LISTS outputs) + cmake_path(GET output PARENT_PATH dir) + if(dir) + list(APPEND makeDirectoryCommand ${dir}) + endif() + unset(dir) + endforeach() + if(makeDirectoryCommand) + list(REMOVE_DUPLICATES makeDirectoryCommand) + list( + PREPEND + makeDirectoryCommand + COMMAND ${CMAKE_COMMAND} -E make_directory + ) + endif() + if(CMAKE_SCRIPT_MODE_FILE) message(STATUS "${message}") - execute_process(COMMAND ${command}) + execute_process(${makeDirectoryCommand} COMMAND ${command}) return() endif() @@ -372,6 +393,7 @@ function(re2c_target) add_custom_command( OUTPUT ${outputs} + ${makeDirectoryCommand} COMMAND ${command} DEPENDS ${input} ${parsed_DEPENDS} $ COMMENT "${message}" diff --git a/cmake/cmake/scripts/GenerateLexersParsers.cmake b/cmake/cmake/scripts/GenerateLexersParsers.cmake index d3ce933d..34459485 100755 --- a/cmake/cmake/scripts/GenerateLexersParsers.cmake +++ b/cmake/cmake/scripts/GenerateLexersParsers.cmake @@ -3,7 +3,11 @@ # Command-line script to generate the lexer and parser files using re2c and # bison. # -# Run as: `cmake -P cmake/scripts/GenerateLexersParsers.cmake` +# Run as: +# +# ```sh +# [RE2C_EXECUTABLE=path/to/re2c] cmake -P cmake/scripts/GenerateLexersParsers.cmake` +# ``` # # re2c and bison options must be manually synced with those used in the # CMakeLists.txt files. From 00a46b5c50fab75d7863dd8dd555c3eb72912137 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 23 Dec 2024 19:47:34 +0100 Subject: [PATCH 03/15] Simplify commands creation --- cmake/cmake/modules/FindRE2C.cmake | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index 1b84e6b7..6b35ea40 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -351,30 +351,29 @@ function(re2c_target) endif() set(message "[RE2C][${ARGV0}] Generating lexer with re2c ${RE2C_VERSION}") - set(command ${RE2C_EXECUTABLE} ${options} --output ${output} ${input}) + set(commands COMMAND ${RE2C_EXECUTABLE} ${options} --output ${output} ${input}) # RE2C cannot create output directories. Ensure any required directories # for the generated files are created if they don't already exist. - set(makeDirectoryCommand "") + set(directories "") foreach(output IN LISTS outputs) cmake_path(GET output PARENT_PATH dir) if(dir) - list(APPEND makeDirectoryCommand ${dir}) + list(APPEND directories ${dir}) endif() - unset(dir) endforeach() - if(makeDirectoryCommand) - list(REMOVE_DUPLICATES makeDirectoryCommand) + if(directories) + list(REMOVE_DUPLICATES directories) list( PREPEND - makeDirectoryCommand - COMMAND ${CMAKE_COMMAND} -E make_directory + commands + COMMAND ${CMAKE_COMMAND} -E make_directory ${directories} ) endif() if(CMAKE_SCRIPT_MODE_FILE) message(STATUS "${message}") - execute_process(${makeDirectoryCommand} COMMAND ${command}) + execute_process(${commands}) return() endif() @@ -393,8 +392,7 @@ function(re2c_target) add_custom_command( OUTPUT ${outputs} - ${makeDirectoryCommand} - COMMAND ${command} + ${commands} DEPENDS ${input} ${parsed_DEPENDS} $ COMMENT "${message}" VERBATIM From 24a1d8ac9b5482c1ce2cd5cbfb4b2f19359b4c5d Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Wed, 25 Dec 2024 21:30:35 +0100 Subject: [PATCH 04/15] Refactor bison and re2c usages - This adds new BISON and RE2C utility modules on top of the find modules to have common configuration at one place. - Zend patching improved a bit - More common naming for lexers and parsers used in filenames: "grammar" - ... --- cmake/Zend/CMakeLists.txt | 98 +-- cmake/Zend/cmake/GenerateGrammar.cmake | 121 ++++ cmake/cmake/Configuration.cmake | 3 - cmake/cmake/Requirements.cmake | 70 -- cmake/cmake/modules/FindBISON.cmake | 37 +- cmake/cmake/modules/FindRE2C.cmake | 653 ++++++++++++------ cmake/cmake/modules/PHP/BISON.cmake | 76 ++ cmake/cmake/modules/PHP/RE2C.cmake | 75 ++ cmake/cmake/scripts/GenerateGrammar.cmake | 72 ++ .../cmake/scripts/GenerateLexersParsers.cmake | 145 ---- cmake/ext/json/CMakeLists.txt | 24 +- cmake/ext/json/cmake/GenerateGrammar.cmake | 37 + cmake/ext/pdo/CMakeLists.txt | 13 +- cmake/ext/pdo/cmake/GenerateGrammar.cmake | 14 + cmake/ext/phar/CMakeLists.txt | 14 +- cmake/ext/phar/cmake/GenerateGrammar.cmake | 15 + cmake/ext/standard/CMakeLists.txt | 20 +- .../ext/standard/cmake/GenerateGrammar.cmake | 26 + cmake/sapi/phpdbg/CMakeLists.txt | 21 +- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 33 + 20 files changed, 953 insertions(+), 614 deletions(-) create mode 100644 cmake/Zend/cmake/GenerateGrammar.cmake create mode 100644 cmake/cmake/modules/PHP/BISON.cmake create mode 100644 cmake/cmake/modules/PHP/RE2C.cmake create mode 100755 cmake/cmake/scripts/GenerateGrammar.cmake delete mode 100755 cmake/cmake/scripts/GenerateLexersParsers.cmake create mode 100644 cmake/ext/json/cmake/GenerateGrammar.cmake create mode 100644 cmake/ext/pdo/cmake/GenerateGrammar.cmake create mode 100644 cmake/ext/phar/cmake/GenerateGrammar.cmake create mode 100644 cmake/ext/standard/cmake/GenerateGrammar.cmake create mode 100644 cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake diff --git a/cmake/Zend/CMakeLists.txt b/cmake/Zend/CMakeLists.txt index b98286e4..da03e21b 100644 --- a/cmake/Zend/CMakeLists.txt +++ b/cmake/Zend/CMakeLists.txt @@ -526,103 +526,7 @@ endif() # Generate lexers and parsers. ################################################################################ -if(BISON_FOUND) - bison_target( - zend_ini_parser - zend_ini_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c - COMPILE_FLAGS "${PHP_DEFAULT_BISON_FLAGS}" - VERBOSE REPORT_FILE zend_ini_parser.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h - ) - - bison_target( - zend_language_parser - zend_language_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c - COMPILE_FLAGS "${PHP_DEFAULT_BISON_FLAGS}" - VERBOSE REPORT_FILE zend_language_parser.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h - ) - - # Tweak zendparse to be exported through ZEND_API. This has to be revisited - # once bison supports foreign skeletons and that bison version is used. Read - # https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more. - file( - GENERATE - OUTPUT CMakeFiles/PatchLanguageParser.cmake - CONTENT [[ - file(READ "${SOURCE_DIR}/zend_language_parser.h" content) - string( - REPLACE - "int zendparse" - "ZEND_API int zendparse" - content_2 - "${content}" - ) - if( - NOT content MATCHES "ZEND_API int zendparse" - AND NOT content STREQUAL "${content_2}" - ) - execute_process( - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --blue --bold - " [Zend] Patching Zend/zend_language_parser.h" - ) - file(WRITE "${SOURCE_DIR}/zend_language_parser.h" "${content_2}") - endif() - - file(READ "${SOURCE_DIR}/zend_language_parser.c" content) - string( - REPLACE - "int zendparse" - "ZEND_API int zendparse" - content_2 - "${content}" - ) - if( - NOT content MATCHES "ZEND_API int zendparse" - AND NOT content STREQUAL "${content_2}" - ) - execute_process( - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --blue --bold - " [Zend] Patching Zend/zend_language_parser.c" - ) - file(WRITE "${SOURCE_DIR}/zend_language_parser.c" "${content_2}") - endif() - ]] - ) - - add_custom_target( - zend_patch_language_parser - COMMAND ${CMAKE_COMMAND} - -D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} - -P "CMakeFiles/PatchLanguageParser.cmake" - DEPENDS ${BISON_zend_language_parser_OUTPUTS} - VERBATIM - ) - - add_dependencies(zend zend_patch_language_parser) -endif() - -if(RE2C_FOUND) - re2c_target( - zend_language_scanner - zend_language_scanner.l - ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h - OPTIONS --case-inverted -cbdF - CODEGEN - ) - - re2c_target( - zend_ini_scanner - zend_ini_scanner.l - ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h - OPTIONS --case-inverted -cbdF - CODEGEN - ) -endif() +include(cmake/GenerateGrammar.cmake) ################################################################################ # Configure fibers. diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake new file mode 100644 index 00000000..c4427c69 --- /dev/null +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -0,0 +1,121 @@ +#[=============================================================================[ +Generate lexer and parser files for Zend Engine. +#]=============================================================================] + +if( + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h +) + set(PHP_BISON_OPTIONAL TRUE) +endif() +include(PHP/BISON) + +if(BISON_FOUND) + php_bison( + zend_ini_parser + zend_ini_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c + COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" + VERBOSE REPORT_FILE zend_ini_parser.output + DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h + ) + + php_bison( + zend_language_parser + zend_language_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c + COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" + VERBOSE REPORT_FILE zend_language_parser.output + DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h + ) + + # Tweak zendparse to be exported through ZEND_API. This has to be revisited + # once bison supports foreign skeletons and that bison version is used. Read + # https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more. + block() + string( + CONCAT patch + "set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})\n" + [[ + file(READ "${SOURCE_DIR}/zend_language_parser.h" content) + string( + REPLACE + "int zendparse" + "ZEND_API int zendparse" + content_2 + "${content}" + ) + if( + NOT content MATCHES "ZEND_API int zendparse" + AND NOT content STREQUAL "${content_2}" + ) + message(STATUS "[Zend] Patching zend_language_parser.h") + file(WRITE "${SOURCE_DIR}/zend_language_parser.h" "${content_2}") + endif() + + file(READ "${SOURCE_DIR}/zend_language_parser.c" content) + string( + REPLACE + "int zendparse" + "ZEND_API int zendparse" + content_2 + "${content}" + ) + if( + NOT content MATCHES "ZEND_API int zendparse" + AND NOT content STREQUAL "${content_2}" + ) + message(STATUS "[Zend] Patching zend_language_parser.c") + file(WRITE "${SOURCE_DIR}/zend_language_parser.c" "${content_2}") + endif() + ]]) + + # Run patch based on whether building or running inside a CMake script. + if(CMAKE_SCRIPT_MODE_FILE) + cmake_language(EVAL CODE "${patch}") + else() + file( + GENERATE + OUTPUT CMakeFiles/PatchLanguageParser.cmake + CONTENT "${patch}" + ) + add_custom_target( + zend_patch_language_parser + COMMAND ${CMAKE_COMMAND} -P CMakeFiles/PatchLanguageParser.cmake + DEPENDS ${BISON_zend_language_parser_OUTPUTS} + VERBATIM + ) + add_dependencies(zend zend_patch_language_parser) + endif() + endblock() +endif() + +if( + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h +) + set(PHP_RE2C_OPTIONAL TRUE) +endif() +include(PHP/RE2C) + +php_re2c( + zend_ini_scanner + zend_ini_scanner.l + ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h + OPTIONS --case-inverted -cbdF + CODEGEN +) + +php_re2c( + zend_language_scanner + zend_language_scanner.l + ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h + OPTIONS --case-inverted -cbdF + CODEGEN +) diff --git a/cmake/cmake/Configuration.cmake b/cmake/cmake/Configuration.cmake index 69df59ad..7729f10d 100644 --- a/cmake/cmake/Configuration.cmake +++ b/cmake/cmake/Configuration.cmake @@ -92,9 +92,6 @@ mark_as_advanced(PHP_PROGRAM_PREFIX) set(PHP_PROGRAM_SUFFIX "" CACHE STRING "Append suffix to the program names") mark_as_advanced(PHP_PROGRAM_SUFFIX) -option(PHP_RE2C_CGOTO "Enable computed goto GCC extension with re2c") -mark_as_advanced(PHP_RE2C_CGOTO) - option(PHP_THREAD_SAFETY "Enable thread safety (ZTS)") cmake_dependent_option( diff --git a/cmake/cmake/Requirements.cmake b/cmake/cmake/Requirements.cmake index 718985a5..a2690fbc 100644 --- a/cmake/cmake/Requirements.cmake +++ b/cmake/cmake/Requirements.cmake @@ -6,7 +6,6 @@ include_guard(GLOBAL) include(CheckSourceRuns) include(CMakePushCheckState) -include(FeatureSummary) ################################################################################ # Check whether some minimum supported compiler is used. @@ -45,75 +44,6 @@ else() message(CHECK_PASS "ASCII") endif() -################################################################################ -# Check if bison and re2c are required. -# -# PHP tarball packaged and released at php.net already contains generated lexer -# and parser files. In such cases these don't need to be generated again. When -# building from a Git repository, bison and re2c are required to be installed so -# files can be generated as part of the build process. -################################################################################ -# -# Check if bison is required. -if( - NOT EXISTS ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.h - OR NOT EXISTS ${PHP_SOURCE_DIR}/Zend/zend_language_parser.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/Zend/zend_language_parser.h - OR NOT EXISTS ${PHP_SOURCE_DIR}/ext/json/json_parser.tab.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/ext/json/json_parser.tab.h - OR NOT EXISTS ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.h -) - find_package(BISON 3.0.0) - set_package_properties( - BISON - PROPERTIES - TYPE REQUIRED - PURPOSE "Necessary to generate PHP parser files." - ) - # Add Bison options based on the build type. - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.32) - # See: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9921 - set(PHP_DEFAULT_BISON_FLAGS "-Wall $<$:-l>") - else() - set(PHP_DEFAULT_BISON_FLAGS "$,-lWall,-Wall>") - endif() -endif() - -# Check if re2c is required. -if( - NOT EXISTS ${PHP_SOURCE_DIR}/Zend/zend_language_scanner.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/Zend/zend_language_scanner_defs.h - OR NOT EXISTS ${PHP_SOURCE_DIR}/Zend/zend_ini_scanner.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/Zend/zend_ini_scanner_defs.h - OR NOT EXISTS ${PHP_SOURCE_DIR}/ext/json/json_scanner.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/ext/json/php_json_scanner_defs.h - OR NOT EXISTS ${PHP_SOURCE_DIR}/ext/pdo/pdo_sql_parser.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/ext/phar/phar_path_check.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/ext/standard/url_scanner_ex.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/ext/standard/var_unserializer.c - OR NOT EXISTS ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_lexer.c -) - if(PHP_RE2C_CGOTO) - set(RE2C_USE_COMPUTED_GOTOS TRUE) - endif() - - set( - RE2C_DEFAULT_OPTIONS - --no-generation-date # Suppress date output in the generated file. - $<$:-i> # Do not output line directives. - ) - - find_package(RE2C 1.0.3) - set_package_properties( - RE2C - PROPERTIES - TYPE REQUIRED - PURPOSE "Necessary to generate PHP lexer files." - ) -endif() - ################################################################################ # Find mailer. ################################################################################ diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake index 89b7191b..cf0c3154 100644 --- a/cmake/cmake/modules/FindBISON.cmake +++ b/cmake/cmake/modules/FindBISON.cmake @@ -8,15 +8,15 @@ See: https://cmake.org/cmake/help/latest/module/FindBISON.html This module overrides the upstream CMake `FindBISON` module with few customizations. -A new `bison_generate()` function is added to be able to use it in command-line +A new `bison_execute()` function is added to be able to use it in command-line scripts. ```cmake -bison_generate( +bison_execute( - [COMPILE_OPTIONS ] + [COMPILE_FLAGS ] [DEFINES_FILE ] [VERBOSE [REPORT_FILE ]] ) @@ -44,14 +44,14 @@ if(NOT BISON_FOUND) return() endif() -function(bison_generate) +function(bison_execute) cmake_parse_arguments( PARSE_ARGV 3 parsed # prefix "VERBOSE" # options - "DEFINES_FILE;REPORT_FILE" # one-value keywords - "COMPILE_OPTIONS" # multi-value keywords + "DEFINES_FILE;REPORT_FILE;COMPILE_FLAGS" # one-value keywords + "" # multi-value keywords ) if(parsed_UNPARSED_ARGUMENTS) @@ -72,12 +72,33 @@ function(bison_generate) set(output ${CMAKE_CURRENT_BINARY_DIR}/${output}) endif() - set(options ${parsed_OPTIONS}) + separate_arguments(options NATIVE_COMMAND "${parsed_COMPILE_FLAGS}") + + if(parsed_DEFINES_FILE) + list(APPEND options --defines=${parsed_DEFINES_FILE}) + endif() + + if(parsed_VERBOSE) + list(APPEND options --verbose) + endif() + + if(parsed_REPORT_FILE AND NOT IS_ABSOLUTE "${parsed_REPORT_FILE}") + set(parsed_REPORT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${parsed_REPORT_FILE}) + endif() + + if(parsed_REPORT_FILE) + list(APPEND options --report-file=${parsed_REPORT_FILE}) + endif() + + set( + commands + COMMAND ${BISON_EXECUTABLE} ${options} --output ${output} ${input} + ) message( STATUS "[BISON][${ARGV0}] Generating parser with bison ${BISON_VERSION}" ) - execute_process(COMMAND ${BISON_EXECUTABLE} ${options} -o ${output} ${input}) + execute_process(${commands}) endfunction() diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index 6b35ea40..abc8ce8d 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -1,45 +1,58 @@ #[=============================================================================[ # FindRE2C -Find re2c. +Find `re2c` command-line lexer generator. -The minimum required version of re2c can be specified using the standard CMake -syntax, e.g. 'find_package(RE2C 0.15.3)'. +When `re2c` cannot be found on the system or the found version is not suitable, +this module can also download and build it from its Git repository sources +release archive as part of the project build using the `ExternalProject` CMake +module. ## Result variables -* `RE2C_FOUND` - Whether re2c program was found. -* `RE2C_VERSION` - Version of re2c program. +* `RE2C_FOUND` - Whether the `re2c` was found. +* `RE2C_VERSION` - The `re2c` version. ## Cache variables -* `RE2C_EXECUTABLE` - Path to the re2c program. When RE2C is downloaded and - built from source as part of the build (using the `ExternalProject` CMake - module), this path will be autofilled to point to the built re2c. Note, that - re2c built from source will not exist until the build phase. +* `RE2C_EXECUTABLE` - Path to the `re2c`. When `re2c` is downloaded and built + from source, this path is autofilled to point to the built `re2c` executable. + Note, that the `re2c` executable built from source will not exist until the + build phase. ## Hints -* `RE2C_DEFAULT_OPTIONS` - A semicolon-separated list of default global options - to pass to re2c for all `re2c_target()` invocations. Set before calling the - `find_package(RE2C)`. These options are prepended to additional options passed - as `re2c_target()` arguments. +These variables can be set before calling the `find_package(RE2C)`: -* `RE2C_DISABLE_DOWNLOAD` - This module can also download and build re2c from - its Git repository using the `ExternalProject` module. Set to `TRUE` to - disable downloading re2c, when it is not found on the system or found version +* `RE2C_DEFAULT_OPTIONS` - A semicolon-separated list of default global re2c + options to be prepended to `re2c(OPTIONS)` argument for all re2c invocations + when generating lexers. + +* `RE2C_DISABLE_DOWNLOAD` - Set to `TRUE` to disable downloading and building + RE2C package from source, when it is not found on the system or found version is not suitable. -* `RE2C_USE_COMPUTED_GOTOS` - Set to `TRUE` before calling `find_package(RE2C)` - to enable the re2c `--computed-gotos` option if the non-standard C - `computed goto` extension is supported by the C compiler. +* `RE2C_DOWNLOAD_VERSION` - Override the default `re2c` version to be downloaded + when not found on the system. + +* `RE2C_NAMESPACE` - Optional namespace prepended to `re2c` CMake function + names. + +* `RE2C_USE_COMPUTED_GOTOS` - Set to `TRUE` to enable the re2c + `--computed-gotos` (`-g`) option if the non-standard C `computed goto` + extension is supported by the C compiler. When using it in command-line script + mode, option is not checked, whether the compiler supports it and is added to + `re2c` options unconditionally. ## Functions provided by this module -If re2c is found, the following function is exposed: +### `re2c()` + +Generate lexer file `` from the given `` template file using the +`re2c` lexer generator. ```cmake -re2c_target( +re2c( @@ -52,13 +65,19 @@ re2c_target( ) ``` -This adds a custom target `` and a custom command that generates lexer -file `` from the given `` re2c template file using the re2c -utility. Relative source file path ` is interpreted as being relative to -the current source directory. Relative `` file path is interpreted as -being relative to the current binary directory. +This creates a custom CMake target `` and adds a custom command that +generates lexer file `` from the given `` template file using the +`re2c` lexer generator. Relative source file path `` is interpreted as +being relative to the current source directory. Relative `` file path is +interpreted as being relative to the current binary directory. If `re2c` is not +a required package and it is not found, it will create a custom target but skip +the `re2c` command execution. + +When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it +simply generates the lexer without creating a target, to make it easier to use +in various scenarios. -### Options +#### Options * `HEADER
` - Generate a given `
` file. Relative header file path is interpreted as being relative to the current binary directory. @@ -69,11 +88,11 @@ being relative to the current binary directory. * `DEPENDS ...` - Optional list of dependent files to regenerate the output file. -* `NO_DEFAULT_OPTIONS` - If specified, then the options from - `RE2C_DEFAULT_OPTIONS` are not added to current re2c invocation. +* `NO_DEFAULT_OPTIONS` - If specified, the `RE2C_DEFAULT_OPTIONS` are not added + to the current `re2c` invocation. -* `NO_COMPUTED_GOTOS` - If specified when using the `RE2C_USE_COMPUTED_GOTOS`, - then the computed gotos option is not added to the current re2c invocation. +* `NO_COMPUTED_GOTOS` - If specified, when using the `RE2C_USE_COMPUTED_GOTOS`, + the computed gotos option is not added to the current `re2c` invocation. * `CODEGEN` - Adds the `CODEGEN` option to the re2c's `add_custom_command()` call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which @@ -84,20 +103,90 @@ being relative to the current binary directory. cmake --build --target codegen ``` +### `re2c_execute()` + +```cmake +re2c_execute( + + + [HEADER
] + [OPTIONS ...] + [NO_DEFAULT_OPTIONS] + [NO_COMPUTED_GOTOS] +) +``` + +This generates `` lexer file from the given `` template using the +`re2c` command-line lexer generator. Relative `` source file path is +interpreted as being relative to the current source directory. Relative +`` file path is interpreted as being relative to the current binary +directory. If `re2c` is not a required package and it is not found, it will skip +the lexer generation. + +This command can be used in scripts or if generated files need to be available +in the configuration phase immediately without creating a CMake target. + +#### Options + +Options available in `re2c_execute` behave the same as in the `re2c()`. + ## Examples -The `re2c_target()` also creates a custom target called `` that can be -used in more complex scenarios, such as defining dependencies: +### Basic usage + +The minimum required `re2c` version can be specified using the standard CMake +syntax, e.g. ```cmake # CMakeLists.txt +find_package(RE2C 1.0.3) +``` + +### Specifying options + +Setting default options for all `re2c()` calls in the scope of +`find_package(RE2C)`: + +```cmake +# CMakeLists.txt + +# Optionally, set default options for all re2c invocations. For example, add +# option to suppress date output in the generated file: +set(RE2C_DEFAULT_OPTIONS --no-generation-date) + find_package(RE2C) -if(RE2C_FOUND) - re2c_target(foo_lexer lexer.re lexer.c) - add_dependencies(some_target foo_lexer) -endif() +# This will execute re2c as: +# re2c --no-generation-date --bit-vectors --conditions --output foo.c foo.re +re2c(foo foo.re foo.c OPTIONS --bit-vectors --conditions) + +# This will execute re2c as: +# re2c --no-generation-date --case-inverted --output bar.c bar.re +re2c(bar bar.re bar.c OPTIONS --case-inverted) +``` + +Generator expressions are supported in `re2c(OPTIONS)`: + +```cmake +# CMakeLists.txt + +find_package(RE2C) + +re2c(foo foo.re foo.c OPTIONS $<$:--debug-output>) +``` + +### Custom target usage + +To specify dependencies with the custom target created by `re2c()`: + +```cmake +# CMakeLists.txt + +find_package(RE2C) + +re2c(foo_lexer lexer.re lexer.c) +add_dependencies(some_target foo_lexer) ``` Or to run only the specific `foo_lexer` target, which generates the lexer. @@ -106,23 +195,34 @@ Or to run only the specific `foo_lexer` target, which generates the lexer. cmake --build --target foo_lexer ``` -When running in script mode: +### Script mode + +When running `re2c()`, for example, in script mode: ```sh cmake -P script.cmake ``` -The generated file is created right away for convenience and custom target is -not created: +the generated file is created right away: ```cmake # script.cmake -find_package(RE2C) +find_package(RE2C REQUIRED) -if(RE2C_FOUND) - re2c_target(foo_lexer lexer.re lexer.c) -endif() +re2c(foo_lexer lexer.re lexer.c) +``` + +### Namespace + +Setting namespace isolates the function definitions to specific namespace in +case they can clash with some existing names. + +```cmake +set(RE2C_NAMESPACE "foo_") +find_package(RE2C REQUIRED) + +foo_re2c(foo_lexer lexer.re lexer.c) ``` #]=============================================================================] @@ -131,12 +231,231 @@ include(CMakePushCheckState) include(FeatureSummary) include(FindPackageHandleStandardArgs) -set_package_properties( - RE2C - PROPERTIES - URL "https://re2c.org/" - DESCRIPTION "Free and open-source lexer generator" -) +################################################################################ +# Functions. +################################################################################ + +if(NOT RE2C_NAMESPACE) + set(RE2C_NAMESPACE "") +endif() + +# Process options. +function(_${RE2C_NAMESPACE}re2c_process_options options result) + set(options ${${options}}) + + if( + RE2C_USE_COMPUTED_GOTOS + AND _RE2C_HAVE_COMPUTED_GOTOS + AND NOT parsed_NO_COMPUTED_GOTOS + ) + list(PREPEND options "--computed-gotos") + endif() + + if(RE2C_DEFAULT_OPTIONS AND NOT parsed_NO_DEFAULT_OPTIONS) + list(PREPEND options ${RE2C_DEFAULT_OPTIONS}) + endif() + + set(${result} ${options}) + + return(PROPAGATE ${result}) +endfunction() + +macro(_${RE2C_NAMESPACE}re2c_process) + if(parsed_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Bad arguments: ${parsed_UNPARSED_ARGUMENTS}") + endif() + + if(parsed_KEYWORDS_MISSING_VALUES) + message(FATAL_ERROR "Missing values for: ${parsed_KEYWORDS_MISSING_VALUES}") + endif() + + set(input ${ARGV1}) + if(NOT IS_ABSOLUTE "${input}") + set(input ${CMAKE_CURRENT_SOURCE_DIR}/${input}) + endif() + cmake_path(SET input NORMALIZE "${input}") + + set(output ${ARGV2}) + if(NOT IS_ABSOLUTE "${output}") + set(output ${CMAKE_CURRENT_BINARY_DIR}/${output}) + endif() + cmake_path(SET output NORMALIZE "${output}") + + set(outputs ${output}) + + cmake_language( + CALL _${RE2C_NAMESPACE}re2c_process_options + parsed_OPTIONS + options + ) + + if(parsed_HEADER) + set(header ${parsed_HEADER}) + if(NOT IS_ABSOLUTE "${header}") + set(header ${CMAKE_CURRENT_BINARY_DIR}/${header}) + endif() + + list(APPEND outputs ${header}) + + # When header option is used before re2c version 1.2, also the '-c' option + # is required. Before 1.1 '-c' long variant is '--start-conditions' and + # after 1.1 '--conditions'. + if(RE2C_VERSION VERSION_LESS_EQUAL 1.2) + list(APPEND options -c) + endif() + + # Since re2c version 3.0, '--header' is the new alias option for the + # '--type-header' option. + if(RE2C_VERSION VERSION_GREATER_EQUAL 3.0) + list(APPEND options --header ${header}) + else() + list(APPEND options --type-header ${header}) + endif() + endif() + + # Assemble commands for add_custom_command() and execute_process(). + set(commands "") + + # RE2C cannot create output directories. Ensure any required directories for + # the generated files are created if they don't already exist. + set(directories "") + foreach(output IN LISTS outputs) + cmake_path(GET output PARENT_PATH dir) + if(dir) + list(APPEND directories ${dir}) + endif() + endforeach() + if(directories) + list(REMOVE_DUPLICATES directories) + list( + APPEND + commands + COMMAND ${CMAKE_COMMAND} -E make_directory ${directories} + ) + endif() + + list( + APPEND + commands + COMMAND ${RE2C_EXECUTABLE} ${options} --output ${output} ${input} + ) + + # Assemble status message. + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${CMAKE_BINARY_DIR} + OUTPUT_VARIABLE outputRelative + ) + + set(message "Generating ${outputRelative} with re2c ${RE2C_VERSION}") +endmacro() + +function(${RE2C_NAMESPACE}re2c) + cmake_parse_arguments( + PARSE_ARGV + 3 + parsed # prefix + "NO_DEFAULT_OPTIONS;NO_COMPUTED_GOTOS;CODEGEN" # options + "HEADER" # one-value keywords + "OPTIONS;DEPENDS" # multi-value keywords + ) + + cmake_language(CALL _${RE2C_NAMESPACE}re2c_process ${ARGN}) + + if(NOT CMAKE_SCRIPT_MODE_FILE) + add_custom_target(${ARGV0} SOURCES ${input} DEPENDS ${outputs}) + endif() + + # Skip generation, if generated files are provided by the release archive. + get_property(type GLOBAL PROPERTY _CMAKE_RE2C_TYPE) + if(NOT RE2C_FOUND AND NOT RE2C_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") + return() + endif() + + if(CMAKE_SCRIPT_MODE_FILE) + message(STATUS "[RE2C] ${message}") + execute_process(${commands}) + return() + endif() + + set(codegen "") + if( + parsed_CODEGEN + AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 + AND POLICY CMP0171 + ) + cmake_policy(GET CMP0171 cmp0171) + + if(cmp0171 STREQUAL "NEW") + set(codegen CODEGEN) + endif() + endif() + + add_custom_command( + OUTPUT ${outputs} + ${commands} + DEPENDS ${input} ${parsed_DEPENDS} $ + COMMENT "[RE2C][${ARGV0}] ${message}" + VERBATIM + COMMAND_EXPAND_LISTS + ${codegen} + ) +endfunction() + +function(${RE2C_NAMESPACE}re2c_execute) + cmake_parse_arguments( + PARSE_ARGV + 2 + parsed # prefix + "NO_DEFAULT_OPTIONS;NO_COMPUTED_GOTOS" # options + "HEADER" # one-value keywords + "OPTIONS" # multi-value keywords + ) + + # First argument enables using the same macro signature for both functions. + cmake_language(CALL _${RE2C_NAMESPACE}re2c_process ${ARGN}) + + # Skip generation, if generated files are provided by the release archive. + get_property(type GLOBAL PROPERTY _CMAKE_RE2C_TYPE) + if(NOT RE2C_FOUND AND NOT RE2C_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") + return() + endif() + + message(STATUS "[RE2C] ${message}") + execute_process(${commands}) +endfunction() + +################################################################################ +# Package definition. +################################################################################ + +block() + cmake_path( + RELATIVE_PATH + CMAKE_CURRENT_SOURCE_DIR + BASE_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE relativeDir + ) + + if(relativeDir STREQUAL ".") + set(purpose "Necessary to generate lexer files.") + else() + set(purpose "Necessary to generate ${relativeDir} lexer files.") + endif() + + set_package_properties( + RE2C + PROPERTIES + URL "https://re2c.org/" + DESCRIPTION "Lexer generator" + PURPOSE "${purpose}" + ) +endblock() + +################################################################################ +# Find the package. +################################################################################ find_program( RE2C_EXECUTABLE @@ -193,57 +512,83 @@ if(${_re2cTest} ${RE2C_EXECUTABLE}) endif() endif() -set(_re2cRequiredVars RE2C_EXECUTABLE RE2C_VERSION) - -if(NOT RE2C_DISABLE_DOWNLOAD AND (NOT RE2C_EXECUTABLE OR NOT _re2cVersionValid)) - # Set the re2c version to download. - set(RE2C_VERSION 4.0.2) - - include(ExternalProject) - - ExternalProject_Add( - re2c - URL - https://github.com/skvadrik/re2c/archive/refs/tags/${RE2C_VERSION}.tar.gz - CMAKE_ARGS - -DRE2C_BUILD_RE2D=OFF - -DRE2C_BUILD_RE2D=OFF - -DRE2C_BUILD_RE2GO=OFF - -DRE2C_BUILD_RE2HS=OFF - -DRE2C_BUILD_RE2JAVA=OFF - -DRE2C_BUILD_RE2JS=OFF - -DRE2C_BUILD_RE2OCAML=OFF - -DRE2C_BUILD_RE2PY=OFF - -DRE2C_BUILD_RE2RUST=OFF - -DRE2C_BUILD_RE2V=OFF - -DRE2C_BUILD_RE2ZIG=OFF - -DRE2C_BUILD_TESTS=OFF - INSTALL_COMMAND "" - ) +set(_re2cRequiredVars "") - # Set re2c executable. - ExternalProject_Get_property(re2c BINARY_DIR) - add_executable(RE2C::RE2C IMPORTED) - set_target_properties( - RE2C::RE2C - PROPERTIES IMPORTED_LOCATION ${BINARY_DIR}/re2c - ) - add_dependencies(RE2C::RE2C re2c) - set_property(CACHE RE2C_EXECUTABLE PROPERTY VALUE ${BINARY_DIR}/re2c) - unset(BINARY_DIR) +################################################################################ +# Download and build the package. +################################################################################ + +if( + NOT CMAKE_SCRIPT_MODE_FILE + AND NOT RE2C_DISABLE_DOWNLOAD + AND (NOT RE2C_EXECUTABLE OR NOT _re2cVersionValid) +) + # Set which re2c version to download. + if(NOT RE2C_DOWNLOAD_VERSION) + set(RE2C_DOWNLOAD_VERSION 4.0.2) + endif() + set(RE2C_VERSION ${RE2C_DOWNLOAD_VERSION}) + + if(NOT TARGET RE2C::RE2C) + include(ExternalProject) + + # Configure re2c build. + if(RE2C_VERSION VERSION_GREATER_EQUAL 4) + set( + _re2cDownloadOptions + -DRE2C_BUILD_RE2D=OFF + -DRE2C_BUILD_RE2HS=OFF + -DRE2C_BUILD_RE2JAVA=OFF + -DRE2C_BUILD_RE2JS=OFF + -DRE2C_BUILD_RE2OCAML=OFF + -DRE2C_BUILD_RE2PY=OFF + -DRE2C_BUILD_RE2V=OFF + -DRE2C_BUILD_RE2ZIG=OFF + -DRE2C_BUILD_TESTS=OFF + ) + else() + set( + _re2cDownloadOptions + -DCMAKE_DISABLE_FIND_PACKAGE_Python3=TRUE + -DPython3_VERSION=3.7 + ) + endif() + ExternalProject_Add( + re2c + URL + https://github.com/skvadrik/re2c/archive/refs/tags/${RE2C_VERSION}.tar.gz + CMAKE_ARGS + -DRE2C_BUILD_RE2GO=OFF + -DRE2C_BUILD_RE2RUST=OFF + ${_re2cDownloadOptions} + INSTALL_COMMAND "" + ) + + # Set re2c executable. + ExternalProject_Get_property(re2c BINARY_DIR) + add_executable(RE2C::RE2C IMPORTED) + set_target_properties( + RE2C::RE2C + PROPERTIES IMPORTED_LOCATION ${BINARY_DIR}/re2c + ) + add_dependencies(RE2C::RE2C re2c) + set_property(CACHE RE2C_EXECUTABLE PROPERTY VALUE ${BINARY_DIR}/re2c) + unset(BINARY_DIR) + endif() - list(PREPEND _re2cRequiredVars _re2cMsg) + set(_re2cRequiredVars _re2cMsg) set(_re2cMsg "downloading at build") endif() find_package_handle_standard_args( RE2C - REQUIRED_VARS ${_re2cRequiredVars} + REQUIRED_VARS ${_re2cRequiredVars} RE2C_EXECUTABLE RE2C_VERSION VERSION_VAR RE2C_VERSION HANDLE_VERSION_RANGE REASON_FAILURE_MESSAGE "re2c not found. Please install re2c." ) +unset(_re2cDownloadOptions) unset(_re2cMsg) unset(_re2cRequiredVars) unset(_re2cTest) @@ -256,7 +601,7 @@ if(NOT RE2C_FOUND) endif() # Check for re2c --computed-gotos option. -if(RE2C_USE_COMPUTED_GOTOS) +if(NOT CMAKE_SCRIPT_MODE_FILE AND RE2C_USE_COMPUTED_GOTOS) message(CHECK_START "Checking for re2c --computed-gotos (-g) option support") cmake_push_check_state(RESET) @@ -280,130 +625,6 @@ if(RE2C_USE_COMPUTED_GOTOS) else() message(CHECK_FAIL "no") endif() +elseif(CMAKE_SCRIPT_MODE_FILE AND RE2C_USE_COMPUTED_GOTOS) + set(_RE2C_HAVE_COMPUTED_GOTOS TRUE) endif() - -function(re2c_target) - cmake_parse_arguments( - PARSE_ARGV - 3 - parsed # prefix - "NO_DEFAULT_OPTIONS;NO_COMPUTED_GOTOS;CODEGEN" # options - "HEADER" # one-value keywords - "OPTIONS;DEPENDS" # multi-value keywords - ) - - if(parsed_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Bad arguments: ${parsed_UNPARSED_ARGUMENTS}") - endif() - - if(parsed_KEYWORDS_MISSING_VALUES) - message(FATAL_ERROR "Missing values for: ${parsed_KEYWORDS_MISSING_VALUES}") - endif() - - set(options ${parsed_OPTIONS}) - - if( - RE2C_USE_COMPUTED_GOTOS - AND _RE2C_HAVE_COMPUTED_GOTOS - AND NOT parsed_NO_COMPUTED_GOTOS - ) - list(PREPEND options "--computed-gotos") - endif() - - if(RE2C_DEFAULT_OPTIONS AND NOT parsed_NO_DEFAULT_OPTIONS) - list(PREPEND options ${RE2C_DEFAULT_OPTIONS}) - endif() - - set(input ${ARGV1}) - if(NOT IS_ABSOLUTE "${input}") - set(input ${CMAKE_CURRENT_SOURCE_DIR}/${input}) - endif() - - set(output ${ARGV2}) - if(NOT IS_ABSOLUTE "${output}") - set(output ${CMAKE_CURRENT_BINARY_DIR}/${output}) - endif() - - set(outputs ${output}) - - if(parsed_HEADER) - set(header ${parsed_HEADER}) - if(NOT IS_ABSOLUTE "${header}") - set(header ${CMAKE_CURRENT_BINARY_DIR}/${header}) - endif() - - list(APPEND outputs ${header}) - - # When header option is used before re2c version 1.2, also the '-c' option - # is required. Before 1.1 '-c' long variant is '--start-conditions' and - # after 1.1 '--conditions'. - if(RE2C_VERSION VERSION_LESS_EQUAL 1.2) - list(APPEND options -c) - endif() - - # Since re2c version 3.0, '--header' is the new alias option for the - # '--type-header' option. - if(RE2C_VERSION VERSION_GREATER_EQUAL 3.0) - list(APPEND options --header ${header}) - else() - list(APPEND options --type-header ${header}) - endif() - endif() - - set(message "[RE2C][${ARGV0}] Generating lexer with re2c ${RE2C_VERSION}") - set(commands COMMAND ${RE2C_EXECUTABLE} ${options} --output ${output} ${input}) - - # RE2C cannot create output directories. Ensure any required directories - # for the generated files are created if they don't already exist. - set(directories "") - foreach(output IN LISTS outputs) - cmake_path(GET output PARENT_PATH dir) - if(dir) - list(APPEND directories ${dir}) - endif() - endforeach() - if(directories) - list(REMOVE_DUPLICATES directories) - list( - PREPEND - commands - COMMAND ${CMAKE_COMMAND} -E make_directory ${directories} - ) - endif() - - if(CMAKE_SCRIPT_MODE_FILE) - message(STATUS "${message}") - execute_process(${commands}) - return() - endif() - - set(codegen "") - if( - parsed_CODEGEN - AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 - AND POLICY CMP0171 - ) - cmake_policy(GET CMP0171 cmp0171) - - if(cmp0171 STREQUAL "NEW") - set(codegen CODEGEN) - endif() - endif() - - add_custom_command( - OUTPUT ${outputs} - ${commands} - DEPENDS ${input} ${parsed_DEPENDS} $ - COMMENT "${message}" - VERBATIM - COMMAND_EXPAND_LISTS - ${codegen} - ) - - add_custom_target( - ${ARGV0} - SOURCES ${input} - DEPENDS ${outputs} - COMMENT "[RE2C] Building lexer with re2c ${RE2C_VERSION}" - ) -endfunction() diff --git a/cmake/cmake/modules/PHP/BISON.cmake b/cmake/cmake/modules/PHP/BISON.cmake new file mode 100644 index 00000000..ef94f33b --- /dev/null +++ b/cmake/cmake/modules/PHP/BISON.cmake @@ -0,0 +1,76 @@ +#[=============================================================================[ +# PHP/BISON + +Wrapper module for using `bison`. + +* `PHP_BISON_OPTIONAL` + + Set to `TRUE` if `bison` is optional and generated parser file is shipped with + the release archive, for example. + +## Basic usage + +```cmake +# CMakeLists.txt + +# Check if bison is required. PHP tarball packaged and released at php.net +# already contains generated lexer and parser files. In such cases these don't +# need to be generated again. When building from a Git repository, bison and +# re2c are required to be installed so files can be generated as part of the +# build process. +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c) + set(PHP_BISON_OPTIONAL TRUE) +endif() +include(PHP/BISON) + +php_bison( + php_ext_json_parser + json_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c + COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" + VERBOSE REPORT_FILE json_parser.tab.output + DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h +) +``` +#]=============================================================================] + +include(FeatureSummary) + +# Minimum required bison version. +set(PHP_BISON_MIN_VERSION 3.0.0) + +# Add Bison options based on the build type. +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.32) + # See: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9921 + set(PHP_BISON_DEFAULT_OPTIONS "-Wall $<$:-l>") +else() + set(PHP_BISON_DEFAULT_OPTIONS "$,-lWall,-Wall>") +endif() + +if(CMAKE_SCRIPT_MODE_FILE) + set(PHP_BISON_DEFAULT_OPTIONS "-l -Wall") +endif() + +find_package(BISON ${PHP_BISON_MIN_VERSION} GLOBAL) + +block() + set(type "") + if(NOT PHP_BISON_OPTIONAL) + set(type TYPE REQUIRED) + endif() + + set_package_properties( + BISON + PROPERTIES + ${type} + PURPOSE "Necessary to generate PHP parser files." + ) +endblock() + +macro(php_bison) + if(CMAKE_SCRIPT_MODE_FILE) + bison_execute(${ARGN}) + else() + bison_target(${ARGN}) + endif() +endmacro() diff --git a/cmake/cmake/modules/PHP/RE2C.cmake b/cmake/cmake/modules/PHP/RE2C.cmake new file mode 100644 index 00000000..51e77b16 --- /dev/null +++ b/cmake/cmake/modules/PHP/RE2C.cmake @@ -0,0 +1,75 @@ +#[=============================================================================[ +# PHP/RE2C + +Wrapper module for using `re2c`. It simplifies setting minimum required version +at one place and use the package in modular way across the PHP build system. + +* `PHP_RE2C_OPTIONAL` + + Set to `TRUE` if `re2c` is optional and generated lexer file is shipped with + the release archive, for example. + +## Basic usage + +```cmake +# CMakeLists.txt + +# Check if re2c is required. PHP tarball packaged and released at php.net +# already contains generated lexer and parser files. In such cases these don't +# need to be generated again. When building from a Git repository, bison and +# re2c are required to be installed so files can be generated as part of the +# build process. +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c) + set(PHP_RE2C_OPTIONAL TRUE) +endif() + +# Include the module. +include(PHP/RE2C) + +php_re2c( + php_ext_json_scanner + json_scanner.re + ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h + OPTIONS -bc + CODEGEN +) +``` +#]=============================================================================] + +include(FeatureSummary) + +# Minimum required re2c version. +set(PHP_RE2C_MIN_VERSION 1.0.3) + +option(PHP_RE2C_CGOTO "Enable computed goto GCC extension with re2c") +mark_as_advanced(PHP_RE2C_CGOTO) + +if(PHP_RE2C_CGOTO) + set(RE2C_USE_COMPUTED_GOTOS TRUE) +endif() + +# Add --no-debug-info (-i) option to not output line directives. +if(CMAKE_SCRIPT_MODE_FILE) + set(RE2C_DEFAULT_OPTIONS --no-debug-info) +else() + set(RE2C_DEFAULT_OPTIONS $<$:--no-debug-info>) +endif() + +list( + APPEND RE2C_DEFAULT_OPTIONS + --no-generation-date # Suppress date output in the generated file. +) + +set(RE2C_NAMESPACE "php_") + +find_package(RE2C ${PHP_RE2C_MIN_VERSION} GLOBAL) + +block() + set(type "") + if(NOT PHP_RE2C_OPTIONAL) + set(type TYPE REQUIRED) + endif() + + set_package_properties(RE2C PROPERTIES ${type}) +endblock() diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake new file mode 100755 index 00000000..6f58ff84 --- /dev/null +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -0,0 +1,72 @@ +#!/usr/bin/env -S cmake -P +# +# CMake-based command-line script to generate the parser files using bison and +# lexer files using bison. +# +# Run as: +# +# cmake -P cmake/scripts/GenerateLexersParsers.cmake +# +# bison and re2c executables can be also manually overridden: +# +# [BISON_EXECUTABLE=path/to/bison] \ +# [RE2C_EXECUTABLE=path/to/re2c] \ +# cmake -P cmake/scripts/GenerateLexersParsers.cmake +# +# TODO: Fix CS and fine tune this. +# +# TODO: Should the Bison-generated report files (*.output) really be also +# created by this script (the `VERBOSE REPORT_FILE ` options)? PHP still +# packages these reports also in the archive release files?! Also, ext/json +# doesn't produce the *.output file. +# +# TODO: Add remaining missing features to FindBISON.cmake module. + +cmake_minimum_required(VERSION 3.25...3.31) + +if(NOT CMAKE_SCRIPT_MODE_FILE) + message(FATAL_ERROR "This is a command-line script.") +endif() + +set(PHP_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) + +if(NOT EXISTS ${PHP_SOURCE_DIR}/main/php_version.h) + message(FATAL_ERROR "This script should be run inside the php-src repository") +endif() + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../modules) + +include(PHP/BISON) +include(PHP/RE2C) + +include(FeatureSummary) +feature_summary( + FATAL_ON_MISSING_REQUIRED_PACKAGES + WHAT REQUIRED_PACKAGES_NOT_FOUND + QUIET_ON_EMPTY + DEFAULT_DESCRIPTION +) + +set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/ext/json) +set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/ext/json) +include(${PHP_SOURCE_DIR}/ext/json/cmake/GenerateGrammar.cmake) + +set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/ext/pdo) +set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/ext/pdo) +include(${PHP_SOURCE_DIR}/ext/pdo/cmake/GenerateGrammar.cmake) + +set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/ext/phar) +set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/ext/phar) +include(${PHP_SOURCE_DIR}/ext/phar/cmake/GenerateGrammar.cmake) + +set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/ext/standard) +set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/ext/standard) +include(${PHP_SOURCE_DIR}/ext/standard/cmake/GenerateGrammar.cmake) + +set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/sapi/phpdbg) +set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/sapi/phpdbg) +include(${PHP_SOURCE_DIR}/sapi/phpdbg/cmake/GenerateGrammar.cmake) + +set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/Zend) +set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/Zend) +include(${PHP_SOURCE_DIR}/Zend/cmake/GenerateGrammar.cmake) diff --git a/cmake/cmake/scripts/GenerateLexersParsers.cmake b/cmake/cmake/scripts/GenerateLexersParsers.cmake deleted file mode 100755 index 34459485..00000000 --- a/cmake/cmake/scripts/GenerateLexersParsers.cmake +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env -S cmake -P -# -# Command-line script to generate the lexer and parser files using re2c and -# bison. -# -# Run as: -# -# ```sh -# [RE2C_EXECUTABLE=path/to/re2c] cmake -P cmake/scripts/GenerateLexersParsers.cmake` -# ``` -# -# re2c and bison options must be manually synced with those used in the -# CMakeLists.txt files. -# -# TODO 1: Should the Bison-generated report files (*.output) really be also -# created by this script (the `VERBOSE REPORT_FILE ` options)? PHP still -# packages these reports also in the archive release files?! -# -# TODO 2: Add patching for Zend/zend_language_parser.{h,c} files -# -# TODO 3: Use Configuration.cmake for versions and default flags. -# -# TODO 4: Add remaining missing features to FindBISON.cmake module. - -cmake_minimum_required(VERSION 3.25...3.31) - -if(NOT CMAKE_SCRIPT_MODE_FILE) - message(FATAL_ERROR "This is a command-line script.") -endif() - -set(PHP_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../) - -if(NOT EXISTS ${PHP_SOURCE_DIR}/main/php_version.h) - message(FATAL_ERROR "This script should be run inside the php-src repository") -endif() - -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../modules) - -include(${CMAKE_CURRENT_LIST_DIR}/../Configuration.cmake) - -set( - RE2C_DEFAULT_OPTIONS - --no-generation-date # Suppress date output in the generated file. - -i # Do not output line directives. -) - -set(RE2C_DISABLE_DOWNLOAD TRUE) - -find_package(BISON 3.0.0 REQUIRED) -find_package(RE2C 1.0.3 REQUIRED) - -# ext/json -bison_generate( - php_ext_json_parser - ${PHP_SOURCE_DIR}/ext/json/json_parser.y - ${PHP_SOURCE_DIR}/ext/json/json_parser.tab.c - COMPILE_OPTIONS -Wall -l - VERBOSE REPORT_FILE ${PHP_SOURCE_DIR}/ext/json/json_parser.tab.output - DEFINES_FILE ${PHP_SOURCE_DIR}/ext/json/json_parser.tab.h -) -re2c_target( - php_ext_json_scanner - ${PHP_SOURCE_DIR}/ext/json/json_scanner.re - ${PHP_SOURCE_DIR}/ext/json/json_scanner.c - HEADER ${PHP_SOURCE_DIR}/ext/json/php_json_scanner_defs.h - OPTIONS -bc -) - -# ext/pdo -re2c_target( - php_ext_pdo_sql_parser - ${PHP_SOURCE_DIR}/ext/pdo/pdo_sql_parser.re - ${PHP_SOURCE_DIR}/ext/pdo/pdo_sql_parser.c -) - -# ext/phar -re2c_target( - php_ext_phar_path_check - ${PHP_SOURCE_DIR}/ext/phar/phar_path_check.re - ${PHP_SOURCE_DIR}/ext/phar/phar_path_check.c - OPTIONS -b -) - -# ext/standard -re2c_target( - php_ext_standard_var_unserializer - ${PHP_SOURCE_DIR}/ext/standard/var_unserializer.re - ${PHP_SOURCE_DIR}/ext/standard/var_unserializer.c - OPTIONS -b -) -re2c_target( - php_ext_standard_url_scanner_ex - ${PHP_SOURCE_DIR}/ext/standard/url_scanner_ex.re - ${PHP_SOURCE_DIR}/ext/standard/url_scanner_ex.c - OPTIONS -b -) - -# sapi/phpdbg -bison_generate( - php_sapi_phpdbg_parser - ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.y - ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.c - COMPILE_OPTIONS -Wall -l - VERBOSE REPORT_FILE ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.output - DEFINES_FILE ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_parser.h -) -re2c_target( - php_sapi_phpdbg_lexer - ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_lexer.l - ${PHP_SOURCE_DIR}/sapi/phpdbg/phpdbg_lexer.c - OPTIONS -cbdF -) - -# Zend -bison_generate( - zend_ini_parser - ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.y - ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.c - COMPILE_OPTIONS -Wall -l - VERBOSE REPORT_FILE ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.output - DEFINES_FILE ${PHP_SOURCE_DIR}/Zend/zend_ini_parser.h -) -# TODO: Also patch the file here: -bison_generate( - zend_language_parser - ${PHP_SOURCE_DIR}/Zend/zend_language_parser.y - ${PHP_SOURCE_DIR}/Zend/zend_language_parser.c - COMPILE_OPTIONS -Wall -l - VERBOSE REPORT_FILE ${PHP_SOURCE_DIR}/Zend/zend_language_parser.output - DEFINES_FILE ${PHP_SOURCE_DIR}/Zend/zend_language_parser.h -) -re2c_target( - zend_language_scanner - ${PHP_SOURCE_DIR}/Zend/zend_language_scanner.l - ${PHP_SOURCE_DIR}/Zend/zend_language_scanner.c - HEADER ${PHP_SOURCE_DIR}/Zend/zend_language_scanner_defs.h - OPTIONS --case-inverted -cbdF -) -re2c_target( - zend_ini_scanner - ${PHP_SOURCE_DIR}/Zend/zend_ini_scanner.l - ${PHP_SOURCE_DIR}/Zend/zend_ini_scanner.c - HEADER ${PHP_SOURCE_DIR}/Zend/zend_ini_scanner_defs.h - OPTIONS --case-inverted -cbdF -) diff --git a/cmake/ext/json/CMakeLists.txt b/cmake/ext/json/CMakeLists.txt index 8201e10a..90066df6 100644 --- a/cmake/ext/json/CMakeLists.txt +++ b/cmake/ext/json/CMakeLists.txt @@ -40,27 +40,11 @@ target_sources( target_compile_definitions(php_ext_json PRIVATE ZEND_ENABLE_STATIC_TSRMLS_CACHE) -if(BISON_FOUND) - bison_target( - php_ext_json_parser - json_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c - COMPILE_FLAGS "${PHP_DEFAULT_BISON_FLAGS}" - VERBOSE REPORT_FILE json_parser.tab.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h - ) -endif() +################################################################################ +# Generate lexer and parser files. +################################################################################ -if(RE2C_FOUND) - re2c_target( - php_ext_json_scanner - json_scanner.re - ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h - OPTIONS -bc - CODEGEN - ) -endif() +include(cmake/GenerateGrammar.cmake) if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") set(HAVE_JSON TRUE) diff --git a/cmake/ext/json/cmake/GenerateGrammar.cmake b/cmake/ext/json/cmake/GenerateGrammar.cmake new file mode 100644 index 00000000..b47515a7 --- /dev/null +++ b/cmake/ext/json/cmake/GenerateGrammar.cmake @@ -0,0 +1,37 @@ +# Generate lexer and parser files. + +if( + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h +) + set(PHP_BISON_OPTIONAL TRUE) +endif() + +include(PHP/BISON) + +php_bison( + php_ext_json_parser + json_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c + COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" + VERBOSE REPORT_FILE json_parser.tab.output + DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h +) + +if( + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h +) + set(PHP_RE2C_OPTIONAL TRUE) +endif() + +include(PHP/RE2C) + +php_re2c( + php_ext_json_scanner + json_scanner.re + ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h + OPTIONS -bc + CODEGEN +) diff --git a/cmake/ext/pdo/CMakeLists.txt b/cmake/ext/pdo/CMakeLists.txt index e3273429..671d9102 100644 --- a/cmake/ext/pdo/CMakeLists.txt +++ b/cmake/ext/pdo/CMakeLists.txt @@ -75,11 +75,8 @@ target_sources( add_dependencies(php_ext_pdo php_ext_spl) -if(RE2C_FOUND) - re2c_target( - php_ext_pdo_sql_parser - pdo_sql_parser.re - ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c - CODEGEN - ) -endif() +################################################################################ +# Generate lexer. +################################################################################ + +include(cmake/GenerateGrammar.cmake) diff --git a/cmake/ext/pdo/cmake/GenerateGrammar.cmake b/cmake/ext/pdo/cmake/GenerateGrammar.cmake new file mode 100644 index 00000000..e548bcb7 --- /dev/null +++ b/cmake/ext/pdo/cmake/GenerateGrammar.cmake @@ -0,0 +1,14 @@ +# Generate lexer. + +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c) + set(PHP_RE2C_OPTIONAL TRUE) +endif() + +include(PHP/RE2C) + +php_re2c( + php_ext_pdo_sql_parser + pdo_sql_parser.re + ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c + CODEGEN +) diff --git a/cmake/ext/phar/CMakeLists.txt b/cmake/ext/phar/CMakeLists.txt index ba81e286..30235e08 100644 --- a/cmake/ext/phar/CMakeLists.txt +++ b/cmake/ext/phar/CMakeLists.txt @@ -88,15 +88,11 @@ target_link_options( add_dependencies(php_ext_phar php_ext_hash php_ext_spl) -if(RE2C_FOUND) - re2c_target( - php_ext_phar_path_check - phar_path_check.re - ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c - OPTIONS -b - CODEGEN - ) -endif() +################################################################################ +# Generate lexer files. +################################################################################ + +include(cmake/GenerateGrammar.cmake) ################################################################################ # Man documentation. diff --git a/cmake/ext/phar/cmake/GenerateGrammar.cmake b/cmake/ext/phar/cmake/GenerateGrammar.cmake new file mode 100644 index 00000000..d6cad28b --- /dev/null +++ b/cmake/ext/phar/cmake/GenerateGrammar.cmake @@ -0,0 +1,15 @@ +# Generate lexer. + +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c) + set(PHP_RE2C_OPTIONAL TRUE) +endif() + +include(PHP/RE2C) + +php_re2c( + php_ext_phar_path_check + phar_path_check.re + ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c + OPTIONS -b + CODEGEN +) diff --git a/cmake/ext/standard/CMakeLists.txt b/cmake/ext/standard/CMakeLists.txt index 411e3e0f..792e65d5 100644 --- a/cmake/ext/standard/CMakeLists.txt +++ b/cmake/ext/standard/CMakeLists.txt @@ -226,26 +226,10 @@ target_link_libraries( ) ################################################################################ -# Generate lexers. +# Generate lexer files. ################################################################################ -if(RE2C_FOUND) - re2c_target( - php_ext_standard_var_unserializer - var_unserializer.re - ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c - OPTIONS -b - CODEGEN - ) - - re2c_target( - php_ext_standard_url_scanner_ex - url_scanner_ex.re - ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c - OPTIONS -b - CODEGEN - ) -endif() +include(cmake/GenerateGrammar.cmake) ################################################################################ # Add Argon2. diff --git a/cmake/ext/standard/cmake/GenerateGrammar.cmake b/cmake/ext/standard/cmake/GenerateGrammar.cmake new file mode 100644 index 00000000..07c19b78 --- /dev/null +++ b/cmake/ext/standard/cmake/GenerateGrammar.cmake @@ -0,0 +1,26 @@ +# Generate lexers. + +if( + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c +) + set(PHP_RE2C_OPTIONAL TRUE) +endif() + +include(PHP/RE2C) + +php_re2c( + php_ext_standard_url_scanner_ex + url_scanner_ex.re + ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c + OPTIONS -b + CODEGEN +) + +php_re2c( + php_ext_standard_var_unserializer + var_unserializer.re + ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c + OPTIONS -b + CODEGEN +) diff --git a/cmake/sapi/phpdbg/CMakeLists.txt b/cmake/sapi/phpdbg/CMakeLists.txt index d77b802c..7dbb63d1 100644 --- a/cmake/sapi/phpdbg/CMakeLists.txt +++ b/cmake/sapi/phpdbg/CMakeLists.txt @@ -245,26 +245,7 @@ endif() # Generate lexers and parsers. ################################################################################ -if(BISON_FOUND) - bison_target( - php_sapi_phpdbg_parser - phpdbg_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c - COMPILE_FLAGS "${PHP_DEFAULT_BISON_FLAGS}" - VERBOSE REPORT_FILE phpdbg_parser.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.h - ) -endif() - -if(RE2C_FOUND) - re2c_target( - php_sapi_phpdbg_lexer - phpdbg_lexer.l - ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c - OPTIONS -cbdF - CODEGEN - ) -endif() +include(cmake/GenerateGrammar.cmake) ################################################################################ # Configuration checks. diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake new file mode 100644 index 00000000..568b0381 --- /dev/null +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -0,0 +1,33 @@ +# Generate lexers and parsers. + +if( + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.h +) + set(PHP_BISON_OPTIONAL TRUE) +endif() +include(PHP/BISON) + +if(BISON_FOUND) + php_bison( + php_sapi_phpdbg_parser + phpdbg_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c + COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" + VERBOSE REPORT_FILE phpdbg_parser.output + DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.h + ) +endif() + +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c) + set(PHP_RE2C_OPTIONAL TRUE) +endif() +include(PHP/RE2C) + +php_re2c( + php_sapi_phpdbg_lexer + phpdbg_lexer.l + ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c + OPTIONS -cbdF + CODEGEN +) From b18e76716da098b543e71c5328f99d8dbac8404a Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Fri, 27 Dec 2024 00:30:09 +0100 Subject: [PATCH 05/15] Add working directories and refactor bison usages --- cmake/Zend/cmake/GenerateGrammar.cmake | 146 +++++++++--------- cmake/cmake/modules/FindBISON.cmake | 5 +- cmake/cmake/modules/FindRE2C.cmake | 5 +- cmake/cmake/modules/PHP/BISON.cmake | 10 +- cmake/cmake/scripts/GenerateGrammar.cmake | 9 +- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 18 +-- 6 files changed, 98 insertions(+), 95 deletions(-) diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake index c4427c69..27d07cda 100644 --- a/cmake/Zend/cmake/GenerateGrammar.cmake +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -12,85 +12,83 @@ if( endif() include(PHP/BISON) -if(BISON_FOUND) - php_bison( - zend_ini_parser - zend_ini_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c - COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" - VERBOSE REPORT_FILE zend_ini_parser.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h - ) +php_bison( + zend_ini_parser + zend_ini_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c + COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" + VERBOSE REPORT_FILE zend_ini_parser.output + DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h +) - php_bison( - zend_language_parser - zend_language_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c - COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" - VERBOSE REPORT_FILE zend_language_parser.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h - ) +php_bison( + zend_language_parser + zend_language_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c + COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" + VERBOSE REPORT_FILE zend_language_parser.output + DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h +) - # Tweak zendparse to be exported through ZEND_API. This has to be revisited - # once bison supports foreign skeletons and that bison version is used. Read - # https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more. - block() +# Tweak zendparse to be exported through ZEND_API. This has to be revisited +# once bison supports foreign skeletons and that bison version is used. Read +# https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more. +block() + string( + CONCAT patch + "set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})\n" + [[ + file(READ "${SOURCE_DIR}/zend_language_parser.h" content) string( - CONCAT patch - "set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})\n" - [[ - file(READ "${SOURCE_DIR}/zend_language_parser.h" content) - string( - REPLACE - "int zendparse" - "ZEND_API int zendparse" - content_2 - "${content}" - ) - if( - NOT content MATCHES "ZEND_API int zendparse" - AND NOT content STREQUAL "${content_2}" - ) - message(STATUS "[Zend] Patching zend_language_parser.h") - file(WRITE "${SOURCE_DIR}/zend_language_parser.h" "${content_2}") - endif() - - file(READ "${SOURCE_DIR}/zend_language_parser.c" content) - string( - REPLACE - "int zendparse" - "ZEND_API int zendparse" - content_2 - "${content}" - ) - if( - NOT content MATCHES "ZEND_API int zendparse" - AND NOT content STREQUAL "${content_2}" - ) - message(STATUS "[Zend] Patching zend_language_parser.c") - file(WRITE "${SOURCE_DIR}/zend_language_parser.c" "${content_2}") - endif() - ]]) + REPLACE + "int zendparse" + "ZEND_API int zendparse" + content_2 + "${content}" + ) + if( + NOT content MATCHES "ZEND_API int zendparse" + AND NOT content STREQUAL "${content_2}" + ) + message(STATUS "[Zend] Patching zend_language_parser.h") + file(WRITE "${SOURCE_DIR}/zend_language_parser.h" "${content_2}") + endif() - # Run patch based on whether building or running inside a CMake script. - if(CMAKE_SCRIPT_MODE_FILE) - cmake_language(EVAL CODE "${patch}") - else() - file( - GENERATE - OUTPUT CMakeFiles/PatchLanguageParser.cmake - CONTENT "${patch}" - ) - add_custom_target( - zend_patch_language_parser - COMMAND ${CMAKE_COMMAND} -P CMakeFiles/PatchLanguageParser.cmake - DEPENDS ${BISON_zend_language_parser_OUTPUTS} - VERBATIM - ) - add_dependencies(zend zend_patch_language_parser) + file(READ "${SOURCE_DIR}/zend_language_parser.c" content) + string( + REPLACE + "int zendparse" + "ZEND_API int zendparse" + content_2 + "${content}" + ) + if( + NOT content MATCHES "ZEND_API int zendparse" + AND NOT content STREQUAL "${content_2}" + ) + message(STATUS "[Zend] Patching zend_language_parser.c") + file(WRITE "${SOURCE_DIR}/zend_language_parser.c" "${content_2}") endif() - endblock() -endif() + ]]) + + # Run patch based on whether building or running inside a CMake script. + if(CMAKE_SCRIPT_MODE_FILE) + cmake_language(EVAL CODE "${patch}") + else() + file( + GENERATE + OUTPUT CMakeFiles/PatchLanguageParser.cmake + CONTENT "${patch}" + ) + add_custom_target( + zend_patch_language_parser + COMMAND ${CMAKE_COMMAND} -P CMakeFiles/PatchLanguageParser.cmake + DEPENDS ${BISON_zend_language_parser_OUTPUTS} + VERBATIM + ) + add_dependencies(zend zend_patch_language_parser) + endif() +endblock() if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake index cf0c3154..f733b18d 100644 --- a/cmake/cmake/modules/FindBISON.cmake +++ b/cmake/cmake/modules/FindBISON.cmake @@ -100,5 +100,8 @@ function(bison_execute) "[BISON][${ARGV0}] Generating parser with bison ${BISON_VERSION}" ) - execute_process(${commands}) + execute_process( + ${commands} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) endfunction() diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index abc8ce8d..dca4449a 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -375,7 +375,7 @@ function(${RE2C_NAMESPACE}re2c) if(CMAKE_SCRIPT_MODE_FILE) message(STATUS "[RE2C] ${message}") - execute_process(${commands}) + execute_process(${commands} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) return() endif() @@ -400,6 +400,7 @@ function(${RE2C_NAMESPACE}re2c) VERBATIM COMMAND_EXPAND_LISTS ${codegen} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) endfunction() @@ -423,7 +424,7 @@ function(${RE2C_NAMESPACE}re2c_execute) endif() message(STATUS "[RE2C] ${message}") - execute_process(${commands}) + execute_process(${commands} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endfunction() ################################################################################ diff --git a/cmake/cmake/modules/PHP/BISON.cmake b/cmake/cmake/modules/PHP/BISON.cmake index ef94f33b..7c7181dd 100644 --- a/cmake/cmake/modules/PHP/BISON.cmake +++ b/cmake/cmake/modules/PHP/BISON.cmake @@ -68,9 +68,11 @@ block() endblock() macro(php_bison) - if(CMAKE_SCRIPT_MODE_FILE) - bison_execute(${ARGN}) - else() - bison_target(${ARGN}) + if(BISON_FOUND) + if(CMAKE_SCRIPT_MODE_FILE) + bison_execute(${ARGN}) + else() + bison_target(${ARGN}) + endif() endif() endmacro() diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake index 6f58ff84..5e6cc900 100755 --- a/cmake/cmake/scripts/GenerateGrammar.cmake +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -7,11 +7,12 @@ # # cmake -P cmake/scripts/GenerateLexersParsers.cmake # -# bison and re2c executables can be also manually overridden: +# To manually override bison and re2c executables: # -# [BISON_EXECUTABLE=path/to/bison] \ -# [RE2C_EXECUTABLE=path/to/re2c] \ -# cmake -P cmake/scripts/GenerateLexersParsers.cmake +# cmake \ +# [-D BISON_EXECUTABLE=path/to/bison] \ +# [-D RE2C_EXECUTABLE=path/to/re2c] \ +# -P cmake/scripts/GenerateLexersParsers.cmake # # TODO: Fix CS and fine tune this. # diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake index 568b0381..11120972 100644 --- a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -8,16 +8,14 @@ if( endif() include(PHP/BISON) -if(BISON_FOUND) - php_bison( - php_sapi_phpdbg_parser - phpdbg_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c - COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" - VERBOSE REPORT_FILE phpdbg_parser.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.h - ) -endif() +php_bison( + php_sapi_phpdbg_parser + phpdbg_parser.y + phpdbg_parser.c + COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" + VERBOSE REPORT_FILE phpdbg_parser.output + DEFINES_FILE phpdbg_parser.h +) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c) set(PHP_RE2C_OPTIONAL TRUE) From bcbffc9df50300de7f2f2bacd9046e642f098dcc Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Fri, 27 Dec 2024 20:15:37 +0100 Subject: [PATCH 06/15] Fine tune and fix some CS --- cmake/Zend/CMakeLists.txt | 2 +- cmake/Zend/cmake/GenerateGrammar.cmake | 4 +- cmake/cmake/modules/FindRE2C.cmake | 2 +- cmake/cmake/scripts/GenerateGrammar.cmake | 46 +++++++------------ .../ext/standard/cmake/GenerateGrammar.cmake | 2 +- cmake/sapi/phpdbg/CMakeLists.txt | 2 +- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 2 +- 7 files changed, 23 insertions(+), 37 deletions(-) diff --git a/cmake/Zend/CMakeLists.txt b/cmake/Zend/CMakeLists.txt index da03e21b..c4b18ce7 100644 --- a/cmake/Zend/CMakeLists.txt +++ b/cmake/Zend/CMakeLists.txt @@ -523,7 +523,7 @@ if(TARGET Zend::MaxExecutionTimers) endif() ################################################################################ -# Generate lexers and parsers. +# Generate lexer and parser files. ################################################################################ include(cmake/GenerateGrammar.cmake) diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake index 27d07cda..f832b2e5 100644 --- a/cmake/Zend/cmake/GenerateGrammar.cmake +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -1,6 +1,4 @@ -#[=============================================================================[ -Generate lexer and parser files for Zend Engine. -#]=============================================================================] +# Generate lexer and parser files. if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index dca4449a..a28bd072 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -26,7 +26,7 @@ These variables can be set before calling the `find_package(RE2C)`: * `RE2C_DEFAULT_OPTIONS` - A semicolon-separated list of default global re2c options to be prepended to `re2c(OPTIONS)` argument for all re2c invocations - when generating lexers. + when generating lexer files. * `RE2C_DISABLE_DOWNLOAD` - Set to `TRUE` to disable downloading and building RE2C package from source, when it is not found on the system or found version diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake index 5e6cc900..ffc05575 100755 --- a/cmake/cmake/scripts/GenerateGrammar.cmake +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -5,16 +5,14 @@ # # Run as: # -# cmake -P cmake/scripts/GenerateLexersParsers.cmake +# cmake -P cmake/scripts/GenerateGrammar.cmake # # To manually override bison and re2c executables: # # cmake \ # [-D BISON_EXECUTABLE=path/to/bison] \ # [-D RE2C_EXECUTABLE=path/to/re2c] \ -# -P cmake/scripts/GenerateLexersParsers.cmake -# -# TODO: Fix CS and fine tune this. +# -P cmake/scripts/GenerateGrammar.cmake # # TODO: Should the Bison-generated report files (*.output) really be also # created by this script (the `VERBOSE REPORT_FILE ` options)? PHP still @@ -32,10 +30,10 @@ endif() set(PHP_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) if(NOT EXISTS ${PHP_SOURCE_DIR}/main/php_version.h) - message(FATAL_ERROR "This script should be run inside the php-src repository") + message(FATAL_ERROR "This script should be run in the php-src repository.") endif() -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../modules) +list(APPEND CMAKE_MODULE_PATH ${PHP_SOURCE_DIR}/cmake/modules) include(PHP/BISON) include(PHP/RE2C) @@ -48,26 +46,16 @@ feature_summary( DEFAULT_DESCRIPTION ) -set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/ext/json) -set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/ext/json) -include(${PHP_SOURCE_DIR}/ext/json/cmake/GenerateGrammar.cmake) - -set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/ext/pdo) -set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/ext/pdo) -include(${PHP_SOURCE_DIR}/ext/pdo/cmake/GenerateGrammar.cmake) - -set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/ext/phar) -set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/ext/phar) -include(${PHP_SOURCE_DIR}/ext/phar/cmake/GenerateGrammar.cmake) - -set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/ext/standard) -set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/ext/standard) -include(${PHP_SOURCE_DIR}/ext/standard/cmake/GenerateGrammar.cmake) - -set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/sapi/phpdbg) -set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/sapi/phpdbg) -include(${PHP_SOURCE_DIR}/sapi/phpdbg/cmake/GenerateGrammar.cmake) - -set(CMAKE_CURRENT_SOURCE_DIR ${PHP_SOURCE_DIR}/Zend) -set(CMAKE_CURRENT_BINARY_DIR ${PHP_SOURCE_DIR}/Zend) -include(${PHP_SOURCE_DIR}/Zend/cmake/GenerateGrammar.cmake) +file( + GLOB_RECURSE scripts + ${PHP_SOURCE_DIR}/ext/*/cmake/GenerateGrammar.cmake + ${PHP_SOURCE_DIR}/sapi/*/cmake/GenerateGrammar.cmake + ${PHP_SOURCE_DIR}/Zend/cmake/GenerateGrammar.cmake +) +foreach(script IN LISTS scripts) + cmake_path(GET script PARENT_PATH path) + cmake_path(GET path PARENT_PATH path) + set(CMAKE_CURRENT_SOURCE_DIR ${path}) + set(CMAKE_CURRENT_BINARY_DIR ${path}) + include(${script}) +endforeach() diff --git a/cmake/ext/standard/cmake/GenerateGrammar.cmake b/cmake/ext/standard/cmake/GenerateGrammar.cmake index 07c19b78..741d2fda 100644 --- a/cmake/ext/standard/cmake/GenerateGrammar.cmake +++ b/cmake/ext/standard/cmake/GenerateGrammar.cmake @@ -1,4 +1,4 @@ -# Generate lexers. +# Generate lexer files. if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c diff --git a/cmake/sapi/phpdbg/CMakeLists.txt b/cmake/sapi/phpdbg/CMakeLists.txt index 7dbb63d1..1395d4da 100644 --- a/cmake/sapi/phpdbg/CMakeLists.txt +++ b/cmake/sapi/phpdbg/CMakeLists.txt @@ -242,7 +242,7 @@ if(PHP_SAPI_PHPDBG_SHARED) endif() ################################################################################ -# Generate lexers and parsers. +# Generate lexer and parser files. ################################################################################ include(cmake/GenerateGrammar.cmake) diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake index 11120972..d67caec4 100644 --- a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -1,4 +1,4 @@ -# Generate lexers and parsers. +# Generate lexer and parser files. if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c From 207070173074b73708ade1ae401fe0620d5092e3 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Sat, 28 Dec 2024 11:08:41 +0100 Subject: [PATCH 07/15] Add customized FindBISON module --- cmake/Zend/cmake/GenerateGrammar.cmake | 198 ++++--- cmake/cmake/modules/FindBISON.cmake | 544 ++++++++++++++++-- cmake/cmake/modules/FindRE2C.cmake | 221 +++---- cmake/cmake/modules/PHP/BISON.cmake | 43 +- cmake/cmake/modules/PHP/RE2C.cmake | 19 +- cmake/cmake/scripts/GenerateGrammar.cmake | 7 +- cmake/ext/json/cmake/GenerateGrammar.cmake | 42 +- cmake/ext/pdo/cmake/GenerateGrammar.cmake | 14 +- cmake/ext/phar/cmake/GenerateGrammar.cmake | 16 +- .../ext/standard/cmake/GenerateGrammar.cmake | 30 +- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 55 +- 11 files changed, 806 insertions(+), 383 deletions(-) diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake index f832b2e5..5a26f142 100644 --- a/cmake/Zend/cmake/GenerateGrammar.cmake +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -10,83 +10,103 @@ if( endif() include(PHP/BISON) -php_bison( - zend_ini_parser - zend_ini_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c - COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" - VERBOSE REPORT_FILE zend_ini_parser.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h -) - -php_bison( - zend_language_parser - zend_language_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c - COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" - VERBOSE REPORT_FILE zend_language_parser.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h -) - -# Tweak zendparse to be exported through ZEND_API. This has to be revisited -# once bison supports foreign skeletons and that bison version is used. Read -# https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more. -block() - string( - CONCAT patch - "set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})\n" - [[ - file(READ "${SOURCE_DIR}/zend_language_parser.h" content) - string( - REPLACE - "int zendparse" - "ZEND_API int zendparse" - content_2 - "${content}" - ) - if( - NOT content MATCHES "ZEND_API int zendparse" - AND NOT content STREQUAL "${content_2}" - ) - message(STATUS "[Zend] Patching zend_language_parser.h") - file(WRITE "${SOURCE_DIR}/zend_language_parser.h" "${content_2}") - endif() +if(BISON_FOUND) + if(CMAKE_SCRIPT_MODE_FILE) + set(verbose "") + else() + set(verbose VERBOSE REPORT_FILE zend_ini_parser.output) + endif() - file(READ "${SOURCE_DIR}/zend_language_parser.c" content) - string( - REPLACE - "int zendparse" - "ZEND_API int zendparse" - content_2 - "${content}" - ) - if( - NOT content MATCHES "ZEND_API int zendparse" - AND NOT content STREQUAL "${content_2}" - ) - message(STATUS "[Zend] Patching zend_language_parser.c") - file(WRITE "${SOURCE_DIR}/zend_language_parser.c" "${content_2}") - endif() - ]]) + bison( + zend_ini_parser + zend_ini_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c + HEADER + #HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h + ${verbose} + ) - # Run patch based on whether building or running inside a CMake script. if(CMAKE_SCRIPT_MODE_FILE) - cmake_language(EVAL CODE "${patch}") + set(verbose "") else() - file( - GENERATE - OUTPUT CMakeFiles/PatchLanguageParser.cmake - CONTENT "${patch}" - ) - add_custom_target( - zend_patch_language_parser - COMMAND ${CMAKE_COMMAND} -P CMakeFiles/PatchLanguageParser.cmake - DEPENDS ${BISON_zend_language_parser_OUTPUTS} - VERBATIM - ) - add_dependencies(zend zend_patch_language_parser) + set(verbose VERBOSE REPORT_FILE zend_language_parser.output) endif() -endblock() + + bison( + zend_language_parser + zend_language_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c + HEADER + #HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h + ${verbose} + ) + + # Tweak zendparse to be exported through ZEND_API. This has to be revisited + # once bison supports foreign skeletons and that bison version is used. Read + # https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more. + block() + string( + CONCAT patch + "cmake_path(SET SOURCE_DIR NORMALIZE ${CMAKE_CURRENT_SOURCE_DIR})\n" + [[ + cmake_path( + RELATIVE_PATH + SOURCE_DIR + BASE_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE relativeDir + ) + file(READ "${SOURCE_DIR}/zend_language_parser.h" content) + string( + REPLACE + "int zendparse" + "ZEND_API int zendparse" + content_2 + "${content}" + ) + if( + NOT content MATCHES "ZEND_API int zendparse" + AND NOT content STREQUAL "${content_2}" + ) + message(STATUS "Patching ${relativeDir}/zend_language_parser.h") + file(WRITE "${SOURCE_DIR}/zend_language_parser.h" "${content_2}") + endif() + + file(READ "${SOURCE_DIR}/zend_language_parser.c" content) + string( + REPLACE + "int zendparse" + "ZEND_API int zendparse" + content_2 + "${content}" + ) + if( + NOT content MATCHES "ZEND_API int zendparse" + AND NOT content STREQUAL "${content_2}" + ) + message(STATUS "Patching ${relativeDir}/zend_language_parser.c") + file(WRITE "${SOURCE_DIR}/zend_language_parser.c" "${content_2}") + endif() + ]]) + + # Run patch based on whether building or running inside a CMake script. + if(CMAKE_SCRIPT_MODE_FILE) + cmake_language(EVAL CODE "${patch}") + else() + file( + GENERATE + OUTPUT CMakeFiles/PatchLanguageParser.cmake + CONTENT "${patch}" + ) + add_custom_target( + zend_language_parser_patch + COMMAND ${CMAKE_COMMAND} -P CMakeFiles/PatchLanguageParser.cmake + DEPENDS zend_language_parser + VERBATIM + ) + add_dependencies(zend zend_language_parser_patch) + endif() + endblock() +endif() if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c @@ -98,20 +118,22 @@ if( endif() include(PHP/RE2C) -php_re2c( - zend_ini_scanner - zend_ini_scanner.l - ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h - OPTIONS --case-inverted -cbdF - CODEGEN -) +if(RE2C_FOUND) + re2c( + zend_ini_scanner + zend_ini_scanner.l + ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h + OPTIONS --case-inverted -cbdF + CODEGEN + ) -php_re2c( - zend_language_scanner - zend_language_scanner.l - ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h - OPTIONS --case-inverted -cbdF - CODEGEN -) + re2c( + zend_language_scanner + zend_language_scanner.l + ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h + OPTIONS --case-inverted -cbdF + CODEGEN + ) +endif() diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake index f733b18d..d8f77df5 100644 --- a/cmake/cmake/modules/FindBISON.cmake +++ b/cmake/cmake/modules/FindBISON.cmake @@ -1,59 +1,231 @@ #[=============================================================================[ # FindBISON -Find the bison utility. +Find `bison` command-line parser generator. -See: https://cmake.org/cmake/help/latest/module/FindBISON.html +This is a standalone and customized find module for finding bison. It is synced +with CMake FindBISON module, where possible. +See also: https://cmake.org/cmake/help/latest/module/FindBISON.html -This module overrides the upstream CMake `FindBISON` module with few -customizations. +## Result variables -A new `bison_execute()` function is added to be able to use it in command-line -scripts. +* `BISON_FOUND` - Whether the `bison` was found. +* `BISON_VERSION` - The `bison` version. + +## Cache variables + +* `BISON_EXECUTABLE` - Path to the `bison`. + +## Hints + +These variables can be set before calling the `find_package(BISON)`: + +* `BISON_DEFAULT_OPTIONS` - A semicolon-separated list of default global bison + options to be prepended to `bison(OPTIONS)` argument for all bison invocations + when generating parser files. + +* `BISON_DISABLE_DOWNLOAD` - Set to `TRUE` to disable downloading and building + bison package from source, when it is not found on the system or found version + is not suitable. + +* `BISON_DOWNLOAD_VERSION` - Override the default `bison` version to be + downloaded when not found on the system. + +## Functions provided by this module + +### `bison()` + +Generate parser file `` from the given `` template file using the +`bison` parser generator. ```cmake -bison_execute( +bison( - [COMPILE_FLAGS ] - [DEFINES_FILE ] + [HEADER | HEADER_FILE
] + [OPTIONS ...] + [DEPENDS ...] [VERBOSE [REPORT_FILE ]] + [NO_DEFAULT_OPTIONS] + [CODEGEN] + [WORKING_DIRECTORY ] ) ``` + +This creates a custom CMake target `` and adds a custom command that +generates parser file `` from the given `` template file using +the `bison` parser generator. Relative source file path `` is interpreted +as being relative to the current source directory. Relative `` file path +is interpreted as being relative to the current binary directory. If `bison` is +not a required package and it is not found, it will create a custom target but +skip the `bison` command execution. + +When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it +simply generates the parser without creating a target, to make it easier to use +in various scenarios. + +#### Options + +* `HEADER` - Produce also a header file automatically. + +* `HEADER_FILE
` - Produce a header as a specified file `
`. + Relative header file path is interpreted as being relative to the current + binary directory. + +* `OPTIONS ...` - Optional list of additional options to pass to the + bison command-line tool. + +* `DEPENDS ...` - Optional list of dependent files to regenerate the + output file. + +* `NO_DEFAULT_OPTIONS` - If specified, the `BISON_DEFAULT_OPTIONS` are not added + to the current `bison` invocation. + +* `CODEGEN` - Adds the `CODEGEN` option to the bison's `add_custom_command()` + call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which + provides a global CMake `codegen` target for convenience to call only the + code-generation-related targets and skips the majority of the build: + + ```sh + cmake --build --target codegen + ``` + +* `WORKING_DIRECTORY ` - The path where the `bison` command + is executed. By default, `bison` is executed in the current binary directory + (`CMAKE_CURRENT_BINARY_DIR`). Relative `` path is + interpreted as being relative to the current binary directory. + +## Examples + +### Minimum bison version + +The minimum required `bison` version can be specified using the standard CMake +syntax, e.g. + +```cmake +# CMakeLists.txt + +find_package(BISON 3.0.0) +``` + +### Running bison + +```cmake +# CMakeLists.txt + +find_package(BISON) + +# Commands provided by find modules must be called conditionally, because user +# can also disable the find module with CMAKE_DISABLE_FIND_PACKAGE_BISON. +if(BISON_FOUND) + bison(...) +endif() +``` + +### Specifying options + +Setting default options for all `bison()` calls in the scope of the +`find_package(BISON)`: + +```cmake +# CMakeLists.txt + +# Optionally, set default options for all bison invocations. For example, add +# option to suppress date output in the generated file: +set(BISON_DEFAULT_OPTIONS -Wall --no-lines) + +find_package(BISON) + +# This will execute bison as: +# bison -Wall --no-lines -d foo.y --output foo.c +if(BISON_FOUND) + bison(foo foo.y foo.c OPTIONS -d) +endif() + +# This will execute bison as: +# bison -l bar.y --output bar.c +if(BISON_FOUND) + bison(bar bar.y bar.c OPTIONS -l) +endif() +``` + +Generator expressions are supported in `bison(OPTIONS)` when running it in the +`project()` mode: + +```cmake +# CMakeLists.txt + +find_package(BISON) + +if(BISON_FOUND) + bison(foo foo.y foo.c OPTIONS $<$:--no-lines>) +endif() +``` + +### Custom target usage + +To specify dependencies with the custom target created by `bison()`: + +```cmake +# CMakeLists.txt + +find_package(BISON) + +if(BISON_FOUND) + bison(foo_parser parser.y parser.c) + add_dependencies(some_target foo_parser) +endif() +``` + +Or to run only the specific `foo_parser` target, which generates the parser. + +```sh +cmake --build --target foo_parser +``` + +### Script mode + +When running `bison()` in script mode: + +```sh +cmake -P script.cmake +``` + +the generated file is created right away: + +```cmake +# script.cmake + +find_package(BISON REQUIRED) + +if(BISON_FOUND) + bison(parser.y parser.c) +endif() +``` #]=============================================================================] include(FeatureSummary) +include(FindPackageHandleStandardArgs) -set_package_properties( - BISON - PROPERTIES - URL "https://www.gnu.org/software/bison/" - DESCRIPTION "General-purpose parser generator" -) +################################################################################ +# Functions. +################################################################################ -# Find package with upstream CMake module; override CMAKE_MODULE_PATH to prevent -# the maximum nesting/recursion depth error on some systems, like macOS. -set(_php_cmake_module_path ${CMAKE_MODULE_PATH}) -unset(CMAKE_MODULE_PATH) -include(FindBISON) -set(CMAKE_MODULE_PATH ${_php_cmake_module_path}) -unset(_php_cmake_module_path) +# Process options. +function(_bison_process_options options result) + set(options ${${options}}) -if(NOT BISON_FOUND) - return() -endif() + if(BISON_DEFAULT_OPTIONS AND NOT parsed_NO_DEFAULT_OPTIONS) + list(PREPEND options ${BISON_DEFAULT_OPTIONS}) + endif() -function(bison_execute) - cmake_parse_arguments( - PARSE_ARGV - 3 - parsed # prefix - "VERBOSE" # options - "DEFINES_FILE;REPORT_FILE;COMPILE_FLAGS" # one-value keywords - "" # multi-value keywords - ) + set(${result} ${options}) + + return(PROPAGATE ${result}) +endfunction() +macro(_bison_process) if(parsed_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Bad arguments: ${parsed_UNPARSED_ARGUMENTS}") endif() @@ -66,42 +238,310 @@ function(bison_execute) if(NOT IS_ABSOLUTE "${input}") set(input ${CMAKE_CURRENT_SOURCE_DIR}/${input}) endif() + cmake_path(SET input NORMALIZE "${input}") set(output ${ARGV2}) if(NOT IS_ABSOLUTE "${output}") set(output ${CMAKE_CURRENT_BINARY_DIR}/${output}) endif() + cmake_path(SET output NORMALIZE "${output}") - separate_arguments(options NATIVE_COMMAND "${parsed_COMPILE_FLAGS}") + set(outputs ${output}) - if(parsed_DEFINES_FILE) - list(APPEND options --defines=${parsed_DEFINES_FILE}) - endif() + _bison_process_options(parsed_OPTIONS options) - if(parsed_VERBOSE) - list(APPEND options --verbose) - endif() + if(parsed_HEADER OR parsed_HEADER_FILE) + # Bison versions 3.8 and later introduced the --header=[FILE] (-H) option. + # For prior versions the --defines=[FILE] (-d) option can be used. + if(parsed_HEADER_FILE) + set(header ${parsed_HEADER_FILE}) + if(NOT IS_ABSOLUTE "${header}") + set(header ${CMAKE_CURRENT_BINARY_DIR}/${header}) + endif() + if(BISON_VERSION VERSION_LESS 3.8) + list(APPEND options --defines=${header}) + else() + list(APPEND options --header=${header}) + endif() + else() + if(BISON_VERSION VERSION_LESS 3.8) + list(APPEND options -d) + else() + list(APPEND options --header) + endif() + + # Produce default header path generated by bison (see option --header) + cmake_path(GET output EXTENSION LAST_ONLY extension) + string(REPLACE "c" "h" extension "${extension}") + if(NOT extension) + set(extension "h") + endif() + cmake_path( + REPLACE_EXTENSION + output + LAST_ONLY + "${extension}" + OUTPUT_VARIABLE header + ) + # TODO: Add path if header is relative. + endif() + + list(APPEND outputs ${header}) - if(parsed_REPORT_FILE AND NOT IS_ABSOLUTE "${parsed_REPORT_FILE}") - set(parsed_REPORT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${parsed_REPORT_FILE}) + if(parsed_VERBOSE) + list(APPEND options --verbose) + if(parsed_REPORT_FILE) + if(NOT IS_ABSOLUTE "${parsed_REPORT_FILE}") + set( + parsed_REPORT_FILE + ${CMAKE_CURRENT_BINARY_DIR}/${parsed_REPORT_FILE} + ) + endif() + list(APPEND options --report-file=${parsed_REPORT_FILE}) + endif() + endif() endif() - if(parsed_REPORT_FILE) - list(APPEND options --report-file=${parsed_REPORT_FILE}) + # Assemble commands for add_custom_command() and execute_process(). + set(commands "") + + # Bison cannot create output directories. Ensure any required directories for + # the generated files are created if they don't already exist. + set(directories "") + foreach(output IN LISTS outputs) + cmake_path(GET output PARENT_PATH dir) + if(dir) + list(APPEND directories ${dir}) + endif() + endforeach() + if(directories) + list(REMOVE_DUPLICATES directories) + list( + APPEND + commands + COMMAND ${CMAKE_COMMAND} -E make_directory ${directories} + ) endif() - set( + list( + APPEND commands - COMMAND ${BISON_EXECUTABLE} ${options} --output ${output} ${input} + COMMAND ${BISON_EXECUTABLE} ${options} ${input} --output ${output} + ) + + # Assemble status message. + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${CMAKE_BINARY_DIR} + OUTPUT_VARIABLE outputRelative + ) + + set(message "Generating ${outputRelative} with bison ${BISON_VERSION}") + + if(NOT parsed_WORKING_DIRECTORY) + set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + else() + if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") + set( + parsed_WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR}/${parsed_WORKING_DIRECTORY} + ) + endif() + endif() +endmacro() + +function(bison) + cmake_parse_arguments( + PARSE_ARGV + 3 + parsed # prefix + "NO_DEFAULT_OPTIONS;CODEGEN;VERBOSE;HEADER" # options + "HEADER_FILE;WORKING_DIRECTORY;REPORT_FILE" # one-value keywords + "OPTIONS;DEPENDS" # multi-value keywords ) - message( - STATUS - "[BISON][${ARGV0}] Generating parser with bison ${BISON_VERSION}" + _bison_process(${ARGN}) + + if(NOT CMAKE_SCRIPT_MODE_FILE) + add_custom_target(${ARGV0} SOURCES ${input} DEPENDS ${outputs}) + endif() + + # Skip generation, if generated files are provided by the release archive. + get_property(type GLOBAL PROPERTY _CMAKE_BISON_TYPE) + if(NOT BISON_FOUND AND NOT BISON_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") + return() + endif() + + if(CMAKE_SCRIPT_MODE_FILE) + message(STATUS "[BISON] ${message}") + execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) + return() + endif() + + set(codegen "") + if( + parsed_CODEGEN + AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 + AND POLICY CMP0171 ) + cmake_policy(GET CMP0171 cmp0171) + + if(cmp0171 STREQUAL "NEW") + set(codegen CODEGEN) + endif() + endif() - execute_process( + add_custom_command( + OUTPUT ${outputs} ${commands} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${input} ${parsed_DEPENDS} $ + COMMENT "[BISON][${ARGV0}] ${message}" + VERBATIM + COMMAND_EXPAND_LISTS + ${codegen} + WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} ) endfunction() + +################################################################################ +# Package definition. +################################################################################ + +block() + cmake_path( + RELATIVE_PATH + CMAKE_CURRENT_SOURCE_DIR + BASE_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE relativeDir + ) + + if(relativeDir STREQUAL ".") + set(purpose "Necessary to generate parser files.") + else() + set(purpose "Necessary to generate ${relativeDir} parser files.") + endif() + + set_package_properties( + BISON + PROPERTIES + URL "https://www.gnu.org/software/bison/" + DESCRIPTION "General-purpose parser generator" + PURPOSE "${purpose}" + ) +endblock() + +################################################################################ +# Find the executable. +################################################################################ + +find_program( + BISON_EXECUTABLE + NAMES bison + DOC "The bison executable path" +) +mark_as_advanced(BISON_EXECUTABLE) + +################################################################################ +# Version. +################################################################################ + +block(PROPAGATE BISON_VERSION _bisonVersionValid) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) + set(test IS_EXECUTABLE) + else() + set(test EXISTS) + endif() + + if(${test} ${BISON_EXECUTABLE}) + execute_process( + COMMAND ${BISON_EXECUTABLE} --version + OUTPUT_VARIABLE versionOutput + ERROR_VARIABLE error + RESULT_VARIABLE result + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if(NOT result EQUAL 0) + message( + SEND_ERROR + "Command \"${BISON_EXECUTABLE} --version\" failed with output:\n" + "${error}" + ) + elseif(versionOutput) + # Bison++ + if(vesionOutput MATCHES "^bison\\+\\+ Version ([^,]+)") + set(BISON_VERSION "${CMAKE_MATCH_1}") + # GNU Bison + elseif(versionOutput MATCHES "^bison \\(GNU Bison\\) ([^\n]+)\n") + set(BISON_VERSION "${CMAKE_MATCH_1}") + elseif(versionOutput MATCHES "^GNU Bison (version )?([^\n]+)") + set(BISON_VERSION "${CMAKE_MATCH_2}") + endif() + + find_package_check_version("${BISON_VERSION}" _bisonVersionValid) + endif() + endif() +endblock() + +set(_bisonRequiredVars "") + +################################################################################ +# Download and build the package. +################################################################################ + +if( + NOT CMAKE_SCRIPT_MODE_FILE + AND NOT BISON_DISABLE_DOWNLOAD + AND (NOT BISON_EXECUTABLE OR NOT _bisonVersionValid) +) + # Set which bison version to download. + if(NOT BISON_DOWNLOAD_VERSION) + set(BISON_DOWNLOAD_VERSION 3.8.2) + endif() + set(BISON_VERSION ${BISON_DOWNLOAD_VERSION}) + + if(NOT TARGET Bison::Bison) + include(ExternalProject) + + # Configure bison build. + set(_bisonDownloadOptions "") + + ExternalProject_Add( + bison + URL + # :( https://github.com/.../.../archive/refs/tags/${BISON_VERSION}.tar.gz + CMAKE_ARGS + -DBISON_TODO=OFF + ${_bisonDownloadOptions} + INSTALL_COMMAND "" + ) + + # Set bison executable. + ExternalProject_Get_property(bison BINARY_DIR) + add_executable(Bison::Bison IMPORTED) + set_target_properties( + Bison::Bison + PROPERTIES IMPORTED_LOCATION ${BINARY_DIR}/bison + ) + add_dependencies(Bison::Bison bison) + set_property(CACHE BISON_EXECUTABLE PROPERTY VALUE ${BINARY_DIR}/bison) + unset(BINARY_DIR) + endif() + + set(_bisonRequiredVars _bisonMsg) + set(_bisonMsg "downloading at build") +endif() + +find_package_handle_standard_args( + BISON + REQUIRED_VARS ${_bisonRequiredVars} BISON_EXECUTABLE BISON_VERSION + VERSION_VAR BISON_VERSION + HANDLE_VERSION_RANGE + REASON_FAILURE_MESSAGE "bison not found. Please install bison." +) + +unset(_bisonDownloadOptions) +unset(_bisonMsg) +unset(_bisonRequiredVars) +unset(_bisonVersionValid) diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index a28bd072..007655a2 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -35,9 +35,6 @@ These variables can be set before calling the `find_package(RE2C)`: * `RE2C_DOWNLOAD_VERSION` - Override the default `re2c` version to be downloaded when not found on the system. -* `RE2C_NAMESPACE` - Optional namespace prepended to `re2c` CMake function - names. - * `RE2C_USE_COMPUTED_GOTOS` - Set to `TRUE` to enable the re2c `--computed-gotos` (`-g`) option if the non-standard C `computed goto` extension is supported by the C compiler. When using it in command-line script @@ -62,6 +59,7 @@ re2c( [NO_DEFAULT_OPTIONS] [NO_COMPUTED_GOTOS] [CODEGEN] + [WORKING_DIRECTORY ] ) ``` @@ -103,36 +101,14 @@ in various scenarios. cmake --build --target codegen ``` -### `re2c_execute()` - -```cmake -re2c_execute( - - - [HEADER
] - [OPTIONS ...] - [NO_DEFAULT_OPTIONS] - [NO_COMPUTED_GOTOS] -) -``` - -This generates `` lexer file from the given `` template using the -`re2c` command-line lexer generator. Relative `` source file path is -interpreted as being relative to the current source directory. Relative -`` file path is interpreted as being relative to the current binary -directory. If `re2c` is not a required package and it is not found, it will skip -the lexer generation. - -This command can be used in scripts or if generated files need to be available -in the configuration phase immediately without creating a CMake target. - -#### Options - -Options available in `re2c_execute` behave the same as in the `re2c()`. +* `WORKING_DIRECTORY ` - The path where the `re2c` command is + executed. By default, `re2c` is executed in the current binary directory + (`CMAKE_CURRENT_BINARY_DIR`). Relative `` path is + interpreted as being relative to the current binary directory. ## Examples -### Basic usage +### Minimum re2c version The minimum required `re2c` version can be specified using the standard CMake syntax, e.g. @@ -143,9 +119,23 @@ syntax, e.g. find_package(RE2C 1.0.3) ``` +### Running re2c + +```cmake +# CMakeLists.txt + +find_package(RE2C) + +# Commands provided by find modules must be called conditionally, because user +# can also disable the find module with CMAKE_DISABLE_FIND_PACKAGE_RE2C. +if(RE2C_FOUND) + re2c(...) +endif() +``` + ### Specifying options -Setting default options for all `re2c()` calls in the scope of +Setting default options for all `re2c()` calls in the scope of the `find_package(RE2C)`: ```cmake @@ -159,21 +149,28 @@ find_package(RE2C) # This will execute re2c as: # re2c --no-generation-date --bit-vectors --conditions --output foo.c foo.re -re2c(foo foo.re foo.c OPTIONS --bit-vectors --conditions) +if(RE2C_FOUND) + re2c(foo foo.re foo.c OPTIONS --bit-vectors --conditions) +endif() # This will execute re2c as: # re2c --no-generation-date --case-inverted --output bar.c bar.re -re2c(bar bar.re bar.c OPTIONS --case-inverted) +if(RE2C_FOUND) + re2c(bar bar.re bar.c OPTIONS --case-inverted) +endif() ``` -Generator expressions are supported in `re2c(OPTIONS)`: +Generator expressions are supported in `re2c(OPTIONS)` when using it in the +`project()` mode: ```cmake # CMakeLists.txt find_package(RE2C) -re2c(foo foo.re foo.c OPTIONS $<$:--debug-output>) +if(RE2C_FOUND) + re2c(foo foo.re foo.c OPTIONS $<$:--debug-output>) +endif() ``` ### Custom target usage @@ -185,8 +182,10 @@ To specify dependencies with the custom target created by `re2c()`: find_package(RE2C) -re2c(foo_lexer lexer.re lexer.c) -add_dependencies(some_target foo_lexer) +if(RE2C_FOUND) + re2c(foo_lexer lexer.re lexer.c) + add_dependencies(some_target foo_lexer) +endif() ``` Or to run only the specific `foo_lexer` target, which generates the lexer. @@ -197,7 +196,7 @@ cmake --build --target foo_lexer ### Script mode -When running `re2c()`, for example, in script mode: +When running `re2c()` in script mode: ```sh cmake -P script.cmake @@ -210,19 +209,9 @@ the generated file is created right away: find_package(RE2C REQUIRED) -re2c(foo_lexer lexer.re lexer.c) -``` - -### Namespace - -Setting namespace isolates the function definitions to specific namespace in -case they can clash with some existing names. - -```cmake -set(RE2C_NAMESPACE "foo_") -find_package(RE2C REQUIRED) - -foo_re2c(foo_lexer lexer.re lexer.c) +if(RE2C_FOUND) + re2c(lexer.re lexer.c) +endif() ``` #]=============================================================================] @@ -235,12 +224,8 @@ include(FindPackageHandleStandardArgs) # Functions. ################################################################################ -if(NOT RE2C_NAMESPACE) - set(RE2C_NAMESPACE "") -endif() - # Process options. -function(_${RE2C_NAMESPACE}re2c_process_options options result) +function(_re2c_process_options options result) set(options ${${options}}) if( @@ -260,7 +245,7 @@ function(_${RE2C_NAMESPACE}re2c_process_options options result) return(PROPAGATE ${result}) endfunction() -macro(_${RE2C_NAMESPACE}re2c_process) +macro(_re2c_process) if(parsed_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Bad arguments: ${parsed_UNPARSED_ARGUMENTS}") endif() @@ -283,11 +268,7 @@ macro(_${RE2C_NAMESPACE}re2c_process) set(outputs ${output}) - cmake_language( - CALL _${RE2C_NAMESPACE}re2c_process_options - parsed_OPTIONS - options - ) + _re2c_process_options(parsed_OPTIONS options) if(parsed_HEADER) set(header ${parsed_HEADER}) @@ -349,19 +330,30 @@ macro(_${RE2C_NAMESPACE}re2c_process) ) set(message "Generating ${outputRelative} with re2c ${RE2C_VERSION}") + + if(NOT parsed_WORKING_DIRECTORY) + set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + else() + if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") + set( + parsed_WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR}/${parsed_WORKING_DIRECTORY} + ) + endif() + endif() endmacro() -function(${RE2C_NAMESPACE}re2c) +function(re2c) cmake_parse_arguments( PARSE_ARGV 3 parsed # prefix "NO_DEFAULT_OPTIONS;NO_COMPUTED_GOTOS;CODEGEN" # options - "HEADER" # one-value keywords + "HEADER;WORKING_DIRECTORY" # one-value keywords "OPTIONS;DEPENDS" # multi-value keywords ) - cmake_language(CALL _${RE2C_NAMESPACE}re2c_process ${ARGN}) + _re2c_process(${ARGN}) if(NOT CMAKE_SCRIPT_MODE_FILE) add_custom_target(${ARGV0} SOURCES ${input} DEPENDS ${outputs}) @@ -375,7 +367,7 @@ function(${RE2C_NAMESPACE}re2c) if(CMAKE_SCRIPT_MODE_FILE) message(STATUS "[RE2C] ${message}") - execute_process(${commands} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) return() endif() @@ -400,33 +392,10 @@ function(${RE2C_NAMESPACE}re2c) VERBATIM COMMAND_EXPAND_LISTS ${codegen} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} ) endfunction() -function(${RE2C_NAMESPACE}re2c_execute) - cmake_parse_arguments( - PARSE_ARGV - 2 - parsed # prefix - "NO_DEFAULT_OPTIONS;NO_COMPUTED_GOTOS" # options - "HEADER" # one-value keywords - "OPTIONS" # multi-value keywords - ) - - # First argument enables using the same macro signature for both functions. - cmake_language(CALL _${RE2C_NAMESPACE}re2c_process ${ARGN}) - - # Skip generation, if generated files are provided by the release archive. - get_property(type GLOBAL PROPERTY _CMAKE_RE2C_TYPE) - if(NOT RE2C_FOUND AND NOT RE2C_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") - return() - endif() - - message(STATUS "[RE2C] ${message}") - execute_process(${commands} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -endfunction() - ################################################################################ # Package definition. ################################################################################ @@ -465,53 +434,41 @@ find_program( ) mark_as_advanced(RE2C_EXECUTABLE) -if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) - set(_re2cTest IS_EXECUTABLE) -else() - set(_re2cTest EXISTS) -endif() - -if(${_re2cTest} ${RE2C_EXECUTABLE}) - execute_process( - COMMAND ${RE2C_EXECUTABLE} --vernum - OUTPUT_VARIABLE RE2C_VERSION_NUM - ERROR_VARIABLE _re2cVersionError - RESULT_VARIABLE _re2cVersionResult - OUTPUT_STRIP_TRAILING_WHITESPACE - ) +block(PROPAGATE RE2C_VERSION _re2cVersionValid) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) + set(test IS_EXECUTABLE) + else() + set(test EXISTS) + endif() - if(NOT _re2cVersionResult EQUAL 0) - message( - SEND_ERROR - "Command \"${RE2C_EXECUTABLE} --vernum\" failed with output:\n" - "${_re2cVersionError}" - ) - elseif(RE2C_VERSION_NUM) - math( - EXPR RE2C_VERSION_MAJOR - "${RE2C_VERSION_NUM} / 10000" + if(${test} ${RE2C_EXECUTABLE}) + execute_process( + COMMAND ${RE2C_EXECUTABLE} --vernum + OUTPUT_VARIABLE versionNumber + ERROR_VARIABLE error + RESULT_VARIABLE result + OUTPUT_STRIP_TRAILING_WHITESPACE ) - math( - EXPR RE2C_VERSION_MINOR - "(${RE2C_VERSION_NUM} - ${RE2C_VERSION_MAJOR} * 10000) / 100" - ) + if(NOT result EQUAL 0) + message( + SEND_ERROR + "Command \"${RE2C_EXECUTABLE} --vernum\" failed with output:\n" + "${error}" + ) + elseif(versionNumber) + math(EXPR major "${versionNumber} / 10000") - math( - EXPR RE2C_VERSION_PATCH - "${RE2C_VERSION_NUM} \ - - ${RE2C_VERSION_MAJOR} * 10000 \ - - ${RE2C_VERSION_MINOR} * 100" - ) + math(EXPR minor "(${versionNumber} - ${major} * 10000) / 100") - set( - RE2C_VERSION - "${RE2C_VERSION_MAJOR}.${RE2C_VERSION_MINOR}.${RE2C_VERSION_PATCH}" - ) + math(EXPR patch "${versionNumber} - ${major} * 10000 - ${minor} * 100") + + set(RE2C_VERSION "${major}.${minor}.${patch}") - find_package_check_version("${RE2C_VERSION}" _re2cVersionValid) + find_package_check_version("${RE2C_VERSION}" _re2cVersionValid) + endif() endif() -endif() +endblock() set(_re2cRequiredVars "") @@ -554,6 +511,7 @@ if( -DPython3_VERSION=3.7 ) endif() + ExternalProject_Add( re2c URL @@ -592,9 +550,6 @@ find_package_handle_standard_args( unset(_re2cDownloadOptions) unset(_re2cMsg) unset(_re2cRequiredVars) -unset(_re2cTest) -unset(_re2cVersionError) -unset(_re2cVersionResult) unset(_re2cVersionValid) if(NOT RE2C_FOUND) diff --git a/cmake/cmake/modules/PHP/BISON.cmake b/cmake/cmake/modules/PHP/BISON.cmake index 7c7181dd..3e84a4e6 100644 --- a/cmake/cmake/modules/PHP/BISON.cmake +++ b/cmake/cmake/modules/PHP/BISON.cmake @@ -23,14 +23,9 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c) endif() include(PHP/BISON) -php_bison( - php_ext_json_parser - json_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c - COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" - VERBOSE REPORT_FILE json_parser.tab.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h -) +if(BISON_FOUND) + bison(...) +endif() ``` #]=============================================================================] @@ -39,17 +34,16 @@ include(FeatureSummary) # Minimum required bison version. set(PHP_BISON_MIN_VERSION 3.0.0) -# Add Bison options based on the build type. -if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.32) - # See: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9921 - set(PHP_BISON_DEFAULT_OPTIONS "-Wall $<$:-l>") +# Add Bison --no-lines (-l) option to not generate '#line' directives based on +# this module usage and build type. +if(CMAKE_SCRIPT_MODE_FILE) + set(BISON_DEFAULT_OPTIONS --no-lines) else() - set(PHP_BISON_DEFAULT_OPTIONS "$,-lWall,-Wall>") + set(BISON_DEFAULT_OPTIONS $<$:--no-lines>) endif() -if(CMAKE_SCRIPT_MODE_FILE) - set(PHP_BISON_DEFAULT_OPTIONS "-l -Wall") -endif() +# Report all warnings. +list(PREPEND BISON_DEFAULT_OPTIONS -Wall) find_package(BISON ${PHP_BISON_MIN_VERSION} GLOBAL) @@ -59,20 +53,5 @@ block() set(type TYPE REQUIRED) endif() - set_package_properties( - BISON - PROPERTIES - ${type} - PURPOSE "Necessary to generate PHP parser files." - ) + set_package_properties(BISON PROPERTIES ${type}) endblock() - -macro(php_bison) - if(BISON_FOUND) - if(CMAKE_SCRIPT_MODE_FILE) - bison_execute(${ARGN}) - else() - bison_target(${ARGN}) - endif() - endif() -endmacro() diff --git a/cmake/cmake/modules/PHP/RE2C.cmake b/cmake/cmake/modules/PHP/RE2C.cmake index 51e77b16..23a40815 100644 --- a/cmake/cmake/modules/PHP/RE2C.cmake +++ b/cmake/cmake/modules/PHP/RE2C.cmake @@ -26,14 +26,9 @@ endif() # Include the module. include(PHP/RE2C) -php_re2c( - php_ext_json_scanner - json_scanner.re - ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h - OPTIONS -bc - CODEGEN -) +if(RE2C_FOUND) + re2c(...) +endif() ``` #]=============================================================================] @@ -56,12 +51,8 @@ else() set(RE2C_DEFAULT_OPTIONS $<$:--no-debug-info>) endif() -list( - APPEND RE2C_DEFAULT_OPTIONS - --no-generation-date # Suppress date output in the generated file. -) - -set(RE2C_NAMESPACE "php_") +# Suppress date output in the generated file. +list(APPEND RE2C_DEFAULT_OPTIONS --no-generation-date) find_package(RE2C ${PHP_RE2C_MIN_VERSION} GLOBAL) diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake index ffc05575..41517ccd 100755 --- a/cmake/cmake/scripts/GenerateGrammar.cmake +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -18,8 +18,6 @@ # created by this script (the `VERBOSE REPORT_FILE ` options)? PHP still # packages these reports also in the archive release files?! Also, ext/json # doesn't produce the *.output file. -# -# TODO: Add remaining missing features to FindBISON.cmake module. cmake_minimum_required(VERSION 3.25...3.31) @@ -48,9 +46,8 @@ feature_summary( file( GLOB_RECURSE scripts - ${PHP_SOURCE_DIR}/ext/*/cmake/GenerateGrammar.cmake - ${PHP_SOURCE_DIR}/sapi/*/cmake/GenerateGrammar.cmake - ${PHP_SOURCE_DIR}/Zend/cmake/GenerateGrammar.cmake + ${PHP_SOURCE_DIR}/*/*/cmake/GenerateGrammar.cmake + ${PHP_SOURCE_DIR}/*/cmake/GenerateGrammar.cmake ) foreach(script IN LISTS scripts) cmake_path(GET script PARENT_PATH path) diff --git a/cmake/ext/json/cmake/GenerateGrammar.cmake b/cmake/ext/json/cmake/GenerateGrammar.cmake index b47515a7..4aef5c0e 100644 --- a/cmake/ext/json/cmake/GenerateGrammar.cmake +++ b/cmake/ext/json/cmake/GenerateGrammar.cmake @@ -9,14 +9,22 @@ endif() include(PHP/BISON) -php_bison( - php_ext_json_parser - json_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c - COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" - VERBOSE REPORT_FILE json_parser.tab.output - DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h -) +if(BISON_FOUND) + if(CMAKE_SCRIPT_MODE_FILE) + set(verbose "") + else() + set(verbose VERBOSE REPORT_FILE json_parser.output) + endif() + + bison( + php_ext_json_parser + json_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c + ${verbose} + HEADER + #HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h + ) +endif() if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c @@ -27,11 +35,13 @@ endif() include(PHP/RE2C) -php_re2c( - php_ext_json_scanner - json_scanner.re - ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h - OPTIONS -bc - CODEGEN -) +if(RE2C_FOUND) + re2c( + php_ext_json_scanner + json_scanner.re + ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h + OPTIONS -bc + CODEGEN + ) +endif() diff --git a/cmake/ext/pdo/cmake/GenerateGrammar.cmake b/cmake/ext/pdo/cmake/GenerateGrammar.cmake index e548bcb7..aeb9813f 100644 --- a/cmake/ext/pdo/cmake/GenerateGrammar.cmake +++ b/cmake/ext/pdo/cmake/GenerateGrammar.cmake @@ -6,9 +6,11 @@ endif() include(PHP/RE2C) -php_re2c( - php_ext_pdo_sql_parser - pdo_sql_parser.re - ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c - CODEGEN -) +if(RE2C_FOUND) + re2c( + php_ext_pdo_sql_parser + pdo_sql_parser.re + ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c + CODEGEN + ) +endif() diff --git a/cmake/ext/phar/cmake/GenerateGrammar.cmake b/cmake/ext/phar/cmake/GenerateGrammar.cmake index d6cad28b..e0034572 100644 --- a/cmake/ext/phar/cmake/GenerateGrammar.cmake +++ b/cmake/ext/phar/cmake/GenerateGrammar.cmake @@ -6,10 +6,12 @@ endif() include(PHP/RE2C) -php_re2c( - php_ext_phar_path_check - phar_path_check.re - ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c - OPTIONS -b - CODEGEN -) +if(RE2C_FOUND) + re2c( + php_ext_phar_path_check + phar_path_check.re + ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c + OPTIONS -b + CODEGEN + ) +endif() diff --git a/cmake/ext/standard/cmake/GenerateGrammar.cmake b/cmake/ext/standard/cmake/GenerateGrammar.cmake index 741d2fda..478716c7 100644 --- a/cmake/ext/standard/cmake/GenerateGrammar.cmake +++ b/cmake/ext/standard/cmake/GenerateGrammar.cmake @@ -9,18 +9,20 @@ endif() include(PHP/RE2C) -php_re2c( - php_ext_standard_url_scanner_ex - url_scanner_ex.re - ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c - OPTIONS -b - CODEGEN -) +if(RE2C_FOUND) + re2c( + php_ext_standard_url_scanner_ex + url_scanner_ex.re + ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c + OPTIONS -b + CODEGEN + ) -php_re2c( - php_ext_standard_var_unserializer - var_unserializer.re - ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c - OPTIONS -b - CODEGEN -) + re2c( + php_ext_standard_var_unserializer + var_unserializer.re + ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c + OPTIONS -b + CODEGEN + ) +endif() diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake index d67caec4..ca85fb6a 100644 --- a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -1,5 +1,12 @@ # Generate lexer and parser files. +if(PHP_SOURCE_DIR) + set(workingDirectory ${PHP_SOURCE_DIR}) +else() + set(workingDirectory ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +# Generate parser files. if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.h @@ -8,24 +15,40 @@ if( endif() include(PHP/BISON) -php_bison( - php_sapi_phpdbg_parser - phpdbg_parser.y - phpdbg_parser.c - COMPILE_FLAGS "${PHP_BISON_DEFAULT_OPTIONS}" - VERBOSE REPORT_FILE phpdbg_parser.output - DEFINES_FILE phpdbg_parser.h -) +if(BISON_FOUND) + if(CMAKE_SCRIPT_MODE_FILE) + set(verbose "") + else() + set(verbose VERBOSE REPORT_FILE phpdbg_parser.output) + endif() + + bison( + php_sapi_phpdbg_parser + phpdbg_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c + HEADER + #HEADER_FILE phpdbg_parser.h + ${verbose} + WORKING_DIRECTORY ${workingDirectory} + ) +endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c) +# Generate lexer files. +if( + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c + AND NOT CMAKE_SCRIPT_MODE_FILE +) set(PHP_RE2C_OPTIONAL TRUE) endif() include(PHP/RE2C) -php_re2c( - php_sapi_phpdbg_lexer - phpdbg_lexer.l - ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c - OPTIONS -cbdF - CODEGEN -) +if(RE2C_FOUND) + re2c( + php_sapi_phpdbg_lexer + phpdbg_lexer.l + ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c + OPTIONS -cbdF + CODEGEN + WORKING_DIRECTORY ${workingDirectory} + ) +endif() From 896e2fe8dfa15d986cb566ddbb81b54855728644 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Sat, 28 Dec 2024 13:28:39 +0100 Subject: [PATCH 08/15] Improve FindBISON module --- cmake/Zend/cmake/GenerateGrammar.cmake | 8 +- cmake/cmake/modules/FindBISON.cmake | 171 ++++++++++++------ cmake/cmake/modules/FindRE2C.cmake | 6 +- cmake/cmake/scripts/GenerateGrammar.cmake | 5 - cmake/ext/json/cmake/GenerateGrammar.cmake | 2 +- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 2 +- 6 files changed, 124 insertions(+), 70 deletions(-) diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake index 5a26f142..a6fb16b9 100644 --- a/cmake/Zend/cmake/GenerateGrammar.cmake +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -14,7 +14,7 @@ if(BISON_FOUND) if(CMAKE_SCRIPT_MODE_FILE) set(verbose "") else() - set(verbose VERBOSE REPORT_FILE zend_ini_parser.output) + set(verbose VERBOSE) endif() bison( @@ -29,7 +29,7 @@ if(BISON_FOUND) if(CMAKE_SCRIPT_MODE_FILE) set(verbose "") else() - set(verbose VERBOSE REPORT_FILE zend_language_parser.output) + set(verbose VERBOSE) endif() bison( @@ -94,12 +94,12 @@ if(BISON_FOUND) else() file( GENERATE - OUTPUT CMakeFiles/PatchLanguageParser.cmake + OUTPUT CMakeFiles/Zend/PatchLanguageParser.cmake CONTENT "${patch}" ) add_custom_target( zend_language_parser_patch - COMMAND ${CMAKE_COMMAND} -P CMakeFiles/PatchLanguageParser.cmake + COMMAND ${CMAKE_COMMAND} -P CMakeFiles/Zend/PatchLanguageParser.cmake DEPENDS zend_language_parser VERBATIM ) diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake index d8f77df5..67a93a94 100644 --- a/cmake/cmake/modules/FindBISON.cmake +++ b/cmake/cmake/modules/FindBISON.cmake @@ -79,6 +79,17 @@ in various scenarios. * `DEPENDS ...` - Optional list of dependent files to regenerate the output file. +* `VERBOSE` - This adds the `--verbose` (`-v`) command-line option to + `bison` executable and will create extra output file + `.output` containing verbose descriptions of the + grammar and parser. File will be created in the current binary directory. + +* `REPORT_FILE ` - This adds the `--report-file=` command-line + option to `bison` executable and will create verbose information report in the + specified ``. This option must be used together with the `VERBOSE` + option. Relative file path is interpreted as being relative to the current + binary directory. + * `NO_DEFAULT_OPTIONS` - If specified, the `BISON_DEFAULT_OPTIONS` are not added to the current `bison` invocation. @@ -225,15 +236,113 @@ function(_bison_process_options options result) return(PROPAGATE ${result}) endfunction() +# Process HEADER and HEADER_FILE options. +function(_bison_process_header_option) + if(NOT parsed_HEADER AND NOT parsed_HEADER_FILE) + return() + endif() + + # Bison versions 3.8 and later introduced the --header=[FILE] (-H) option. + # For prior versions the --defines=[FILE] (-d) option can be used. + if(parsed_HEADER_FILE) + set(header ${parsed_HEADER_FILE}) + if(NOT IS_ABSOLUTE "${header}") + set(header ${CMAKE_CURRENT_BINARY_DIR}/${header}) + endif() + + if(BISON_VERSION VERSION_LESS 3.8) + list(APPEND options --defines=${header}) + else() + list(APPEND options --header=${header}) + endif() + else() + if(BISON_VERSION VERSION_LESS 3.8) + list(APPEND options -d) + else() + list(APPEND options --header) + endif() + + # Produce default header path generated by bison (see option --header). + cmake_path(GET output EXTENSION LAST_ONLY extension) + string(REPLACE "c" "h" extension "${extension}") + if(NOT extension) + set(extension ".h") + endif() + cmake_path( + REPLACE_EXTENSION + output + LAST_ONLY + "${extension}" + OUTPUT_VARIABLE header + ) + # TODO: Add path if header is relative. + endif() + + list(APPEND outputs ${header}) + + return(PROPAGATE outputs options) +endfunction() + +# Process the VERBOSE and REPORT_FILE options. +function(_bison_process_verbose_option) + if(NOT parsed_VERBOSE) + return() + endif() + + list(APPEND options --verbose) + + if(NOT parsed_REPORT_FILE) + cmake_path(GET output FILENAME reportFile) + cmake_path(GET output EXTENSION extension) + + # Bison treats output files .tab. + # differently. It removes the '.tab' part of the extension and creates + # .output file. Elsewhere, it replaces only the + # last extension with '.output'. + if(extension MATCHES "\\.tab\\.([^.]+)$") + string( + REGEX REPLACE + "\\.tab\\.${CMAKE_MATCH_1}$" + ".output" + reportFile + "${reportFile}" + ) + else() + cmake_path(REPLACE_EXTENSION reportFile LAST_ONLY "output") + endif() + else() + set(reportFile ${parsed_REPORT_FILE}) + endif() + + if(NOT IS_ABSOLUTE "${reportFile}") + set(reportFile ${CMAKE_CURRENT_BINARY_DIR}/${reportFile}) + endif() + + list(APPEND options --report-file=${reportFile}) + + return(PROPAGATE options) +endfunction() + macro(_bison_process) if(parsed_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Bad arguments: ${parsed_UNPARSED_ARGUMENTS}") + message(FATAL_ERROR "Unrecognized arguments: ${parsed_UNPARSED_ARGUMENTS}") endif() if(parsed_KEYWORDS_MISSING_VALUES) message(FATAL_ERROR "Missing values for: ${parsed_KEYWORDS_MISSING_VALUES}") endif() + if(parsed_HEADER AND parsed_HEADER_FILE) + message( + FATAL_ERROR + "When 'HEADER_FILE' is specified, remove redundant 'HEADER' option." + ) + endif() + + if(parsed_REPORT_FILE AND NOT parsed_VERBOSE) + message(FATAL_ERROR "'REPORT_FILE' option requires also 'VERBOSE' option.") + endif() + set(input ${ARGV1}) if(NOT IS_ABSOLUTE "${input}") set(input ${CMAKE_CURRENT_SOURCE_DIR}/${input}) @@ -249,58 +358,8 @@ macro(_bison_process) set(outputs ${output}) _bison_process_options(parsed_OPTIONS options) - - if(parsed_HEADER OR parsed_HEADER_FILE) - # Bison versions 3.8 and later introduced the --header=[FILE] (-H) option. - # For prior versions the --defines=[FILE] (-d) option can be used. - if(parsed_HEADER_FILE) - set(header ${parsed_HEADER_FILE}) - if(NOT IS_ABSOLUTE "${header}") - set(header ${CMAKE_CURRENT_BINARY_DIR}/${header}) - endif() - if(BISON_VERSION VERSION_LESS 3.8) - list(APPEND options --defines=${header}) - else() - list(APPEND options --header=${header}) - endif() - else() - if(BISON_VERSION VERSION_LESS 3.8) - list(APPEND options -d) - else() - list(APPEND options --header) - endif() - - # Produce default header path generated by bison (see option --header) - cmake_path(GET output EXTENSION LAST_ONLY extension) - string(REPLACE "c" "h" extension "${extension}") - if(NOT extension) - set(extension "h") - endif() - cmake_path( - REPLACE_EXTENSION - output - LAST_ONLY - "${extension}" - OUTPUT_VARIABLE header - ) - # TODO: Add path if header is relative. - endif() - - list(APPEND outputs ${header}) - - if(parsed_VERBOSE) - list(APPEND options --verbose) - if(parsed_REPORT_FILE) - if(NOT IS_ABSOLUTE "${parsed_REPORT_FILE}") - set( - parsed_REPORT_FILE - ${CMAKE_CURRENT_BINARY_DIR}/${parsed_REPORT_FILE} - ) - endif() - list(APPEND options --report-file=${parsed_REPORT_FILE}) - endif() - endif() - endif() + _bison_process_header_option() + _bison_process_verbose_option() # Assemble commands for add_custom_command() and execute_process(). set(commands "") @@ -356,7 +415,7 @@ function(bison) PARSE_ARGV 3 parsed # prefix - "NO_DEFAULT_OPTIONS;CODEGEN;VERBOSE;HEADER" # options + "NO_DEFAULT_OPTIONS;CODEGEN;HEADER;VERBOSE" # options "HEADER_FILE;WORKING_DIRECTORY;REPORT_FILE" # one-value keywords "OPTIONS;DEPENDS" # multi-value keywords ) @@ -484,12 +543,12 @@ block(PROPAGATE BISON_VERSION _bisonVersionValid) endif() endblock() -set(_bisonRequiredVars "") - ################################################################################ # Download and build the package. ################################################################################ +set(_bisonRequiredVars "") + if( NOT CMAKE_SCRIPT_MODE_FILE AND NOT BISON_DISABLE_DOWNLOAD diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index 007655a2..078dd6ff 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -247,7 +247,7 @@ endfunction() macro(_re2c_process) if(parsed_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Bad arguments: ${parsed_UNPARSED_ARGUMENTS}") + message(FATAL_ERROR "Unrecognized arguments: ${parsed_UNPARSED_ARGUMENTS}") endif() if(parsed_KEYWORDS_MISSING_VALUES) @@ -470,12 +470,12 @@ block(PROPAGATE RE2C_VERSION _re2cVersionValid) endif() endblock() -set(_re2cRequiredVars "") - ################################################################################ # Download and build the package. ################################################################################ +set(_re2cRequiredVars "") + if( NOT CMAKE_SCRIPT_MODE_FILE AND NOT RE2C_DISABLE_DOWNLOAD diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake index 41517ccd..6036e5f3 100755 --- a/cmake/cmake/scripts/GenerateGrammar.cmake +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -13,11 +13,6 @@ # [-D BISON_EXECUTABLE=path/to/bison] \ # [-D RE2C_EXECUTABLE=path/to/re2c] \ # -P cmake/scripts/GenerateGrammar.cmake -# -# TODO: Should the Bison-generated report files (*.output) really be also -# created by this script (the `VERBOSE REPORT_FILE ` options)? PHP still -# packages these reports also in the archive release files?! Also, ext/json -# doesn't produce the *.output file. cmake_minimum_required(VERSION 3.25...3.31) diff --git a/cmake/ext/json/cmake/GenerateGrammar.cmake b/cmake/ext/json/cmake/GenerateGrammar.cmake index 4aef5c0e..e370159c 100644 --- a/cmake/ext/json/cmake/GenerateGrammar.cmake +++ b/cmake/ext/json/cmake/GenerateGrammar.cmake @@ -13,7 +13,7 @@ if(BISON_FOUND) if(CMAKE_SCRIPT_MODE_FILE) set(verbose "") else() - set(verbose VERBOSE REPORT_FILE json_parser.output) + set(verbose VERBOSE) #REPORT_FILE json_parser.output) endif() bison( diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake index ca85fb6a..92a023cd 100644 --- a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -19,7 +19,7 @@ if(BISON_FOUND) if(CMAKE_SCRIPT_MODE_FILE) set(verbose "") else() - set(verbose VERBOSE REPORT_FILE phpdbg_parser.output) + set(verbose VERBOSE) endif() bison( From a7ff470b6a6f21516a4dd120742e782932397d9d Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 30 Dec 2024 05:13:45 +0100 Subject: [PATCH 09/15] Resolve relative and absolute paths in generated files --- cmake/Zend/cmake/GenerateGrammar.cmake | 29 +- cmake/cmake/modules/FindBISON.cmake | 401 +++++++++++------- cmake/cmake/modules/FindRE2C.cmake | 371 ++++++++++------ cmake/cmake/modules/PHP/BISON.cmake | 57 --- cmake/cmake/modules/PHP/Package/BISON.cmake | 47 ++ cmake/cmake/modules/PHP/Package/RE2C.cmake | 54 +++ cmake/cmake/modules/PHP/RE2C.cmake | 66 --- cmake/cmake/scripts/GenerateGrammar.cmake | 23 +- cmake/ext/json/cmake/GenerateGrammar.cmake | 22 +- cmake/ext/pdo/cmake/GenerateGrammar.cmake | 9 +- cmake/ext/phar/cmake/GenerateGrammar.cmake | 9 +- .../ext/standard/cmake/GenerateGrammar.cmake | 11 +- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 29 +- 13 files changed, 653 insertions(+), 475 deletions(-) delete mode 100644 cmake/cmake/modules/PHP/BISON.cmake create mode 100644 cmake/cmake/modules/PHP/Package/BISON.cmake create mode 100644 cmake/cmake/modules/PHP/Package/RE2C.cmake delete mode 100644 cmake/cmake/modules/PHP/RE2C.cmake diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake index a6fb16b9..5433802d 100644 --- a/cmake/Zend/cmake/GenerateGrammar.cmake +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -1,14 +1,17 @@ # Generate lexer and parser files. +include(FeatureSummary) +include(PHP/Package/BISON) +include(PHP/Package/RE2C) + if( - EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h + NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h ) - set(PHP_BISON_OPTIONAL TRUE) + set_package_properties(BISON PROPERTIES TYPE REQUIRED) endif() -include(PHP/BISON) if(BISON_FOUND) if(CMAKE_SCRIPT_MODE_FILE) @@ -22,7 +25,6 @@ if(BISON_FOUND) zend_ini_parser.y ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c HEADER - #HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h ${verbose} ) @@ -37,8 +39,8 @@ if(BISON_FOUND) zend_language_parser.y ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c HEADER - #HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h ${verbose} + CODEGEN ) # Tweak zendparse to be exported through ZEND_API. This has to be revisited @@ -109,14 +111,13 @@ if(BISON_FOUND) endif() if( - EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h + NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h ) - set(PHP_RE2C_OPTIONAL TRUE) + set_package_properties(RE2C PROPERTIES TYPE REQUIRED) endif() -include(PHP/RE2C) if(RE2C_FOUND) re2c( diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake index 67a93a94..79a2ecdf 100644 --- a/cmake/cmake/modules/FindBISON.cmake +++ b/cmake/cmake/modules/FindBISON.cmake @@ -1,7 +1,7 @@ #[=============================================================================[ # FindBISON -Find `bison` command-line parser generator. +Find `bison`, the general-purpose parser generator, command-line executable. This is a standalone and customized find module for finding bison. It is synced with CMake FindBISON module, where possible. @@ -31,6 +31,10 @@ These variables can be set before calling the `find_package(BISON)`: * `BISON_DOWNLOAD_VERSION` - Override the default `bison` version to be downloaded when not found on the system. +* `BISON_WORKING_DIRECTORY` - Set the default global working directory + (`WORKING_DIRECTORY ` option) for all `bison()` invocations in the scope + of `find_package(BISON)`. + ## Functions provided by this module ### `bison()` @@ -50,6 +54,7 @@ bison( [NO_DEFAULT_OPTIONS] [CODEGEN] [WORKING_DIRECTORY ] + [ABSOLUTE_PATHS] ) ``` @@ -102,10 +107,31 @@ in various scenarios. cmake --build --target codegen ``` +* `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `bison` + command-line invocations. By default all file paths are added to `bison` + command-line relative to the working directory. Using relative paths is + convenient when line directives (`#line ...`) are generated in the output + parser files to not show the full path on the disk, when file is committed to + Git repository, where multiple people develop. + + When this option is enabled: + + ```c + #line 15 "/home/user/projects/php-src/sapi/phpdbg/phpdbg_parser.y" + ``` + + Without this option, relative paths will be generated: + + ```c + #line 15 "sapi/phpdbg/phpdbg_parser.y" + ``` + * `WORKING_DIRECTORY ` - The path where the `bison` command - is executed. By default, `bison` is executed in the current binary directory - (`CMAKE_CURRENT_BINARY_DIR`). Relative `` path is - interpreted as being relative to the current binary directory. + is executed. Relative `` path is interpreted as being + relative to the current binary directory. If not set, `bison` is by default + executed in the current binary directory (`CMAKE_CURRENT_BINARY_DIR`). If + variable `BISON_WORKING_DIRECTORY` is set before calling the + `find_package(BISON)`, it will set the default working directory. ## Examples @@ -220,109 +246,76 @@ include(FeatureSummary) include(FindPackageHandleStandardArgs) ################################################################################ -# Functions. +# Configuration. ################################################################################ -# Process options. -function(_bison_process_options options result) - set(options ${${options}}) +# If Bison is not found on the system, set which version to download. +if(NOT BISON_DOWNLOAD_VERSION) + set(BISON_DOWNLOAD_VERSION 3.8.2) +endif() - if(BISON_DEFAULT_OPTIONS AND NOT parsed_NO_DEFAULT_OPTIONS) - list(PREPEND options ${BISON_DEFAULT_OPTIONS}) - endif() +################################################################################ +# Functions. +################################################################################ - set(${result} ${options}) +function(bison) + cmake_parse_arguments( + PARSE_ARGV + 3 + parsed # prefix + "NO_DEFAULT_OPTIONS;CODEGEN;HEADER;VERBOSE;ABSOLUTE_PATHS" # options + "HEADER_FILE;WORKING_DIRECTORY;REPORT_FILE" # one-value keywords + "OPTIONS;DEPENDS" # multi-value keywords + ) - return(PROPAGATE ${result}) -endfunction() + _bison_process(${ARGN}) -# Process HEADER and HEADER_FILE options. -function(_bison_process_header_option) - if(NOT parsed_HEADER AND NOT parsed_HEADER_FILE) - return() + if(NOT CMAKE_SCRIPT_MODE_FILE) + add_custom_target(${ARGV0} SOURCES ${input} DEPENDS ${outputs}) endif() - # Bison versions 3.8 and later introduced the --header=[FILE] (-H) option. - # For prior versions the --defines=[FILE] (-d) option can be used. - if(parsed_HEADER_FILE) - set(header ${parsed_HEADER_FILE}) - if(NOT IS_ABSOLUTE "${header}") - set(header ${CMAKE_CURRENT_BINARY_DIR}/${header}) - endif() - - if(BISON_VERSION VERSION_LESS 3.8) - list(APPEND options --defines=${header}) - else() - list(APPEND options --header=${header}) - endif() - else() - if(BISON_VERSION VERSION_LESS 3.8) - list(APPEND options -d) - else() - list(APPEND options --header) - endif() - - # Produce default header path generated by bison (see option --header). - cmake_path(GET output EXTENSION LAST_ONLY extension) - string(REPLACE "c" "h" extension "${extension}") - if(NOT extension) - set(extension ".h") - endif() - cmake_path( - REPLACE_EXTENSION - output - LAST_ONLY - "${extension}" - OUTPUT_VARIABLE header - ) - # TODO: Add path if header is relative. + # Skip generation, if generated files are provided by the release archive. + get_property(type GLOBAL PROPERTY _CMAKE_BISON_TYPE) + if(NOT BISON_FOUND AND NOT BISON_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") + return() endif() - list(APPEND outputs ${header}) - - return(PROPAGATE outputs options) -endfunction() - -# Process the VERBOSE and REPORT_FILE options. -function(_bison_process_verbose_option) - if(NOT parsed_VERBOSE) + if(CMAKE_SCRIPT_MODE_FILE) + message(STATUS "[BISON] ${message}") + execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) return() endif() - list(APPEND options --verbose) - - if(NOT parsed_REPORT_FILE) - cmake_path(GET output FILENAME reportFile) - cmake_path(GET output EXTENSION extension) + set(codegen "") + if( + parsed_CODEGEN + AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 + AND POLICY CMP0171 + ) + cmake_policy(GET CMP0171 cmp0171) - # Bison treats output files .tab. - # differently. It removes the '.tab' part of the extension and creates - # .output file. Elsewhere, it replaces only the - # last extension with '.output'. - if(extension MATCHES "\\.tab\\.([^.]+)$") - string( - REGEX REPLACE - "\\.tab\\.${CMAKE_MATCH_1}$" - ".output" - reportFile - "${reportFile}" - ) - else() - cmake_path(REPLACE_EXTENSION reportFile LAST_ONLY "output") + if(cmp0171 STREQUAL "NEW") + set(codegen CODEGEN) endif() - else() - set(reportFile ${parsed_REPORT_FILE}) endif() - if(NOT IS_ABSOLUTE "${reportFile}") - set(reportFile ${CMAKE_CURRENT_BINARY_DIR}/${reportFile}) - endif() - - list(APPEND options --report-file=${reportFile}) - - return(PROPAGATE options) + add_custom_command( + OUTPUT ${outputs} + ${commands} + DEPENDS + ${input} + ${parsed_DEPENDS} + $ + $ + COMMENT "[BISON][${ARGV0}] ${message}" + VERBATIM + COMMAND_EXPAND_LISTS + ${codegen} + WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} + ) endfunction() +# Process arguments. macro(_bison_process) if(parsed_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unrecognized arguments: ${parsed_UNPARSED_ARGUMENTS}") @@ -334,7 +327,7 @@ macro(_bison_process) if(parsed_HEADER AND parsed_HEADER_FILE) message( - FATAL_ERROR + AUTHOR_WARNING "When 'HEADER_FILE' is specified, remove redundant 'HEADER' option." ) endif() @@ -351,16 +344,40 @@ macro(_bison_process) set(output ${ARGV2}) if(NOT IS_ABSOLUTE "${output}") - set(output ${CMAKE_CURRENT_BINARY_DIR}/${output}) + cmake_path( + ABSOLUTE_PATH + output + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) endif() cmake_path(SET output NORMALIZE "${output}") set(outputs ${output}) + _bison_set_working_directory() _bison_process_options(parsed_OPTIONS options) _bison_process_header_option() _bison_process_verbose_option() + if(parsed_ABSOLUTE_PATHS) + set(inputArgument "${input}") + set(outputArgument "${output}") + else() + cmake_path( + RELATIVE_PATH + input + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE inputArgument + ) + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE outputArgument + ) + endif() + # Assemble commands for add_custom_command() and execute_process(). set(commands "") @@ -385,7 +402,11 @@ macro(_bison_process) list( APPEND commands - COMMAND ${BISON_EXECUTABLE} ${options} ${input} --output ${output} + COMMAND + ${BISON_EXECUTABLE} + ${options} + ${inputArgument} + --output ${outputArgument} ) # Assemble status message. @@ -397,70 +418,148 @@ macro(_bison_process) ) set(message "Generating ${outputRelative} with bison ${BISON_VERSION}") +endmacro() - if(NOT parsed_WORKING_DIRECTORY) - set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - else() - if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") - set( - parsed_WORKING_DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/${parsed_WORKING_DIRECTORY} +# Process options. +function(_bison_process_options options result) + set(options ${${options}}) + + if(BISON_DEFAULT_OPTIONS AND NOT parsed_NO_DEFAULT_OPTIONS) + list(PREPEND options ${BISON_DEFAULT_OPTIONS}) + endif() + + set(${result} ${options}) + + return(PROPAGATE ${result}) +endfunction() + +# Process HEADER and HEADER_FILE options. +function(_bison_process_header_option) + if(NOT parsed_HEADER AND NOT parsed_HEADER_FILE) + return() + endif() + + # Bison versions 3.8 and later introduced the --header=[FILE] (-H) option. + # For prior versions the --defines=[FILE] (-d) option can be used. + if(parsed_HEADER_FILE) + set(header ${parsed_HEADER_FILE}) + if(NOT IS_ABSOLUTE "${header}") + cmake_path( + ABSOLUTE_PATH + header + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE ) endif() - endif() -endmacro() -function(bison) - cmake_parse_arguments( - PARSE_ARGV - 3 - parsed # prefix - "NO_DEFAULT_OPTIONS;CODEGEN;HEADER;VERBOSE" # options - "HEADER_FILE;WORKING_DIRECTORY;REPORT_FILE" # one-value keywords - "OPTIONS;DEPENDS" # multi-value keywords - ) + if(parsed_ABSOLUTE_PATHS) + set(headerArgument "${header}") + else() + cmake_path( + RELATIVE_PATH + header + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE headerArgument + ) + endif() - _bison_process(${ARGN}) + if(BISON_VERSION VERSION_LESS 3.8) + list(APPEND options --defines=${headerArgument}) + else() + list(APPEND options --header=${headerArgument}) + endif() + else() + if(BISON_VERSION VERSION_LESS 3.8) + list(APPEND options -d) + else() + list(APPEND options --header) + endif() - if(NOT CMAKE_SCRIPT_MODE_FILE) - add_custom_target(${ARGV0} SOURCES ${input} DEPENDS ${outputs}) + # Produce default header path generated by bison (see option --header). + cmake_path(GET output EXTENSION LAST_ONLY extension) + string(REPLACE "c" "h" extension "${extension}") + if(NOT extension) + set(extension ".h") + endif() + cmake_path( + REPLACE_EXTENSION + output + LAST_ONLY + "${extension}" + OUTPUT_VARIABLE header + ) endif() - # Skip generation, if generated files are provided by the release archive. - get_property(type GLOBAL PROPERTY _CMAKE_BISON_TYPE) - if(NOT BISON_FOUND AND NOT BISON_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") + list(APPEND outputs ${header}) + + return(PROPAGATE outputs options) +endfunction() + +# Process the VERBOSE and REPORT_FILE options. +function(_bison_process_verbose_option) + if(NOT parsed_VERBOSE) return() endif() - if(CMAKE_SCRIPT_MODE_FILE) - message(STATUS "[BISON] ${message}") - execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) - return() + list(APPEND options --verbose) + + if(NOT parsed_REPORT_FILE) + cmake_path(GET output FILENAME reportFile) + cmake_path(GET output EXTENSION extension) + + # Bison treats output files .tab. + # differently. It removes the '.tab' part of the extension and creates + # .output file. Elsewhere, it replaces only the + # last extension with '.output'. + if(extension MATCHES "\\.tab\\.([^.]+)$") + string( + REGEX REPLACE + "\\.tab\\.${CMAKE_MATCH_1}$" + ".output" + reportFile + "${reportFile}" + ) + else() + cmake_path(REPLACE_EXTENSION reportFile LAST_ONLY "output") + endif() + else() + set(reportFile ${parsed_REPORT_FILE}) endif() - set(codegen "") - if( - parsed_CODEGEN - AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 - AND POLICY CMP0171 - ) - cmake_policy(GET CMP0171 cmp0171) + if(NOT IS_ABSOLUTE "${reportFile}") + cmake_path( + ABSOLUTE_PATH + reportFile + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + endif() - if(cmp0171 STREQUAL "NEW") - set(codegen CODEGEN) + list(APPEND options --report-file=${reportFile}) + + return(PROPAGATE options) +endfunction() + +# Set or adjust the parsed_WORKING_DIRECTORY. +function(_bison_set_working_directory) + if(NOT parsed_WORKING_DIRECTORY) + if(BISON_WORKING_DIRECTORY) + set(parsed_WORKING_DIRECTORY ${BISON_WORKING_DIRECTORY}) + else() + set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() endif() - add_custom_command( - OUTPUT ${outputs} - ${commands} - DEPENDS ${input} ${parsed_DEPENDS} $ - COMMENT "[BISON][${ARGV0}] ${message}" - VERBATIM - COMMAND_EXPAND_LISTS - ${codegen} - WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} - ) + if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") + cmake_path( + ABSOLUTE_PATH + parsed_WORKING_DIRECTORY + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + endif() + + return(PROPAGATE parsed_WORKING_DIRECTORY) endfunction() ################################################################################ @@ -496,8 +595,8 @@ endblock() find_program( BISON_EXECUTABLE - NAMES bison - DOC "The bison executable path" + NAMES bison win-bison win_bison + DOC "The path to the bison executable" ) mark_as_advanced(BISON_EXECUTABLE) @@ -553,26 +652,18 @@ if( NOT CMAKE_SCRIPT_MODE_FILE AND NOT BISON_DISABLE_DOWNLOAD AND (NOT BISON_EXECUTABLE OR NOT _bisonVersionValid) + AND FALSE # TODO: Integrate building Bison from source. ) - # Set which bison version to download. - if(NOT BISON_DOWNLOAD_VERSION) - set(BISON_DOWNLOAD_VERSION 3.8.2) - endif() set(BISON_VERSION ${BISON_DOWNLOAD_VERSION}) - if(NOT TARGET Bison::Bison) + if(NOT TARGET Bison::Bison AND NOT TARGET bison) include(ExternalProject) - # Configure bison build. - set(_bisonDownloadOptions "") - ExternalProject_Add( bison - URL - # :( https://github.com/.../.../archive/refs/tags/${BISON_VERSION}.tar.gz - CMAKE_ARGS - -DBISON_TODO=OFF - ${_bisonDownloadOptions} + URL https://ftp.gnu.org/gnu/bison/bison-${BISON_VERSION}.tar.gz + CONFIGURE_COMMAND /configure + BUILD_COMMAND make INSTALL_COMMAND "" ) @@ -597,10 +688,10 @@ find_package_handle_standard_args( REQUIRED_VARS ${_bisonRequiredVars} BISON_EXECUTABLE BISON_VERSION VERSION_VAR BISON_VERSION HANDLE_VERSION_RANGE - REASON_FAILURE_MESSAGE "bison not found. Please install bison." + REASON_FAILURE_MESSAGE + "The Bison executable not found. Please install Bison parser generator." ) -unset(_bisonDownloadOptions) unset(_bisonMsg) unset(_bisonRequiredVars) unset(_bisonVersionValid) diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index 078dd6ff..07d9a2bd 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -24,7 +24,10 @@ module. These variables can be set before calling the `find_package(RE2C)`: -* `RE2C_DEFAULT_OPTIONS` - A semicolon-separated list of default global re2c +* `RE2C_COMPUTED_GOTOS` - Add the `COMPUTED_GOTOS TRUE` option to all `re2c()` + invocations in the scope of `find_package(RE2C)`. + +* `RE2C_DEFAULT_OPTIONS` - A semicolon-separated list of default global `re2c` options to be prepended to `re2c(OPTIONS)` argument for all re2c invocations when generating lexer files. @@ -35,11 +38,9 @@ These variables can be set before calling the `find_package(RE2C)`: * `RE2C_DOWNLOAD_VERSION` - Override the default `re2c` version to be downloaded when not found on the system. -* `RE2C_USE_COMPUTED_GOTOS` - Set to `TRUE` to enable the re2c - `--computed-gotos` (`-g`) option if the non-standard C `computed goto` - extension is supported by the C compiler. When using it in command-line script - mode, option is not checked, whether the compiler supports it and is added to - `re2c` options unconditionally. +* `RE2C_WORKING_DIRECTORY` - Set the default global working directory + (`WORKING_DIRECTORY ` option) for all `re2c()` invocations in the scope of + `find_package(RE2C)`. ## Functions provided by this module @@ -57,9 +58,10 @@ re2c( [OPTIONS ...] [DEPENDS ...] [NO_DEFAULT_OPTIONS] - [NO_COMPUTED_GOTOS] + [COMPUTED_GOTOS ] [CODEGEN] [WORKING_DIRECTORY ] + [ABSOLUTE_PATHS] ) ``` @@ -89,8 +91,12 @@ in various scenarios. * `NO_DEFAULT_OPTIONS` - If specified, the `RE2C_DEFAULT_OPTIONS` are not added to the current `re2c` invocation. -* `NO_COMPUTED_GOTOS` - If specified, when using the `RE2C_USE_COMPUTED_GOTOS`, - the computed gotos option is not added to the current `re2c` invocation. +* `COMPUTED_GOTOS ` - Set to `TRUE` to add the re2c + `--computed-gotos` (`-g`) command-line option if the non-standard C computed + goto extension is supported by the C compiler. When calling `re2c()` in the + command-line script mode (`CMAKE_SCRIPT_MODE`), option is not checked, whether + the compiler supports it and is added to `re2c` command-line options + unconditionally. * `CODEGEN` - Adds the `CODEGEN` option to the re2c's `add_custom_command()` call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which @@ -102,9 +108,30 @@ in various scenarios. ``` * `WORKING_DIRECTORY ` - The path where the `re2c` command is - executed. By default, `re2c` is executed in the current binary directory - (`CMAKE_CURRENT_BINARY_DIR`). Relative `` path is - interpreted as being relative to the current binary directory. + executed. Relative `` path is interpreted as being relative + to the current binary directory. If not set, `re2c` is by default executed in + the current binary directory (`CMAKE_CURRENT_BINARY_DIR`). If variable + `RE2C_WORKING_DIRECTORY` is set before calling the `find_package(RE2C)`, it + will set the default working directory. + +* `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `re2c` + command-line invocations. By default all file paths are added to `re2c` + command-line relative to the working directory. Using relative paths is + convenient when line directives (`#line ...`) are generated in the output + lexer files to not show the full path on the disk, when file is committed to + Git repository, where multiple people develop. + + When this option is enabled: + + ```c + #line 108 "/home/user/projects/php-src/ext/phar/phar_path_check.c" + ``` + + Without this option, relative paths will be generated: + + ```c + #line 108 "ext/phar/phar_path_check.c" + ``` ## Examples @@ -221,30 +248,76 @@ include(FeatureSummary) include(FindPackageHandleStandardArgs) ################################################################################ -# Functions. +# Configuration. ################################################################################ -# Process options. -function(_re2c_process_options options result) - set(options ${${options}}) +# If re2c is not found on the system, set which version to download. +if(NOT RE2C_DOWNLOAD_VERSION) + set(RE2C_DOWNLOAD_VERSION 4.0.2) +endif() - if( - RE2C_USE_COMPUTED_GOTOS - AND _RE2C_HAVE_COMPUTED_GOTOS - AND NOT parsed_NO_COMPUTED_GOTOS +################################################################################ +# Functions. +################################################################################ + +function(re2c) + cmake_parse_arguments( + PARSE_ARGV + 3 + parsed # prefix + "NO_DEFAULT_OPTIONS;CODEGEN;ABSOLUTE_PATHS" # options + "HEADER;WORKING_DIRECTORY;COMPUTED_GOTOS" # one-value keywords + "OPTIONS;DEPENDS" # multi-value keywords ) - list(PREPEND options "--computed-gotos") + + _re2c_process(${ARGN}) + + if(NOT CMAKE_SCRIPT_MODE_FILE) + add_custom_target(${ARGV0} SOURCES ${input} DEPENDS ${outputs}) endif() - if(RE2C_DEFAULT_OPTIONS AND NOT parsed_NO_DEFAULT_OPTIONS) - list(PREPEND options ${RE2C_DEFAULT_OPTIONS}) + # Skip generation, if generated files are provided by the release archive. + get_property(type GLOBAL PROPERTY _CMAKE_RE2C_TYPE) + if(NOT RE2C_FOUND AND NOT RE2C_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") + return() endif() - set(${result} ${options}) + if(CMAKE_SCRIPT_MODE_FILE) + message(STATUS "[RE2C] ${message}") + execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) + return() + endif() - return(PROPAGATE ${result}) + set(codegen "") + if( + parsed_CODEGEN + AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 + AND POLICY CMP0171 + ) + cmake_policy(GET CMP0171 cmp0171) + + if(cmp0171 STREQUAL "NEW") + set(codegen CODEGEN) + endif() + endif() + + add_custom_command( + OUTPUT ${outputs} + ${commands} + DEPENDS + ${input} + ${parsed_DEPENDS} + $ + $ + COMMENT "[RE2C][${ARGV0}] ${message}" + VERBATIM + COMMAND_EXPAND_LISTS + ${codegen} + WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} + ) endfunction() +# Process arguments. macro(_re2c_process) if(parsed_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unrecognized arguments: ${parsed_UNPARSED_ARGUMENTS}") @@ -256,43 +329,30 @@ macro(_re2c_process) set(input ${ARGV1}) if(NOT IS_ABSOLUTE "${input}") - set(input ${CMAKE_CURRENT_SOURCE_DIR}/${input}) + cmake_path( + ABSOLUTE_PATH + input + BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + NORMALIZE + ) endif() cmake_path(SET input NORMALIZE "${input}") set(output ${ARGV2}) if(NOT IS_ABSOLUTE "${output}") - set(output ${CMAKE_CURRENT_BINARY_DIR}/${output}) + cmake_path( + ABSOLUTE_PATH + output + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) endif() cmake_path(SET output NORMALIZE "${output}") set(outputs ${output}) _re2c_process_options(parsed_OPTIONS options) - - if(parsed_HEADER) - set(header ${parsed_HEADER}) - if(NOT IS_ABSOLUTE "${header}") - set(header ${CMAKE_CURRENT_BINARY_DIR}/${header}) - endif() - - list(APPEND outputs ${header}) - - # When header option is used before re2c version 1.2, also the '-c' option - # is required. Before 1.1 '-c' long variant is '--start-conditions' and - # after 1.1 '--conditions'. - if(RE2C_VERSION VERSION_LESS_EQUAL 1.2) - list(APPEND options -c) - endif() - - # Since re2c version 3.0, '--header' is the new alias option for the - # '--type-header' option. - if(RE2C_VERSION VERSION_GREATER_EQUAL 3.0) - list(APPEND options --header ${header}) - else() - list(APPEND options --type-header ${header}) - endif() - endif() + _re2c_process_header_option() # Assemble commands for add_custom_command() and execute_process(). set(commands "") @@ -315,10 +375,34 @@ macro(_re2c_process) ) endif() + _re2c_set_working_directory() + + if(parsed_ABSOLUTE_PATHS) + set(inputArgument "${input}") + set(outputArgument "${output}") + else() + cmake_path( + RELATIVE_PATH + input + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE inputArgument + ) + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE outputArgument + ) + endif() + list( APPEND commands - COMMAND ${RE2C_EXECUTABLE} ${options} --output ${output} ${input} + COMMAND + ${RE2C_EXECUTABLE} + ${options} + --output ${outputArgument} + ${inputArgument} ) # Assemble status message. @@ -330,70 +414,122 @@ macro(_re2c_process) ) set(message "Generating ${outputRelative} with re2c ${RE2C_VERSION}") +endmacro() - if(NOT parsed_WORKING_DIRECTORY) - set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - else() - if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") - set( - parsed_WORKING_DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/${parsed_WORKING_DIRECTORY} - ) +# Process options. +function(_re2c_process_options options result) + set(options ${${options}}) + + if(RE2C_COMPUTED_GOTOS OR parsed_COMPUTED_GOTOS) + _re2c_check_computed_gotos(result) + if(result) + list(PREPEND options --computed-gotos) endif() endif() -endmacro() -function(re2c) - cmake_parse_arguments( - PARSE_ARGV - 3 - parsed # prefix - "NO_DEFAULT_OPTIONS;NO_COMPUTED_GOTOS;CODEGEN" # options - "HEADER;WORKING_DIRECTORY" # one-value keywords - "OPTIONS;DEPENDS" # multi-value keywords - ) + if(RE2C_DEFAULT_OPTIONS AND NOT parsed_NO_DEFAULT_OPTIONS) + list(PREPEND options ${RE2C_DEFAULT_OPTIONS}) + endif() - _re2c_process(${ARGN}) + set(${result} ${options}) - if(NOT CMAKE_SCRIPT_MODE_FILE) - add_custom_target(${ARGV0} SOURCES ${input} DEPENDS ${outputs}) - endif() + return(PROPAGATE ${result}) +endfunction() - # Skip generation, if generated files are provided by the release archive. - get_property(type GLOBAL PROPERTY _CMAKE_RE2C_TYPE) - if(NOT RE2C_FOUND AND NOT RE2C_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") +# Process HEADER option. +function(_re2c_process_header_option) + if(NOT parsed_HEADER) return() endif() - if(CMAKE_SCRIPT_MODE_FILE) - message(STATUS "[RE2C] ${message}") - execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) - return() + set(header ${parsed_HEADER}) + if(NOT IS_ABSOLUTE "${header}") + cmake_path( + ABSOLUTE_PATH + header + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) endif() - set(codegen "") - if( - parsed_CODEGEN - AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 - AND POLICY CMP0171 - ) - cmake_policy(GET CMP0171 cmp0171) + list(APPEND outputs ${header}) - if(cmp0171 STREQUAL "NEW") - set(codegen CODEGEN) + # When header option is used before re2c version 1.2, also the '-c' option + # is required. Before 1.1 '-c' long variant is '--start-conditions' and + # after 1.1 '--conditions'. + if(RE2C_VERSION VERSION_LESS_EQUAL 1.2) + list(APPEND options -c) + endif() + + # Since re2c version 3.0, '--header' is the new alias option for the + # '--type-header' option. + if(RE2C_VERSION VERSION_GREATER_EQUAL 3.0) + list(APPEND options --header ${header}) + else() + list(APPEND options --type-header ${header}) + endif() + + return(PROPAGATE outputs options) +endfunction() + +# Set or adjust the parsed_WORKING_DIRECTORY. +function(_re2c_set_working_directory) + if(NOT parsed_WORKING_DIRECTORY) + if(RE2C_WORKING_DIRECTORY) + set(parsed_WORKING_DIRECTORY ${RE2C_WORKING_DIRECTORY}) + else() + set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() endif() - add_custom_command( - OUTPUT ${outputs} - ${commands} - DEPENDS ${input} ${parsed_DEPENDS} $ - COMMENT "[RE2C][${ARGV0}] ${message}" - VERBATIM - COMMAND_EXPAND_LISTS - ${codegen} - WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} - ) + if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") + cmake_path( + ABSOLUTE_PATH + parsed_WORKING_DIRECTORY + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + endif() + + return(PROPAGATE parsed_WORKING_DIRECTORY) +endfunction() + +# Check for re2c --computed-gotos option. +function(_re2c_check_computed_gotos result) + if(CMAKE_SCRIPT_MODE_FILE) + set(${result} TRUE) + return(PROPAGATE ${result}) + endif() + + if(DEFINED _FIND_RE2C_HAVE_COMPUTED_GOTOS) + set(${result} ${_FIND_RE2C_HAVE_COMPUTED_GOTOS}) + return(PROPAGATE ${result}) + endif() + + message(CHECK_START "Checking for re2c --computed-gotos (-g) option support") + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_QUIET TRUE) + check_source_compiles(C [[ + int main(void) + { + label1: + ; + label2: + ; + static void *adr[] = { &&label1, &&label2 }; + goto *adr[0]; + return 0; + } + ]] _FIND_RE2C_HAVE_COMPUTED_GOTOS) + cmake_pop_check_state() + if(_FIND_RE2C_HAVE_COMPUTED_GOTOS) + message(CHECK_PASS "yes") + else() + message(CHECK_FAIL "no") + endif() + + set(${result} ${_FIND_RE2C_HAVE_COMPUTED_GOTOS}) + return(PROPAGATE ${result}) endfunction() ################################################################################ @@ -481,13 +617,9 @@ if( AND NOT RE2C_DISABLE_DOWNLOAD AND (NOT RE2C_EXECUTABLE OR NOT _re2cVersionValid) ) - # Set which re2c version to download. - if(NOT RE2C_DOWNLOAD_VERSION) - set(RE2C_DOWNLOAD_VERSION 4.0.2) - endif() set(RE2C_VERSION ${RE2C_DOWNLOAD_VERSION}) - if(NOT TARGET RE2C::RE2C) + if(NOT TARGET RE2C::RE2C AND NOT TARGET re2c) include(ExternalProject) # Configure re2c build. @@ -555,32 +687,3 @@ unset(_re2cVersionValid) if(NOT RE2C_FOUND) return() endif() - -# Check for re2c --computed-gotos option. -if(NOT CMAKE_SCRIPT_MODE_FILE AND RE2C_USE_COMPUTED_GOTOS) - message(CHECK_START "Checking for re2c --computed-gotos (-g) option support") - - cmake_push_check_state(RESET) - set(CMAKE_REQUIRED_QUIET TRUE) - check_source_compiles(C [[ - int main(void) - { - label1: - ; - label2: - ; - static void *adr[] = { &&label1, &&label2 }; - goto *adr[0]; - return 0; - } - ]] _RE2C_HAVE_COMPUTED_GOTOS) - cmake_pop_check_state() - - if(_RE2C_HAVE_COMPUTED_GOTOS) - message(CHECK_PASS "yes") - else() - message(CHECK_FAIL "no") - endif() -elseif(CMAKE_SCRIPT_MODE_FILE AND RE2C_USE_COMPUTED_GOTOS) - set(_RE2C_HAVE_COMPUTED_GOTOS TRUE) -endif() diff --git a/cmake/cmake/modules/PHP/BISON.cmake b/cmake/cmake/modules/PHP/BISON.cmake deleted file mode 100644 index 3e84a4e6..00000000 --- a/cmake/cmake/modules/PHP/BISON.cmake +++ /dev/null @@ -1,57 +0,0 @@ -#[=============================================================================[ -# PHP/BISON - -Wrapper module for using `bison`. - -* `PHP_BISON_OPTIONAL` - - Set to `TRUE` if `bison` is optional and generated parser file is shipped with - the release archive, for example. - -## Basic usage - -```cmake -# CMakeLists.txt - -# Check if bison is required. PHP tarball packaged and released at php.net -# already contains generated lexer and parser files. In such cases these don't -# need to be generated again. When building from a Git repository, bison and -# re2c are required to be installed so files can be generated as part of the -# build process. -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c) - set(PHP_BISON_OPTIONAL TRUE) -endif() -include(PHP/BISON) - -if(BISON_FOUND) - bison(...) -endif() -``` -#]=============================================================================] - -include(FeatureSummary) - -# Minimum required bison version. -set(PHP_BISON_MIN_VERSION 3.0.0) - -# Add Bison --no-lines (-l) option to not generate '#line' directives based on -# this module usage and build type. -if(CMAKE_SCRIPT_MODE_FILE) - set(BISON_DEFAULT_OPTIONS --no-lines) -else() - set(BISON_DEFAULT_OPTIONS $<$:--no-lines>) -endif() - -# Report all warnings. -list(PREPEND BISON_DEFAULT_OPTIONS -Wall) - -find_package(BISON ${PHP_BISON_MIN_VERSION} GLOBAL) - -block() - set(type "") - if(NOT PHP_BISON_OPTIONAL) - set(type TYPE REQUIRED) - endif() - - set_package_properties(BISON PROPERTIES ${type}) -endblock() diff --git a/cmake/cmake/modules/PHP/Package/BISON.cmake b/cmake/cmake/modules/PHP/Package/BISON.cmake new file mode 100644 index 00000000..39fe8e10 --- /dev/null +++ b/cmake/cmake/modules/PHP/Package/BISON.cmake @@ -0,0 +1,47 @@ +#[=============================================================================[ +# PHP/Package/BISON + +PHP-related configuration for using `bison`. + +## Basic usage + +```cmake +# CMakeLists.txt + +include(PHP/Package/BISON) + +# Check if bison is required. PHP released archive from php.net contains +# generated parser files, so these don't need to be regenerated. When building +# from a Git repository, bison is required to generate files during the build. +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c) + set_package_properties(BISON PROPERTIES TYPE REQUIRED) +endif() + +if(BISON_FOUND) + bison(...) +endif() +``` +#]=============================================================================] + +# Minimum required bison version. +set(BISON_FIND_VERSION 3.0.0) + +# Add Bison --no-lines (-l) option to not generate '#line' directives based on +# this module usage and build type. +if(CMAKE_SCRIPT_MODE_FILE) + set(BISON_DEFAULT_OPTIONS --no-lines) +else() + set(BISON_DEFAULT_OPTIONS $<$:--no-lines>) +endif() + +# Report all warnings. +list(PREPEND BISON_DEFAULT_OPTIONS -Wall) + +# Set working directory for all bison invocations. +if(PHP_SOURCE_DIR) + set(BISON_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) +else() + set(BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +find_package(BISON GLOBAL) diff --git a/cmake/cmake/modules/PHP/Package/RE2C.cmake b/cmake/cmake/modules/PHP/Package/RE2C.cmake new file mode 100644 index 00000000..cfe12857 --- /dev/null +++ b/cmake/cmake/modules/PHP/Package/RE2C.cmake @@ -0,0 +1,54 @@ +#[=============================================================================[ +# PHP/Package/RE2C + +PHP-related configuration for using `re2c` to simplify setting minimum required +version at one place and use the package with common settings across the build. + +## Basic usage + +```cmake +# CMakeLists.txt + +include(PHP/Package/RE2C) + +# Check if re2c is required. PHP released archive from php.net contains +# generated lexer files, so these don't need to be regenerated. When building +# from a Git repository, re2c is required to generate files during the build. +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c) + set_package_properties(RE2C PROPERTIES TYPE REQUIRED) +endif() + +if(RE2C_FOUND) + re2c(...) +endif() +``` +#]=============================================================================] + +# Minimum required re2c version. +set(RE2C_FIND_VERSION 1.0.3) + +option(PHP_RE2C_COMPUTED_GOTOS "Enable computed goto GCC extension with re2c") +mark_as_advanced(PHP_RE2C_COMPUTED_GOTOS) + +if(PHP_RE2C_COMPUTED_GOTOS) + set(RE2C_COMPUTED_GOTOS TRUE) +endif() + +# Add --no-debug-info (-i) option to not output line directives. +if(CMAKE_SCRIPT_MODE_FILE) + set(RE2C_DEFAULT_OPTIONS --no-debug-info) +else() + set(RE2C_DEFAULT_OPTIONS $<$:--no-debug-info>) +endif() + +# Suppress date output in the generated file. +list(APPEND RE2C_DEFAULT_OPTIONS --no-generation-date) + +# Set working directory for all re2c invocations. +if(PHP_SOURCE_DIR) + set(RE2C_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) +else() + set(RE2C_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +find_package(RE2C GLOBAL) diff --git a/cmake/cmake/modules/PHP/RE2C.cmake b/cmake/cmake/modules/PHP/RE2C.cmake deleted file mode 100644 index 23a40815..00000000 --- a/cmake/cmake/modules/PHP/RE2C.cmake +++ /dev/null @@ -1,66 +0,0 @@ -#[=============================================================================[ -# PHP/RE2C - -Wrapper module for using `re2c`. It simplifies setting minimum required version -at one place and use the package in modular way across the PHP build system. - -* `PHP_RE2C_OPTIONAL` - - Set to `TRUE` if `re2c` is optional and generated lexer file is shipped with - the release archive, for example. - -## Basic usage - -```cmake -# CMakeLists.txt - -# Check if re2c is required. PHP tarball packaged and released at php.net -# already contains generated lexer and parser files. In such cases these don't -# need to be generated again. When building from a Git repository, bison and -# re2c are required to be installed so files can be generated as part of the -# build process. -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c) - set(PHP_RE2C_OPTIONAL TRUE) -endif() - -# Include the module. -include(PHP/RE2C) - -if(RE2C_FOUND) - re2c(...) -endif() -``` -#]=============================================================================] - -include(FeatureSummary) - -# Minimum required re2c version. -set(PHP_RE2C_MIN_VERSION 1.0.3) - -option(PHP_RE2C_CGOTO "Enable computed goto GCC extension with re2c") -mark_as_advanced(PHP_RE2C_CGOTO) - -if(PHP_RE2C_CGOTO) - set(RE2C_USE_COMPUTED_GOTOS TRUE) -endif() - -# Add --no-debug-info (-i) option to not output line directives. -if(CMAKE_SCRIPT_MODE_FILE) - set(RE2C_DEFAULT_OPTIONS --no-debug-info) -else() - set(RE2C_DEFAULT_OPTIONS $<$:--no-debug-info>) -endif() - -# Suppress date output in the generated file. -list(APPEND RE2C_DEFAULT_OPTIONS --no-generation-date) - -find_package(RE2C ${PHP_RE2C_MIN_VERSION} GLOBAL) - -block() - set(type "") - if(NOT PHP_RE2C_OPTIONAL) - set(type TYPE REQUIRED) - endif() - - set_package_properties(RE2C PROPERTIES ${type}) -endblock() diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake index 6036e5f3..825e7905 100755 --- a/cmake/cmake/scripts/GenerateGrammar.cmake +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -28,15 +28,19 @@ endif() list(APPEND CMAKE_MODULE_PATH ${PHP_SOURCE_DIR}/cmake/modules) -include(PHP/BISON) -include(PHP/RE2C) - include(FeatureSummary) + +include(PHP/Package/BISON) +set_package_properties(BISON PROPERTIES TYPE REQUIRED) + +include(PHP/Package/RE2C) +set_package_properties(RE2C PROPERTIES TYPE REQUIRED) + feature_summary( + DEFAULT_DESCRIPTION FATAL_ON_MISSING_REQUIRED_PACKAGES - WHAT REQUIRED_PACKAGES_NOT_FOUND QUIET_ON_EMPTY - DEFAULT_DESCRIPTION + WHAT REQUIRED_PACKAGES_NOT_FOUND ) file( @@ -49,5 +53,14 @@ foreach(script IN LISTS scripts) cmake_path(GET path PARENT_PATH path) set(CMAKE_CURRENT_SOURCE_DIR ${path}) set(CMAKE_CURRENT_BINARY_DIR ${path}) + + cmake_path( + RELATIVE_PATH + path + BASE_DIRECTORY ${PHP_SOURCE_DIR} + OUTPUT_VARIABLE relativeDir + ) + message(STATUS "Processing ${relativeDir} files") + include(${script}) endforeach() diff --git a/cmake/ext/json/cmake/GenerateGrammar.cmake b/cmake/ext/json/cmake/GenerateGrammar.cmake index e370159c..060e6d94 100644 --- a/cmake/ext/json/cmake/GenerateGrammar.cmake +++ b/cmake/ext/json/cmake/GenerateGrammar.cmake @@ -1,14 +1,16 @@ # Generate lexer and parser files. +include(FeatureSummary) +include(PHP/Package/BISON) +include(PHP/Package/RE2C) + if( - EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h + NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h ) - set(PHP_BISON_OPTIONAL TRUE) + set_package_properties(BISON PROPERTIES TYPE REQUIRED) endif() -include(PHP/BISON) - if(BISON_FOUND) if(CMAKE_SCRIPT_MODE_FILE) set(verbose "") @@ -22,19 +24,17 @@ if(BISON_FOUND) ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c ${verbose} HEADER - #HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h + CODEGEN ) endif() if( - EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h + NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h ) - set(PHP_RE2C_OPTIONAL TRUE) + set_package_properties(RE2C PROPERTIES TYPE REQUIRED) endif() -include(PHP/RE2C) - if(RE2C_FOUND) re2c( php_ext_json_scanner diff --git a/cmake/ext/pdo/cmake/GenerateGrammar.cmake b/cmake/ext/pdo/cmake/GenerateGrammar.cmake index aeb9813f..b04749fb 100644 --- a/cmake/ext/pdo/cmake/GenerateGrammar.cmake +++ b/cmake/ext/pdo/cmake/GenerateGrammar.cmake @@ -1,10 +1,11 @@ # Generate lexer. -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c) - set(PHP_RE2C_OPTIONAL TRUE) -endif() +include(FeatureSummary) +include(PHP/Package/RE2C) -include(PHP/RE2C) +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c) + set_package_properties(RE2C PROPERTIES TYPE REQUIRED) +endif() if(RE2C_FOUND) re2c( diff --git a/cmake/ext/phar/cmake/GenerateGrammar.cmake b/cmake/ext/phar/cmake/GenerateGrammar.cmake index e0034572..4d3ffd01 100644 --- a/cmake/ext/phar/cmake/GenerateGrammar.cmake +++ b/cmake/ext/phar/cmake/GenerateGrammar.cmake @@ -1,10 +1,11 @@ # Generate lexer. -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c) - set(PHP_RE2C_OPTIONAL TRUE) -endif() +include(FeatureSummary) +include(PHP/Package/RE2C) -include(PHP/RE2C) +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c) + set_package_properties(RE2C PROPERTIES TYPE REQUIRED) +endif() if(RE2C_FOUND) re2c( diff --git a/cmake/ext/standard/cmake/GenerateGrammar.cmake b/cmake/ext/standard/cmake/GenerateGrammar.cmake index 478716c7..7b2bee27 100644 --- a/cmake/ext/standard/cmake/GenerateGrammar.cmake +++ b/cmake/ext/standard/cmake/GenerateGrammar.cmake @@ -1,14 +1,15 @@ # Generate lexer files. +include(FeatureSummary) +include(PHP/Package/RE2C) + if( - EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c + NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c ) - set(PHP_RE2C_OPTIONAL TRUE) + set_package_properties(RE2C PROPERTIES TYPE REQUIRED) endif() -include(PHP/RE2C) - if(RE2C_FOUND) re2c( php_ext_standard_url_scanner_ex diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake index 92a023cd..be1ea55d 100644 --- a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -1,19 +1,15 @@ # Generate lexer and parser files. -if(PHP_SOURCE_DIR) - set(workingDirectory ${PHP_SOURCE_DIR}) -else() - set(workingDirectory ${CMAKE_CURRENT_SOURCE_DIR}) -endif() +include(FeatureSummary) +include(PHP/Package/BISON) +include(PHP/Package/RE2C) -# Generate parser files. if( - EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c - AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.h + NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c + OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.h ) - set(PHP_BISON_OPTIONAL TRUE) + set_package_properties(BISON PROPERTIES TYPE REQUIRED) endif() -include(PHP/BISON) if(BISON_FOUND) if(CMAKE_SCRIPT_MODE_FILE) @@ -27,20 +23,14 @@ if(BISON_FOUND) phpdbg_parser.y ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c HEADER - #HEADER_FILE phpdbg_parser.h ${verbose} - WORKING_DIRECTORY ${workingDirectory} + CODEGEN ) endif() -# Generate lexer files. -if( - EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c - AND NOT CMAKE_SCRIPT_MODE_FILE -) - set(PHP_RE2C_OPTIONAL TRUE) +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c) + set_package_properties(RE2C PROPERTIES TYPE REQUIRED) endif() -include(PHP/RE2C) if(RE2C_FOUND) re2c( @@ -49,6 +39,5 @@ if(RE2C_FOUND) ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c OPTIONS -cbdF CODEGEN - WORKING_DIRECTORY ${workingDirectory} ) endif() From c2ddec740acff59206dbe55fd61bcc4675ef140d Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 30 Dec 2024 07:23:48 +0100 Subject: [PATCH 10/15] Use long re2c options and adjust the --conditions The --conditions option is available since re2c 1.1. --- cmake/Zend/cmake/GenerateGrammar.cmake | 21 ++++++++++++------- cmake/cmake/modules/FindRE2C.cmake | 13 ++++++++++++ cmake/ext/json/cmake/GenerateGrammar.cmake | 6 +++--- cmake/ext/phar/cmake/GenerateGrammar.cmake | 2 +- .../ext/standard/cmake/GenerateGrammar.cmake | 4 ++-- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 6 +++++- 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake index 5433802d..e972fb25 100644 --- a/cmake/Zend/cmake/GenerateGrammar.cmake +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -26,14 +26,9 @@ if(BISON_FOUND) ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c HEADER ${verbose} + CODEGEN ) - if(CMAKE_SCRIPT_MODE_FILE) - set(verbose "") - else() - set(verbose VERBOSE) - endif() - bison( zend_language_parser zend_language_parser.y @@ -125,7 +120,12 @@ if(RE2C_FOUND) zend_ini_scanner.l ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h - OPTIONS --case-inverted -cbdF + OPTIONS + --case-inverted + --conditions + --bit-vectors + --debug-output + --flex-syntax CODEGEN ) @@ -134,7 +134,12 @@ if(RE2C_FOUND) zend_language_scanner.l ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h - OPTIONS --case-inverted -cbdF + OPTIONS + --case-inverted + --conditions + --bit-vectors + --debug-output + --flex-syntax CODEGEN ) endif() diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index 07d9a2bd..f78855f1 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -431,6 +431,19 @@ function(_re2c_process_options options result) list(PREPEND options ${RE2C_DEFAULT_OPTIONS}) endif() + # Remove any generator expressions when running in script mode. + if(CMAKE_SCRIPT_MODE_FILE) + list(TRANSFORM options GENEX_STRIP) + endif() + + # Sync long -c variants. The long --conditions option was introduced in re2c + # version 1.1 as a new alias for the legacy --start-conditions. + if(RE2C_VERSION VERSION_LESS 1.1) + list(TRANSFORM options REPLACE "^--conditions$" "--start-conditions") + else() + list(TRANSFORM options REPLACE "^--start-conditions$" "--conditions") + endif() + set(${result} ${options}) return(PROPAGATE ${result}) diff --git a/cmake/ext/json/cmake/GenerateGrammar.cmake b/cmake/ext/json/cmake/GenerateGrammar.cmake index 060e6d94..72231518 100644 --- a/cmake/ext/json/cmake/GenerateGrammar.cmake +++ b/cmake/ext/json/cmake/GenerateGrammar.cmake @@ -15,15 +15,15 @@ if(BISON_FOUND) if(CMAKE_SCRIPT_MODE_FILE) set(verbose "") else() - set(verbose VERBOSE) #REPORT_FILE json_parser.output) + set(verbose VERBOSE) endif() bison( php_ext_json_parser json_parser.y ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c - ${verbose} HEADER + ${verbose} CODEGEN ) endif() @@ -41,7 +41,7 @@ if(RE2C_FOUND) json_scanner.re ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h - OPTIONS -bc + OPTIONS --bit-vectors --conditions CODEGEN ) endif() diff --git a/cmake/ext/phar/cmake/GenerateGrammar.cmake b/cmake/ext/phar/cmake/GenerateGrammar.cmake index 4d3ffd01..6243a3b7 100644 --- a/cmake/ext/phar/cmake/GenerateGrammar.cmake +++ b/cmake/ext/phar/cmake/GenerateGrammar.cmake @@ -12,7 +12,7 @@ if(RE2C_FOUND) php_ext_phar_path_check phar_path_check.re ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c - OPTIONS -b + OPTIONS --bit-vectors CODEGEN ) endif() diff --git a/cmake/ext/standard/cmake/GenerateGrammar.cmake b/cmake/ext/standard/cmake/GenerateGrammar.cmake index 7b2bee27..ba572038 100644 --- a/cmake/ext/standard/cmake/GenerateGrammar.cmake +++ b/cmake/ext/standard/cmake/GenerateGrammar.cmake @@ -15,7 +15,7 @@ if(RE2C_FOUND) php_ext_standard_url_scanner_ex url_scanner_ex.re ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c - OPTIONS -b + OPTIONS --bit-vectors CODEGEN ) @@ -23,7 +23,7 @@ if(RE2C_FOUND) php_ext_standard_var_unserializer var_unserializer.re ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c - OPTIONS -b + OPTIONS --bit-vectors CODEGEN ) endif() diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake index be1ea55d..1a8cef02 100644 --- a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -37,7 +37,11 @@ if(RE2C_FOUND) php_sapi_phpdbg_lexer phpdbg_lexer.l ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c - OPTIONS -cbdF + OPTIONS + --conditions + --debug-output + --bit-vectors + --flex-syntax CODEGEN ) endif() From 45ea85227a2705ca4d875336156b3d4b946a88ae Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Sun, 5 Jan 2025 22:33:44 +0100 Subject: [PATCH 11/15] Refactor RE2C and BISON find modules Find modules are not meant to provide functions. This is an edge bad practice learned from some existing modules out there for convenience. Find modules should ideally only deal with finding packages and providing the imported targets. Ideally, how the package is used should be done in some wrapper module, which provides these functions. Here, the php_bison() and php_re2c(). Also, downloading is moved to these modules for now. --- cmake/Zend/cmake/GenerateGrammar.cmake | 246 +++--- cmake/cmake/modules/FindBISON.cmake | 698 +--------------- cmake/cmake/modules/FindRE2C.cmake | 681 +--------------- cmake/cmake/modules/PHP/Bison.cmake | 750 ++++++++++++++++++ cmake/cmake/modules/PHP/Package/BISON.cmake | 47 -- cmake/cmake/modules/PHP/Package/RE2C.cmake | 54 -- cmake/cmake/modules/PHP/Re2c.cmake | 744 +++++++++++++++++ cmake/cmake/scripts/GenerateGrammar.cmake | 8 +- cmake/ext/json/cmake/GenerateGrammar.cmake | 62 +- cmake/ext/pdo/cmake/GenerateGrammar.cmake | 23 +- cmake/ext/phar/cmake/GenerateGrammar.cmake | 25 +- .../ext/standard/cmake/GenerateGrammar.cmake | 42 +- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 68 +- 13 files changed, 1755 insertions(+), 1693 deletions(-) create mode 100644 cmake/cmake/modules/PHP/Bison.cmake delete mode 100644 cmake/cmake/modules/PHP/Package/BISON.cmake delete mode 100644 cmake/cmake/modules/PHP/Package/RE2C.cmake create mode 100644 cmake/cmake/modules/PHP/Re2c.cmake diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake index e972fb25..10a4474d 100644 --- a/cmake/Zend/cmake/GenerateGrammar.cmake +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -1,145 +1,129 @@ # Generate lexer and parser files. -include(FeatureSummary) -include(PHP/Package/BISON) -include(PHP/Package/RE2C) +if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) + message(FATAL_ERROR "This file should be used with include().") +endif() -if( - NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.h - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.h -) - set_package_properties(BISON PROPERTIES TYPE REQUIRED) +include(PHP/Bison) + +if(CMAKE_SCRIPT_MODE_FILE) + set(verbose "") +else() + set(verbose VERBOSE) endif() -if(BISON_FOUND) - if(CMAKE_SCRIPT_MODE_FILE) - set(verbose "") - else() - set(verbose VERBOSE) - endif() +php_bison( + zend_ini_parser + zend_ini_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c + HEADER + ${verbose} + CODEGEN +) - bison( - zend_ini_parser - zend_ini_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c - HEADER - ${verbose} - CODEGEN - ) +php_bison( + zend_language_parser + zend_language_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c + HEADER + ${verbose} + CODEGEN +) - bison( - zend_language_parser - zend_language_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c - HEADER - ${verbose} - CODEGEN - ) +# Tweak zendparse to be exported through ZEND_API. This has to be revisited +# once bison supports foreign skeletons and that bison version is used. Read +# https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more. +block() + string( + CONCAT patch + "cmake_path(SET SOURCE_DIR NORMALIZE ${CMAKE_CURRENT_SOURCE_DIR})\n" + [[ + cmake_path( + RELATIVE_PATH + SOURCE_DIR + BASE_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE relativeDir + ) + file(READ "${SOURCE_DIR}/zend_language_parser.h" content) + string( + REPLACE + "int zendparse" + "ZEND_API int zendparse" + content_2 + "${content}" + ) + if( + NOT content MATCHES "ZEND_API int zendparse" + AND NOT content STREQUAL "${content_2}" + ) + message(STATUS "Patching ${relativeDir}/zend_language_parser.h") + file(WRITE "${SOURCE_DIR}/zend_language_parser.h" "${content_2}") + endif() - # Tweak zendparse to be exported through ZEND_API. This has to be revisited - # once bison supports foreign skeletons and that bison version is used. Read - # https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more. - block() + file(READ "${SOURCE_DIR}/zend_language_parser.c" content) string( - CONCAT patch - "cmake_path(SET SOURCE_DIR NORMALIZE ${CMAKE_CURRENT_SOURCE_DIR})\n" - [[ - cmake_path( - RELATIVE_PATH - SOURCE_DIR - BASE_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE relativeDir - ) - file(READ "${SOURCE_DIR}/zend_language_parser.h" content) - string( - REPLACE - "int zendparse" - "ZEND_API int zendparse" - content_2 - "${content}" - ) - if( - NOT content MATCHES "ZEND_API int zendparse" - AND NOT content STREQUAL "${content_2}" - ) - message(STATUS "Patching ${relativeDir}/zend_language_parser.h") - file(WRITE "${SOURCE_DIR}/zend_language_parser.h" "${content_2}") - endif() + REPLACE + "int zendparse" + "ZEND_API int zendparse" + content_2 + "${content}" + ) + if( + NOT content MATCHES "ZEND_API int zendparse" + AND NOT content STREQUAL "${content_2}" + ) + message(STATUS "Patching ${relativeDir}/zend_language_parser.c") + file(WRITE "${SOURCE_DIR}/zend_language_parser.c" "${content_2}") + endif() + ]]) - file(READ "${SOURCE_DIR}/zend_language_parser.c" content) - string( - REPLACE - "int zendparse" - "ZEND_API int zendparse" - content_2 - "${content}" - ) - if( - NOT content MATCHES "ZEND_API int zendparse" - AND NOT content STREQUAL "${content_2}" - ) - message(STATUS "Patching ${relativeDir}/zend_language_parser.c") - file(WRITE "${SOURCE_DIR}/zend_language_parser.c" "${content_2}") - endif() - ]]) + # Run patch based on whether building or running inside a CMake script. + if(CMAKE_SCRIPT_MODE_FILE) + cmake_language(EVAL CODE "${patch}") + else() + file( + GENERATE + OUTPUT CMakeFiles/Zend/PatchLanguageParser.cmake + CONTENT "${patch}" + ) + add_custom_target( + zend_language_parser_patch + COMMAND ${CMAKE_COMMAND} -P CMakeFiles/Zend/PatchLanguageParser.cmake + DEPENDS zend_language_parser + VERBATIM + ) + add_dependencies(zend zend_language_parser_patch) + endif() +endblock() - # Run patch based on whether building or running inside a CMake script. - if(CMAKE_SCRIPT_MODE_FILE) - cmake_language(EVAL CODE "${patch}") - else() - file( - GENERATE - OUTPUT CMakeFiles/Zend/PatchLanguageParser.cmake - CONTENT "${patch}" - ) - add_custom_target( - zend_language_parser_patch - COMMAND ${CMAKE_COMMAND} -P CMakeFiles/Zend/PatchLanguageParser.cmake - DEPENDS zend_language_parser - VERBATIM - ) - add_dependencies(zend zend_language_parser_patch) - endif() - endblock() -endif() +include(PHP/Re2c) -if( - NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h +php_re2c( + zend_ini_scanner + zend_ini_scanner.l + ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h + APPEND + OPTIONS + --bit-vectors + --case-inverted + --conditions + --debug-output + --flex-syntax + CODEGEN ) - set_package_properties(RE2C PROPERTIES TYPE REQUIRED) -endif() - -if(RE2C_FOUND) - re2c( - zend_ini_scanner - zend_ini_scanner.l - ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h - OPTIONS - --case-inverted - --conditions - --bit-vectors - --debug-output - --flex-syntax - CODEGEN - ) - re2c( - zend_language_scanner - zend_language_scanner.l - ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h - OPTIONS - --case-inverted - --conditions - --bit-vectors - --debug-output - --flex-syntax - CODEGEN - ) -endif() +php_re2c( + zend_language_scanner + zend_language_scanner.l + ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h + APPEND + OPTIONS + --bit-vectors + --case-inverted + --conditions + --debug-output + --flex-syntax + CODEGEN +) diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake index 79a2ecdf..0ba6063b 100644 --- a/cmake/cmake/modules/FindBISON.cmake +++ b/cmake/cmake/modules/FindBISON.cmake @@ -3,695 +3,23 @@ Find `bison`, the general-purpose parser generator, command-line executable. -This is a standalone and customized find module for finding bison. It is synced -with CMake FindBISON module, where possible. -See also: https://cmake.org/cmake/help/latest/module/FindBISON.html - -## Result variables - -* `BISON_FOUND` - Whether the `bison` was found. -* `BISON_VERSION` - The `bison` version. - -## Cache variables - -* `BISON_EXECUTABLE` - Path to the `bison`. - -## Hints - -These variables can be set before calling the `find_package(BISON)`: - -* `BISON_DEFAULT_OPTIONS` - A semicolon-separated list of default global bison - options to be prepended to `bison(OPTIONS)` argument for all bison invocations - when generating parser files. - -* `BISON_DISABLE_DOWNLOAD` - Set to `TRUE` to disable downloading and building - bison package from source, when it is not found on the system or found version - is not suitable. - -* `BISON_DOWNLOAD_VERSION` - Override the default `bison` version to be - downloaded when not found on the system. - -* `BISON_WORKING_DIRECTORY` - Set the default global working directory - (`WORKING_DIRECTORY ` option) for all `bison()` invocations in the scope - of `find_package(BISON)`. - -## Functions provided by this module - -### `bison()` - -Generate parser file `` from the given `` template file using the -`bison` parser generator. - -```cmake -bison( - - - - [HEADER | HEADER_FILE
] - [OPTIONS ...] - [DEPENDS ...] - [VERBOSE [REPORT_FILE ]] - [NO_DEFAULT_OPTIONS] - [CODEGEN] - [WORKING_DIRECTORY ] - [ABSOLUTE_PATHS] -) -``` - -This creates a custom CMake target `` and adds a custom command that -generates parser file `` from the given `` template file using -the `bison` parser generator. Relative source file path `` is interpreted -as being relative to the current source directory. Relative `` file path -is interpreted as being relative to the current binary directory. If `bison` is -not a required package and it is not found, it will create a custom target but -skip the `bison` command execution. - -When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it -simply generates the parser without creating a target, to make it easier to use -in various scenarios. - -#### Options - -* `HEADER` - Produce also a header file automatically. - -* `HEADER_FILE
` - Produce a header as a specified file `
`. - Relative header file path is interpreted as being relative to the current - binary directory. - -* `OPTIONS ...` - Optional list of additional options to pass to the - bison command-line tool. - -* `DEPENDS ...` - Optional list of dependent files to regenerate the - output file. - -* `VERBOSE` - This adds the `--verbose` (`-v`) command-line option to - `bison` executable and will create extra output file - `.output` containing verbose descriptions of the - grammar and parser. File will be created in the current binary directory. - -* `REPORT_FILE ` - This adds the `--report-file=` command-line - option to `bison` executable and will create verbose information report in the - specified ``. This option must be used together with the `VERBOSE` - option. Relative file path is interpreted as being relative to the current - binary directory. - -* `NO_DEFAULT_OPTIONS` - If specified, the `BISON_DEFAULT_OPTIONS` are not added - to the current `bison` invocation. - -* `CODEGEN` - Adds the `CODEGEN` option to the bison's `add_custom_command()` - call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which - provides a global CMake `codegen` target for convenience to call only the - code-generation-related targets and skips the majority of the build: - - ```sh - cmake --build --target codegen - ``` - -* `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `bison` - command-line invocations. By default all file paths are added to `bison` - command-line relative to the working directory. Using relative paths is - convenient when line directives (`#line ...`) are generated in the output - parser files to not show the full path on the disk, when file is committed to - Git repository, where multiple people develop. - - When this option is enabled: - - ```c - #line 15 "/home/user/projects/php-src/sapi/phpdbg/phpdbg_parser.y" - ``` - - Without this option, relative paths will be generated: - - ```c - #line 15 "sapi/phpdbg/phpdbg_parser.y" - ``` - -* `WORKING_DIRECTORY ` - The path where the `bison` command - is executed. Relative `` path is interpreted as being - relative to the current binary directory. If not set, `bison` is by default - executed in the current binary directory (`CMAKE_CURRENT_BINARY_DIR`). If - variable `BISON_WORKING_DIRECTORY` is set before calling the - `find_package(BISON)`, it will set the default working directory. - -## Examples - -### Minimum bison version - -The minimum required `bison` version can be specified using the standard CMake -syntax, e.g. - -```cmake -# CMakeLists.txt - -find_package(BISON 3.0.0) -``` - -### Running bison - -```cmake -# CMakeLists.txt - -find_package(BISON) - -# Commands provided by find modules must be called conditionally, because user -# can also disable the find module with CMAKE_DISABLE_FIND_PACKAGE_BISON. -if(BISON_FOUND) - bison(...) -endif() -``` - -### Specifying options - -Setting default options for all `bison()` calls in the scope of the -`find_package(BISON)`: - -```cmake -# CMakeLists.txt - -# Optionally, set default options for all bison invocations. For example, add -# option to suppress date output in the generated file: -set(BISON_DEFAULT_OPTIONS -Wall --no-lines) - -find_package(BISON) - -# This will execute bison as: -# bison -Wall --no-lines -d foo.y --output foo.c -if(BISON_FOUND) - bison(foo foo.y foo.c OPTIONS -d) -endif() - -# This will execute bison as: -# bison -l bar.y --output bar.c -if(BISON_FOUND) - bison(bar bar.y bar.c OPTIONS -l) -endif() -``` - -Generator expressions are supported in `bison(OPTIONS)` when running it in the -`project()` mode: - -```cmake -# CMakeLists.txt - -find_package(BISON) - -if(BISON_FOUND) - bison(foo foo.y foo.c OPTIONS $<$:--no-lines>) -endif() -``` - -### Custom target usage - -To specify dependencies with the custom target created by `bison()`: - -```cmake -# CMakeLists.txt - -find_package(BISON) - -if(BISON_FOUND) - bison(foo_parser parser.y parser.c) - add_dependencies(some_target foo_parser) -endif() -``` - -Or to run only the specific `foo_parser` target, which generates the parser. - -```sh -cmake --build --target foo_parser -``` - -### Script mode - -When running `bison()` in script mode: - -```sh -cmake -P script.cmake -``` - -the generated file is created right away: - -```cmake -# script.cmake - -find_package(BISON REQUIRED) - -if(BISON_FOUND) - bison(parser.y parser.c) -endif() -``` +This module extends the upstream CMake `FindBISON` module. +See: https://cmake.org/cmake/help/latest/module/FindBISON.html #]=============================================================================] include(FeatureSummary) -include(FindPackageHandleStandardArgs) - -################################################################################ -# Configuration. -################################################################################ - -# If Bison is not found on the system, set which version to download. -if(NOT BISON_DOWNLOAD_VERSION) - set(BISON_DOWNLOAD_VERSION 3.8.2) -endif() - -################################################################################ -# Functions. -################################################################################ - -function(bison) - cmake_parse_arguments( - PARSE_ARGV - 3 - parsed # prefix - "NO_DEFAULT_OPTIONS;CODEGEN;HEADER;VERBOSE;ABSOLUTE_PATHS" # options - "HEADER_FILE;WORKING_DIRECTORY;REPORT_FILE" # one-value keywords - "OPTIONS;DEPENDS" # multi-value keywords - ) - - _bison_process(${ARGN}) - - if(NOT CMAKE_SCRIPT_MODE_FILE) - add_custom_target(${ARGV0} SOURCES ${input} DEPENDS ${outputs}) - endif() - - # Skip generation, if generated files are provided by the release archive. - get_property(type GLOBAL PROPERTY _CMAKE_BISON_TYPE) - if(NOT BISON_FOUND AND NOT BISON_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") - return() - endif() - - if(CMAKE_SCRIPT_MODE_FILE) - message(STATUS "[BISON] ${message}") - execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) - return() - endif() - - set(codegen "") - if( - parsed_CODEGEN - AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 - AND POLICY CMP0171 - ) - cmake_policy(GET CMP0171 cmp0171) - - if(cmp0171 STREQUAL "NEW") - set(codegen CODEGEN) - endif() - endif() - - add_custom_command( - OUTPUT ${outputs} - ${commands} - DEPENDS - ${input} - ${parsed_DEPENDS} - $ - $ - COMMENT "[BISON][${ARGV0}] ${message}" - VERBATIM - COMMAND_EXPAND_LISTS - ${codegen} - WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} - ) -endfunction() - -# Process arguments. -macro(_bison_process) - if(parsed_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Unrecognized arguments: ${parsed_UNPARSED_ARGUMENTS}") - endif() - - if(parsed_KEYWORDS_MISSING_VALUES) - message(FATAL_ERROR "Missing values for: ${parsed_KEYWORDS_MISSING_VALUES}") - endif() - - if(parsed_HEADER AND parsed_HEADER_FILE) - message( - AUTHOR_WARNING - "When 'HEADER_FILE' is specified, remove redundant 'HEADER' option." - ) - endif() - - if(parsed_REPORT_FILE AND NOT parsed_VERBOSE) - message(FATAL_ERROR "'REPORT_FILE' option requires also 'VERBOSE' option.") - endif() - - set(input ${ARGV1}) - if(NOT IS_ABSOLUTE "${input}") - set(input ${CMAKE_CURRENT_SOURCE_DIR}/${input}) - endif() - cmake_path(SET input NORMALIZE "${input}") - - set(output ${ARGV2}) - if(NOT IS_ABSOLUTE "${output}") - cmake_path( - ABSOLUTE_PATH - output - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - endif() - cmake_path(SET output NORMALIZE "${output}") - - set(outputs ${output}) - - _bison_set_working_directory() - _bison_process_options(parsed_OPTIONS options) - _bison_process_header_option() - _bison_process_verbose_option() - - if(parsed_ABSOLUTE_PATHS) - set(inputArgument "${input}") - set(outputArgument "${output}") - else() - cmake_path( - RELATIVE_PATH - input - BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} - OUTPUT_VARIABLE inputArgument - ) - cmake_path( - RELATIVE_PATH - output - BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} - OUTPUT_VARIABLE outputArgument - ) - endif() - - # Assemble commands for add_custom_command() and execute_process(). - set(commands "") - - # Bison cannot create output directories. Ensure any required directories for - # the generated files are created if they don't already exist. - set(directories "") - foreach(output IN LISTS outputs) - cmake_path(GET output PARENT_PATH dir) - if(dir) - list(APPEND directories ${dir}) - endif() - endforeach() - if(directories) - list(REMOVE_DUPLICATES directories) - list( - APPEND - commands - COMMAND ${CMAKE_COMMAND} -E make_directory ${directories} - ) - endif() - - list( - APPEND - commands - COMMAND - ${BISON_EXECUTABLE} - ${options} - ${inputArgument} - --output ${outputArgument} - ) - - # Assemble status message. - cmake_path( - RELATIVE_PATH - output - BASE_DIRECTORY ${CMAKE_BINARY_DIR} - OUTPUT_VARIABLE outputRelative - ) - - set(message "Generating ${outputRelative} with bison ${BISON_VERSION}") -endmacro() - -# Process options. -function(_bison_process_options options result) - set(options ${${options}}) - - if(BISON_DEFAULT_OPTIONS AND NOT parsed_NO_DEFAULT_OPTIONS) - list(PREPEND options ${BISON_DEFAULT_OPTIONS}) - endif() - - set(${result} ${options}) - - return(PROPAGATE ${result}) -endfunction() - -# Process HEADER and HEADER_FILE options. -function(_bison_process_header_option) - if(NOT parsed_HEADER AND NOT parsed_HEADER_FILE) - return() - endif() - - # Bison versions 3.8 and later introduced the --header=[FILE] (-H) option. - # For prior versions the --defines=[FILE] (-d) option can be used. - if(parsed_HEADER_FILE) - set(header ${parsed_HEADER_FILE}) - if(NOT IS_ABSOLUTE "${header}") - cmake_path( - ABSOLUTE_PATH - header - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - endif() - - if(parsed_ABSOLUTE_PATHS) - set(headerArgument "${header}") - else() - cmake_path( - RELATIVE_PATH - header - BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} - OUTPUT_VARIABLE headerArgument - ) - endif() - - if(BISON_VERSION VERSION_LESS 3.8) - list(APPEND options --defines=${headerArgument}) - else() - list(APPEND options --header=${headerArgument}) - endif() - else() - if(BISON_VERSION VERSION_LESS 3.8) - list(APPEND options -d) - else() - list(APPEND options --header) - endif() - - # Produce default header path generated by bison (see option --header). - cmake_path(GET output EXTENSION LAST_ONLY extension) - string(REPLACE "c" "h" extension "${extension}") - if(NOT extension) - set(extension ".h") - endif() - cmake_path( - REPLACE_EXTENSION - output - LAST_ONLY - "${extension}" - OUTPUT_VARIABLE header - ) - endif() - - list(APPEND outputs ${header}) - - return(PROPAGATE outputs options) -endfunction() - -# Process the VERBOSE and REPORT_FILE options. -function(_bison_process_verbose_option) - if(NOT parsed_VERBOSE) - return() - endif() - - list(APPEND options --verbose) - - if(NOT parsed_REPORT_FILE) - cmake_path(GET output FILENAME reportFile) - cmake_path(GET output EXTENSION extension) - - # Bison treats output files .tab. - # differently. It removes the '.tab' part of the extension and creates - # .output file. Elsewhere, it replaces only the - # last extension with '.output'. - if(extension MATCHES "\\.tab\\.([^.]+)$") - string( - REGEX REPLACE - "\\.tab\\.${CMAKE_MATCH_1}$" - ".output" - reportFile - "${reportFile}" - ) - else() - cmake_path(REPLACE_EXTENSION reportFile LAST_ONLY "output") - endif() - else() - set(reportFile ${parsed_REPORT_FILE}) - endif() - - if(NOT IS_ABSOLUTE "${reportFile}") - cmake_path( - ABSOLUTE_PATH - reportFile - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - endif() - - list(APPEND options --report-file=${reportFile}) - - return(PROPAGATE options) -endfunction() - -# Set or adjust the parsed_WORKING_DIRECTORY. -function(_bison_set_working_directory) - if(NOT parsed_WORKING_DIRECTORY) - if(BISON_WORKING_DIRECTORY) - set(parsed_WORKING_DIRECTORY ${BISON_WORKING_DIRECTORY}) - else() - set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - endif() - endif() - - if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") - cmake_path( - ABSOLUTE_PATH - parsed_WORKING_DIRECTORY - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - endif() - - return(PROPAGATE parsed_WORKING_DIRECTORY) -endfunction() - -################################################################################ -# Package definition. -################################################################################ - -block() - cmake_path( - RELATIVE_PATH - CMAKE_CURRENT_SOURCE_DIR - BASE_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE relativeDir - ) - - if(relativeDir STREQUAL ".") - set(purpose "Necessary to generate parser files.") - else() - set(purpose "Necessary to generate ${relativeDir} parser files.") - endif() - - set_package_properties( - BISON - PROPERTIES - URL "https://www.gnu.org/software/bison/" - DESCRIPTION "General-purpose parser generator" - PURPOSE "${purpose}" - ) -endblock() - -################################################################################ -# Find the executable. -################################################################################ - -find_program( - BISON_EXECUTABLE - NAMES bison win-bison win_bison - DOC "The path to the bison executable" -) -mark_as_advanced(BISON_EXECUTABLE) - -################################################################################ -# Version. -################################################################################ - -block(PROPAGATE BISON_VERSION _bisonVersionValid) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) - set(test IS_EXECUTABLE) - else() - set(test EXISTS) - endif() - - if(${test} ${BISON_EXECUTABLE}) - execute_process( - COMMAND ${BISON_EXECUTABLE} --version - OUTPUT_VARIABLE versionOutput - ERROR_VARIABLE error - RESULT_VARIABLE result - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if(NOT result EQUAL 0) - message( - SEND_ERROR - "Command \"${BISON_EXECUTABLE} --version\" failed with output:\n" - "${error}" - ) - elseif(versionOutput) - # Bison++ - if(vesionOutput MATCHES "^bison\\+\\+ Version ([^,]+)") - set(BISON_VERSION "${CMAKE_MATCH_1}") - # GNU Bison - elseif(versionOutput MATCHES "^bison \\(GNU Bison\\) ([^\n]+)\n") - set(BISON_VERSION "${CMAKE_MATCH_1}") - elseif(versionOutput MATCHES "^GNU Bison (version )?([^\n]+)") - set(BISON_VERSION "${CMAKE_MATCH_2}") - endif() - - find_package_check_version("${BISON_VERSION}" _bisonVersionValid) - endif() - endif() -endblock() - -################################################################################ -# Download and build the package. -################################################################################ - -set(_bisonRequiredVars "") - -if( - NOT CMAKE_SCRIPT_MODE_FILE - AND NOT BISON_DISABLE_DOWNLOAD - AND (NOT BISON_EXECUTABLE OR NOT _bisonVersionValid) - AND FALSE # TODO: Integrate building Bison from source. -) - set(BISON_VERSION ${BISON_DOWNLOAD_VERSION}) - - if(NOT TARGET Bison::Bison AND NOT TARGET bison) - include(ExternalProject) - - ExternalProject_Add( - bison - URL https://ftp.gnu.org/gnu/bison/bison-${BISON_VERSION}.tar.gz - CONFIGURE_COMMAND /configure - BUILD_COMMAND make - INSTALL_COMMAND "" - ) - - # Set bison executable. - ExternalProject_Get_property(bison BINARY_DIR) - add_executable(Bison::Bison IMPORTED) - set_target_properties( - Bison::Bison - PROPERTIES IMPORTED_LOCATION ${BINARY_DIR}/bison - ) - add_dependencies(Bison::Bison bison) - set_property(CACHE BISON_EXECUTABLE PROPERTY VALUE ${BINARY_DIR}/bison) - unset(BINARY_DIR) - endif() - - set(_bisonRequiredVars _bisonMsg) - set(_bisonMsg "downloading at build") -endif() -find_package_handle_standard_args( +set_package_properties( BISON - REQUIRED_VARS ${_bisonRequiredVars} BISON_EXECUTABLE BISON_VERSION - VERSION_VAR BISON_VERSION - HANDLE_VERSION_RANGE - REASON_FAILURE_MESSAGE - "The Bison executable not found. Please install Bison parser generator." + PROPERTIES + URL "https://www.gnu.org/software/bison/" + DESCRIPTION "General-purpose parser generator" ) -unset(_bisonMsg) -unset(_bisonRequiredVars) -unset(_bisonVersionValid) +# Find package with upstream CMake module; override CMAKE_MODULE_PATH to prevent +# the maximum nesting/recursion depth error on some systems, like macOS. +set(_php_cmake_module_path ${CMAKE_MODULE_PATH}) +unset(CMAKE_MODULE_PATH) +include(FindBISON) +set(CMAKE_MODULE_PATH ${_php_cmake_module_path}) +unset(_php_cmake_module_path) diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index f78855f1..406c1a67 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -3,11 +3,6 @@ Find `re2c` command-line lexer generator. -When `re2c` cannot be found on the system or the found version is not suitable, -this module can also download and build it from its Git repository sources -release archive as part of the project build using the `ExternalProject` CMake -module. - ## Result variables * `RE2C_FOUND` - Whether the `re2c` was found. @@ -15,235 +10,9 @@ module. ## Cache variables -* `RE2C_EXECUTABLE` - Path to the `re2c`. When `re2c` is downloaded and built - from source, this path is autofilled to point to the built `re2c` executable. - Note, that the `re2c` executable built from source will not exist until the - build phase. - -## Hints - -These variables can be set before calling the `find_package(RE2C)`: - -* `RE2C_COMPUTED_GOTOS` - Add the `COMPUTED_GOTOS TRUE` option to all `re2c()` - invocations in the scope of `find_package(RE2C)`. - -* `RE2C_DEFAULT_OPTIONS` - A semicolon-separated list of default global `re2c` - options to be prepended to `re2c(OPTIONS)` argument for all re2c invocations - when generating lexer files. - -* `RE2C_DISABLE_DOWNLOAD` - Set to `TRUE` to disable downloading and building - RE2C package from source, when it is not found on the system or found version - is not suitable. - -* `RE2C_DOWNLOAD_VERSION` - Override the default `re2c` version to be downloaded - when not found on the system. - -* `RE2C_WORKING_DIRECTORY` - Set the default global working directory - (`WORKING_DIRECTORY ` option) for all `re2c()` invocations in the scope of - `find_package(RE2C)`. - -## Functions provided by this module - -### `re2c()` - -Generate lexer file `` from the given `` template file using the -`re2c` lexer generator. - -```cmake -re2c( - - - - [HEADER
] - [OPTIONS ...] - [DEPENDS ...] - [NO_DEFAULT_OPTIONS] - [COMPUTED_GOTOS ] - [CODEGEN] - [WORKING_DIRECTORY ] - [ABSOLUTE_PATHS] -) -``` - -This creates a custom CMake target `` and adds a custom command that -generates lexer file `` from the given `` template file using the -`re2c` lexer generator. Relative source file path `` is interpreted as -being relative to the current source directory. Relative `` file path is -interpreted as being relative to the current binary directory. If `re2c` is not -a required package and it is not found, it will create a custom target but skip -the `re2c` command execution. - -When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it -simply generates the lexer without creating a target, to make it easier to use -in various scenarios. - -#### Options - -* `HEADER
` - Generate a given `
` file. Relative header file - path is interpreted as being relative to the current binary directory. - -* `OPTIONS ...` - Optional list of additional options to pass to the - re2c command-line tool. - -* `DEPENDS ...` - Optional list of dependent files to regenerate the - output file. - -* `NO_DEFAULT_OPTIONS` - If specified, the `RE2C_DEFAULT_OPTIONS` are not added - to the current `re2c` invocation. - -* `COMPUTED_GOTOS ` - Set to `TRUE` to add the re2c - `--computed-gotos` (`-g`) command-line option if the non-standard C computed - goto extension is supported by the C compiler. When calling `re2c()` in the - command-line script mode (`CMAKE_SCRIPT_MODE`), option is not checked, whether - the compiler supports it and is added to `re2c` command-line options - unconditionally. - -* `CODEGEN` - Adds the `CODEGEN` option to the re2c's `add_custom_command()` - call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which - provides a global CMake `codegen` target for convenience to call only the - code-generation-related targets and skips the majority of the build: - - ```sh - cmake --build --target codegen - ``` - -* `WORKING_DIRECTORY ` - The path where the `re2c` command is - executed. Relative `` path is interpreted as being relative - to the current binary directory. If not set, `re2c` is by default executed in - the current binary directory (`CMAKE_CURRENT_BINARY_DIR`). If variable - `RE2C_WORKING_DIRECTORY` is set before calling the `find_package(RE2C)`, it - will set the default working directory. - -* `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `re2c` - command-line invocations. By default all file paths are added to `re2c` - command-line relative to the working directory. Using relative paths is - convenient when line directives (`#line ...`) are generated in the output - lexer files to not show the full path on the disk, when file is committed to - Git repository, where multiple people develop. - - When this option is enabled: - - ```c - #line 108 "/home/user/projects/php-src/ext/phar/phar_path_check.c" - ``` - - Without this option, relative paths will be generated: - - ```c - #line 108 "ext/phar/phar_path_check.c" - ``` - -## Examples - -### Minimum re2c version - -The minimum required `re2c` version can be specified using the standard CMake -syntax, e.g. - -```cmake -# CMakeLists.txt - -find_package(RE2C 1.0.3) -``` - -### Running re2c - -```cmake -# CMakeLists.txt - -find_package(RE2C) - -# Commands provided by find modules must be called conditionally, because user -# can also disable the find module with CMAKE_DISABLE_FIND_PACKAGE_RE2C. -if(RE2C_FOUND) - re2c(...) -endif() -``` - -### Specifying options - -Setting default options for all `re2c()` calls in the scope of the -`find_package(RE2C)`: - -```cmake -# CMakeLists.txt - -# Optionally, set default options for all re2c invocations. For example, add -# option to suppress date output in the generated file: -set(RE2C_DEFAULT_OPTIONS --no-generation-date) - -find_package(RE2C) - -# This will execute re2c as: -# re2c --no-generation-date --bit-vectors --conditions --output foo.c foo.re -if(RE2C_FOUND) - re2c(foo foo.re foo.c OPTIONS --bit-vectors --conditions) -endif() - -# This will execute re2c as: -# re2c --no-generation-date --case-inverted --output bar.c bar.re -if(RE2C_FOUND) - re2c(bar bar.re bar.c OPTIONS --case-inverted) -endif() -``` - -Generator expressions are supported in `re2c(OPTIONS)` when using it in the -`project()` mode: - -```cmake -# CMakeLists.txt - -find_package(RE2C) - -if(RE2C_FOUND) - re2c(foo foo.re foo.c OPTIONS $<$:--debug-output>) -endif() -``` - -### Custom target usage - -To specify dependencies with the custom target created by `re2c()`: - -```cmake -# CMakeLists.txt - -find_package(RE2C) - -if(RE2C_FOUND) - re2c(foo_lexer lexer.re lexer.c) - add_dependencies(some_target foo_lexer) -endif() -``` - -Or to run only the specific `foo_lexer` target, which generates the lexer. - -```sh -cmake --build --target foo_lexer -``` - -### Script mode - -When running `re2c()` in script mode: - -```sh -cmake -P script.cmake -``` - -the generated file is created right away: - -```cmake -# script.cmake - -find_package(RE2C REQUIRED) - -if(RE2C_FOUND) - re2c(lexer.re lexer.c) -endif() -``` +* `RE2C_EXECUTABLE` - Path to the `re2c` executable. #]=============================================================================] -include(CheckSourceCompiles) -include(CMakePushCheckState) include(FeatureSummary) include(FindPackageHandleStandardArgs) @@ -251,339 +20,35 @@ include(FindPackageHandleStandardArgs) # Configuration. ################################################################################ -# If re2c is not found on the system, set which version to download. -if(NOT RE2C_DOWNLOAD_VERSION) - set(RE2C_DOWNLOAD_VERSION 4.0.2) -endif() - -################################################################################ -# Functions. -################################################################################ - -function(re2c) - cmake_parse_arguments( - PARSE_ARGV - 3 - parsed # prefix - "NO_DEFAULT_OPTIONS;CODEGEN;ABSOLUTE_PATHS" # options - "HEADER;WORKING_DIRECTORY;COMPUTED_GOTOS" # one-value keywords - "OPTIONS;DEPENDS" # multi-value keywords - ) - - _re2c_process(${ARGN}) - - if(NOT CMAKE_SCRIPT_MODE_FILE) - add_custom_target(${ARGV0} SOURCES ${input} DEPENDS ${outputs}) - endif() - - # Skip generation, if generated files are provided by the release archive. - get_property(type GLOBAL PROPERTY _CMAKE_RE2C_TYPE) - if(NOT RE2C_FOUND AND NOT RE2C_FIND_REQUIRED AND NOT type STREQUAL "REQUIRED") - return() - endif() - - if(CMAKE_SCRIPT_MODE_FILE) - message(STATUS "[RE2C] ${message}") - execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) - return() - endif() - - set(codegen "") - if( - parsed_CODEGEN - AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 - AND POLICY CMP0171 - ) - cmake_policy(GET CMP0171 cmp0171) - - if(cmp0171 STREQUAL "NEW") - set(codegen CODEGEN) - endif() - endif() - - add_custom_command( - OUTPUT ${outputs} - ${commands} - DEPENDS - ${input} - ${parsed_DEPENDS} - $ - $ - COMMENT "[RE2C][${ARGV0}] ${message}" - VERBATIM - COMMAND_EXPAND_LISTS - ${codegen} - WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} - ) -endfunction() - -# Process arguments. -macro(_re2c_process) - if(parsed_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Unrecognized arguments: ${parsed_UNPARSED_ARGUMENTS}") - endif() - - if(parsed_KEYWORDS_MISSING_VALUES) - message(FATAL_ERROR "Missing values for: ${parsed_KEYWORDS_MISSING_VALUES}") - endif() - - set(input ${ARGV1}) - if(NOT IS_ABSOLUTE "${input}") - cmake_path( - ABSOLUTE_PATH - input - BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - NORMALIZE - ) - endif() - cmake_path(SET input NORMALIZE "${input}") - - set(output ${ARGV2}) - if(NOT IS_ABSOLUTE "${output}") - cmake_path( - ABSOLUTE_PATH - output - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - endif() - cmake_path(SET output NORMALIZE "${output}") - - set(outputs ${output}) - - _re2c_process_options(parsed_OPTIONS options) - _re2c_process_header_option() - - # Assemble commands for add_custom_command() and execute_process(). - set(commands "") - - # RE2C cannot create output directories. Ensure any required directories for - # the generated files are created if they don't already exist. - set(directories "") - foreach(output IN LISTS outputs) - cmake_path(GET output PARENT_PATH dir) - if(dir) - list(APPEND directories ${dir}) - endif() - endforeach() - if(directories) - list(REMOVE_DUPLICATES directories) - list( - APPEND - commands - COMMAND ${CMAKE_COMMAND} -E make_directory ${directories} - ) - endif() - - _re2c_set_working_directory() - - if(parsed_ABSOLUTE_PATHS) - set(inputArgument "${input}") - set(outputArgument "${output}") - else() - cmake_path( - RELATIVE_PATH - input - BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} - OUTPUT_VARIABLE inputArgument - ) - cmake_path( - RELATIVE_PATH - output - BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} - OUTPUT_VARIABLE outputArgument - ) - endif() - - list( - APPEND - commands - COMMAND - ${RE2C_EXECUTABLE} - ${options} - --output ${outputArgument} - ${inputArgument} - ) - - # Assemble status message. - cmake_path( - RELATIVE_PATH - output - BASE_DIRECTORY ${CMAKE_BINARY_DIR} - OUTPUT_VARIABLE outputRelative - ) - - set(message "Generating ${outputRelative} with re2c ${RE2C_VERSION}") -endmacro() - -# Process options. -function(_re2c_process_options options result) - set(options ${${options}}) - - if(RE2C_COMPUTED_GOTOS OR parsed_COMPUTED_GOTOS) - _re2c_check_computed_gotos(result) - if(result) - list(PREPEND options --computed-gotos) - endif() - endif() - - if(RE2C_DEFAULT_OPTIONS AND NOT parsed_NO_DEFAULT_OPTIONS) - list(PREPEND options ${RE2C_DEFAULT_OPTIONS}) - endif() - - # Remove any generator expressions when running in script mode. - if(CMAKE_SCRIPT_MODE_FILE) - list(TRANSFORM options GENEX_STRIP) - endif() - - # Sync long -c variants. The long --conditions option was introduced in re2c - # version 1.1 as a new alias for the legacy --start-conditions. - if(RE2C_VERSION VERSION_LESS 1.1) - list(TRANSFORM options REPLACE "^--conditions$" "--start-conditions") - else() - list(TRANSFORM options REPLACE "^--start-conditions$" "--conditions") - endif() - - set(${result} ${options}) - - return(PROPAGATE ${result}) -endfunction() - -# Process HEADER option. -function(_re2c_process_header_option) - if(NOT parsed_HEADER) - return() - endif() - - set(header ${parsed_HEADER}) - if(NOT IS_ABSOLUTE "${header}") - cmake_path( - ABSOLUTE_PATH - header - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - endif() - - list(APPEND outputs ${header}) - - # When header option is used before re2c version 1.2, also the '-c' option - # is required. Before 1.1 '-c' long variant is '--start-conditions' and - # after 1.1 '--conditions'. - if(RE2C_VERSION VERSION_LESS_EQUAL 1.2) - list(APPEND options -c) - endif() - - # Since re2c version 3.0, '--header' is the new alias option for the - # '--type-header' option. - if(RE2C_VERSION VERSION_GREATER_EQUAL 3.0) - list(APPEND options --header ${header}) - else() - list(APPEND options --type-header ${header}) - endif() - - return(PROPAGATE outputs options) -endfunction() - -# Set or adjust the parsed_WORKING_DIRECTORY. -function(_re2c_set_working_directory) - if(NOT parsed_WORKING_DIRECTORY) - if(RE2C_WORKING_DIRECTORY) - set(parsed_WORKING_DIRECTORY ${RE2C_WORKING_DIRECTORY}) - else() - set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - endif() - endif() - - if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") - cmake_path( - ABSOLUTE_PATH - parsed_WORKING_DIRECTORY - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - endif() - - return(PROPAGATE parsed_WORKING_DIRECTORY) -endfunction() - -# Check for re2c --computed-gotos option. -function(_re2c_check_computed_gotos result) - if(CMAKE_SCRIPT_MODE_FILE) - set(${result} TRUE) - return(PROPAGATE ${result}) - endif() - - if(DEFINED _FIND_RE2C_HAVE_COMPUTED_GOTOS) - set(${result} ${_FIND_RE2C_HAVE_COMPUTED_GOTOS}) - return(PROPAGATE ${result}) - endif() - - message(CHECK_START "Checking for re2c --computed-gotos (-g) option support") - cmake_push_check_state(RESET) - set(CMAKE_REQUIRED_QUIET TRUE) - check_source_compiles(C [[ - int main(void) - { - label1: - ; - label2: - ; - static void *adr[] = { &&label1, &&label2 }; - goto *adr[0]; - return 0; - } - ]] _FIND_RE2C_HAVE_COMPUTED_GOTOS) - cmake_pop_check_state() - if(_FIND_RE2C_HAVE_COMPUTED_GOTOS) - message(CHECK_PASS "yes") - else() - message(CHECK_FAIL "no") - endif() - - set(${result} ${_FIND_RE2C_HAVE_COMPUTED_GOTOS}) - return(PROPAGATE ${result}) -endfunction() +set_package_properties( + RE2C + PROPERTIES + URL "https://re2c.org/" + DESCRIPTION "Lexer generator" +) ################################################################################ -# Package definition. +# Find re2c. ################################################################################ -block() - cmake_path( - RELATIVE_PATH - CMAKE_CURRENT_SOURCE_DIR - BASE_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE relativeDir - ) - - if(relativeDir STREQUAL ".") - set(purpose "Necessary to generate lexer files.") - else() - set(purpose "Necessary to generate ${relativeDir} lexer files.") - endif() - - set_package_properties( - RE2C - PROPERTIES - URL "https://re2c.org/" - DESCRIPTION "Lexer generator" - PURPOSE "${purpose}" - ) -endblock() - -################################################################################ -# Find the package. -################################################################################ +set(_reason "") find_program( RE2C_EXECUTABLE NAMES re2c - DOC "The re2c executable path" + DOC "The path to the re2c executable" ) mark_as_advanced(RE2C_EXECUTABLE) -block(PROPAGATE RE2C_VERSION _re2cVersionValid) +if(NOT RE2C_EXECUTABLE) + string(APPEND _reason "The re2c command-line executable not found. ") +endif() + +################################################################################ +# Check version. +################################################################################ + +block(PROPAGATE RE2C_VERSION _reason) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) set(test IS_EXECUTABLE) else() @@ -592,111 +57,37 @@ block(PROPAGATE RE2C_VERSION _re2cVersionValid) if(${test} ${RE2C_EXECUTABLE}) execute_process( - COMMAND ${RE2C_EXECUTABLE} --vernum - OUTPUT_VARIABLE versionNumber + COMMAND ${RE2C_EXECUTABLE} --version + OUTPUT_VARIABLE version ERROR_VARIABLE error RESULT_VARIABLE result OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE ) if(NOT result EQUAL 0) - message( - SEND_ERROR - "Command \"${RE2C_EXECUTABLE} --vernum\" failed with output:\n" - "${error}" - ) - elseif(versionNumber) - math(EXPR major "${versionNumber} / 10000") - - math(EXPR minor "(${versionNumber} - ${major} * 10000) / 100") - - math(EXPR patch "${versionNumber} - ${major} * 10000 - ${minor} * 100") - - set(RE2C_VERSION "${major}.${minor}.${patch}") - - find_package_check_version("${RE2C_VERSION}" _re2cVersionValid) - endif() - endif() -endblock() - -################################################################################ -# Download and build the package. -################################################################################ - -set(_re2cRequiredVars "") - -if( - NOT CMAKE_SCRIPT_MODE_FILE - AND NOT RE2C_DISABLE_DOWNLOAD - AND (NOT RE2C_EXECUTABLE OR NOT _re2cVersionValid) -) - set(RE2C_VERSION ${RE2C_DOWNLOAD_VERSION}) - - if(NOT TARGET RE2C::RE2C AND NOT TARGET re2c) - include(ExternalProject) - - # Configure re2c build. - if(RE2C_VERSION VERSION_GREATER_EQUAL 4) - set( - _re2cDownloadOptions - -DRE2C_BUILD_RE2D=OFF - -DRE2C_BUILD_RE2HS=OFF - -DRE2C_BUILD_RE2JAVA=OFF - -DRE2C_BUILD_RE2JS=OFF - -DRE2C_BUILD_RE2OCAML=OFF - -DRE2C_BUILD_RE2PY=OFF - -DRE2C_BUILD_RE2V=OFF - -DRE2C_BUILD_RE2ZIG=OFF - -DRE2C_BUILD_TESTS=OFF + string( + APPEND + _reason + "Command \"${RE2C_EXECUTABLE} --version\" failed:\n${error} " ) + elseif(version MATCHES "^re2c ([0-9.]+[^\n]+)") + find_package_check_version("${CMAKE_MATCH_1}" valid) + if(valid) + set(RE2C_VERSION "${CMAKE_MATCH_1}") + endif() else() - set( - _re2cDownloadOptions - -DCMAKE_DISABLE_FIND_PACKAGE_Python3=TRUE - -DPython3_VERSION=3.7 - ) + string(APPEND _reason "Invalid version format:\n${version} ") endif() - - ExternalProject_Add( - re2c - URL - https://github.com/skvadrik/re2c/archive/refs/tags/${RE2C_VERSION}.tar.gz - CMAKE_ARGS - -DRE2C_BUILD_RE2GO=OFF - -DRE2C_BUILD_RE2RUST=OFF - ${_re2cDownloadOptions} - INSTALL_COMMAND "" - ) - - # Set re2c executable. - ExternalProject_Get_property(re2c BINARY_DIR) - add_executable(RE2C::RE2C IMPORTED) - set_target_properties( - RE2C::RE2C - PROPERTIES IMPORTED_LOCATION ${BINARY_DIR}/re2c - ) - add_dependencies(RE2C::RE2C re2c) - set_property(CACHE RE2C_EXECUTABLE PROPERTY VALUE ${BINARY_DIR}/re2c) - unset(BINARY_DIR) endif() - - set(_re2cRequiredVars _re2cMsg) - set(_re2cMsg "downloading at build") -endif() +endblock() find_package_handle_standard_args( RE2C - REQUIRED_VARS ${_re2cRequiredVars} RE2C_EXECUTABLE RE2C_VERSION + REQUIRED_VARS RE2C_EXECUTABLE RE2C_VERSION VERSION_VAR RE2C_VERSION HANDLE_VERSION_RANGE - REASON_FAILURE_MESSAGE "re2c not found. Please install re2c." + REASON_FAILURE_MESSAGE "${_reason}" ) -unset(_re2cDownloadOptions) -unset(_re2cMsg) -unset(_re2cRequiredVars) -unset(_re2cVersionValid) - -if(NOT RE2C_FOUND) - return() -endif() +unset(_reason) diff --git a/cmake/cmake/modules/PHP/Bison.cmake b/cmake/cmake/modules/PHP/Bison.cmake new file mode 100644 index 00000000..0d7901a4 --- /dev/null +++ b/cmake/cmake/modules/PHP/Bison.cmake @@ -0,0 +1,750 @@ +#[=============================================================================[ +# PHP/Bison + +Generate parser-related files with Bison. This module includes common `bison` +configuration with minimum required version and common settings across the +PHP build. + +When `bison` cannot be found on the system or the found version is not suitable, +this module can also download and build it from its Git repository sources +release archive as part of the project build. + +## Configuration variables + +These variables can be set before including this module +`include(PHP/Bison)`: + +* `PHP_BISON_VERSION` - The bison version constraint, when looking for + BISON package with `find_package(BISON ...)` in this + module. + +* `PHP_BISON_OPTIONS` - A semicolon-separated list of default Bison options. + This module sets some sensible defaults. When `php_bison(APPEND)` is used, the + options specified in the `php_bison(OPTIONS ...)` are appended to + these default global options. + +* `PHP_BISON_DISABLE_DOWNLOAD` - Set to `TRUE` to disable downloading and + building bison package from source, when it is not found on the system or + found version is not suitable. + +* `PHP_BISON_DOWNLOAD_VERSION` - Override the default `bison` version to be + downloaded when not found on the system. + +* `PHP_BISON_WORKING_DIRECTORY` - Set the default global working directory + (`WORKING_DIRECTORY ` option) for all `php_bison()` invocations in the + scope of the current directory. + +## Functions provided by this module + +### `php_bison()` + +Generate parser file from the given template file using the `bison` parser +generator. + +```cmake +php_bison( + + + + [HEADER | HEADER_FILE
] + [APPEND] + [OPTIONS ...] + [DEPENDS ...] + [VERBOSE [REPORT_FILE ]] + [CODEGEN] + [WORKING_DIRECTORY ] + [ABSOLUTE_PATHS] +) +``` + +This creates a custom CMake target `` and adds a custom command that +generates parser file `` from the given `` template file using +the `bison` parser generator. Relative source file path `` is interpreted +as being relative to the current source directory. Relative `` file path +is interpreted as being relative to the current binary directory. If generated +files are already available (for example, shipped with the released archive), +and Bison is not found, it will create a custom target but skip the `bison` +command-line execution. + +When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it +generates the parser without creating a target, to make it easier to use in +various scenarios. + +#### Options + +* `HEADER` - Produce also a header file automatically. + +* `HEADER_FILE
` - Produce a specified header file `
`. Relative + header file path is interpreted as being relative to the current binary + directory. + +* `APPEND` - If specified, the `PHP_BISON_OPTIONS` are prepended to + `OPTIONS ` for the current `bison` invocation. + +* `OPTIONS ...` - List of additional options to pass to the `bison` + command-line tool. Module sets common-sensible default options. + +* `DEPENDS ...` - Optional list of dependent files to regenerate the + output file. + +* `VERBOSE` - This adds the `--verbose` (`-v`) command-line option to + `bison` executable and will create extra output file + `.output` containing verbose descriptions of the + grammar and parser. File will be created in the current binary directory. + +* `REPORT_FILE ` - This adds the `--report-file=` command-line + option to `bison` executable and will create verbose information report in the + specified ``. This option must be used together with the `VERBOSE` + option. Relative file path is interpreted as being relative to the current + binary directory. + +* `CODEGEN` - Adds the `CODEGEN` option to the bison's `add_custom_command()` + call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which + provides a global CMake `codegen` target for convenience to call only the + code-generation-related targets and skips the majority of the build: + + ```sh + cmake --build --target codegen + ``` + +* `WORKING_DIRECTORY ` - The path where the `bison` command + is executed. Relative `` path is interpreted as being + relative to the current binary directory. If not set, `bison` is by default + executed in the current binary directory (`CMAKE_CURRENT_BINARY_DIR`). If + variable `PHP_BISON_WORKING_DIRECTORY` is set before calling the + `php_bison()` without this option, it will set the default working directory + to that. + +* `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `bison` + command-line invocations. By default all file paths are added to `bison` + command-line relative to the working directory. Using relative paths is + convenient when line directives (`#line ...`) are generated in the output + parser files to not show the full path on the disk, when file is committed to + Git repository, where multiple people develop. + + When this option is enabled: + + ```c + #line 15 "/home/user/projects/php-src/sapi/phpdbg/phpdbg_parser.y" + ``` + + Without this option, relative paths will be generated: + + ```c + #line 15 "sapi/phpdbg/phpdbg_parser.y" + ``` + +## Examples + +### Basic usage + +```cmake +# CMakeLists.txt + +include(PHP/Bison) + +php_bison(...) +``` + +### Minimum bison version + +To override the module default minimum required `bison` version: + +```cmake +# CMakeLists.txt + +set(PHP_BISON_VERSION 3.8.0) +include(PHP/Bison) +``` + +### Specifying options + +```cmake +# CMakeLists.txt + +include(PHP/Bison) + +php_bison(foo foo.y foo.c OPTIONS -Wall --debug) +# This will run: +# bison -Wall --debug foo.y --output foo.c +``` + +This module also provides some sensible default options, which can be prepended +to current specified options using the `APPEND` keyword. + +```cmake +# CMakeLists.txt + +include(PHP/Bison) + +php_bison(foo foo.y foo.c APPEND OPTIONS --debug --yacc) +# This will run: +# bison -Wall --no-lines --debug --yacc foo.y --output foo.c +``` + +Generator expressions are supported in `php_bison(OPTIONS)` when running in +normal CMake `project()` mode: + +```cmake +# CMakeLists.txt + +include(PHP/Bison) + +php_bison(foo foo.y foo.c OPTIONS $<$:--debug>) +# When build type is Debug, this will run: +# bison --debug foo.y --output foo.c +# For other build types, this will run: +# bison foo.y --output foo.c +``` + +Setting default options for all `php_bison()` calls in the current directory +scope: + +```cmake +# CMakeLists.txt + +set(PHP_BISON_OPTIONS -Werror --no-lines) + +include(PHP/Bison) + +php_bison(foo foo.y foo.c APPEND OPTIONS --debug) +# This will run: +# bison -Werror --no-lines --debug foo.y --output foo.c +``` + +### Custom target usage + +To specify dependencies with the custom target created by `bison()`: + +```cmake +# CMakeLists.txt + +include(PHP/Bison) + +php_bison(foo_parser parser.y parser.c) +add_dependencies(some_target foo_parser) +``` + +Or to run only the specific `foo_parser` target, which generates the +parser-related files + +```sh +cmake --build --target foo_parser +``` + +### Script mode + +When running `php_bison()` in script mode (`CMAKE_SCRIPT_MODE_FILE`): + +```sh +cmake -P script.cmake +``` + +the generated file is created right away, without creating target: + +```cmake +# script.cmake + +include(PHP/Bison) + +php_bison(foo_parser parser.y parser.c) +``` + +In script mode also all options with generator expressions are removed from the +invocation as they can't be parsed and determined in such mode. + +```cmake +# script.cmake + +include(PHP/Bison) + +php_bison(foo parser.y parser.c OPTIONS $<$:--debug> --yacc) +# This will run: +# bison --yacc parser.y --output parser.c +``` +#]=============================================================================] + +include_guard(GLOBAL) + +include(FetchContent) +include(FeatureSummary) + +################################################################################ +# Configuration. +################################################################################ + +macro(_php_bison_config) + # Minimum required bison version. + if(NOT PHP_BISON_VERSION) + set(PHP_BISON_VERSION 3.0.0) + endif() + + # If bison is not found on the system, set which version to download. + if(NOT PHP_BISON_DOWNLOAD_VERSION) + set(PHP_BISON_DOWNLOAD_VERSION 3.8.2) + endif() + + # Add Bison --no-lines (-l) option to not generate '#line' directives based on + # this module usage and build type. + if(NOT PHP_BISON_OPTIONS) + if(CMAKE_SCRIPT_MODE_FILE) + set(PHP_BISON_OPTIONS --no-lines) + else() + set(PHP_BISON_OPTIONS $<$:--no-lines>) + endif() + + # Report all warnings. + list(PREPEND PHP_BISON_OPTIONS -Wall) + endif() + + # Set working directory for all bison invocations. + if(NOT PHP_BISON_WORKING_DIRECTORY) + if(PHP_SOURCE_DIR) + set(PHP_BISON_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) + else() + set(PHP_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + endif() +endmacro() + +################################################################################ +# Functions. +################################################################################ + +function(php_bison name input output) + cmake_parse_arguments( + PARSE_ARGV + 3 + parsed # prefix + "APPEND;CODEGEN;HEADER;VERBOSE;ABSOLUTE_PATHS" # options + "HEADER_FILE;WORKING_DIRECTORY;REPORT_FILE" # one-value keywords + "OPTIONS;DEPENDS" # multi-value keywords + ) + + if(parsed_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unrecognized arguments: ${parsed_UNPARSED_ARGUMENTS}") + endif() + + if(parsed_KEYWORDS_MISSING_VALUES) + message(FATAL_ERROR "Missing values for: ${parsed_KEYWORDS_MISSING_VALUES}") + endif() + + if(parsed_HEADER AND parsed_HEADER_FILE) + message( + AUTHOR_WARNING + "When 'HEADER_FILE' is specified, remove redundant 'HEADER' option." + ) + endif() + + if(parsed_REPORT_FILE AND NOT parsed_VERBOSE) + message(FATAL_ERROR "'REPORT_FILE' option requires also 'VERBOSE' option.") + endif() + + if(NOT IS_ABSOLUTE "${input}") + cmake_path( + ABSOLUTE_PATH + input + BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + NORMALIZE + ) + else() + cmake_path(SET input NORMALIZE "${input}") + endif() + + if(NOT IS_ABSOLUTE "${output}") + cmake_path( + ABSOLUTE_PATH + output + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + else() + cmake_path(SET output NORMALIZE "${output}") + endif() + + set(outputs ${output}) + set(extraOutputs "") + + _php_bison_config() + _php_bison_process_header_file() + _php_bison_set_package_properties() + + get_property(packageType GLOBAL PROPERTY _CMAKE_BISON_TYPE) + set(quiet "") + if(NOT packageType STREQUAL "REQUIRED") + set(quiet "QUIET") + endif() + + find_package(BISON ${PHP_BISON_VERSION} GLOBAL ${quiet}) + + if( + NOT BISON_FOUND + AND NOT PHP_BISON_DISABLE_DOWNLOAD + AND packageType STREQUAL "REQUIRED" + ) + _php_bison_download() + endif() + + _php_bison_process_working_directory() + _php_bison_process_options() + _php_bison_process_header_option() + _php_bison_process_verbose_option() + + if(NOT CMAKE_SCRIPT_MODE_FILE) + add_custom_target(${name} SOURCES ${input} DEPENDS ${outputs}) + endif() + + # Skip generation, if generated files are provided by the release archive. + if(NOT BISON_FOUND AND NOT packageType STREQUAL "REQUIRED") + return() + endif() + + _php_bison_get_commands(commands) + + # Assemble status message. + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${CMAKE_BINARY_DIR} + OUTPUT_VARIABLE outputRelative + ) + set(message "[bison] Generating ${outputRelative} with Bison ${BISON_VERSION}") + + if(CMAKE_SCRIPT_MODE_FILE) + message(STATUS "${message}") + execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) + return() + endif() + + set(codegen "") + if( + parsed_CODEGEN + AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 + AND POLICY CMP0171 + ) + cmake_policy(GET CMP0171 cmp0171) + + if(cmp0171 STREQUAL "NEW") + set(codegen CODEGEN) + endif() + endif() + + add_custom_command( + OUTPUT ${outputs} + ${commands} + DEPENDS + ${input} + ${parsed_DEPENDS} + $ + $ + COMMENT "${message}" + VERBATIM + COMMAND_EXPAND_LISTS + ${codegen} + WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} + ) +endfunction() + +# Process working directory. +function(_php_bison_process_working_directory) + if(NOT parsed_WORKING_DIRECTORY) + if(PHP_BISON_WORKING_DIRECTORY) + set(parsed_WORKING_DIRECTORY ${PHP_BISON_WORKING_DIRECTORY}) + else() + set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() + else() + set(parsed_WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) + endif() + + if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") + cmake_path( + ABSOLUTE_PATH + parsed_WORKING_DIRECTORY + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + else() + cmake_path( + SET + parsed_WORKING_DIRECTORY + NORMALIZE + "${parsed_WORKING_DIRECTORY}" + ) + endif() + + return(PROPAGATE parsed_WORKING_DIRECTORY) +endfunction() + +# Process options. +function(_php_bison_process_options) + set(options ${parsed_OPTIONS}) + + if(PHP_BISON_OPTIONS AND parsed_APPEND) + list(PREPEND options ${PHP_BISON_OPTIONS}) + endif() + + # Remove any generator expressions when running in script mode. + if(CMAKE_SCRIPT_MODE_FILE) + list(TRANSFORM options GENEX_STRIP) + endif() + + return(PROPAGATE options) +endfunction() + +# Process HEADER_FILE. +function(_php_bison_process_header_file) + if(NOT parsed_HEADER AND NOT parsed_HEADER_FILE) + return() + endif() + + if(parsed_HEADER_FILE) + set(header ${parsed_HEADER_FILE}) + if(NOT IS_ABSOLUTE "${header}") + cmake_path( + ABSOLUTE_PATH + header + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + else() + cmake_path(SET header NORMALIZE "${header}") + endif() + else() + # Produce default header path generated by bison (see option --header). + cmake_path(GET output EXTENSION LAST_ONLY extension) + string(REPLACE "c" "h" extension "${extension}") + if(NOT extension) + set(extension ".h") + endif() + cmake_path( + REPLACE_EXTENSION + output + LAST_ONLY + "${extension}" + OUTPUT_VARIABLE header + ) + endif() + + list(APPEND outputs ${header}) + + return(PROPAGATE header outputs) +endfunction() + +# Process HEADER and HEADER_FILE options. +function(_php_bison_process_header_option) + if(NOT parsed_HEADER AND NOT parsed_HEADER_FILE) + return() + endif() + + # Bison versions 3.8 and later introduced the --header=[FILE] (-H) option. + # For prior versions the --defines=[FILE] (-d) option can be used. + if(parsed_HEADER_FILE) + if(parsed_ABSOLUTE_PATHS) + set(headerArgument "${header}") + else() + cmake_path( + RELATIVE_PATH + header + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE headerArgument + ) + endif() + + if(BISON_VERSION VERSION_LESS 3.8) + list(APPEND options --defines=${headerArgument}) + else() + list(APPEND options --header=${headerArgument}) + endif() + else() + if(BISON_VERSION VERSION_LESS 3.8) + list(APPEND options -d) + else() + list(APPEND options --header) + endif() + endif() + + return(PROPAGATE options) +endfunction() + +# Process the VERBOSE and REPORT_FILE options. +function(_php_bison_process_verbose_option) + if(NOT parsed_VERBOSE) + return() + endif() + + list(APPEND options --verbose) + + if(NOT parsed_REPORT_FILE) + cmake_path(GET output FILENAME reportFile) + cmake_path(GET output EXTENSION extension) + + # Bison treats output files .tab. + # differently. It removes the '.tab' part of the extension and creates + # .output file. Elsewhere, it replaces only the + # last extension with '.output'. + if(extension MATCHES "\\.tab\\.([^.]+)$") + string( + REGEX REPLACE + "\\.tab\\.${CMAKE_MATCH_1}$" + ".output" + reportFile + "${reportFile}" + ) + else() + cmake_path(REPLACE_EXTENSION reportFile LAST_ONLY "output") + endif() + else() + set(reportFile ${parsed_REPORT_FILE}) + endif() + + if(NOT IS_ABSOLUTE "${reportFile}") + cmake_path( + ABSOLUTE_PATH + reportFile + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + else() + cmake_path(SET reportFile NORMALIZE "${reportFile}") + endif() + + list(APPEND extraOutputs "${reportFile}") + list(APPEND options --report-file=${reportFile}) + + return(PROPAGATE options extraOutputs) +endfunction() + +# Set BISON package properties TYPE and PURPOSE. If parser-related output files +# are already generated, for example, shipped with the released archive, then +# BISON package type is set to RECOMMENDED. If generated files are not +# available, for example, when building from a Git repository, type is set to +# REQUIRED to generate files during the build. +function(_php_bison_set_package_properties) + set_package_properties(BISON PROPERTIES TYPE RECOMMENDED) + + foreach(output IN LISTS outputs) + if(NOT EXISTS ${output}) + set_package_properties(BISON PROPERTIES TYPE REQUIRED) + break() + endif() + endforeach() + + # Set package PURPOSE property. + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE relativePath + ) + if(relativePath STREQUAL ".") + set(purpose "Necessary to generate parser files.") + else() + set(purpose "Necessary to generate ${relativePath} parser files.") + endif() + set_package_properties(BISON PROPERTIES PURPOSE "${purpose}") +endfunction() + +# Assemble commands for add_custom_command() and execute_process(). +function(_php_bison_get_commands result) + set(${result} "") + + if(parsed_ABSOLUTE_PATHS) + set(inputArgument "${input}") + set(outputArgument "${output}") + else() + cmake_path( + RELATIVE_PATH + input + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE inputArgument + ) + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE outputArgument + ) + endif() + + # Bison cannot create output directories. Ensure any required directories for + # the generated files are created if they don't already exist. + set(directories "") + foreach(output IN LISTS outputs extraOutputs) + cmake_path(GET output PARENT_PATH dir) + if(dir) + list(APPEND directories ${dir}) + endif() + endforeach() + if(directories) + list(REMOVE_DUPLICATES directories) + list( + APPEND + ${result} + COMMAND ${CMAKE_COMMAND} -E make_directory ${directories} + ) + endif() + + list( + APPEND + ${result} + COMMAND + ${BISON_EXECUTABLE} + ${options} + ${inputArgument} + --output ${outputArgument} + ) + + return(PROPAGATE ${result}) +endfunction() + +################################################################################ +# Download and build bison if not found. +################################################################################ + +function(_php_bison_download) + set(BISON_VERSION ${PHP_BISON_DOWNLOAD_VERSION}) + + message(STATUS "Downloading bison ${BISON_VERSION}") + FetchContent_Populate( + BISON + URL https://ftp.gnu.org/gnu/bison/bison-${BISON_VERSION}.tar.gz + SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/bison + ) + + message(STATUS "Configuring Bison ${BISON_VERSION}") + execute_process( + COMMAND ./configure + OUTPUT_VARIABLE result + ECHO_OUTPUT_VARIABLE + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_deps/bison + ) + + message(STATUS "Building Bison ${BISON_VERSION}") + include(ProcessorCount) + processorcount(processors) + execute_process( + COMMAND ${CMAKE_MAKE_PROGRAM} -j${processors} + OUTPUT_VARIABLE result + ECHO_OUTPUT_VARIABLE + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_deps/bison + ) + + set(BISON_FOUND TRUE) + + set_property( + CACHE BISON_EXECUTABLE + PROPERTY VALUE ${CMAKE_BINARY_DIR}/_deps/bison/src/bison + ) + + # Move dependency to PACKAGES_FOUND. + block() + get_property(packagesNotFound GLOBAL PROPERTY PACKAGES_NOT_FOUND) + list(REMOVE_ITEM packagesNotFound BISON) + set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND packagesNotFound) + get_property(packagesFound GLOBAL PROPERTY PACKAGES_FOUND) + set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND BISON) + endblock() + + return(PROPAGATE BISON_FOUND BISON_VERSION) +endfunction() diff --git a/cmake/cmake/modules/PHP/Package/BISON.cmake b/cmake/cmake/modules/PHP/Package/BISON.cmake deleted file mode 100644 index 39fe8e10..00000000 --- a/cmake/cmake/modules/PHP/Package/BISON.cmake +++ /dev/null @@ -1,47 +0,0 @@ -#[=============================================================================[ -# PHP/Package/BISON - -PHP-related configuration for using `bison`. - -## Basic usage - -```cmake -# CMakeLists.txt - -include(PHP/Package/BISON) - -# Check if bison is required. PHP released archive from php.net contains -# generated parser files, so these don't need to be regenerated. When building -# from a Git repository, bison is required to generate files during the build. -if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c) - set_package_properties(BISON PROPERTIES TYPE REQUIRED) -endif() - -if(BISON_FOUND) - bison(...) -endif() -``` -#]=============================================================================] - -# Minimum required bison version. -set(BISON_FIND_VERSION 3.0.0) - -# Add Bison --no-lines (-l) option to not generate '#line' directives based on -# this module usage and build type. -if(CMAKE_SCRIPT_MODE_FILE) - set(BISON_DEFAULT_OPTIONS --no-lines) -else() - set(BISON_DEFAULT_OPTIONS $<$:--no-lines>) -endif() - -# Report all warnings. -list(PREPEND BISON_DEFAULT_OPTIONS -Wall) - -# Set working directory for all bison invocations. -if(PHP_SOURCE_DIR) - set(BISON_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) -else() - set(BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -endif() - -find_package(BISON GLOBAL) diff --git a/cmake/cmake/modules/PHP/Package/RE2C.cmake b/cmake/cmake/modules/PHP/Package/RE2C.cmake deleted file mode 100644 index cfe12857..00000000 --- a/cmake/cmake/modules/PHP/Package/RE2C.cmake +++ /dev/null @@ -1,54 +0,0 @@ -#[=============================================================================[ -# PHP/Package/RE2C - -PHP-related configuration for using `re2c` to simplify setting minimum required -version at one place and use the package with common settings across the build. - -## Basic usage - -```cmake -# CMakeLists.txt - -include(PHP/Package/RE2C) - -# Check if re2c is required. PHP released archive from php.net contains -# generated lexer files, so these don't need to be regenerated. When building -# from a Git repository, re2c is required to generate files during the build. -if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c) - set_package_properties(RE2C PROPERTIES TYPE REQUIRED) -endif() - -if(RE2C_FOUND) - re2c(...) -endif() -``` -#]=============================================================================] - -# Minimum required re2c version. -set(RE2C_FIND_VERSION 1.0.3) - -option(PHP_RE2C_COMPUTED_GOTOS "Enable computed goto GCC extension with re2c") -mark_as_advanced(PHP_RE2C_COMPUTED_GOTOS) - -if(PHP_RE2C_COMPUTED_GOTOS) - set(RE2C_COMPUTED_GOTOS TRUE) -endif() - -# Add --no-debug-info (-i) option to not output line directives. -if(CMAKE_SCRIPT_MODE_FILE) - set(RE2C_DEFAULT_OPTIONS --no-debug-info) -else() - set(RE2C_DEFAULT_OPTIONS $<$:--no-debug-info>) -endif() - -# Suppress date output in the generated file. -list(APPEND RE2C_DEFAULT_OPTIONS --no-generation-date) - -# Set working directory for all re2c invocations. -if(PHP_SOURCE_DIR) - set(RE2C_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) -else() - set(RE2C_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -endif() - -find_package(RE2C GLOBAL) diff --git a/cmake/cmake/modules/PHP/Re2c.cmake b/cmake/cmake/modules/PHP/Re2c.cmake new file mode 100644 index 00000000..136f8aa5 --- /dev/null +++ b/cmake/cmake/modules/PHP/Re2c.cmake @@ -0,0 +1,744 @@ +#[=============================================================================[ +# PHP/Re2c + +Generate lexer-related files with re2c. This module includes common `re2c` +configuration with minimum required version and common settings across the +PHP build. + +When `re2c` cannot be found on the system or the found version is not suitable, +this module can also download and build it from its Git repository sources +release archive as part of the project build. + +## Configuration variables + +These variables can be set before including this module +`include(PHP/Re2c)`: + +* `PHP_RE2C_VERSION` - The re2c version constraint, when looking for RE2C + package with `find_package(RE2C ...)`. + +* `PHP_RE2C_COMPUTED_GOTOS` - Add the `COMPUTED_GOTOS TRUE` option to all + `php_re2c()` invocations in the scope of current directory. + +* `PHP_RE2C_OPTIONS` - A semicolon-separated list of default re2c options. + This module sets some sensible defaults. When `php_re2c(APPEND)` is used, the + options specified in the `php_re2c(OPTIONS ...)` are appended to + these default global options. + +* `PHP_RE2C_DISABLE_DOWNLOAD` - Set to `TRUE` to disable downloading and + building RE2C package from source, when it is not found on the system or found + version is not suitable. + +* `PHP_RE2C_DOWNLOAD_VERSION` - Override the default `re2c` version to be + downloaded when not found on the system. + +* `PHP_RE2C_WORKING_DIRECTORY` - Set the default global working directory + (`WORKING_DIRECTORY ` option) for all `php_re2c()` invocations in the + scope of the current directory. + +## Functions provided by this module + +### `php_re2c()` + +Generate lexer file from the given template file using the `re2c` lexer +generator. + +```cmake +php_re2c( + + + + [HEADER
] + [APPEND] + [OPTIONS ...] + [DEPENDS ...] + [COMPUTED_GOTOS ] + [CODEGEN] + [WORKING_DIRECTORY ] + [ABSOLUTE_PATHS] +) +``` + +This creates a custom CMake target `` and adds a custom command that +generates lexer file `` from the given `` template file using the +`re2c` lexer generator. Relative source file path `` is interpreted as +being relative to the current source directory. Relative `` file path is +interpreted as being relative to the current binary directory. If generated +files are already available (for example, shipped with the released archive), +and re2c is not found, it will create a custom target but skip the `re2c` +command-line execution. + +When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it +generates the lexer without creating a target, to make it easier to use in +various scenarios. + +#### Options + +* `HEADER
` - Generate a given `
` file. Relative header file + path is interpreted as being relative to the current binary directory. + +* `APPEND` - If specified, the `PHP_RE2C_OPTIONS` are prepended to + `OPTIONS ` for the current `re2c` invocation. + +* `DEPENDS ...` - Optional list of dependent files to regenerate the + output file. + +* `COMPUTED_GOTOS ` - Set to `TRUE` to add the re2c + `--computed-gotos` (`-g`) command-line option if the non-standard C computed + goto extension is supported by the C compiler. When calling `re2c()` in the + command-line script mode (`CMAKE_SCRIPT_MODE`), option is not checked, whether + the compiler supports it and is added to `re2c` command-line options + unconditionally. + +* `CODEGEN` - Adds the `CODEGEN` option to the re2c's `add_custom_command()` + call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which + provides a global CMake `codegen` target for convenience to call only the + code-generation-related targets and skips the majority of the build: + + ```sh + cmake --build --target codegen + ``` + +* `WORKING_DIRECTORY ` - The path where the `re2c` command is + executed. Relative `` path is interpreted as being relative + to the current binary directory. If not set, `re2c` is by default executed in + the current binary directory (`CMAKE_CURRENT_BINARY_DIR`). If variable + `PHP_RE2C_WORKING_DIRECTORY` is set before calling the `php_re2c()` without + this option, it will set the default working directory to that. + +* `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `re2c` + command-line invocations. By default all file paths are added to `re2c` + command-line relative to the working directory. Using relative paths is + convenient when line directives (`#line ...`) are generated in the output + lexer files to not show the full path on the disk, when file is committed to + Git repository, where multiple people develop. + + When this option is enabled: + + ```c + #line 108 "/home/user/projects/php-src/ext/phar/phar_path_check.c" + ``` + + Without this option, relative paths will be generated: + + ```c + #line 108 "ext/phar/phar_path_check.c" + ``` + +## Examples + +### Basic usage + +```cmake +# CMakeLists.txt + +include(PHP/Re2c) + +php_re2c(...) +``` + +### Minimum re2c version + +To override the module default minimum required `re2c` version: + +```cmake +# CMakeLists.txt + +set(PHP_RE2C_VERSION 3.8.0) +include(PHP/Re2c) +``` + +### Specifying options + +```cmake +# CMakeLists.txt + +include(PHP/Re2c) + +php_re2c(foo foo.re foo.c OPTIONS --bit-vectors --conditions) +# This will run: +# re2c --bit-vectors --conditions --output foo.c foo.re +``` + +This module also provides some sensible default options, which can be prepended +to current specified options using the `APPEND` keyword. + +```cmake +# CMakeLists.txt + +include(PHP/Re2c) + +php_re2c(foo foo.re foo.c APPEND OPTIONS --conditions) +# This will run: +# re2c --no-debug-info --no-generation-date --conditions --output foo.c foo.re +``` + +Generator expressions are supported in `php_re2c(OPTIONS)` when running in +normal CMake `project()` mode: + +```cmake +# CMakeLists.txt + +include(PHP/Re2c) + +php_re2c(foo foo.re foo.c OPTIONS $<$:--debug-output> --conditions) +# When build type is Debug, this will run: +# re2c --debug-output -conditions --output foo.c foo.re +# For other build types: +# re2c --conditions --output foo.c foo.re +``` + +Setting default options for all `php_re2c()` calls in the current directory +scope: + +```cmake +# CMakeLists.txt + +set(PHP_RE2C_OPTIONS --no-generation-date) + +include(PHP/Re2c) + +php_re2c(foo foo.re foo.c APPEND OPTIONS --conditions) +# This will run: +# re2c --no-generation-date --conditions --output foo.c foo.re +``` + +### Custom target usage + +To specify dependencies with the custom target created by `re2c()`: + +```cmake +# CMakeLists.txt + +include(PHP/Re2c) + +php_re2c(foo_lexer lexer.re lexer.c) +add_dependencies(some_target foo_lexer) +``` + +Or to run only the specific `foo_lexer` target, which generates the +lexer-related files. + +```sh +cmake --build --target foo_lexer +``` + +### Script mode + +When running `php_re2c()` in script mode (`CMAKE_SCRIPT_MODE_FILE`): + +```sh +cmake -P script.cmake +``` + +the generated file is created right away, without creating target: + +```cmake +# script.cmake + +include(PHP/Re2c) + +php_re2c(foo_lexer lexer.re lexer.c) +``` + +In script mode also all options with generator expressions are removed from the +invocation as they can't be parsed and determined in such mode. + +```cmake +# script.cmake + +include(PHP/Re2c) + +php_re2c(foo lexer.y lexer.c OPTIONS $<$:--debug-output> -F) +# This will run: +# re2c -F --output lexer.c lexer.re +``` +#]=============================================================================] + +include_guard(GLOBAL) + +include(FeatureSummary) + +################################################################################ +# Configuration. +################################################################################ + +option(PHP_RE2C_COMPUTED_GOTOS "Enable computed goto GCC extension with re2c") +mark_as_advanced(PHP_RE2C_COMPUTED_GOTOS) + +macro(_php_re2c_config) + # Minimum required re2c version. + if(NOT PHP_RE2C_VERSION) + set(PHP_RE2C_VERSION 1.0.3) + endif() + + # If re2c is not found on the system, set which version to download. + if(NOT PHP_RE2C_DOWNLOAD_VERSION) + set(PHP_RE2C_DOWNLOAD_VERSION 4.0.2) + endif() + + if(NOT PHP_RE2C_OPTIONS) + # Add --no-debug-info (-i) option to not output line directives. + if(CMAKE_SCRIPT_MODE_FILE) + set(PHP_RE2C_OPTIONS --no-debug-info) + else() + set(PHP_RE2C_OPTIONS $<$:--no-debug-info>) + endif() + + # Suppress date output in the generated file. + list(APPEND PHP_RE2C_OPTIONS --no-generation-date) + endif() + + # Set working directory for all re2c invocations. + if(NOT PHP_RE2C_WORKING_DIRECTORY) + if(PHP_SOURCE_DIR) + set(PHP_RE2C_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) + else() + set(PHP_RE2C_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + endif() + + # See: https://github.com/php/php-src/issues/17204 + # TODO: Remove this once fixed upstream. + # TODO: Refactor this because the found re2c version is here not known yet. + if(RE2C_VERSION VERSION_GREATER_EQUAL 4) + list( + APPEND + PHP_RE2C_OPTIONS + -Wno-unreachable-rules + -Wno-condition-order + -Wno-undefined-control-flow + ) + endif() +endmacro() + +################################################################################ +# Functions. +################################################################################ + +function(php_re2c name input output) + cmake_parse_arguments( + PARSE_ARGV + 3 + parsed # prefix + "APPEND;CODEGEN;ABSOLUTE_PATHS" # options + "HEADER;WORKING_DIRECTORY;COMPUTED_GOTOS" # one-value keywords + "OPTIONS;DEPENDS" # multi-value keywords + ) + + _php_re2c_config() + + find_package(RE2C ${PHP_RE2C_VERSION} GLOBAL) + if(NOT RE2C_FOUND AND NOT PHP_RE2C_DISABLE_DOWNLOAD) + _php_re2c_download() + endif() + + if(parsed_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unrecognized arguments: ${parsed_UNPARSED_ARGUMENTS}") + endif() + + if(parsed_KEYWORDS_MISSING_VALUES) + message(FATAL_ERROR "Missing values for: ${parsed_KEYWORDS_MISSING_VALUES}") + endif() + + if(NOT IS_ABSOLUTE "${input}") + cmake_path( + ABSOLUTE_PATH + input + BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + NORMALIZE + ) + else() + cmake_path(SET input NORMALIZE "${input}") + endif() + + if(NOT IS_ABSOLUTE "${output}") + cmake_path( + ABSOLUTE_PATH + output + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + else() + cmake_path(SET output NORMALIZE "${output}") + endif() + + set(outputs ${output}) + + _php_re2c_process_working_directory() + _php_re2c_process_options() + _php_re2c_process_header_option() + _php_re2c_set_package_properties() + + if(NOT CMAKE_SCRIPT_MODE_FILE) + add_custom_target(${name} SOURCES ${input} DEPENDS ${outputs}) + endif() + + # Skip generation, if generated files are provided by the release archive. + get_property(type GLOBAL PROPERTY _CMAKE_RE2C_TYPE) + if(NOT RE2C_FOUND AND NOT type STREQUAL "REQUIRED") + return() + endif() + + _php_re2c_get_commands(commands) + + # Assemble status message. + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${CMAKE_BINARY_DIR} + OUTPUT_VARIABLE outputRelative + ) + set(message "[re2c] Generating ${outputRelative} with re2c ${RE2C_VERSION}") + + if(CMAKE_SCRIPT_MODE_FILE) + message(STATUS "${message}") + execute_process(${commands} WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) + return() + endif() + + set(codegen "") + if( + parsed_CODEGEN + AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.31 + AND POLICY CMP0171 + ) + cmake_policy(GET CMP0171 cmp0171) + + if(cmp0171 STREQUAL "NEW") + set(codegen CODEGEN) + endif() + endif() + + add_custom_command( + OUTPUT ${outputs} + ${commands} + DEPENDS + ${input} + ${parsed_DEPENDS} + $ + $ + COMMENT "${message}" + VERBATIM + COMMAND_EXPAND_LISTS + ${codegen} + WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY} + ) +endfunction() + +# Process working directory. +function(_php_re2c_process_working_directory) + if(NOT parsed_WORKING_DIRECTORY) + if(PHP_RE2C_WORKING_DIRECTORY) + set(parsed_WORKING_DIRECTORY ${PHP_RE2C_WORKING_DIRECTORY}) + else() + set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() + endif() + + if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") + cmake_path( + ABSOLUTE_PATH + parsed_WORKING_DIRECTORY + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + else() + cmake_path( + SET + parsed_WORKING_DIRECTORY + NORMALIZE + "${parsed_WORKING_DIRECTORY}" + ) + endif() + + return(PROPAGATE parsed_WORKING_DIRECTORY) +endfunction() + +# Process options. +function(_php_re2c_process_options) + set(options ${parsed_OPTIONS}) + + if(PHP_RE2C_COMPUTED_GOTOS OR parsed_COMPUTED_GOTOS) + _php_re2c_check_computed_gotos(result) + if(result) + list(PREPEND options --computed-gotos) + endif() + endif() + + if(PHP_RE2C_OPTIONS AND parsed_APPEND) + list(PREPEND options ${PHP_RE2C_OPTIONS}) + endif() + + # Remove any generator expressions when running in script mode. + if(CMAKE_SCRIPT_MODE_FILE) + list(TRANSFORM options GENEX_STRIP) + endif() + + # Sync long -c variants. The long --conditions option was introduced in re2c + # version 1.1 as a new alias for the legacy --start-conditions. + if(RE2C_VERSION VERSION_LESS 1.1) + list(TRANSFORM options REPLACE "^--conditions$" "--start-conditions") + else() + list(TRANSFORM options REPLACE "^--start-conditions$" "--conditions") + endif() + + return(PROPAGATE options) +endfunction() + +# Process HEADER option. +function(_php_re2c_process_header_option) + if(NOT parsed_HEADER) + return() + endif() + + set(header ${parsed_HEADER}) + if(NOT IS_ABSOLUTE "${header}") + cmake_path( + ABSOLUTE_PATH + header + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + else() + cmake_path(SET header NORMALIZE "${header}") + endif() + + list(APPEND outputs ${header}) + + # When header option is used before re2c version 1.2, also the '-c' option + # is required. Before 1.1 '-c' long variant is '--start-conditions' and + # after 1.1 '--conditions'. + if(RE2C_VERSION VERSION_LESS_EQUAL 1.2) + list(APPEND options -c) + endif() + + # Since re2c version 3.0, '--header' is the new alias option for the + # '--type-header' option. + if(RE2C_VERSION VERSION_GREATER_EQUAL 3.0) + list(APPEND options --header ${header}) + else() + list(APPEND options --type-header ${header}) + endif() + + return(PROPAGATE outputs options) +endfunction() + +# Check for re2c --computed-gotos option. +function(_php_re2c_check_computed_gotos result) + if(CMAKE_SCRIPT_MODE_FILE) + set(${result} TRUE) + return(PROPAGATE ${result}) + endif() + + if(DEFINED _PHP_RE2C_HAVE_COMPUTED_GOTOS) + set(${result} ${_PHP_RE2C_HAVE_COMPUTED_GOTOS}) + return(PROPAGATE ${result}) + endif() + + include(CheckSourceCompiles) + include(CMakePushCheckState) + + message(CHECK_START "Checking for re2c --computed-gotos (-g) option support") + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_QUIET TRUE) + check_source_compiles(C [[ + int main(void) + { + label1: + ; + label2: + ; + static void *adr[] = { &&label1, &&label2 }; + goto *adr[0]; + return 0; + } + ]] _PHP_RE2C_HAVE_COMPUTED_GOTOS) + cmake_pop_check_state() + if(_PHP_RE2C_HAVE_COMPUTED_GOTOS) + message(CHECK_PASS "yes") + else() + message(CHECK_FAIL "no") + endif() + + set(${result} ${_PHP_RE2C_HAVE_COMPUTED_GOTOS}) + return(PROPAGATE ${result}) +endfunction() + +# Set RE2C package properties TYPE and PURPOSE. If lexer-related output files +# are already generated, for example, shipped with the released archive, then +# RE2C package type is set to RECOMMENDED. If generated files are not +# available, for example, when building from a Git repository, type is set to +# REQUIRED to generate files during the build. +function(_php_re2c_set_package_properties) + set_package_properties(RE2C PROPERTIES TYPE RECOMMENDED) + foreach(output IN LISTS outputs) + if(NOT EXISTS ${output}) + set_package_properties(RE2C PROPERTIES TYPE REQUIRED) + break() + endif() + endforeach() + + # Set package PURPOSE property. + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE relativePath + ) + if(relativePath STREQUAL ".") + set(purpose "Necessary to generate lexer files.") + else() + set(purpose "Necessary to generate ${relativePath} lexer files.") + endif() + set_package_properties(RE2C PROPERTIES PURPOSE "${purpose}") +endfunction() + +# Assemble commands for add_custom_command() and execute_process(). +function(_php_re2c_get_commands result) + set(${result} "") + + if(parsed_ABSOLUTE_PATHS) + set(inputArgument "${input}") + set(outputArgument "${output}") + else() + cmake_path( + RELATIVE_PATH + input + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE inputArgument + ) + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE outputArgument + ) + endif() + + # re2c cannot create output directories. Ensure any required directories for + # the generated files are created if they don't already exist. + set(directories "") + foreach(output IN LISTS outputs) + cmake_path(GET output PARENT_PATH dir) + if(dir) + list(APPEND directories ${dir}) + endif() + endforeach() + if(directories) + list(REMOVE_DUPLICATES directories) + list( + APPEND + ${result} + COMMAND ${CMAKE_COMMAND} -E make_directory ${directories} + ) + endif() + + list( + APPEND + ${result} + COMMAND + ${RE2C_EXECUTABLE} + ${options} + --output ${outputArgument} + ${inputArgument} + ) + + return(PROPAGATE ${result}) +endfunction() + +################################################################################ +# Download and build re2c if not found. +################################################################################ + +function(_php_re2c_download) + set(RE2C_VERSION ${PHP_RE2C_DOWNLOAD_VERSION}) + + message(STATUS "Downloading re2c ${RE2C_VERSION}") + + if(NOT CMAKE_SCRIPT_MODE_FILE AND NOT TARGET RE2C::RE2C AND NOT TARGET re2c) + include(ExternalProject) + + # Configure re2c build. + if(RE2C_VERSION VERSION_GREATER_EQUAL 4) + set( + _re2cDownloadOptions + -DRE2C_BUILD_RE2D=OFF + -DRE2C_BUILD_RE2HS=OFF + -DRE2C_BUILD_RE2JAVA=OFF + -DRE2C_BUILD_RE2JS=OFF + -DRE2C_BUILD_RE2OCAML=OFF + -DRE2C_BUILD_RE2PY=OFF + -DRE2C_BUILD_RE2V=OFF + -DRE2C_BUILD_RE2ZIG=OFF + -DRE2C_BUILD_TESTS=OFF + ) + else() + set( + _re2cDownloadOptions + -DCMAKE_DISABLE_FIND_PACKAGE_Python3=TRUE + -DPython3_VERSION=3.7 + ) + endif() + + ExternalProject_Add( + re2c + URL + https://github.com/skvadrik/re2c/archive/refs/tags/${RE2C_VERSION}.tar.gz + CMAKE_ARGS + -DRE2C_BUILD_RE2GO=OFF + -DRE2C_BUILD_RE2RUST=OFF + ${_re2cDownloadOptions} + INSTALL_COMMAND "" + ) + + # Set re2c executable. + ExternalProject_Get_property(re2c BINARY_DIR) + add_executable(RE2C::RE2C IMPORTED) + set_target_properties( + RE2C::RE2C + PROPERTIES IMPORTED_LOCATION ${BINARY_DIR}/re2c + ) + add_dependencies(RE2C::RE2C re2c) + set_property(CACHE RE2C_EXECUTABLE PROPERTY VALUE ${BINARY_DIR}/re2c) + else() + include(FetchContent) + FetchContent_Populate( + RE2C + URL https://github.com/skvadrik/re2c/archive/refs/tags/${RE2C_VERSION}.tar.gz + SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/re2c + ) + + message(STATUS "Configuring re2c ${RE2C_VERSION}") + execute_process( + COMMAND ${CMAKE_COMMAND} -B re2c-build + OUTPUT_VARIABLE result + ECHO_OUTPUT_VARIABLE + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_deps/re2c + ) + + message(STATUS "Building re2c ${RE2C_VERSION}") + execute_process( + COMMAND ${CMAKE_COMMAND} --build re2c-build -j + OUTPUT_VARIABLE result + ECHO_OUTPUT_VARIABLE + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_deps/re2c + ) + + set_property( + CACHE RE2C_EXECUTABLE + PROPERTY VALUE ${CMAKE_BINARY_DIR}/_deps/re2c/re2c-build/re2c + ) + endif() + + # Move dependency to PACKAGES_FOUND. + get_property(packagesNotFound GLOBAL PROPERTY PACKAGES_NOT_FOUND) + list(REMOVE_ITEM packagesNotFound RE2C) + set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND packagesNotFound) + get_property(packagesFound GLOBAL PROPERTY PACKAGES_FOUND) + set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND RE2C) + + set(RE2C_FOUND TRUE) + + return(PROPAGATE RE2C_FOUND RE2C_VERSION) +endfunction() diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake index 825e7905..333e0935 100755 --- a/cmake/cmake/scripts/GenerateGrammar.cmake +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -21,6 +21,8 @@ if(NOT CMAKE_SCRIPT_MODE_FILE) endif() set(PHP_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +set(CMAKE_SOURCE_DIR ${PHP_SOURCE_DIR}) +set(CMAKE_BINARY_DIR ${PHP_SOURCE_DIR}) if(NOT EXISTS ${PHP_SOURCE_DIR}/main/php_version.h) message(FATAL_ERROR "This script should be run in the php-src repository.") @@ -30,10 +32,10 @@ list(APPEND CMAKE_MODULE_PATH ${PHP_SOURCE_DIR}/cmake/modules) include(FeatureSummary) -include(PHP/Package/BISON) +include(PHP/Bison) set_package_properties(BISON PROPERTIES TYPE REQUIRED) -include(PHP/Package/RE2C) +include(PHP/Re2c) set_package_properties(RE2C PROPERTIES TYPE REQUIRED) feature_summary( @@ -60,7 +62,7 @@ foreach(script IN LISTS scripts) BASE_DIRECTORY ${PHP_SOURCE_DIR} OUTPUT_VARIABLE relativeDir ) - message(STATUS "Processing ${relativeDir} files") + message(STATUS "Processing ${relativeDir} directory") include(${script}) endforeach() diff --git a/cmake/ext/json/cmake/GenerateGrammar.cmake b/cmake/ext/json/cmake/GenerateGrammar.cmake index 72231518..019a3d98 100644 --- a/cmake/ext/json/cmake/GenerateGrammar.cmake +++ b/cmake/ext/json/cmake/GenerateGrammar.cmake @@ -1,47 +1,33 @@ # Generate lexer and parser files. -include(FeatureSummary) -include(PHP/Package/BISON) -include(PHP/Package/RE2C) - -if( - NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.h -) - set_package_properties(BISON PROPERTIES TYPE REQUIRED) +if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) + message(FATAL_ERROR "This file should be used with include().") endif() -if(BISON_FOUND) - if(CMAKE_SCRIPT_MODE_FILE) - set(verbose "") - else() - set(verbose VERBOSE) - endif() +include(PHP/Bison) - bison( - php_ext_json_parser - json_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c - HEADER - ${verbose} - CODEGEN - ) +if(CMAKE_SCRIPT_MODE_FILE) + set(verbose "") +else() + set(verbose VERBOSE) endif() -if( - NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h +php_bison( + php_ext_json_parser + json_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c + HEADER + ${verbose} + CODEGEN ) - set_package_properties(RE2C PROPERTIES TYPE REQUIRED) -endif() -if(RE2C_FOUND) - re2c( - php_ext_json_scanner - json_scanner.re - ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c - HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h - OPTIONS --bit-vectors --conditions - CODEGEN - ) -endif() +include(PHP/Re2c) + +php_re2c( + php_ext_json_scanner + json_scanner.re + ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c + HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h + APPEND OPTIONS --bit-vectors --conditions + CODEGEN +) diff --git a/cmake/ext/pdo/cmake/GenerateGrammar.cmake b/cmake/ext/pdo/cmake/GenerateGrammar.cmake index b04749fb..bf8b0d76 100644 --- a/cmake/ext/pdo/cmake/GenerateGrammar.cmake +++ b/cmake/ext/pdo/cmake/GenerateGrammar.cmake @@ -1,17 +1,14 @@ # Generate lexer. -include(FeatureSummary) -include(PHP/Package/RE2C) - -if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c) - set_package_properties(RE2C PROPERTIES TYPE REQUIRED) +if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) + message(FATAL_ERROR "This file should be used with include().") endif() -if(RE2C_FOUND) - re2c( - php_ext_pdo_sql_parser - pdo_sql_parser.re - ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c - CODEGEN - ) -endif() +include(PHP/Re2c) + +php_re2c( + php_ext_pdo_sql_parser + pdo_sql_parser.re + ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c + CODEGEN +) diff --git a/cmake/ext/phar/cmake/GenerateGrammar.cmake b/cmake/ext/phar/cmake/GenerateGrammar.cmake index 6243a3b7..30652c90 100644 --- a/cmake/ext/phar/cmake/GenerateGrammar.cmake +++ b/cmake/ext/phar/cmake/GenerateGrammar.cmake @@ -1,18 +1,15 @@ # Generate lexer. -include(FeatureSummary) -include(PHP/Package/RE2C) - -if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c) - set_package_properties(RE2C PROPERTIES TYPE REQUIRED) +if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) + message(FATAL_ERROR "This file should be used with include().") endif() -if(RE2C_FOUND) - re2c( - php_ext_phar_path_check - phar_path_check.re - ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c - OPTIONS --bit-vectors - CODEGEN - ) -endif() +include(PHP/Re2c) + +php_re2c( + php_ext_phar_path_check + phar_path_check.re + ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c + APPEND OPTIONS --bit-vectors + CODEGEN +) diff --git a/cmake/ext/standard/cmake/GenerateGrammar.cmake b/cmake/ext/standard/cmake/GenerateGrammar.cmake index ba572038..8d49f686 100644 --- a/cmake/ext/standard/cmake/GenerateGrammar.cmake +++ b/cmake/ext/standard/cmake/GenerateGrammar.cmake @@ -1,29 +1,23 @@ # Generate lexer files. -include(FeatureSummary) -include(PHP/Package/RE2C) - -if( - NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c -) - set_package_properties(RE2C PROPERTIES TYPE REQUIRED) +if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) + message(FATAL_ERROR "This file should be used with include().") endif() -if(RE2C_FOUND) - re2c( - php_ext_standard_url_scanner_ex - url_scanner_ex.re - ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c - OPTIONS --bit-vectors - CODEGEN - ) +include(PHP/Re2c) - re2c( - php_ext_standard_var_unserializer - var_unserializer.re - ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c - OPTIONS --bit-vectors - CODEGEN - ) -endif() +php_re2c( + php_ext_standard_url_scanner_ex + url_scanner_ex.re + ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c + APPEND OPTIONS --bit-vectors + CODEGEN +) + +php_re2c( + php_ext_standard_var_unserializer + var_unserializer.re + ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c + APPEND OPTIONS --bit-vectors + CODEGEN +) diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake index 1a8cef02..c0031598 100644 --- a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -1,47 +1,37 @@ # Generate lexer and parser files. -include(FeatureSummary) -include(PHP/Package/BISON) -include(PHP/Package/RE2C) - -if( - NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c - OR NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.h -) - set_package_properties(BISON PROPERTIES TYPE REQUIRED) +if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) + message(FATAL_ERROR "This file should be used with include().") endif() -if(BISON_FOUND) - if(CMAKE_SCRIPT_MODE_FILE) - set(verbose "") - else() - set(verbose VERBOSE) - endif() +include(PHP/Bison) - bison( - php_sapi_phpdbg_parser - phpdbg_parser.y - ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c - HEADER - ${verbose} - CODEGEN - ) +if(CMAKE_SCRIPT_MODE_FILE) + set(verbose "") +else() + set(verbose VERBOSE) endif() -if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c) - set_package_properties(RE2C PROPERTIES TYPE REQUIRED) -endif() +php_bison( + php_sapi_phpdbg_parser + phpdbg_parser.y + ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c + HEADER + ${verbose} + CODEGEN +) -if(RE2C_FOUND) - re2c( - php_sapi_phpdbg_lexer - phpdbg_lexer.l - ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c - OPTIONS - --conditions - --debug-output - --bit-vectors - --flex-syntax - CODEGEN - ) -endif() +include(PHP/Re2c) + +php_re2c( + php_sapi_phpdbg_lexer + phpdbg_lexer.l + ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c + APPEND + OPTIONS + --bit-vectors + --conditions + --debug-output + --flex-syntax + CODEGEN +) From f6a49bc187077cdb2aa48416d1de88f1154808af Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 6 Jan 2025 09:53:25 +0100 Subject: [PATCH 12/15] Use ExternalProject for downloading bison and re2c This simplifies downloading, configuring etc. The Bison downloading and configuring for now works only for GNU Bison. Should be improved further. --- cmake/cmake/Configuration.cmake | 3 + cmake/cmake/modules/FindBISON.cmake | 80 ++++++- cmake/cmake/modules/FindRE2C.cmake | 13 +- cmake/cmake/modules/PHP/Bison.cmake | 97 ++++---- cmake/cmake/modules/PHP/Re2c.cmake | 265 ++++++++++----------- cmake/cmake/scripts/GenerateGrammar.cmake | 8 +- cmake/ext/pdo/CMakeLists.txt | 2 +- cmake/ext/pdo/cmake/GenerateGrammar.cmake | 2 +- cmake/ext/phar/cmake/GenerateGrammar.cmake | 2 +- 9 files changed, 262 insertions(+), 210 deletions(-) diff --git a/cmake/cmake/Configuration.cmake b/cmake/cmake/Configuration.cmake index 7729f10d..994beb14 100644 --- a/cmake/cmake/Configuration.cmake +++ b/cmake/cmake/Configuration.cmake @@ -258,3 +258,6 @@ set_package_properties( URL "https://zlib.net/" DESCRIPTION "Compression library" ) + +# Set base directory for the ExternalProject CMake module across the PHP. +set_directory_properties(PROPERTIES EP_BASE ${PHP_BINARY_DIR}/_deps/EP) diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake index 0ba6063b..c44bb7da 100644 --- a/cmake/cmake/modules/FindBISON.cmake +++ b/cmake/cmake/modules/FindBISON.cmake @@ -8,6 +8,11 @@ See: https://cmake.org/cmake/help/latest/module/FindBISON.html #]=============================================================================] include(FeatureSummary) +include(FindPackageHandleStandardArgs) + +################################################################################ +# Configuration. +################################################################################ set_package_properties( BISON @@ -18,8 +23,73 @@ set_package_properties( # Find package with upstream CMake module; override CMAKE_MODULE_PATH to prevent # the maximum nesting/recursion depth error on some systems, like macOS. -set(_php_cmake_module_path ${CMAKE_MODULE_PATH}) -unset(CMAKE_MODULE_PATH) -include(FindBISON) -set(CMAKE_MODULE_PATH ${_php_cmake_module_path}) -unset(_php_cmake_module_path) +#set(_php_cmake_module_path ${CMAKE_MODULE_PATH}) +#unset(CMAKE_MODULE_PATH) +#include(FindBISON) +#set(CMAKE_MODULE_PATH ${_php_cmake_module_path}) +#unset(_php_cmake_module_path) + +################################################################################ +# Find the executable. +################################################################################ + +set(_reason "") + +find_program( + BISON_EXECUTABLE + NAMES bison win-bison win_bison + DOC "The path to the bison executable" +) +mark_as_advanced(BISON_EXECUTABLE) + +if(NOT BISON_EXECUTABLE) + string(APPEND _reason "The bison command-line executable not found. ") +endif() + +################################################################################ +# Check version. +################################################################################ + +block(PROPAGATE BISON_VERSION _reason) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) + set(test IS_EXECUTABLE) + else() + set(test EXISTS) + endif() + + if(${test} ${BISON_EXECUTABLE}) + execute_process( + COMMAND ${BISON_EXECUTABLE} --version + OUTPUT_VARIABLE version + RESULT_VARIABLE result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if(NOT result EQUAL 0) + string(APPEND _reason "Command ${BISON_EXECUTABLE} --version failed. ") + elseif(version) + # Bison++ + if(version MATCHES "^bison\\+\\+ Version ([^,]+)") + set(BISON_VERSION "${CMAKE_MATCH_1}") + # GNU Bison + elseif(version MATCHES "^bison \\(GNU Bison\\) ([^\n]+)\n") + set(BISON_VERSION "${CMAKE_MATCH_1}") + elseif(version MATCHES "^GNU Bison (version )?([^\n]+)") + set(BISON_VERSION "${CMAKE_MATCH_2}") + else() + string(APPEND _reason "Invalid version format. ") + endif() + endif() + endif() +endblock() + +find_package_handle_standard_args( + BISON + REQUIRED_VARS BISON_EXECUTABLE BISON_VERSION + VERSION_VAR BISON_VERSION + HANDLE_VERSION_RANGE + REASON_FAILURE_MESSAGE "${_reason}" +) + +unset(_reason) diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index 406c1a67..e8bce346 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -28,7 +28,7 @@ set_package_properties( ) ################################################################################ -# Find re2c. +# Find the executable. ################################################################################ set(_reason "") @@ -59,25 +59,20 @@ block(PROPAGATE RE2C_VERSION _reason) execute_process( COMMAND ${RE2C_EXECUTABLE} --version OUTPUT_VARIABLE version - ERROR_VARIABLE error RESULT_VARIABLE result + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_STRIP_TRAILING_WHITESPACE ) if(NOT result EQUAL 0) - string( - APPEND - _reason - "Command \"${RE2C_EXECUTABLE} --version\" failed:\n${error} " - ) + string(APPEND _reason "Command \"${RE2C_EXECUTABLE} --version\" failed. ") elseif(version MATCHES "^re2c ([0-9.]+[^\n]+)") find_package_check_version("${CMAKE_MATCH_1}" valid) if(valid) set(RE2C_VERSION "${CMAKE_MATCH_1}") endif() else() - string(APPEND _reason "Invalid version format:\n${version} ") + string(APPEND _reason "Invalid version format. ") endif() endif() endblock() diff --git a/cmake/cmake/modules/PHP/Bison.cmake b/cmake/cmake/modules/PHP/Bison.cmake index 0d7901a4..fe995d4e 100644 --- a/cmake/cmake/modules/PHP/Bison.cmake +++ b/cmake/cmake/modules/PHP/Bison.cmake @@ -5,10 +5,6 @@ Generate parser-related files with Bison. This module includes common `bison` configuration with minimum required version and common settings across the PHP build. -When `bison` cannot be found on the system or the found version is not suitable, -this module can also download and build it from its Git repository sources -release archive as part of the project build. - ## Configuration variables These variables can be set before including this module @@ -18,18 +14,16 @@ These variables can be set before including this module BISON package with `find_package(BISON ...)` in this module. +* `PHP_BISON_DOWNLOAD_VERSION` - When Bison cannot be found on the system or the + found version is not suitable, this module can also download and build it from + its release archive sources as part of the project build. Set which Bison + version should be downloaded. + * `PHP_BISON_OPTIONS` - A semicolon-separated list of default Bison options. This module sets some sensible defaults. When `php_bison(APPEND)` is used, the options specified in the `php_bison(OPTIONS ...)` are appended to these default global options. -* `PHP_BISON_DISABLE_DOWNLOAD` - Set to `TRUE` to disable downloading and - building bison package from source, when it is not found on the system or - found version is not suitable. - -* `PHP_BISON_DOWNLOAD_VERSION` - Override the default `bison` version to be - downloaded when not found on the system. - * `PHP_BISON_WORKING_DIRECTORY` - Set the default global working directory (`WORKING_DIRECTORY ` option) for all `php_bison()` invocations in the scope of the current directory. @@ -266,14 +260,13 @@ php_bison(foo parser.y parser.c OPTIONS $<$:--debug> --yacc) include_guard(GLOBAL) -include(FetchContent) include(FeatureSummary) ################################################################################ # Configuration. ################################################################################ -macro(_php_bison_config) +macro(php_bison_config) # Minimum required bison version. if(NOT PHP_BISON_VERSION) set(PHP_BISON_VERSION 3.0.0) @@ -365,7 +358,7 @@ function(php_bison name input output) set(outputs ${output}) set(extraOutputs "") - _php_bison_config() + php_bison_config() _php_bison_process_header_file() _php_bison_set_package_properties() @@ -375,12 +368,15 @@ function(php_bison name input output) set(quiet "QUIET") endif() - find_package(BISON ${PHP_BISON_VERSION} GLOBAL ${quiet}) + if(NOT TARGET Bison::Bison) + find_package(BISON ${PHP_BISON_VERSION} GLOBAL ${quiet}) + endif() if( NOT BISON_FOUND - AND NOT PHP_BISON_DISABLE_DOWNLOAD + AND PHP_BISON_DOWNLOAD_VERSION AND packageType STREQUAL "REQUIRED" + AND NOT CMAKE_SCRIPT_MODE_FILE ) _php_bison_download() endif() @@ -436,7 +432,6 @@ function(php_bison name input output) ${input} ${parsed_DEPENDS} $ - $ COMMENT "${message}" VERBATIM COMMAND_EXPAND_LISTS @@ -698,53 +693,49 @@ function(_php_bison_get_commands result) return(PROPAGATE ${result}) endfunction() -################################################################################ -# Download and build bison if not found. -################################################################################ - +# Download and build Bison if not found. function(_php_bison_download) set(BISON_VERSION ${PHP_BISON_DOWNLOAD_VERSION}) + set(BISON_FOUND TRUE) - message(STATUS "Downloading bison ${BISON_VERSION}") - FetchContent_Populate( - BISON - URL https://ftp.gnu.org/gnu/bison/bison-${BISON_VERSION}.tar.gz - SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/bison - ) + if(TARGET Bison::Bison) + return(PROPAGATE BISON_FOUND BISON_VERSION) + endif() - message(STATUS "Configuring Bison ${BISON_VERSION}") - execute_process( - COMMAND ./configure - OUTPUT_VARIABLE result - ECHO_OUTPUT_VARIABLE - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_deps/bison - ) + message(STATUS "Bison ${BISON_VERSION} will be downloaded at build phase") + + include(ExternalProject) - message(STATUS "Building Bison ${BISON_VERSION}") - include(ProcessorCount) - processorcount(processors) - execute_process( - COMMAND ${CMAKE_MAKE_PROGRAM} -j${processors} - OUTPUT_VARIABLE result - ECHO_OUTPUT_VARIABLE - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_deps/bison + ExternalProject_Add( + bison + URL https://ftp.gnu.org/gnu/bison/bison-${BISON_VERSION}.tar.gz + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + CONFIGURE_COMMAND + /configure + --prefix= + --enable-silent-rules + --disable-yacc + --disable-dependency-tracking + LOG_INSTALL TRUE ) - set(BISON_FOUND TRUE) + # Set bison executable. + ExternalProject_Get_Property(bison INSTALL_DIR) + set_property(CACHE BISON_EXECUTABLE PROPERTY VALUE ${INSTALL_DIR}/bin/bison) - set_property( - CACHE BISON_EXECUTABLE - PROPERTY VALUE ${CMAKE_BINARY_DIR}/_deps/bison/src/bison + add_executable(Bison::Bison IMPORTED GLOBAL) + set_target_properties( + Bison::Bison + PROPERTIES IMPORTED_LOCATION ${BISON_EXECUTABLE} ) + add_dependencies(Bison::Bison bison) # Move dependency to PACKAGES_FOUND. - block() - get_property(packagesNotFound GLOBAL PROPERTY PACKAGES_NOT_FOUND) - list(REMOVE_ITEM packagesNotFound BISON) - set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND packagesNotFound) - get_property(packagesFound GLOBAL PROPERTY PACKAGES_FOUND) - set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND BISON) - endblock() + get_property(packagesNotFound GLOBAL PROPERTY PACKAGES_NOT_FOUND) + list(REMOVE_ITEM packagesNotFound BISON) + set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND packagesNotFound) + get_property(packagesFound GLOBAL PROPERTY PACKAGES_FOUND) + set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND BISON) return(PROPAGATE BISON_FOUND BISON_VERSION) endfunction() diff --git a/cmake/cmake/modules/PHP/Re2c.cmake b/cmake/cmake/modules/PHP/Re2c.cmake index 136f8aa5..439b1a9a 100644 --- a/cmake/cmake/modules/PHP/Re2c.cmake +++ b/cmake/cmake/modules/PHP/Re2c.cmake @@ -5,10 +5,6 @@ Generate lexer-related files with re2c. This module includes common `re2c` configuration with minimum required version and common settings across the PHP build. -When `re2c` cannot be found on the system or the found version is not suitable, -this module can also download and build it from its Git repository sources -release archive as part of the project build. - ## Configuration variables These variables can be set before including this module @@ -17,6 +13,11 @@ These variables can be set before including this module * `PHP_RE2C_VERSION` - The re2c version constraint, when looking for RE2C package with `find_package(RE2C ...)`. +* `PHP_RE2C_DOWNLOAD_VERSION` - When re2c cannot be found on the system or the + found version is not suitable, this module can also download and build it from + its release archive sources as part of the project build. Set which re2c + version should be downloaded. + * `PHP_RE2C_COMPUTED_GOTOS` - Add the `COMPUTED_GOTOS TRUE` option to all `php_re2c()` invocations in the scope of current directory. @@ -25,13 +26,6 @@ These variables can be set before including this module options specified in the `php_re2c(OPTIONS ...)` are appended to these default global options. -* `PHP_RE2C_DISABLE_DOWNLOAD` - Set to `TRUE` to disable downloading and - building RE2C package from source, when it is not found on the system or found - version is not suitable. - -* `PHP_RE2C_DOWNLOAD_VERSION` - Override the default `re2c` version to be - downloaded when not found on the system. - * `PHP_RE2C_WORKING_DIRECTORY` - Set the default global working directory (`WORKING_DIRECTORY ` option) for all `php_re2c()` invocations in the scope of the current directory. @@ -266,7 +260,7 @@ include(FeatureSummary) option(PHP_RE2C_COMPUTED_GOTOS "Enable computed goto GCC extension with re2c") mark_as_advanced(PHP_RE2C_COMPUTED_GOTOS) -macro(_php_re2c_config) +macro(php_re2c_config) # Minimum required re2c version. if(NOT PHP_RE2C_VERSION) set(PHP_RE2C_VERSION 1.0.3) @@ -326,13 +320,6 @@ function(php_re2c name input output) "OPTIONS;DEPENDS" # multi-value keywords ) - _php_re2c_config() - - find_package(RE2C ${PHP_RE2C_VERSION} GLOBAL) - if(NOT RE2C_FOUND AND NOT PHP_RE2C_DISABLE_DOWNLOAD) - _php_re2c_download() - endif() - if(parsed_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unrecognized arguments: ${parsed_UNPARSED_ARGUMENTS}") endif() @@ -365,10 +352,32 @@ function(php_re2c name input output) set(outputs ${output}) + php_re2c_config() + _php_re2c_process_header_file() + _php_re2c_set_package_properties() + + get_property(packageType GLOBAL PROPERTY _CMAKE_RE2C_TYPE) + set(quiet "") + if(NOT packageType STREQUAL "REQUIRED") + set(quiet "QUIET") + endif() + + if(NOT TARGET RE2C::RE2C) + find_package(RE2C ${PHP_RE2C_VERSION} GLOBAL ${quiet}) + endif() + + if( + NOT RE2C_FOUND + AND PHP_RE2C_DOWNLOAD_VERSION + AND packageType STREQUAL "REQUIRED" + AND NOT CMAKE_SCRIPT_MODE_FILE + ) + _php_re2c_download() + endif() + _php_re2c_process_working_directory() _php_re2c_process_options() _php_re2c_process_header_option() - _php_re2c_set_package_properties() if(NOT CMAKE_SCRIPT_MODE_FILE) add_custom_target(${name} SOURCES ${input} DEPENDS ${outputs}) @@ -417,7 +426,6 @@ function(php_re2c name input output) ${input} ${parsed_DEPENDS} $ - $ COMMENT "${message}" VERBATIM COMMAND_EXPAND_LISTS @@ -426,6 +434,58 @@ function(php_re2c name input output) ) endfunction() +# Process header file. +function(_php_re2c_process_header_file) + if(NOT parsed_HEADER) + return() + endif() + + set(header ${parsed_HEADER}) + if(NOT IS_ABSOLUTE "${header}") + cmake_path( + ABSOLUTE_PATH + header + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + else() + cmake_path(SET header NORMALIZE "${header}") + endif() + + list(APPEND outputs ${header}) + + return(PROPAGATE header outputs) +endfunction() + +# Set RE2C package properties TYPE and PURPOSE. If lexer-related output files +# are already generated, for example, shipped with the released archive, then +# RE2C package type is set to RECOMMENDED. If generated files are not +# available, for example, when building from a Git repository, type is set to +# REQUIRED to generate files during the build. +function(_php_re2c_set_package_properties) + set_package_properties(RE2C PROPERTIES TYPE RECOMMENDED) + foreach(output IN LISTS outputs) + if(NOT EXISTS ${output}) + set_package_properties(RE2C PROPERTIES TYPE REQUIRED) + break() + endif() + endforeach() + + # Set package PURPOSE property. + cmake_path( + RELATIVE_PATH + output + BASE_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE relativePath + ) + if(relativePath STREQUAL ".") + set(purpose "Necessary to generate lexer files.") + else() + set(purpose "Necessary to generate ${relativePath} lexer files.") + endif() + set_package_properties(RE2C PROPERTIES PURPOSE "${purpose}") +endfunction() + # Process working directory. function(_php_re2c_process_working_directory) if(NOT parsed_WORKING_DIRECTORY) @@ -492,20 +552,6 @@ function(_php_re2c_process_header_option) return() endif() - set(header ${parsed_HEADER}) - if(NOT IS_ABSOLUTE "${header}") - cmake_path( - ABSOLUTE_PATH - header - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - else() - cmake_path(SET header NORMALIZE "${header}") - endif() - - list(APPEND outputs ${header}) - # When header option is used before re2c version 1.2, also the '-c' option # is required. Before 1.1 '-c' long variant is '--start-conditions' and # after 1.1 '--conditions'. @@ -521,7 +567,7 @@ function(_php_re2c_process_header_option) list(APPEND options --type-header ${header}) endif() - return(PROPAGATE outputs options) + return(PROPAGATE options) endfunction() # Check for re2c --computed-gotos option. @@ -562,36 +608,8 @@ function(_php_re2c_check_computed_gotos result) endif() set(${result} ${_PHP_RE2C_HAVE_COMPUTED_GOTOS}) - return(PROPAGATE ${result}) -endfunction() - -# Set RE2C package properties TYPE and PURPOSE. If lexer-related output files -# are already generated, for example, shipped with the released archive, then -# RE2C package type is set to RECOMMENDED. If generated files are not -# available, for example, when building from a Git repository, type is set to -# REQUIRED to generate files during the build. -function(_php_re2c_set_package_properties) - set_package_properties(RE2C PROPERTIES TYPE RECOMMENDED) - foreach(output IN LISTS outputs) - if(NOT EXISTS ${output}) - set_package_properties(RE2C PROPERTIES TYPE REQUIRED) - break() - endif() - endforeach() - # Set package PURPOSE property. - cmake_path( - RELATIVE_PATH - output - BASE_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE relativePath - ) - if(relativePath STREQUAL ".") - set(purpose "Necessary to generate lexer files.") - else() - set(purpose "Necessary to generate ${relativePath} lexer files.") - endif() - set_package_properties(RE2C PROPERTIES PURPOSE "${purpose}") + return(PROPAGATE ${result}) endfunction() # Assemble commands for add_custom_command() and execute_process(). @@ -647,89 +665,62 @@ function(_php_re2c_get_commands result) return(PROPAGATE ${result}) endfunction() -################################################################################ # Download and build re2c if not found. -################################################################################ - function(_php_re2c_download) set(RE2C_VERSION ${PHP_RE2C_DOWNLOAD_VERSION}) + set(RE2C_FOUND TRUE) - message(STATUS "Downloading re2c ${RE2C_VERSION}") - - if(NOT CMAKE_SCRIPT_MODE_FILE AND NOT TARGET RE2C::RE2C AND NOT TARGET re2c) - include(ExternalProject) - - # Configure re2c build. - if(RE2C_VERSION VERSION_GREATER_EQUAL 4) - set( - _re2cDownloadOptions - -DRE2C_BUILD_RE2D=OFF - -DRE2C_BUILD_RE2HS=OFF - -DRE2C_BUILD_RE2JAVA=OFF - -DRE2C_BUILD_RE2JS=OFF - -DRE2C_BUILD_RE2OCAML=OFF - -DRE2C_BUILD_RE2PY=OFF - -DRE2C_BUILD_RE2V=OFF - -DRE2C_BUILD_RE2ZIG=OFF - -DRE2C_BUILD_TESTS=OFF - ) - else() - set( - _re2cDownloadOptions - -DCMAKE_DISABLE_FIND_PACKAGE_Python3=TRUE - -DPython3_VERSION=3.7 - ) - endif() + if(TARGET RE2C::RE2C) + return(PROPAGATE RE2C_FOUND RE2C_VERSION) + endif() - ExternalProject_Add( - re2c - URL - https://github.com/skvadrik/re2c/archive/refs/tags/${RE2C_VERSION}.tar.gz - CMAKE_ARGS - -DRE2C_BUILD_RE2GO=OFF - -DRE2C_BUILD_RE2RUST=OFF - ${_re2cDownloadOptions} - INSTALL_COMMAND "" - ) + message(STATUS "Re2c ${RE2C_VERSION} will be downloaded at build phase") + + include(ExternalProject) - # Set re2c executable. - ExternalProject_Get_property(re2c BINARY_DIR) - add_executable(RE2C::RE2C IMPORTED) - set_target_properties( - RE2C::RE2C - PROPERTIES IMPORTED_LOCATION ${BINARY_DIR}/re2c + # Configure re2c build. + if(RE2C_VERSION VERSION_GREATER_EQUAL 4) + set( + re2cOptions + -DRE2C_BUILD_RE2D=OFF + -DRE2C_BUILD_RE2HS=OFF + -DRE2C_BUILD_RE2JAVA=OFF + -DRE2C_BUILD_RE2JS=OFF + -DRE2C_BUILD_RE2OCAML=OFF + -DRE2C_BUILD_RE2PY=OFF + -DRE2C_BUILD_RE2V=OFF + -DRE2C_BUILD_RE2ZIG=OFF + -DRE2C_BUILD_TESTS=OFF ) - add_dependencies(RE2C::RE2C re2c) - set_property(CACHE RE2C_EXECUTABLE PROPERTY VALUE ${BINARY_DIR}/re2c) else() - include(FetchContent) - FetchContent_Populate( - RE2C - URL https://github.com/skvadrik/re2c/archive/refs/tags/${RE2C_VERSION}.tar.gz - SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/re2c + set( + re2cOptions + -DCMAKE_DISABLE_FIND_PACKAGE_Python3=TRUE + -DPython3_VERSION=3.7 ) + endif() - message(STATUS "Configuring re2c ${RE2C_VERSION}") - execute_process( - COMMAND ${CMAKE_COMMAND} -B re2c-build - OUTPUT_VARIABLE result - ECHO_OUTPUT_VARIABLE - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_deps/re2c - ) + ExternalProject_Add( + re2c + URL + https://github.com/skvadrik/re2c/archive/refs/tags/${RE2C_VERSION}.tar.gz + CMAKE_ARGS + -DRE2C_BUILD_RE2GO=OFF + -DRE2C_BUILD_RE2RUST=OFF + ${re2cOptions} + INSTALL_COMMAND "" + ) - message(STATUS "Building re2c ${RE2C_VERSION}") - execute_process( - COMMAND ${CMAKE_COMMAND} --build re2c-build -j - OUTPUT_VARIABLE result - ECHO_OUTPUT_VARIABLE - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_deps/re2c - ) + # Set re2c executable. + ExternalProject_Get_Property(re2c BINARY_DIR) + set_property(CACHE RE2C_EXECUTABLE PROPERTY VALUE ${BINARY_DIR}/re2c) - set_property( - CACHE RE2C_EXECUTABLE - PROPERTY VALUE ${CMAKE_BINARY_DIR}/_deps/re2c/re2c-build/re2c - ) - endif() + add_executable(RE2C::RE2C IMPORTED GLOBAL) + set_target_properties( + RE2C::RE2C + PROPERTIES IMPORTED_LOCATION ${RE2C_EXECUTABLE} + ) + add_dependencies(RE2C::RE2C re2c) # Move dependency to PACKAGES_FOUND. get_property(packagesNotFound GLOBAL PROPERTY PACKAGES_NOT_FOUND) @@ -738,7 +729,5 @@ function(_php_re2c_download) get_property(packagesFound GLOBAL PROPERTY PACKAGES_FOUND) set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND RE2C) - set(RE2C_FOUND TRUE) - return(PROPAGATE RE2C_FOUND RE2C_VERSION) endfunction() diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake index 333e0935..384c5167 100755 --- a/cmake/cmake/scripts/GenerateGrammar.cmake +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -1,7 +1,7 @@ #!/usr/bin/env -S cmake -P # -# CMake-based command-line script to generate the parser files using bison and -# lexer files using bison. +# CMake-based command-line script to generate the parser files with bison and +# lexer files with re2c. # # Run as: # @@ -33,9 +33,13 @@ list(APPEND CMAKE_MODULE_PATH ${PHP_SOURCE_DIR}/cmake/modules) include(FeatureSummary) include(PHP/Bison) +php_bison_config() +find_package(BISON ${PHP_BISON_VERSION}) set_package_properties(BISON PROPERTIES TYPE REQUIRED) include(PHP/Re2c) +php_re2c_config() +find_package(RE2C ${PHP_RE2C_VERSION}) set_package_properties(RE2C PROPERTIES TYPE REQUIRED) feature_summary( diff --git a/cmake/ext/pdo/CMakeLists.txt b/cmake/ext/pdo/CMakeLists.txt index 671d9102..e6b02703 100644 --- a/cmake/ext/pdo/CMakeLists.txt +++ b/cmake/ext/pdo/CMakeLists.txt @@ -76,7 +76,7 @@ target_sources( add_dependencies(php_ext_pdo php_ext_spl) ################################################################################ -# Generate lexer. +# Generate lexer files. ################################################################################ include(cmake/GenerateGrammar.cmake) diff --git a/cmake/ext/pdo/cmake/GenerateGrammar.cmake b/cmake/ext/pdo/cmake/GenerateGrammar.cmake index bf8b0d76..91c8c6f4 100644 --- a/cmake/ext/pdo/cmake/GenerateGrammar.cmake +++ b/cmake/ext/pdo/cmake/GenerateGrammar.cmake @@ -1,4 +1,4 @@ -# Generate lexer. +# Generate lexer files. if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) message(FATAL_ERROR "This file should be used with include().") diff --git a/cmake/ext/phar/cmake/GenerateGrammar.cmake b/cmake/ext/phar/cmake/GenerateGrammar.cmake index 30652c90..59a9202b 100644 --- a/cmake/ext/phar/cmake/GenerateGrammar.cmake +++ b/cmake/ext/phar/cmake/GenerateGrammar.cmake @@ -1,4 +1,4 @@ -# Generate lexer. +# Generate lexer files. if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) message(FATAL_ERROR "This file should be used with include().") From ddd7b8da5c48405528901a0ca17cfff204d320b4 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 6 Jan 2025 10:30:52 +0100 Subject: [PATCH 13/15] Remove bison from CI --- .github/workflows/ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 428dcf0c..56f779e6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -63,7 +63,6 @@ jobs: run: | sudo apt-get -y install \ build-essential \ - bison \ libssl-dev \ libpcre2-dev \ libsqlite3-dev \ From 0d9a2cf77713c432c6a8593a112ab3c94eced8b1 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Wed, 8 Jan 2025 06:24:25 +0100 Subject: [PATCH 14/15] Simplify usage and make configuration extendable --- cmake/Zend/cmake/GenerateGrammar.cmake | 6 +- cmake/cmake/modules/FindBISON.cmake | 82 +--- cmake/cmake/modules/PHP/Bison.cmake | 395 +++++++---------- cmake/cmake/modules/PHP/Re2c.cmake | 406 +++++++----------- cmake/cmake/scripts/GenerateGrammar.cmake | 14 +- cmake/ext/json/cmake/GenerateGrammar.cmake | 4 +- cmake/ext/pdo/cmake/GenerateGrammar.cmake | 1 + cmake/ext/phar/cmake/GenerateGrammar.cmake | 3 +- .../ext/standard/cmake/GenerateGrammar.cmake | 6 +- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 3 +- 10 files changed, 342 insertions(+), 578 deletions(-) diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake index 10a4474d..9f1b1b3f 100644 --- a/cmake/Zend/cmake/GenerateGrammar.cmake +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -17,6 +17,7 @@ php_bison( zend_ini_parser.y ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_parser.c HEADER + ADD_DEFAULT_OPTIONS ${verbose} CODEGEN ) @@ -26,6 +27,7 @@ php_bison( zend_language_parser.y ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_parser.c HEADER + ADD_DEFAULT_OPTIONS ${verbose} CODEGEN ) @@ -103,7 +105,7 @@ php_re2c( zend_ini_scanner.l ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner.c HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_ini_scanner_defs.h - APPEND + ADD_DEFAULT_OPTIONS OPTIONS --bit-vectors --case-inverted @@ -118,7 +120,7 @@ php_re2c( zend_language_scanner.l ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner.c HEADER ${CMAKE_CURRENT_SOURCE_DIR}/zend_language_scanner_defs.h - APPEND + ADD_DEFAULT_OPTIONS OPTIONS --bit-vectors --case-inverted diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake index c44bb7da..39fea516 100644 --- a/cmake/cmake/modules/FindBISON.cmake +++ b/cmake/cmake/modules/FindBISON.cmake @@ -3,16 +3,11 @@ Find `bison`, the general-purpose parser generator, command-line executable. -This module extends the upstream CMake `FindBISON` module. +This module extends the CMake `FindBISON` module. See: https://cmake.org/cmake/help/latest/module/FindBISON.html #]=============================================================================] include(FeatureSummary) -include(FindPackageHandleStandardArgs) - -################################################################################ -# Configuration. -################################################################################ set_package_properties( BISON @@ -21,75 +16,6 @@ set_package_properties( DESCRIPTION "General-purpose parser generator" ) -# Find package with upstream CMake module; override CMAKE_MODULE_PATH to prevent -# the maximum nesting/recursion depth error on some systems, like macOS. -#set(_php_cmake_module_path ${CMAKE_MODULE_PATH}) -#unset(CMAKE_MODULE_PATH) -#include(FindBISON) -#set(CMAKE_MODULE_PATH ${_php_cmake_module_path}) -#unset(_php_cmake_module_path) - -################################################################################ -# Find the executable. -################################################################################ - -set(_reason "") - -find_program( - BISON_EXECUTABLE - NAMES bison win-bison win_bison - DOC "The path to the bison executable" -) -mark_as_advanced(BISON_EXECUTABLE) - -if(NOT BISON_EXECUTABLE) - string(APPEND _reason "The bison command-line executable not found. ") -endif() - -################################################################################ -# Check version. -################################################################################ - -block(PROPAGATE BISON_VERSION _reason) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) - set(test IS_EXECUTABLE) - else() - set(test EXISTS) - endif() - - if(${test} ${BISON_EXECUTABLE}) - execute_process( - COMMAND ${BISON_EXECUTABLE} --version - OUTPUT_VARIABLE version - RESULT_VARIABLE result - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if(NOT result EQUAL 0) - string(APPEND _reason "Command ${BISON_EXECUTABLE} --version failed. ") - elseif(version) - # Bison++ - if(version MATCHES "^bison\\+\\+ Version ([^,]+)") - set(BISON_VERSION "${CMAKE_MATCH_1}") - # GNU Bison - elseif(version MATCHES "^bison \\(GNU Bison\\) ([^\n]+)\n") - set(BISON_VERSION "${CMAKE_MATCH_1}") - elseif(version MATCHES "^GNU Bison (version )?([^\n]+)") - set(BISON_VERSION "${CMAKE_MATCH_2}") - else() - string(APPEND _reason "Invalid version format. ") - endif() - endif() - endif() -endblock() - -find_package_handle_standard_args( - BISON - REQUIRED_VARS BISON_EXECUTABLE BISON_VERSION - VERSION_VAR BISON_VERSION - HANDLE_VERSION_RANGE - REASON_FAILURE_MESSAGE "${_reason}" -) - -unset(_reason) +# Include CMake find module. Absolute path prevents the maximum +# nesting/recursion depth error on some systems, like macOS. +include(${CMAKE_ROOT}/Modules/FindBISON.cmake) diff --git a/cmake/cmake/modules/PHP/Bison.cmake b/cmake/cmake/modules/PHP/Bison.cmake index fe995d4e..50c63719 100644 --- a/cmake/cmake/modules/PHP/Bison.cmake +++ b/cmake/cmake/modules/PHP/Bison.cmake @@ -1,39 +1,13 @@ #[=============================================================================[ # PHP/Bison -Generate parser-related files with Bison. This module includes common `bison` -configuration with minimum required version and common settings across the -PHP build. +Generate parser files with Bison. -## Configuration variables - -These variables can be set before including this module -`include(PHP/Bison)`: - -* `PHP_BISON_VERSION` - The bison version constraint, when looking for - BISON package with `find_package(BISON ...)` in this - module. - -* `PHP_BISON_DOWNLOAD_VERSION` - When Bison cannot be found on the system or the - found version is not suitable, this module can also download and build it from - its release archive sources as part of the project build. Set which Bison - version should be downloaded. - -* `PHP_BISON_OPTIONS` - A semicolon-separated list of default Bison options. - This module sets some sensible defaults. When `php_bison(APPEND)` is used, the - options specified in the `php_bison(OPTIONS ...)` are appended to - these default global options. - -* `PHP_BISON_WORKING_DIRECTORY` - Set the default global working directory - (`WORKING_DIRECTORY ` option) for all `php_bison()` invocations in the - scope of the current directory. - -## Functions provided by this module +## Functions ### `php_bison()` -Generate parser file from the given template file using the `bison` parser -generator. +Generate parser file from the given template file using the Bison generator. ```cmake php_bison( @@ -41,7 +15,7 @@ php_bison( [HEADER | HEADER_FILE
] - [APPEND] + [ADD_DEFAULT_OPTIONS] [OPTIONS ...] [DEPENDS ...] [VERBOSE [REPORT_FILE ]] @@ -51,107 +25,105 @@ php_bison( ) ``` -This creates a custom CMake target `` and adds a custom command that -generates parser file `` from the given `` template file using -the `bison` parser generator. Relative source file path `` is interpreted -as being relative to the current source directory. Relative `` file path -is interpreted as being relative to the current binary directory. If generated -files are already available (for example, shipped with the released archive), -and Bison is not found, it will create a custom target but skip the `bison` -command-line execution. +This creates a CMake target `` and adds a command that generates parser +file `` from the given `` template file using the `bison` parser +generator. Relative source file path `` is interpreted as being relative +to the current source directory. Relative `` file path is interpreted as +being relative to the current binary directory. If generated files are already +available (for example, shipped with the released archive), and Bison is not +found, it will create a custom target but skip the `bison` command-line +execution. When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it -generates the parser without creating a target, to make it easier to use in -various scenarios. +generates the parser right away without creating a target. #### Options -* `HEADER` - Produce also a header file automatically. +* `HEADER` - Generate also a header file automatically. -* `HEADER_FILE
` - Produce a specified header file `
`. Relative +* `HEADER_FILE
` - Generate a specified header file `
`. Relative header file path is interpreted as being relative to the current binary directory. -* `APPEND` - If specified, the `PHP_BISON_OPTIONS` are prepended to - `OPTIONS ` for the current `bison` invocation. +* `ADD_DEFAULT_OPTIONS` - When specified, the options from the + `PHP_BISON_OPTIONS` configuration variable are prepended to the current + `bison` command-line invocation. This module provides some sensible defaults. * `OPTIONS ...` - List of additional options to pass to the `bison` - command-line tool. Module sets common-sensible default options. + command-line tool. Supports generator expressions. In script mode + (`CMAKE_SCRIPT_MODE_FILE`) generator expressions are stripped as they can't be + determined. * `DEPENDS ...` - Optional list of dependent files to regenerate the output file. -* `VERBOSE` - This adds the `--verbose` (`-v`) command-line option to - `bison` executable and will create extra output file - `.output` containing verbose descriptions of the - grammar and parser. File will be created in the current binary directory. +* `VERBOSE` - This adds the `--verbose` (`-v`) command-line option to and will + create extra output file `.output` containing verbose + descriptions of the grammar and parser. File will be by default created in the + current binary directory. * `REPORT_FILE ` - This adds the `--report-file=` command-line - option to `bison` executable and will create verbose information report in the - specified ``. This option must be used together with the `VERBOSE` - option. Relative file path is interpreted as being relative to the current - binary directory. + option and will create verbose information report in the specified ``. + This option must be used together with the `VERBOSE` option. Relative file + path is interpreted as being relative to the current binary directory. -* `CODEGEN` - Adds the `CODEGEN` option to the bison's `add_custom_command()` - call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which - provides a global CMake `codegen` target for convenience to call only the - code-generation-related targets and skips the majority of the build: +* `CODEGEN` - This adds the `CODEGEN` option to the `add_custom_command()` call. + Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which provides a + global CMake `codegen` target for convenience to call only the + code-generation-related targets and skip the majority of the build: ```sh cmake --build --target codegen ``` -* `WORKING_DIRECTORY ` - The path where the `bison` command - is executed. Relative `` path is interpreted as being - relative to the current binary directory. If not set, `bison` is by default - executed in the current binary directory (`CMAKE_CURRENT_BINARY_DIR`). If - variable `PHP_BISON_WORKING_DIRECTORY` is set before calling the - `php_bison()` without this option, it will set the default working directory - to that. +* `WORKING_DIRECTORY ` - The path where the `bison` is + executed. Relative `` path is interpreted as being relative + to the current binary directory. If not set, `bison` is by default executed in + the `PHP_SOURCE_DIR` when building the php-src repository. Otherwise it is + executed in the directory of the `` file. If variable + `PHP_BISON_WORKING_DIRECTORY` is set before calling the `php_bison()` without + this option, it will set the default working directory to that instead. * `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `bison` - command-line invocations. By default all file paths are added to `bison` - command-line relative to the working directory. Using relative paths is - convenient when line directives (`#line ...`) are generated in the output - parser files to not show the full path on the disk, when file is committed to - Git repository, where multiple people develop. + command-line invocations. By default all file paths are added to `bison` as + relative to the working directory. Using relative paths is convenient when + line directives (`#line ...`) are generated in the output files to not show + the full path on the disk, if file is committed to Git repository. When this option is enabled: ```c - #line 15 "/home/user/projects/php-src/sapi/phpdbg/phpdbg_parser.y" + #line 15 "/home/user/php-src/sapi/phpdbg/phpdbg_parser.y" ``` - Without this option, relative paths will be generated: + Without this option relative paths are generated: ```c #line 15 "sapi/phpdbg/phpdbg_parser.y" ``` -## Examples - -### Basic usage - -```cmake -# CMakeLists.txt +## Configuration variables -include(PHP/Bison) +These variables can be set before using this module to configure behavior: -php_bison(...) -``` +* `PHP_BISON_OPTIONS` - A semicolon-separated list of default Bison command-line + options when `php_bison(ADD_DEFAULT_OPTIONS)` is used. -### Minimum bison version +* `PHP_BISON_VERSION` - The version constraint, when looking for BISON package + with `find_package(BISON ...)` in this module. -To override the module default minimum required `bison` version: +* `PHP_BISON_VERSION_DOWNLOAD` - When Bison cannot be found on the system or the + found version is not suitable, this module can also download and build it from + its release archive sources as part of the project build. Set which version + should be downloaded. -```cmake -# CMakeLists.txt +* `PHP_BISON_WORKING_DIRECTORY` - Set the default global working directory + for all `php_bison()` invocations in the directory scope where the + `WORKING_DIRECTORY ` option is not set. -set(PHP_BISON_VERSION 3.8.0) -include(PHP/Bison) -``` +## Examples -### Specifying options +### Basic usage ```cmake # CMakeLists.txt @@ -163,52 +135,33 @@ php_bison(foo foo.y foo.c OPTIONS -Wall --debug) # bison -Wall --debug foo.y --output foo.c ``` -This module also provides some sensible default options, which can be prepended -to current specified options using the `APPEND` keyword. +### Specifying options -```cmake -# CMakeLists.txt +This module provides some default options when using the `ADD_DEFAULT_OPTIONS`: +```cmake include(PHP/Bison) -php_bison(foo foo.y foo.c APPEND OPTIONS --debug --yacc) +php_bison(foo foo.y foo.c ADD_DEFAULT_OPTIONS OPTIONS --debug --yacc) # This will run: # bison -Wall --no-lines --debug --yacc foo.y --output foo.c ``` -Generator expressions are supported in `php_bison(OPTIONS)` when running in -normal CMake `project()` mode: +### Generator expressions ```cmake -# CMakeLists.txt - include(PHP/Bison) -php_bison(foo foo.y foo.c OPTIONS $<$:--debug>) +php_bison(foo foo.y foo.c OPTIONS $<$:--debug> --yacc) # When build type is Debug, this will run: -# bison --debug foo.y --output foo.c -# For other build types, this will run: -# bison foo.y --output foo.c -``` - -Setting default options for all `php_bison()` calls in the current directory -scope: - -```cmake -# CMakeLists.txt - -set(PHP_BISON_OPTIONS -Werror --no-lines) - -include(PHP/Bison) - -php_bison(foo foo.y foo.c APPEND OPTIONS --debug) -# This will run: -# bison -Werror --no-lines --debug foo.y --output foo.c +# bison --debug --yacc foo.y --output foo.c +# For other build types (including the script mode - CMAKE_SCRIPT_MODE_FILE): +# bison --yacc foo.y --output foo.c ``` ### Custom target usage -To specify dependencies with the custom target created by `bison()`: +To specify dependencies with the custom target created by `php_bison()`: ```cmake # CMakeLists.txt @@ -220,65 +173,57 @@ add_dependencies(some_target foo_parser) ``` Or to run only the specific `foo_parser` target, which generates the -parser-related files +parser-related files: ```sh cmake --build --target foo_parser ``` -### Script mode - -When running `php_bison()` in script mode (`CMAKE_SCRIPT_MODE_FILE`): +### Module configuration -```sh -cmake -P script.cmake -``` - -the generated file is created right away, without creating target: +To specify minimum required Bison version other than the module's default, +`find_package(BISON)` can be called before the `php_bison()`: ```cmake -# script.cmake - +find_package(BISON 3.7) include(PHP/Bison) - -php_bison(foo_parser parser.y parser.c) +php_bison(...) ``` -In script mode also all options with generator expressions are removed from the -invocation as they can't be parsed and determined in such mode. +Set `PHP_BISON_*` variables to override module default configuration: ```cmake -# script.cmake - +set(PHP_BISON_VERSION_DOWNLOAD 3.7) include(PHP/Bison) - -php_bison(foo parser.y parser.c OPTIONS $<$:--debug> --yacc) -# This will run: -# bison --yacc parser.y --output parser.c +php_bison(...) ``` #]=============================================================================] -include_guard(GLOBAL) - -include(FeatureSummary) - ################################################################################ # Configuration. ################################################################################ -macro(php_bison_config) +macro(_php_bison_config) # Minimum required bison version. if(NOT PHP_BISON_VERSION) set(PHP_BISON_VERSION 3.0.0) endif() # If bison is not found on the system, set which version to download. - if(NOT PHP_BISON_DOWNLOAD_VERSION) - set(PHP_BISON_DOWNLOAD_VERSION 3.8.2) + if(NOT PHP_BISON_VERSION_DOWNLOAD) + set(PHP_BISON_VERSION_DOWNLOAD 3.8.2) endif() +endmacro() + +_php_bison_config() + +include_guard(GLOBAL) + +include(FeatureSummary) - # Add Bison --no-lines (-l) option to not generate '#line' directives based on - # this module usage and build type. +# Configuration after find_package() in this module. +macro(_php_bison_config_options) + # Add --no-lines (-l) option to not output '#line' directives. if(NOT PHP_BISON_OPTIONS) if(CMAKE_SCRIPT_MODE_FILE) set(PHP_BISON_OPTIONS --no-lines) @@ -287,16 +232,7 @@ macro(php_bison_config) endif() # Report all warnings. - list(PREPEND PHP_BISON_OPTIONS -Wall) - endif() - - # Set working directory for all bison invocations. - if(NOT PHP_BISON_WORKING_DIRECTORY) - if(PHP_SOURCE_DIR) - set(PHP_BISON_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) - else() - set(PHP_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - endif() + list(APPEND PHP_BISON_OPTIONS -Wall) endif() endmacro() @@ -309,7 +245,7 @@ function(php_bison name input output) PARSE_ARGV 3 parsed # prefix - "APPEND;CODEGEN;HEADER;VERBOSE;ABSOLUTE_PATHS" # options + "ADD_DEFAULT_OPTIONS;CODEGEN;HEADER;VERBOSE;ABSOLUTE_PATHS" # options "HEADER_FILE;WORKING_DIRECTORY;REPORT_FILE" # one-value keywords "OPTIONS;DEPENDS" # multi-value keywords ) @@ -333,32 +269,23 @@ function(php_bison name input output) message(FATAL_ERROR "'REPORT_FILE' option requires also 'VERBOSE' option.") endif() - if(NOT IS_ABSOLUTE "${input}") - cmake_path( - ABSOLUTE_PATH - input - BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - NORMALIZE - ) - else() - cmake_path(SET input NORMALIZE "${input}") - endif() + cmake_path( + ABSOLUTE_PATH + input + BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + NORMALIZE + ) - if(NOT IS_ABSOLUTE "${output}") - cmake_path( - ABSOLUTE_PATH - output - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - else() - cmake_path(SET output NORMALIZE "${output}") - endif() + cmake_path( + ABSOLUTE_PATH + output + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) set(outputs ${output}) set(extraOutputs "") - php_bison_config() _php_bison_process_header_file() _php_bison_set_package_properties() @@ -368,20 +295,43 @@ function(php_bison name input output) set(quiet "QUIET") endif() - if(NOT TARGET Bison::Bison) - find_package(BISON ${PHP_BISON_VERSION} GLOBAL ${quiet}) + _php_bison_config() + + # Skip consecutive calls if downloading or outer find_package() was called. + if(NOT TARGET Bison::Bison AND NOT DEFINED BISON_FOUND) + find_package(BISON ${PHP_BISON_VERSION} ${quiet}) endif() if( NOT BISON_FOUND - AND PHP_BISON_DOWNLOAD_VERSION + AND PHP_BISON_VERSION_DOWNLOAD AND packageType STREQUAL "REQUIRED" AND NOT CMAKE_SCRIPT_MODE_FILE + # TODO: Support for other platforms. + AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" ) _php_bison_download() endif() - _php_bison_process_working_directory() + # Set working directory. + if(NOT parsed_WORKING_DIRECTORY) + if(PHP_BISON_WORKING_DIRECTORY) + set(parsed_WORKING_DIRECTORY ${PHP_BISON_WORKING_DIRECTORY}) + elseif(PHP_HOMEPAGE_URL AND PHP_SOURCE_DIR) + # Building php-src. + set(parsed_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) + else() + # Otherwise set working directory to the directory of the output file. + cmake_path(GET output PARENT_PATH parsed_WORKING_DIRECTORY) + endif() + endif() + cmake_path( + ABSOLUTE_PATH + parsed_WORKING_DIRECTORY + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + _php_bison_process_options() _php_bison_process_header_option() _php_bison_process_verbose_option() @@ -402,9 +352,9 @@ function(php_bison name input output) RELATIVE_PATH output BASE_DIRECTORY ${CMAKE_BINARY_DIR} - OUTPUT_VARIABLE outputRelative + OUTPUT_VARIABLE relativePath ) - set(message "[bison] Generating ${outputRelative} with Bison ${BISON_VERSION}") + set(message "[bison] Generating ${relativePath} with Bison ${BISON_VERSION}") if(CMAKE_SCRIPT_MODE_FILE) message(STATUS "${message}") @@ -440,42 +390,13 @@ function(php_bison name input output) ) endfunction() -# Process working directory. -function(_php_bison_process_working_directory) - if(NOT parsed_WORKING_DIRECTORY) - if(PHP_BISON_WORKING_DIRECTORY) - set(parsed_WORKING_DIRECTORY ${PHP_BISON_WORKING_DIRECTORY}) - else() - set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - endif() - else() - set(parsed_WORKING_DIRECTORY ${parsed_WORKING_DIRECTORY}) - endif() - - if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") - cmake_path( - ABSOLUTE_PATH - parsed_WORKING_DIRECTORY - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - else() - cmake_path( - SET - parsed_WORKING_DIRECTORY - NORMALIZE - "${parsed_WORKING_DIRECTORY}" - ) - endif() - - return(PROPAGATE parsed_WORKING_DIRECTORY) -endfunction() - # Process options. function(_php_bison_process_options) + _php_bison_config_options() + set(options ${parsed_OPTIONS}) - if(PHP_BISON_OPTIONS AND parsed_APPEND) + if(PHP_BISON_OPTIONS AND parsed_ADD_DEFAULT_OPTIONS) list(PREPEND options ${PHP_BISON_OPTIONS}) endif() @@ -495,16 +416,12 @@ function(_php_bison_process_header_file) if(parsed_HEADER_FILE) set(header ${parsed_HEADER_FILE}) - if(NOT IS_ABSOLUTE "${header}") - cmake_path( - ABSOLUTE_PATH - header - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - else() - cmake_path(SET header NORMALIZE "${header}") - endif() + cmake_path( + ABSOLUTE_PATH + header + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) else() # Produce default header path generated by bison (see option --header). cmake_path(GET output EXTENSION LAST_ONLY extension) @@ -593,16 +510,12 @@ function(_php_bison_process_verbose_option) set(reportFile ${parsed_REPORT_FILE}) endif() - if(NOT IS_ABSOLUTE "${reportFile}") - cmake_path( - ABSOLUTE_PATH - reportFile - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - else() - cmake_path(SET reportFile NORMALIZE "${reportFile}") - endif() + cmake_path( + ABSOLUTE_PATH + reportFile + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) list(APPEND extraOutputs "${reportFile}") list(APPEND options --report-file=${reportFile}) @@ -695,7 +608,7 @@ endfunction() # Download and build Bison if not found. function(_php_bison_download) - set(BISON_VERSION ${PHP_BISON_DOWNLOAD_VERSION}) + set(BISON_VERSION ${PHP_BISON_VERSION_DOWNLOAD}) set(BISON_FOUND TRUE) if(TARGET Bison::Bison) @@ -712,10 +625,10 @@ function(_php_bison_download) DOWNLOAD_EXTRACT_TIMESTAMP TRUE CONFIGURE_COMMAND /configure - --prefix= - --enable-silent-rules - --disable-yacc --disable-dependency-tracking + --disable-yacc + --enable-silent-rules + --prefix= LOG_INSTALL TRUE ) diff --git a/cmake/cmake/modules/PHP/Re2c.cmake b/cmake/cmake/modules/PHP/Re2c.cmake index 439b1a9a..9eae9b71 100644 --- a/cmake/cmake/modules/PHP/Re2c.cmake +++ b/cmake/cmake/modules/PHP/Re2c.cmake @@ -1,41 +1,13 @@ #[=============================================================================[ # PHP/Re2c -Generate lexer-related files with re2c. This module includes common `re2c` -configuration with minimum required version and common settings across the -PHP build. +Generate lexer files with re2c. -## Configuration variables - -These variables can be set before including this module -`include(PHP/Re2c)`: - -* `PHP_RE2C_VERSION` - The re2c version constraint, when looking for RE2C - package with `find_package(RE2C ...)`. - -* `PHP_RE2C_DOWNLOAD_VERSION` - When re2c cannot be found on the system or the - found version is not suitable, this module can also download and build it from - its release archive sources as part of the project build. Set which re2c - version should be downloaded. - -* `PHP_RE2C_COMPUTED_GOTOS` - Add the `COMPUTED_GOTOS TRUE` option to all - `php_re2c()` invocations in the scope of current directory. - -* `PHP_RE2C_OPTIONS` - A semicolon-separated list of default re2c options. - This module sets some sensible defaults. When `php_re2c(APPEND)` is used, the - options specified in the `php_re2c(OPTIONS ...)` are appended to - these default global options. - -* `PHP_RE2C_WORKING_DIRECTORY` - Set the default global working directory - (`WORKING_DIRECTORY ` option) for all `php_re2c()` invocations in the - scope of the current directory. - -## Functions provided by this module +## Functions ### `php_re2c()` -Generate lexer file from the given template file using the `re2c` lexer -generator. +Generate lexer file from the given template file using the re2c generator. ```cmake php_re2c( @@ -43,7 +15,7 @@ php_re2c( [HEADER
] - [APPEND] + [ADD_DEFAULT_OPTIONS] [OPTIONS ...] [DEPENDS ...] [COMPUTED_GOTOS ] @@ -53,96 +25,101 @@ php_re2c( ) ``` -This creates a custom CMake target `` and adds a custom command that -generates lexer file `` from the given `` template file using the -`re2c` lexer generator. Relative source file path `` is interpreted as -being relative to the current source directory. Relative `` file path is -interpreted as being relative to the current binary directory. If generated -files are already available (for example, shipped with the released archive), -and re2c is not found, it will create a custom target but skip the `re2c` -command-line execution. +This creates a CMake target `` and adds a command that generates lexer +file `` from the given `` template file using the `re2c` lexer +generator. Relative source file path `` is interpreted as being relative +to the current source directory. Relative `` file path is interpreted as +being relative to the current binary directory. If generated files are already +available (for example, shipped with the released archive), and re2c is not +found, it will create a custom target but skip the `re2c` command-line +execution. When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it -generates the lexer without creating a target, to make it easier to use in -various scenarios. +generates the lexer right away without creating a target. #### Options * `HEADER
` - Generate a given `
` file. Relative header file path is interpreted as being relative to the current binary directory. -* `APPEND` - If specified, the `PHP_RE2C_OPTIONS` are prepended to - `OPTIONS ` for the current `re2c` invocation. +* `ADD_DEFAULT_OPTIONS` - When specified, the options from the + `PHP_RE2C_OPTIONS` configuration variable are prepended to the current + `re2c` command-line invocation. This module provides some sensible defaults. + +* `OPTIONS ...` - List of additional options to pass to the `re2c` + command-line tool. Supports generator expressions. In script mode + (`CMAKE_SCRIPT_MODE_FILE`) generator expressions are stripped as they can't be + determined. * `DEPENDS ...` - Optional list of dependent files to regenerate the output file. -* `COMPUTED_GOTOS ` - Set to `TRUE` to add the re2c - `--computed-gotos` (`-g`) command-line option if the non-standard C computed - goto extension is supported by the C compiler. When calling `re2c()` in the - command-line script mode (`CMAKE_SCRIPT_MODE`), option is not checked, whether - the compiler supports it and is added to `re2c` command-line options - unconditionally. +* `COMPUTED_GOTOS ` - Set to `TRUE` to add the `--computed-gotos` + (`-g`) command-line option if the non-standard C computed goto extension is + supported by the C compiler. When calling `re2c()` in the command-line script + mode (`CMAKE_SCRIPT_MODE`), option is not checked, whether the compiler + supports it and is added unconditionally. -* `CODEGEN` - Adds the `CODEGEN` option to the re2c's `add_custom_command()` - call. Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which - provides a global CMake `codegen` target for convenience to call only the - code-generation-related targets and skips the majority of the build: +* `CODEGEN` - This adds the `CODEGEN` option to the `add_custom_command()` call. + Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which provides a + global CMake `codegen` target for convenience to call only the + code-generation-related targets and skip the majority of the build: ```sh cmake --build --target codegen ``` -* `WORKING_DIRECTORY ` - The path where the `re2c` command is +* `WORKING_DIRECTORY ` - The path where the `re2c` is executed. Relative `` path is interpreted as being relative to the current binary directory. If not set, `re2c` is by default executed in - the current binary directory (`CMAKE_CURRENT_BINARY_DIR`). If variable + the `PHP_SOURCE_DIR` when building the php-src repository. Otherwise it is + executed in the directory of the `` file. If variable `PHP_RE2C_WORKING_DIRECTORY` is set before calling the `php_re2c()` without - this option, it will set the default working directory to that. + this option, it will set the default working directory to that instead. * `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `re2c` - command-line invocations. By default all file paths are added to `re2c` - command-line relative to the working directory. Using relative paths is - convenient when line directives (`#line ...`) are generated in the output - lexer files to not show the full path on the disk, when file is committed to - Git repository, where multiple people develop. + command-line invocations. By default all file paths are added to `re2c` as + relative to the working directory. Using relative paths is convenient when + line directives (`#line ...`) are generated in the output files to not show + the full path on the disk, if file is committed to Git repository. When this option is enabled: ```c - #line 108 "/home/user/projects/php-src/ext/phar/phar_path_check.c" + #line 108 "/home/user/php-src/ext/phar/phar_path_check.c" ``` - Without this option, relative paths will be generated: + Without this option relative paths are generated: ```c #line 108 "ext/phar/phar_path_check.c" ``` -## Examples - -### Basic usage +## Configuration variables -```cmake -# CMakeLists.txt +These variables can be set before using this module to configure behavior: -include(PHP/Re2c) +* `PHP_RE2C_COMPUTED_GOTOS` - Add the `COMPUTED_GOTOS TRUE` option to all + `php_re2c()` invocations in the directory scope. -php_re2c(...) -``` +* `PHP_RE2C_OPTIONS` - A semicolon-separated list of default re2c command-line + options when `php_re2c(ADD_DEFAULT_OPTIONS)` is used. -### Minimum re2c version +* `PHP_RE2C_VERSION` - The version constraint, when looking for RE2C package + with `find_package(RE2C ...)` in this module. -To override the module default minimum required `re2c` version: +* `PHP_RE2C_VERSION_DOWNLOAD` - When re2c cannot be found on the system or the + found version is not suitable, this module can also download and build it from + its release archive sources as part of the project build. Set which version + should be downloaded. -```cmake -# CMakeLists.txt +* `PHP_RE2C_WORKING_DIRECTORY` - Set the default global working directory + for all `php_re2c()` invocations in the directory scope where the + `WORKING_DIRECTORY ` option is not set. -set(PHP_RE2C_VERSION 3.8.0) -include(PHP/Re2c) -``` +## Examples -### Specifying options +### Basic usage ```cmake # CMakeLists.txt @@ -154,52 +131,33 @@ php_re2c(foo foo.re foo.c OPTIONS --bit-vectors --conditions) # re2c --bit-vectors --conditions --output foo.c foo.re ``` -This module also provides some sensible default options, which can be prepended -to current specified options using the `APPEND` keyword. +### Specifying options -```cmake -# CMakeLists.txt +This module provides some default options when using the `ADD_DEFAULT_OPTIONS`: +```cmake include(PHP/Re2c) -php_re2c(foo foo.re foo.c APPEND OPTIONS --conditions) +php_re2c(foo foo.re foo.c ADD_DEFAULT_OPTIONS OPTIONS --conditions) # This will run: # re2c --no-debug-info --no-generation-date --conditions --output foo.c foo.re ``` -Generator expressions are supported in `php_re2c(OPTIONS)` when running in -normal CMake `project()` mode: +### Generator expressions ```cmake -# CMakeLists.txt - include(PHP/Re2c) -php_re2c(foo foo.re foo.c OPTIONS $<$:--debug-output> --conditions) +php_re2c(foo foo.re foo.c OPTIONS $<$:--debug-output> -F) # When build type is Debug, this will run: -# re2c --debug-output -conditions --output foo.c foo.re -# For other build types: -# re2c --conditions --output foo.c foo.re -``` - -Setting default options for all `php_re2c()` calls in the current directory -scope: - -```cmake -# CMakeLists.txt - -set(PHP_RE2C_OPTIONS --no-generation-date) - -include(PHP/Re2c) - -php_re2c(foo foo.re foo.c APPEND OPTIONS --conditions) -# This will run: -# re2c --no-generation-date --conditions --output foo.c foo.re +# re2c --debug-output -F --output foo.c foo.re +# For other build types (including the script mode - CMAKE_SCRIPT_MODE_FILE): +# re2c -F --output foo.c foo.re ``` ### Custom target usage -To specify dependencies with the custom target created by `re2c()`: +To specify dependencies with the custom target created by `php_re2c()`: ```cmake # CMakeLists.txt @@ -211,68 +169,61 @@ add_dependencies(some_target foo_lexer) ``` Or to run only the specific `foo_lexer` target, which generates the -lexer-related files. +lexer-related files: ```sh cmake --build --target foo_lexer ``` -### Script mode - -When running `php_re2c()` in script mode (`CMAKE_SCRIPT_MODE_FILE`): - -```sh -cmake -P script.cmake -``` +### Module configuration -the generated file is created right away, without creating target: +To specify minimum required re2c version other than the module's default, +`find_package(RE2C)` can be called before the `php_re2c()`: ```cmake -# script.cmake - +find_package(RE2C 3.1) include(PHP/Re2c) - -php_re2c(foo_lexer lexer.re lexer.c) +php_re2c(...) ``` -In script mode also all options with generator expressions are removed from the -invocation as they can't be parsed and determined in such mode. +Set `PHP_RE2C_*` variables to override module default configuration: ```cmake -# script.cmake - +set(PHP_RE2C_VERSION_DOWNLOAD 3.1) include(PHP/Re2c) - -php_re2c(foo lexer.y lexer.c OPTIONS $<$:--debug-output> -F) -# This will run: -# re2c -F --output lexer.c lexer.re +php_re2c(...) ``` #]=============================================================================] -include_guard(GLOBAL) - -include(FeatureSummary) - ################################################################################ # Configuration. ################################################################################ -option(PHP_RE2C_COMPUTED_GOTOS "Enable computed goto GCC extension with re2c") -mark_as_advanced(PHP_RE2C_COMPUTED_GOTOS) - -macro(php_re2c_config) +macro(_php_re2c_config) # Minimum required re2c version. if(NOT PHP_RE2C_VERSION) set(PHP_RE2C_VERSION 1.0.3) endif() # If re2c is not found on the system, set which version to download. - if(NOT PHP_RE2C_DOWNLOAD_VERSION) - set(PHP_RE2C_DOWNLOAD_VERSION 4.0.2) + if(NOT PHP_RE2C_VERSION_DOWNLOAD) + set(PHP_RE2C_VERSION_DOWNLOAD 4.0.2) endif() +endmacro() + +_php_re2c_config() + +include_guard(GLOBAL) +include(FeatureSummary) + +option(PHP_RE2C_COMPUTED_GOTOS "Enable computed goto GCC extension with re2c") +mark_as_advanced(PHP_RE2C_COMPUTED_GOTOS) + +# Configuration after find_package() in this module. +macro(_php_re2c_config_options) if(NOT PHP_RE2C_OPTIONS) - # Add --no-debug-info (-i) option to not output line directives. + # Add --no-debug-info (-i) option to not output '#line' directives. if(CMAKE_SCRIPT_MODE_FILE) set(PHP_RE2C_OPTIONS --no-debug-info) else() @@ -281,29 +232,18 @@ macro(php_re2c_config) # Suppress date output in the generated file. list(APPEND PHP_RE2C_OPTIONS --no-generation-date) - endif() - # Set working directory for all re2c invocations. - if(NOT PHP_RE2C_WORKING_DIRECTORY) - if(PHP_SOURCE_DIR) - set(PHP_RE2C_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) - else() - set(PHP_RE2C_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + # TODO: https://github.com/php/php-src/issues/17204 + if(RE2C_VERSION VERSION_GREATER_EQUAL 4) + list( + APPEND + PHP_RE2C_OPTIONS + -Wno-unreachable-rules + -Wno-condition-order + -Wno-undefined-control-flow + ) endif() endif() - - # See: https://github.com/php/php-src/issues/17204 - # TODO: Remove this once fixed upstream. - # TODO: Refactor this because the found re2c version is here not known yet. - if(RE2C_VERSION VERSION_GREATER_EQUAL 4) - list( - APPEND - PHP_RE2C_OPTIONS - -Wno-unreachable-rules - -Wno-condition-order - -Wno-undefined-control-flow - ) - endif() endmacro() ################################################################################ @@ -315,7 +255,7 @@ function(php_re2c name input output) PARSE_ARGV 3 parsed # prefix - "APPEND;CODEGEN;ABSOLUTE_PATHS" # options + "ADD_DEFAULT_OPTIONS;CODEGEN;ABSOLUTE_PATHS" # options "HEADER;WORKING_DIRECTORY;COMPUTED_GOTOS" # one-value keywords "OPTIONS;DEPENDS" # multi-value keywords ) @@ -328,32 +268,32 @@ function(php_re2c name input output) message(FATAL_ERROR "Missing values for: ${parsed_KEYWORDS_MISSING_VALUES}") endif() - if(NOT IS_ABSOLUTE "${input}") - cmake_path( - ABSOLUTE_PATH - input - BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - NORMALIZE - ) - else() - cmake_path(SET input NORMALIZE "${input}") - endif() + cmake_path( + ABSOLUTE_PATH + input + BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + NORMALIZE + ) + + cmake_path( + ABSOLUTE_PATH + output + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) - if(NOT IS_ABSOLUTE "${output}") + set(outputs ${output}) + + if(parsed_HEADER) cmake_path( ABSOLUTE_PATH - output + parsed_HEADER BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} NORMALIZE ) - else() - cmake_path(SET output NORMALIZE "${output}") + list(APPEND outputs ${parsed_HEADER}) endif() - set(outputs ${output}) - - php_re2c_config() - _php_re2c_process_header_file() _php_re2c_set_package_properties() get_property(packageType GLOBAL PROPERTY _CMAKE_RE2C_TYPE) @@ -362,20 +302,41 @@ function(php_re2c name input output) set(quiet "QUIET") endif() - if(NOT TARGET RE2C::RE2C) - find_package(RE2C ${PHP_RE2C_VERSION} GLOBAL ${quiet}) + _php_re2c_config() + + # Skip consecutive calls if downloading or outer find_package() was called. + if(NOT TARGET RE2C::RE2C AND NOT DEFINED RE2C_FOUND) + find_package(RE2C ${PHP_RE2C_VERSION} ${quiet}) endif() if( NOT RE2C_FOUND - AND PHP_RE2C_DOWNLOAD_VERSION + AND PHP_RE2C_VERSION_DOWNLOAD AND packageType STREQUAL "REQUIRED" AND NOT CMAKE_SCRIPT_MODE_FILE ) _php_re2c_download() endif() - _php_re2c_process_working_directory() + # Set working directory. + if(NOT parsed_WORKING_DIRECTORY) + if(PHP_RE2C_WORKING_DIRECTORY) + set(parsed_WORKING_DIRECTORY ${PHP_RE2C_WORKING_DIRECTORY}) + elseif(PHP_HOMEPAGE_URL AND PHP_SOURCE_DIR) + # Building php-src. + set(parsed_WORKING_DIRECTORY ${PHP_SOURCE_DIR}) + else() + # Otherwise set working directory to the directory of the output file. + cmake_path(GET output PARENT_PATH parsed_WORKING_DIRECTORY) + endif() + endif() + cmake_path( + ABSOLUTE_PATH + parsed_WORKING_DIRECTORY + BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + NORMALIZE + ) + _php_re2c_process_options() _php_re2c_process_header_option() @@ -396,9 +357,9 @@ function(php_re2c name input output) RELATIVE_PATH output BASE_DIRECTORY ${CMAKE_BINARY_DIR} - OUTPUT_VARIABLE outputRelative + OUTPUT_VARIABLE relativePath ) - set(message "[re2c] Generating ${outputRelative} with re2c ${RE2C_VERSION}") + set(message "[re2c] Generating ${relativePath} with re2c ${RE2C_VERSION}") if(CMAKE_SCRIPT_MODE_FILE) message(STATUS "${message}") @@ -434,29 +395,6 @@ function(php_re2c name input output) ) endfunction() -# Process header file. -function(_php_re2c_process_header_file) - if(NOT parsed_HEADER) - return() - endif() - - set(header ${parsed_HEADER}) - if(NOT IS_ABSOLUTE "${header}") - cmake_path( - ABSOLUTE_PATH - header - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - else() - cmake_path(SET header NORMALIZE "${header}") - endif() - - list(APPEND outputs ${header}) - - return(PROPAGATE header outputs) -endfunction() - # Set RE2C package properties TYPE and PURPOSE. If lexer-related output files # are already generated, for example, shipped with the released archive, then # RE2C package type is set to RECOMMENDED. If generated files are not @@ -486,37 +424,10 @@ function(_php_re2c_set_package_properties) set_package_properties(RE2C PROPERTIES PURPOSE "${purpose}") endfunction() -# Process working directory. -function(_php_re2c_process_working_directory) - if(NOT parsed_WORKING_DIRECTORY) - if(PHP_RE2C_WORKING_DIRECTORY) - set(parsed_WORKING_DIRECTORY ${PHP_RE2C_WORKING_DIRECTORY}) - else() - set(parsed_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - endif() - endif() - - if(NOT IS_ABSOLUTE "${parsed_WORKING_DIRECTORY}") - cmake_path( - ABSOLUTE_PATH - parsed_WORKING_DIRECTORY - BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - NORMALIZE - ) - else() - cmake_path( - SET - parsed_WORKING_DIRECTORY - NORMALIZE - "${parsed_WORKING_DIRECTORY}" - ) - endif() - - return(PROPAGATE parsed_WORKING_DIRECTORY) -endfunction() - # Process options. function(_php_re2c_process_options) + _php_re2c_config_options() + set(options ${parsed_OPTIONS}) if(PHP_RE2C_COMPUTED_GOTOS OR parsed_COMPUTED_GOTOS) @@ -526,7 +437,7 @@ function(_php_re2c_process_options) endif() endif() - if(PHP_RE2C_OPTIONS AND parsed_APPEND) + if(PHP_RE2C_OPTIONS AND parsed_ADD_DEFAULT_OPTIONS) list(PREPEND options ${PHP_RE2C_OPTIONS}) endif() @@ -552,6 +463,17 @@ function(_php_re2c_process_header_option) return() endif() + if(parsed_ABSOLUTE_PATHS) + set(headerArgument "${parsed_HEADER}") + else() + cmake_path( + RELATIVE_PATH + parsed_HEADER + BASE_DIRECTORY ${parsed_WORKING_DIRECTORY} + OUTPUT_VARIABLE headerArgument + ) + endif() + # When header option is used before re2c version 1.2, also the '-c' option # is required. Before 1.1 '-c' long variant is '--start-conditions' and # after 1.1 '--conditions'. @@ -562,9 +484,9 @@ function(_php_re2c_process_header_option) # Since re2c version 3.0, '--header' is the new alias option for the # '--type-header' option. if(RE2C_VERSION VERSION_GREATER_EQUAL 3.0) - list(APPEND options --header ${header}) + list(APPEND options --header ${headerArgument}) else() - list(APPEND options --type-header ${header}) + list(APPEND options --type-header ${headerArgument}) endif() return(PROPAGATE options) @@ -667,7 +589,7 @@ endfunction() # Download and build re2c if not found. function(_php_re2c_download) - set(RE2C_VERSION ${PHP_RE2C_DOWNLOAD_VERSION}) + set(RE2C_VERSION ${PHP_RE2C_VERSION_DOWNLOAD}) set(RE2C_FOUND TRUE) if(TARGET RE2C::RE2C) diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake index 384c5167..f826aec6 100755 --- a/cmake/cmake/scripts/GenerateGrammar.cmake +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -20,7 +20,8 @@ if(NOT CMAKE_SCRIPT_MODE_FILE) message(FATAL_ERROR "This is a command-line script.") endif() -set(PHP_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +cmake_path(SET PHP_SOURCE_DIR NORMALIZE ${CMAKE_CURRENT_LIST_DIR}/../..) + set(CMAKE_SOURCE_DIR ${PHP_SOURCE_DIR}) set(CMAKE_BINARY_DIR ${PHP_SOURCE_DIR}) @@ -33,12 +34,10 @@ list(APPEND CMAKE_MODULE_PATH ${PHP_SOURCE_DIR}/cmake/modules) include(FeatureSummary) include(PHP/Bison) -php_bison_config() find_package(BISON ${PHP_BISON_VERSION}) set_package_properties(BISON PROPERTIES TYPE REQUIRED) include(PHP/Re2c) -php_re2c_config() find_package(RE2C ${PHP_RE2C_VERSION}) set_package_properties(RE2C PROPERTIES TYPE REQUIRED) @@ -60,13 +59,8 @@ foreach(script IN LISTS scripts) set(CMAKE_CURRENT_SOURCE_DIR ${path}) set(CMAKE_CURRENT_BINARY_DIR ${path}) - cmake_path( - RELATIVE_PATH - path - BASE_DIRECTORY ${PHP_SOURCE_DIR} - OUTPUT_VARIABLE relativeDir - ) - message(STATUS "Processing ${relativeDir} directory") + cmake_path(RELATIVE_PATH path BASE_DIRECTORY ${PHP_SOURCE_DIR}) + message(STATUS "Processing ${path} directory") include(${script}) endforeach() diff --git a/cmake/ext/json/cmake/GenerateGrammar.cmake b/cmake/ext/json/cmake/GenerateGrammar.cmake index 019a3d98..c1f26836 100644 --- a/cmake/ext/json/cmake/GenerateGrammar.cmake +++ b/cmake/ext/json/cmake/GenerateGrammar.cmake @@ -17,6 +17,7 @@ php_bison( json_parser.y ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.tab.c HEADER + ADD_DEFAULT_OPTIONS ${verbose} CODEGEN ) @@ -28,6 +29,7 @@ php_re2c( json_scanner.re ${CMAKE_CURRENT_SOURCE_DIR}/json_scanner.c HEADER ${CMAKE_CURRENT_SOURCE_DIR}/php_json_scanner_defs.h - APPEND OPTIONS --bit-vectors --conditions + ADD_DEFAULT_OPTIONS + OPTIONS --bit-vectors --conditions CODEGEN ) diff --git a/cmake/ext/pdo/cmake/GenerateGrammar.cmake b/cmake/ext/pdo/cmake/GenerateGrammar.cmake index 91c8c6f4..427b0eb7 100644 --- a/cmake/ext/pdo/cmake/GenerateGrammar.cmake +++ b/cmake/ext/pdo/cmake/GenerateGrammar.cmake @@ -10,5 +10,6 @@ php_re2c( php_ext_pdo_sql_parser pdo_sql_parser.re ${CMAKE_CURRENT_SOURCE_DIR}/pdo_sql_parser.c + ADD_DEFAULT_OPTIONS CODEGEN ) diff --git a/cmake/ext/phar/cmake/GenerateGrammar.cmake b/cmake/ext/phar/cmake/GenerateGrammar.cmake index 59a9202b..7f594825 100644 --- a/cmake/ext/phar/cmake/GenerateGrammar.cmake +++ b/cmake/ext/phar/cmake/GenerateGrammar.cmake @@ -10,6 +10,7 @@ php_re2c( php_ext_phar_path_check phar_path_check.re ${CMAKE_CURRENT_SOURCE_DIR}/phar_path_check.c - APPEND OPTIONS --bit-vectors + ADD_DEFAULT_OPTIONS + OPTIONS --bit-vectors CODEGEN ) diff --git a/cmake/ext/standard/cmake/GenerateGrammar.cmake b/cmake/ext/standard/cmake/GenerateGrammar.cmake index 8d49f686..a1ed1f4a 100644 --- a/cmake/ext/standard/cmake/GenerateGrammar.cmake +++ b/cmake/ext/standard/cmake/GenerateGrammar.cmake @@ -10,7 +10,8 @@ php_re2c( php_ext_standard_url_scanner_ex url_scanner_ex.re ${CMAKE_CURRENT_SOURCE_DIR}/url_scanner_ex.c - APPEND OPTIONS --bit-vectors + ADD_DEFAULT_OPTIONS + OPTIONS --bit-vectors CODEGEN ) @@ -18,6 +19,7 @@ php_re2c( php_ext_standard_var_unserializer var_unserializer.re ${CMAKE_CURRENT_SOURCE_DIR}/var_unserializer.c - APPEND OPTIONS --bit-vectors + ADD_DEFAULT_OPTIONS + OPTIONS --bit-vectors CODEGEN ) diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake index c0031598..dc9e54af 100644 --- a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -17,6 +17,7 @@ php_bison( phpdbg_parser.y ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_parser.c HEADER + ADD_DEFAULT_OPTIONS ${verbose} CODEGEN ) @@ -27,7 +28,7 @@ php_re2c( php_sapi_phpdbg_lexer phpdbg_lexer.l ${CMAKE_CURRENT_SOURCE_DIR}/phpdbg_lexer.c - APPEND + ADD_DEFAULT_OPTIONS OPTIONS --bit-vectors --conditions From 0532a991adfec18d686b6df13f690a09e29e60f7 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Wed, 8 Jan 2025 23:38:00 +0100 Subject: [PATCH 15/15] Fix nits --- bin/check-cmake.php | 39 +++++++--- cmake/Zend/CMakeLists.txt | 2 +- cmake/Zend/cmake/GenerateGrammar.cmake | 10 +-- cmake/cmake/Configuration.cmake | 6 +- cmake/cmake/modules/FindBISON.cmake | 4 +- cmake/cmake/modules/FindRE2C.cmake | 14 ++-- cmake/cmake/modules/PHP/Bison.cmake | 77 ++++++++----------- cmake/cmake/modules/PHP/Re2c.cmake | 58 ++++++-------- cmake/cmake/scripts/GenerateGrammar.cmake | 6 +- cmake/ext/json/CMakeLists.txt | 2 +- cmake/ext/json/cmake/GenerateGrammar.cmake | 2 +- cmake/sapi/phpdbg/CMakeLists.txt | 2 +- cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake | 2 +- 13 files changed, 108 insertions(+), 116 deletions(-) diff --git a/bin/check-cmake.php b/bin/check-cmake.php index ee17c219..267401c3 100755 --- a/bin/check-cmake.php +++ b/bin/check-cmake.php @@ -191,6 +191,7 @@ function getProjectModules(): array 'FindPackageMessage' => ['find_package_message'], 'ProcessorCount' => ['processorcount'], 'PHP/AddCustomCommand' => ['php_add_custom_command'], + 'PHP/Bison' => ['php_bison', '/find_package\([\n ]*BISON/'], 'PHP/CheckAttribute' => [ 'php_check_function_attribute', 'php_check_variable_attribute', @@ -199,6 +200,7 @@ function getProjectModules(): array 'PHP/ConfigureFile' => ['php_configure_file'], 'PHP/Install' => ['php_install'], 'PHP/PkgConfigGenerator' => ['pkgconfig_generate_pc'], + 'PHP/Re2c' => ['php_re2c', '/find_package\([\n ]*RE2C/'], 'PHP/SearchLibraries' => ['php_search_libraries'], 'PHP/Set' => ['php_set'], 'PHP/SystemExtensions' => ['PHP::SystemExtensions'], @@ -273,7 +275,7 @@ function checkCMakeInclude(Iterator $files, array $modules): int $content = getCMakeCode($file); // Check for redundant includes. - foreach ($modules as $module => $commands) { + foreach ($modules as $module => $patterns) { $hasModule = false; $moduleEscaped = str_replace('/', '\/', $module); @@ -281,16 +283,21 @@ function checkCMakeInclude(Iterator $files, array $modules): int $hasModule = true; } - $hasCommand = false; - foreach ($commands as $command) { - if ( + $hasPattern = false; + foreach ($patterns as $pattern) { + if (isRegularExpression($pattern)) { + if (1 === preg_match($pattern, $content)) { + $hasPattern = true; + break; + } + } elseif ( ( - 1 === preg_match('/::/', $command) - && 1 === preg_match('/[^A-Za-z0-9_]' . $command . '[^A-Za-z0-9_]/m', $content) + 1 === preg_match('/::/', $pattern) + && 1 === preg_match('/[^A-Za-z0-9_]' . $pattern . '[^A-Za-z0-9_]/m', $content) ) - || 1 === preg_match('/^[ \t]*' . $command . '[ \t]*\(/m', $content) + || 1 === preg_match('/^[ \t]*' . $pattern . '[ \t]*\(/m', $content) ) { - $hasCommand = true; + $hasPattern = true; break; } } @@ -304,12 +311,12 @@ function checkCMakeInclude(Iterator $files, array $modules): int continue; } - if ($hasModule && !$hasCommand) { + if ($hasModule && !$hasPattern) { $status = 1; output("E: redundant include($module) in $file"); } - if (!$hasModule && $hasCommand) { + if (!$hasModule && $hasPattern) { $status = 1; output("E: missing include($module) in $file"); } @@ -319,6 +326,18 @@ function checkCMakeInclude(Iterator $files, array $modules): int return $status; }; +/** + * Check if given string is regular expression. + */ +function isRegularExpression(string $string): bool +{ + set_error_handler(static function () {}, E_WARNING); + $isRegularExpression = false !== preg_match($string, ''); + restore_error_handler(); + + return $isRegularExpression; +} + /** * Check for set() usages with only one argument. These should be * replaced with set( ""). diff --git a/cmake/Zend/CMakeLists.txt b/cmake/Zend/CMakeLists.txt index c4b18ce7..626cd4ed 100644 --- a/cmake/Zend/CMakeLists.txt +++ b/cmake/Zend/CMakeLists.txt @@ -523,7 +523,7 @@ if(TARGET Zend::MaxExecutionTimers) endif() ################################################################################ -# Generate lexer and parser files. +# Generate parser and lexer files. ################################################################################ include(cmake/GenerateGrammar.cmake) diff --git a/cmake/Zend/cmake/GenerateGrammar.cmake b/cmake/Zend/cmake/GenerateGrammar.cmake index 9f1b1b3f..3afe20cc 100644 --- a/cmake/Zend/cmake/GenerateGrammar.cmake +++ b/cmake/Zend/cmake/GenerateGrammar.cmake @@ -1,4 +1,4 @@ -# Generate lexer and parser files. +# Generate parser and lexer files. if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) message(FATAL_ERROR "This file should be used with include().") @@ -32,9 +32,9 @@ php_bison( CODEGEN ) -# Tweak zendparse to be exported through ZEND_API. This has to be revisited -# once bison supports foreign skeletons and that bison version is used. Read -# https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more. +# Tweak zendparse to be exported through ZEND_API. This has to be revisited if +# Bison will support foreign skeletons. +# See: https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md block() string( CONCAT patch @@ -79,7 +79,7 @@ block() endif() ]]) - # Run patch based on whether building or running inside a CMake script. + # Run patch based on whether building or running inside a script. if(CMAKE_SCRIPT_MODE_FILE) cmake_language(EVAL CODE "${patch}") else() diff --git a/cmake/cmake/Configuration.cmake b/cmake/cmake/Configuration.cmake index 994beb14..184a99da 100644 --- a/cmake/cmake/Configuration.cmake +++ b/cmake/cmake/Configuration.cmake @@ -259,5 +259,7 @@ set_package_properties( DESCRIPTION "Compression library" ) -# Set base directory for the ExternalProject CMake module across the PHP. -set_directory_properties(PROPERTIES EP_BASE ${PHP_BINARY_DIR}/_deps/EP) +# Set base directory for ExternalProject CMake module. +set_directory_properties( + PROPERTIES EP_BASE ${PHP_BINARY_DIR}/CMakeFiles/PHP/ExternalProject +) diff --git a/cmake/cmake/modules/FindBISON.cmake b/cmake/cmake/modules/FindBISON.cmake index 39fea516..60d50d0e 100644 --- a/cmake/cmake/modules/FindBISON.cmake +++ b/cmake/cmake/modules/FindBISON.cmake @@ -16,6 +16,6 @@ set_package_properties( DESCRIPTION "General-purpose parser generator" ) -# Include CMake find module. Absolute path prevents the maximum -# nesting/recursion depth error on some systems, like macOS. +# Find package with upstream CMake find module. Absolute path prevents the +# maximum nesting/recursion depth error on some systems, like macOS. include(${CMAKE_ROOT}/Modules/FindBISON.cmake) diff --git a/cmake/cmake/modules/FindRE2C.cmake b/cmake/cmake/modules/FindRE2C.cmake index e8bce346..2cc31e50 100644 --- a/cmake/cmake/modules/FindRE2C.cmake +++ b/cmake/cmake/modules/FindRE2C.cmake @@ -31,6 +31,7 @@ set_package_properties( # Find the executable. ################################################################################ +set(_re2cRequiredVars RE2C_EXECUTABLE) set(_reason "") find_program( @@ -48,7 +49,7 @@ endif() # Check version. ################################################################################ -block(PROPAGATE RE2C_VERSION _reason) +block(PROPAGATE RE2C_VERSION _reason _re2cRequiredVars) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) set(test IS_EXECUTABLE) else() @@ -56,6 +57,7 @@ block(PROPAGATE RE2C_VERSION _reason) endif() if(${test} ${RE2C_EXECUTABLE}) + list(APPEND _re2cRequiredVars RE2C_VERSION) execute_process( COMMAND ${RE2C_EXECUTABLE} --version OUTPUT_VARIABLE version @@ -65,12 +67,9 @@ block(PROPAGATE RE2C_VERSION _reason) ) if(NOT result EQUAL 0) - string(APPEND _reason "Command \"${RE2C_EXECUTABLE} --version\" failed. ") + string(APPEND _reason "Command '${RE2C_EXECUTABLE} --version' failed. ") elseif(version MATCHES "^re2c ([0-9.]+[^\n]+)") - find_package_check_version("${CMAKE_MATCH_1}" valid) - if(valid) - set(RE2C_VERSION "${CMAKE_MATCH_1}") - endif() + set(RE2C_VERSION "${CMAKE_MATCH_1}") else() string(APPEND _reason "Invalid version format. ") endif() @@ -79,10 +78,11 @@ endblock() find_package_handle_standard_args( RE2C - REQUIRED_VARS RE2C_EXECUTABLE RE2C_VERSION + REQUIRED_VARS ${_re2cRequiredVars} VERSION_VAR RE2C_VERSION HANDLE_VERSION_RANGE REASON_FAILURE_MESSAGE "${_reason}" ) +unset(_re2cRequiredVars) unset(_reason) diff --git a/cmake/cmake/modules/PHP/Bison.cmake b/cmake/cmake/modules/PHP/Bison.cmake index 50c63719..bea33110 100644 --- a/cmake/cmake/modules/PHP/Bison.cmake +++ b/cmake/cmake/modules/PHP/Bison.cmake @@ -25,16 +25,15 @@ php_bison( ) ``` -This creates a CMake target `` and adds a command that generates parser -file `` from the given `` template file using the `bison` parser +This creates a target `` and adds a command that generates parser file +`` from the given `` template file using the Bison parser generator. Relative source file path `` is interpreted as being relative to the current source directory. Relative `` file path is interpreted as being relative to the current binary directory. If generated files are already available (for example, shipped with the released archive), and Bison is not -found, it will create a custom target but skip the `bison` command-line -execution. +found, it will create a target but skip the `bison` command-line execution. -When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it +When used in command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it generates the parser right away without creating a target. #### Options @@ -57,38 +56,36 @@ generates the parser right away without creating a target. * `DEPENDS ...` - Optional list of dependent files to regenerate the output file. -* `VERBOSE` - This adds the `--verbose` (`-v`) command-line option to and will - create extra output file `.output` containing verbose - descriptions of the grammar and parser. File will be by default created in the - current binary directory. +* `VERBOSE` - Adds the `--verbose` (`-v`) command-line option and creates extra + output file `.output` in the current binary directory. + Report contains verbose grammar and parser descriptions. -* `REPORT_FILE ` - This adds the `--report-file=` command-line - option and will create verbose information report in the specified ``. - This option must be used together with the `VERBOSE` option. Relative file - path is interpreted as being relative to the current binary directory. +* `REPORT_FILE ` - Adds the `--report-file=` command-line option and + creates verbose information report in the specified ``. This option must + be used with the `VERBOSE` option. Relative file path is interpreted as being + relative to the current binary directory. -* `CODEGEN` - This adds the `CODEGEN` option to the `add_custom_command()` call. - Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which provides a - global CMake `codegen` target for convenience to call only the - code-generation-related targets and skip the majority of the build: +* `CODEGEN` - Adds the `CODEGEN` option to the `add_custom_command()` call. This + option is available starting with CMake 3.31 when the policy `CMP0171` is set + to `NEW`. It provides a `codegen` target for convenience, allowing to run only + code-generation-related targets while skipping the majority of the build: ```sh cmake --build --target codegen ``` -* `WORKING_DIRECTORY ` - The path where the `bison` is - executed. Relative `` path is interpreted as being relative - to the current binary directory. If not set, `bison` is by default executed in - the `PHP_SOURCE_DIR` when building the php-src repository. Otherwise it is +* `WORKING_DIRECTORY ` - The path where the `re2c` is executed. + Relative `` path is interpreted as being relative to the current + binary directory. If not set, `bison` is by default executed in the + `PHP_SOURCE_DIR` when building the php-src repository. Otherwise it is executed in the directory of the `` file. If variable `PHP_BISON_WORKING_DIRECTORY` is set before calling the `php_bison()` without this option, it will set the default working directory to that instead. * `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `bison` - command-line invocations. By default all file paths are added to `bison` as - relative to the working directory. Using relative paths is convenient when - line directives (`#line ...`) are generated in the output files to not show - the full path on the disk, if file is committed to Git repository. + command-line invocations. By default all file paths are added as relative to + the working directory. Using relative paths is convenient when line directives + (`#line ...`) are generated in the output files committed to Git repository. When this option is enabled: @@ -119,7 +116,7 @@ These variables can be set before using this module to configure behavior: * `PHP_BISON_WORKING_DIRECTORY` - Set the default global working directory for all `php_bison()` invocations in the directory scope where the - `WORKING_DIRECTORY ` option is not set. + `WORKING_DIRECTORY ` option is not set. ## Examples @@ -159,9 +156,9 @@ php_bison(foo foo.y foo.c OPTIONS $<$:--debug> --yacc) # bison --yacc foo.y --output foo.c ``` -### Custom target usage +### Target usage -To specify dependencies with the custom target created by `php_bison()`: +Target created by `php_bison()` can be used to specify additional dependencies: ```cmake # CMakeLists.txt @@ -172,8 +169,7 @@ php_bison(foo_parser parser.y parser.c) add_dependencies(some_target foo_parser) ``` -Or to run only the specific `foo_parser` target, which generates the -parser-related files: +Running only the `foo_parser` target to generate the parser-related files: ```sh cmake --build --target foo_parser @@ -181,20 +177,12 @@ cmake --build --target foo_parser ### Module configuration -To specify minimum required Bison version other than the module's default, -`find_package(BISON)` can be called before the `php_bison()`: +To specify different minimum required Bison version than the module's default, +the `find_package(BISON)` can be called before `php_bison()`: ```cmake -find_package(BISON 3.7) -include(PHP/Bison) -php_bison(...) -``` - -Set `PHP_BISON_*` variables to override module default configuration: - -```cmake -set(PHP_BISON_VERSION_DOWNLOAD 3.7) include(PHP/Bison) +find_package(BISON 3.7) php_bison(...) ``` #]=============================================================================] @@ -204,12 +192,12 @@ php_bison(...) ################################################################################ macro(_php_bison_config) - # Minimum required bison version. + # Minimum required Bison version. if(NOT PHP_BISON_VERSION) set(PHP_BISON_VERSION 3.0.0) endif() - # If bison is not found on the system, set which version to download. + # If Bison is not found on the system, set which version to download. if(NOT PHP_BISON_VERSION_DOWNLOAD) set(PHP_BISON_VERSION_DOWNLOAD 3.8.2) endif() @@ -354,7 +342,7 @@ function(php_bison name input output) BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE relativePath ) - set(message "[bison] Generating ${relativePath} with Bison ${BISON_VERSION}") + set(message "[Bison] Generating ${relativePath} with Bison ${BISON_VERSION}") if(CMAKE_SCRIPT_MODE_FILE) message(STATUS "${message}") @@ -632,7 +620,6 @@ function(_php_bison_download) LOG_INSTALL TRUE ) - # Set bison executable. ExternalProject_Get_Property(bison INSTALL_DIR) set_property(CACHE BISON_EXECUTABLE PROPERTY VALUE ${INSTALL_DIR}/bin/bison) diff --git a/cmake/cmake/modules/PHP/Re2c.cmake b/cmake/cmake/modules/PHP/Re2c.cmake index 9eae9b71..94a24571 100644 --- a/cmake/cmake/modules/PHP/Re2c.cmake +++ b/cmake/cmake/modules/PHP/Re2c.cmake @@ -20,21 +20,20 @@ php_re2c( [DEPENDS ...] [COMPUTED_GOTOS ] [CODEGEN] - [WORKING_DIRECTORY ] + [WORKING_DIRECTORY ] [ABSOLUTE_PATHS] ) ``` -This creates a CMake target `` and adds a command that generates lexer -file `` from the given `` template file using the `re2c` lexer +This creates a target `` and adds a command that generates lexer file +`` from the given `` template file using the re2c lexer generator. Relative source file path `` is interpreted as being relative to the current source directory. Relative `` file path is interpreted as being relative to the current binary directory. If generated files are already available (for example, shipped with the released archive), and re2c is not -found, it will create a custom target but skip the `re2c` command-line -execution. +found, it will create a target but skip the `re2c` command-line execution. -When used in CMake command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it +When used in command-line script mode (see `CMAKE_SCRIPT_MODE_FILE`) it generates the lexer right away without creating a target. #### Options @@ -60,28 +59,27 @@ generates the lexer right away without creating a target. mode (`CMAKE_SCRIPT_MODE`), option is not checked, whether the compiler supports it and is added unconditionally. -* `CODEGEN` - This adds the `CODEGEN` option to the `add_custom_command()` call. - Works as of CMake 3.31 when policy `CMP0171` is set to `NEW`, which provides a - global CMake `codegen` target for convenience to call only the - code-generation-related targets and skip the majority of the build: +* `CODEGEN` - Adds the `CODEGEN` option to the `add_custom_command()` call. This + option is available starting with CMake 3.31 when the policy `CMP0171` is set + to `NEW`. It provides a `codegen` target for convenience, allowing to run only + code-generation-related targets while skipping the majority of the build: ```sh cmake --build --target codegen ``` -* `WORKING_DIRECTORY ` - The path where the `re2c` is - executed. Relative `` path is interpreted as being relative - to the current binary directory. If not set, `re2c` is by default executed in - the `PHP_SOURCE_DIR` when building the php-src repository. Otherwise it is +* `WORKING_DIRECTORY ` - The path where the `re2c` is executed. + Relative `` path is interpreted as being relative to the current + binary directory. If not set, `re2c` is by default executed in the + `PHP_SOURCE_DIR` when building the php-src repository. Otherwise it is executed in the directory of the `` file. If variable `PHP_RE2C_WORKING_DIRECTORY` is set before calling the `php_re2c()` without this option, it will set the default working directory to that instead. * `ABSOLUTE_PATHS` - Whether to use absolute file paths in the `re2c` - command-line invocations. By default all file paths are added to `re2c` as - relative to the working directory. Using relative paths is convenient when - line directives (`#line ...`) are generated in the output files to not show - the full path on the disk, if file is committed to Git repository. + command-line invocations. By default all file paths are added as relative to + the working directory. Using relative paths is convenient when line directives + (`#line ...`) are generated in the output files committed to Git repository. When this option is enabled: @@ -115,7 +113,7 @@ These variables can be set before using this module to configure behavior: * `PHP_RE2C_WORKING_DIRECTORY` - Set the default global working directory for all `php_re2c()` invocations in the directory scope where the - `WORKING_DIRECTORY ` option is not set. + `WORKING_DIRECTORY ` option is not set. ## Examples @@ -155,9 +153,9 @@ php_re2c(foo foo.re foo.c OPTIONS $<$:--debug-output> -F) # re2c -F --output foo.c foo.re ``` -### Custom target usage +### Target usage -To specify dependencies with the custom target created by `php_re2c()`: +Target created by `php_re2c()` can be used to specify additional dependencies: ```cmake # CMakeLists.txt @@ -168,8 +166,7 @@ php_re2c(foo_lexer lexer.re lexer.c) add_dependencies(some_target foo_lexer) ``` -Or to run only the specific `foo_lexer` target, which generates the -lexer-related files: +Running only the `foo_lexer` target to generate the lexer-related files: ```sh cmake --build --target foo_lexer @@ -177,20 +174,12 @@ cmake --build --target foo_lexer ### Module configuration -To specify minimum required re2c version other than the module's default, -`find_package(RE2C)` can be called before the `php_re2c()`: +To specify different minimum required re2c version than the module's default, +the `find_package(RE2C)` can be called before `php_re2c()`: ```cmake -find_package(RE2C 3.1) -include(PHP/Re2c) -php_re2c(...) -``` - -Set `PHP_RE2C_*` variables to override module default configuration: - -```cmake -set(PHP_RE2C_VERSION_DOWNLOAD 3.1) include(PHP/Re2c) +find_package(RE2C 3.1) php_re2c(...) ``` #]=============================================================================] @@ -633,7 +622,6 @@ function(_php_re2c_download) INSTALL_COMMAND "" ) - # Set re2c executable. ExternalProject_Get_Property(re2c BINARY_DIR) set_property(CACHE RE2C_EXECUTABLE PROPERTY VALUE ${BINARY_DIR}/re2c) diff --git a/cmake/cmake/scripts/GenerateGrammar.cmake b/cmake/cmake/scripts/GenerateGrammar.cmake index f826aec6..9f30a843 100755 --- a/cmake/cmake/scripts/GenerateGrammar.cmake +++ b/cmake/cmake/scripts/GenerateGrammar.cmake @@ -1,14 +1,10 @@ #!/usr/bin/env -S cmake -P # -# CMake-based command-line script to generate the parser files with bison and +# CMake-based command-line script to generate the parser files with Bison and # lexer files with re2c. # # Run as: # -# cmake -P cmake/scripts/GenerateGrammar.cmake -# -# To manually override bison and re2c executables: -# # cmake \ # [-D BISON_EXECUTABLE=path/to/bison] \ # [-D RE2C_EXECUTABLE=path/to/re2c] \ diff --git a/cmake/ext/json/CMakeLists.txt b/cmake/ext/json/CMakeLists.txt index 90066df6..d13e6232 100644 --- a/cmake/ext/json/CMakeLists.txt +++ b/cmake/ext/json/CMakeLists.txt @@ -41,7 +41,7 @@ target_sources( target_compile_definitions(php_ext_json PRIVATE ZEND_ENABLE_STATIC_TSRMLS_CACHE) ################################################################################ -# Generate lexer and parser files. +# Generate parser and lexer files. ################################################################################ include(cmake/GenerateGrammar.cmake) diff --git a/cmake/ext/json/cmake/GenerateGrammar.cmake b/cmake/ext/json/cmake/GenerateGrammar.cmake index c1f26836..e65ba9e4 100644 --- a/cmake/ext/json/cmake/GenerateGrammar.cmake +++ b/cmake/ext/json/cmake/GenerateGrammar.cmake @@ -1,4 +1,4 @@ -# Generate lexer and parser files. +# Generate parser and lexer files. if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) message(FATAL_ERROR "This file should be used with include().") diff --git a/cmake/sapi/phpdbg/CMakeLists.txt b/cmake/sapi/phpdbg/CMakeLists.txt index 1395d4da..6e1a495c 100644 --- a/cmake/sapi/phpdbg/CMakeLists.txt +++ b/cmake/sapi/phpdbg/CMakeLists.txt @@ -242,7 +242,7 @@ if(PHP_SAPI_PHPDBG_SHARED) endif() ################################################################################ -# Generate lexer and parser files. +# Generate parser and lexer files. ################################################################################ include(cmake/GenerateGrammar.cmake) diff --git a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake index dc9e54af..4c43f529 100644 --- a/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake +++ b/cmake/sapi/phpdbg/cmake/GenerateGrammar.cmake @@ -1,4 +1,4 @@ -# Generate lexer and parser files. +# Generate parser and lexer files. if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) message(FATAL_ERROR "This file should be used with include().")