Compare commits

...

35 Commits

Author SHA1 Message Date
Jerry Ma
be8eb90b86 cs fix (#166) 2023-09-08 22:12:59 +08:00
Jerry Ma
54e98666e7 Update ConsoleApplication.php 2023-09-08 22:03:40 +08:00
Joseph Bielawski
e8b277ad0d Prevent unknown extension call 2023-09-07 19:05:00 +08:00
Joseph Bielawski
3bd037f48f Rework style of dev command showing extensions details 2023-09-07 19:05:00 +08:00
Joseph Bielawski
4d0e825b43 Adjust dependencies in composer.json file
Removed unsupported Symfony versions
Bump minimal version of dev dependencies to the latest supported
2023-09-06 21:29:04 +08:00
Jerry Ma
b14179a8de Update README-en.md 2023-09-06 16:26:51 +08:00
Jerry Ma
01111c51ee Update README.md 2023-09-06 16:26:22 +08:00
Jerry Ma
e7230d9f50 Update README-en.md 2023-09-06 16:13:43 +08:00
Jerry Ma
c22c5617ad Update README.md 2023-09-06 16:05:38 +08:00
Joseph Bielawski
cae7bb1dda Add GH Action for tests 2023-09-06 15:47:10 +08:00
Joseph Bielawski
c0830a9e1f Allow setting suffix for licence name 2023-09-06 09:53:45 +08:00
Joseph Bielawski
33798ff108 Add simple unit test 2023-09-06 01:00:24 +08:00
Joseph Bielawski
8d348b9e14 Allow setting multiple license in extensions, libraries & sources 2023-09-06 01:00:24 +08:00
Joseph Bielawski
3d2f6e4c3a Sort lib definition 2023-09-04 23:12:13 +08:00
Joseph Bielawski
88e9639482 Fix operator precedence 2023-09-04 23:12:13 +08:00
Joseph Bielawski
0381a1c412 Adjust extension definition after review 2023-09-04 23:12:13 +08:00
Joseph Bielawski
fdc3a7a04b Add snappy extension 2023-09-04 23:12:13 +08:00
crazywhalecc
6de5c1dab0 Remove unused source libressl 2023-08-31 20:27:46 +08:00
Kévin Dunglas
dc28ce0899 fix: curl dependency on openssl 2023-08-31 20:05:37 +08:00
Kévin Dunglas
9286153742 fix: linxml build on macOS 2023-08-29 14:28:12 +08:00
crazywhalecc
f90892c92f fix curl in musl-gcc bug, fix #88 2023-08-27 03:24:32 +08:00
crazywhalecc
5359f3a79a fix webp compile to cmake, fix #95 2023-08-27 03:08:12 +08:00
crazywhalecc
42fbf18bba update license 2023-08-27 00:25:51 +08:00
crazywhalecc
ed227ce00e fix linux libxml2 #75 issue 2023-08-27 00:25:51 +08:00
crazywhalecc
6c49d35aec add libxslt compile command 2023-08-27 00:25:51 +08:00
crazywhalecc
238fd7fc74 add libxslt source 2023-08-27 00:25:51 +08:00
Kévin Dunglas
1ebc58664e ci: remove useless step and dump Compose autoloader 2023-08-26 17:58:34 +08:00
Kévin Dunglas
bcf64cbeef fix: throw if the PHP version doesn't exist 2023-08-26 13:58:09 +08:00
Kévin Dunglas
dc12d4d982 fix: ExceptionHandler:: must not be accessed before initialization 2023-08-26 13:57:43 +08:00
Kévin Dunglas
42e5877a7f fix: check of xz 2023-08-26 13:57:18 +08:00
Kévin Dunglas
a8924ac4fe fix: setup-runtime portability 2023-08-26 13:53:52 +08:00
Jerry Ma
7fb27c0c29 fix reference error 2023-08-23 10:42:53 +08:00
Kévin Dunglas
3d9a3194b2 hide warning 2023-08-22 23:37:34 +08:00
Kévin Dunglas
e7e0ac006f more optims 2023-08-22 23:37:34 +08:00
Kévin Dunglas
cf35a270bb minor: read Dockerfile from stdin 2023-08-22 23:37:34 +08:00
42 changed files with 606 additions and 217 deletions

View File

@@ -40,11 +40,6 @@ jobs:
steps:
- uses: actions/checkout@v3
# Install Ubuntu missing packages and mark os suffix
- run: |
sudo apt install musl-tools -y
echo "SPC_BUILD_OS=linux" >> $GITHUB_ENV
# Cache composer dependencies
- id: cache-composer-deps
uses: actions/cache@v3
@@ -54,7 +49,7 @@ jobs:
# If there's no Composer cache, install dependencies
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
run: composer update --no-dev
run: composer update --no-dev --classmap-authoritative
# Cache downloaded source
- id: cache-download

View File

@@ -54,7 +54,7 @@ jobs:
# If there's no Composer cache, install dependencies
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
run: composer update --no-dev
run: composer update --no-dev --classmap-authoritative
# Cache downloaded source
- id: cache-download

98
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,98 @@
name: Tests
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
php-cs-fixer:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
extensions: curl, openssl, mbstring
ini-values: memory_limit=-1
tools: pecl, composer, php-cs-fixer
- name: Run PHP-CS-Fixer fix
run: php-cs-fixer fix --dry-run --diff --ansi
phpstan:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
extensions: curl, openssl, mbstring
ini-values: memory_limit=-1
tools: composer
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-phpstan-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-phpstan-
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Run phpstan
run: vendor/bin/phpstan analyse
phpunit:
name: PHPUnit (PHP ${{ matrix.php }})
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
include:
- php: '8.1'
- php: '8.2'
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php }}"
tools: pecl, composer
extensions: curl, openssl, mbstring
ini-values: memory_limit=-1
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Run PHPUnit tests
run: |
vendor/bin/phpunit tests/ --no-coverage

6
.gitignore vendored
View File

@@ -17,11 +17,15 @@ composer.lock
# default source build root directory
/buildroot/
# php cs fixer cache file
# tools cache files
.php-cs-fixer.cache
.phpunit.result.cache
# exclude self-runtime
/bin/*
!/bin/spc
!/bin/setup-runtime
!/bin/spc-alpine-docker
# default test directory
/tests/var/

View File

@@ -65,5 +65,5 @@ return (new PhpCsFixer\Config())
'phpdoc_var_without_name' => false,
])
->setFinder(
PhpCsFixer\Finder::create()->in(__DIR__ . '/src')
PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests/SPC'])
);

View File

@@ -1,15 +1,17 @@
# static-php-cli
Compile A Statically Linked PHP With Swoole and other Extensions.
Build single static PHP binary, with PHP project together, with popular extensions included.
The project name is static-php-cli, but it actually supports cli, fpm, micro and embed (on the way) SAPI 😎
Compile a purely static php-cli binary file with various extensions to make PHP applications more portable! (cli SAPI)
<img width="600" alt="截屏2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png">
<img width="600" alt="2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png">
You can also use the micro binary file to combine php binary and php source code into one for distribution!
This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro). (micro SAPI)
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
<img width="600" alt="2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
[![Version](https://img.shields.io/badge/Version-2.0--rc5-pink.svg?style=flat-square)]()
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]()
@@ -19,8 +21,6 @@ This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro
[![](https://img.shields.io/badge/Extension%20Counter-55+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]()
> The project has renamed the `refactor` branch to the `main` branch, please pay attention to changing the branch name for dependent projects.
## Compilation Requirements
Yes, this project is written in PHP, pretty funny.
@@ -194,18 +194,6 @@ Because php-fpm must specify a configuration file before running, the php-fpm co
Specifying `php-fpm.conf` can use the command parameter `-y`, for example: `./php-fpm -y php-fpm.conf`.
## Current Status
- [X] Basic CLI framework (by `symfony/console`)
- [X] Linux support
- [X] macOS support
- [X] Exception handler
- [ ] Windows support
- [X] PHP 7.4 support
- [X] fpm support
More functions and features are coming soon, Bugs and TODOs: https://github.com/crazywhalecc/static-php-cli/issues/32
## Contribution
Currently, there are only a few supported extensions.
@@ -236,8 +224,9 @@ You can sponsor my project on [this page](https://github.com/crazywhalecc/crazyw
## Open-Source License
This project is based on the tradition of using the MIT License for old versions,
while the new version references source code from some other projects:
This project itself is based on MIT License,
some newly added extensions and dependencies may originate from the following projects (including but not limited to),
and the headers of these code files will also be given additional instructions LICENSE and AUTHOR:
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs) (Mulun Permissive License)
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli) (Apache 2.0 LICENSE+SWOOLE-CLI LICENSE)
@@ -253,4 +242,4 @@ and comply with the corresponding project's LICENSE.
The refactoring branch of this project is written modularly.
If you are interested in this project and want to join the development,
you can refer to the [Contribution Guide](https://static-php-cli.zhamao.me) of the documentation to contribute code or documentation. (TODO)
you can refer to the [Contribution Guide](https://static-php-cli.zhamao.me) of the documentation to contribute code or documentation.

View File

@@ -1,6 +1,6 @@
# static-php-cli
Compile A Statically Linked PHP With Swoole and other Extensions.
Build single static PHP binary, with PHP project together, with popular extensions included.
**If you are using English, see [English README](README-en.md).**
@@ -19,7 +19,7 @@ Compile A Statically Linked PHP With Swoole and other Extensions.
[![](https://img.shields.io/badge/Extension%20Counter-55+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]()
> 项目已重命名 `refactor` 分支为 `main` 分支,请依赖的项目注意更改分支名称。
> 项目名称是 static-php-cli但其实支持 cli、fpm、micro 和 embed正在路上SAPI 😎
## 编译环境需求
@@ -181,18 +181,6 @@ cat micro.sfx code.php > single-app && chmod +x single-app
指定 `php-fpm.conf` 可以使用命令参数 `-y`,例如:`./php-fpm -y php-fpm.conf`
## 项目支持情况
- [X] 基础结构编写(采用 `symfony/console`
- [X] 错误处理
- [X] macOS 支持
- [ ] Windows 支持
- [X] Linux 支持
- [X] PHP 7.4 支持
- [X] fpm 支持
更多功能和特性正在陆续支持中详见https://github.com/crazywhalecc/static-php-cli/issues/32
## 贡献
目前支持的扩展较少,如果缺少你需要的扩展,可发起 Issue。如果你对本项目较熟悉也欢迎为本项目发起 Pull Request。
@@ -224,4 +212,4 @@ cat micro.sfx code.php > single-app && chmod +x single-app
## 进阶
本项目重构分支为模块化编写。如果你对本项目感兴趣,想加入开发,可以参照文档的 [贡献指南](https://static-php-cli.zhamao.me) 贡献代码或文档。TODO
本项目重构分支为模块化编写。如果你对本项目感兴趣,想加入开发,可以参照文档的 [贡献指南](https://static-php-cli.zhamao.me) 贡献代码或文档。

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
# set error-quit, verbose, non-variable-quit
set -eu
@@ -52,6 +52,10 @@ china)
esac
if ! command -v curl > /dev/null && command -v apk > /dev/null; then
apk add --no-cache curl
fi
test -d "${__PROJECT__}"/downloads || mkdir "${__PROJECT__}"/downloads
# download static php binary
test -f "${__PROJECT__}"/downloads/runtime.tar.gz || { echo "Downloading $__PHP_RUNTIME_URL__ ..." && curl -#fSL -o "${__PROJECT__}"/downloads/runtime.tar.gz "$__PHP_RUNTIME_URL__" ; }

View File

@@ -52,24 +52,47 @@ fi
# Detect docker env is setup
if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH; then
echo "Docker container does not exist. Building docker image ..."
ALPINE_DOCKERFILE=$(cat << EOF
$DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH -f- . <<EOF
FROM $ALPINE_FROM
$SPC_USE_MIRROR
RUN apk update
RUN apk add bash file wget cmake gcc g++ jq autoconf git libstdc++ linux-headers make m4 libgcc binutils bison flex pkgconfig automake curl
RUN apk add build-base xz php81 php81-common php81-pcntl php81-tokenizer php81-phar php81-posix php81-xml composer
RUN mkdir /app
RUN apk update; \
apk add --no-cache \
autoconf \
automake \
bash \
binutils \
bison \
build-base \
cmake \
composer \
curl \
file \
flex \
g++ \
gcc \
git \
jq \
libgcc \
libstdc++ \
linux-headers \
m4 \
make \
php81 \
php81-common \
php81-pcntl \
php81-phar \
php81-posix \
php81-tokenizer \
php81-xml \
pkgconfig \
wget \
xz
WORKDIR /app
ADD ./src /app/src
ADD ./composer.json /app/composer.json
ADD ./bin /app/bin
RUN composer update --no-dev
RUN composer update --no-dev --classmap-authoritative
EOF
)
echo "$ALPINE_DOCKERFILE" > "$(pwd)"/Dockerfile
$DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH .
rm "$(pwd)"/Dockerfile
fi
# Check if in ci (local terminal can execute with -it)
@@ -81,4 +104,4 @@ fi
# Run docker
# shellcheck disable=SC2068
$DOCKER_EXECUTABLE run --rm "$INTERACT" -e SPC_FIX_DEPLOY_ROOT="$(pwd)" -v "$(pwd)"/config:/app/config -v "$(pwd)"/src:/app/src -v "$(pwd)"/buildroot:/app/buildroot -v "$(pwd)"/source:/app/source -v "$(pwd)"/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" -v "$(pwd)"/config:/app/config -v "$(pwd)"/src:/app/src -v "$(pwd)"/buildroot:/app/buildroot -v "$(pwd)"/source:/app/source -v "$(pwd)"/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@

View File

@@ -13,15 +13,16 @@
"ext-mbstring": "*",
"ext-pcntl": "*",
"laravel/prompts": "^0.1.3",
"symfony/console": "^6 || ^5 || ^4",
"symfony/console": "^5.4 || ^6 || ^7",
"zhamao/logger": "^1.0"
},
"require-dev": {
"nunomaduro/collision": "*",
"friendsofphp/php-cs-fixer": "^3.2 != 3.7.0",
"phpstan/phpstan": "^1.1",
"captainhook/captainhook": "^5.10",
"captainhook/plugin-composer": "^5.3"
"captainhook/plugin-composer": "^5.3",
"friendsofphp/php-cs-fixer": "^3.25",
"nunomaduro/collision": "^7.8",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.3"
},
"autoload": {
"psr-4": {
@@ -32,13 +33,18 @@
"src/globals/functions.php"
]
},
"autoload-dev": {
"psr-4": {
"SPC\\Tests\\": "tests/SPC"
}
},
"bin": [
"bin/spc"
],
"scripts": {
"analyse": "phpstan analyse --memory-limit 300M",
"cs-fix": "php-cs-fixer fix",
"test": "bin/phpunit --no-coverage"
"test": "vendor/bin/phpunit tests/ --no-coverage"
},
"config": {
"allow-plugins": {

View File

@@ -325,6 +325,18 @@
"libxml2"
]
},
"snappy": {
"type": "external",
"source": "ext-snappy",
"cpp-extension": true,
"arg-type": "custom",
"lib-depends": [
"snappy"
],
"ext-suggest": [
"apcu"
]
},
"snmp": {
"type": "builtin",
"arg-type": "with",
@@ -449,9 +461,13 @@
},
"xsl": {
"type": "builtin",
"arg-type": "with",
"arg-type": "with-prefix",
"lib-depends": [
"libxslt"
],
"ext-depends": [
"xml",
"dom"
]
},
"yaml": {
@@ -486,4 +502,4 @@
"zstd"
]
}
}
}

View File

@@ -42,14 +42,14 @@
"curl"
],
"lib-depends-unix": [
"openssl",
"zlib"
],
"lib-suggests": [
"libssh2",
"brotli",
"nghttp2",
"zstd",
"openssl"
"zstd"
],
"lib-suggests-windows": [
"zlib",
@@ -279,20 +279,29 @@
"libxml2"
],
"lib-depends": [
"libiconv"
"libiconv",
"zlib"
],
"lib-suggests": [
"xz",
"zlib",
"icu"
],
"lib-suggests-windows": [
"icu",
"xz",
"zlib",
"pthreads4w"
]
},
"libxslt": {
"source": "libxslt",
"static-libs-unix": [
"libxslt.a",
"libexslt.a"
],
"lib-depends": [
"libxml2"
]
},
"libyaml": {
"source": "libyaml",
"static-libs-unix": [
@@ -436,6 +445,22 @@
"ncurses"
]
},
"snappy": {
"source": "snappy",
"static-libs-unix": [
"libsnappy.a"
],
"headers-unix": [
"snappy-c.h",
"snappy-sinksource.h",
"snappy.h",
"snappy-stubs-internal.h",
"snappy-stubs-public.h"
],
"lib-depends": [
"zlib"
]
},
"sqlite": {
"source": "sqlite",
"static-libs-unix": [
@@ -502,4 +527,4 @@
"zstd_errors.h"
]
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -14,7 +14,7 @@ use Symfony\Component\Console\Command\ListCommand;
*/
class ConsoleApplication extends Application
{
public const VERSION = '2.0.0';
public const VERSION = '2.0-rc6';
/**
* @throws \ReflectionException

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('snappy')]
class snappy extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/-lsnappy/',
$this->getLibFilesString() . ($this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++')
);
return true;
}
public function getUnixConfigureArg(): string
{
return '--enable-snappy --with-snappy-includedir="' . BUILD_ROOT_PATH . '"';
}
}

View File

@@ -19,21 +19,22 @@ class libxml2 extends LinuxLibraryBase
public function build(): void
{
$enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
$enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
// $enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
[, , $destdir] = SEPARATED_PATH;
FileSystem::resetDir($this->source_dir . '/build');
shell()->cd($this->source_dir . '/build')
->exec(
"{$this->builder->configure_env} " . ' cmake ' .
"{$this->builder->makeCmakeArgs()} " .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DCMAKE_INSTALL_PREFIX=' . escapeshellarg(BUILD_ROOT_PATH) . ' ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DCMAKE_INSTALL_BINDIR=' . escapeshellarg(BUILD_ROOT_PATH . '/bin') . ' ' .
'-DLIBXML2_WITH_ICONV=ON ' .
'-DIconv_IS_BUILT_IN=OFF ' .
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
"-DLIBXML2_WITH_ICU={$enable_icu} " .
'-DLIBXML2_WITH_ICU=OFF ' .
"-DLIBXML2_WITH_LZMA={$enable_xz} " .
'-DLIBXML2_WITH_PYTHON=OFF ' .
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
@@ -41,15 +42,6 @@ class libxml2 extends LinuxLibraryBase
'..'
)
->exec("cmake --build . -j {$this->builder->concurrency}")
->exec("make install DESTDIR={$destdir}");
if (is_dir(BUILD_INCLUDE_PATH . '/libxml2/libxml')) {
if (is_dir(BUILD_INCLUDE_PATH . '/libxml')) {
shell()->exec('rm -rf "' . BUILD_INCLUDE_PATH . '/libxml"');
}
$path = FileSystem::convertPath(BUILD_INCLUDE_PATH . '/libxml2/libxml');
$dst_path = FileSystem::convertPath(BUILD_INCLUDE_PATH . '/');
shell()->exec('mv "' . $path . '" "' . $dst_path . '"');
}
->exec('make install');
}
}

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
/**
* gmp is a template library class for unix
*/
class libxslt extends LinuxLibraryBase
{
use \SPC\builder\unix\library\libxslt;
public const NAME = 'libxslt';
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class snappy extends LinuxLibraryBase
{
use \SPC\builder\unix\library\snappy;
public const NAME = 'snappy';
}

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
/**
* gmp is a template library class for unix
*/
class libxslt extends MacOSLibraryBase
{
use \SPC\builder\unix\library\libxslt;
public const NAME = 'libxslt';
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class snappy extends MacOSLibraryBase
{
use \SPC\builder\unix\library\snappy;
public const NAME = 'snappy';
}

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace SPC\builder\traits;
trait LibraryTrait
{
}
trait LibraryTrait {}

View File

@@ -51,6 +51,7 @@ trait curl
FileSystem::resetDir($this->source_dir . '/build');
// compile
shell()->cd($this->source_dir . '/build')
->exec('sed -i.save s@\${CMAKE_C_IMPLICIT_LINK_LIBRARIES}@@ ../CMakeLists.txt')
->exec("{$this->builder->configure_env} cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DBUILD_CURL_EXE=OFF {$extra} ..")
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);

View File

@@ -7,6 +7,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
trait libwebp
{
@@ -17,25 +18,20 @@ trait libwebp
*/
protected function build(): void
{
[,,$destdir] = SEPARATED_PATH;
shell()->cd($this->source_dir)
->exec('./autogen.sh')
// CMake needs a clean build directory
FileSystem::resetDir($this->source_dir . '/build');
// Start build
shell()->cd($this->source_dir . '/build')
->exec(
"{$this->builder->configure_env} ./configure " .
'--enable-static ' .
'--disable-shared ' .
'--prefix= ' .
'--enable-libwebpdecoder ' .
'--enable-libwebpextras ' .
'--disable-tiff ' .
'--disable-gl ' .
'--disable-sdl ' .
'--disable-wic'
"{$this->builder->configure_env} cmake " .
$this->builder->makeCmakeArgs() . ' ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DWEBP_BUILD_EXTRAS=ON ' .
'..'
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . $destdir);
->exec("cmake --build . -j {$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
// patch pkgconfig
$this->patchPkgconfPrefix(['libsharpyuv.pc', 'libwebp.pc', 'libwebpdecoder.pc', 'libwebpdemux.pc', 'libwebpmux.pc'], PKGCONF_PATCH_PREFIX);
$this->cleanLaFiles();
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
trait libxslt
{
/**
* @throws FileSystemException
* @throws RuntimeException
*/
protected function build(): void
{
shell()->cd($this->source_dir)
->exec(
"{$this->builder->configure_env} ./configure " .
'--enable-static --disable-shared ' .
'--without-python ' .
'--without-mem-debug ' .
'--without-crypto ' .
'--without-debug ' .
'--without-debugger ' .
'--with-libxml-prefix=' . escapeshellarg(BUILD_ROOT_PATH) . ' ' .
'--prefix='
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . escapeshellarg(BUILD_ROOT_PATH));
$this->patchPkgconfPrefix(['libexslt.pc']);
}
}

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait snappy
{
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
FileSystem::resetDir($this->source_dir . '/cmake/build');
shell()->cd($this->source_dir . '/cmake/build')
->exec(
"{$this->builder->configure_env} cmake " .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DCMAKE_INSTALL_PREFIX=' . escapeshellarg(BUILD_ROOT_PATH) . ' ' .
'-DSNAPPY_BUILD_TESTS=OFF ' .
'-DSNAPPY_BUILD_BENCHMARKS=OFF ' .
'../..'
)
->exec("cmake --build . -j {$this->builder->concurrency}")
->exec('make install');
}
}

View File

@@ -6,15 +6,19 @@ namespace SPC\command\dev;
use SPC\command\BaseCommand;
use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\util\DependencyUtil;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand('dev:ext-all', 'Dev command', ['list-ext'])]
#[AsCommand('dev:extensions', 'Helper command that lists available extension details', ['list-ext'])]
class AllExtCommand extends BaseCommand
{
public function configure(): void
{
$this->addOption('line', 'l', null, 'Show with separate lines');
$this->addArgument('extensions', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Extension name', null);
}
/**
@@ -22,7 +26,45 @@ class AllExtCommand extends BaseCommand
*/
public function handle(): int
{
$this->output->writeln(implode($this->input->getOption('line') ? PHP_EOL : ',', array_keys(Config::getExts())));
$extensions = $this->input->getArgument('extensions') ?: [];
$style = new SymfonyStyle($this->input, $this->output);
$style->writeln($extensions ? 'Available extensions:' : 'Extensions:');
$data = [];
foreach (Config::getExts() as $extension => $details) {
if ($extensions !== [] && !\in_array($extension, $extensions, true)) {
continue;
}
try {
[, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]);
} catch (WrongUsageException) {
$libraries = $not_included = [];
}
$lib_suggests = Config::getExt($extension, 'lib-suggests', []);
$ext_suggests = Config::getExt($extension, 'ext-suggests', []);
$data[] = [
$extension,
implode(', ', $libraries),
implode(', ', $lib_suggests),
implode(',', $not_included),
implode(', ', $ext_suggests),
Config::getExt($extension, 'unix-only', false) ? 'true' : 'false',
];
}
if ($data === []) {
$style->warning('Unknown extension selected: ' . implode(',', $extensions));
} else {
$style->table(
['Extension', 'lib-depends', 'lib-suggests', 'ext-depends', 'ext-suggests', 'unix-only'],
$data
);
}
return static::SUCCESS;
}
}

View File

@@ -1,50 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\command\dev;
use SPC\command\BaseCommand;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\util\DependencyUtil;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
#[AsCommand('dev:ext-info', 'Dev command')]
class ExtInfoCommand extends BaseCommand
{
public function configure(): void
{
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extension name you need to get info');
}
/**
* @throws WrongUsageException
* @throws FileSystemException
* @throws RuntimeException
*/
public function handle(): int
{
$extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions'))));
// 根据提供的扩展列表获取依赖库列表并编译
foreach ($extensions as $extension) {
$this->output->writeln('<comment>[ ' . $extension . ' ]</comment>');
[, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]);
$lib_suggests = Config::getExt($extension, 'lib-suggests', []);
$ext_suggests = Config::getExt($extension, 'ext-suggests', []);
$this->output->writeln("<info>lib-depends:\t" . implode(', ', $libraries) . '</info>');
$this->output->writeln("<info>lib-suggests:\t" . implode(', ', $lib_suggests) . '</info>');
$this->output->writeln("<info>ext-depends:\t" . implode(',', $not_included) . '</info>');
$this->output->writeln("<info>ext-suggests:\t" . implode(', ', $ext_suggests) . '</info>');
if (Config::getExt($extension, 'unix-only', false)) {
$this->output->writeln("<info>Unix only:\ttrue</info>");
}
$this->output->writeln('');
}
return static::SUCCESS;
}
}

View File

@@ -14,6 +14,5 @@ class AsCheckItem
public ?string $limit_os = null,
public int $level = 100,
public bool $manual = false,
) {
}
) {}
}

View File

@@ -7,7 +7,5 @@ namespace SPC\doctor;
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class AsFixItem
{
public function __construct(public string $name)
{
}
public function __construct(public string $name) {}
}

View File

@@ -6,9 +6,7 @@ namespace SPC\doctor;
class CheckResult
{
public function __construct(private readonly bool $ok, private readonly ?string $message = null, private string $fix_item = '', private array $fix_params = [])
{
}
public function __construct(private readonly bool $ok, private readonly ?string $message = null, private string $fix_item = '', private array $fix_params = []) {}
public static function fail(string $message, string $fix_item = '', array $fix_params = []): CheckResult
{

View File

@@ -28,6 +28,7 @@ class LinuxToolCheckList
'git', 'autoconf', 'automake',
'tar', 'unzip', 'gzip',
'bzip2', 'cmake', 'patch',
'xz',
];
/** @noinspection PhpUnused */
@@ -87,7 +88,7 @@ class LinuxToolCheckList
logger()->warning('Current user is not root, using sudo for running command');
}
try {
shell(true)->exec($prefix . $install_cmd . ' ' . implode(' ', $missing));
shell(true)->exec($prefix . $install_cmd . ' ' . implode(' ', str_replace('xz', 'xz-utils', $missing)));
} catch (RuntimeException) {
return false;
}

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace SPC\exception;
class DownloaderException extends \Exception
{
}
class DownloaderException extends \Exception {}

View File

@@ -6,7 +6,7 @@ namespace SPC\exception;
class ExceptionHandler
{
protected mixed $whoops;
protected mixed $whoops = null;
private static ?ExceptionHandler $obj = null;

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace SPC\exception;
class FileSystemException extends \Exception
{
}
class FileSystemException extends \Exception {}

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace SPC\exception;
class InvalidArgumentException extends \Exception
{
}
class InvalidArgumentException extends \Exception {}

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace SPC\exception;
class RuntimeException extends \Exception
{
}
class RuntimeException extends \Exception {}

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace SPC\exception;
class ValidationException extends \Exception
{
}
class ValidationException extends \Exception {}

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace SPC\exception;
class WrongUsageException extends \Exception
{
}
class WrongUsageException extends \Exception {}

View File

@@ -35,6 +35,10 @@ class PhpSource extends CustomSourceBase
{
// 查找最新的小版本号
$info = json_decode(Downloader::curlExec(url: "https://www.php.net/releases/index.php?json&version={$major_version}"), true);
if (!isset($info['version'])) {
throw new DownloaderException("Version {$major_version} not found.");
}
$version = $info['version'];
// 从官网直接下载

View File

@@ -13,9 +13,7 @@ class CustomExt
{
private static array $custom_ext_class = [];
public function __construct(protected string $ext_name)
{
}
public function __construct(protected string $ext_name) {}
/**
* Load all custom extension classes

View File

@@ -45,46 +45,58 @@ class LicenseDumper
{
// mkdir first
if (is_dir($target_dir) && !FileSystem::removeDir($target_dir)) {
logger()->warning('Target dump directory is noe empty, be aware!');
logger()->warning('Target dump directory is not empty, be aware!');
}
FileSystem::createDir($target_dir);
foreach ($this->exts as $ext) {
if (Config::getExt($ext, 'type') !== 'external') {
continue;
}
$source_name = Config::getExt($ext, 'source');
$content = $this->getSourceLicense($source_name);
file_put_contents($target_dir . '/ext_' . $ext . '.txt', $content);
foreach ($this->getSourceLicenses($source_name) as $index => $license) {
file_put_contents("{$target_dir}/ext_{$ext}_{$index}.txt", $license);
}
}
foreach ($this->libs as $lib) {
$source_name = Config::getLib($lib, 'source');
$content = $this->getSourceLicense($source_name);
file_put_contents($target_dir . '/lib_' . $lib . '.txt', $content);
foreach ($this->getSourceLicenses($source_name) as $index => $license) {
file_put_contents("{$target_dir}/lib_{$lib}_{$index}.txt", $license);
}
}
foreach ($this->sources as $source) {
file_put_contents($target_dir . '/src_' . $source . '.txt', $this->getSourceLicense($source));
foreach ($this->getSourceLicenses($source) as $index => $license) {
file_put_contents("{$target_dir}/src_{$source}_{$index}.txt", $license);
}
}
return true;
}
/**
* @return string[]
* @throws FileSystemException
* @throws RuntimeException
*/
private function getSourceLicense(string $source_name): ?string
private function getSourceLicenses(string $source_name): iterable
{
$src = Config::getSource($source_name)['license'] ?? null;
if ($src === null) {
throw new RuntimeException('source [' . $source_name . '] license meta is not exist');
$licenses = Config::getSource($source_name)['license'] ?? [];
if ($licenses === []) {
throw new RuntimeException('source [' . $source_name . '] license meta not exist');
}
return match ($src['type']) {
'text' => $src['text'],
'file' => $this->loadSourceFile($source_name, $src['path'], Config::getSource($source_name)['path'] ?? null),
default => throw new RuntimeException('source [' . $source_name . '] license type is not allowed'),
};
if (!array_is_list($licenses)) {
$licenses = [$licenses];
}
foreach ($licenses as $index => $license) {
yield ($license['suffix'] ?? $index) => match ($license['type']) {
'text' => $license['text'],
'file' => $this->loadSourceFile($source_name, $license['path'], Config::getSource($source_name)['path'] ?? null),
default => throw new RuntimeException('source [' . $source_name . '] license type is not allowed'),
};
}
}
/**
@@ -93,8 +105,9 @@ class LicenseDumper
private function loadSourceFile(string $source_name, string $in_path, ?string $custom_base_path = null): string
{
if (!file_exists(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path)) {
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] is not exist');
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] not exist');
}
return file_get_contents(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path);
}
}

View File

@@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace SPC\Tests\util;
use PHPUnit\Framework\TestCase;
use SPC\store\Config;
use SPC\util\LicenseDumper;
/**
* @internal
*/
final class LicenseDumperTest extends TestCase
{
private const DIRECTORY = '../../var/license-dump';
protected function setUp(): void
{
@rmdir(self::DIRECTORY);
}
protected function tearDown(): void
{
array_map('unlink', glob(self::DIRECTORY . '/*.txt'));
}
public function testDumpWithSingleLicense(): void
{
Config::$lib = [
'fake_lib' => [
'source' => 'fake_lib',
],
];
Config::$source = [
'fake_lib' => [
'license' => [
'type' => 'text',
'text' => 'license',
'suffix' => 'zend',
],
],
];
$dumper = new LicenseDumper();
$dumper->addLibs(['fake_lib']);
$dumper->dump(self::DIRECTORY);
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt');
}
public function testDumpWithMultipleLicenses(): void
{
Config::$lib = [
'fake_lib' => [
'source' => 'fake_lib',
],
];
Config::$source = [
'fake_lib' => [
'license' => [
[
'type' => 'text',
'text' => 'license',
],
[
'type' => 'text',
'text' => 'license',
],
[
'type' => 'text',
'text' => 'license',
'suffix' => 'zend',
],
],
],
];
$dumper = new LicenseDumper();
$dumper->addLibs(['fake_lib']);
$dumper->dump(self::DIRECTORY);
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_1.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt');
}
}