diff --git a/.github/workflows/build-linux-x86_64.yml b/.github/workflows/build-linux-x86_64.yml index 5a3a210d..0fbe82d8 100644 --- a/.github/workflows/build-linux-x86_64.yml +++ b/.github/workflows/build-linux-x86_64.yml @@ -114,3 +114,9 @@ jobs: path: | buildroot/build-extensions.json buildroot/build-libraries.json + + # Upload downloaded files + - uses: actions/upload-artifact@v3 + with: + name: download-files + path: downloads/ diff --git a/.github/workflows/build-macos-x86_64.yml b/.github/workflows/build-macos-x86_64.yml index 3270480f..d37900ec 100644 --- a/.github/workflows/build-macos-x86_64.yml +++ b/.github/workflows/build-macos-x86_64.yml @@ -114,3 +114,9 @@ jobs: path: | buildroot/build-extensions.json buildroot/build-libraries.json + + # Upload downloaded files + - uses: actions/upload-artifact@v3 + with: + name: download-files + path: downloads/ diff --git a/README-en.md b/README-en.md index 253b7480..4bd3120a 100755 --- a/README-en.md +++ b/README-en.md @@ -11,14 +11,12 @@ This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro 截屏2023-05-02 15 52 33 -> This branch is new version, if you are looking for old bash version of static-php-cli, see [bash-version](https://github.com/crazywhalecc/static-php-cli/tree/bash-version). - -[![Version](https://img.shields.io/badge/Version-2.0--beta3-orange.svg?style=flat-square)]() +[![Version](https://img.shields.io/badge/Version-2.0--rc1-pink.svg?style=flat-square)]() [![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]() [![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-linux-x86_64.yml?branch=refactor&label=Linux%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml) [![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-macos-x86_64.yml?branch=refactor&label=macOS%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml) -[![](https://img.shields.io/badge/Extension%20Counter-45+-yellow.svg?style=flat-square)]() +[![](https://img.shields.io/badge/Extension%20Counter-50+-yellow.svg?style=flat-square)]() [![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]() ## Compilation Requirements @@ -129,6 +127,14 @@ If anything goes wrong, use `--debug` option to display full terminal output: ./bin/spc fetch --all --debug ``` +In addition, we build NTS by default. If you are going to build ZTS version, just add `--enable-zts` option. + +```bash +./bin/spc build openssl,pcntl --build-all --enable-zts +``` + +Adding option `--no-strip` can produce binaries with debug symbols, in order to debug (using gdb). Disabling strip will increase the size of static binary. + ### php-cli Usage > php-cli is a single static binary, you can use it like normal php installed on your system. diff --git a/README.md b/README.md index 4da33583..84e93f0f 100755 --- a/README.md +++ b/README.md @@ -12,13 +12,11 @@ If you are using English, see [English README](README-en.md). 截屏2023-05-02 15 52 33 -> 此分支为重构的新版,如果你在找纯 Bash 编写的旧版本,请到 [bash-version 分支](https://github.com/crazywhalecc/static-php-cli/tree/bash-version)。 - -[![Version](https://img.shields.io/badge/Version-2.0--beta3-orange.svg?style=flat-square)]() +[![Version](https://img.shields.io/badge/Version-2.0--rc1-pink.svg?style=flat-square)]() [![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]() [![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-linux-x86_64.yml?branch=refactor&label=Linux%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml) [![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-macos-x86_64.yml?branch=refactor&label=macOS%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml) -[![](https://img.shields.io/badge/Extension%20Counter-45+-yellow.svg?style=flat-square)]() +[![](https://img.shields.io/badge/Extension%20Counter-50+-yellow.svg?style=flat-square)]() [![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]() ## 编译环境需求 @@ -125,6 +123,14 @@ chmod +x bin/spc ./bin/spc fetch --all --debug ``` +此外,默认编译的 PHP 为 NTS 版本。如需编译线程安全版本(ZTS),只需添加参数 `--enable-zts` 即可。 + +```bash +./bin/spc build openssl,pcntl --build-all --enable-zts +``` + +同时,你也可以使用参数 `--no-strip` 来关闭裁剪,关闭裁剪后可以使用 gdb 等工具调试,但这样会让静态二进制体积变大。 + ### 使用 php-cli > php-cli 是一个静态的二进制文件,类似 Go、Rust 语言编译后的单个可移植的二进制文件。 diff --git a/bin/setup-runtime b/bin/setup-runtime index d77d8181..48144f97 100755 --- a/bin/setup-runtime +++ b/bin/setup-runtime @@ -25,7 +25,7 @@ __DIR__=$(cd "$(dirname "$0")" && pwd) __PROJECT__=$(cd ${__DIR__}/../ && pwd) # set download dir -__PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.5-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz" +__PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.6-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz" __COMPOSER_URL__="https://getcomposer.org/download/latest-stable/composer.phar" # use china mirror @@ -46,7 +46,7 @@ done case "$mirror" in china) - __PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.5-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz" + __PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.6-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz" __COMPOSER_URL__="https://mirrors.aliyun.com/composer/composer.phar" ;; diff --git a/config/ext.json b/config/ext.json index fab1d737..2a78acb1 100644 --- a/config/ext.json +++ b/config/ext.json @@ -1,4 +1,8 @@ { + "apcu": { + "type": "external", + "source": "apcu" + }, "bcmath": { "type": "builtin" }, @@ -35,10 +39,6 @@ "zlib" ] }, - "apcu": { - "type": "external", - "source": "apcu" - }, "event": { "type": "external", "source": "ext-event", @@ -114,6 +114,14 @@ "libiconv" ] }, + "imagick": { + "type": "external", + "source": "ext-imagick", + "arg-type": "custom", + "lib-depends": [ + "imagemagick" + ] + }, "imap": { "type": "builtin", "arg-type": "with", @@ -288,7 +296,7 @@ "type": "builtin", "arg-type": "with", "lib-depends": [ - "sodium" + "libsodium" ] }, "sqlite3": { @@ -298,6 +306,14 @@ "sqlite" ] }, + "ssh2": { + "type": "external", + "source": "ext-ssh2", + "arg-type": "with-prefix", + "lib-depends": [ + "libssh2" + ] + }, "swoole": { "type": "external", "source": "swoole", diff --git a/config/lib.json b/config/lib.json index 500ebe3d..bfe6ec6c 100644 --- a/config/lib.json +++ b/config/lib.json @@ -15,21 +15,6 @@ "brotli" ] }, - "ncurses": { - "source": "ncurses", - "static-libs-unix": [ - "libncurses.a" - ] - }, - "readline": { - "source": "readline", - "static-libs-unix": [ - "libreadline.a" - ], - "lib-depends": [ - "ncurses" - ] - }, "bzip2": { "source": "bzip2", "static-libs-unix": [ @@ -111,6 +96,28 @@ "gmp.h" ] }, + "imagemagick": { + "source": "imagemagick", + "static-libs-unix": [ + "libMagick++-7.Q16HDRI.a", + "libMagickCore-7.Q16HDRI.a", + "libMagickWand-7.Q16HDRI.a" + ], + "lib-depends": [ + "zlib", + "libpng", + "libjpeg", + "bzip2", + "libwebp", + "freetype" + ], + "lib-suggests": [ + "zstd", + "xz", + "libzip", + "libxml2" + ] + }, "libavif": { "source": "libavif", "static-libs-unix": [ @@ -294,6 +301,12 @@ "libmcrypt.a" ] }, + "ncurses": { + "source": "ncurses", + "static-libs-unix": [ + "libncurses.a" + ] + }, "nghttp2": { "source": "nghttp2", "static-libs-unix": [ @@ -346,6 +359,9 @@ "zlib" ] }, + "pkg-config": { + "source": "pkg-config" + }, "postgresql": { "source": "postgresql", "static-libs-unix": [ @@ -364,6 +380,15 @@ "semaphore.h" ] }, + "readline": { + "source": "readline", + "static-libs-unix": [ + "libreadline.a" + ], + "lib-depends": [ + "ncurses" + ] + }, "sqlite": { "source": "sqlite", "static-libs-unix": [ @@ -429,5 +454,11 @@ "zstd.h", "zstd_errors.h" ] + }, + "libsodium": { + "source": "libsodium", + "static-libs-unix": [ + "libsodium.a" + ] } } \ No newline at end of file diff --git a/config/source.json b/config/source.json index 0b72e00d..d74fd496 100644 --- a/config/source.json +++ b/config/source.json @@ -6,6 +6,16 @@ "path": "LICENSE" } }, + "apcu": { + "type": "url", + "url": "http://pecl.php.net/get/APCu", + "path": "php-src/ext/apcu", + "filename": "apcu.tgz", + "license": { + "type": "file", + "path": "LICENSE" + } + }, "brotli": { "type": "ghtar", "repo": "google/brotli", @@ -41,22 +51,24 @@ "path": "LICENSE" } }, - "ncurses": { - "type": "filelist", - "url": "https://ftp.gnu.org/pub/gnu/ncurses/", - "regex": "/href=\"(?ncurses-(?[^\"]+)\\.tar\\.gz)\"/", + "ext-imagick": { + "type": "url", + "url": "https://pecl.php.net/get/imagick", + "path": "php-src/ext/imagick", + "filename": "imagick.tgz", "license": { "type": "file", - "path": "COPYING" + "path": "LICENSE" } }, - "readline": { - "type": "filelist", - "url": "https://ftp.gnu.org/pub/gnu/readline/", - "regex": "/href=\"(?readline-(?[^\"]+)\\.tar\\.gz)\"/", + "ext-ssh2": { + "type": "url", + "url": "http://pecl.php.net/get/ssh2", + "path": "php-src/ext/ssh2", + "filename": "ssh2.tgz", "license": { "type": "file", - "path": "COPYING" + "path": "LICENSE" } }, "ext-zstd": { @@ -87,6 +99,14 @@ "text": "Since version 6, GMP is distributed under the dual licenses, GNU LGPL v3 and GNU GPL v2. These licenses make the library free to use, share, and improve, and allow you to pass on the result. The GNU licenses give freedoms, but also set firm restrictions on the use with non-free programs." } }, + "imagemagick": { + "type": "ghtar", + "repo": "ImageMagick/ImageMagick", + "license": { + "type": "file", + "path": "LICENSE" + } + }, "inotify": { "type": "url", "url": "http://pecl.php.net/get/inotify", @@ -209,16 +229,6 @@ "path": "LICENSE" } }, - "apcu": { - "type": "url", - "url": "http://pecl.php.net/get/APCu", - "path": "php-src/ext/apcu", - "filename": "apcu.tgz", - "license": { - "type": "file", - "path": "LICENSE" - } - }, "mcrypt": { "type": "url", "url": "https://jaist.dl.sourceforge.net/project/mcrypt/MCrypt/2.6.8/mcrypt-2.6.8.tar.gz", @@ -247,6 +257,15 @@ "path": "LICENSE" } }, + "ncurses": { + "type": "filelist", + "url": "https://ftp.gnu.org/pub/gnu/ncurses/", + "regex": "/href=\"(?ncurses-(?[^\"]+)\\.tar\\.gz)\"/", + "license": { + "type": "file", + "path": "COPYING" + } + }, "nghttp2": { "type": "ghrel", "repo": "nghttp2/nghttp2", @@ -274,6 +293,15 @@ "path": "LICENSE.txt" } }, + "pkg-config": { + "type": "filelist", + "url": "https://pkgconfig.freedesktop.org/releases/", + "regex": "/href=\"(?pkg-config-(?[^\"]+)\\.tar\\.gz)\"/", + "license": { + "type": "file", + "path": "COPYING" + } + }, "postgresql": { "type": "custom", "license": { @@ -300,6 +328,15 @@ "path": "LICENSE" } }, + "readline": { + "type": "filelist", + "url": "https://ftp.gnu.org/pub/gnu/readline/", + "regex": "/href=\"(?readline-(?[^\"]+)\\.tar\\.gz)\"/", + "license": { + "type": "file", + "path": "COPYING" + } + }, "redis": { "type": "git", "path": "php-src/ext/redis", @@ -374,5 +411,13 @@ "type": "file", "path": "LICENSE" } + }, + "libsodium": { + "type": "url", + "url": "https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz", + "license": { + "type": "file", + "path": "LICENSE" + } } } \ No newline at end of file diff --git a/ext-support.md b/ext-support.md index afdccdf0..9af15a0d 100644 --- a/ext-support.md +++ b/ext-support.md @@ -19,6 +19,7 @@ | enchant | | | | | event | yes | yes | | | exif | yes | yes | | +| ffi | | yes, [docs]() | | | filter | yes | yes | | | fileinfo | yes | yes | | | ftp | yes | yes | | @@ -26,6 +27,7 @@ | gettext | | | | | gmp | yes | yes | | | iconv | yes | yes | | +| imagick | yes | yes | | | inotify | yes | yes | | | mbstring | yes | yes | | | mbregex | yes | yes | | @@ -49,14 +51,16 @@ | simplexml | yes | yes | | | soap | yes | yes | | | sockets | yes | yes | | +| sodium | yes | yes | | | sqlite3 | yes | yes | | +| ssh2 | yes, untested | yes, untested | | | swow | yes | yes | | | swoole | [partial](https://github.com/crazywhalecc/static-php-cli/issues/51) | yes | | | tokenizer | yes | yes | | | xml | yes | yes | | | xmlreader | yes, untested | yes, untested | | | xmlwriter | yes, untested | yes, untested | | -| zip | yes, untested | yes | | +| zip | yes, untested | yes, untested | | | zlib | yes | yes | | | zstd | yes | yes | | diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index 33862e3c..9253aa15 100644 --- a/src/SPC/ConsoleApplication.php +++ b/src/SPC/ConsoleApplication.php @@ -16,7 +16,7 @@ use Symfony\Component\Console\Command\ListCommand; */ class ConsoleApplication extends Application { - public const VERSION = '2.0-beta3'; + public const VERSION = '2.0-rc1'; /** * @throws \ReflectionException diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index 09240cb0..900bb4ed 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -38,6 +38,9 @@ abstract class BuilderBase /** @var bool 本次编译是否只编译 libs,不编译 PHP */ protected bool $libs_only = false; + /** @var bool 是否 strip 最终的二进制 */ + protected bool $strip = true; + /** * 构建指定列表的 libs * @@ -63,16 +66,13 @@ abstract class BuilderBase if ($libraries === [] && $this->isLibsOnly()) { $libraries = array_keys($support_lib_list); } + if (!in_array('pkg-config', $libraries)) { + array_unshift($libraries, 'pkg-config'); + } // 排序 libs,根据依赖计算一个新的列表出来 $libraries = DependencyUtil::getLibsByDeps($libraries); - // 这里筛选 libraries,比如纯静态模式排除掉ffi - if (defined('BUILD_ALL_STATIC') && BUILD_ALL_STATIC) { - $k = array_search('libffi', $libraries, true); - $k !== false && array_splice($libraries, $k, 1); - } - // 过滤不支持的库后添加 foreach ($libraries as $library) { if (!isset($support_lib_list[$library])) { @@ -234,6 +234,11 @@ abstract class BuilderBase return implode(', ', $ls); } + public function setStrip(bool $strip): void + { + $this->strip = $strip; + } + /** * 检查是否存在 lib 库对应的源码,如果不存在,则抛出异常 * diff --git a/src/SPC/builder/BuilderProvider.php b/src/SPC/builder/BuilderProvider.php index 4a19aef2..879153f8 100644 --- a/src/SPC/builder/BuilderProvider.php +++ b/src/SPC/builder/BuilderProvider.php @@ -31,11 +31,13 @@ class BuilderProvider cc: $input->getOption('cc'), cxx: $input->getOption('cxx'), arch: $input->getOption('arch'), + zts: $input->getOption('enable-zts'), ), 'Linux' => new LinuxBuilder( cc: $input->getOption('cc'), cxx: $input->getOption('cxx'), arch: $input->getOption('arch'), + zts: $input->getOption('enable-zts'), ), default => throw new WrongUsageException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'), }; diff --git a/src/SPC/builder/LibraryBase.php b/src/SPC/builder/LibraryBase.php index dfd6b859..7f234a5b 100644 --- a/src/SPC/builder/LibraryBase.php +++ b/src/SPC/builder/LibraryBase.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace SPC\builder; +use SPC\builder\macos\library\MacOSLibraryBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\store\Config; @@ -152,6 +153,11 @@ abstract class LibraryBase return BUILD_STATUS_OK; } } + // pkg-config 做特殊处理,如果是 pkg-config 就检查有没有 pkg-config 二进制 + if ($this instanceof MacOSLibraryBase && static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) { + $this->tryBuild(true); + return BUILD_STATUS_OK; + } // 到这里说明所有的文件都存在,就跳过编译 return BUILD_STATUS_ALREADY; } diff --git a/src/SPC/builder/extension/ffi.php b/src/SPC/builder/extension/ffi.php index 106f2a64..f0cf9fe6 100644 --- a/src/SPC/builder/extension/ffi.php +++ b/src/SPC/builder/extension/ffi.php @@ -12,7 +12,6 @@ class ffi extends Extension { public function getUnixConfigureArg(): string { - return '--with-ffi FFI_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '" ' . - 'FFI_LIBS="' . $this->getLibFilesString() . '"'; + return '--with-ffi --enable-zend-signals'; } } diff --git a/src/SPC/builder/extension/imagick.php b/src/SPC/builder/extension/imagick.php new file mode 100644 index 00000000..ed456e17 --- /dev/null +++ b/src/SPC/builder/extension/imagick.php @@ -0,0 +1,17 @@ +cc = $cc ?? match (SystemUtil::getOSRelease()['dist']) { @@ -53,6 +53,7 @@ class LinuxBuilder extends BuilderBase $this->cxx = $cxx ?? 'g++'; $this->arch = $arch ?? php_uname('m'); $this->gnu_arch = arch2gnu($this->arch); + $this->zts = $zts; $this->libc = 'musl'; // SystemUtil::selectLibc($this->cc); // 根据 CPU 线程数设置编译进程数 @@ -70,7 +71,7 @@ class LinuxBuilder extends BuilderBase cxx: $this->cxx ); // 设置 pkgconfig - $this->pkgconf_env = 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig"'; + $this->pkgconf_env = 'PKG_CONFIG="' . BUILD_ROOT_PATH . '/bin/pkg-config" PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig"'; // 设置 configure 依赖的环境变量 $this->configure_env = $this->pkgconf_env . ' ' . @@ -141,6 +142,9 @@ class LinuxBuilder extends BuilderBase if ($this->getExt('swoole')) { $extra_libs .= ' -lstdc++'; } + if ($this->getExt('imagick')) { + $extra_libs .= ' /usr/lib/libMagick++-7.Q16HDRI.a /usr/lib/libMagickCore-7.Q16HDRI.a /usr/lib/libMagickWand-7.Q16HDRI.a'; + } $envs = $this->pkgconf_env . ' ' . "CC='{$this->cc}' " . @@ -169,7 +173,7 @@ class LinuxBuilder extends BuilderBase shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force'); SourcePatcher::patchPHPConfigure($this); - + if ($this->getPHPVersionID() < 80000) { $json_74 = '--enable-json '; } else { diff --git a/src/SPC/builder/linux/SystemUtil.php b/src/SPC/builder/linux/SystemUtil.php index b0a43789..5f2df6a3 100644 --- a/src/SPC/builder/linux/SystemUtil.php +++ b/src/SPC/builder/linux/SystemUtil.php @@ -149,7 +149,7 @@ class SystemUtil { $paths = getenv('LIBPATH'); if (!$paths) { - $paths = '/lib:/lib64:/usr/lib:/usr/lib64:/usr/local/lib:/usr/local/lib64'; + $paths = '/lib:/lib64:/usr/lib:/usr/lib64:/usr/local/lib:/usr/local/lib64:'; } foreach (explode(':', $paths) as $path) { if (file_exists("{$path}/{$name}")) { diff --git a/src/SPC/builder/linux/library/LinuxLibraryBase.php b/src/SPC/builder/linux/library/LinuxLibraryBase.php index 1105578f..2712976b 100644 --- a/src/SPC/builder/linux/library/LinuxLibraryBase.php +++ b/src/SPC/builder/linux/library/LinuxLibraryBase.php @@ -61,6 +61,11 @@ abstract class LinuxLibraryBase extends LibraryBase return BUILD_STATUS_OK; } } + // pkg-config 做特殊处理,如果是 pkg-config 就检查有没有 pkg-config 二进制 + if (static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) { + $this->tryBuild(true); + return BUILD_STATUS_OK; + } // 到这里说明所有的文件都存在,就跳过编译 return BUILD_STATUS_ALREADY; } diff --git a/src/SPC/builder/linux/library/imagemagick.php b/src/SPC/builder/linux/library/imagemagick.php new file mode 100644 index 00000000..6006a222 --- /dev/null +++ b/src/SPC/builder/linux/library/imagemagick.php @@ -0,0 +1,15 @@ +cd(BUILD_LIB_PATH) ->exec('ln -sf libpng16.a libpng.a'); $this->patchPkgconfPrefix(['libpng16.pc'], PKGCONF_PATCH_PREFIX); + $this->cleanLaFiles(); } } diff --git a/src/SPC/builder/linux/library/libsodium.php b/src/SPC/builder/linux/library/libsodium.php new file mode 100644 index 00000000..76012bec --- /dev/null +++ b/src/SPC/builder/linux/library/libsodium.php @@ -0,0 +1,12 @@ +set_x = defined('DEBUG_MODE') ? 'set -x' : 'true'; @@ -40,6 +40,7 @@ class MacOSBuilder extends BuilderBase $this->cxx = $cxx ?? 'clang++'; $this->arch = $arch ?? php_uname('m'); $this->gnu_arch = arch2gnu($this->arch); + $this->zts = $zts; // 根据 CPU 线程数设置编译进程数 $this->concurrency = SystemUtil::getCpuCount(); // 设置 cflags @@ -49,6 +50,7 @@ class MacOSBuilder extends BuilderBase $this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile('Darwin', $this->arch, $this->arch_c_flags); // 设置 configure 依赖的环境变量 $this->configure_env = + 'PKG_CONFIG="' . BUILD_ROOT_PATH . '/bin/pkg-config" ' . 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig/" ' . "CC='{$this->cc}' " . "CXX='{$this->cxx}' " . @@ -145,7 +147,7 @@ class MacOSBuilder extends BuilderBase if ($this->getLib('libxml2') || $this->getExt('iconv')) { $extra_libs .= ' -liconv'; } - + if ($this->getPHPVersionID() < 80000) { $json_74 = '--enable-json '; } else { @@ -206,10 +208,11 @@ class MacOSBuilder extends BuilderBase */ public function buildCli(string $extra_libs): void { - shell()->cd(SOURCE_PATH . '/php-src') - ->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" cli") - ->exec('dsymutil -f sapi/cli/php') - ->exec('strip sapi/cli/php'); + $shell = shell()->cd(SOURCE_PATH . '/php-src'); + $shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" cli"); + if ($this->strip) { + $shell->exec('dsymutil -f sapi/cli/php')->exec('strip sapi/cli/php'); + } $this->deployBinary(BUILD_TARGET_CLI); } @@ -229,7 +232,7 @@ class MacOSBuilder extends BuilderBase } shell()->cd(SOURCE_PATH . '/php-src') - ->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" STRIP=\"dsymutil -f \" micro"); + ->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" " . ($this->strip ? 'STRIP="dsymutil -f " ' : '') . 'micro'); $this->deployBinary(BUILD_TARGET_MICRO); } @@ -241,10 +244,11 @@ class MacOSBuilder extends BuilderBase */ public function buildFpm(string $extra_libs): void { - shell()->cd(SOURCE_PATH . '/php-src') - ->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" fpm") - ->exec('dsymutil -f sapi/fpm/php-fpm') - ->exec('strip sapi/fpm/php-fpm'); + $shell = shell()->cd(SOURCE_PATH . '/php-src'); + $shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" fpm"); + if ($this->strip) { + $shell->exec('dsymutil -f sapi/fpm/php-fpm')->exec('strip sapi/fpm/php-fpm'); + } $this->deployBinary(BUILD_TARGET_FPM); } } diff --git a/src/SPC/builder/macos/library/imagemagick.php b/src/SPC/builder/macos/library/imagemagick.php new file mode 100644 index 00000000..446f208b --- /dev/null +++ b/src/SPC/builder/macos/library/imagemagick.php @@ -0,0 +1,15 @@ +builder->arch}-apple-darwin " . "--target={$this->builder->arch}-apple-darwin " . - '--prefix= ' . // use prefix=/ - "--libdir={$lib}" + '--prefix= ' // use prefix=/ ) ->exec('make clean') ->exec("make -j{$this->builder->concurrency}") ->exec("make install DESTDIR={$destdir}"); + $this->patchPkgconfPrefix(['libffi.pc']); } } diff --git a/src/SPC/builder/macos/library/libpng.php b/src/SPC/builder/macos/library/libpng.php index 07d3c767..76a0645e 100644 --- a/src/SPC/builder/macos/library/libpng.php +++ b/src/SPC/builder/macos/library/libpng.php @@ -55,5 +55,6 @@ class libpng extends MacOSLibraryBase ->cd(BUILD_LIB_PATH) ->exec('ln -sf libpng16.a libpng.a'); $this->patchPkgconfPrefix(['libpng16.pc'], PKGCONF_PATCH_PREFIX); + $this->cleanLaFiles(); } } diff --git a/src/SPC/builder/macos/library/libsodium.php b/src/SPC/builder/macos/library/libsodium.php new file mode 100644 index 00000000..fe179174 --- /dev/null +++ b/src/SPC/builder/macos/library/libsodium.php @@ -0,0 +1,12 @@ +exts as $ext) { logger()->debug('testing ext: ' . $ext->getName()); - [$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri ' . $ext->getDistName(), false); + [$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "' . $ext->getDistName() . '"', false); if ($ret !== 0) { throw new RuntimeException('extension ' . $ext->getName() . ' failed compile check'); } diff --git a/src/SPC/builder/traits/UnixLibraryTrait.php b/src/SPC/builder/traits/UnixLibraryTrait.php index 494b3ab8..4bc210fa 100644 --- a/src/SPC/builder/traits/UnixLibraryTrait.php +++ b/src/SPC/builder/traits/UnixLibraryTrait.php @@ -77,4 +77,20 @@ trait UnixLibraryTrait FileSystem::writeFile($realpath, $file); } } + + /** + * remove libtool archive files + * + * @throws FileSystemException + * @throws RuntimeException + */ + public function cleanLaFiles(): void + { + foreach ($this->getStaticLibs() as $lib) { + $filename = pathinfo($lib, PATHINFO_FILENAME) . '.la'; + if (file_exists(BUILD_LIB_PATH . '/' . $filename)) { + unlink(BUILD_LIB_PATH . '/' . $filename); + } + } + } } diff --git a/src/SPC/builder/traits/UnixSystemUtilTrait.php b/src/SPC/builder/traits/UnixSystemUtilTrait.php index adc25a5f..6e25ab7a 100644 --- a/src/SPC/builder/traits/UnixSystemUtilTrait.php +++ b/src/SPC/builder/traits/UnixSystemUtilTrait.php @@ -38,8 +38,6 @@ trait UnixSystemUtilTrait $cxxLine = 'SET(CMAKE_CXX_COMPILER ' . self::findCommand($cxx) . ')'; } $toolchain = <<exec("make -j{$this->builder->concurrency}") ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); $this->patchPkgconfPrefix(['freetype2.pc']); + FileSystem::replaceFile( + BUILD_ROOT_PATH . '/lib/pkgconfig/freetype2.pc', + REPLACE_FILE_STR, + ' -L/lib ', + ' -L' . BUILD_ROOT_PATH . '/lib ' + ); + + $this->cleanLaFiles(); } } diff --git a/src/SPC/builder/unix/library/imagemagick.php b/src/SPC/builder/unix/library/imagemagick.php new file mode 100644 index 00000000..6f1fd461 --- /dev/null +++ b/src/SPC/builder/unix/library/imagemagick.php @@ -0,0 +1,57 @@ +builder->getLib('libzip') ? '--with-zip ' : '--without-zip '; + // jpeg support + $extra .= $this->builder->getLib('libjpeg') ? '--with-jpeg ' : ''; + // png support + $extra .= $this->builder->getLib('libpng') ? '--with-png ' : ''; + // webp support + $extra .= $this->builder->getLib('libwebp') ? '--with-webp ' : ''; + // zstd support + // $extra .= $this->builder->getLib('zstd') ? '--with-zstd ' : '--without-zstd '; + // freetype support + $extra .= $this->builder->getLib('freetype') ? '--with-freetype ' : '--without-freetype '; + + shell()->cd($this->source_dir) + ->exec( + "{$this->builder->configure_env} ./configure " . + '--enable-static --disable-shared ' . + $extra . + '--prefix=' + ) + ->exec('make clean') + ->exec("make -j{$this->builder->concurrency}") + ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + $filelist = [ + 'ImageMagick.pc', + 'ImageMagick-7.Q16HDRI.pc', + 'Magick++.pc', + 'Magick++-7.Q16HDRI.pc', + 'MagickCore.pc', + 'MagickCore-7.Q16HDRI.pc', + 'MagickWand.pc', + 'MagickWand-7.Q16HDRI.pc', + ]; + $this->patchPkgconfPrefix($filelist); + foreach ($filelist as $file) { + FileSystem::replaceFile( + BUILD_LIB_PATH . '/pkgconfig/' . $file, + REPLACE_FILE_PREG, + '#includearchdir=/include/ImageMagick-7#m', + 'includearchdir=${prefix}/include/ImageMagick-7' + ); + } + } +} diff --git a/src/SPC/builder/unix/library/libavif.php b/src/SPC/builder/unix/library/libavif.php index 413b471d..ac27a5d9 100644 --- a/src/SPC/builder/unix/library/libavif.php +++ b/src/SPC/builder/unix/library/libavif.php @@ -24,5 +24,6 @@ trait libavif ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); // patch pkgconfig $this->patchPkgconfPrefix(['libavif.pc']); + $this->cleanLaFiles(); } } diff --git a/src/SPC/builder/unix/library/libjpeg.php b/src/SPC/builder/unix/library/libjpeg.php index 08c51d85..65da0c08 100644 --- a/src/SPC/builder/unix/library/libjpeg.php +++ b/src/SPC/builder/unix/library/libjpeg.php @@ -24,5 +24,6 @@ trait libjpeg ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); // patch pkgconfig $this->patchPkgconfPrefix(['libjpeg.pc', 'libturbojpeg.pc']); + $this->cleanLaFiles(); } } diff --git a/src/SPC/builder/unix/library/libsodium.php b/src/SPC/builder/unix/library/libsodium.php new file mode 100644 index 00000000..2f093d03 --- /dev/null +++ b/src/SPC/builder/unix/library/libsodium.php @@ -0,0 +1,18 @@ +cd($this->source_dir) + ->exec("{$this->builder->configure_env} ./configure --enable-static --disable-shared --prefix={$root}") + ->exec('make clean') + ->exec("make -j{$this->builder->concurrency}") + ->exec('make install'); + } +} diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 9d06842d..f6e7a596 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -28,5 +28,6 @@ trait libwebp ->exec("make -j{$this->builder->concurrency}") ->exec('make install DESTDIR=' . $destdir); $this->patchPkgconfPrefix(['libsharpyuv.pc', 'libwebp.pc', 'libwebpdecoder.pc', 'libwebpdemux.pc', 'libwebpmux.pc'], PKGCONF_PATCH_PREFIX); + $this->cleanLaFiles(); } } diff --git a/src/SPC/builder/unix/library/libzip.php b/src/SPC/builder/unix/library/libzip.php index f50a6144..b4b8f99f 100644 --- a/src/SPC/builder/unix/library/libzip.php +++ b/src/SPC/builder/unix/library/libzip.php @@ -15,8 +15,8 @@ trait libzip $extra .= $this->builder->getLib('bzip2') ? '-DENABLE_BZIP2=ON ' : '-DENABLE_BZIP2=OFF '; // lib:xz $extra .= $this->builder->getLib('xz') ? '-DENABLE_LZMA=ON ' : '-DENABLE_LZMA=OFF '; - // lib:zstd - $extra .= $this->builder->getLib('zstd') ? '-DENABLE_ZSTD=ON ' : '-DENABLE_ZSTD=OFF '; + // lib:zstd (disabled due to imagemagick link issue + $extra .= /* $this->builder->getLib('zstd') ? '-DENABLE_ZSTD=ON ' : */ '-DENABLE_ZSTD=OFF '; // lib:openssl $extra .= $this->builder->getLib('openssl') ? '-DENABLE_OPENSSL=ON ' : '-DENABLE_OPENSSL=OFF '; diff --git a/src/SPC/builder/unix/library/pkgconfig.php b/src/SPC/builder/unix/library/pkgconfig.php new file mode 100644 index 00000000..6cc475d9 --- /dev/null +++ b/src/SPC/builder/unix/library/pkgconfig.php @@ -0,0 +1,43 @@ +builder->cc}' " . + "CXX='{$this->builder->cxx}' " . + "CFLAGS='{$this->builder->arch_c_flags} -Wimplicit-function-declaration' "; + $linux_env = 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig" ' . + "CC='{$this->builder->cc}' " . + "CXX='{$this->builder->cxx}' "; + + $extra = match (PHP_OS_FAMILY) { + 'Darwin' => '', + default => '--with-internal-glib ', + }; + shell()->cd($this->source_dir) + ->exec( + match (PHP_OS_FAMILY) { + 'Darwin' => $macos_env, + default => $linux_env, + } . + './configure ' . + '--disable-shared ' . + '--enable-static ' . + $extra . + '--prefix=' . BUILD_ROOT_PATH . ' ' . + '--without-sysroot ' . + '--without-system-include-path ' . + '--without-system-library-path ' . + '--without-pc-path' + ) + ->exec('make clean') + ->exec("make -j{$this->builder->concurrency}") + ->exec('make install'); + } +} diff --git a/src/SPC/command/BuildCliCommand.php b/src/SPC/command/BuildCliCommand.php index 0c0cfa49..6aad5509 100644 --- a/src/SPC/command/BuildCliCommand.php +++ b/src/SPC/command/BuildCliCommand.php @@ -25,6 +25,8 @@ class BuildCliCommand extends BuildCommand $this->addOption('build-cli', null, null, 'build cli'); $this->addOption('build-fpm', null, null, 'build fpm'); $this->addOption('build-all', null, null, 'build cli, micro, fpm'); + $this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions'); + $this->addOption('enable-zts', null, null, 'enable ZTS support'); } public function handle(): int @@ -68,6 +70,8 @@ class BuildCliCommand extends BuildCommand $builder->buildLibs($libraries); // 执行扩展检测 $builder->proveExts($extensions); + // strip + $builder->setStrip(false); // 构建 $builder->buildPHP($rule, $this->getOption('bloat')); // 统计时间 diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index 9319b220..aba47b92 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -6,6 +6,7 @@ namespace SPC\store; use SPC\builder\BuilderBase; use SPC\builder\linux\LinuxBuilder; +use SPC\builder\linux\SystemUtil; use SPC\builder\macos\MacOSBuilder; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; @@ -84,6 +85,9 @@ class SourcePatcher if ($readline = $builder->getExt('readline')) { $patch[] = ['readline patch', '/-lncurses/', $readline->getLibFilesString()]; } + if ($ssh2 = $builder->getExt('ssh2')) { + $patch[] = ['ssh2 patch', '/-lssh2/', $ssh2->getLibFilesString()]; + } $patch[] = ['disable capstone', '/have_capstone="yes"/', 'have_capstone="no"']; foreach ($patch as $item) { logger()->info('Patching configure: ' . $item[0]); @@ -99,6 +103,24 @@ class SourcePatcher '-lz', BUILD_LIB_PATH . '/libz.a' ); + if (SystemUtil::getOSRelease()['dist'] === 'alpine') { + FileSystem::replaceFile( + SOURCE_PATH . '/libpng/configure', + REPLACE_FILE_STR, + '-lm', + '/usr/lib/libm.a' + ); + } + } + + public static function patchUnixSsh2(): void + { + FileSystem::replaceFile( + SOURCE_PATH . '/php-src/configure', + REPLACE_FILE_STR, + '-lssh2', + BUILD_LIB_PATH . '/libssh2.a' + ); } public static function patchCurlMacOS(): void diff --git a/src/globals/functions.php b/src/globals/functions.php index 9ce84214..5f6cc29f 100644 --- a/src/globals/functions.php +++ b/src/globals/functions.php @@ -66,6 +66,8 @@ function osfamily2dir(): string } /** + * 执行shell,直接输出在终端,出现错误抛出异常 + * * @throws \SPC\exception\RuntimeException */ function f_passthru(string $cmd): ?bool @@ -89,7 +91,13 @@ function f_passthru(string $cmd): ?bool return $ret; } -function f_exec(string $command, &$output, &$result_code) +/** + * 执行命令,不输出内容,返回执行结果和内容 + * + * @param mixed $output + * @param mixed $result_code + */ +function f_exec(string $command, &$output, &$result_code): bool|string { logger()->debug('Running command (no output) : ' . $command); return exec($command, $output, $result_code);