This commit is contained in:
DubbleClick
2025-07-24 10:53:49 +07:00
42 changed files with 591 additions and 467 deletions

View File

@@ -136,11 +136,4 @@ jobs:
- name: "Build library: ${{ matrix.library }}" - name: "Build library: ${{ matrix.library }}"
run: | run: |
SPC_USE_SUDO=yes ./bin/spc doctor --auto-fix SPC_USE_SUDO=yes ./bin/spc doctor --auto-fix
if [ "${{ env.OS }}" = "linux-x86_64" ]; then ./bin/spc build --build-cli --build-micro --build-fpm ${{ matrix.extension }} --debug --with-suggested-libs --with-suggested-exts
./bin/spc install-pkg upx
UPX=--with-upx-pack
elif [ "${{ env.OS }}" = "linux-aarch64" ]; then
./bin/spc install-pkg upx
UPX=--with-upx-pack
fi
./bin/spc build --build-cli --build-micro --build-fpm ${{ matrix.extension }} --debug $UPX --with-suggested-libs --with-suggested-exts

View File

@@ -10,7 +10,7 @@ on:
env: env:
PHP_VERSION: 8.4 PHP_VERSION: 8.4
MICRO_VERSION: 8.4.4 MICRO_VERSION: 8.4.10
jobs: jobs:
build-release-artifacts: build-release-artifacts:
@@ -42,12 +42,13 @@ jobs:
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
- name: "Install PHP for official runners" - name: "Install PHP for official runners"
uses: "shivammathur/setup-php@v2" uses: shivammathur/setup-php@v2
with: with:
coverage: none coverage: none
tools: composer:v2 tools: composer:v2
php-version: "${{ env.PHP_VERSION }}" php-version: "${{ env.PHP_VERSION }}"
ini-values: memory_limit=-1 ini-values: memory_limit=-1
extensions: curl, openssl, mbstring
- name: "Get Composer Cache Directory" - name: "Get Composer Cache Directory"
id: composer-cache id: composer-cache

View File

@@ -123,6 +123,7 @@ jobs:
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
with: with:
php-version: 8.4 php-version: 8.4
extensions: curl, openssl, mbstring
- name: Define - name: Define
id: gendef id: gendef

View File

@@ -32,12 +32,13 @@ jobs:
cp -r config/* docs/.vitepress/config/ cp -r config/* docs/.vitepress/config/
- name: "Install PHP for official runners" - name: "Install PHP for official runners"
uses: "shivammathur/setup-php@v2" uses: shivammathur/setup-php@v2
with: with:
coverage: none coverage: none
tools: composer:v2 tools: composer:v2
php-version: 8.4 php-version: 8.4
ini-values: memory_limit=-1 ini-values: memory_limit=-1
extensions: curl, openssl, mbstring
- name: "Get Composer Cache Directory" - name: "Get Composer Cache Directory"
id: composer-cache id: composer-cache

66
composer.lock generated
View File

@@ -2904,16 +2904,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.76.0", "version": "v3.84.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "0e3c484cef0ae9314b0f85986a36296087432c40" "reference": "38dad0767bf2a9b516b976852200ae722fe984ca"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/0e3c484cef0ae9314b0f85986a36296087432c40", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/38dad0767bf2a9b516b976852200ae722fe984ca",
"reference": "0e3c484cef0ae9314b0f85986a36296087432c40", "reference": "38dad0767bf2a9b516b976852200ae722fe984ca",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2997,7 +2997,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.76.0" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.84.0"
}, },
"funding": [ "funding": [
{ {
@@ -3005,7 +3005,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-06-30T14:15:06+00:00" "time": "2025-07-15T18:21:57+00:00"
}, },
{ {
"name": "humbug/box", "name": "humbug/box",
@@ -3548,16 +3548,16 @@
}, },
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
"version": "1.13.2", "version": "1.13.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/myclabs/DeepCopy.git", "url": "https://github.com/myclabs/DeepCopy.git",
"reference": "d25e62e636b0a9b01e3bdebb7823b474876dd829" "reference": "faed855a7b5f4d4637717c2b3863e277116beb36"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/d25e62e636b0a9b01e3bdebb7823b474876dd829", "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36",
"reference": "d25e62e636b0a9b01e3bdebb7823b474876dd829", "reference": "faed855a7b5f4d4637717c2b3863e277116beb36",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3596,7 +3596,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/myclabs/DeepCopy/issues", "issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.2" "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3"
}, },
"funding": [ "funding": [
{ {
@@ -3604,7 +3604,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-04T14:07:32+00:00" "time": "2025-07-05T12:25:42+00:00"
}, },
{ {
"name": "nikic/iter", "name": "nikic/iter",
@@ -4406,16 +4406,16 @@
}, },
{ {
"name": "phpstan/phpdoc-parser", "name": "phpstan/phpdoc-parser",
"version": "2.1.0", "version": "2.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git", "url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68" "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8",
"reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4447,22 +4447,22 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types", "description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": { "support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues", "issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.1.0" "source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0"
}, },
"time": "2025-02-19T13:28:12+00:00" "time": "2025-07-13T07:04:09+00:00"
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.12.27", "version": "1.12.28",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "3a6e423c076ab39dfedc307e2ac627ef579db162" "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3a6e423c076ab39dfedc307e2ac627ef579db162", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9",
"reference": "3a6e423c076ab39dfedc307e2ac627ef579db162", "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4507,7 +4507,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-05-21T20:51:45+00:00" "time": "2025-07-17T17:15:39+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@@ -4832,16 +4832,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "10.5.47", "version": "10.5.48",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3" "reference": "6e0a2bc39f6fae7617989d690d76c48e6d2eb541"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e0a2bc39f6fae7617989d690d76c48e6d2eb541",
"reference": "3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3", "reference": "6e0a2bc39f6fae7617989d690d76c48e6d2eb541",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4851,7 +4851,7 @@
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-xml": "*", "ext-xml": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.13.1", "myclabs/deep-copy": "^1.13.3",
"phar-io/manifest": "^2.0.4", "phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1", "phar-io/version": "^3.2.1",
"php": ">=8.1", "php": ">=8.1",
@@ -4913,7 +4913,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.47" "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.48"
}, },
"funding": [ "funding": [
{ {
@@ -4937,7 +4937,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-06-20T11:29:11+00:00" "time": "2025-07-11T04:07:17+00:00"
}, },
{ {
"name": "psr/event-dispatcher", "name": "psr/event-dispatcher",
@@ -7628,7 +7628,7 @@
], ],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": [], "stability-flags": {},
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
@@ -7636,6 +7636,6 @@
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-zlib": "*" "ext-zlib": "*"
}, },
"platform-dev": [], "platform-dev": {},
"plugin-api-version": "2.3.0" "plugin-api-version": "2.6.0"
} }

View File

@@ -73,7 +73,7 @@ SPC_EXTRA_LIBS=""
; - musl-native: used for alpine linux, can build `musl` and `musl -dynamic` target. ; - musl-native: used for alpine linux, can build `musl` and `musl -dynamic` target.
; - gnu-native: used for general linux distros, can build gnu target for the installed glibc version only. ; - gnu-native: used for general linux distros, can build gnu target for the installed glibc version only.
; LEGACY option to specify the target, switch to SPC_TARGET with zig toolchain instead ; LEGACY option to specify the target
SPC_LIBC=musl SPC_LIBC=musl
; Recommended: specify your target here. Zig toolchain will be used. ; Recommended: specify your target here. Zig toolchain will be used.
@@ -91,10 +91,8 @@ CXX=${SPC_LINUX_DEFAULT_CXX}
AR=${SPC_LINUX_DEFAULT_AR} AR=${SPC_LINUX_DEFAULT_AR}
LD=${SPC_LINUX_DEFAULT_LD} LD=${SPC_LINUX_DEFAULT_LD}
; default compiler flags, used in CMake toolchain file, openssl and pkg-config build ; default compiler flags, used in CMake toolchain file, openssl and pkg-config build
SPC_DEFAULT_C_FLAGS="-fPIC -Os -Wno-error=date-time" SPC_DEFAULT_C_FLAGS="-fPIC -Os"
SPC_DEFAULT_CXX_FLAGS="-fPIC -Os -Wno-error=date-time" SPC_DEFAULT_CXX_FLAGS="-fPIC -Os"
; extra libs for building php executable, used in `make` command for building php (this value may changed by extension build process, space separated)
SPC_EXTRA_LIBS=
; upx executable path ; upx executable path
UPX_EXEC=${PKG_ROOT_PATH}/bin/upx UPX_EXEC=${PKG_ROOT_PATH}/bin/upx
; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches ; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches
@@ -132,8 +130,6 @@ CXX=clang++
; default compiler flags, used in CMake toolchain file, openssl and pkg-config build ; default compiler flags, used in CMake toolchain file, openssl and pkg-config build
SPC_DEFAULT_C_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os" SPC_DEFAULT_C_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os"
SPC_DEFAULT_CXX_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os" SPC_DEFAULT_CXX_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os"
; extra libs for building php executable, used in `make` command for building php (this value may changed by extension build process, space separated)
SPC_EXTRA_LIBS=
; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches ; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches
SPC_MICRO_PATCHES=cli_checks,macos_iconv SPC_MICRO_PATCHES=cli_checks,macos_iconv

View File

@@ -34,7 +34,7 @@
}, },
"bz2": { "bz2": {
"type": "builtin", "type": "builtin",
"arg-type-unix": "with-prefix", "arg-type-unix": "with-path",
"arg-type-windows": "with", "arg-type-windows": "with",
"lib-depends": [ "lib-depends": [
"bzip2" "bzip2"
@@ -185,7 +185,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"lib-depends": [ "lib-depends": [
"gettext" "gettext"
] ]
@@ -211,7 +211,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"lib-depends": [ "lib-depends": [
"gmp" "gmp"
] ]
@@ -233,7 +233,7 @@
}, },
"type": "external", "type": "external",
"source": "grpc", "source": "grpc",
"arg-type-unix": "custom", "arg-type-unix": "enable-path",
"cpp-extension": true, "cpp-extension": true,
"lib-depends": [ "lib-depends": [
"grpc" "grpc"
@@ -244,7 +244,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"arg-type-windows": "with", "arg-type-windows": "with",
"lib-depends-unix": [ "lib-depends-unix": [
"libiconv" "libiconv"
@@ -320,7 +320,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"lib-depends": [ "lib-depends": [
"ldap" "ldap"
], ],
@@ -530,7 +530,7 @@
}, },
"notes": true, "notes": true,
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"lib-depends": [ "lib-depends": [
"libargon2" "libargon2"
] ]
@@ -572,7 +572,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"arg-type-windows": "custom", "arg-type-windows": "custom",
"ext-depends": [ "ext-depends": [
"pdo", "pdo",
@@ -675,7 +675,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"lib-depends": [ "lib-depends": [
"readline" "readline"
], ],
@@ -786,7 +786,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"arg-type-windows": "with", "arg-type-windows": "with",
"lib-depends": [ "lib-depends": [
"sqlite" "sqlite"
@@ -812,7 +812,7 @@
}, },
"type": "external", "type": "external",
"source": "ext-ssh2", "source": "ext-ssh2",
"arg-type": "with-prefix", "arg-type": "with-path",
"arg-type-windows": "with", "arg-type-windows": "with",
"lib-depends": [ "lib-depends": [
"libssh2" "libssh2"
@@ -938,7 +938,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"lib-depends": [ "lib-depends": [
"tidy" "tidy"
] ]
@@ -954,7 +954,7 @@
}, },
"type": "external", "type": "external",
"source": "ext-uuid", "source": "ext-uuid",
"arg-type": "with-prefix", "arg-type": "with-path",
"lib-depends": [ "lib-depends": [
"libuuid" "libuuid"
] ]
@@ -966,7 +966,7 @@
}, },
"type": "external", "type": "external",
"source": "ext-uv", "source": "ext-uv",
"arg-type": "with-prefix", "arg-type": "with-path",
"lib-depends": [ "lib-depends": [
"libuv" "libuv"
], ],
@@ -1068,7 +1068,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"lib-depends": [ "lib-depends": [
"libxslt" "libxslt"
], ],
@@ -1105,7 +1105,7 @@
}, },
"type": "external", "type": "external",
"source": "yaml", "source": "yaml",
"arg-type-unix": "with-prefix", "arg-type-unix": "with-path",
"arg-type-windows": "with", "arg-type-windows": "with",
"lib-depends": [ "lib-depends": [
"libyaml" "libyaml"
@@ -1116,7 +1116,7 @@
"BSD": "wip" "BSD": "wip"
}, },
"type": "builtin", "type": "builtin",
"arg-type": "with-prefix", "arg-type": "with-path",
"arg-type-windows": "enable", "arg-type-windows": "enable",
"lib-depends-unix": [ "lib-depends-unix": [
"libzip" "libzip"

View File

@@ -35,10 +35,10 @@
}, },
"brotli": { "brotli": {
"source": "brotli", "source": "brotli",
"static-libs-unix": [ "pkg-configs": [
"libbrotlidec.a", "libbrotlicommon",
"libbrotlienc.a", "libbrotlidec",
"libbrotlicommon.a" "libbrotlienc"
], ],
"static-libs-windows": [ "static-libs-windows": [
"brotlicommon.lib", "brotlicommon.lib",
@@ -89,7 +89,8 @@
"nghttp3", "nghttp3",
"ngtcp2", "ngtcp2",
"zstd", "zstd",
"libcares" "libcares",
"ldap"
], ],
"lib-suggests-windows": [ "lib-suggests-windows": [
"brotli", "brotli",
@@ -185,14 +186,15 @@
}, },
"grpc": { "grpc": {
"source": "grpc", "source": "grpc",
"static-libs-unix": [ "pkg-configs": [
"libgrpc.a", "grpc"
"libcares.a"
], ],
"lib-depends": [ "lib-depends": [
"zlib", "zlib",
"openssl" "openssl",
"libcares"
], ],
"provide-pre-built": true,
"frameworks": [ "frameworks": [
"CoreFoundation" "CoreFoundation"
] ]
@@ -200,11 +202,10 @@
"icu": { "icu": {
"source": "icu", "source": "icu",
"cpp-library": true, "cpp-library": true,
"static-libs-unix": [ "pkg-configs": [
"libicui18n.a", "icu-uc",
"libicuio.a", "icu-i18n",
"libicuuc.a", "icu-io"
"libicudata.a"
] ]
}, },
"icu-static-win": { "icu-static-win": {
@@ -221,10 +222,10 @@
}, },
"imagemagick": { "imagemagick": {
"source": "imagemagick", "source": "imagemagick",
"static-libs-unix": [ "pkg-configs": [
"libMagick++-7.Q16HDRI.a", "Magick++-7.Q16HDRI",
"libMagickWand-7.Q16HDRI.a", "MagickCore-7.Q16HDRI",
"libMagickCore-7.Q16HDRI.a" "MagickWand-7.Q16HDRI"
], ],
"lib-depends": [ "lib-depends": [
"zlib", "zlib",
@@ -267,9 +268,9 @@
}, },
"ldap": { "ldap": {
"source": "ldap", "source": "ldap",
"static-libs-unix": [ "pkg-configs": [
"libldap.a", "ldap",
"liblber.a" "lber"
], ],
"lib-depends": [ "lib-depends": [
"openssl", "openssl",
@@ -422,11 +423,11 @@
}, },
"libjxl": { "libjxl": {
"source": "libjxl", "source": "libjxl",
"static-libs-unix": [ "pkg-configs": [
"libjxl.a", "libjxl",
"libjxl_cms.a", "libjxl_cms",
"libjxl_threads.a", "libjxl_threads",
"libhwy.a" "libhwy"
], ],
"lib-depends": [ "lib-depends": [
"brotli", "brotli",
@@ -556,12 +557,12 @@
}, },
"libwebp": { "libwebp": {
"source": "libwebp", "source": "libwebp",
"static-libs-unix": [ "pkg-configs": [
"libwebp.a", "libwebp",
"libwebpdecoder.a", "libwebpdecoder",
"libwebpdemux.a", "libwebpdemux",
"libwebpmux.a", "libwebpmux",
"libsharpyuv.a" "libsharpyuv"
], ],
"static-libs-windows": [ "static-libs-windows": [
"libwebp.lib", "libwebp.lib",
@@ -737,8 +738,8 @@
"openssl": { "openssl": {
"source": "openssl", "source": "openssl",
"static-libs-unix": [ "static-libs-unix": [
"libssl.a", "libcrypto.a",
"libcrypto.a" "libssl.a"
], ],
"static-libs-windows": [ "static-libs-windows": [
"libssl.lib", "libssl.lib",
@@ -753,10 +754,8 @@
}, },
"postgresql": { "postgresql": {
"source": "postgresql", "source": "postgresql",
"static-libs-unix": [ "pkg-configs": [
"libpq.a", "libpq"
"libpgport.a",
"libpgcommon.a"
], ],
"lib-depends": [ "lib-depends": [
"libiconv", "libiconv",

View File

@@ -66,13 +66,17 @@ abstract class BuilderBase
// build all libs // build all libs
foreach ($this->libs as $lib) { foreach ($this->libs as $lib) {
$starttime = microtime(true); $starttime = microtime(true);
match ($lib->setup($this->getOption('rebuild', false))) { $status = $lib->setup($this->getOption('rebuild', false));
match ($status) {
LIB_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] setup success, took ' . round(microtime(true) - $starttime, 2) . ' s'), LIB_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] setup success, took ' . round(microtime(true) - $starttime, 2) . ' s'),
LIB_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'), LIB_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
LIB_STATUS_BUILD_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'), LIB_STATUS_BUILD_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'),
LIB_STATUS_INSTALL_FAILED => logger()->error('lib [' . $lib::NAME . '] install failed'), LIB_STATUS_INSTALL_FAILED => logger()->error('lib [' . $lib::NAME . '] install failed'),
default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'), default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
}; };
if (in_array($status, [LIB_STATUS_BUILD_FAILED, LIB_STATUS_INSTALL_FAILED])) {
throw new RuntimeException('Library [' . $lib::NAME . '] setup failed.');
}
} }
} }

View File

@@ -84,13 +84,15 @@ class Extension
*/ */
public function getEnableArg(bool $shared = false): string public function getEnableArg(bool $shared = false): string
{ {
$escapedPath = str_replace("'", '', escapeshellarg(BUILD_ROOT_PATH)) !== BUILD_ROOT_PATH || str_contains(BUILD_ROOT_PATH, ' ') ? escapeshellarg(BUILD_ROOT_PATH) : BUILD_ROOT_PATH;
$_name = str_replace('_', '-', $this->name); $_name = str_replace('_', '-', $this->name);
return match ($arg_type = Config::getExt($this->name, 'arg-type', 'enable')) { return match ($arg_type = Config::getExt($this->name, 'arg-type', 'enable')) {
'enable' => '--enable-' . $_name . ($shared ? '=shared' : '') . ' ', 'enable' => '--enable-' . $_name . ($shared ? '=shared' : '') . ' ',
'enable-path' => '--enable-' . $_name . '=' . ($shared ? 'shared,' : '') . $escapedPath . ' ',
'with' => '--with-' . $_name . ($shared ? '=shared' : '') . ' ', 'with' => '--with-' . $_name . ($shared ? '=shared' : '') . ' ',
'with-prefix' => '--with-' . $_name . '=' . ($shared ? 'shared,' : '') . '"' . BUILD_ROOT_PATH . '" ', 'with-path' => '--with-' . $_name . '=' . ($shared ? 'shared,' : '') . $escapedPath . ' ',
'none', 'custom' => '', 'none', 'custom' => '',
default => throw new WrongUsageException("argType does not accept {$arg_type}, use [enable/with/with-prefix] ."), default => throw new WrongUsageException("argType does not accept {$arg_type}, use [enable/with/with-path] ."),
}; };
} }

View File

@@ -182,22 +182,8 @@ abstract class LibraryBase
return LIB_STATUS_INSTALL_FAILED; return LIB_STATUS_INSTALL_FAILED;
} }
} }
foreach ($this->getStaticLibs() as $name) { if (!$this->isLibraryInstalled()) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) { return $this->tryInstall($lock, true);
$this->tryInstall($lock, true);
return LIB_STATUS_OK;
}
}
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryInstall($lock, true);
return LIB_STATUS_OK;
}
}
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists
if (static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryInstall($lock, true);
return LIB_STATUS_OK;
} }
return LIB_STATUS_ALREADY; return LIB_STATUS_ALREADY;
} }
@@ -240,28 +226,8 @@ abstract class LibraryBase
return LIB_STATUS_OK; return LIB_STATUS_OK;
} }
// check if these libraries exist, if not, invoke compilation and return the result status if (!$this->isLibraryInstalled()) {
foreach ($this->getStaticLibs() as $name) { return $this->tryBuild(true);
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryBuild(true);
return LIB_STATUS_OK;
}
}
// header files the same
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryBuild(true);
return LIB_STATUS_OK;
}
}
// current library is package and binary file is not exists
if (Config::getLib(static::NAME, 'type', 'lib') === 'package') {
foreach ($this->getBinaryFiles() as $name) {
if (!file_exists(BUILD_BIN_PATH . "/{$name}")) {
$this->tryBuild(true);
return LIB_STATUS_OK;
}
}
} }
// if all the files exist at this point, skip the compilation process // if all the files exist at this point, skip the compilation process
return LIB_STATUS_ALREADY; return LIB_STATUS_ALREADY;
@@ -350,7 +316,27 @@ abstract class LibraryBase
protected function install(): void protected function install(): void
{ {
// do something after extracting pre-built files, default do nothing. overwrite this method to do something // replace placeholders if BUILD_ROOT_PATH/.spc-extract-placeholder.json exists
$replace_item_file = BUILD_ROOT_PATH . '/.spc-extract-placeholder.json';
if (!file_exists($replace_item_file)) {
return;
}
$replace_items = json_decode(file_get_contents($replace_item_file), true);
if (!is_array($replace_items)) {
throw new RuntimeException('Invalid placeholder file: ' . $replace_item_file);
}
$placeholders = get_pack_replace();
// replace placeholders in BUILD_ROOT_PATH
foreach ($replace_items as $item) {
$filepath = BUILD_ROOT_PATH . "/{$item}";
FileSystem::replaceFileStr(
$filepath,
array_values($placeholders),
array_keys($placeholders),
);
}
// remove placeholder file
unlink($replace_item_file);
} }
/** /**
@@ -397,4 +383,29 @@ abstract class LibraryBase
} }
} }
} }
protected function isLibraryInstalled(): bool
{
foreach (Config::getLib(static::NAME, 'static-libs', []) as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
return false;
}
}
foreach (Config::getLib(static::NAME, 'headers', []) as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
return false;
}
}
foreach (Config::getLib(static::NAME, 'pkg-configs', []) as $name) {
if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$name}.pc")) {
return false;
}
}
foreach (Config::getLib(static::NAME, 'bin', []) as $name) {
if (!file_exists(BUILD_BIN_PATH . "/{$name}")) {
return false;
}
}
return true;
}
} }

View File

@@ -5,36 +5,47 @@ declare(strict_types=1);
namespace SPC\builder\extension; namespace SPC\builder\extension;
use SPC\builder\Extension; use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\builder\windows\WindowsBuilder; use SPC\builder\windows\WindowsBuilder;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\util\CustomExt; use SPC\util\CustomExt;
use SPC\util\GlobalEnvManager; use SPC\util\GlobalEnvManager;
use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget;
#[CustomExt('grpc')] #[CustomExt('grpc')]
class grpc extends Extension class grpc extends Extension
{ {
public function patchBeforeBuildconf(): bool public function patchBeforeBuildconf(): bool
{ {
// soft link to the grpc source code
if ($this->builder instanceof WindowsBuilder) { if ($this->builder instanceof WindowsBuilder) {
// not support windows yet
throw new \RuntimeException('grpc extension does not support windows yet'); throw new \RuntimeException('grpc extension does not support windows yet');
} }
if (!is_link(SOURCE_PATH . '/php-src/ext/grpc')) { if (file_exists(SOURCE_PATH . '/php-src/ext/grpc')) {
if (is_dir($this->builder->getLib('grpc')->getSourceDir() . '/src/php/ext/grpc')) { return false;
shell()->exec('ln -s ' . $this->builder->getLib('grpc')->getSourceDir() . '/src/php/ext/grpc ' . SOURCE_PATH . '/php-src/ext/grpc');
} elseif (is_dir(BUILD_ROOT_PATH . '/grpc_php_ext_src')) {
shell()->exec('ln -s ' . BUILD_ROOT_PATH . '/grpc_php_ext_src ' . SOURCE_PATH . '/php-src/ext/grpc');
} else {
throw new \RuntimeException('Cannot find grpc source code');
}
$macos = $this->builder instanceof MacOSBuilder ? "\n" . ' LDFLAGS="$LDFLAGS -framework CoreFoundation"' : '';
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/ext/grpc/config.m4', '/GRPC_LIBDIR=.*$/m', 'GRPC_LIBDIR=' . BUILD_LIB_PATH . $macos);
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/ext/grpc/config.m4', '/SEARCH_PATH=.*$/m', 'SEARCH_PATH="' . BUILD_ROOT_PATH . '"');
return true;
} }
return false; // soft link to the grpc source code
if (is_dir($this->source_dir . '/src/php/ext/grpc')) {
shell()->exec('ln -s ' . $this->source_dir . '/src/php/ext/grpc ' . SOURCE_PATH . '/php-src/ext/grpc');
} else {
throw new \RuntimeException('Cannot find grpc source code');
}
if (SPCTarget::getTargetOS() === 'Darwin') {
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/ext/grpc/config.m4',
'/GRPC_LIBDIR=.*$/m',
'GRPC_LIBDIR=' . BUILD_LIB_PATH . "\n" . 'LDFLAGS="$LDFLAGS -framework CoreFoundation"'
);
}
return true;
}
public function patchBeforeConfigure(): bool
{
$util = new SPCConfigUtil($this->builder, ['libs_only_deps' => true]);
$config = $util->config(['grpc']);
$libs = $config['libs'];
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/configure', '-lgrpc', $libs);
return true;
} }
public function patchBeforeMake(): bool public function patchBeforeMake(): bool
@@ -44,9 +55,4 @@ class grpc extends Extension
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -Wno-strict-prototypes'); GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -Wno-strict-prototypes');
return true; return true;
} }
public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-grpc=' . BUILD_ROOT_PATH . '/grpc GRPC_LIB_SUBDIR=' . BUILD_LIB_PATH;
}
} }

View File

@@ -63,18 +63,6 @@ class BSDBuilder extends UnixBuilderBase
*/ */
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
{ {
// ---------- Update extra-libs ----------
$extra_libs = $this->getOption('extra-libs', '');
// add libc++, some extensions or libraries need it (C++ cannot be linked statically)
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lc++ ' : '');
if (!$this->getOption('bloat', false)) {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles());
} else {
logger()->info('bloat linking');
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Wl,-force_load,{$x}", array_filter($this->getAllStaticLibFiles())));
}
$this->setOption('extra-libs', $extra_libs);
$this->emitPatchPoint('before-php-buildconf'); $this->emitPatchPoint('before-php-buildconf');
SourcePatcher::patchBeforeBuildconf($this); SourcePatcher::patchBeforeBuildconf($this);

View File

@@ -9,13 +9,4 @@ class curl extends BSDLibraryBase
use \SPC\builder\unix\library\curl; use \SPC\builder\unix\library\curl;
public const NAME = 'curl'; public const NAME = 'curl';
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true, bool $include_self = true): string
{
$libs = parent::getStaticLibFiles($style, $recursive, $include_self);
if ($this->builder->getLib('openssl')) {
$this->builder->setOption('extra-libs', $this->builder->getOption('extra-libs') . ' /usr/lib/libpthread.a /usr/lib/libdl.a');
}
return $libs;
}
} }

View File

@@ -11,6 +11,7 @@ use SPC\exception\WrongUsageException;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\store\SourcePatcher; use SPC\store\SourcePatcher;
use SPC\util\GlobalEnvManager; use SPC\util\GlobalEnvManager;
use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget; use SPC\util\SPCTarget;
class LinuxBuilder extends UnixBuilderBase class LinuxBuilder extends UnixBuilderBase
@@ -50,17 +51,6 @@ class LinuxBuilder extends UnixBuilderBase
*/ */
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
{ {
// ---------- Update extra-libs ----------
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
// bloat means force-load all static libraries, even if they are not used
if (!$this->getOption('bloat', false)) {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles());
} else {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", array_filter($this->getAllStaticLibFiles())));
}
// add libstdc++, some extensions or libraries need it
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lstdc++ ' : '');
f_putenv('SPC_EXTRA_LIBS=' . $extra_libs);
$cflags = $this->arch_c_flags; $cflags = $this->arch_c_flags;
f_putenv('CFLAGS=' . $cflags); f_putenv('CFLAGS=' . $cflags);
@@ -97,13 +87,13 @@ class LinuxBuilder extends UnixBuilderBase
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED; $enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
$enableFrankenphp = ($build_target & BUILD_TARGET_FRANKENPHP) === BUILD_TARGET_FRANKENPHP; $enableFrankenphp = ($build_target & BUILD_TARGET_FRANKENPHP) === BUILD_TARGET_FRANKENPHP;
$mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : '';
// prepare build php envs // prepare build php envs
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
$envs_build_php = SystemUtil::makeEnvVarString([ $envs_build_php = SystemUtil::makeEnvVarString([
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'), 'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'), 'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'),
'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'), 'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'),
'LIBS' => $mimallocLibs . SPCTarget::getRuntimeLibs(), 'LIBS' => $config['libs'],
]); ]);
$embed_type = getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') ?: 'static'; $embed_type = getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') ?: 'static';
@@ -341,9 +331,10 @@ class LinuxBuilder extends UnixBuilderBase
private function getMakeExtraVars(): array private function getMakeExtraVars(): array
{ {
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true, 'absolute_libs' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
return [ return [
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), 'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'EXTRA_LIBS' => getenv('SPC_EXTRA_LIBS') . ' ' . SPCTarget::getRuntimeLibs(), 'EXTRA_LIBS' => $config['libs'] . ' ' . SPCTarget::getRuntimeLibs(),
'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), 'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'),
'EXTRA_LDFLAGS_PROGRAM' => SPCTarget::isStatic() ? '-all-static -pie' : '-pie', 'EXTRA_LDFLAGS_PROGRAM' => SPCTarget::isStatic() ? '-all-static -pie' : '-pie',
]; ];

View File

@@ -9,13 +9,4 @@ class curl extends LinuxLibraryBase
use \SPC\builder\unix\library\curl; use \SPC\builder\unix\library\curl;
public const NAME = 'curl'; public const NAME = 'curl';
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true, bool $include_self = true): string
{
$libs = parent::getStaticLibFiles($style, $recursive, $include_self);
if ($this->builder->getLib('openssl')) {
$libs .= ' -ldl -lpthread';
}
return $libs;
}
} }

View File

@@ -38,7 +38,7 @@ class icu extends LinuxLibraryBase
->exec("make -j{$this->builder->concurrency}") ->exec("make -j{$this->builder->concurrency}")
->exec('make install'); ->exec('make install');
$this->patchPkgconfPrefix(['icu-i18n.pc', 'icu-io.pc', 'icu-uc.pc'], PKGCONF_PATCH_PREFIX); $this->patchPkgconfPrefix(patch_option: PKGCONF_PATCH_PREFIX);
FileSystem::removeDir(BUILD_LIB_PATH . '/icu'); FileSystem::removeDir(BUILD_LIB_PATH . '/icu');
} }
} }

View File

@@ -64,8 +64,8 @@ class openssl extends LinuxLibraryBase
shell()->cd($this->source_dir)->initializeEnv($this) shell()->cd($this->source_dir)->initializeEnv($this)
->exec( ->exec(
"{$env} ./Configure no-shared {$extra} " . "{$env} ./Configure no-shared {$extra} " .
'--prefix=/ ' . '--prefix=' . BUILD_ROOT_PATH . ' ' .
'--libdir=lib ' . '--libdir=' . BUILD_LIB_PATH . ' ' .
'--openssldir=/etc/ssl ' . '--openssldir=/etc/ssl ' .
"{$zlib_extra}" . "{$zlib_extra}" .
'enable-pie ' . 'enable-pie ' .
@@ -74,28 +74,19 @@ class openssl extends LinuxLibraryBase
) )
->exec('make clean') ->exec('make clean')
->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"") ->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"")
->exec("make install_sw DESTDIR={$destdir}"); ->exec('make install_sw');
$this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']); $this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']);
// patch for openssl 3.3.0+ // patch for openssl 3.3.0+
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
} }
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
} }
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
} }
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Libs.private: ${libdir}/libz.a'); FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Libs.private: ${libdir}/libz.a');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")'); FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")');
} }
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true, bool $include_self = true): string
{
$libFiles = parent::getStaticLibFiles($style, $recursive, $include_self);
if (!str_contains('-ldl -lpthread', $libFiles)) {
$libFiles .= ' -ldl -lpthread';
}
return $libFiles;
}
} }

View File

@@ -12,7 +12,7 @@ use SPC\exception\WrongUsageException;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\store\SourcePatcher; use SPC\store\SourcePatcher;
use SPC\util\GlobalEnvManager; use SPC\util\GlobalEnvManager;
use SPC\util\SPCTarget; use SPC\util\SPCConfigUtil;
class MacOSBuilder extends UnixBuilderBase class MacOSBuilder extends UnixBuilderBase
{ {
@@ -34,7 +34,7 @@ class MacOSBuilder extends UnixBuilderBase
// ---------- set necessary compile vars ---------- // ---------- set necessary compile vars ----------
// concurrency // concurrency
$this->concurrency = (int) getenv('SPC_CONCURRENCY'); $this->concurrency = intval(getenv('SPC_CONCURRENCY'));
// cflags // cflags
$this->arch_c_flags = getenv('SPC_DEFAULT_C_FLAGS'); $this->arch_c_flags = getenv('SPC_DEFAULT_C_FLAGS');
$this->arch_cxx_flags = getenv('SPC_DEFAULT_CXX_FLAGS'); $this->arch_cxx_flags = getenv('SPC_DEFAULT_CXX_FLAGS');
@@ -132,7 +132,7 @@ class MacOSBuilder extends UnixBuilderBase
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'), 'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'), 'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'),
'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'), 'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'),
'LIBS' => $mimallocLibs . SPCTarget::getRuntimeLibs(), 'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'),
]); ]);
if ($this->getLib('postgresql')) { if ($this->getLib('postgresql')) {
@@ -292,9 +292,10 @@ class MacOSBuilder extends UnixBuilderBase
private function getMakeExtraVars(): array private function getMakeExtraVars(): array
{ {
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
return [ return [
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), 'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'EXTRA_LIBS' => getenv('SPC_EXTRA_LIBS') . ' ' . SPCTarget::getRuntimeLibs(), 'EXTRA_LIBS' => $config['libs'],
]; ];
} }
} }

View File

@@ -21,7 +21,7 @@ class icu extends MacOSLibraryBase
->exec("make -j{$this->builder->concurrency}") ->exec("make -j{$this->builder->concurrency}")
->exec('make install'); ->exec('make install');
$this->patchPkgconfPrefix(['icu-i18n.pc', 'icu-io.pc', 'icu-uc.pc'], PKGCONF_PATCH_PREFIX); $this->patchPkgconfPrefix(patch_option: PKGCONF_PATCH_PREFIX);
FileSystem::removeDir(BUILD_LIB_PATH . '/icu'); FileSystem::removeDir(BUILD_LIB_PATH . '/icu');
} }
} }

View File

@@ -37,8 +37,6 @@ class openssl extends MacOSLibraryBase
*/ */
protected function build(): void protected function build(): void
{ {
[$lib,,$destdir] = SEPARATED_PATH;
// lib:zlib // lib:zlib
$extra = ''; $extra = '';
$ex_lib = ''; $ex_lib = '';
@@ -52,24 +50,24 @@ class openssl extends MacOSLibraryBase
shell()->cd($this->source_dir)->initializeEnv($this) shell()->cd($this->source_dir)->initializeEnv($this)
->exec( ->exec(
"./Configure no-shared {$extra} " . "./Configure no-shared {$extra} " .
'--prefix=/ ' . // use prefix=/ '--prefix=' . BUILD_ROOT_PATH . ' ' . // use prefix=/
"--libdir={$lib} " . '--libdir=lib ' .
'--openssldir=/etc/ssl ' . '--openssldir=/etc/ssl ' .
"darwin64-{$arch}-cc" "darwin64-{$arch}-cc"
) )
->exec('make clean') ->exec('make clean')
->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"") ->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"")
->exec("make install_sw DESTDIR={$destdir}"); ->exec('make install_sw');
$this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']); $this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']);
// patch for openssl 3.3.0+ // patch for openssl 3.3.0+
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
} }
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
} }
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
} }
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Libs.private: ${libdir}/libz.a'); FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Libs.private: ${libdir}/libz.a');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")'); FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")');

View File

@@ -4,11 +4,12 @@ declare(strict_types=1);
namespace SPC\builder\traits; namespace SPC\builder\traits;
use SPC\builder\LibraryBase;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\util\SPCConfigUtil;
trait UnixLibraryTrait trait UnixLibraryTrait
{ {
@@ -17,44 +18,13 @@ trait UnixLibraryTrait
* @throws FileSystemException * @throws FileSystemException
* @throws WrongUsageException * @throws WrongUsageException
*/ */
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true, bool $include_self = true): string public function getStaticLibFiles(bool $include_self = true): string
{ {
$libs = $include_self ? [$this] : []; $libs = $include_self ? [$this] : [];
if ($recursive) { array_unshift($libs, ...array_values($this->getDependencies(recursive: true)));
array_unshift($libs, ...array_values($this->getDependencies(recursive: true))); $config = new SPCConfigUtil($this->builder, options: ['libs_only_deps' => true, 'absolute_libs' => true]);
} $res = $config->config(libraries: array_map(fn ($x) => $x->getName(), $libs));
return $res['libs'];
$sep = match ($style) {
'autoconf' => ' ',
'cmake' => ';',
default => throw new RuntimeException('style only support autoconf and cmake'),
};
$ret = [];
/** @var LibraryBase $lib */
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);
}
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function makeAutoconfEnv(?string $prefix = null): string
{
if ($prefix === null) {
$prefix = str_replace('-', '_', strtoupper(static::NAME));
}
return $prefix . '_CFLAGS="-I' . BUILD_INCLUDE_PATH . '" ' .
$prefix . '_LIBS="' . $this->getStaticLibFiles() . '"';
} }
/** /**
@@ -64,9 +34,12 @@ trait UnixLibraryTrait
* @throws FileSystemException * @throws FileSystemException
* @throws RuntimeException * @throws RuntimeException
*/ */
public function patchPkgconfPrefix(array $files, int $patch_option = PKGCONF_PATCH_ALL, ?array $custom_replace = null): void public function patchPkgconfPrefix(array $files = [], int $patch_option = PKGCONF_PATCH_ALL, ?array $custom_replace = null): void
{ {
logger()->info('Patching library [' . static::NAME . '] pkgconfig'); logger()->info('Patching library [' . static::NAME . '] pkgconfig');
if ($files === [] && ($conf_pc = Config::getLib(static::NAME, 'pkg-configs', [])) !== []) {
$files = array_map(fn ($x) => "{$x}.pc", $conf_pc);
}
foreach ($files as $name) { foreach ($files as $name) {
$realpath = realpath(BUILD_ROOT_PATH . '/lib/pkgconfig/' . $name); $realpath = realpath(BUILD_ROOT_PATH . '/lib/pkgconfig/' . $name);
if ($realpath === false) { if ($realpath === false) {
@@ -75,7 +48,7 @@ trait UnixLibraryTrait
logger()->debug('Patching ' . $realpath); logger()->debug('Patching ' . $realpath);
// replace prefix // replace prefix
$file = FileSystem::readFile($realpath); $file = FileSystem::readFile($realpath);
$file = ($patch_option & PKGCONF_PATCH_PREFIX) === PKGCONF_PATCH_PREFIX ? preg_replace('/^prefix\s*=.*$/m', 'prefix=${pcfiledir}/../..', $file) : $file; $file = ($patch_option & PKGCONF_PATCH_PREFIX) === PKGCONF_PATCH_PREFIX ? preg_replace('/^prefix\s*=.*$/m', 'prefix=' . BUILD_ROOT_PATH, $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_EXEC_PREFIX) === PKGCONF_PATCH_EXEC_PREFIX ? preg_replace('/^exec_prefix\s*=.*$/m', 'exec_prefix=${prefix}', $file) : $file; $file = ($patch_option & PKGCONF_PATCH_EXEC_PREFIX) === PKGCONF_PATCH_EXEC_PREFIX ? preg_replace('/^exec_prefix\s*=.*$/m', 'exec_prefix=${prefix}', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_LIBDIR) === PKGCONF_PATCH_LIBDIR ? preg_replace('/^libdir\s*=.*$/m', 'libdir=${prefix}/lib', $file) : $file; $file = ($patch_option & PKGCONF_PATCH_LIBDIR) === PKGCONF_PATCH_LIBDIR ? preg_replace('/^libdir\s*=.*$/m', 'libdir=${prefix}/lib', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_INCLUDEDIR) === PKGCONF_PATCH_INCLUDEDIR ? preg_replace('/^includedir\s*=.*$/m', 'includedir=${prefix}/include', $file) : $file; $file = ($patch_option & PKGCONF_PATCH_INCLUDEDIR) === PKGCONF_PATCH_INCLUDEDIR ? preg_replace('/^includedir\s*=.*$/m', 'includedir=${prefix}/include', $file) : $file;

View File

@@ -5,9 +5,6 @@ declare(strict_types=1);
namespace SPC\builder\unix; namespace SPC\builder\unix;
use SPC\builder\BuilderBase; use SPC\builder\BuilderBase;
use SPC\builder\freebsd\library\BSDLibraryBase;
use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
@@ -29,85 +26,6 @@ abstract class UnixBuilderBase extends BuilderBase
/** @var string C++ flags */ /** @var string C++ flags */
public string $arch_cxx_flags; public string $arch_cxx_flags;
/**
* @throws WrongUsageException
* @throws FileSystemException
*/
public function getAllStaticLibFiles(): array
{
$libs = [];
// reorder libs
foreach ($this->libs as $lib) {
foreach ($lib->getDependencies() as $dep) {
$libs[] = $dep;
}
$libs[] = $lib;
}
$libFiles = [];
$libNames = [];
// merge libs
foreach ($libs as $lib) {
if (!in_array($lib::NAME, $libNames, true)) {
$libNames[] = $lib::NAME;
array_unshift($libFiles, ...$lib->getStaticLibs());
}
}
return array_map(fn ($x) => realpath(BUILD_LIB_PATH . "/{$x}"), $libFiles);
}
/**
* Generate configure flags
*/
public function makeAutoconfFlags(int $flag = AUTOCONF_ALL): string
{
$extra = '';
// TODO: add auto pkg-config support
if (($flag & AUTOCONF_LIBS) === AUTOCONF_LIBS) {
$extra .= 'LIBS="' . BUILD_LIB_PATH . '" ';
}
if (($flag & AUTOCONF_CFLAGS) === AUTOCONF_CFLAGS) {
$extra .= 'CFLAGS="-I' . BUILD_INCLUDE_PATH . '" ';
}
if (($flag & AUTOCONF_CPPFLAGS) === AUTOCONF_CPPFLAGS) {
$extra .= 'CPPFLAGS="-I' . BUILD_INCLUDE_PATH . '" ';
}
if (($flag & AUTOCONF_LDFLAGS) === AUTOCONF_LDFLAGS) {
$extra .= 'LDFLAGS="-L' . BUILD_LIB_PATH . '" ';
}
return $extra;
}
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function makeAutoconfArgs(string $name, array $libSpecs): string
{
$ret = '';
foreach ($libSpecs as $libName => $arr) {
$lib = $this->getLib($libName);
if ($lib === null && str_starts_with($libName, 'lib')) {
$lib = $this->getLib(substr($libName, 3));
}
$arr = $arr ?? [];
$disableArgs = $arr[0] ?? null;
$prefix = $arr[1] ?? null;
if ($lib instanceof LinuxLibraryBase || $lib instanceof MacOSLibraryBase || $lib instanceof BSDLibraryBase) {
logger()->info("{$name} \033[32;1mwith\033[0;1m {$libName} support");
$ret .= "--with-{$libName}=yes " . $lib->makeAutoconfEnv($prefix) . ' ';
} else {
logger()->info("{$name} \033[31;1mwithout\033[0;1m {$libName} support");
$ret .= ($disableArgs ?? "--with-{$libName}=no") . ' ';
}
}
return rtrim($ret);
}
public function proveLibs(array $sorted_libraries): void public function proveLibs(array $sorted_libraries): void
{ {
// search all supported libs // search all supported libs
@@ -233,8 +151,9 @@ abstract class UnixBuilderBase extends BuilderBase
if (!file_exists($frankenphp)) { if (!file_exists($frankenphp)) {
throw new RuntimeException('FrankenPHP binary not found: ' . $frankenphp); throw new RuntimeException('FrankenPHP binary not found: ' . $frankenphp);
} }
$prefix = PHP_OS_FAMILY === 'Darwin' ? 'DYLD_' : 'LD_';
[$ret, $output] = shell() [$ret, $output] = shell()
->setEnv(['LD_LIBRARY_PATH' => BUILD_LIB_PATH]) ->setEnv(["{$prefix}LIBRARY_PATH" => BUILD_LIB_PATH])
->execWithResult("{$frankenphp} version"); ->execWithResult("{$frankenphp} version");
if ($ret !== 0 || !str_contains(implode('', $output), 'FrankenPHP')) { if ($ret !== 0 || !str_contains(implode('', $output), 'FrankenPHP')) {
throw new RuntimeException('FrankenPHP failed sanity check: ret[' . $ret . ']. out[' . implode('', $output) . ']'); throw new RuntimeException('FrankenPHP failed sanity check: ret[' . $ret . ']. out[' . implode('', $output) . ']');

View File

@@ -21,10 +21,10 @@ trait curl
UnixCMakeExecutor::create($this) UnixCMakeExecutor::create($this)
->optionalLib('openssl', '-DCURL_USE_OPENSSL=ON -DCURL_CA_BUNDLE=OFF -DCURL_CA_PATH=OFF -DCURL_CA_FALLBACK=ON', '-DCURL_USE_OPENSSL=OFF -DCURL_ENABLE_SSL=OFF') ->optionalLib('openssl', '-DCURL_USE_OPENSSL=ON -DCURL_CA_BUNDLE=OFF -DCURL_CA_PATH=OFF -DCURL_CA_FALLBACK=ON', '-DCURL_USE_OPENSSL=OFF -DCURL_ENABLE_SSL=OFF')
->optionalLib('brotli', ...cmake_boolean_args('CURL_BROTLI')) ->optionalLib('brotli', ...cmake_boolean_args('CURL_BROTLI'))
->optionalLib('libssh2', fn ($lib) => "-DLIBSSH2_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DLIBSSH2_INCLUDE_DIR={$lib->getIncludeDir()}", '-DCURL_USE_LIBSSH2=OFF') ->optionalLib('libssh2', ...cmake_boolean_args('CURL_USE_LIBSSH2'))
->optionalLib('nghttp2', fn ($lib) => "-DUSE_NGHTTP2=ON -DNGHTTP2_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DNGHTTP2_INCLUDE_DIR={$lib->getIncludeDir()}", '-DUSE_NGHTTP2=OFF') ->optionalLib('nghttp2', ...cmake_boolean_args('USE_NGHTTP2'))
->optionalLib('nghttp3', fn ($lib) => "-DUSE_NGHTTP3=ON -DNGHTTP3_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DNGHTTP3_INCLUDE_DIR={$lib->getIncludeDir()}", '-DUSE_NGHTTP3=OFF') ->optionalLib('nghttp3', ...cmake_boolean_args('USE_NGHTTP3'))
->optionalLib('ngtcp2', fn ($lib) => "-DUSE_NGTCP2=ON -DNGNGTCP2_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DNGNGTCP2_INCLUDE_DIR={$lib->getIncludeDir()}", '-DUSE_NGTCP2=OFF') ->optionalLib('ngtcp2', ...cmake_boolean_args('USE_NGTCP2'))
->optionalLib('ldap', ...cmake_boolean_args('CURL_DISABLE_LDAP', true)) ->optionalLib('ldap', ...cmake_boolean_args('CURL_DISABLE_LDAP', true))
->optionalLib('zstd', ...cmake_boolean_args('CURL_ZSTD')) ->optionalLib('zstd', ...cmake_boolean_args('CURL_ZSTD'))
->optionalLib('idn2', ...cmake_boolean_args('USE_LIBIDN2')) ->optionalLib('idn2', ...cmake_boolean_args('USE_LIBIDN2'))

View File

@@ -4,22 +4,55 @@ declare(strict_types=1);
namespace SPC\builder\unix\library; namespace SPC\builder\unix\library;
use SPC\builder\linux\SystemUtil;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\util\executor\UnixCMakeExecutor;
use SPC\util\SPCTarget;
trait grpc trait grpc
{ {
public function patchBeforeBuild(): bool
{
FileSystem::replaceFileStr(
$this->source_dir . '/third_party/re2/util/pcre.h',
["#define UTIL_PCRE_H_\n#include <stdint.h>", '#define UTIL_PCRE_H_'],
['#define UTIL_PCRE_H_', "#define UTIL_PCRE_H_\n#include <stdint.h>"],
);
return true;
}
protected function build(): void protected function build(): void
{ {
shell()->cd($this->source_dir) $cmake = UnixCMakeExecutor::create($this)
->exec('EXTRA_DEFINES=GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK EMBED_OPENSSL=false CXXFLAGS="-L' . BUILD_LIB_PATH . ' -I' . BUILD_INCLUDE_PATH . '" make static -j' . $this->builder->concurrency); ->setBuildDir("{$this->source_dir}/avoid_BUILD_file_conflict")
copy($this->source_dir . '/libs/opt/libgrpc.a', BUILD_LIB_PATH . '/libgrpc.a'); ->addConfigureArgs(
copy($this->source_dir . '/libs/opt/libboringssl.a', BUILD_LIB_PATH . '/libboringssl.a'); '-DgRPC_INSTALL_BINDIR=' . BUILD_BIN_PATH,
if (!file_exists(BUILD_LIB_PATH . '/libcares.a')) { '-DgRPC_INSTALL_LIBDIR=' . BUILD_LIB_PATH,
copy($this->source_dir . '/libs/opt/libcares.a', BUILD_LIB_PATH . '/libcares.a'); '-DgRPC_INSTALL_SHAREDIR=' . BUILD_ROOT_PATH . '/share/grpc',
'-DCMAKE_C_FLAGS="-DGRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK -L' . BUILD_LIB_PATH . ' -I' . BUILD_INCLUDE_PATH . '"',
'-DCMAKE_CXX_FLAGS="-DGRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK -L' . BUILD_LIB_PATH . ' -I' . BUILD_INCLUDE_PATH . '"',
'-DgRPC_BUILD_CODEGEN=OFF',
'-DgRPC_DOWNLOAD_ARCHIVES=OFF',
'-DgRPC_BUILD_TESTS=OFF',
// providers
'-DgRPC_ZLIB_PROVIDER=package',
'-DgRPC_CARES_PROVIDER=package',
'-DgRPC_SSL_PROVIDER=package',
);
if (PHP_OS_FAMILY === 'Linux' && SPCTarget::isStatic() && !SystemUtil::isMuslDist()) {
$cmake->addConfigureArgs(
'-DCMAKE_EXE_LINKER_FLAGS="-static-libgcc -static-libstdc++"',
'-DCMAKE_SHARED_LINKER_FLAGS="-static-libgcc -static-libstdc++"',
'-DCMAKE_CXX_STANDARD_LIBRARIES="-static-libgcc -static-libstdc++"',
);
} }
FileSystem::copyDir($this->source_dir . '/include/grpc', BUILD_INCLUDE_PATH . '/grpc');
FileSystem::copyDir($this->source_dir . '/include/grpc++', BUILD_INCLUDE_PATH . '/grpc++'); $cmake->build();
FileSystem::copyDir($this->source_dir . '/include/grpcpp', BUILD_INCLUDE_PATH . '/grpcpp');
FileSystem::copyDir($this->source_dir . '/src/php/ext/grpc', BUILD_ROOT_PATH . '/grpc_php_ext_src'); $re2Content = file_get_contents($this->source_dir . '/third_party/re2/re2.pc');
$re2Content = 'prefix=' . BUILD_ROOT_PATH . "\nexec_prefix=\${prefix}\n" . $re2Content;
file_put_contents(BUILD_LIB_PATH . '/pkgconfig/re2.pc', $re2Content);
$this->patchPkgconfPrefix(['grpc++.pc', 'grpc.pc', 'grpc++_unsecure.pc', 'grpc_unsecure.pc', 're2.pc']);
} }
} }

View File

@@ -17,6 +17,7 @@ trait icu
protected function install(): void protected function install(): void
{ {
parent::install();
$icu_config = BUILD_ROOT_PATH . '/bin/icu-config'; $icu_config = BUILD_ROOT_PATH . '/bin/icu-config';
FileSystem::replaceFileStr($icu_config, '{BUILD_ROOT_PATH}', BUILD_ROOT_PATH); FileSystem::replaceFileStr($icu_config, '{BUILD_ROOT_PATH}', BUILD_ROOT_PATH);
} }

View File

@@ -68,6 +68,7 @@ trait libevent
protected function install(): void protected function install(): void
{ {
parent::install();
FileSystem::replaceFileStr( FileSystem::replaceFileStr(
BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake', BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake',
'{BUILD_ROOT_PATH}', '{BUILD_ROOT_PATH}',

View File

@@ -22,8 +22,7 @@ trait libwebp
->addConfigureArgs('-DWEBP_BUILD_EXTRAS=ON') ->addConfigureArgs('-DWEBP_BUILD_EXTRAS=ON')
->build(); ->build();
// patch pkgconfig // patch pkgconfig
$this->patchPkgconfPrefix(['libsharpyuv.pc', 'libwebp.pc', 'libwebpdecoder.pc', 'libwebpdemux.pc', 'libwebpmux.pc'], PKGCONF_PATCH_PREFIX | PKGCONF_PATCH_LIBDIR); $this->patchPkgconfPrefix(patch_option: PKGCONF_PATCH_PREFIX | PKGCONF_PATCH_LIBDIR);
$this->patchPkgconfPrefix(['libsharpyuv.pc'], PKGCONF_PATCH_CUSTOM, ['/^includedir=.*$/m', 'includedir=${prefix}/include/webp']); $this->patchPkgconfPrefix(['libsharpyuv.pc'], PKGCONF_PATCH_CUSTOM, ['/^includedir=.*$/m', 'includedir=${prefix}/include/webp']);
$this->patchPkgconfPrefix(['libwebp.pc'], PKGCONF_PATCH_CUSTOM, ['/-lwebp$/m', '-lwebp -lsharpyuv']);
} }
} }

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\unix\library; namespace SPC\builder\unix\library;
use SPC\builder\linux\library\LinuxLibraryBase; use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
@@ -20,11 +21,12 @@ trait libxslt
protected function build(): void protected function build(): void
{ {
$static_libs = $this instanceof LinuxLibraryBase ? $this->getStaticLibFiles(include_self: false) : ''; $static_libs = $this instanceof LinuxLibraryBase ? $this->getStaticLibFiles(include_self: false) : '';
$cpp = $this instanceof MacOSLibraryBase ? '-lc++' : '-lstdc++';
$ac = UnixAutoconfExecutor::create($this) $ac = UnixAutoconfExecutor::create($this)
->appendEnv([ ->appendEnv([
'CFLAGS' => "-I{$this->getIncludeDir()}", 'CFLAGS' => "-I{$this->getIncludeDir()}",
'LDFLAGS' => "-L{$this->getLibDir()}", 'LDFLAGS' => "-L{$this->getLibDir()}",
'LIBS' => "{$static_libs} -lstdc++", 'LIBS' => "{$static_libs} {$cpp}",
]) ])
->addConfigureArgs( ->addConfigureArgs(
'--without-python', '--without-python',
@@ -41,7 +43,7 @@ trait libxslt
} }
$ac->configure()->make(); $ac->configure()->make();
$this->patchPkgconfPrefix(['libexslt.pc']); $this->patchPkgconfPrefix(['libexslt.pc', 'libxslt.pc']);
$this->patchLaDependencyPrefix(); $this->patchLaDependencyPrefix();
shell()->cd(BUILD_LIB_PATH) shell()->cd(BUILD_LIB_PATH)
->exec("ar -t libxslt.a | grep '\\.a$' | xargs -n1 ar d libxslt.a") ->exec("ar -t libxslt.a | grep '\\.a$' | xargs -n1 ar d libxslt.a")

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace SPC\builder\unix\library; namespace SPC\builder\unix\library;
use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
@@ -19,7 +21,7 @@ trait ngtcp2
protected function build(): void protected function build(): void
{ {
UnixAutoconfExecutor::create($this) UnixAutoconfExecutor::create($this)
->optionalLib('openssl', fn ($lib) => implode(' ', [ ->optionalLib('openssl', fn (LinuxLibraryBase|MacOSLibraryBase $lib) => implode(' ', [
'--with-openssl=yes', '--with-openssl=yes',
"OPENSSL_LIBS=\"{$lib->getStaticLibFiles()}\"", "OPENSSL_LIBS=\"{$lib->getStaticLibFiles()}\"",
"OPENSSL_CFLAGS=\"-I{$lib->getIncludeDir()}\"", "OPENSSL_CFLAGS=\"-I{$lib->getIncludeDir()}\"",
@@ -29,7 +31,7 @@ trait ngtcp2
->optionalLib('jemalloc', ...ac_with_args('jemalloc', true)) ->optionalLib('jemalloc', ...ac_with_args('jemalloc', true))
->optionalLib( ->optionalLib(
'brotli', 'brotli',
fn ($lib) => implode(' ', [ fn (LinuxLibraryBase|MacOSLibraryBase $lib) => implode(' ', [
'--with-brotlidec=yes', '--with-brotlidec=yes',
"LIBBROTLIDEC_CFLAGS=\"-I{$lib->getIncludeDir()}\"", "LIBBROTLIDEC_CFLAGS=\"-I{$lib->getIncludeDir()}\"",
"LIBBROTLIDEC_LIBS=\"{$lib->getStaticLibFiles()}\"", "LIBBROTLIDEC_LIBS=\"{$lib->getStaticLibFiles()}\"",

View File

@@ -21,6 +21,7 @@ trait xz
'--disable-scripts', '--disable-scripts',
'--disable-doc', '--disable-doc',
'--with-libiconv', '--with-libiconv',
'--bindir=/tmp/xz', // xz binary will corrupt `tar` command, that's really strange.
) )
->make(); ->make();
$this->patchPkgconfPrefix(['liblzma.pc']); $this->patchPkgconfPrefix(['liblzma.pc']);

View File

@@ -18,7 +18,6 @@ abstract class BuildCommand extends BaseCommand
} }
$this->addOption('with-clean', null, null, 'fresh build, remove `source` and `buildroot` dir before build'); $this->addOption('with-clean', null, null, 'fresh build, remove `source` and `buildroot` dir before build');
$this->addOption('bloat', null, null, 'add all libraries into binary');
$this->addOption('rebuild', 'r', null, 'Delete old build and rebuild'); $this->addOption('rebuild', 'r', null, 'Delete old build and rebuild');
$this->addOption('enable-zts', null, null, 'enable ZTS support'); $this->addOption('enable-zts', null, null, 'enable ZTS support');
} }

View File

@@ -23,6 +23,9 @@ class SPCConfigCommand extends BaseCommand
$this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts'); $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('includes', null, null, 'Add additional include path');
$this->addOption('libs', null, null, 'Add additional libs path'); $this->addOption('libs', null, null, 'Add additional libs path');
$this->addOption('libs-only-deps', null, null, 'Output dependent libraries with -l prefix');
$this->addOption('absolute-libs', null, null, 'Output absolute paths for libraries');
$this->addOption('no-php', null, null, 'Do not link to PHP library');
} }
/** /**
@@ -37,16 +40,19 @@ class SPCConfigCommand extends BaseCommand
$include_suggest_ext = $this->getOption('with-suggested-exts'); $include_suggest_ext = $this->getOption('with-suggested-exts');
$include_suggest_lib = $this->getOption('with-suggested-libs'); $include_suggest_lib = $this->getOption('with-suggested-libs');
$util = new SPCConfigUtil(); $util = new SPCConfigUtil(options: [
'no_php' => $this->getOption('no-php'),
'libs_only_deps' => $this->getOption('libs-only-deps'),
'absolute_libs' => $this->getOption('absolute-libs'),
]);
$config = $util->config($extensions, $libraries, $include_suggest_ext, $include_suggest_lib); $config = $util->config($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
if ($this->getOption('includes')) { $this->output->writeln(match (true) {
$this->output->writeln($config['cflags']); $this->getOption('includes') => $config['cflags'],
} elseif ($this->getOption('libs')) { $this->getOption('libs-only-deps') => $config['libs'],
$this->output->writeln("{$config['ldflags']} {$config['libs']}"); $this->getOption('libs') => "{$config['ldflags']} {$config['libs']}",
} else { default => "{$config['cflags']} {$config['ldflags']} {$config['libs']}",
$this->output->writeln("{$config['cflags']} {$config['ldflags']} {$config['libs']}"); });
}
return 0; return 0;
} }

View File

@@ -51,6 +51,10 @@ class PackLibCommand extends BuildCommand
} }
} }
$origin_files = [];
// get pack placehoder defines
$placehoder = get_pack_replace();
foreach ($builder->getLibs() as $lib) { foreach ($builder->getLibs() as $lib) {
if ($lib->getName() !== $lib_name) { if ($lib->getName() !== $lib_name) {
// other dependencies: install or build, both ok // other dependencies: install or build, both ok
@@ -73,6 +77,27 @@ class PackLibCommand extends BuildCommand
// After build: load buildroot/ directory, and calculate increase files // After build: load buildroot/ directory, and calculate increase files
$after_buildroot = FileSystem::scanDirFiles(BUILD_ROOT_PATH, relative: true); $after_buildroot = FileSystem::scanDirFiles(BUILD_ROOT_PATH, relative: true);
$increase_files = array_diff($after_buildroot, $before_buildroot); $increase_files = array_diff($after_buildroot, $before_buildroot);
// patch pkg-config and la files with absolute path
foreach ($increase_files as $file) {
if (str_ends_with($file, '.pc') || str_ends_with($file, '.la')) {
$content = FileSystem::readFile(BUILD_ROOT_PATH . '/' . $file);
$origin_files[$file] = $content;
// replace relative paths with absolute paths
$content = str_replace(
array_keys($placehoder),
array_values($placehoder),
$content
);
FileSystem::writeFile(BUILD_ROOT_PATH . '/' . $file, $content);
}
}
// add .spc-extract-placeholder.json in BUILD_ROOT_PATH
$placeholder_file = BUILD_ROOT_PATH . '/.spc-extract-placeholder.json';
file_put_contents($placeholder_file, json_encode(array_keys($origin_files), JSON_PRETTY_PRINT));
$increase_files[] = '.spc-extract-placeholder.json';
// every file mapped with BUILD_ROOT_PATH // every file mapped with BUILD_ROOT_PATH
// get BUILD_ROOT_PATH last dir part // get BUILD_ROOT_PATH last dir part
$buildroot_part = basename(BUILD_ROOT_PATH); $buildroot_part = basename(BUILD_ROOT_PATH);
@@ -94,6 +119,16 @@ class PackLibCommand extends BuildCommand
$filename = WORKING_DIR . '/dist/' . $filename; $filename = WORKING_DIR . '/dist/' . $filename;
f_passthru("tar {$tar_option} {$filename} -T " . WORKING_DIR . '/packlib_files.txt'); f_passthru("tar {$tar_option} {$filename} -T " . WORKING_DIR . '/packlib_files.txt');
logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.'); logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.');
// remove temp files
unlink($placeholder_file);
}
}
foreach ($origin_files as $file => $content) {
// restore original files
if (file_exists(BUILD_ROOT_PATH . '/' . $file)) {
FileSystem::writeFile(BUILD_ROOT_PATH . '/' . $file, $content);
} }
} }

View File

@@ -90,6 +90,9 @@ class ConfigValidator
if (isset($lib['static-libs' . $suffix]) && !is_list_array($lib['static-libs' . $suffix])) { if (isset($lib['static-libs' . $suffix]) && !is_list_array($lib['static-libs' . $suffix])) {
throw new ValidationException("lib {$name} static-libs must be a list"); throw new ValidationException("lib {$name} static-libs must be a list");
} }
if (isset($lib['pkg-configs' . $suffix]) && !is_list_array($lib['pkg-configs' . $suffix])) {
throw new ValidationException("lib {$name} pkg-configs must be a list");
}
} }
// check if frameworks is a list array // check if frameworks is a list array
if (isset($lib['frameworks']) && !is_list_array($lib['frameworks'])) { if (isset($lib['frameworks']) && !is_list_array($lib['frameworks'])) {

View File

@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace SPC\util;
use SPC\exception\RuntimeException;
class PkgConfigUtil
{
/**
* Returns --cflags-only-other output.
* The reason we return the string is we cannot use array_unique() on cflags,
* some cflags may contains spaces.
*
* @param string $pkg_config_str .pc file str, accepts multiple files
* @return string cflags string, e.g. "-Wno-implicit-int-float-conversion ..."
* @throws RuntimeException
*/
public static function getCflags(string $pkg_config_str): string
{
// get other things
$result = self::execWithResult("pkg-config --static --cflags-only-other {$pkg_config_str}");
return trim($result);
}
/**
* Returns --libs-only-l and --libs-only-other output.
* The reason we return the array is to avoid duplicate lib defines.
*
* @param string $pkg_config_str .pc file str, accepts multiple files
* @return array Unique libs array, e.g. [-lz, -lxml, ...]
* @throws RuntimeException
*/
public static function getLibsArray(string $pkg_config_str): array
{
// Use this instead of shell() to avoid unnecessary outputs
$result = self::execWithResult("pkg-config --static --libs-only-l {$pkg_config_str}");
$libs = explode(' ', trim($result));
// get other things
$result = self::execWithResult("pkg-config --static --libs-only-other {$pkg_config_str}");
// convert libxxx.a to -L{path} -lxxx
$exp = explode(' ', trim($result));
foreach ($exp as $item) {
if (str_starts_with($item, '-L')) {
$libs[] = $item;
continue;
}
// if item ends with .a, convert it to -lxxx
if (str_ends_with($item, '.a') && (str_starts_with($item, 'lib') || str_starts_with($item, BUILD_LIB_PATH))) {
$name = pathinfo($item, PATHINFO_BASENAME);
$name = substr($name, 3, -2); // remove 'lib' prefix and '.a' suffix
$shortlib = "-l{$name}";
if (!in_array($shortlib, $libs)) {
$libs[] = $shortlib;
}
} elseif (!in_array($item, $libs)) {
$libs[] = $item;
}
}
// enhancement for linker
return array_reverse(array_unique(array_reverse($libs)));
}
private static function execWithResult(string $cmd): string
{
f_exec($cmd, $output, $result_code);
if ($result_code !== 0) {
throw new RuntimeException("pkg-config command failed with code {$result_code}: {$cmd}");
}
return implode("\n", $output);
}
}

View File

@@ -6,7 +6,6 @@ namespace SPC\util;
use SPC\builder\BuilderBase; use SPC\builder\BuilderBase;
use SPC\builder\BuilderProvider; use SPC\builder\BuilderProvider;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
@@ -17,11 +16,27 @@ class SPCConfigUtil
{ {
private ?BuilderBase $builder = null; private ?BuilderBase $builder = null;
public function __construct(?BuilderBase $builder = null) private bool $no_php;
private bool $libs_only_deps;
private bool $absolute_libs;
/**
* @param array{
* no_php?: bool,
* libs_only_deps?: bool,
* absolute_libs?: bool
* } $options Options pass to spc-config
*/
public function __construct(?BuilderBase $builder = null, array $options = [])
{ {
if ($builder !== null) { if ($builder !== null) {
$this->builder = $builder; // BuilderProvider::makeBuilderByInput($input ?? new ArgvInput()); $this->builder = $builder; // BuilderProvider::makeBuilderByInput($input ?? new ArgvInput());
} }
$this->no_php = $options['no_php'] ?? false;
$this->libs_only_deps = $options['libs_only_deps'] ?? false;
$this->absolute_libs = $options['absolute_libs'] ?? false;
} }
/** /**
@@ -54,45 +69,93 @@ class SPCConfigUtil
} }
ob_get_clean(); ob_get_clean();
$ldflags = $this->getLdflagsString(); $ldflags = $this->getLdflagsString();
$libs = $this->getLibsString($libraries, $with_dependencies); $cflags = $this->getIncludesString($libraries);
if (SPCTarget::getTargetOS() === 'Darwin') { $libs = $this->getLibsString($libraries, !$this->absolute_libs);
$libs .= " {$this->getFrameworksString($extensions)}";
}
$cflags = $this->getIncludesString();
// additional OS-specific libraries (e.g. macOS -lresolv)
// embed // embed
$libs = trim("-lphp -lc {$libs}");
if ($extra_libs = SPCTarget::getRuntimeLibs()) { if ($extra_libs = SPCTarget::getRuntimeLibs()) {
$libs .= " {$extra_libs}"; $libs .= " {$extra_libs}";
} }
// c++ $extra_env = getenv('SPC_EXTRA_LIBS');
if ($this->builder->hasCpp()) { if (is_string($extra_env) && !empty($extra_env)) {
$libs .= $this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++'; $libs .= " {$extra_env}";
} }
$libs .= ' ' . (getenv('SPC_EXTRA_LIBS') ?: ''); // extension frameworks
if (SPCTarget::getTargetOS() === 'Darwin') {
$libs .= " {$this->getFrameworksString($extensions)}";
}
if ($this->builder->hasCpp()) {
$libs .= SPCTarget::getTargetOS() === 'Darwin' ? ' -lc++' : ' -lstdc++';
}
if ($this->libs_only_deps) {
// mimalloc must come first
if (str_contains($libs, BUILD_LIB_PATH . '/mimalloc.o')) {
$libs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $libs);
}
return [
'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags),
'ldflags' => trim(getenv('LDFLAGS') . ' ' . $ldflags),
'libs' => trim(getenv('LIBS') . ' ' . $libs),
];
}
// embed
if (!$this->no_php) {
$libs = "-lphp {$libs} -lc";
}
$allLibs = getenv('LIBS') . ' ' . $libs;
// mimalloc must come first // mimalloc must come first
if (str_contains($libs, BUILD_LIB_PATH . '/mimalloc.o')) { if (str_contains($libs, BUILD_LIB_PATH . '/mimalloc.o')) {
$libs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $libs); $allLibs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $allLibs);
} }
return [ return [
'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags), 'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags),
'ldflags' => trim(getenv('LDFLAGS') . ' ' . $ldflags), 'ldflags' => trim(getenv('LDFLAGS') . ' ' . $ldflags),
'libs' => trim(getenv('LIBS') . ' ' . $libs), 'libs' => trim($allLibs),
]; ];
} }
private function getIncludesString(): string private function getIncludesString(array $libraries): string
{ {
$base = BUILD_INCLUDE_PATH; $base = BUILD_INCLUDE_PATH;
$php_embed_includes = [ $includes = ["-I{$base}"];
"-I{$base}",
"-I{$base}/php", // link with libphp
"-I{$base}/php/main", if (!$this->no_php) {
"-I{$base}/php/TSRM", $includes = [
"-I{$base}/php/Zend", ...$includes,
"-I{$base}/php/ext", "-I{$base}/php",
]; "-I{$base}/php/main",
return implode(' ', $php_embed_includes); "-I{$base}/php/TSRM",
"-I{$base}/php/Zend",
"-I{$base}/php/ext",
];
}
// parse pkg-configs
foreach ($libraries as $library) {
$pc = Config::getLib($library, 'pkg-configs', []);
foreach ($pc as $file) {
if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$file}.pc")) {
throw new WrongUsageException("pkg-config file '{$file}.pc' for lib [{$library}] does not exist in '" . BUILD_LIB_PATH . "/pkgconfig'. Please build it first.");
}
}
$pc_cflags = implode(' ', $pc);
if ($pc_cflags !== '' && ($pc_cflags = PkgConfigUtil::getCflags($pc_cflags)) !== '') {
$arr = explode(' ', $pc_cflags);
$arr = array_unique($arr);
$arr = array_filter($arr, fn ($x) => !str_starts_with($x, 'SHELL:-Xarch_'));
$pc_cflags = implode(' ', $arr);
$includes[] = $pc_cflags;
}
}
$includes = array_unique($includes);
return implode(' ', $includes);
} }
private function getLdflagsString(): string private function getLdflagsString(): string
@@ -100,55 +163,62 @@ class SPCConfigUtil
return '-L' . BUILD_LIB_PATH; return '-L' . BUILD_LIB_PATH;
} }
private function getLibsString(array $libraries, bool $withDependencies = false): string private function getLibsString(array $libraries, bool $use_short_libs = true): string
{ {
$short_name = []; $lib_names = [];
foreach (array_reverse($libraries) as $library) { $frameworks = [];
foreach ($libraries as $library) {
// add pkg-configs libs
$pkg_configs = Config::getLib($library, 'pkg-configs', []);
foreach ($pkg_configs as $pkg_config) {
if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$pkg_config}.pc")) {
throw new WrongUsageException("pkg-config file '{$pkg_config}.pc' for lib [{$library}] does not exist in '" . BUILD_LIB_PATH . "/pkgconfig'. Please build it first.");
}
}
$pkg_configs = implode(' ', $pkg_configs);
if ($pkg_configs !== '') {
// static libs with dependencies come in reverse order, so reverse this too
$pc_libs = array_reverse(PkgConfigUtil::getLibsArray($pkg_configs));
$lib_names = [...$lib_names, ...$pc_libs];
}
// convert all static-libs to short names
$libs = Config::getLib($library, 'static-libs', []); $libs = Config::getLib($library, 'static-libs', []);
foreach ($libs as $lib) { foreach ($libs as $lib) {
if ($withDependencies) { // check file existence
$noExt = str_replace('.a', '', $lib); if (!file_exists(BUILD_LIB_PATH . "/{$lib}")) {
$requiredLibs = []; throw new WrongUsageException("Library file '{$lib}' for lib [{$library}] does not exist in '" . BUILD_LIB_PATH . "'. Please build it first.");
$pkgconfFile = BUILD_LIB_PATH . "/pkgconfig/{$noExt}.pc";
if (file_exists($pkgconfFile)) {
$lines = file($pkgconfFile);
foreach ($lines as $value) {
if (str_starts_with($value, 'Libs')) {
$items = explode(' ', $value);
foreach ($items as $item) {
$item = trim($item);
if (str_starts_with($item, '-l')) {
$requiredLibs[] = $item;
}
}
}
}
} else {
$requiredLibs[] = $this->getShortLibName($lib);
}
foreach ($requiredLibs as $requiredLib) {
if (!in_array($requiredLib, $short_name)) {
$short_name[] = $requiredLib;
}
}
} else {
$short_name[] = $this->getShortLibName($lib);
} }
$lib_names[] = $this->getShortLibName($lib);
} }
if (PHP_OS_FAMILY !== 'Darwin') { // add frameworks for macOS
continue; if (SPCTarget::getTargetOS() === 'Darwin') {
$frameworks = array_merge($frameworks, Config::getLib($library, 'frameworks', []));
} }
foreach (Config::getLib($library, 'frameworks', []) as $fw) { }
// post-process
$lib_names = array_filter($lib_names, fn ($x) => $x !== '');
$lib_names = array_reverse(array_unique($lib_names));
$frameworks = array_unique($frameworks);
// process frameworks to short_name
if (SPCTarget::getTargetOS() === 'Darwin') {
foreach ($frameworks as $fw) {
$ks = '-framework ' . $fw; $ks = '-framework ' . $fw;
if (!in_array($ks, $short_name)) { if (!in_array($ks, $lib_names)) {
$short_name[] = $ks; $lib_names[] = $ks;
} }
} }
} }
if (in_array('imap', $libraries) && SPCTarget::getLibc() === 'glibc') { if (in_array('imap', $libraries) && SPCTarget::getLibc() === 'glibc') {
$short_name[] = '-lcrypt'; $lib_names[] = '-lcrypt';
} }
return implode(' ', $short_name); if (!$use_short_libs) {
$lib_names = array_map(fn ($l) => $this->getFullLibName($l), $lib_names);
}
return implode(' ', $lib_names);
} }
private function getShortLibName(string $lib): string private function getShortLibName(string $lib): string
@@ -160,6 +230,19 @@ class SPCConfigUtil
return '-l' . substr($lib, 3, -2); return '-l' . substr($lib, 3, -2);
} }
private function getFullLibName(string $lib)
{
if (!str_starts_with($lib, '-l')) {
return $lib;
}
$libname = substr($lib, 2);
$staticLib = BUILD_LIB_PATH . '/' . "lib{$libname}.a";
if (file_exists($staticLib)) {
return $staticLib;
}
return $lib;
}
private function getFrameworksString(array $extensions): string private function getFrameworksString(array $extensions): string
{ {
$list = []; $list = [];

View File

@@ -12,7 +12,7 @@ use SPC\util\UnixShell;
class UnixAutoconfExecutor extends Executor class UnixAutoconfExecutor extends Executor
{ {
protected ?UnixShell $shell = null; protected UnixShell $shell;
protected array $configure_args = []; protected array $configure_args = [];

View File

@@ -5,25 +5,37 @@ declare(strict_types=1);
namespace SPC\util\executor; namespace SPC\util\executor;
use Closure; use Closure;
use SPC\builder\freebsd\library\BSDLibraryBase;
use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\util\UnixShell;
/** /**
* Unix-like OS cmake command executor. * Unix-like OS cmake command executor.
*/ */
class UnixCMakeExecutor extends Executor class UnixCMakeExecutor extends Executor
{ {
protected ?string $build_dir = null; protected UnixShell $shell;
protected array $configure_args = []; protected array $configure_args = [];
protected ?string $build_dir = null;
protected ?array $custom_default_args = null; protected ?array $custom_default_args = null;
protected int $steps = 3; protected int $steps = 3;
protected bool $reset = true; protected bool $reset = true;
public function __construct(protected BSDLibraryBase|LinuxLibraryBase|MacOSLibraryBase $library)
{
parent::__construct($library);
$this->initShell();
}
public function build(string $build_pos = '..'): void public function build(string $build_pos = '..'): void
{ {
// set cmake dir // set cmake dir
@@ -33,17 +45,16 @@ class UnixCMakeExecutor extends Executor
FileSystem::resetDir($this->build_dir); FileSystem::resetDir($this->build_dir);
} }
// prepare shell $this->shell = $this->shell->cd($this->build_dir);
$shell = shell()->cd($this->build_dir)->initializeEnv($this->library);
// config // config
$this->steps >= 1 && $shell->exec("cmake {$this->getConfigureArgs()} {$this->getDefaultCMakeArgs()} {$build_pos}"); $this->steps >= 1 && $this->shell->exec("cmake {$this->getConfigureArgs()} {$this->getDefaultCMakeArgs()} {$build_pos}");
// make // make
$this->steps >= 2 && $shell->exec("cmake --build . -j {$this->library->getBuilder()->concurrency}"); $this->steps >= 2 && $this->shell->exec("cmake --build . -j {$this->library->getBuilder()->concurrency}");
// install // install
$this->steps >= 3 && $shell->exec('make install'); $this->steps >= 3 && $this->shell->exec('make install');
} }
/** /**
@@ -77,6 +88,12 @@ class UnixCMakeExecutor extends Executor
return $this; return $this;
} }
public function appendEnv(array $env): static
{
$this->shell->appendEnv($env);
return $this;
}
/** /**
* To build steps. * To build steps.
* *
@@ -209,4 +226,9 @@ CMAKE;
FileSystem::writeFile(SOURCE_PATH . '/toolchain.cmake', $toolchain); FileSystem::writeFile(SOURCE_PATH . '/toolchain.cmake', $toolchain);
return $created = realpath(SOURCE_PATH . '/toolchain.cmake'); return $created = realpath(SOURCE_PATH . '/toolchain.cmake');
} }
private function initShell(): void
{
$this->shell = shell()->initializeEnv($this->library);
}
} }

View File

@@ -232,3 +232,13 @@ function ac_with_args(string $arg_name, bool $use_value = false): array
{ {
return $use_value ? ["--with-{$arg_name}=yes", "--with-{$arg_name}=no"] : ["--with-{$arg_name}", "--without-{$arg_name}"]; return $use_value ? ["--with-{$arg_name}=yes", "--with-{$arg_name}=no"] : ["--with-{$arg_name}", "--without-{$arg_name}"];
} }
function get_pack_replace(): array
{
return [
BUILD_LIB_PATH => '@build_lib_path@',
BUILD_BIN_PATH => '@build_bin_path@',
BUILD_INCLUDE_PATH => '@build_include_path@',
BUILD_ROOT_PATH => '@build_root_path@',
];
}

View File

@@ -78,11 +78,6 @@ class ExtensionTest extends TestCase
} }
} }
public function testGetLibFilesString()
{
$this->assertStringEndsWith('libonig.a', $this->extension->getLibFilesString());
}
public function testGetName() public function testGetName()
{ {
$this->assertEquals('mbregex', $this->extension->getName()); $this->assertEquals('mbregex', $this->extension->getName());

View File

@@ -54,7 +54,7 @@ class SPCConfigUtilTest extends TestCase
$this->assertStringContainsString('-lphp', $result['libs']); $this->assertStringContainsString('-lphp', $result['libs']);
// has cpp // has cpp
$result = (new SPCConfigUtil())->config(['swoole']); $result = (new SPCConfigUtil())->config(['rar']);
$this->assertStringContainsString(PHP_OS_FAMILY === 'Darwin' ? '-lc++' : '-lstdc++', $result['libs']); $this->assertStringContainsString(PHP_OS_FAMILY === 'Darwin' ? '-lc++' : '-lstdc++', $result['libs']);
// has mimalloc.o in lib dir // has mimalloc.o in lib dir