Skip to content

Commit 48c5c49

Browse files
committed
Add initial custom PHP command module
This enables generating files either with PHP found on the system or by using the built PHP CLI executable.
1 parent d782809 commit 48c5c49

File tree

9 files changed

+211
-109
lines changed

9 files changed

+211
-109
lines changed

bin/check-cmake/cmake-includes.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ modules="
8888
FindPackageMessage
8989
ProcessorCount
9090
91+
PHP/AddCustomCommand
9192
PHP/CheckAttribute
9293
PHP/CheckCompilerFlag
9394
PHP/ConfigureFile
@@ -153,6 +154,7 @@ FindPackageHandleStandardArgs="
153154
FindPackageMessage="find_package_message"
154155
ProcessorCount="processorcount"
155156

157+
PHP_AddCustomCommand="php_add_custom_command"
156158
PHP_CheckAttribute="
157159
php_check_function_attribute
158160
php_check_variable_attribute

bin/init.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,12 @@ if test -z "$branch"; then
139139
case $branch in
140140
PHP-[0-9]\.[0-9]*)
141141
;;
142+
master)
143+
branch=master
144+
;;
142145
*)
143-
branch="master"
146+
echo "Unknown branch. Please, add the '--branch' option" >&2
147+
exit 1
144148
;;
145149
esac
146150
fi

cmake/Zend/CMakeLists.txt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ include(CheckIncludeFile)
4949
include(CheckSourceCompiles)
5050
include(CheckSymbolExists)
5151
include(CMakePushCheckState)
52+
include(PHP/AddCustomCommand)
5253
include(PHP/SearchLibraries)
5354

5455
################################################################################
@@ -483,18 +484,21 @@ endif()
483484
# 32-bit targets are not considered development oriented environments, where the
484485
# files need to be regenerated, executing this script is skipped.
485486
# See: https://github.com/php/php-src/issues/15899
486-
if(PHPSystem_EXECUTABLE AND NOT CMAKE_SIZEOF_VOID_P EQUAL 4)
487-
add_custom_command(
487+
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 4)
488+
php_add_custom_command(
489+
zend_generate_vm
488490
OUTPUT
489491
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_execute.h
490-
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_opcodes.h
492+
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_handlers.h
491493
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_opcodes.c
492-
COMMAND ${PHPSystem_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_gen.php
494+
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_opcodes.h
493495
DEPENDS
496+
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_def.h
494497
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_execute.skl
495498
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_gen.php
496-
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_def.h
497-
COMMENT "[Zend] Regenerating zend_vm_execute.h and zend_vm_opcodes.{h,c}"
499+
PHP_COMMAND
500+
${CMAKE_CURRENT_SOURCE_DIR}/zend_vm_gen.php
501+
COMMENT "[Zend] Regenerating zend_vm_execute.h, zend_vm_handlers.h and zend_vm_opcodes.{h,c}"
498502
VERBATIM
499503
)
500504
endif()
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#[=============================================================================[
2+
Add custom command.
3+
4+
This module is built on top of the CMake
5+
[`add_custom_command`](https://cmake.org/cmake/help/latest/command/add_custom_command.html)
6+
and [`add_custom_target()`](https://cmake.org/cmake/help/latest/command/add_custom_target.html)
7+
commands.
8+
9+
A common issue in build systems is the generation of files with the project
10+
program itself. Here are two main cases:
11+
* PHP is found on the system: this is the most simple and developer-friendly to
12+
use as some files can be generated during the build phase.
13+
* When PHP is not found on the system, ideally the files could be generated
14+
after the PHP CLI binary is built in the current project itself. However, this
15+
can quickly bring cyclic dependencies between the target at hand, PHP CLI and
16+
the generated files. In such case, inconvenience is that two build steps might
17+
need to be done in order to generate the entire project once the file has been
18+
regenerated.
19+
20+
This module exposes the following function:
21+
22+
```cmake
23+
php_add_custom_command(
24+
<unique-symbolic-target-name>
25+
OUTPUT ...
26+
DEPENDS ...
27+
PHP_COMMAND ...
28+
[COMMENT <comment>]
29+
[VERBATIM]
30+
)
31+
```
32+
33+
It acts similar to `add_custom_command()` and `add_custom_target()`, except that
34+
the DEPENDS argument doesn't add dependencies among targets but instead checks
35+
their timestamps manually and executes the PHP_COMMAND only when needed.
36+
37+
```cmake
38+
php_add_custom_command(
39+
php_generate_something
40+
OUTPUTS
41+
list of generated files
42+
DEPENDS
43+
list of files or targets that this generation depends on
44+
PHP_COMMAND
45+
${CMAKE_CURRENT_SOURCE_DIR}/generate-something.php
46+
COMMENT "Generate something"
47+
VERBATIM
48+
)
49+
```
50+
#]=============================================================================]
51+
52+
include_guard(GLOBAL)
53+
54+
function(php_add_custom_command)
55+
cmake_parse_arguments(
56+
PARSE_ARGV
57+
1
58+
parsed # prefix
59+
"VERBATIM" # options
60+
"COMMENT" # one-value keywords
61+
"OUTPUT;DEPENDS;PHP_COMMAND" # multi-value keywords
62+
)
63+
64+
if(parsed_UNPARSED_ARGUMENTS)
65+
message(FATAL_ERROR "Bad arguments: ${parsed_UNPARSED_ARGUMENTS}")
66+
endif()
67+
68+
if(NOT ARGV0)
69+
message(FATAL_ERROR "1st argument (target name) is missing.")
70+
endif()
71+
72+
set(targetName ${ARGV0})
73+
74+
if(parsed_VERBATIM)
75+
set(verbatim VERBATIM)
76+
else()
77+
set(verbatim)
78+
endif()
79+
80+
if(PHPSystem_EXECUTABLE)
81+
add_custom_command(
82+
OUTPUT ${parsed_OUTPUT}
83+
COMMAND ${PHPSystem_EXECUTABLE} ${parsed_PHP_COMMAND}
84+
DEPENDS ${parsed_DEPENDS}
85+
COMMENT "${parsed_COMMENT}"
86+
${verbatim}
87+
)
88+
89+
return()
90+
endif()
91+
92+
if(NOT CMAKE_CROSSCOMPILING)
93+
set(PHP_EXECUTABLE "$<TARGET_FILE:php_cli>")
94+
elseif(CMAKE_CROSSCOMPILING AND CMAKE_CROSSCOMPILING_EMULATOR)
95+
set(PHP_EXECUTABLE "${CMAKE_CROSSCOMPILING_EMULATOR};$<TARGET_FILE:php_cli>")
96+
else()
97+
return()
98+
endif()
99+
100+
add_custom_target(
101+
${targetName} ALL
102+
COMMAND ${CMAKE_COMMAND}
103+
-D "PHP_EXECUTABLE=${PHP_EXECUTABLE}"
104+
-D "OUTPUT=${parsed_OUTPUT}"
105+
-D "PHP_COMMAND=${parsed_PHP_COMMAND}"
106+
-D "DEPENDS=${parsed_DEPENDS}"
107+
-D "COMMENT=${parsed_COMMENT}"
108+
-P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/AddCustomCommand/RunCommand.cmake
109+
${verbatim}
110+
)
111+
endfunction()
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#[=============================================================================[
2+
Script for PHP/AddCustomCommand module that loops over output files and their
3+
dependant input source files and runs the command inside the execute_process().
4+
5+
Expected variables:
6+
7+
* PHP_EXECUTABLE
8+
* PHP_COMMAND
9+
* DEPENDS
10+
* OUTPUT
11+
* COMMENT
12+
#]=============================================================================]
13+
14+
if(NOT CMAKE_SCRIPT_MODE_FILE OR NOT PHP_EXECUTABLE OR NOT PHP_COMMAND)
15+
return()
16+
endif()
17+
18+
set(needsUpdate FALSE)
19+
20+
foreach(input ${DEPENDS})
21+
if(NOT EXISTS ${input})
22+
continue()
23+
endif()
24+
25+
foreach(output ${OUTPUT})
26+
if(NOT EXISTS ${output})
27+
continue()
28+
endif()
29+
30+
if("${input}" IS_NEWER_THAN "${output}")
31+
set(needsUpdate TRUE)
32+
break()
33+
endif()
34+
endforeach()
35+
36+
if(needsUpdate)
37+
break()
38+
endif()
39+
endforeach()
40+
41+
if(NOT needsUpdate)
42+
return()
43+
endif()
44+
45+
if(COMMENT)
46+
execute_process(
47+
COMMAND
48+
${CMAKE_COMMAND} -E cmake_echo_color --blue --bold " ${COMMENT}"
49+
)
50+
endif()
51+
52+
execute_process(COMMAND ${PHP_EXECUTABLE} ${PHP_COMMAND})
53+
54+
# Update modification times of output files to not re-run the command on the
55+
# consecutive build runs.
56+
file(TOUCH_NOCREATE ${OUTPUT})

cmake/ext/tokenizer/CMakeLists.txt

Lines changed: 16 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
include(CMakeDependentOption)
22
include(FeatureSummary)
3+
include(PHP/AddCustomCommand)
34

45
option(EXT_TOKENIZER "Enable the tokenizer extension" ON)
56

@@ -37,91 +38,18 @@ target_sources(
3738
# The tokenizer extension depends on the generated Zend scanner and parser.
3839
add_dependencies(php_tokenizer Zend::Zend)
3940

40-
if(PHPSystem_EXECUTABLE)
41-
set(PHP_EXECUTABLE ${PHPSystem_EXECUTABLE})
42-
elseif(NOT CMAKE_CROSSCOMPILING)
43-
set(PHP_EXECUTABLE "$<TARGET_FILE:php_cli>")
44-
elseif(CMAKE_CROSSCOMPILING AND CMAKE_CROSSCOMPILING_EMULATOR)
45-
set(PHP_EXECUTABLE "${CMAKE_CROSSCOMPILING_EMULATOR};$<TARGET_FILE:php_cli>")
46-
endif()
47-
48-
if(PHP_EXECUTABLE)
49-
# Patch tokenizer_data_gen.php to generate output only when needed.
50-
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_data_gen.php" content)
51-
string(
52-
REPLACE
53-
[[$infile = __DIR__ . '/../../Zend/zend_language_parser.y';]]
54-
"$infile = '${PHP_SOURCE_DIR}/Zend/zend_language_parser.y';"
55-
content
56-
"${content}"
57-
)
58-
string(
59-
REPLACE
60-
[[$outfile_stub = __DIR__ . '/tokenizer_data.stub.php';]]
61-
"$outfile_stub = '${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_data.stub.php';"
62-
content
63-
"${content}"
64-
)
65-
string(
66-
REPLACE
67-
[[$outfile_c = __DIR__ . '/tokenizer_data.c';]]
68-
"$outfile_c = '${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_data.c';"
69-
content
70-
"${content}"
71-
)
72-
string(
73-
REPLACE
74-
[[file_put_contents($outfile_stub, $result);
75-
76-
echo "Wrote $outfile_stub\n";]]
77-
[[
78-
if (file_exists($outfile_stub)) {
79-
$currentContent = file_get_contents($outfile_stub);
80-
}
81-
if ($currentContent !== $result) {
82-
file_put_contents($outfile_stub, $result);
83-
echo "Wrote $outfile_stub\n";
84-
}
85-
]]
86-
content
87-
"${content}"
88-
)
89-
string(
90-
REPLACE
91-
[[file_put_contents($outfile_c, $result);
92-
93-
echo "Wrote $outfile_c\n";]]
94-
[[
95-
$currentContent = '';
96-
if (file_exists($outfile_c)) {
97-
$currentContent = file_get_contents($outfile_c);
98-
}
99-
if ($currentContent !== $result) {
100-
file_put_contents($outfile_c, $result);
101-
echo "Wrote $outfile_c\n";
102-
}
103-
]]
104-
content
105-
"${content}"
106-
)
107-
file(
108-
WRITE
109-
"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/tokenizer_data_gen.php"
110-
"${content}"
111-
)
112-
113-
add_custom_command(
114-
OUTPUT
115-
php_tokenizer_data
116-
COMMAND
117-
${PHP_EXECUTABLE}
118-
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/tokenizer_data_gen.php
119-
DEPENDS
120-
${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_data_gen.php
121-
${PHP_SOURCE_DIR}/Zend/zend_language_parser.y
122-
COMMENT "[ext/tokenizer] Regenerating ext/tokenizer/tokenizer_data.c"
123-
VERBATIM
124-
)
125-
add_custom_target(php_tokenizer_generate_data ALL DEPENDS php_tokenizer_data)
126-
set_property(SOURCE php_tokenizer_data PROPERTY SYMBOLIC TRUE)
127-
endif()
41+
# Generate tokenizer data source files.
42+
php_add_custom_command(
43+
php_generate_tokenizer_data
44+
OUTPUT
45+
${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_data.stub.php
46+
${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_data.c
47+
DEPENDS
48+
${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_data_gen.php
49+
${PHP_SOURCE_DIR}/Zend/zend_language_parser.y
50+
PHP_COMMAND
51+
${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_data_gen.php
52+
COMMENT
53+
"[ext/tokenizer] Regenerating tokenizer_data.c and tokenizer_data.stub.php"
54+
VERBATIM
55+
)

cmake/main/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ foreach(extension IN LISTS extensions)
190190
else()
191191
target_link_libraries(php_main PRIVATE PHP::${extension})
192192
endif()
193+
194+
add_dependencies(php_${extension} zend)
193195
endforeach()
194196

195197
################################################################################

patches/8.3/php-config.patch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ index 61ee5c1675..1a8d67a783 100644
5858

5959
dnl
6060
diff --git a/configure.ac b/configure.ac
61-
index 8784bbf088..49f9094ac4 100644
61+
index 9c90d92240..88a86e35a5 100644
6262
--- a/configure.ac
6363
+++ b/configure.ac
6464
@@ -1480,6 +1480,9 @@ exec_prefix=$old_exec_prefix

0 commit comments

Comments
 (0)