mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-02 22:35:43 +08:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bad28fa263 | ||
|
|
985cd6781e | ||
|
|
44dcc830f4 | ||
|
|
10ef4c0d3b | ||
|
|
d0fbc5ab2d | ||
|
|
1bc7bc3421 | ||
|
|
8b9b70704a | ||
|
|
804020210d | ||
|
|
5c51305978 | ||
|
|
43cc9d0ba3 | ||
|
|
52869218e0 | ||
|
|
82e11e52dd | ||
|
|
955c367a47 | ||
|
|
a613e9a84f | ||
|
|
c4b9660cd7 | ||
|
|
f433866671 | ||
|
|
fdc4a907c7 | ||
|
|
cf37e16e38 | ||
|
|
2aa42123f6 | ||
|
|
c840165fa8 | ||
|
|
4e95d969e3 | ||
|
|
330dd2bfc6 | ||
|
|
c0b52fc2d1 |
15
.github/workflows/build-macos-x86_64.yml
vendored
15
.github/workflows/build-macos-x86_64.yml
vendored
@@ -13,8 +13,6 @@ on:
|
||||
- '8.3'
|
||||
- '8.2'
|
||||
- '8.1'
|
||||
- '8.0'
|
||||
- '7.4'
|
||||
build-cli:
|
||||
description: build cli binary
|
||||
default: true
|
||||
@@ -36,6 +34,10 @@ on:
|
||||
debug:
|
||||
description: enable debug logs
|
||||
type: boolean
|
||||
no-strip:
|
||||
description: keep debug symbols for debugging
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -81,13 +83,15 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: downloads
|
||||
key: php-${{ env.INPUT_HASH }}
|
||||
key: php-${{ inputs.version }}-macos-x86_64
|
||||
|
||||
# With or without debug
|
||||
- if: inputs.debug == true
|
||||
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
|
||||
- if: inputs.prefer-pre-built == true
|
||||
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
|
||||
- if: inputs.no-strip == true
|
||||
run: echo "SPC_NO_STRIP=--no-strip" >> $env:GITHUB_ENV
|
||||
|
||||
# With target select: cli, micro or both
|
||||
- if: ${{ inputs.build-cli == true }}
|
||||
@@ -98,11 +102,10 @@ jobs:
|
||||
run: echo "SPC_BUILD_FPM=--build-fpm" >> $GITHUB_ENV
|
||||
|
||||
# If there's no dependencies cache, fetch sources, with or without debug
|
||||
- if: steps.cache-download.outputs.cache-hit != 'true'
|
||||
run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
|
||||
- run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }} --ignore-cache-sources=php-src
|
||||
|
||||
# Run build command
|
||||
- run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}
|
||||
- run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_NO_STRIP }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}
|
||||
|
||||
# Upload cli executable
|
||||
- if: ${{ inputs.build-cli == true }}
|
||||
|
||||
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@@ -199,3 +199,7 @@ jobs:
|
||||
|
||||
- name: "Run Build Tests (build)"
|
||||
run: php src/globals/test-extensions.php build_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||
|
||||
- name: "Run Build Tests (build - embed for non-windows)"
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: php src/globals/test-extensions.php build_embed_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||
|
||||
@@ -708,6 +708,19 @@
|
||||
"zlib"
|
||||
]
|
||||
},
|
||||
"rdkafka": {
|
||||
"support": {
|
||||
"BSD": "wip",
|
||||
"Windows": "wip"
|
||||
},
|
||||
"type": "external",
|
||||
"source": "ext-rdkafka",
|
||||
"arg-type": "custom",
|
||||
"cpp-extension": true,
|
||||
"lib-depends": [
|
||||
"librdkafka"
|
||||
]
|
||||
},
|
||||
"swoole": {
|
||||
"support": {
|
||||
"Windows": "no",
|
||||
|
||||
@@ -143,7 +143,6 @@
|
||||
"source": "grpc",
|
||||
"static-libs-unix": [
|
||||
"libgrpc.a",
|
||||
"libboringssl.a",
|
||||
"libcares.a"
|
||||
],
|
||||
"lib-depends": [
|
||||
@@ -559,6 +558,18 @@
|
||||
"pkg-config": {
|
||||
"source": "pkg-config"
|
||||
},
|
||||
"librdkafka": {
|
||||
"source": "librdkafka",
|
||||
"static-libs-unix": [
|
||||
"librdkafka.a",
|
||||
"librdkafka++.a",
|
||||
"librdkafka-static.a"
|
||||
],
|
||||
"cpp-library": true,
|
||||
"lib-suggests": [
|
||||
"zstd"
|
||||
]
|
||||
},
|
||||
"postgresql": {
|
||||
"source": "postgresql",
|
||||
"static-libs-unix": [
|
||||
|
||||
@@ -69,6 +69,23 @@
|
||||
"path": "LICENSE"
|
||||
}
|
||||
},
|
||||
"librdkafka": {
|
||||
"type": "ghtar",
|
||||
"repo": "confluentinc/librdkafka",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
},
|
||||
"ext-rdkafka": {
|
||||
"type": "ghtar",
|
||||
"repo": "arnaud-lb/php-rdkafka",
|
||||
"path": "php-src/ext/rdkafka",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
},
|
||||
"ext-event": {
|
||||
"type": "url",
|
||||
"url": "https://bitbucket.org/osmanov/pecl-event/get/3.0.8.tar.gz",
|
||||
|
||||
@@ -553,3 +553,76 @@ If you need to build multiple times locally, the following method can save you t
|
||||
- If you want to rebuild once, but do not re-download the source code, you can first `rm -rf buildroot source` to delete the compilation directory and source code directory, and then rebuild.
|
||||
- If you want to update a version of a dependency, you can use `bin/spc del-download <source-name>` to delete the specified source code, and then use `download <source-name>` to download it again.
|
||||
- If you want to update all dependent versions, you can use `bin/spc download --clean` to delete all downloaded sources, and then download them again.
|
||||
|
||||
## embed usage
|
||||
|
||||
If you want to embed static-php into other C language programs, you can use `--build-embed` to build an embed version of PHP.
|
||||
|
||||
```bash
|
||||
bin/spc build {your extensions} --build-embed --debug
|
||||
```
|
||||
|
||||
Under normal circumstances, PHP embed will generate `php-config` after compilation.
|
||||
For static-php, we provide `spc-config` to obtain the parameters during compilation.
|
||||
In addition, when using embed SAPI (libphp.a), you need to use the same compiler as libphp, otherwise there will be a link error.
|
||||
|
||||
Here is the basic usage of spc-config:
|
||||
|
||||
```bash
|
||||
# output all flags and options
|
||||
bin/spc spc-config curl,zlib,phar,openssl
|
||||
|
||||
# output libs
|
||||
bin/spc spc-config curl,zlib,phar,openssl --libs
|
||||
|
||||
# output includes
|
||||
bin/spc spc-config curl,zlib,phar,openssl --includes
|
||||
```
|
||||
|
||||
By default, static-php uses the following compilers on different systems:
|
||||
|
||||
- macOS: `clang`
|
||||
- Linux (Alpine Linux): `gcc`
|
||||
- Linux (glibc based distros, x86_64): `/usr/local/musl/bin/x86_64-linux-musl-gcc`
|
||||
- Linux (glibc based distros, aarch64): `/usr/local/musl/bin/aarch64-linux-musl-gcc`
|
||||
- FreeBSD: `clang`
|
||||
|
||||
Here is an example of using embed SAPI:
|
||||
|
||||
```c
|
||||
// embed.c
|
||||
#include <sapi/embed/php_embed.h>
|
||||
|
||||
int main(int argc,char **argv){
|
||||
|
||||
PHP_EMBED_START_BLOCK(argc,argv)
|
||||
|
||||
zend_file_handle file_handle;
|
||||
|
||||
zend_stream_init_filename(&file_handle,"embed.php");
|
||||
|
||||
if(php_execute_script(&file_handle) == FAILURE){
|
||||
php_printf("Failed to execute PHP script.\n");
|
||||
}
|
||||
|
||||
PHP_EMBED_END_BLOCK()
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
```php
|
||||
<?php
|
||||
// embed.php
|
||||
echo "Hello world!\n";
|
||||
```
|
||||
|
||||
```bash
|
||||
# compile in debian/ubuntu x86_64
|
||||
/usr/local/musl/bin/x86_64-linux-musl-gcc embed.c $(bin/spc spc-config bcmath,zlib) -static -o embed
|
||||
# compile in macOS/FreeBSD
|
||||
clang embed.c $(bin/spc spc-config bcmath,zlib) -o embed
|
||||
|
||||
./embed
|
||||
# out: Hello world!
|
||||
```
|
||||
|
||||
@@ -493,3 +493,75 @@ static-php-cli 开放的方法非常多,文档中无法一一列举,但只
|
||||
- 如果你想重新构建一次,但不重新下载源码,可以先 `rm -rf buildroot source` 删除编译目录和源码目录,然后重新构建。
|
||||
- 如果你想更新某个依赖的版本,可以使用 `bin/spc del-download <source-name>` 删除指定的源码,然后使用 `download <source-name>` 重新下载。
|
||||
- 如果你想更新所有依赖的版本,可以使用 `bin/spc download --clean` 删除所有下载的源码,然后重新下载。
|
||||
|
||||
## embed 使用
|
||||
|
||||
如果你想将 static-php 嵌入到其他 C 语言程序中,可以使用 `--build-embed` 构建一个 embed 版本的 PHP。
|
||||
|
||||
```bash
|
||||
bin/spc build {your extensions} --build-embed --debug
|
||||
```
|
||||
|
||||
在通常的情况下,PHP embed 编译后会生成 `php-config`。对于 static-php,我们提供了 `spc-config`,用于获取编译时的参数。
|
||||
另外,在使用 embed SAPI(libphp.a)时,你需要使用和编译 libphp 相同的编译器,否则会出现链接错误。
|
||||
|
||||
下面是 spc-config 的基本用法:
|
||||
|
||||
```bash
|
||||
# output all flags and options
|
||||
bin/spc spc-config curl,zlib,phar,openssl
|
||||
|
||||
# output libs
|
||||
bin/spc spc-config curl,zlib,phar,openssl --libs
|
||||
|
||||
# output includes
|
||||
bin/spc spc-config curl,zlib,phar,openssl --includes
|
||||
```
|
||||
|
||||
默认情况下,static-php 在不同系统使用的编译器分别是:
|
||||
|
||||
- macOS: `clang`
|
||||
- Linux (Alpine Linux): `gcc`
|
||||
- Linux (glibc based distros, x86_64): `/usr/local/musl/bin/x86_64-linux-musl-gcc`
|
||||
- Linux (glibc based distros, aarch64): `/usr/local/musl/bin/aarch64-linux-musl-gcc`
|
||||
- FreeBSD: `clang`
|
||||
|
||||
下面是一个使用 embed SAPI 的例子:
|
||||
|
||||
```c
|
||||
// embed.c
|
||||
#include <sapi/embed/php_embed.h>
|
||||
|
||||
int main(int argc,char **argv){
|
||||
|
||||
PHP_EMBED_START_BLOCK(argc,argv)
|
||||
|
||||
zend_file_handle file_handle;
|
||||
|
||||
zend_stream_init_filename(&file_handle,"embed.php");
|
||||
|
||||
if(php_execute_script(&file_handle) == FAILURE){
|
||||
php_printf("Failed to execute PHP script.\n");
|
||||
}
|
||||
|
||||
PHP_EMBED_END_BLOCK()
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
```php
|
||||
<?php
|
||||
// embed.php
|
||||
echo "Hello world!\n";
|
||||
```
|
||||
|
||||
```bash
|
||||
# compile in debian/ubuntu x86_64
|
||||
/usr/local/musl/bin/x86_64-linux-musl-gcc embed.c $(bin/spc spc-config bcmath,zlib) -static -o embed
|
||||
# compile in macOS/FreeBSD
|
||||
clang embed.c $(bin/spc spc-config bcmath,zlib) -o embed
|
||||
|
||||
./embed
|
||||
# out: Hello world!
|
||||
```
|
||||
|
||||
@@ -22,6 +22,7 @@ use SPC\command\DumpLicenseCommand;
|
||||
use SPC\command\ExtractCommand;
|
||||
use SPC\command\InstallPkgCommand;
|
||||
use SPC\command\MicroCombineCommand;
|
||||
use SPC\command\SPCConfigCommand;
|
||||
use SPC\command\SwitchPhpVersionCommand;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
@@ -30,7 +31,7 @@ use Symfony\Component\Console\Application;
|
||||
*/
|
||||
final class ConsoleApplication extends Application
|
||||
{
|
||||
public const VERSION = '2.4.1';
|
||||
public const VERSION = '2.4.2';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -52,6 +53,7 @@ final class ConsoleApplication extends Application
|
||||
new ExtractCommand(),
|
||||
new MicroCombineCommand(),
|
||||
new SwitchPhpVersionCommand(),
|
||||
new SPCConfigCommand(),
|
||||
|
||||
// Dev commands
|
||||
new AllExtCommand(),
|
||||
|
||||
@@ -25,6 +25,12 @@ abstract class BuilderBase
|
||||
/** @var array<string, Extension> extensions */
|
||||
protected array $exts = [];
|
||||
|
||||
/** @var array<int, string> extension names */
|
||||
protected array $ext_list = [];
|
||||
|
||||
/** @var array<int, string> library names */
|
||||
protected array $lib_list = [];
|
||||
|
||||
/** @var bool compile libs only (just mark it) */
|
||||
protected bool $libs_only = false;
|
||||
|
||||
@@ -161,7 +167,7 @@ abstract class BuilderBase
|
||||
* @throws FileSystemException
|
||||
* @throws RuntimeException
|
||||
* @throws \ReflectionException
|
||||
* @throws WrongUsageException
|
||||
* @throws \Throwable|WrongUsageException
|
||||
* @internal
|
||||
*/
|
||||
public function proveExts(array $extensions, bool $skip_check_deps = false): void
|
||||
@@ -191,6 +197,7 @@ abstract class BuilderBase
|
||||
foreach ($this->exts as $ext) {
|
||||
$ext->checkDependency();
|
||||
}
|
||||
$this->ext_list = $extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,14 +21,6 @@ class pgsql extends Extension
|
||||
*/
|
||||
public function patchBeforeConfigure(): bool
|
||||
{
|
||||
if ($this->builder->getPHPVersionID() >= 80400) {
|
||||
FileSystem::replaceFileStr(
|
||||
SOURCE_PATH . '/php-src/configure',
|
||||
'LIBS="-lpq',
|
||||
'LIBS="-lpq -lpgport -lpgcommon -lssl -lcrypto -lz -lm'
|
||||
);
|
||||
return true;
|
||||
}
|
||||
FileSystem::replaceFileRegex(
|
||||
SOURCE_PATH . '/php-src/configure',
|
||||
'/-lpq/',
|
||||
@@ -44,7 +36,7 @@ class pgsql extends Extension
|
||||
public function getUnixConfigureArg(): string
|
||||
{
|
||||
if ($this->builder->getPHPVersionID() >= 80400) {
|
||||
return '--with-pgsql=' . BUILD_ROOT_PATH . ' PGSQL_CFLAGS=-I' . BUILD_INCLUDE_PATH . ' PGSQL_LIBS="-L' . BUILD_LIB_PATH . ' -lpq -lpgport -lpgcommon"';
|
||||
return '--with-pgsql PGSQL_CFLAGS=-I' . BUILD_INCLUDE_PATH . ' PGSQL_LIBS="-L' . BUILD_LIB_PATH . ' -lpq -lpgport -lpgcommon"';
|
||||
}
|
||||
return '--with-pgsql=' . BUILD_ROOT_PATH;
|
||||
}
|
||||
|
||||
36
src/SPC/builder/extension/rdkafka.php
Normal file
36
src/SPC/builder/extension/rdkafka.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\extension;
|
||||
|
||||
use SPC\builder\Extension;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\CustomExt;
|
||||
|
||||
#[CustomExt('rdkafka')]
|
||||
class rdkafka extends Extension
|
||||
{
|
||||
public function patchBeforeMake(): bool
|
||||
{
|
||||
// when compiling rdkafka with inline builds, it shows some errors, I don't know why.
|
||||
FileSystem::replaceFileStr(
|
||||
SOURCE_PATH . '/php-src/ext/rdkafka/rdkafka.c',
|
||||
"#ifdef HAS_RD_KAFKA_TRANSACTIONS\n#include \"kafka_error_exception.h\"\n#endif",
|
||||
'#include "kafka_error_exception.h"'
|
||||
);
|
||||
FileSystem::replaceFileStr(
|
||||
SOURCE_PATH . '/php-src/ext/rdkafka/kafka_error_exception.h',
|
||||
['#ifdef HAS_RD_KAFKA_TRANSACTIONS', '#endif'],
|
||||
''
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getConfigureArg(): string
|
||||
{
|
||||
$pkgconf_libs = shell()->execWithResult('pkg-config --libs --static rdkafka')[1];
|
||||
$pkgconf_libs = trim(implode('', $pkgconf_libs));
|
||||
return '--with-rdkafka=' . BUILD_ROOT_PATH . ' LIBS="' . $pkgconf_libs . '"';
|
||||
}
|
||||
}
|
||||
13
src/SPC/builder/linux/library/librdkafka.php
Normal file
13
src/SPC/builder/linux/library/librdkafka.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
class librdkafka extends LinuxLibraryBase
|
||||
{
|
||||
// TODO: Linux is buggy, see https://github.com/confluentinc/librdkafka/discussions/4495
|
||||
use \SPC\builder\unix\library\librdkafka;
|
||||
|
||||
public const NAME = 'librdkafka';
|
||||
}
|
||||
12
src/SPC/builder/macos/library/librdkafka.php
Normal file
12
src/SPC/builder/macos/library/librdkafka.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\macos\library;
|
||||
|
||||
class librdkafka extends MacOSLibraryBase
|
||||
{
|
||||
use \SPC\builder\unix\library\librdkafka;
|
||||
|
||||
public const NAME = 'librdkafka';
|
||||
}
|
||||
@@ -12,6 +12,7 @@ use SPC\exception\WrongUsageException;
|
||||
use SPC\store\Config;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\DependencyUtil;
|
||||
use SPC\util\SPCConfigUtil;
|
||||
|
||||
abstract class UnixBuilderBase extends BuilderBase
|
||||
{
|
||||
@@ -128,6 +129,7 @@ abstract class UnixBuilderBase extends BuilderBase
|
||||
foreach ($this->libs as $lib) {
|
||||
$lib->calcDependency();
|
||||
}
|
||||
$this->lib_list = $sorted_libraries;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,6 +172,32 @@ abstract class UnixBuilderBase extends BuilderBase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check for embed
|
||||
if (($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED) {
|
||||
logger()->info('running embed sanity check');
|
||||
$sample_file_path = SOURCE_PATH . '/embed-test';
|
||||
if (!is_dir($sample_file_path)) {
|
||||
@mkdir($sample_file_path);
|
||||
}
|
||||
// copy embed test files
|
||||
copy(ROOT_DIR . '/src/globals/common-tests/embed.c', $sample_file_path . '/embed.c');
|
||||
copy(ROOT_DIR . '/src/globals/common-tests/embed.php', $sample_file_path . '/embed.php');
|
||||
$util = new SPCConfigUtil($this);
|
||||
$config = $util->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
|
||||
$lens = "{$config['cflags']} {$config['ldflags']} {$config['libs']}";
|
||||
if (PHP_OS_FAMILY === 'Linux') {
|
||||
$lens .= ' -static';
|
||||
}
|
||||
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens);
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('embed failed sanity check: build failed. Error message: ' . implode("\n", $out));
|
||||
}
|
||||
[$ret, $output] = shell()->cd($sample_file_path)->execWithResult('./embed');
|
||||
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
|
||||
throw new RuntimeException('embed failed sanity check: run failed. Error message: ' . implode("\n", $output));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@ trait gettext
|
||||
'--disable-java ' .
|
||||
'--disable-c+ ' .
|
||||
$extra .
|
||||
'--with-included-gettext ' .
|
||||
'--with-libiconv-prefix=' . BUILD_ROOT_PATH . ' ' .
|
||||
'--prefix=' . BUILD_ROOT_PATH
|
||||
)
|
||||
|
||||
39
src/SPC/builder/unix/library/librdkafka.php
Normal file
39
src/SPC/builder/unix/library/librdkafka.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\unix\library;
|
||||
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
trait librdkafka
|
||||
{
|
||||
/**
|
||||
* @throws FileSystemException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function build(): void
|
||||
{
|
||||
$builddir = BUILD_ROOT_PATH;
|
||||
|
||||
$zstd_option = $this->builder->getLib('zstd') ? ("STATIC_LIB_libzstd={$builddir}/lib/libzstd.a ") : '';
|
||||
shell()->cd($this->source_dir)
|
||||
->exec(
|
||||
$zstd_option .
|
||||
'./configure ' .
|
||||
'--enable-static --disable-shared --disable-curl --disable-sasl --disable-valgrind --disable-zlib --disable-ssl ' .
|
||||
($zstd_option == '' ? '--disable-zstd ' : '') .
|
||||
'--prefix='
|
||||
)
|
||||
->exec('make clean')
|
||||
->exec("make -j{$this->builder->concurrency}")
|
||||
->exec("make install DESTDIR={$builddir}");
|
||||
$this->patchPkgconfPrefix(['rdkafka.pc', 'rdkafka-static.pc', 'rdkafka++.pc', 'rdkafka++-static.pc']);
|
||||
// remove dynamic libs
|
||||
shell()
|
||||
->exec("rm -rf {$builddir}/lib/*.so.*")
|
||||
->exec("rm -rf {$builddir}/lib/*.so")
|
||||
->exec("rm -rf {$builddir}/lib/*.dylib");
|
||||
}
|
||||
}
|
||||
@@ -248,6 +248,7 @@ class WindowsBuilder extends BuilderBase
|
||||
foreach ($this->libs as $lib) {
|
||||
$lib->calcDependency();
|
||||
}
|
||||
$this->lib_list = $sorted_libraries;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -181,7 +181,9 @@ class BuildCliCommand extends BuildCommand
|
||||
|
||||
// compile stopwatch :P
|
||||
$time = round(microtime(true) - START_TIME, 3);
|
||||
logger()->info('Build complete, used ' . $time . ' s !');
|
||||
logger()->info('');
|
||||
logger()->info(' Build complete, used ' . $time . ' s !');
|
||||
logger()->info('');
|
||||
|
||||
// ---------- When using bin/spc-alpine-docker, the build root path is different from the host system ----------
|
||||
$build_root_path = BUILD_ROOT_PATH;
|
||||
|
||||
53
src/SPC/command/SPCConfigCommand.php
Normal file
53
src/SPC/command/SPCConfigCommand.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\util\SPCConfigUtil;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand('spc-config', 'Build dependencies')]
|
||||
class SPCConfigCommand extends BuildCommand
|
||||
{
|
||||
protected bool $no_motd = true;
|
||||
|
||||
public function configure(): void
|
||||
{
|
||||
$this->addArgument('extensions', InputArgument::OPTIONAL, 'The extensions will be compiled, comma separated');
|
||||
$this->addOption('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', '');
|
||||
$this->addOption('with-suggested-libs', 'L', null, 'Build with suggested libs for selected exts and libs');
|
||||
$this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts');
|
||||
$this->addOption('includes', null, null, 'Add additional include path');
|
||||
$this->addOption('libs', null, null, 'Add additional libs path');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
// transform string to array
|
||||
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs'))));
|
||||
// transform string to array
|
||||
$extensions = $this->getArgument('extensions') ? $this->parseExtensionList($this->getArgument('extensions')) : [];
|
||||
$include_suggest_ext = $this->getOption('with-suggested-exts');
|
||||
$include_suggest_lib = $this->getOption('with-suggested-libs');
|
||||
|
||||
$util = new SPCConfigUtil(null, $this->input);
|
||||
$config = $util->config($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
||||
|
||||
if ($this->getOption('includes')) {
|
||||
$this->output->writeln($config['cflags']);
|
||||
} elseif ($this->getOption('libs')) {
|
||||
$this->output->writeln("{$config['ldflags']} {$config['libs']}");
|
||||
} else {
|
||||
$this->output->writeln("{$config['cflags']} {$config['ldflags']} {$config['libs']}");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
104
src/SPC/util/SPCConfigUtil.php
Normal file
104
src/SPC/util/SPCConfigUtil.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\util;
|
||||
|
||||
use SPC\builder\BuilderBase;
|
||||
use SPC\builder\BuilderProvider;
|
||||
use SPC\builder\macos\MacOSBuilder;
|
||||
use SPC\store\Config;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
class SPCConfigUtil
|
||||
{
|
||||
public function __construct(private ?BuilderBase $builder = null, ?InputInterface $input = null)
|
||||
{
|
||||
if ($builder === null) {
|
||||
$this->builder = BuilderProvider::makeBuilderByInput($input ?? new ArgvInput());
|
||||
}
|
||||
}
|
||||
|
||||
public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
|
||||
{
|
||||
[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
||||
|
||||
ob_start();
|
||||
$this->builder->proveLibs($libraries);
|
||||
$this->builder->proveExts($extensions);
|
||||
ob_get_clean();
|
||||
$ldflags = $this->getLdflagsString();
|
||||
$libs = $this->getLibsString($libraries);
|
||||
$cflags = $this->getIncludesString();
|
||||
|
||||
// embed
|
||||
$libs = '-lphp -lc ' . $libs;
|
||||
$extra_env = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS');
|
||||
if (is_string($extra_env)) {
|
||||
$libs .= ' ' . $extra_env;
|
||||
}
|
||||
// c++
|
||||
if ($this->builder->hasCpp()) {
|
||||
$libs .= $this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++';
|
||||
}
|
||||
return [
|
||||
'cflags' => $cflags,
|
||||
'ldflags' => $ldflags,
|
||||
'libs' => $libs,
|
||||
];
|
||||
}
|
||||
|
||||
private function getIncludesString(): string
|
||||
{
|
||||
$base = BUILD_INCLUDE_PATH;
|
||||
$php_embed_includes = [
|
||||
"-I{$base}",
|
||||
"-I{$base}/php",
|
||||
"-I{$base}/php/main",
|
||||
"-I{$base}/php/TSRM",
|
||||
"-I{$base}/php/Zend",
|
||||
"-I{$base}/php/ext",
|
||||
];
|
||||
return implode(' ', $php_embed_includes);
|
||||
}
|
||||
|
||||
private function getLdflagsString(): string
|
||||
{
|
||||
return '-L' . BUILD_LIB_PATH;
|
||||
}
|
||||
|
||||
private function getLibsString(array $libraries): string
|
||||
{
|
||||
$short_name = [];
|
||||
foreach (array_reverse($libraries) as $library) {
|
||||
$libs = Config::getLib($library, 'static-libs', []);
|
||||
foreach ($libs as $lib) {
|
||||
$short_name[] = $this->getShortLibName($lib);
|
||||
}
|
||||
if (PHP_OS_FAMILY !== 'Darwin') {
|
||||
continue;
|
||||
}
|
||||
foreach (Config::getLib($library, 'frameworks', []) as $fw) {
|
||||
$ks = '-framework ' . $fw;
|
||||
if (!in_array($ks, $short_name)) {
|
||||
$short_name[] = $ks;
|
||||
}
|
||||
}
|
||||
}
|
||||
// patch: imagick (imagemagick wrapper) for linux needs -lgomp
|
||||
if (in_array('imagemagick', $libraries) && PHP_OS_FAMILY === 'Linux') {
|
||||
$short_name[] = '-lgomp';
|
||||
}
|
||||
return implode(' ', $short_name);
|
||||
}
|
||||
|
||||
private function getShortLibName(string $lib): string
|
||||
{
|
||||
if (!str_starts_with($lib, 'lib') || !str_ends_with($lib, '.a')) {
|
||||
return BUILD_LIB_PATH . '/' . $lib;
|
||||
}
|
||||
// get short name
|
||||
return '-l' . substr($lib, 3, -2);
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,9 @@ class UnixShell
|
||||
logger()->debug(ConsoleColor::blue('[EXEC] ') . ConsoleColor::gray($cmd));
|
||||
}
|
||||
logger()->debug('Executed at: ' . debug_backtrace()[0]['file'] . ':' . debug_backtrace()[0]['line']);
|
||||
if ($this->cd !== null) {
|
||||
$cmd = 'cd ' . escapeshellarg($this->cd) . ' && ' . $cmd;
|
||||
}
|
||||
exec($cmd, $out, $code);
|
||||
return [$code, $out];
|
||||
}
|
||||
|
||||
17
src/globals/common-tests/embed.c
Normal file
17
src/globals/common-tests/embed.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <sapi/embed/php_embed.h>
|
||||
|
||||
int main(int argc,char **argv){
|
||||
|
||||
PHP_EMBED_START_BLOCK(argc,argv)
|
||||
|
||||
zend_file_handle file_handle;
|
||||
|
||||
zend_stream_init_filename(&file_handle,"embed.php");
|
||||
|
||||
if(php_execute_script(&file_handle) == FAILURE){
|
||||
php_printf("Failed to execute PHP script.\n");
|
||||
}
|
||||
|
||||
PHP_EMBED_END_BLOCK()
|
||||
return 0;
|
||||
}
|
||||
4
src/globals/common-tests/embed.php
Normal file
4
src/globals/common-tests/embed.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
echo 'hello' . PHP_EOL;
|
||||
@@ -21,12 +21,13 @@ $test_php_version = [
|
||||
|
||||
// test os (macos-13, macos-14, ubuntu-latest, windows-latest are available)
|
||||
$test_os = [
|
||||
'macos-14',
|
||||
'ubuntu-latest',
|
||||
// 'macos-14',
|
||||
'macos-13',
|
||||
// 'ubuntu-latest',
|
||||
];
|
||||
|
||||
// whether enable thread safe
|
||||
$zts = true;
|
||||
$zts = false;
|
||||
|
||||
$no_strip = false;
|
||||
|
||||
@@ -34,12 +35,12 @@ $no_strip = false;
|
||||
$upx = false;
|
||||
|
||||
// prefer downloading pre-built packages to speed up the build process
|
||||
$prefer_pre_built = false;
|
||||
$prefer_pre_built = true;
|
||||
|
||||
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
|
||||
$extensions = match (PHP_OS_FAMILY) {
|
||||
'Linux', 'Darwin' => 'parallel',
|
||||
'Windows' => 'amqp,apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,ds,exif,ffi,fileinfo,filter,ftp,gd,iconv,igbinary,libxml,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pdo,pdo_mysql,pdo_sqlite,pdo_sqlsrv,phar,rar,redis,session,shmop,simdjson,simplexml,soap,sockets,sqlite3,sqlsrv,ssh2,swow,sysvshm,tokenizer,xml,xmlreader,xmlwriter,yac,yaml,zip,zlib',
|
||||
'Linux', 'Darwin' => 'rdkafka',
|
||||
'Windows' => 'zlib',
|
||||
};
|
||||
|
||||
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
|
||||
@@ -52,7 +53,7 @@ $with_libs = match (PHP_OS_FAMILY) {
|
||||
// You can use `common`, `bulk`, `minimal` or `none`.
|
||||
// note: combination is only available for *nix platform. Windows must use `none` combination
|
||||
$base_combination = match (PHP_OS_FAMILY) {
|
||||
'Linux', 'Darwin' => 'minimal',
|
||||
'Linux', 'Darwin' => 'bulk',
|
||||
'Windows' => 'none',
|
||||
};
|
||||
|
||||
@@ -114,14 +115,13 @@ if ($argv[1] === 'download_cmd') {
|
||||
}
|
||||
|
||||
// generate build command
|
||||
if ($argv[1] === 'build_cmd') {
|
||||
if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') {
|
||||
$build_cmd = 'build ';
|
||||
$build_cmd .= quote2($final_extensions) . ' ';
|
||||
$build_cmd .= $zts ? '--enable-zts ' : '';
|
||||
$build_cmd .= $no_strip ? '--no-strip ' : '';
|
||||
$build_cmd .= $upx ? '--with-upx-pack ' : '';
|
||||
$build_cmd .= $final_libs === '' ? '' : ('--with-libs=' . quote2($final_libs) . ' ');
|
||||
$build_cmd .= '--build-cli --build-micro ';
|
||||
$build_cmd .= str_starts_with($argv[2], 'windows-') ? '' : '--build-fpm ';
|
||||
$build_cmd .= '--debug ';
|
||||
}
|
||||
@@ -139,6 +139,7 @@ echo match ($argv[1]) {
|
||||
'prefer_pre_built' => $prefer_pre_built ? '--prefer-pre-built' : '',
|
||||
'download_cmd' => $down_cmd,
|
||||
'build_cmd' => $build_cmd,
|
||||
'build_embed_cmd' => $build_cmd,
|
||||
default => '',
|
||||
};
|
||||
|
||||
@@ -150,9 +151,16 @@ if ($argv[1] === 'download_cmd') {
|
||||
}
|
||||
} elseif ($argv[1] === 'build_cmd') {
|
||||
if (str_starts_with($argv[2], 'windows-')) {
|
||||
passthru('powershell.exe -file .\bin\spc.ps1 ' . $build_cmd, $retcode);
|
||||
passthru('powershell.exe -file .\bin\spc.ps1 ' . $build_cmd . ' --build-cli --build-micro', $retcode);
|
||||
} else {
|
||||
passthru('./bin/spc ' . $build_cmd, $retcode);
|
||||
passthru('./bin/spc ' . $build_cmd . ' --build-cli --build-micro', $retcode);
|
||||
}
|
||||
} elseif ($argv[1] === 'build_embed_cmd') {
|
||||
if (str_starts_with($argv[2], 'windows-')) {
|
||||
// windows does not accept embed SAPI
|
||||
passthru('powershell.exe -file .\bin\spc.ps1 ' . $build_cmd . ' --build-cli', $retcode);
|
||||
} else {
|
||||
passthru('./bin/spc ' . $build_cmd . ' --build-embed', $retcode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user