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()