Commit 4fc487f6d9c for php.net
commit 4fc487f6d9c6876bdc328914d7887d933eee3d84
Author: Marc <m@pyc.ac>
Date: Tue Jul 28 16:27:20 2026 +0700
Make php-cli functionality available in embed build (#21385)
diff --git a/NEWS b/NEWS
index a7aa29cd904..48864929c22 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,9 @@ PHP NEWS
. Fixed bug GH-22825 (DOMElement::setAttribute() fails silently when the DTD
declares a default value for the attribute). (iliaal)
+- Embed:
+ . Made php-cli functionality available in embed builds. (henderkes)
+
- GMP:
. Added gmp_prevprime(). (Weilin Du, David Carlier)
. Fixed GMP power and shift operators to reject GMP right operands outside
diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index 39f5d72e270..8b4b5912317 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -191,6 +191,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES
strings from one or more buffers.
. Added zend_string_ends_with() and related variants.
. Added trait support for internal classes.
+ . Added do_php_cli().
========================
2. Build system changes
@@ -227,6 +228,10 @@ PHP 8.6 INTERNALS UPGRADE NOTES
. Added a new function CHECK_HEADER() which is intended to be used instead of
the CHECK_HEADER_ADD_INCLUDE().
+- Embed:
+ . The CLI SAPI can not be disabled when building the embed SAPI
+ (--enable-embed is incompatible with --disable-cli).
+
========================
3. Module changes
========================
@@ -307,3 +312,6 @@ PHP 8.6 INTERNALS UPGRADE NOTES
- AG and SCNG are now allocated with ts_allocate_tls_id() and live in native
__thread storage on ZTS builds.
+
+- php-cli functionality is now available in embed builds via the do_php_cli()
+ function.
diff --git a/sapi/cli/cli.h b/sapi/cli/cli.h
index 2f6ef95052c..9502a6726fe 100644
--- a/sapi/cli/cli.h
+++ b/sapi/cli/cli.h
@@ -54,4 +54,7 @@ typedef struct php_cli_server_context {
php_cli_mode mode;
} php_cli_server_context;
+/* this performs full cli-SAPI boot, loads modules, sets up TSRM and co. */
+extern PHP_CLI_API int do_php_cli(int argc, char *argv[]);
+
#endif /* CLI_H */
diff --git a/sapi/cli/cli_win32.c b/sapi/cli/cli_win32.c
index 4407fd088f6..de7d0a0282f 100644
--- a/sapi/cli/cli_win32.c
+++ b/sapi/cli/cli_win32.c
@@ -1,2 +1,7 @@
#define PHP_CLI_WIN32_NO_CONSOLE 1
#include "php_cli.c"
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
+{
+ return do_php_cli(__argc, __argv);
+}
diff --git a/sapi/cli/config.m4 b/sapi/cli/config.m4
index 76c2d64e8c8..6abaa88df41 100644
--- a/sapi/cli/config.m4
+++ b/sapi/cli/config.m4
@@ -5,6 +5,11 @@ PHP_ARG_ENABLE([cli],
[yes],
[no])
+dnl The embed SAPI requires the CLI sources for do_php_cli().
+if test "$PHP_EMBED" != "no" -a "$PHP_CLI" = "no"; then
+ AC_MSG_ERROR([--enable-embed requires the CLI SAPI, do not use --disable-cli with --enable-embed])
+fi
+
if test "$PHP_CLI" != "no"; then
AC_CHECK_FUNCS([setproctitle])
@@ -32,9 +37,17 @@ if test "$PHP_CLI" != "no"; then
dnl Select SAPI.
PHP_SELECT_SAPI([cli],
[program],
- [php_cli.c php_http_parser.c php_cli_server.c ps_title.c php_cli_process_title.c],
+ [php_cli_main.c],
[-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+ dnl Everything except the main() entry point, so that the embed SAPI can link
+ dnl the same objects into libphp for do_php_cli().
+ PHP_ADD_SOURCES_X([sapi/cli],
+ [php_cli.c php_http_parser.c php_cli_server.c ps_title.c php_cli_process_title.c],
+ [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1],
+ [PHP_CLI_SHARED_OBJS])
+ PHP_CLI_OBJS="$PHP_CLI_OBJS $PHP_CLI_SHARED_OBJS"
+
AS_CASE([$host_alias],
[*aix*], [
AS_VAR_IF([php_sapi_module], [shared], [
diff --git a/sapi/cli/config.w32 b/sapi/cli/config.w32
index 5dff4054b69..695a5b46ec1 100644
--- a/sapi/cli/config.w32
+++ b/sapi/cli/config.w32
@@ -3,8 +3,13 @@
ARG_ENABLE('cli', 'Build CLI version of PHP', 'yes');
ARG_ENABLE('cli-win32', 'Build console-less CLI version of PHP', 'no');
+// The embed SAPI requires the CLI sources for do_php_cli().
+if (PHP_EMBED != "no" && PHP_CLI != "yes") {
+ ERROR("--enable-embed requires the CLI SAPI, do not use --disable-cli with --enable-embed");
+}
+
if (PHP_CLI == "yes") {
- SAPI('cli', 'php_cli.c php_http_parser.c php_cli_server.c', 'php.exe', '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
+ SAPI('cli', 'php_cli.c php_cli_main.c php_http_parser.c php_cli_server.c', 'php.exe', '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
ADD_SOURCES(configure_module_dirname, 'php_cli_process_title.c ps_title.c', 'cli');
ADD_FLAG("LIBS_CLI", "ws2_32.lib");
ADD_FLAG("LIBS_CLI", "shell32.lib");
diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c
index 9095fb10dd4..296b7cd521f 100644
--- a/sapi/cli/php_cli.c
+++ b/sapi/cli/php_cli.c
@@ -1173,18 +1173,10 @@ static int do_cli(int argc, char **argv) /* {{{ */
}
/* }}} */
-/* {{{ main */
-#ifdef PHP_CLI_WIN32_NO_CONSOLE
-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
-#else
-int main(int argc, char *argv[])
-#endif
+/* {{{ do_php_cli */
+PHP_CLI_API int do_php_cli(int argc, char *argv[])
{
#if defined(PHP_WIN32)
-# ifdef PHP_CLI_WIN32_NO_CONSOLE
- int argc = __argc;
- char **argv = __argv;
-# endif
int num_args;
wchar_t **argv_wide;
char **argv_save = argv;
@@ -1387,6 +1379,6 @@ int main(int argc, char *argv[])
* exiting.
*/
cleanup_ps_args(argv);
- exit(exit_status);
+ return exit_status;
}
/* }}} */
diff --git a/sapi/cli/php_cli_main.c b/sapi/cli/php_cli_main.c
new file mode 100644
index 00000000000..1030b5feb92
--- /dev/null
+++ b/sapi/cli/php_cli_main.c
@@ -0,0 +1,19 @@
+/*
+ +----------------------------------------------------------------------+
+ | Copyright © The PHP Group and Contributors. |
+ +----------------------------------------------------------------------+
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at <https://www.php.net/license/>. |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+ +----------------------------------------------------------------------+
+*/
+
+#include "php.h"
+#include "cli.h"
+
+int main(int argc, char *argv[])
+{
+ return do_php_cli(argc, argv);
+}
diff --git a/sapi/embed/config.m4 b/sapi/embed/config.m4
index 2bb5ed4df4d..e0051ecf66d 100644
--- a/sapi/embed/config.m4
+++ b/sapi/embed/config.m4
@@ -1,10 +1,3 @@
-PHP_ARG_ENABLE([embed],,
- [AS_HELP_STRING([[--enable-embed[=TYPE]]],
- [Enable building of embedded SAPI library TYPE is either
- 'shared' or 'static'. [TYPE=shared]])],
- [no],
- [no])
-
AC_MSG_CHECKING([for embedded SAPI library support])
if test "$PHP_EMBED" != "no"; then
@@ -33,6 +26,9 @@ if test "$PHP_EMBED" != "no"; then
[php_embed.c],
[-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
PHP_INSTALL_HEADERS([sapi/embed], [php_embed.h])
+
+ dnl Link the CLI objects into libphp for do_php_cli().
+ PHP_SAPI_OBJS="$PHP_SAPI_OBJS $PHP_CLI_SHARED_OBJS"
])
else
AC_MSG_RESULT([no])
diff --git a/sapi/embed/config.w32 b/sapi/embed/config.w32
index 394982126ca..3ac4668bce8 100644
--- a/sapi/embed/config.w32
+++ b/sapi/embed/config.w32
@@ -6,5 +6,8 @@ var PHP_EMBED_PGO = false;
if (PHP_EMBED != "no") {
SAPI('embed', 'php_embed.c', 'php' + PHP_VERSION + 'embed.lib', '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
+ ADD_SOURCES("sapi/cli", "php_cli.c php_http_parser.c php_cli_server.c ps_title.c php_cli_process_title.c", "embed", undefined, true);
+ ADD_FLAG("LIBS_EMBED", "ws2_32.lib");
+ ADD_FLAG("LIBS_EMBED", "shell32.lib");
PHP_INSTALL_HEADERS("sapi/embed", "php_embed.h");
}
diff --git a/sapi/embed/config0.m4 b/sapi/embed/config0.m4
new file mode 100644
index 00000000000..f1c05b8ea01
--- /dev/null
+++ b/sapi/embed/config0.m4
@@ -0,0 +1,6 @@
+PHP_ARG_ENABLE([embed],,
+ [AS_HELP_STRING([[--enable-embed[=TYPE]]],
+ [Enable building of embedded SAPI library TYPE is either
+ 'shared' or 'static'. [TYPE=shared]])],
+ [no],
+ [no])
diff --git a/sapi/embed/php_embed.c b/sapi/embed/php_embed.c
index 75249f97fc8..96534c18a69 100644
--- a/sapi/embed/php_embed.c
+++ b/sapi/embed/php_embed.c
@@ -28,10 +28,6 @@ static const char HARDCODED_INI[] =
"max_execution_time=0\n"
"max_input_time=-1\n\0";
-#if defined(PHP_WIN32) && defined(ZTS)
-ZEND_TSRMLS_CACHE_DEFINE()
-#endif
-
static char* php_embed_read_cookies(void)
{
return NULL;