From 3945ac037baa9cb92a005be87b1e91bf044a1636 Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Thu, 22 Feb 2024 14:37:10 +0800 Subject: [PATCH] Add curl and ssh2 support for windows (#348) * add curl and ssh2 support for windows * add curl and ssh2 test for windows * cs fix * update README [skip ci] * update README [skip ci] * update README [skip ci] * update README [skip ci] * update README [skip ci] --- README-zh.md | 46 ++++++++++++---- README.md | 53 ++++++++++++++----- config/ext.json | 9 ++++ config/lib.json | 14 ++--- .../windows/library/WindowsLibraryBase.php | 32 +++++++++++ src/SPC/builder/windows/library/curl.php | 39 ++++++++++++++ src/SPC/builder/windows/library/libssh2.php | 38 +++++++++++++ src/SPC/builder/windows/library/nghttp2.php | 37 +++++++++++++ src/SPC/store/FileSystem.php | 6 ++- src/globals/test-extensions.php | 2 +- 10 files changed, 244 insertions(+), 32 deletions(-) create mode 100644 src/SPC/builder/windows/library/curl.php create mode 100644 src/SPC/builder/windows/library/libssh2.php create mode 100644 src/SPC/builder/windows/library/nghttp2.php diff --git a/README-zh.md b/README-zh.md index f9017749..586bca67 100755 --- a/README-zh.md +++ b/README-zh.md @@ -20,7 +20,7 @@ static-php-cli(简称 `spc`)有许多特性: - :handbag: 构建独立的单文件 PHP 解释器,无需任何依赖 - :hamburger: 构建 **[phpmicro](https://github.com/dixyes/phpmicro)** 自执行二进制(将 PHP 代码和 PHP 解释器打包为一个文件) - :pill: 提供一键检查和修复编译环境的 Doctor 模块 -- :zap: 支持多个系统:`Linux`、`macOS`、`FreeBSD`、[`Windows (WIP)`](https://github.com/crazywhalecc/static-php-cli/pull/301) +- :zap: 支持多个系统:`Linux`、`macOS`、`FreeBSD`、`Windows` - :wrench: 高度自定义的代码 patch 功能 - :books: 自带编译依赖管理 - 📦 提供由自身编译的独立 `spc` 二进制(使用 spc 和 [box](https://github.com/box-project/box) 构建) @@ -47,16 +47,18 @@ static-php-cli(简称 `spc`)有许多特性: - [扩展组合 - bulk](https://dl.static-php.dev/static-php-cli/bulk/):bulk 组合包含了 [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) 个扩展,体积为 70MB 左右。 - [扩展组合 - minimal](https://dl.static-php.dev/static-php-cli/minimal/):minimal 组合包含了 [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) 个扩展,体积为 6MB 左右。 +对于 Windows 系统,目前支持的扩展较少,故仅提供 SPC 自身运行的最小扩展组合的 `cli` 和 `micro`:[扩展组合 - spc-min](https://dl.static-php.dev/static-php-cli/windows/spc-min/)。 + ## 使用 static-php-cli 构建 PHP ### 编译环境需求 - PHP >= 8.1(这是 spc 自身需要的版本,不是支持的构建版本) -- 扩展:`mbstring,pcntl,posix,tokenizer,phar` +- 扩展:`mbstring,tokenizer,phar` - 系统安装了 `curl` 和 `git` 是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。 -但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 mbstring、pcntl 扩展和 PHP 版本大于等于 8.1 即可。 +但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含上面提到的扩展和 PHP 版本大于等于 8.1 即可。 下面是架构支持情况,:octocat: 代表支持 GitHub Action 构建,:computer: 代表支持本地构建,空 代表暂不支持。 @@ -64,10 +66,26 @@ static-php-cli(简称 `spc`)有许多特性: |---------|----------------------|----------------------| | macOS | :octocat: :computer: | :octocat: :computer: | | Linux | :octocat: :computer: | :octocat: :computer: | -| Windows | | | +| Windows | :computer: | | | FreeBSD | :computer: | :computer: | -目前支持编译的 PHP 版本为:`7.3`,`7.4`,`8.0`,`8.1`,`8.2`,`8.3`。 +当前支持编译的 PHP 版本: + +> :warning: 支持,但可能不再提供修复 +> +> :heavy_check_mark: 支持 +> +> :x: 不支持 + +| PHP Version | Status | Comment | +|-------------|--------------------|------------------------------| +| 7.2 | :x: | | +| 7.3 | :warning: | phpmicro 和许多扩展不支持 7.3、7.4 版本 | +| 7.4 | :warning: | phpmicro 和许多扩展不支持 7.3、7.4 版本 | +| 8.0 | :heavy_check_mark: | PHP 官方已停止 8.0 的维护 | +| 8.1 | :heavy_check_mark: | | +| 8.2 | :heavy_check_mark: | | +| 8.3 | :heavy_check_mark: | | ### 支持的扩展 @@ -107,10 +125,16 @@ curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-a curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-x86_64 # macOS aarch64 (Apple) curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-aarch64 +# Windows (x86_64, win10 build 17063 or later) +curl.exe -o spc.exe https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-windows-x64.exe -# add x perm +# Add execute perm (Linux and macOS only) chmod +x ./spc + +# Run (Linux and macOS) ./spc --version +# Run (Windows powershell) +.\spc.exe --version ``` 自托管 `spc` 由 GitHub Actions 构建,你也可以从 Actions 直接下载:[此处](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml)。 @@ -149,14 +173,16 @@ bin/spc --version # 拉取所有依赖库 ./bin/spc download --all # 只拉取编译指定扩展需要的所有依赖(推荐) -./bin/spc download --for-extensions=openssl,pcntl,mbstring,pdo_sqlite +./bin/spc download --for-extensions="openssl,pcntl,mbstring,pdo_sqlite" # 下载编译不同版本的 PHP (--with-php=x.y,推荐 7.3 ~ 8.3) -./bin/spc download --for-extensions=openssl,curl,mbstring --with-php=8.1 +./bin/spc download --for-extensions="openssl,curl,mbstring" --with-php=8.1 # 构建包含 bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl 扩展的 php-cli 和 micro.sfx ./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro # 编译线程安全版本 (--enable-zts) -./bin/spc build curl,phar --enable-zts --build-cli +./bin/spc build "curl,phar" --enable-zts --build-cli +# 编译后使用 UPX 减小可执行文件体积 (--with-upx-pack) (至少压缩至原来的 30~50%) +./bin/spc build "curl,phar" --enable-zts --build-cli --with-upx-pack ``` 其中,目前支持构建 cli,micro,fpm 和 embed,使用以下参数的一个或多个来指定编译的 SAPI: @@ -170,7 +196,7 @@ bin/spc --version 如果出现了任何错误,可以使用 `--debug` 参数来展示完整的输出日志,以供排查错误: ```bash -./bin/spc build openssl,pcntl,mbstring --debug --build-all +./bin/spc build "openssl,pcntl,mbstring" --debug --build-all ./bin/spc download --all --debug ``` diff --git a/README.md b/README.md index 504d900f..4f42756d 100755 --- a/README.md +++ b/README.md @@ -53,16 +53,19 @@ which can be downloaded directly according to your needs. - [Extension-Combination - bulk](https://dl.static-php.dev/static-php-cli/bulk/): `bulk` contains [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) extensions and is about 70MB in size. - [Extension-Combination - minimal](https://dl.static-php.dev/static-php-cli/minimal/): `minimal` contains [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) extensions and is about 6MB in size. +For Windows systems, there are currently fewer extensions supported, +so only `cli` and `micro` that run the minimum extension combination of SPC itself are provided: [Extension-Combination - spc-min](https://dl.static-php.dev/static-php-cli/windows/spc-min/). + ## Build ### Compilation Requirements -- PHP >= 8.1 (This is the version required by spc itself, not the build version) -- Extension: `mbstring,pcntl,posix,tokenizer,phar` -- Supported OS with `curl` and `git` installed - You can say I made a PHP builder written in PHP, pretty funny. -But static-php-cli runtime only requires an environment above PHP 8.1 and `mbstring`, `pcntl` extension. +But static-php-cli runtime only requires an environment above PHP 8.1 and extensions mentioned below. + +- PHP >= 8.1 (This is the version required by spc itself, not the build version) +- Extension: `mbstring,tokenizer,phar` +- Supported OS with `curl` and `git` installed Here is the supported OS and arch, where :octocat: represents support for GitHub Action builds, :computer: represents support for local manual builds, and blank represents not currently supported. @@ -74,7 +77,23 @@ Here is the supported OS and arch, where :octocat: represents support for GitHub | Windows | :computer: | | | FreeBSD | :computer: | :computer: | -Currently supported PHP versions for compilation are: `7.3`, `7.4`, `8.0`, `8.1`, `8.2`, `8.3`. +Currently supported PHP versions for compilation: + +> :warning: supported but not maintained +> +> :heavy_check_mark: supported +> +> :x: not supported + +| PHP Version | Status | Comment | +|-------------|--------------------|---------------------------------------------------| +| 7.2 | :x: | | +| 7.3 | :warning: | phpmicro and some extensions not supported on 7.x | +| 7.4 | :warning: | phpmicro and some extensions not supported on 7.x | +| 8.0 | :heavy_check_mark: | PHP official has stopped maintenance of 8.0 | +| 8.1 | :heavy_check_mark: | | +| 8.2 | :heavy_check_mark: | | +| 8.3 | :heavy_check_mark: | | ### Supported Extensions @@ -117,10 +136,16 @@ curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-a curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-x86_64 # macOS aarch64 (Apple) curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-aarch64 +# Windows (x86_64, win10 build 17063 or later) +curl.exe -o spc.exe https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-windows-x64.exe -# add x perm +# Add execute perm (Linux and macOS only) chmod +x ./spc + +# Run (Linux and macOS) ./spc --version +# Run (Windows powershell) +.\spc.exe --version ``` Self-hosted `spc` is built by GitHub Actions, you can also download from Actions artifacts [here](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml). @@ -150,7 +175,7 @@ bin/spc --version Basic usage for building php with some extensions: -> If you are using the packaged `spc` binary, you need to replace `bin/spc` with `./spc` in the following commands. +> If you are using the packaged standalone `spc` binary, you need to replace `bin/spc` with `./spc` or `.\spc.exe` in the following commands. ```bash # Check system tool dependencies, auto-fix them if possible @@ -159,14 +184,16 @@ Basic usage for building php with some extensions: # fetch all libraries ./bin/spc download --all # only fetch necessary sources by needed extensions (recommended) -./bin/spc download --for-extensions=openssl,pcntl,mbstring,pdo_sqlite +./bin/spc download --for-extensions="openssl,pcntl,mbstring,pdo_sqlite" # download different PHP version (--with-php=x.y, recommend 7.3 ~ 8.3) -./bin/spc download --for-extensions=openssl,curl,mbstring --with-php=8.1 +./bin/spc download --for-extensions="openssl,curl,mbstring" --with-php=8.1 # with bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl extension, build both CLI and phpmicro SAPI -./bin/spc build bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl --build-cli --build-micro +./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro # build thread-safe (ZTS) version (--enable-zts) -./bin/spc build curl,phar --enable-zts --build-cli +./bin/spc build "curl,phar" --enable-zts --build-cli +# build, pack executable with UPX (--with-upx-pack) (reduce binary size for 30~50%) +./bin/spc build "curl,phar" --enable-zts --build-cli --with-upx-pack ``` Now we support `cli`, `micro`, `fpm` and `embed` SAPI. You can use one or more of the following parameters to specify the compiled SAPI: @@ -180,7 +207,7 @@ Now we support `cli`, `micro`, `fpm` and `embed` SAPI. You can use one or more o If anything goes wrong, use `--debug` option to display full terminal output: ```bash -./bin/spc build openssl,pcntl,mbstring --debug --build-all +./bin/spc build "openssl,pcntl,mbstring" --debug --build-all ./bin/spc download --all --debug ``` diff --git a/config/ext.json b/config/ext.json index 104d527a..af349727 100644 --- a/config/ext.json +++ b/config/ext.json @@ -24,6 +24,10 @@ "arg-type": "with", "lib-depends": [ "curl" + ], + "ext-depends-windows": [ + "zlib", + "openssl" ] }, "dba": { @@ -403,8 +407,13 @@ "type": "external", "source": "ext-ssh2", "arg-type": "with-prefix", + "arg-type-windows": "with", "lib-depends": [ "libssh2" + ], + "ext-depends-windows": [ + "openssl", + "zlib" ] }, "swoole": { diff --git a/config/lib.json b/config/lib.json index 6f3b058e..25b027a5 100644 --- a/config/lib.json +++ b/config/lib.json @@ -45,19 +45,21 @@ "openssl", "zlib" ], - "lib-suggests": [ + "lib-depends-windows": [ + "openssl", + "zlib", + "libssh2", + "nghttp2" + ], + "lib-suggests-unix": [ "libssh2", "brotli", "nghttp2", "zstd" ], "lib-suggests-windows": [ - "zlib", - "libssh2", "brotli", - "nghttp2", - "zstd", - "openssl" + "zstd" ], "frameworks": [ "CoreFoundation", diff --git a/src/SPC/builder/windows/library/WindowsLibraryBase.php b/src/SPC/builder/windows/library/WindowsLibraryBase.php index c3fa49d6..e8de629e 100644 --- a/src/SPC/builder/windows/library/WindowsLibraryBase.php +++ b/src/SPC/builder/windows/library/WindowsLibraryBase.php @@ -8,6 +8,8 @@ use SPC\builder\BuilderBase; use SPC\builder\LibraryBase; use SPC\builder\windows\WindowsBuilder; use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\FileSystem; abstract class WindowsLibraryBase extends LibraryBase @@ -22,6 +24,36 @@ abstract class WindowsLibraryBase extends LibraryBase return $this->builder; } + /** + * @throws RuntimeException + * @throws FileSystemException + * @throws WrongUsageException + */ + public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string + { + $libs = [$this]; + if ($recursive) { + array_unshift($libs, ...array_values($this->getDependencies(recursive: true))); + } + + $sep = match ($style) { + 'autoconf' => ' ', + 'cmake' => ';', + default => throw new RuntimeException('style only support autoconf and cmake'), + }; + $ret = []; + foreach ($libs as $lib) { + $libFiles = []; + foreach ($lib->getStaticLibs() as $name) { + $name = str_replace(' ', '\ ', FileSystem::convertPath(BUILD_LIB_PATH . "/{$name}")); + $name = str_replace('"', '\"', $name); + $libFiles[] = $name; + } + array_unshift($ret, implode($sep, $libFiles)); + } + return implode($sep, $ret); + } + /** * Create a nmake wrapper file. * diff --git a/src/SPC/builder/windows/library/curl.php b/src/SPC/builder/windows/library/curl.php new file mode 100644 index 00000000..5f8443a0 --- /dev/null +++ b/src/SPC/builder/windows/library/curl.php @@ -0,0 +1,39 @@ +source_dir . '\build'); + + // start build + cmd()->cd($this->source_dir) + ->execWithWrapper( + $this->builder->makeSimpleWrapper('cmake'), + '-B build ' . + '-A x64 ' . + "-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " . + '-DCMAKE_BUILD_TYPE=Release ' . + '-DBUILD_SHARED_LIBS=OFF ' . + '-DBUILD_STATIC_LIBS=ON ' . + '-DBUILD_CURL_EXE=OFF ' . + '-DUSE_ZLIB=ON ' . + '-DCURL_USE_OPENSSL=ON ' . + '-DCURL_USE_LIBLSSH2=ON ' . + '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' + ) + ->execWithWrapper( + $this->builder->makeSimpleWrapper('cmake'), + "--build build --config Release --target install -j{$this->builder->concurrency}" + ); + } +} diff --git a/src/SPC/builder/windows/library/libssh2.php b/src/SPC/builder/windows/library/libssh2.php new file mode 100644 index 00000000..f064e139 --- /dev/null +++ b/src/SPC/builder/windows/library/libssh2.php @@ -0,0 +1,38 @@ +builder->getLib('zlib') ? 'ON' : 'OFF'; + // reset cmake + FileSystem::resetDir($this->source_dir . '\build'); + + // start build + cmd()->cd($this->source_dir) + ->execWithWrapper( + $this->builder->makeSimpleWrapper('cmake'), + '-B build ' . + '-A x64 ' . + "-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " . + '-DCMAKE_BUILD_TYPE=Release ' . + '-DBUILD_SHARED_LIBS=OFF ' . + '-DBUILD_STATIC_LIBS=ON ' . + '-DBUILD_TESTING=OFF ' . + "-DENABLE_ZLIB_COMPRESSION={$zlib} " . + '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' + ) + ->execWithWrapper( + $this->builder->makeSimpleWrapper('cmake'), + "--build build --config Release --target install -j{$this->builder->concurrency}" + ); + } +} diff --git a/src/SPC/builder/windows/library/nghttp2.php b/src/SPC/builder/windows/library/nghttp2.php new file mode 100644 index 00000000..a17fe89b --- /dev/null +++ b/src/SPC/builder/windows/library/nghttp2.php @@ -0,0 +1,37 @@ +source_dir . '\build'); + + // start build + cmd()->cd($this->source_dir) + ->execWithWrapper( + $this->builder->makeSimpleWrapper('cmake'), + '-B build ' . + '-A x64 ' . + "-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " . + '-DCMAKE_BUILD_TYPE=Release ' . + '-DBUILD_SHARED_LIBS=OFF ' . + '-DBUILD_STATIC_LIBS=ON ' . + '-DENABLE_STATIC_CRT=ON ' . + '-DENABLE_LIB_ONLY=ON ' . + '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' + ) + ->execWithWrapper( + $this->builder->makeSimpleWrapper('cmake'), + "--build build --config Release --target install -j{$this->builder->concurrency}" + ); + } +} diff --git a/src/SPC/store/FileSystem.php b/src/SPC/store/FileSystem.php index 2a694044..2cb45e00 100644 --- a/src/SPC/store/FileSystem.php +++ b/src/SPC/store/FileSystem.php @@ -185,9 +185,11 @@ class FileSystem } if ($move_path !== null) { $move_path = SOURCE_PATH . '/' . $move_path; + } else { + $move_path = SOURCE_PATH . "/{$name}"; } - logger()->info("extracting {$name} source to " . ($move_path ?? (SOURCE_PATH . "/{$name}")) . ' ...'); - $target = self::convertPath($move_path ?? (SOURCE_PATH . "/{$name}")); + $target = self::convertPath($move_path); + logger()->info("extracting {$name} source to {$target}" . ' ...'); if (!is_dir($dir = dirname($target))) { self::createDir($dir); } diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 77ff00ac..fd0f1083 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -14,7 +14,7 @@ declare(strict_types=1); // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { 'Linux', 'Darwin' => 'event,gettext', - 'Windows' => 'mbstring', + 'Windows' => 'mbstring,curl,ssh2', }; // If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).