diff --git a/.github/workflows/build-unix.yml b/.github/workflows/build-unix.yml index e0b51614..31b13c61 100644 --- a/.github/workflows/build-unix.yml +++ b/.github/workflows/build-unix.yml @@ -230,12 +230,12 @@ jobs: - uses: actions/upload-artifact@v4 name: "Upload License Files" with: - name: license-files + name: license-files-${{ inputs.php-version }}-${{ inputs.os }} path: buildroot/license/ - uses: actions/upload-artifact@v4 name: "Upload Build Metadata" with: - name: build-meta + name: build-meta-${{ inputs.php-version }}-${{ inputs.os }} path: | buildroot/build-extensions.json buildroot/build-libraries.json diff --git a/.github/workflows/ext-matrix-tests.yml b/.github/workflows/ext-matrix-tests.yml index 557024b1..822b95d7 100644 --- a/.github/workflows/ext-matrix-tests.yml +++ b/.github/workflows/ext-matrix-tests.yml @@ -136,11 +136,4 @@ jobs: - name: "Build library: ${{ matrix.library }}" run: | SPC_USE_SUDO=yes ./bin/spc doctor --auto-fix - if [ "${{ env.OS }}" = "linux-x86_64" ]; then - ./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 + ./bin/spc build --build-cli --build-micro --build-fpm ${{ matrix.extension }} --debug --with-suggested-libs --with-suggested-exts diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 5c0c4f0d..bee83560 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -10,7 +10,7 @@ on: env: PHP_VERSION: 8.4 - MICRO_VERSION: 8.4.4 + MICRO_VERSION: 8.4.10 jobs: build-release-artifacts: @@ -42,12 +42,13 @@ jobs: run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV - name: "Install PHP for official runners" - uses: "shivammathur/setup-php@v2" + uses: shivammathur/setup-php@v2 with: coverage: none tools: composer:v2 php-version: "${{ env.PHP_VERSION }}" ini-values: memory_limit=-1 + extensions: curl, openssl, mbstring - name: "Get Composer Cache Directory" id: composer-cache diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5ed6d59d..d02be5ef 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -121,6 +121,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: 8.4 + extensions: curl, openssl, mbstring - name: Define id: gendef @@ -198,3 +199,7 @@ jobs: - name: "Run Build Tests (build - embed for non-windows)" if: ${{ !startsWith(matrix.os, 'windows-') }} run: php src/globals/test-extensions.php build_embed_cmd ${{ matrix.os }} ${{ matrix.php }} + +# - name: Setup tmate session +# if: ${{ failure() }} +# uses: mxschmitt/action-tmate@v3 diff --git a/.github/workflows/vitepress-deploy.yml b/.github/workflows/vitepress-deploy.yml index b44bef84..52aa8e25 100644 --- a/.github/workflows/vitepress-deploy.yml +++ b/.github/workflows/vitepress-deploy.yml @@ -32,12 +32,13 @@ jobs: cp -r config/* docs/.vitepress/config/ - name: "Install PHP for official runners" - uses: "shivammathur/setup-php@v2" + uses: shivammathur/setup-php@v2 with: coverage: none tools: composer:v2 php-version: 8.4 ini-values: memory_limit=-1 + extensions: curl, openssl, mbstring - name: "Get Composer Cache Directory" id: composer-cache diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 47d17866..55fca81a 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -4,6 +4,7 @@ declare(strict_types=1); return (new PhpCsFixer\Config()) ->setRiskyAllowed(true) + ->setUnsupportedPhpVersionAllowed(true) ->setRules([ '@PSR12' => true, '@Symfony' => true, diff --git a/bin/spc-gnu-docker b/bin/spc-gnu-docker index 20a26389..1a9e7e03 100755 --- a/bin/spc-gnu-docker +++ b/bin/spc-gnu-docker @@ -86,7 +86,7 @@ RUN sed -i 's/^#.*baseurl=http/baseurl=http/g' /etc/yum.repos.d/*.repo && \ sed -i 's/^mirrorlist=http/#mirrorlist=http/g' /etc/yum.repos.d/*.repo RUN yum update -y && \ - yum install -y devtoolset-10-gcc-* + yum install -y devtoolset-10-gcc-* devtoolset-10-libatomic-devel RUN echo "source scl_source enable devtoolset-10" >> /etc/bashrc RUN source /etc/bashrc RUN yum install -y which diff --git a/composer.lock b/composer.lock index 3004785e..a05a1e0d 100644 --- a/composer.lock +++ b/composer.lock @@ -8,7 +8,7 @@ "packages": [ { "name": "illuminate/collections", - "version": "v11.44.4", + "version": "v11.45.1", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", @@ -64,7 +64,7 @@ }, { "name": "illuminate/conditionable", - "version": "v11.44.4", + "version": "v11.45.1", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -110,7 +110,7 @@ }, { "name": "illuminate/contracts", - "version": "v11.44.4", + "version": "v11.45.1", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -158,7 +158,7 @@ }, { "name": "illuminate/macroable", - "version": "v11.44.4", + "version": "v11.45.1", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -416,16 +416,16 @@ }, { "name": "symfony/console", - "version": "v6.4.20", + "version": "v6.4.23", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "2e4af9c952617cc3f9559ff706aee420a8464c36" + "reference": "9056771b8eca08d026cd3280deeec3cfd99c4d93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2e4af9c952617cc3f9559ff706aee420a8464c36", - "reference": "2e4af9c952617cc3f9559ff706aee420a8464c36", + "url": "https://api.github.com/repos/symfony/console/zipball/9056771b8eca08d026cd3280deeec3cfd99c4d93", + "reference": "9056771b8eca08d026cd3280deeec3cfd99c4d93", "shasum": "" }, "require": { @@ -490,7 +490,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.20" + "source": "https://github.com/symfony/console/tree/v6.4.23" }, "funding": [ { @@ -506,20 +506,20 @@ "type": "tidelift" } ], - "time": "2025-03-03T17:16:38+00:00" + "time": "2025-06-27T19:37:22+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -532,7 +532,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -557,7 +557,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -573,11 +573,11 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -636,7 +636,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -656,7 +656,7 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", @@ -714,7 +714,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -734,7 +734,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -795,7 +795,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -815,19 +815,20 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { + "ext-iconv": "*", "php": ">=7.2" }, "provide": { @@ -875,7 +876,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -891,20 +892,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/process", - "version": "v7.2.5", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "87b7c93e57df9d8e39a093d32587702380ff045d" + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d", - "reference": "87b7c93e57df9d8e39a093d32587702380ff045d", + "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "shasum": "" }, "require": { @@ -936,7 +937,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.5" + "source": "https://github.com/symfony/process/tree/v7.3.0" }, "funding": [ { @@ -952,20 +953,20 @@ "type": "tidelift" } ], - "time": "2025-03-13T12:21:46+00:00" + "time": "2025-04-17T09:11:12+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -983,7 +984,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -1019,7 +1020,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -1035,20 +1036,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "symfony/string", - "version": "v7.2.0", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" + "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", - "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", + "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125", + "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125", "shasum": "" }, "require": { @@ -1106,7 +1107,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.2.0" + "source": "https://github.com/symfony/string/tree/v7.3.0" }, "funding": [ { @@ -1122,20 +1123,20 @@ "type": "tidelift" } ], - "time": "2024-11-13T13:31:26+00:00" + "time": "2025-04-20T20:19:01+00:00" }, { "name": "symfony/yaml", - "version": "v7.2.5", + "version": "v7.3.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "4c4b6f4cfcd7e52053f0c8bfad0f7f30fb924912" + "reference": "0c3555045a46ab3cd4cc5a69d161225195230edb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/4c4b6f4cfcd7e52053f0c8bfad0f7f30fb924912", - "reference": "4c4b6f4cfcd7e52053f0c8bfad0f7f30fb924912", + "url": "https://api.github.com/repos/symfony/yaml/zipball/0c3555045a46ab3cd4cc5a69d161225195230edb", + "reference": "0c3555045a46ab3cd4cc5a69d161225195230edb", "shasum": "" }, "require": { @@ -1178,7 +1179,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.2.5" + "source": "https://github.com/symfony/yaml/tree/v7.3.1" }, "funding": [ { @@ -1194,7 +1195,7 @@ "type": "tidelift" } ], - "time": "2025-03-03T07:12:39+00:00" + "time": "2025-06-03T06:57:57+00:00" }, { "name": "zhamao/logger", @@ -2077,16 +2078,16 @@ }, { "name": "captainhook/captainhook-phar", - "version": "5.25.2", + "version": "5.25.6", "source": { "type": "git", "url": "https://github.com/captainhook-git/captainhook-phar.git", - "reference": "ab47b0561ec7997bf9b88181d090857874f2cf8c" + "reference": "a5dbcd8d20b3dcdb1cbd6948d0d3a058453b3d6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/captainhook-git/captainhook-phar/zipball/ab47b0561ec7997bf9b88181d090857874f2cf8c", - "reference": "ab47b0561ec7997bf9b88181d090857874f2cf8c", + "url": "https://api.github.com/repos/captainhook-git/captainhook-phar/zipball/a5dbcd8d20b3dcdb1cbd6948d0d3a058453b3d6a", + "reference": "a5dbcd8d20b3dcdb1cbd6948d0d3a058453b3d6a", "shasum": "" }, "require": { @@ -2119,7 +2120,7 @@ } ], "description": "PHP git hook manager", - "homepage": "https://github.com/captainhookphp/captainhook", + "homepage": "https://github.com/captainhook-git/captainhook", "keywords": [ "commit-msg", "git", @@ -2130,8 +2131,8 @@ "prepare-commit-msg" ], "support": { - "issues": "https://github.com/captainhookphp/captainhook/issues", - "source": "https://github.com/captainhook-git/captainhook-phar/tree/5.25.2" + "issues": "https://github.com/captainhook-git/captainhook/issues", + "source": "https://github.com/captainhook-git/captainhook-phar/tree/5.25.6" }, "funding": [ { @@ -2139,7 +2140,7 @@ "type": "github" } ], - "time": "2025-03-30T17:19:44+00:00" + "time": "2025-04-08T07:07:48+00:00" }, { "name": "captainhook/hook-installer", @@ -2832,16 +2833,16 @@ }, { "name": "filp/whoops", - "version": "2.18.0", + "version": "2.18.3", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e" + "reference": "59a123a3d459c5a23055802237cb317f609867e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e", - "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e", + "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", + "reference": "59a123a3d459c5a23055802237cb317f609867e5", "shasum": "" }, "require": { @@ -2891,7 +2892,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.0" + "source": "https://github.com/filp/whoops/tree/2.18.3" }, "funding": [ { @@ -2899,62 +2900,63 @@ "type": "github" } ], - "time": "2025-03-15T12:00:00+00:00" + "time": "2025-06-16T00:02:10+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.75.0", + "version": "v3.84.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "399a128ff2fdaf4281e4e79b755693286cdf325c" + "reference": "38dad0767bf2a9b516b976852200ae722fe984ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/399a128ff2fdaf4281e4e79b755693286cdf325c", - "reference": "399a128ff2fdaf4281e4e79b755693286cdf325c", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/38dad0767bf2a9b516b976852200ae722fe984ca", + "reference": "38dad0767bf2a9b516b976852200ae722fe984ca", "shasum": "" }, "require": { "clue/ndjson-react": "^1.0", "composer/semver": "^3.4", - "composer/xdebug-handler": "^3.0.3", + "composer/xdebug-handler": "^3.0.5", "ext-filter": "*", "ext-hash": "*", "ext-json": "*", "ext-tokenizer": "*", "fidry/cpu-core-counter": "^1.2", "php": "^7.4 || ^8.0", - "react/child-process": "^0.6.5", + "react/child-process": "^0.6.6", "react/event-loop": "^1.0", - "react/promise": "^2.0 || ^3.0", + "react/promise": "^2.11 || ^3.0", "react/socket": "^1.0", "react/stream": "^1.0", - "sebastian/diff": "^4.0 || ^5.1 || ^6.0 || ^7.0", - "symfony/console": "^5.4 || ^6.4 || ^7.0", - "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", - "symfony/filesystem": "^5.4 || ^6.4 || ^7.0", - "symfony/finder": "^5.4 || ^6.4 || ^7.0", - "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", - "symfony/polyfill-mbstring": "^1.31", - "symfony/polyfill-php80": "^1.31", - "symfony/polyfill-php81": "^1.31", - "symfony/process": "^5.4 || ^6.4 || ^7.2", - "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", + "symfony/console": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", + "symfony/polyfill-mbstring": "^1.32", + "symfony/polyfill-php80": "^1.32", + "symfony/polyfill-php81": "^1.32", + "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", + "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" }, "require-dev": { "facile-it/paraunit": "^1.3.1 || ^2.6", "infection/infection": "^0.29.14", - "justinrainbow/json-schema": "^5.3 || ^6.2", - "keradus/cli-executor": "^2.1", + "justinrainbow/json-schema": "^5.3 || ^6.4", + "keradus/cli-executor": "^2.2", "mikey179/vfsstream": "^1.6.12", - "php-coveralls/php-coveralls": "^2.7", + "php-coveralls/php-coveralls": "^2.8", "php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", - "phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.12", - "symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.3", - "symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.3" + "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", + "symfony/polyfill-php84": "^1.32", + "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", + "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -2995,7 +2997,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.75.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.84.0" }, "funding": [ { @@ -3003,7 +3005,7 @@ "type": "github" } ], - "time": "2025-03-31T18:40:42+00:00" + "time": "2025-07-15T18:21:57+00:00" }, { "name": "humbug/box", @@ -3546,16 +3548,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.13.0", + "version": "1.13.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + "reference": "faed855a7b5f4d4637717c2b3863e277116beb36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36", + "reference": "faed855a7b5f4d4637717c2b3863e277116beb36", "shasum": "" }, "require": { @@ -3594,7 +3596,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3" }, "funding": [ { @@ -3602,7 +3604,7 @@ "type": "tidelift" } ], - "time": "2025-02-12T12:17:51+00:00" + "time": "2025-07-05T12:25:42+00:00" }, { "name": "nikic/iter", @@ -3658,16 +3660,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.4.0", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", "shasum": "" }, "require": { @@ -3710,9 +3712,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" }, - "time": "2024-12-30T11:07:19+00:00" + "time": "2025-05-31T08:24:38+00:00" }, { "name": "nunomaduro/collision", @@ -4404,16 +4406,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.1.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68" + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", - "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", "shasum": "" }, "require": { @@ -4445,22 +4447,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "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", - "version": "1.12.24", + "version": "1.12.28", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "338b92068f58d9f8035b76aed6cf2b9e5624c025" + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/338b92068f58d9f8035b76aed6cf2b9e5624c025", - "reference": "338b92068f58d9f8035b76aed6cf2b9e5624c025", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", "shasum": "" }, "require": { @@ -4505,7 +4507,7 @@ "type": "github" } ], - "time": "2025-04-16T13:01:53+00:00" + "time": "2025-07-17T17:15:39+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4830,16 +4832,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.45", + "version": "10.5.48", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "bd68a781d8e30348bc297449f5234b3458267ae8" + "reference": "6e0a2bc39f6fae7617989d690d76c48e6d2eb541" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8", - "reference": "bd68a781d8e30348bc297449f5234b3458267ae8", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e0a2bc39f6fae7617989d690d76c48e6d2eb541", + "reference": "6e0a2bc39f6fae7617989d690d76c48e6d2eb541", "shasum": "" }, "require": { @@ -4849,7 +4851,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.1", + "myclabs/deep-copy": "^1.13.3", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.1", @@ -4911,7 +4913,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.48" }, "funding": [ { @@ -4922,12 +4924,20 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2025-02-06T16:08:12+00:00" + "time": "2025-07-11T04:07:17+00:00" }, { "name": "psr/event-dispatcher", @@ -6715,16 +6725,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v7.2.0", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", - "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", "shasum": "" }, "require": { @@ -6775,7 +6785,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" }, "funding": [ { @@ -6791,20 +6801,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-04-22T09:11:45+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", "shasum": "" }, "require": { @@ -6818,7 +6828,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -6851,7 +6861,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { @@ -6867,11 +6877,11 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/filesystem", - "version": "v7.2.0", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -6917,7 +6927,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.2.0" + "source": "https://github.com/symfony/filesystem/tree/v7.3.0" }, "funding": [ { @@ -6937,16 +6947,16 @@ }, { "name": "symfony/finder", - "version": "v7.2.2", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d", + "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d", "shasum": "" }, "require": { @@ -6981,7 +6991,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.2.2" + "source": "https://github.com/symfony/finder/tree/v7.3.0" }, "funding": [ { @@ -6997,20 +7007,20 @@ "type": "tidelift" } ], - "time": "2024-12-30T19:00:17+00:00" + "time": "2024-12-30T19:00:26+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.2.0", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" + "reference": "afb9a8038025e5dbc657378bfab9198d75f10fca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/afb9a8038025e5dbc657378bfab9198d75f10fca", + "reference": "afb9a8038025e5dbc657378bfab9198d75f10fca", "shasum": "" }, "require": { @@ -7048,7 +7058,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" + "source": "https://github.com/symfony/options-resolver/tree/v7.3.0" }, "funding": [ { @@ -7064,20 +7074,20 @@ "type": "tidelift" } ], - "time": "2024-11-20T11:17:29+00:00" + "time": "2025-04-04T13:12:05+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956" + "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956", - "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/5f3b930437ae03ae5dff61269024d8ea1b3774aa", + "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa", "shasum": "" }, "require": { @@ -7128,7 +7138,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.32.0" }, "funding": [ { @@ -7144,20 +7154,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-09-17T14:58:18+00:00" }, { "name": "symfony/polyfill-php84", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "e5493eb51311ab0b1cc2243416613f06ed8f18bd" + "reference": "000df7860439609837bbe28670b0be15783b7fbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/e5493eb51311ab0b1cc2243416613f06ed8f18bd", - "reference": "e5493eb51311ab0b1cc2243416613f06ed8f18bd", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/000df7860439609837bbe28670b0be15783b7fbf", + "reference": "000df7860439609837bbe28670b0be15783b7fbf", "shasum": "" }, "require": { @@ -7204,7 +7214,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.32.0" }, "funding": [ { @@ -7220,11 +7230,11 @@ "type": "tidelift" } ], - "time": "2024-09-09T12:04:04+00:00" + "time": "2025-02-20T12:04:08+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.2.4", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -7266,7 +7276,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.2.4" + "source": "https://github.com/symfony/stopwatch/tree/v7.3.0" }, "funding": [ { @@ -7286,20 +7296,21 @@ }, { "name": "symfony/var-dumper", - "version": "v7.2.3", + "version": "v7.3.1", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "82b478c69745d8878eb60f9a049a4d584996f73a" + "reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/82b478c69745d8878eb60f9a049a4d584996f73a", - "reference": "82b478c69745d8878eb60f9a049a4d584996f73a", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6e209fbe5f5a7b6043baba46fe5735a4b85d0d42", + "reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { @@ -7349,7 +7360,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.2.3" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.1" }, "funding": [ { @@ -7365,20 +7376,20 @@ "type": "tidelift" } ], - "time": "2025-01-17T11:39:41+00:00" + "time": "2025-06-27T19:55:54+00:00" }, { "name": "thecodingmachine/safe", - "version": "v3.1.0", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/thecodingmachine/safe.git", - "reference": "e14ac96126e6c19ea9d1f4029abb51487f4cf2cf" + "reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/e14ac96126e6c19ea9d1f4029abb51487f4cf2cf", - "reference": "e14ac96126e6c19ea9d1f4029abb51487f4cf2cf", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/2cdd579eeaa2e78e51c7509b50cc9fb89a956236", + "reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236", "shasum": "" }, "require": { @@ -7488,7 +7499,7 @@ "description": "PHP core functions that throw exceptions instead of returning FALSE on error", "support": { "issues": "https://github.com/thecodingmachine/safe/issues", - "source": "https://github.com/thecodingmachine/safe/tree/v3.1.0" + "source": "https://github.com/thecodingmachine/safe/tree/v3.3.0" }, "funding": [ { @@ -7504,7 +7515,7 @@ "type": "github" } ], - "time": "2025-04-12T06:41:26+00:00" + "time": "2025-05-14T06:15:44+00:00" }, { "name": "theseer/tokenizer", diff --git a/config/env.ini b/config/env.ini index 95a3d946..c4c27c50 100644 --- a/config/env.ini +++ b/config/env.ini @@ -34,7 +34,6 @@ ; SPC_LINUX_DEFAULT_CXX: the default c++ compiler for linux. (For alpine linux: `g++`, default: `$GNU_ARCH-linux-musl-g++`) ; SPC_LINUX_DEFAULT_AR: the default archiver for linux. (For alpine linux: `ar`, default: `$GNU_ARCH-linux-musl-ar`) - [global] ; Build concurrency for make -jN, default is CPU_COUNT, this value are used in every libs. SPC_CONCURRENCY=${CPU_COUNT} @@ -63,6 +62,8 @@ PHP_SDK_PATH="${WORKING_DIR}\php-sdk-binary-tools" UPX_EXEC="${PKG_ROOT_PATH}\bin\upx.exe" ; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime140,win32,zend_stream,cli_static +; Windows static linking system libs +SPC_EXTRA_LIBS="" [linux] ; Linux can use different build toolchain, but the toolchain can not be changed in this file: @@ -87,7 +88,7 @@ LD=${SPC_LINUX_DEFAULT_LD} SPC_DEFAULT_C_FLAGS="-fPIC -Os" 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= +SPC_EXTRA_LIBS="" ; upx executable path UPX_EXEC=${PKG_ROOT_PATH}/bin/upx ; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches @@ -99,11 +100,11 @@ SPC_CMD_PREFIX_PHP_BUILDCONF="./buildconf --force" ; configure command SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --disable-shared --enable-static --disable-all --disable-cgi --disable-phpdbg --with-pic" ; make command -SPC_CMD_PREFIX_PHP_MAKE="make -j${CPU_COUNT}" -; embed type for php, static (libphp.a) or shared (libphp.so) -SPC_CMD_VAR_PHP_EMBED_TYPE="static" +SPC_CMD_PREFIX_PHP_MAKE="make -j${SPC_CONCURRENCY}" ; *** default build vars for building php *** +; embed type for php, static (libphp.a) or shared (libphp.so) +SPC_CMD_VAR_PHP_EMBED_TYPE="static" ; CFLAGS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS="${SPC_DEFAULT_C_FLAGS} -fPIE" ; CPPFLAGS for configuring php @@ -113,13 +114,9 @@ SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}" ; LIBS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_LIBS="-ldl -lpthread -lm" ; EXTRA_CFLAGS for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fno-ident -fPIE ${SPC_DEFAULT_C_FLAGS}" +SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_DEFAULT_C_FLAGS} -g -fstack-protector-strong -fno-ident -fPIE" ; EXTRA_LIBS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm" -; EXTRA_LDFLAGS for `make` php, can use -release to set a soname for libphp.so -SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS="" -; EXTRA_LDFLAGS_PROGRAM for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-all-static -Wl,-O1 -pie" [macos] ; build target: macho or macho (possibly we could support macho-universal in the future) @@ -132,7 +129,7 @@ CXX=clang++ SPC_DEFAULT_C_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= +SPC_EXTRA_LIBS="" ; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches SPC_MICRO_PATCHES=cli_checks,macos_iconv @@ -142,9 +139,11 @@ SPC_CMD_PREFIX_PHP_BUILDCONF="./buildconf --force" ; configure command SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --enable-shared=no --enable-static=yes --disable-all --disable-cgi --disable-phpdbg" ; make command -SPC_CMD_PREFIX_PHP_MAKE="make -j${CPU_COUNT}" +SPC_CMD_PREFIX_PHP_MAKE="make -j${SPC_CONCURRENCY}" ; *** default build vars for building php *** +; embed type for php, static (libphp.a) or shared (libphp.dylib) +SPC_CMD_VAR_PHP_EMBED_TYPE="static" ; CFLAGS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS="${SPC_DEFAULT_C_FLAGS} -Werror=unknown-warning-option" ; CPPFLAGS for configuring php @@ -152,11 +151,9 @@ SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS="-I${BUILD_INCLUDE_PATH}" ; LDFLAGS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}" ; EXTRA_CFLAGS for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie ${SPC_DEFAULT_C_FLAGS}" +SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_DEFAULT_C_FLAGS} -g -fstack-protector-strong -fpic -fpie" ; EXTRA_LIBS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-lresolv" -; embed type for php, static (libphp.a) or shared (libphp.dylib) -SPC_CMD_VAR_PHP_EMBED_TYPE="static" [freebsd] ; compiler environments diff --git a/config/ext.json b/config/ext.json index a5eca9f4..61897bb5 100644 --- a/config/ext.json +++ b/config/ext.json @@ -34,7 +34,7 @@ }, "bz2": { "type": "builtin", - "arg-type-unix": "with-prefix", + "arg-type-unix": "with-path", "arg-type-windows": "with", "lib-depends": [ "bzip2" @@ -185,7 +185,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "lib-depends": [ "gettext" ] @@ -211,7 +211,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "lib-depends": [ "gmp" ] @@ -233,7 +233,7 @@ }, "type": "external", "source": "grpc", - "arg-type-unix": "custom", + "arg-type-unix": "enable-path", "cpp-extension": true, "lib-depends": [ "grpc" @@ -244,7 +244,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "arg-type-windows": "with", "lib-depends-unix": [ "libiconv" @@ -320,7 +320,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "lib-depends": [ "ldap" ], @@ -529,7 +529,7 @@ }, "notes": true, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "lib-depends": [ "libargon2" ] @@ -571,7 +571,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "arg-type-windows": "custom", "ext-depends": [ "pdo", @@ -674,7 +674,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "lib-depends": [ "readline" ], @@ -785,7 +785,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "arg-type-windows": "with", "lib-depends": [ "sqlite" @@ -811,7 +811,7 @@ }, "type": "external", "source": "ext-ssh2", - "arg-type": "with-prefix", + "arg-type": "with-path", "arg-type-windows": "with", "lib-depends": [ "libssh2" @@ -937,7 +937,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "lib-depends": [ "tidy" ] @@ -953,7 +953,7 @@ }, "type": "external", "source": "ext-uuid", - "arg-type": "with-prefix", + "arg-type": "with-path", "lib-depends": [ "libuuid" ] @@ -965,7 +965,7 @@ }, "type": "external", "source": "ext-uv", - "arg-type": "with-prefix", + "arg-type": "with-path", "lib-depends": [ "libuv" ], @@ -1067,7 +1067,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "lib-depends": [ "libxslt" ], @@ -1104,7 +1104,7 @@ }, "type": "external", "source": "yaml", - "arg-type-unix": "with-prefix", + "arg-type-unix": "with-path", "arg-type-windows": "with", "lib-depends": [ "libyaml" @@ -1115,7 +1115,7 @@ "BSD": "wip" }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type": "with-path", "arg-type-windows": "enable", "lib-depends-unix": [ "libzip" diff --git a/config/lib.json b/config/lib.json index 1a195f66..13f886ca 100644 --- a/config/lib.json +++ b/config/lib.json @@ -35,10 +35,10 @@ }, "brotli": { "source": "brotli", - "static-libs-unix": [ - "libbrotlidec.a", - "libbrotlienc.a", - "libbrotlicommon.a" + "pkg-configs": [ + "libbrotlicommon", + "libbrotlidec", + "libbrotlienc" ], "static-libs-windows": [ "brotlicommon.lib", @@ -89,7 +89,8 @@ "nghttp3", "ngtcp2", "zstd", - "libcares" + "libcares", + "ldap" ], "lib-suggests-windows": [ "brotli", @@ -185,14 +186,15 @@ }, "grpc": { "source": "grpc", - "static-libs-unix": [ - "libgrpc.a", - "libcares.a" + "pkg-configs": [ + "grpc" ], "lib-depends": [ "zlib", - "openssl" + "openssl", + "libcares" ], + "provide-pre-built": true, "frameworks": [ "CoreFoundation" ] @@ -200,11 +202,10 @@ "icu": { "source": "icu", "cpp-library": true, - "static-libs-unix": [ - "libicui18n.a", - "libicuio.a", - "libicuuc.a", - "libicudata.a" + "pkg-configs": [ + "icu-uc", + "icu-i18n", + "icu-io" ] }, "icu-static-win": { @@ -221,15 +222,16 @@ }, "imagemagick": { "source": "imagemagick", - "static-libs-unix": [ - "libMagick++-7.Q16HDRI.a", - "libMagickWand-7.Q16HDRI.a", - "libMagickCore-7.Q16HDRI.a" + "pkg-configs": [ + "Magick++-7.Q16HDRI", + "MagickCore-7.Q16HDRI", + "MagickWand-7.Q16HDRI" ], "lib-depends": [ "zlib", - "libpng", "libjpeg", + "libjxl", + "libpng", "libwebp", "freetype", "libtiff", @@ -252,11 +254,23 @@ "openssl" ] }, + "jbig": { + "source": "jbig", + "static-libs-unix": [ + "libjbig.a", + "libjbig85.a" + ], + "headers": [ + "jbig.h", + "jbig85.h", + "jbig_ar.h" + ] + }, "ldap": { "source": "ldap", - "static-libs-unix": [ - "libldap.a", - "liblber.a" + "pkg-configs": [ + "ldap", + "lber" ], "lib-depends": [ "openssl", @@ -265,6 +279,13 @@ "libsodium" ] }, + "lerc": { + "source": "lerc", + "static-libs-unix": [ + "libLerc.a" + ], + "cpp-library": true + }, "libacl": { "source": "libacl", "static-libs-unix": [ @@ -400,6 +421,21 @@ "zlib" ] }, + "libjxl": { + "source": "libjxl", + "pkg-configs": [ + "libjxl", + "libjxl_cms", + "libjxl_threads", + "libhwy" + ], + "lib-depends": [ + "brotli", + "libjpeg", + "libpng", + "libwebp" + ] + }, "liblz4": { "source": "liblz4", "static-libs-unix": [ @@ -485,9 +521,6 @@ ], "lib-depends": [ "openssl" - ], - "lib-suggests": [ - "zlib" ] }, "libtiff": { @@ -498,6 +531,13 @@ "lib-depends": [ "zlib", "libjpeg" + ], + "lib-suggests-unix": [ + "lerc", + "libwebp", + "jbig", + "xz", + "zstd" ] }, "libuuid": { @@ -517,12 +557,12 @@ }, "libwebp": { "source": "libwebp", - "static-libs-unix": [ - "libwebp.a", - "libwebpdecoder.a", - "libwebpdemux.a", - "libwebpmux.a", - "libsharpyuv.a" + "pkg-configs": [ + "libwebp", + "libwebpdecoder", + "libwebpdemux", + "libwebpmux", + "libsharpyuv" ], "static-libs-windows": [ "libwebp.lib", @@ -698,8 +738,8 @@ "openssl": { "source": "openssl", "static-libs-unix": [ - "libssl.a", - "libcrypto.a" + "libcrypto.a", + "libssl.a" ], "static-libs-windows": [ "libssl.lib", @@ -714,10 +754,8 @@ }, "postgresql": { "source": "postgresql", - "static-libs-unix": [ - "libpq.a", - "libpgport.a", - "libpgcommon.a" + "pkg-configs": [ + "libpq" ], "lib-depends": [ "libiconv", @@ -813,6 +851,15 @@ "libiconv" ] }, + "watcher": { + "source": "watcher", + "static-libs-unix": [ + "libwatcher-c.a" + ], + "headers": [ + "wtr/watcher-c.h" + ] + }, "xz": { "source": "xz", "static-libs-unix": [ @@ -866,14 +913,5 @@ "zstd.h", "zstd_errors.h" ] - }, - "watcher": { - "source": "watcher", - "static-libs-unix": [ - "libwatcher-c.a" - ], - "headers": [ - "wtr/watcher-c.h" - ] } } diff --git a/config/source.json b/config/source.json index 32f8d7c6..e49ef0f3 100644 --- a/config/source.json +++ b/config/source.json @@ -4,7 +4,8 @@ "license": { "type": "file", "path": "LICENSE" - } + }, + "alt": false }, "amqp": { "type": "url", @@ -387,6 +388,19 @@ "path": "LICENSE" } }, + "jbig": { + "type": "url", + "url": "https://dl.static-php.dev/static-php-cli/deps/jbig/jbigkit-2.1.tar.gz", + "provide-pre-built": true, + "alt": { + "type": "url", + "url": "https://www.cl.cam.ac.uk/~mgk25/jbigkit/download/jbigkit-2.1.tar.gz" + }, + "license": { + "type": "file", + "path": "COPYING" + } + }, "ldap": { "type": "filelist", "url": "https://www.openldap.org/software/download/OpenLDAP/openldap-release/", @@ -396,6 +410,16 @@ "path": "LICENSE" } }, + "lerc": { + "type": "ghtar", + "repo": "Esri/lerc", + "prefer-stable": true, + "provide-pre-built": true, + "license": { + "type": "file", + "path": "LICENSE" + } + }, "libacl": { "alt": { "type": "url", @@ -533,6 +557,21 @@ "path": "LICENSE.md" } }, + "libjxl": { + "type": "git", + "url": "https://github.com/libjxl/libjxl", + "rev": "main", + "submodules": [ + "third_party/highway", + "third_party/libjpeg-turbo", + "third_party/sjpeg", + "third_party/skcms" + ], + "license": { + "type": "file", + "path": "LICENSE" + } + }, "liblz4": { "type": "ghrel", "repo": "lz4/lz4", @@ -596,6 +635,7 @@ "repo": "libssh2/libssh2", "match": "libssh2.+\\.tar\\.gz", "prefer-stable": true, + "provide-pre-built": true, "license": { "type": "file", "path": "COPYING" @@ -605,7 +645,6 @@ "type": "filelist", "url": "https://download.osgeo.org/libtiff/", "regex": "/href=\"(?tiff-(?[^\"]+)\\.tar\\.xz)\"/", - "provide-pre-built": true, "license": { "type": "file", "path": "LICENSE.md" @@ -998,6 +1037,15 @@ "path": "COPYING" } }, + "watcher": { + "type": "ghtar", + "repo": "e-dant/watcher", + "prefer-stable": true, + "license": { + "type": "file", + "path": "license" + } + }, "xdebug": { "type": "url", "url": "https://pecl.php.net/get/xdebug", @@ -1078,14 +1126,5 @@ "type": "file", "path": "LICENSE" } - }, - "watcher": { - "type": "ghtar", - "repo": "e-dant/watcher", - "prefer-stable": true, - "license": { - "type": "file", - "path": "license" - } } } diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index b2e6bc09..3fcc6792 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -66,13 +66,17 @@ abstract class BuilderBase // build all libs foreach ($this->libs as $lib) { $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_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'), LIB_STATUS_BUILD_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'), LIB_STATUS_INSTALL_FAILED => logger()->error('lib [' . $lib::NAME . '] install failed'), 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.'); + } } } diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 76fc76d6..585ecfc7 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -10,7 +10,6 @@ use SPC\exception\WrongUsageException; use SPC\store\Config; use SPC\store\FileSystem; use SPC\util\SPCConfigUtil; -use SPC\util\SPCTarget; class Extension { @@ -84,13 +83,15 @@ class Extension */ 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); return match ($arg_type = Config::getExt($this->name, 'arg-type', 'enable')) { 'enable' => '--enable-' . $_name . ($shared ? '=shared' : '') . ' ', + 'enable-path' => '--enable-' . $_name . '=' . ($shared ? 'shared,' : '') . $escapedPath . ' ', 'with' => '--with-' . $_name . ($shared ? '=shared' : '') . ' ', - 'with-prefix' => '--with-' . $_name . '=' . ($shared ? 'shared,' : '') . '"' . BUILD_ROOT_PATH . '" ', + 'with-path' => '--with-' . $_name . '=' . ($shared ? 'shared,' : '') . $escapedPath . ' ', '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] ."), }; } @@ -516,8 +517,7 @@ class Extension $sharedLibString = ''; $staticLibString = ''; $staticLibs = $this->getLibFilesString(); - $staticLibs = str_replace(BUILD_LIB_PATH . '/lib', '-l', $staticLibs); - $staticLibs = str_replace('.a', '', $staticLibs); + $staticLibs = str_replace([BUILD_LIB_PATH . '/lib', '.a'], ['-l', ''], $staticLibs); $staticLibs = explode('-l', $staticLibs . ' ' . $config['libs']); foreach ($staticLibs as $lib) { $lib = trim($lib); @@ -533,8 +533,8 @@ class Extension $sharedLibString .= '-l' . $lib . ' '; } } - // move static libstdc++ to shared if we are on non-full-static build target - if (!SPCTarget::isStatic() && in_array(SPCTarget::getLibc(), SPCTarget::LIBC_LIST)) { + // move -lstdc++ to static libraries because centos 7 the shared libstdc++ is incomplete + if (str_contains((string) getenv('PATH'), 'rh/devtoolset-10')) { $staticLibString .= ' -lstdc++'; $sharedLibString = str_replace('-lstdc++', '', $sharedLibString); } diff --git a/src/SPC/builder/LibraryBase.php b/src/SPC/builder/LibraryBase.php index b97b5929..5f03d72c 100644 --- a/src/SPC/builder/LibraryBase.php +++ b/src/SPC/builder/LibraryBase.php @@ -182,22 +182,8 @@ abstract class LibraryBase return LIB_STATUS_INSTALL_FAILED; } } - foreach ($this->getStaticLibs() as $name) { - if (!file_exists(BUILD_LIB_PATH . "/{$name}")) { - $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; + if (!$this->isLibraryInstalled()) { + return $this->tryInstall($lock, true); } return LIB_STATUS_ALREADY; } @@ -240,28 +226,8 @@ abstract class LibraryBase return LIB_STATUS_OK; } - // check if these libraries exist, if not, invoke compilation and return the result status - foreach ($this->getStaticLibs() as $name) { - 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 (!$this->isLibraryInstalled()) { + return $this->tryBuild(true); } // if all the files exist at this point, skip the compilation process return LIB_STATUS_ALREADY; @@ -350,7 +316,27 @@ abstract class LibraryBase 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; + } } diff --git a/src/SPC/builder/extension/curl.php b/src/SPC/builder/extension/curl.php index 0c5de6a5..9ac3fd9b 100644 --- a/src/SPC/builder/extension/curl.php +++ b/src/SPC/builder/extension/curl.php @@ -7,6 +7,7 @@ namespace SPC\builder\extension; use SPC\builder\Extension; use SPC\builder\linux\LinuxBuilder; use SPC\builder\macos\MacOSBuilder; +use SPC\builder\windows\WindowsBuilder; use SPC\exception\FileSystemException; use SPC\exception\WrongUsageException; use SPC\store\FileSystem; @@ -57,6 +58,17 @@ class curl extends Extension return true; } + public function patchBeforeMake(): bool + { + $extra_libs = getenv('SPC_EXTRA_LIBS'); + if ($this->builder instanceof WindowsBuilder && !str_contains($extra_libs, 'secur32.lib')) { + $extra_libs .= ' secur32.lib'; + putenv('SPC_EXTRA_LIBS=' . trim($extra_libs)); + return true; + } + return false; + } + public function patchBeforeSharedConfigure(): bool { $file = $this->source_dir . '/config.m4'; diff --git a/src/SPC/builder/extension/grpc.php b/src/SPC/builder/extension/grpc.php index 852f2933..6ddfb008 100644 --- a/src/SPC/builder/extension/grpc.php +++ b/src/SPC/builder/extension/grpc.php @@ -5,36 +5,47 @@ declare(strict_types=1); namespace SPC\builder\extension; use SPC\builder\Extension; -use SPC\builder\macos\MacOSBuilder; use SPC\builder\windows\WindowsBuilder; use SPC\store\FileSystem; use SPC\util\CustomExt; use SPC\util\GlobalEnvManager; +use SPC\util\SPCConfigUtil; +use SPC\util\SPCTarget; #[CustomExt('grpc')] class grpc extends Extension { public function patchBeforeBuildconf(): bool { - // soft link to the grpc source code if ($this->builder instanceof WindowsBuilder) { - // not support windows yet throw new \RuntimeException('grpc extension does not support windows yet'); } - if (!is_link(SOURCE_PATH . '/php-src/ext/grpc')) { - if (is_dir($this->builder->getLib('grpc')->getSourceDir() . '/src/php/ext/grpc')) { - 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; + if (file_exists(SOURCE_PATH . '/php-src/ext/grpc')) { + return false; } - 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 @@ -43,9 +54,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'); return true; } - - public function getUnixConfigureArg(bool $shared = false): string - { - return '--enable-grpc=' . BUILD_ROOT_PATH . '/grpc GRPC_LIB_SUBDIR=' . BUILD_LIB_PATH; - } } diff --git a/src/SPC/builder/freebsd/BSDBuilder.php b/src/SPC/builder/freebsd/BSDBuilder.php index 65ebea57..3e9cc80b 100644 --- a/src/SPC/builder/freebsd/BSDBuilder.php +++ b/src/SPC/builder/freebsd/BSDBuilder.php @@ -63,18 +63,6 @@ class BSDBuilder extends UnixBuilderBase */ 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'); SourcePatcher::patchBeforeBuildconf($this); diff --git a/src/SPC/builder/freebsd/library/curl.php b/src/SPC/builder/freebsd/library/curl.php index 4eeab20d..2cad3ee7 100644 --- a/src/SPC/builder/freebsd/library/curl.php +++ b/src/SPC/builder/freebsd/library/curl.php @@ -9,13 +9,4 @@ class curl extends BSDLibraryBase use \SPC\builder\unix\library\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; - } } diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 94d8a41e..7628f667 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -11,6 +11,8 @@ use SPC\exception\WrongUsageException; use SPC\store\FileSystem; use SPC\store\SourcePatcher; use SPC\util\GlobalEnvManager; +use SPC\util\SPCConfigUtil; +use SPC\util\SPCTarget; class LinuxBuilder extends UnixBuilderBase { @@ -56,17 +58,6 @@ class LinuxBuilder extends UnixBuilderBase */ 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; f_putenv('CFLAGS=' . $cflags); @@ -106,7 +97,7 @@ class LinuxBuilder extends UnixBuilderBase $envs_build_php = SystemUtil::makeEnvVarString([ 'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'), 'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'), - 'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'), + 'LDFLAGS' => '-L' . BUILD_LIB_PATH, 'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'), ]); @@ -308,11 +299,13 @@ class LinuxBuilder extends UnixBuilderBase 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')); + $static = SPCTarget::isStatic() ? '-all-static' : ''; + $lib = BUILD_LIB_PATH; return [ 'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), - 'EXTRA_LIBS' => getenv('SPC_EXTRA_LIBS') . ' ' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS'), - 'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), - 'EXTRA_LDFLAGS_PROGRAM' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM'), + 'EXTRA_LIBS' => $config['libs'], + 'EXTRA_LDFLAGS_PROGRAM' => "-L{$lib} {$static} -pie", ]; } diff --git a/src/SPC/builder/linux/library/curl.php b/src/SPC/builder/linux/library/curl.php index f382773f..20ed10f2 100644 --- a/src/SPC/builder/linux/library/curl.php +++ b/src/SPC/builder/linux/library/curl.php @@ -9,13 +9,4 @@ class curl extends LinuxLibraryBase use \SPC\builder\unix\library\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; - } } diff --git a/src/SPC/builder/linux/library/icu.php b/src/SPC/builder/linux/library/icu.php index c911a2fe..7b8bcf8e 100644 --- a/src/SPC/builder/linux/library/icu.php +++ b/src/SPC/builder/linux/library/icu.php @@ -38,7 +38,7 @@ class icu extends LinuxLibraryBase ->exec("make -j{$this->builder->concurrency}") ->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'); } } diff --git a/src/SPC/builder/linux/library/jbig.php b/src/SPC/builder/linux/library/jbig.php new file mode 100644 index 00000000..e47e21f4 --- /dev/null +++ b/src/SPC/builder/linux/library/jbig.php @@ -0,0 +1,12 @@ +cd($this->source_dir)->initializeEnv($this) ->exec( "{$env} ./Configure no-shared {$extra} " . - '--prefix=/ ' . - '--libdir=lib ' . + '--prefix=' . BUILD_ROOT_PATH . ' ' . + '--libdir=' . BUILD_LIB_PATH . ' ' . '--openssldir=/etc/ssl ' . "{$zlib_extra}" . 'no-legacy ' . @@ -76,28 +76,19 @@ class openssl extends LinuxLibraryBase ) ->exec('make clean') ->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']); // patch for openssl 3.3.0+ 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=')) { - 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=')) { - 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 . '/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; - } } diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index 362a68fe..9b131b9d 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -12,6 +12,7 @@ use SPC\exception\WrongUsageException; use SPC\store\FileSystem; use SPC\store\SourcePatcher; use SPC\util\GlobalEnvManager; +use SPC\util\SPCConfigUtil; class MacOSBuilder extends UnixBuilderBase { @@ -88,21 +89,6 @@ class MacOSBuilder extends UnixBuilderBase */ public function buildPHP(int $build_target = BUILD_TARGET_NONE): void { - $extra_libs = getenv('SPC_EXTRA_LIBS') ?: ''; - // ---------- Update extra-libs ---------- - // add macOS frameworks - $extra_libs .= (empty($extra_libs) ? '' : ' ') . $this->getFrameworks(true); - // add libc++, some extensions or libraries need it (C++ cannot be linked statically) - $extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lc++ ' : ''); - // 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 { - logger()->info('bloat linking'); - $extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Wl,-force_load,{$x}", array_filter($this->getAllStaticLibFiles()))); - } - f_putenv('SPC_EXTRA_LIBS=' . $extra_libs); - $this->emitPatchPoint('before-php-buildconf'); SourcePatcher::patchBeforeBuildconf($this); @@ -130,7 +116,7 @@ class MacOSBuilder extends UnixBuilderBase $envs_build_php = SystemUtil::makeEnvVarString([ 'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'), 'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'), - 'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'), + 'LDFLAGS' => '-L' . BUILD_LIB_PATH, 'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'), ]); @@ -291,9 +277,11 @@ class MacOSBuilder extends UnixBuilderBase 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 [ 'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), - 'EXTRA_LIBS' => getenv('SPC_EXTRA_LIBS') . ' ' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS'), + 'EXTRA_LDFLAGS_PROGRAM' => '-L' . BUILD_LIB_PATH, + 'EXTRA_LIBS' => $config['libs'], ]; } } diff --git a/src/SPC/builder/macos/library/icu.php b/src/SPC/builder/macos/library/icu.php index d49f43f8..ebe1946f 100644 --- a/src/SPC/builder/macos/library/icu.php +++ b/src/SPC/builder/macos/library/icu.php @@ -21,7 +21,7 @@ class icu extends MacOSLibraryBase ->exec("make -j{$this->builder->concurrency}") ->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'); } } diff --git a/src/SPC/builder/macos/library/jbig.php b/src/SPC/builder/macos/library/jbig.php new file mode 100644 index 00000000..10b64974 --- /dev/null +++ b/src/SPC/builder/macos/library/jbig.php @@ -0,0 +1,12 @@ +cd($this->source_dir)->initializeEnv($this) ->exec( "./Configure no-shared {$extra} " . - '--prefix=/ ' . // use prefix=/ - "--libdir={$lib} " . + '--prefix=' . BUILD_ROOT_PATH . ' ' . // use prefix=/ + '--libdir=lib ' . '--openssldir=/etc/ssl ' . "darwin64-{$arch}-cc" ) ->exec('make clean') ->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']); // patch for openssl 3.3.0+ 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=')) { - 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=')) { - 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 . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")'); diff --git a/src/SPC/builder/traits/UnixLibraryTrait.php b/src/SPC/builder/traits/UnixLibraryTrait.php index e98a6f3a..1d69f82a 100644 --- a/src/SPC/builder/traits/UnixLibraryTrait.php +++ b/src/SPC/builder/traits/UnixLibraryTrait.php @@ -4,11 +4,12 @@ declare(strict_types=1); namespace SPC\builder\traits; -use SPC\builder\LibraryBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; +use SPC\store\Config; use SPC\store\FileSystem; +use SPC\util\SPCConfigUtil; trait UnixLibraryTrait { @@ -17,44 +18,13 @@ trait UnixLibraryTrait * @throws FileSystemException * @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] : []; - if ($recursive) { - array_unshift($libs, ...array_values($this->getDependencies(recursive: true))); - } - - $sep = match ($style) { - 'autoconf' => ' ', - 'cmake' => ';', - default => throw new RuntimeException('style only support autoconf and cmake'), - }; - $ret = []; - /** @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() . '"'; + 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']; } /** @@ -64,9 +34,12 @@ trait UnixLibraryTrait * @throws FileSystemException * @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'); + if ($files === [] && ($conf_pc = Config::getLib(static::NAME, 'pkg-configs', [])) !== []) { + $files = array_map(fn ($x) => "{$x}.pc", $conf_pc); + } foreach ($files as $name) { $realpath = realpath(BUILD_ROOT_PATH . '/lib/pkgconfig/' . $name); if ($realpath === false) { @@ -75,7 +48,7 @@ trait UnixLibraryTrait logger()->debug('Patching ' . $realpath); // replace prefix $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_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; diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index f0e4e169..27f9c01f 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -5,9 +5,6 @@ declare(strict_types=1); namespace SPC\builder\unix; 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\RuntimeException; use SPC\exception\WrongUsageException; @@ -27,85 +24,6 @@ abstract class UnixBuilderBase extends BuilderBase /** @var string C++ 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 { // search all supported libs @@ -210,11 +128,22 @@ abstract class UnixBuilderBase extends BuilderBase } // if someone changed to --enable-embed=shared, we need to add LD_LIBRARY_PATH if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') { - $ext_path = 'LD_LIBRARY_PATH=' . BUILD_ROOT_PATH . '/lib:$LD_LIBRARY_PATH '; - FileSystem::removeFileIfExists(BUILD_ROOT_PATH . '/lib/libphp.a'); + if (PHP_OS_FAMILY === 'Darwin') { + $ext_path = 'DYLD_LIBRARY_PATH=' . BUILD_LIB_PATH . ':$DYLD_LIBRARY_PATH '; + } else { + $ext_path = 'LD_LIBRARY_PATH=' . BUILD_LIB_PATH . ':$LD_LIBRARY_PATH '; + } + FileSystem::removeFileIfExists(BUILD_LIB_PATH . '/libphp.a'); } else { $ext_path = ''; - FileSystem::removeFileIfExists(BUILD_ROOT_PATH . '/lib/libphp.so'); + $suffix = PHP_OS_FAMILY === 'Darwin' ? 'dylib' : 'so'; + foreach (glob(BUILD_LIB_PATH . "/libphp*.{$suffix}") as $file) { + unlink($file); + } + } + [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens); + if ($ret !== 0) { + throw new RuntimeException('embed failed sanity check: build failed. Error message: ' . implode("\n", $out)); } [$ret, $output] = shell()->cd($sample_file_path)->execWithResult($ext_path . './embed'); if ($ret !== 0 || trim(implode('', $output)) !== 'hello') { @@ -229,8 +158,9 @@ abstract class UnixBuilderBase extends BuilderBase if (!file_exists($frankenphp)) { throw new RuntimeException('FrankenPHP binary not found: ' . $frankenphp); } + $prefix = PHP_OS_FAMILY === 'Darwin' ? 'DYLD_' : 'LD_'; [$ret, $output] = shell() - ->setEnv(['LD_LIBRARY_PATH' => BUILD_LIB_PATH]) + ->setEnv(["{$prefix}LIBRARY_PATH" => BUILD_LIB_PATH]) ->execWithResult("{$frankenphp} version"); if ($ret !== 0 || !str_contains(implode('', $output), 'FrankenPHP')) { throw new RuntimeException('FrankenPHP failed sanity check: ret[' . $ret . ']. out[' . implode('', $output) . ']'); diff --git a/src/SPC/builder/unix/library/curl.php b/src/SPC/builder/unix/library/curl.php index c38201e5..6e304d60 100644 --- a/src/SPC/builder/unix/library/curl.php +++ b/src/SPC/builder/unix/library/curl.php @@ -21,10 +21,10 @@ trait curl 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('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('nghttp2', fn ($lib) => "-DUSE_NGHTTP2=ON -DNGHTTP2_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DNGHTTP2_INCLUDE_DIR={$lib->getIncludeDir()}", '-DUSE_NGHTTP2=OFF') - ->optionalLib('nghttp3', fn ($lib) => "-DUSE_NGHTTP3=ON -DNGHTTP3_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DNGHTTP3_INCLUDE_DIR={$lib->getIncludeDir()}", '-DUSE_NGHTTP3=OFF') - ->optionalLib('ngtcp2', fn ($lib) => "-DUSE_NGTCP2=ON -DNGNGTCP2_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DNGNGTCP2_INCLUDE_DIR={$lib->getIncludeDir()}", '-DUSE_NGTCP2=OFF') + ->optionalLib('libssh2', ...cmake_boolean_args('CURL_USE_LIBSSH2')) + ->optionalLib('nghttp2', ...cmake_boolean_args('USE_NGHTTP2')) + ->optionalLib('nghttp3', ...cmake_boolean_args('USE_NGHTTP3')) + ->optionalLib('ngtcp2', ...cmake_boolean_args('USE_NGTCP2')) ->optionalLib('ldap', ...cmake_boolean_args('CURL_DISABLE_LDAP', true)) ->optionalLib('zstd', ...cmake_boolean_args('CURL_ZSTD')) ->optionalLib('idn2', ...cmake_boolean_args('USE_LIBIDN2')) diff --git a/src/SPC/builder/unix/library/grpc.php b/src/SPC/builder/unix/library/grpc.php index a7472448..f8fed3d9 100644 --- a/src/SPC/builder/unix/library/grpc.php +++ b/src/SPC/builder/unix/library/grpc.php @@ -4,22 +4,55 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\builder\linux\SystemUtil; use SPC\store\FileSystem; +use SPC\util\executor\UnixCMakeExecutor; +use SPC\util\SPCTarget; trait grpc { + public function patchBeforeBuild(): bool + { + FileSystem::replaceFileStr( + $this->source_dir . '/third_party/re2/util/pcre.h', + ["#define UTIL_PCRE_H_\n#include ", '#define UTIL_PCRE_H_'], + ['#define UTIL_PCRE_H_', "#define UTIL_PCRE_H_\n#include "], + ); + return true; + } + protected function build(): void { - shell()->cd($this->source_dir) - ->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); - copy($this->source_dir . '/libs/opt/libgrpc.a', BUILD_LIB_PATH . '/libgrpc.a'); - copy($this->source_dir . '/libs/opt/libboringssl.a', BUILD_LIB_PATH . '/libboringssl.a'); - if (!file_exists(BUILD_LIB_PATH . '/libcares.a')) { - copy($this->source_dir . '/libs/opt/libcares.a', BUILD_LIB_PATH . '/libcares.a'); + $cmake = UnixCMakeExecutor::create($this) + ->setBuildDir("{$this->source_dir}/avoid_BUILD_file_conflict") + ->addConfigureArgs( + '-DgRPC_INSTALL_BINDIR=' . BUILD_BIN_PATH, + '-DgRPC_INSTALL_LIBDIR=' . BUILD_LIB_PATH, + '-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++'); - 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'); + + $cmake->build(); + + $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']); } } diff --git a/src/SPC/builder/unix/library/icu.php b/src/SPC/builder/unix/library/icu.php index d1aa8dc1..6f2e8611 100644 --- a/src/SPC/builder/unix/library/icu.php +++ b/src/SPC/builder/unix/library/icu.php @@ -17,6 +17,7 @@ trait icu protected function install(): void { + parent::install(); $icu_config = BUILD_ROOT_PATH . '/bin/icu-config'; FileSystem::replaceFileStr($icu_config, '{BUILD_ROOT_PATH}', BUILD_ROOT_PATH); } diff --git a/src/SPC/builder/unix/library/imagemagick.php b/src/SPC/builder/unix/library/imagemagick.php index d7cfa887..3a6975af 100644 --- a/src/SPC/builder/unix/library/imagemagick.php +++ b/src/SPC/builder/unix/library/imagemagick.php @@ -32,9 +32,9 @@ trait imagemagick ->optionalLib('zstd', ...ac_with_args('zstd')) ->optionalLib('freetype', ...ac_with_args('freetype')) ->optionalLib('bzip2', ...ac_with_args('bzlib')) + ->optionalLib('libjxl', ...ac_with_args('jxl')) ->addConfigureArgs( '--disable-openmp', - '--without-jxl', '--without-x', ); diff --git a/src/SPC/builder/unix/library/jbig.php b/src/SPC/builder/unix/library/jbig.php new file mode 100644 index 00000000..85e24748 --- /dev/null +++ b/src/SPC/builder/unix/library/jbig.php @@ -0,0 +1,35 @@ +source_dir . '/Makefile', 'CFLAGS = -O2 -W -Wno-unused-result', 'CFLAGS = -O2 -W -Wno-unused-result -fPIC'); + return true; + } + + /** + * @throws RuntimeException + */ + protected function build(): void + { + shell()->cd($this->source_dir)->initializeEnv($this) + ->exec("make -j{$this->builder->concurrency} {$this->builder->getEnvString()} lib") + ->exec('cp libjbig/libjbig.a ' . BUILD_LIB_PATH) + ->exec('cp libjbig/libjbig85.a ' . BUILD_LIB_PATH) + ->exec('cp libjbig/jbig.h ' . BUILD_INCLUDE_PATH) + ->exec('cp libjbig/jbig85.h ' . BUILD_INCLUDE_PATH) + ->exec('cp libjbig/jbig_ar.h ' . BUILD_INCLUDE_PATH); + } +} diff --git a/src/SPC/builder/unix/library/lerc.php b/src/SPC/builder/unix/library/lerc.php new file mode 100644 index 00000000..290c0f61 --- /dev/null +++ b/src/SPC/builder/unix/library/lerc.php @@ -0,0 +1,22 @@ +build(); + } +} diff --git a/src/SPC/builder/unix/library/libevent.php b/src/SPC/builder/unix/library/libevent.php index 55889d1d..ab4838e3 100644 --- a/src/SPC/builder/unix/library/libevent.php +++ b/src/SPC/builder/unix/library/libevent.php @@ -68,6 +68,7 @@ trait libevent protected function install(): void { + parent::install(); FileSystem::replaceFileStr( BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake', '{BUILD_ROOT_PATH}', diff --git a/src/SPC/builder/unix/library/libjxl.php b/src/SPC/builder/unix/library/libjxl.php new file mode 100644 index 00000000..871477b9 --- /dev/null +++ b/src/SPC/builder/unix/library/libjxl.php @@ -0,0 +1,28 @@ +addConfigureArgs('-DJPEGXL_ENABLE_TOOLS=OFF') + ->addConfigureArgs('-DJPEGXL_ENABLE_EXAMPLES=OFF') + ->addConfigureArgs('-DJPEGXL_ENABLE_MANPAGES=OFF') + ->addConfigureArgs('-DJPEGXL_ENABLE_BENCHMARK=OFF') + ->addConfigureArgs('-DJPEGXL_ENABLE_PLUGINS=OFF') + ->addConfigureArgs('-DJPEGXL_ENABLE_SJPOEG=ON') + ->addConfigureArgs('-DJPEGXL_ENABLE_JNI=OFF') + ->addConfigureArgs('-DJPEGXL_ENABLE_TRANSCODE_JPEG=ON') + ->addConfigureArgs('-DJPEGXL_STATIC=' . (SPCTarget::isStatic() ? 'ON' : 'OFF')) + ->addConfigureArgs('-DJPEGXL_FORCE_SYSTEM_BROTLI=ON') + ->addConfigureArgs('-DBUILD_TESTING=OFF') + ->build(); + } +} diff --git a/src/SPC/builder/unix/library/libtiff.php b/src/SPC/builder/unix/library/libtiff.php index f615019a..b4afdd7f 100644 --- a/src/SPC/builder/unix/library/libtiff.php +++ b/src/SPC/builder/unix/library/libtiff.php @@ -6,7 +6,9 @@ namespace SPC\builder\unix\library; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\store\FileSystem; use SPC\util\executor\UnixAutoconfExecutor; +use SPC\util\SPCTarget; trait libtiff { @@ -16,7 +18,15 @@ trait libtiff */ protected function build(): void { + $libcpp = SPCTarget::getTargetOS() === 'Linux' ? '-lstdc++' : '-lc++'; + FileSystem::replaceFileStr($this->source_dir . '/configure', '-lwebp', '-lwebp -lsharpyuv'); + FileSystem::replaceFileStr($this->source_dir . '/configure', '-l"$lerc_lib_name"', '-l"$lerc_lib_name" ' . $libcpp); UnixAutoconfExecutor::create($this) + ->optionalLib('lerc', '--enable-lerc', '--disable-lerc') + ->optionalLib('zstd', '--enable-zstd', '--disable-zstd') + ->optionalLib('libwebp', '--enable-webp', '--disable-webp') + ->optionalLib('xz', '--enable-lzma', '--disable-lzma') + ->optionalLib('jbig', '--enable-jbig', '--disable-jbig') ->configure( // zlib deps '--enable-zlib', @@ -24,16 +34,15 @@ trait libtiff "--with-zlib-lib-dir={$this->getLibDir()}", // libjpeg deps '--enable-jpeg', - '--disable-old-jpeg', - '--disable-jpeg12', "--with-jpeg-include-dir={$this->getIncludeDir()}", "--with-jpeg-lib-dir={$this->getLibDir()}", - // We disabled lzma, zstd, webp, libdeflate by default to reduce the size of the binary - '--disable-lzma', - '--disable-zstd', - '--disable-webp', + '--disable-old-jpeg', + '--disable-jpeg12', '--disable-libdeflate', + '--disable-tools', + '--disable-contrib', '--disable-cxx', + '--without-x', ) ->make(); $this->patchPkgconfPrefix(['libtiff-4.pc']); diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 32331ea2..a7651dd5 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -22,8 +22,7 @@ trait libwebp ->addConfigureArgs('-DWEBP_BUILD_EXTRAS=ON') ->build(); // 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(['libwebp.pc'], PKGCONF_PATCH_CUSTOM, ['/-lwebp$/m', '-lwebp -lsharpyuv']); } } diff --git a/src/SPC/builder/unix/library/libxslt.php b/src/SPC/builder/unix/library/libxslt.php index aabc277d..98ceba8d 100644 --- a/src/SPC/builder/unix/library/libxslt.php +++ b/src/SPC/builder/unix/library/libxslt.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace SPC\builder\unix\library; use SPC\builder\linux\library\LinuxLibraryBase; +use SPC\builder\macos\library\MacOSLibraryBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; @@ -20,11 +21,12 @@ trait libxslt protected function build(): void { $static_libs = $this instanceof LinuxLibraryBase ? $this->getStaticLibFiles(include_self: false) : ''; + $cpp = $this instanceof MacOSLibraryBase ? '-lc++' : '-lstdc++'; $ac = UnixAutoconfExecutor::create($this) ->appendEnv([ 'CFLAGS' => "-I{$this->getIncludeDir()}", 'LDFLAGS' => "-L{$this->getLibDir()}", - 'LIBS' => "{$static_libs} -lstdc++", + 'LIBS' => "{$static_libs} {$cpp}", ]) ->addConfigureArgs( '--without-python', @@ -41,7 +43,7 @@ trait libxslt } $ac->configure()->make(); - $this->patchPkgconfPrefix(['libexslt.pc']); + $this->patchPkgconfPrefix(['libexslt.pc', 'libxslt.pc']); $this->patchLaDependencyPrefix(); shell()->cd(BUILD_LIB_PATH) ->exec("ar -t libxslt.a | grep '\\.a$' | xargs -n1 ar d libxslt.a") diff --git a/src/SPC/builder/unix/library/ngtcp2.php b/src/SPC/builder/unix/library/ngtcp2.php index df29fba3..9c9919d8 100644 --- a/src/SPC/builder/unix/library/ngtcp2.php +++ b/src/SPC/builder/unix/library/ngtcp2.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\builder\linux\library\LinuxLibraryBase; +use SPC\builder\macos\library\MacOSLibraryBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; @@ -19,7 +21,7 @@ trait ngtcp2 protected function build(): void { UnixAutoconfExecutor::create($this) - ->optionalLib('openssl', fn ($lib) => implode(' ', [ + ->optionalLib('openssl', fn (LinuxLibraryBase|MacOSLibraryBase $lib) => implode(' ', [ '--with-openssl=yes', "OPENSSL_LIBS=\"{$lib->getStaticLibFiles()}\"", "OPENSSL_CFLAGS=\"-I{$lib->getIncludeDir()}\"", @@ -29,7 +31,7 @@ trait ngtcp2 ->optionalLib('jemalloc', ...ac_with_args('jemalloc', true)) ->optionalLib( 'brotli', - fn ($lib) => implode(' ', [ + fn (LinuxLibraryBase|MacOSLibraryBase $lib) => implode(' ', [ '--with-brotlidec=yes', "LIBBROTLIDEC_CFLAGS=\"-I{$lib->getIncludeDir()}\"", "LIBBROTLIDEC_LIBS=\"{$lib->getStaticLibFiles()}\"", diff --git a/src/SPC/builder/unix/library/xz.php b/src/SPC/builder/unix/library/xz.php index f127e59a..98f33bea 100644 --- a/src/SPC/builder/unix/library/xz.php +++ b/src/SPC/builder/unix/library/xz.php @@ -21,6 +21,7 @@ trait xz '--disable-scripts', '--disable-doc', '--with-libiconv', + '--bindir=/tmp/xz', // xz binary will corrupt `tar` command, that's really strange. ) ->make(); $this->patchPkgconfPrefix(['liblzma.pc']); diff --git a/src/SPC/builder/windows/WindowsBuilder.php b/src/SPC/builder/windows/WindowsBuilder.php index 25a503eb..4becc926 100644 --- a/src/SPC/builder/windows/WindowsBuilder.php +++ b/src/SPC/builder/windows/WindowsBuilder.php @@ -61,11 +61,6 @@ class WindowsBuilder extends BuilderBase */ public function buildPHP(int $build_target = BUILD_TARGET_NONE): void { - // ---------- Update extra-libs ---------- - $extra_libs = getenv('SPC_EXTRA_LIBS') ?: ''; - $extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles()); - f_putenv('SPC_EXTRA_LIBS=' . $extra_libs); - $enableCli = ($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI; $enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM; $enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO; @@ -162,8 +157,10 @@ class WindowsBuilder extends BuilderBase { SourcePatcher::patchWindowsCLITarget(); + $extra_libs = getenv('SPC_EXTRA_LIBS') ?: ''; + // add nmake wrapper - FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_cli_wrapper.bat', "nmake /nologo LIBS_CLI=\"{$this->getOption('extra-libs')} ws2_32.lib shell32.lib\" EXTRA_LD_FLAGS_PROGRAM= %*"); + FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_cli_wrapper.bat', "nmake /nologo LIBS_CLI=\"ws2_32.lib shell32.lib {$extra_libs}\" EXTRA_LD_FLAGS_PROGRAM= %*"); cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_cli_wrapper.bat --task-args php.exe"); @@ -197,9 +194,11 @@ class WindowsBuilder extends BuilderBase } FileSystem::writeFile(SOURCE_PATH . '\php-src\Makefile', $makefile); + $extra_libs = getenv('SPC_EXTRA_LIBS') ?: ''; + // add nmake wrapper $fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' /DPHP_MICRO_FAKE_CLI" ' : ''; - $wrapper = "nmake /nologo LIBS_MICRO=\"{$this->getOption('extra-libs')} ws2_32.lib shell32.lib\" CFLAGS_MICRO=\"/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1{$fake_cli}\" %*"; + $wrapper = "nmake /nologo LIBS_MICRO=\"ws2_32.lib shell32.lib {$extra_libs}\" CFLAGS_MICRO=\"/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1{$fake_cli}\" %*"; FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_micro_wrapper.bat', $wrapper); // phar patch for micro diff --git a/src/SPC/builder/windows/library/curl.php b/src/SPC/builder/windows/library/curl.php index a758bf05..1229dbd6 100644 --- a/src/SPC/builder/windows/library/curl.php +++ b/src/SPC/builder/windows/library/curl.php @@ -37,6 +37,7 @@ class curl extends WindowsLibraryBase '-DBUILD_EXAMPLES=OFF ' . // disable examples '-DUSE_LIBIDN2=OFF ' . // disable libidn2 '-DCURL_USE_LIBPSL=OFF ' . // disable libpsl + '-DUSE_WINDOWS_SSPI=ON ' . // use Schannel instead of OpenSSL '-DCURL_USE_SCHANNEL=ON ' . // use Schannel instead of OpenSSL '-DCURL_USE_OPENSSL=OFF ' . // disable openssl due to certificate issue '-DCURL_ENABLE_SSL=ON ' . diff --git a/src/SPC/command/BuildCommand.php b/src/SPC/command/BuildCommand.php index 6020931f..0285c333 100644 --- a/src/SPC/command/BuildCommand.php +++ b/src/SPC/command/BuildCommand.php @@ -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('bloat', null, null, 'add all libraries into binary'); $this->addOption('rebuild', 'r', null, 'Delete old build and rebuild'); $this->addOption('enable-zts', null, null, 'enable ZTS support'); } diff --git a/src/SPC/command/DownloadCommand.php b/src/SPC/command/DownloadCommand.php index 1e895bdb..dfa4c9ee 100644 --- a/src/SPC/command/DownloadCommand.php +++ b/src/SPC/command/DownloadCommand.php @@ -245,11 +245,14 @@ class DownloadCommand extends BaseCommand } // if download failed, we will try to download alternative sources logger()->warning("Download failed: {$e->getMessage()}"); - logger()->notice("Trying to download alternative sources for {$source}"); $alt_sources = Config::getSource($source)['alt'] ?? null; if ($alt_sources === null) { - $alt_config = array_merge($config, $this->getDefaultAlternativeSource($source)); + logger()->warning("No alternative sources found for {$source}, using default alternative source"); + $alt_config = array_merge($config, Downloader::getDefaultAlternativeSource($source)); + } elseif ($alt_sources === false) { + throw new DownloaderException("No alternative sources found for {$source}, skipping alternative download"); } else { + logger()->notice("Trying to download alternative sources for {$source}"); $alt_config = array_merge($config, $alt_sources); } Downloader::downloadSource($source, $alt_config, $force_all || in_array($source, $force_list)); @@ -395,27 +398,4 @@ class DownloadCommand extends BaseCommand } return static::FAILURE; } - - private function getDefaultAlternativeSource(string $source_name): array - { - return [ - 'type' => 'custom', - 'func' => function (bool $force, array $source, int $download_as) use ($source_name) { - logger()->debug("Fetching alternative source for {$source_name}"); - // get from dl.static-php.dev - $url = "https://dl.static-php.dev/static-php-cli/deps/spc-download-mirror/{$source_name}/?format=json"; - $json = json_decode(Downloader::curlExec(url: $url, retries: intval(getenv('SPC_DOWNLOAD_RETRIES') ?: 0)), true); - if (!is_array($json)) { - throw new RuntimeException('failed http fetch'); - } - $item = $json[0] ?? null; - if ($item === null) { - throw new RuntimeException('failed to parse json'); - } - $full_url = 'https://dl.static-php.dev' . $item['full_path']; - $filename = basename($item['full_path']); - Downloader::downloadFile($source_name, $full_url, $filename, $source['path'] ?? null, $download_as); - }, - ]; - } } diff --git a/src/SPC/command/InstallPkgCommand.php b/src/SPC/command/InstallPkgCommand.php index b1ea3cd5..19d1532b 100644 --- a/src/SPC/command/InstallPkgCommand.php +++ b/src/SPC/command/InstallPkgCommand.php @@ -24,6 +24,8 @@ class InstallPkgCommand extends BaseCommand $this->addArgument('packages', InputArgument::REQUIRED, 'The packages will be installed, comma separated'); $this->addOption('shallow-clone', null, null, 'Clone shallow'); $this->addOption('custom-url', 'U', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Specify custom source download url, e.g "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"'); + $this->addOption('no-alt', null, null, 'Do not download alternative packages'); + $this->addOption('skip-extract', null, null, 'Skip package extraction, just download the package archive'); } /** @@ -66,10 +68,20 @@ class InstallPkgCommand extends BaseCommand $new_config['filename'] = $config['filename']; } logger()->info("Installing source {$pkg} from custom url [{$ni}/{$cnt}]"); - PackageManager::installPackage($pkg, $new_config); + PackageManager::installPackage( + $pkg, + $new_config, + allow_alt: false, + extract: !$this->getOption('skip-extract') + ); } else { logger()->info("Fetching package {$pkg} [{$ni}/{$cnt}]"); - PackageManager::installPackage($pkg, Config::getPkg($pkg)); + PackageManager::installPackage( + $pkg, + Config::getPkg($pkg), + allow_alt: !$this->getOption('no-alt'), + extract: !$this->getOption('skip-extract') + ); } } $time = round(microtime(true) - START_TIME, 3); diff --git a/src/SPC/command/SPCConfigCommand.php b/src/SPC/command/SPCConfigCommand.php index a1886ed1..4b6d1bc4 100644 --- a/src/SPC/command/SPCConfigCommand.php +++ b/src/SPC/command/SPCConfigCommand.php @@ -23,6 +23,9 @@ class SPCConfigCommand extends BaseCommand $this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts'); $this->addOption('includes', null, null, 'Add additional include path'); $this->addOption('libs', null, null, 'Add additional libs path'); + $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_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); - if ($this->getOption('includes')) { - $this->output->writeln($config['cflags']); - } elseif ($this->getOption('libs')) { - $this->output->writeln("{$config['ldflags']} {$config['libs']}"); - } else { - $this->output->writeln("{$config['cflags']} {$config['ldflags']} {$config['libs']}"); - } + $this->output->writeln(match (true) { + $this->getOption('includes') => $config['cflags'], + $this->getOption('libs-only-deps') => $config['libs'], + $this->getOption('libs') => "{$config['ldflags']} {$config['libs']}", + default => "{$config['cflags']} {$config['ldflags']} {$config['libs']}", + }); return 0; } diff --git a/src/SPC/command/dev/PackLibCommand.php b/src/SPC/command/dev/PackLibCommand.php index e51cdb17..366ef71e 100644 --- a/src/SPC/command/dev/PackLibCommand.php +++ b/src/SPC/command/dev/PackLibCommand.php @@ -42,6 +42,19 @@ class PackLibCommand extends BuildCommand $builder->proveLibs($libraries); $builder->validateLibsAndExts(); + + // before pack, check if the dependency tree contains lib-suggests + foreach ($libraries as $lib) { + if (Config::getLib($lib, 'lib-suggests', []) !== []) { + logger()->critical("The library {$lib} has lib-suggests, packing [{$lib_name}] is not safe, abort !"); + return static::FAILURE; + } + } + + $origin_files = []; + // get pack placehoder defines + $placehoder = get_pack_replace(); + foreach ($builder->getLibs() as $lib) { if ($lib->getName() !== $lib_name) { // other dependencies: install or build, both ok @@ -64,6 +77,27 @@ class PackLibCommand extends BuildCommand // After build: load buildroot/ directory, and calculate increase files $after_buildroot = FileSystem::scanDirFiles(BUILD_ROOT_PATH, relative: true); $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 // get BUILD_ROOT_PATH last dir part $buildroot_part = basename(BUILD_ROOT_PATH); @@ -85,6 +119,16 @@ class PackLibCommand extends BuildCommand $filename = WORKING_DIR . '/dist/' . $filename; f_passthru("tar {$tar_option} {$filename} -T " . WORKING_DIR . '/packlib_files.txt'); 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); } } diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index f031d73a..c9b71c86 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -219,34 +219,41 @@ class Downloader * @throws RuntimeException * @throws WrongUsageException */ - public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retries = 0, int $lock_as = SPC_DOWNLOAD_SOURCE): void + public static function downloadGit(string $name, string $url, string $branch, ?array $submodules = null, ?string $move_path = null, int $retries = 0, int $lock_as = SPC_DOWNLOAD_SOURCE): void { $download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}"); if (file_exists($download_path)) { FileSystem::removeDir($download_path); } logger()->debug("cloning {$name} source"); - $check = !defined('DEBUG_MODE') ? ' -q' : ''; - $cancel_func = function () use ($download_path) { + + $quiet = !defined('DEBUG_MODE') ? '-q --quiet' : ''; + $git = SPC_GIT_EXEC; + $shallow = defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : ''; + $recursive = ($submodules === null) ? '--recursive' : ''; + + try { + self::registerCancelEvent(function () use ($download_path) { + if (is_dir($download_path)) { + logger()->warning('Removing path ' . $download_path); + FileSystem::removeDir($download_path); + } + }); + f_passthru("{$git} clone {$quiet} --config core.autocrlf=false --branch \"{$branch}\" {$shallow} {$recursive} \"{$url}\" \"{$download_path}\""); + if ($submodules !== null) { + foreach ($submodules as $submodule) { + f_passthru("cd \"{$download_path}\" && {$git} submodule update --init " . escapeshellarg($submodule)); + } + } + } catch (RuntimeException $e) { if (is_dir($download_path)) { - logger()->warning('Removing path ' . $download_path); FileSystem::removeDir($download_path); } - }; - try { - self::registerCancelEvent($cancel_func); - f_passthru( - SPC_GIT_EXEC . ' clone' . $check . - (defined('DEBUG_MODE') ? '' : ' --quiet') . - ' --config core.autocrlf=false ' . - "--branch \"{$branch}\" " . (defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '') . " --recursive \"{$url}\" \"{$download_path}\"" - ); - } catch (RuntimeException $e) { if ($e->getCode() === 2 || $e->getCode() === -1073741510) { throw new WrongUsageException('Keyboard interrupted, download failed !'); } if ($retries > 0) { - self::downloadGit($name, $url, $branch, $move_path, $retries - 1); + self::downloadGit($name, $url, $branch, $submodules, $move_path, $retries - 1, $lock_as); return; } throw $e; @@ -343,6 +350,7 @@ class Downloader $name, $pkg['url'], $pkg['rev'], + $pkg['submodules'] ?? null, $pkg['extract'] ?? null, self::getRetryAttempts(), SPC_DOWNLOAD_PRE_BUILT @@ -360,6 +368,11 @@ class Downloader break; case 'custom': // Custom download method, like API-based download or other $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/pkg', 'SPC\store\pkg'); + if (isset($pkg['func']) && is_callable($pkg['func'])) { + $pkg['name'] = $name; + $pkg['func']($force, $pkg, SPC_DOWNLOAD_PACKAGE); + break; + } foreach ($classes as $class) { if (is_a($class, CustomPackage::class, true) && $class !== CustomPackage::class) { $cls = new $class(); @@ -462,6 +475,7 @@ class Downloader $name, $source['url'], $source['rev'], + $source['submodules'] ?? null, $source['path'] ?? null, self::getRetryAttempts(), $download_as @@ -599,6 +613,29 @@ class Downloader return "{$source}-{$os_family}-{$gnu_arch}-{$libc}-{$libc_version}"; } + public static function getDefaultAlternativeSource(string $source_name): array + { + return [ + 'type' => 'custom', + 'func' => function (bool $force, array $source, int $download_as) use ($source_name) { + logger()->debug("Fetching alternative source for {$source_name}"); + // get from dl.static-php.dev + $url = "https://dl.static-php.dev/static-php-cli/deps/spc-download-mirror/{$source_name}/?format=json"; + $json = json_decode(Downloader::curlExec(url: $url, retries: intval(getenv('SPC_DOWNLOAD_RETRIES') ?: 0)), true); + if (!is_array($json)) { + throw new RuntimeException('failed http fetch'); + } + $item = $json[0] ?? null; + if ($item === null) { + throw new RuntimeException('failed to parse json'); + } + $full_url = 'https://dl.static-php.dev' . $item['full_path']; + $filename = basename($item['full_path']); + Downloader::downloadFile($source_name, $full_url, $filename, $source['path'] ?? null, $download_as); + }, + ]; + } + /** * Register CTRL+C event for different OS. * diff --git a/src/SPC/store/PackageManager.php b/src/SPC/store/PackageManager.php index d5c1043d..dc662a5b 100644 --- a/src/SPC/store/PackageManager.php +++ b/src/SPC/store/PackageManager.php @@ -4,13 +4,14 @@ declare(strict_types=1); namespace SPC\store; +use SPC\exception\DownloaderException; use SPC\exception\FileSystemException; use SPC\exception\WrongUsageException; use SPC\store\pkg\CustomPackage; class PackageManager { - public static function installPackage(string $pkg_name, ?array $config = null, bool $force = false): void + public static function installPackage(string $pkg_name, ?array $config = null, bool $force = false, bool $allow_alt = true, bool $extract = true): void { if ($config === null) { $config = Config::getPkg($pkg_name); @@ -32,7 +33,31 @@ class PackageManager } // Download package - Downloader::downloadPackage($pkg_name, $config, $force); + try { + Downloader::downloadPackage($pkg_name, $config, $force); + } catch (\Throwable $e) { + if (!$allow_alt) { + throw new DownloaderException("Download package {$pkg_name} failed: " . $e->getMessage()); + } + // if download failed, we will try to download alternative packages + logger()->warning("Download package {$pkg_name} failed: " . $e->getMessage()); + $alt = $config['alt'] ?? null; + if ($alt === null) { + logger()->warning("No alternative package found for {$pkg_name}, using default mirror."); + $alt_config = array_merge($config, Downloader::getDefaultAlternativeSource($pkg_name)); + } elseif ($alt === false) { + logger()->error("No alternative package found for {$pkg_name}."); + throw $e; + } else { + logger()->notice("Trying alternative package for {$pkg_name}."); + $alt_config = array_merge($config, $alt); + } + Downloader::downloadPackage($pkg_name, $alt_config, $force); + } + if (!$extract) { + logger()->info("Package [{$pkg_name}] downloaded, but extraction is skipped."); + return; + } if (Config::getPkg($pkg_name)['type'] === 'custom') { // Custom extract function $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/pkg', 'SPC\store\pkg'); diff --git a/src/SPC/util/ConfigValidator.php b/src/SPC/util/ConfigValidator.php index dbc8ce23..b908efce 100644 --- a/src/SPC/util/ConfigValidator.php +++ b/src/SPC/util/ConfigValidator.php @@ -90,6 +90,9 @@ class ConfigValidator if (isset($lib['static-libs' . $suffix]) && !is_list_array($lib['static-libs' . $suffix])) { 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 if (isset($lib['frameworks']) && !is_list_array($lib['frameworks'])) { diff --git a/src/SPC/util/PkgConfigUtil.php b/src/SPC/util/PkgConfigUtil.php new file mode 100644 index 00000000..87075b49 --- /dev/null +++ b/src/SPC/util/PkgConfigUtil.php @@ -0,0 +1,75 @@ +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,89 @@ class SPCConfigUtil } ob_get_clean(); $ldflags = $this->getLdflagsString(); - $libs = $this->getLibsString($libraries, $with_dependencies); - if (SPCTarget::getTargetOS() === 'Darwin') { - $libs .= " {$this->getFrameworksString($extensions)}"; - } - $cflags = $this->getIncludesString(); + $cflags = $this->getIncludesString($libraries); + $libs = $this->getLibsString($libraries, !$this->absolute_libs); - // embed - $libs = trim("-lphp -lc {$libs}"); + // additional OS-specific libraries (e.g. macOS -lresolv) $extra_env = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS'); if (is_string($extra_env)) { $libs .= ' ' . trim($extra_env, '"'); } - // c++ - if ($this->builder->hasCpp()) { - $libs .= $this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++'; + $extra_env = getenv('SPC_EXTRA_LIBS'); + if (is_string($extra_env) && !empty($extra_env)) { + $libs .= " {$extra_env}"; } + // 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) { + 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 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 [ 'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags), '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; - $php_embed_includes = [ - "-I{$base}", - "-I{$base}/php", - "-I{$base}/php/main", - "-I{$base}/php/TSRM", - "-I{$base}/php/Zend", - "-I{$base}/php/ext", - ]; - return implode(' ', $php_embed_includes); + $includes = ["-I{$base}"]; + + // link with libphp + if (!$this->no_php) { + $includes = [ + ...$includes, + "-I{$base}/php", + "-I{$base}/php/main", + "-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 @@ -100,55 +159,62 @@ class SPCConfigUtil 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 = []; - foreach (array_reverse($libraries) as $library) { + $lib_names = []; + $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', []); foreach ($libs as $lib) { - if ($withDependencies) { - $noExt = str_replace('.a', '', $lib); - $requiredLibs = []; - $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); + // check file existence + if (!file_exists(BUILD_LIB_PATH . "/{$lib}")) { + throw new WrongUsageException("Library file '{$lib}' for lib [{$library}] does not exist in '" . BUILD_LIB_PATH . "'. Please build it first."); } + $lib_names[] = $this->getShortLibName($lib); } - if (PHP_OS_FAMILY !== 'Darwin') { - continue; + // add frameworks for macOS + 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; - if (!in_array($ks, $short_name)) { - $short_name[] = $ks; + if (!in_array($ks, $lib_names)) { + $lib_names[] = $ks; } } } + 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 @@ -160,6 +226,19 @@ class SPCConfigUtil 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 { $list = []; diff --git a/src/SPC/util/SPCTarget.php b/src/SPC/util/SPCTarget.php index 071f2620..b674379e 100644 --- a/src/SPC/util/SPCTarget.php +++ b/src/SPC/util/SPCTarget.php @@ -73,7 +73,7 @@ class SPCTarget public static function getTargetOS(): string { $target = getenv('SPC_TARGET'); - if ($target === false) { + if ($target === false || $target === '') { return PHP_OS_FAMILY; } // TODO: zig target parser like below? diff --git a/src/SPC/util/executor/UnixAutoconfExecutor.php b/src/SPC/util/executor/UnixAutoconfExecutor.php index 1c9f496e..8f923b1f 100644 --- a/src/SPC/util/executor/UnixAutoconfExecutor.php +++ b/src/SPC/util/executor/UnixAutoconfExecutor.php @@ -12,7 +12,7 @@ use SPC\util\UnixShell; class UnixAutoconfExecutor extends Executor { - protected ?UnixShell $shell = null; + protected UnixShell $shell; protected array $configure_args = []; diff --git a/src/SPC/util/executor/UnixCMakeExecutor.php b/src/SPC/util/executor/UnixCMakeExecutor.php index b9c7ef58..71a81951 100644 --- a/src/SPC/util/executor/UnixCMakeExecutor.php +++ b/src/SPC/util/executor/UnixCMakeExecutor.php @@ -5,25 +5,37 @@ declare(strict_types=1); namespace SPC\util\executor; 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\WrongUsageException; use SPC\store\FileSystem; +use SPC\util\UnixShell; /** * Unix-like OS cmake command executor. */ class UnixCMakeExecutor extends Executor { - protected ?string $build_dir = null; + protected UnixShell $shell; protected array $configure_args = []; + protected ?string $build_dir = null; + protected ?array $custom_default_args = null; protected int $steps = 3; protected bool $reset = true; + public function __construct(protected BSDLibraryBase|LinuxLibraryBase|MacOSLibraryBase $library) + { + parent::__construct($library); + $this->initShell(); + } + public function build(string $build_pos = '..'): void { // set cmake dir @@ -33,17 +45,16 @@ class UnixCMakeExecutor extends Executor FileSystem::resetDir($this->build_dir); } - // prepare shell - $shell = shell()->cd($this->build_dir)->initializeEnv($this->library); + $this->shell = $this->shell->cd($this->build_dir); // 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 - $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 - $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; } + public function appendEnv(array $env): static + { + $this->shell->appendEnv($env); + return $this; + } + /** * To build steps. * @@ -209,4 +226,9 @@ CMAKE; FileSystem::writeFile(SOURCE_PATH . '/toolchain.cmake', $toolchain); return $created = realpath(SOURCE_PATH . '/toolchain.cmake'); } + + private function initShell(): void + { + $this->shell = shell()->initializeEnv($this->library); + } } diff --git a/src/globals/ext-tests/curl.php b/src/globals/ext-tests/curl.php index a890a8cf..7c3eecf7 100644 --- a/src/globals/ext-tests/curl.php +++ b/src/globals/ext-tests/curl.php @@ -9,7 +9,7 @@ assert(function_exists('curl_close')); $curl_version = curl_version(); if (stripos($curl_version['ssl_version'], 'schannel') !== false) { $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL, 'https://example.com/'); + curl_setopt($curl, CURLOPT_URL, 'https://captive.apple.com/'); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_HEADER, 0); $data = curl_exec($curl); diff --git a/src/globals/ext-tests/imagick.php b/src/globals/ext-tests/imagick.php index 5fac8dcc..49f41fbe 100644 --- a/src/globals/ext-tests/imagick.php +++ b/src/globals/ext-tests/imagick.php @@ -10,3 +10,4 @@ assert(Imagick::queryFormats('WEBP') !== []); assert(Imagick::queryFormats('JPEG') !== []); assert(Imagick::queryFormats('PNG') !== []); assert(Imagick::queryFormats('TIFF') !== []); +assert(Imagick::queryFormats('JXL') !== []); diff --git a/src/globals/ext-tests/openssl.php b/src/globals/ext-tests/openssl.php index 3b3452b3..0453101a 100644 --- a/src/globals/ext-tests/openssl.php +++ b/src/globals/ext-tests/openssl.php @@ -5,5 +5,5 @@ declare(strict_types=1); assert(function_exists('openssl_digest')); assert(openssl_digest('123456', 'md5') === 'e10adc3949ba59abbe56e057f20f883e'); if (file_exists('/etc/ssl/openssl.cnf')) { - assert(file_get_contents('https://example.com/') !== false); + assert(file_get_contents('https://captive.apple.com/') !== false); } diff --git a/src/globals/functions.php b/src/globals/functions.php index 998b2d1c..b45d8c5e 100644 --- a/src/globals/functions.php +++ b/src/globals/functions.php @@ -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}"]; } + +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@', + ]; +} diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 98ecdea4..4d1f7d2a 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -17,12 +17,11 @@ $test_php_version = [ // '8.2', // '8.3', '8.4', - '8.5', ]; // test os (macos-13, macos-14, macos-15, ubuntu-latest, windows-latest are available) $test_os = [ - 'macos-13', // bin/spc for x86_64 + // 'macos-13', // bin/spc for x86_64 // 'macos-14', // bin/spc for arm64 'macos-15', // bin/spc for arm64 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 @@ -30,7 +29,7 @@ $test_os = [ // 'ubuntu-24.04', // bin/spc for x86_64 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 'ubuntu-24.04-arm', // bin/spc for arm64 - 'windows-latest', // .\bin\spc.ps1 + // 'windows-latest', // .\bin\spc.ps1 ]; // whether enable thread safe @@ -49,8 +48,8 @@ $prefer_pre_built = false; // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,event,exif,fileinfo,filter,ftp,gd,gmp,iconv,imagick,imap,intl,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,opentelemetry,pcntl,pdo,pdo_mysql,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,sysvmsg,sysvsem,sysvshm,tokenizer,xml,xmlreader,xmlwriter,xsl,zip,zlib', - 'Windows' => 'apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,ds,exif,ffi,fileinfo,filter,ftp,gd,iconv,igbinary,libxml,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pdo,pdo_mysql,pdo_sqlite,pdo_sqlsrv,phar,rar,redis,session,shmop,simdjson,simplexml,soap,sockets,sqlite3,sqlsrv,ssh2,sysvshm,tokenizer,xml,xmlreader,xmlwriter,yac,yaml,zip,zlib', + 'Linux', 'Darwin' => 'grpc', + 'Windows' => 'curl', }; // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). diff --git a/tests/SPC/builder/ExtensionTest.php b/tests/SPC/builder/ExtensionTest.php index 499a800f..c387dc99 100644 --- a/tests/SPC/builder/ExtensionTest.php +++ b/tests/SPC/builder/ExtensionTest.php @@ -78,11 +78,6 @@ class ExtensionTest extends TestCase } } - public function testGetLibFilesString() - { - $this->assertStringEndsWith('libonig.a', $this->extension->getLibFilesString()); - } - public function testGetName() { $this->assertEquals('mbregex', $this->extension->getName()); diff --git a/tests/SPC/util/SPCConfigUtilTest.php b/tests/SPC/util/SPCConfigUtilTest.php index ebd2f92a..c37f01f3 100644 --- a/tests/SPC/util/SPCConfigUtilTest.php +++ b/tests/SPC/util/SPCConfigUtilTest.php @@ -54,7 +54,7 @@ class SPCConfigUtilTest extends TestCase $this->assertStringContainsString('-lphp', $result['libs']); // has cpp - $result = (new SPCConfigUtil())->config(['swoole']); + $result = (new SPCConfigUtil())->config(['rar']); $this->assertStringContainsString(PHP_OS_FAMILY === 'Darwin' ? '-lc++' : '-lstdc++', $result['libs']); // has mimalloc.o in lib dir