Compare commits

...

32 Commits

Author SHA1 Message Date
crazywhalecc
57dd174aff Provide libevent, libiconv-win, libsodium, libwebp, libyaml, ncurses, readline, unixodbc, xz pre-built libs 2024-07-09 15:05:53 +08:00
crazywhalecc
80effd029f Provide libcares pre-built binary 2024-07-09 11:21:20 +08:00
crazywhalecc
1c79cc9f61 Provide icu pre-built binary 2024-07-09 11:15:34 +08:00
crazywhalecc
491eb5c2f2 Fix pkgconf patch with space between '=' bug 2024-07-09 11:14:58 +08:00
crazywhalecc
8632a4e005 Add onig as pre-built library 2024-07-09 00:44:14 +08:00
crazywhalecc
4b44c3adf7 Adjust shell debug log 2024-07-09 00:44:03 +08:00
crazywhalecc
a950498fd4 Add timer for build libs 2024-07-09 00:43:38 +08:00
crazywhalecc
48294c9c5f Add brotli, libargon2, libavif, libiconv, libpng, libtiff pre-built libs 2024-07-08 13:27:03 +08:00
crazywhalecc
ce155987ad Remove suffix for LicenseDumper and LicenseDumperTest 2024-07-08 12:58:57 +08:00
crazywhalecc
32a98bb8a1 Add license installer for build mode 2024-07-08 12:55:41 +08:00
crazywhalecc
8cec136656 Add openssl to pre-built 2024-07-08 11:21:01 +08:00
crazywhalecc
8ec50c88ca Remove perl.exe check log in doctor 2024-07-08 10:51:09 +08:00
crazywhalecc
5ec194efb2 Remove initSource for sorted libs in WindowsBuilder 2024-07-08 10:46:32 +08:00
crazywhalecc
b8f63ec3b9 Fix windows sqlite portable build 2024-07-08 00:51:30 +08:00
crazywhalecc
125d6ca772 Add liblz4, sqlite for pre-built libs 2024-07-08 00:23:26 +08:00
crazywhalecc
cedd58443d Patch sqlite pkgconf file 2024-07-08 00:07:30 +08:00
crazywhalecc
467c7ae667 Remove icu tools 2024-07-08 00:06:59 +08:00
crazywhalecc
0c30fc2039 Fix alpine-docker ssl bug 2024-07-07 22:57:42 +08:00
crazywhalecc
28b336c666 Fix CI quote 2024-07-07 22:53:45 +08:00
crazywhalecc
884d7bf56a Add aarch64-linux to CI 2024-07-07 22:51:22 +08:00
crazywhalecc
9c8b525f89 Fix CI 2024-07-07 22:32:01 +08:00
crazywhalecc
6cb2b3f28c Fix CI 2024-07-07 22:29:52 +08:00
crazywhalecc
9a954bd75f Fix CI 2024-07-07 22:13:58 +08:00
crazywhalecc
730d304ca2 Use bash in windows 2024-07-07 22:11:46 +08:00
crazywhalecc
768fd0d4a0 Fix CI 2024-07-07 22:08:56 +08:00
crazywhalecc
ac5f1919b4 Fix CI 2024-07-07 21:49:39 +08:00
crazywhalecc
cc7f9fb44f Remove windows with pkg-config 2024-07-07 21:41:48 +08:00
crazywhalecc
91e089d74a Remove windows with pkg-config 2024-07-07 21:40:57 +08:00
crazywhalecc
14ce15c85e Add pack-lib tests 2024-07-07 21:39:22 +08:00
crazywhalecc
fc617134ca Add pack-lib tests 2024-07-07 21:34:04 +08:00
crazywhalecc
ff8863d5a1 Code style fix and comment addition 2024-07-07 21:18:30 +08:00
crazywhalecc
fc053253e7 Add pre-built lib feature 2024-07-07 20:45:18 +08:00
50 changed files with 576 additions and 116 deletions

View File

@@ -34,7 +34,12 @@ on:
description: extensions to compile (comma separated) description: extensions to compile (comma separated)
required: true required: true
type: string type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug: debug:
description: enable debug logs
type: boolean type: boolean
env: env:
@@ -73,6 +78,8 @@ jobs:
# With or without debug # With or without debug
- if: inputs.debug == true - if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both # With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }} - if: ${{ inputs.build-cli == true }}
@@ -84,7 +91,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug # If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true' - if: steps.cache-download.outputs.cache-hit != 'true'
run: SPC_USE_ARCH=${{ inputs.operating-system }} ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} run: SPC_USE_ARCH=${{ inputs.operating-system }} ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command # Run build command
- run: SPC_USE_ARCH=${{ inputs.operating-system }} ./bin/spc-alpine-docker build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }} - run: SPC_USE_ARCH=${{ inputs.operating-system }} ./bin/spc-alpine-docker build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -28,7 +28,12 @@ on:
description: extensions to compile (comma separated) description: extensions to compile (comma separated)
required: true required: true
type: string type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug: debug:
description: enable debug logs
type: boolean type: boolean
env: env:
@@ -67,6 +72,8 @@ jobs:
# With or without debug # With or without debug
- if: inputs.debug == true - if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both # With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }} - if: ${{ inputs.build-cli == true }}
@@ -78,7 +85,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug # If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true' - if: steps.cache-download.outputs.cache-hit != 'true'
run: CACHE_API_EXEC=yes ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} run: CACHE_API_EXEC=yes ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command # Run build command
- run: ./bin/spc-alpine-docker build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }} - run: ./bin/spc-alpine-docker build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -28,7 +28,12 @@ on:
description: extensions to compile (comma separated) description: extensions to compile (comma separated)
required: true required: true
type: string type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug: debug:
description: enable debug logs
type: boolean type: boolean
env: env:
@@ -82,6 +87,8 @@ jobs:
# With or without debug # With or without debug
- if: inputs.debug == true - if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both # With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }} - if: ${{ inputs.build-cli == true }}
@@ -93,7 +100,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug # If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true' - if: steps.cache-download.outputs.cache-hit != 'true'
run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command # Run build command
- run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }} - run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -28,7 +28,12 @@ on:
description: extensions to compile (comma separated) description: extensions to compile (comma separated)
required: true required: true
type: string type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug: debug:
description: enable debug logs
type: boolean type: boolean
env: env:
@@ -80,6 +85,8 @@ jobs:
# With or without debug # With or without debug
- if: inputs.debug == true - if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both # With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }} - if: ${{ inputs.build-cli == true }}
@@ -91,7 +98,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug # If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true' - if: steps.cache-download.outputs.cache-hit != 'true'
run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command # Run build command
- run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }} - run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -25,7 +25,12 @@ on:
description: extensions to compile (comma separated) description: extensions to compile (comma separated)
required: true required: true
type: string type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug: debug:
description: enable debug logs
type: boolean type: boolean
env: env:
@@ -65,6 +70,8 @@ jobs:
# With or without debug # With or without debug
- if: inputs.debug == true - if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $env:GITHUB_ENV run: echo "SPC_BUILD_DEBUG=--debug" >> $env:GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both # With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }} - if: ${{ inputs.build-cli == true }}
@@ -76,7 +83,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug # If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true' - if: steps.cache-download.outputs.cache-hit != 'true'
run: ./bin/spc download --with-php="${{ inputs.version }}" --for-extensions="${{ inputs.extensions }}" ${{ env.SPC_BUILD_DEBUG }} run: ./bin/spc download --with-php="${{ inputs.version }}" --for-extensions="${{ inputs.extensions }}" ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command # Run build command
- run: ./bin/spc build "${{ inputs.extensions }}" ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }} - run: ./bin/spc build "${{ inputs.extensions }}" ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -178,6 +178,12 @@ jobs:
run: | run: |
bin/spc download --for-extensions="$(php src/globals/test-extensions.php extensions)" --for-libs="$(php src/globals/test-extensions.php libs)" --with-php=${{ matrix.php }} --ignore-cache-sources=php-src --debug --retry=5 --shallow-clone bin/spc download --for-extensions="$(php src/globals/test-extensions.php extensions)" --for-libs="$(php src/globals/test-extensions.php libs)" --with-php=${{ matrix.php }} --ignore-cache-sources=php-src --debug --retry=5 --shallow-clone
- name: "Download pre-built libraries for pkg-config"
if: matrix.os != 'windows-latest'
run: |
bin/spc del-download pkg-config
bin/spc download pkg-config --prefer-pre-built --debug
- name: "Run Build Tests (build, *nix)" - name: "Run Build Tests (build, *nix)"
if: matrix.os != 'windows-latest' if: matrix.os != 'windows-latest'
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) $(php src/globals/test-extensions.php no_strip) $UPX_CMD --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --build-fpm --debug run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) $(php src/globals/test-extensions.php no_strip) $UPX_CMD --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --build-fpm --debug

4
.gitignore vendored
View File

@@ -19,6 +19,10 @@ docker/source/
# default package root directory # default package root directory
/pkgroot/ /pkgroot/
# default pack:lib and release directory
/dist/
packlib_files.txt
# tools cache files # tools cache files
.php-cs-fixer.cache .php-cs-fixer.cache
.phpunit.result.cache .phpunit.result.cache

View File

@@ -56,6 +56,7 @@ if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH; then
FROM $ALPINE_FROM FROM $ALPINE_FROM
$SPC_USE_MIRROR $SPC_USE_MIRROR
RUN apk update; \ RUN apk update; \
apk upgrade -a; \
apk add --no-cache \ apk add --no-cache \
autoconf \ autoconf \
automake \ automake \
@@ -110,4 +111,4 @@ fi
# Run docker # Run docker
# shellcheck disable=SC2068 # shellcheck disable=SC2068
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" -v "$(pwd)"/config:/app/config -v "$(pwd)"/src:/app/src -v "$(pwd)"/buildroot:/app/buildroot -v "$(pwd)"/source:/app/source -v "$(pwd)"/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@ $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" -v "$(pwd)"/config:/app/config -v "$(pwd)"/src:/app/src -v "$(pwd)"/buildroot:/app/buildroot -v "$(pwd)"/source:/app/source -v "$(pwd)"/dist:/app/dist -v "$(pwd)"/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@

View File

@@ -1,5 +1,6 @@
{ {
"repo": "static-php/static-php-cli-hosted", "repo": "static-php/static-php-cli-hosted",
"match-pattern": "{name}-{arch}-{os}.tgz", "prefer-stable": true,
"pack-config": {} "match-pattern": "{name}-{arch}-{os}.txz",
"suffix": "txz"
} }

View File

@@ -29,6 +29,7 @@
"brotli": { "brotli": {
"type": "ghtar", "type": "ghtar",
"repo": "google/brotli", "repo": "google/brotli",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE" "path": "LICENSE"
@@ -38,6 +39,7 @@
"type": "filelist", "type": "filelist",
"url": "https://sourceware.org/pub/bzip2/", "url": "https://sourceware.org/pub/bzip2/",
"regex": "/href=\"(?<file>bzip2-(?<version>[^\"]+)\\.tar\\.gz)\"/", "regex": "/href=\"(?<file>bzip2-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": { "license": {
"type": "text", "type": "text",
"text": "This program, \"bzip2\", the associated library \"libbzip2\", and all documentation, are copyright (C) 1996-2010 Julian R Seward. All rights reserved. \n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nJulian Seward, jseward@bzip.org bzip2/libbzip2 version 1.0.6 of 6 September 2010\n\nPATENTS: To the best of my knowledge, bzip2 and libbzip2 do not use any patented algorithms. However, I do not have the resources to carry out a patent search. Therefore I cannot give any guarantee of the above statement." "text": "This program, \"bzip2\", the associated library \"libbzip2\", and all documentation, are copyright (C) 1996-2010 Julian R Seward. All rights reserved. \n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nJulian Seward, jseward@bzip.org bzip2/libbzip2 version 1.0.6 of 6 September 2010\n\nPATENTS: To the best of my knowledge, bzip2 and libbzip2 do not use any patented algorithms. However, I do not have the resources to carry out a patent search. Therefore I cannot give any guarantee of the above statement."
@@ -182,6 +184,7 @@
"gmp": { "gmp": {
"type": "url", "type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz", "url": "https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz",
"provide-pre-built": true,
"alt": { "alt": {
"type": "ghtagtar", "type": "ghtagtar",
"repo": "alisw/GMP" "repo": "alisw/GMP"
@@ -196,6 +199,7 @@
"repo": "unicode-org/icu", "repo": "unicode-org/icu",
"match": "icu4c.+-src\\.tgz", "match": "icu4c.+-src\\.tgz",
"prefer-stable": true, "prefer-stable": true,
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE" "path": "LICENSE"
@@ -251,6 +255,7 @@
"type": "git", "type": "git",
"rev": "master", "rev": "master",
"url": "https://github.com/static-php/phc-winner-argon2", "url": "https://github.com/static-php/phc-winner-argon2",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE" "path": "LICENSE"
@@ -259,6 +264,7 @@
"libavif": { "libavif": {
"type": "ghtar", "type": "ghtar",
"repo": "AOMediaCodec/libavif", "repo": "AOMediaCodec/libavif",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE" "path": "LICENSE"
@@ -269,6 +275,7 @@
"repo": "c-ares/c-ares", "repo": "c-ares/c-ares",
"match": "c-ares-.+\\.tar\\.gz", "match": "c-ares-.+\\.tar\\.gz",
"prefer-stable": true, "prefer-stable": true,
"provide-pre-built": true,
"alt": { "alt": {
"type": "filelist", "type": "filelist",
"url": "https://c-ares.org/download/", "url": "https://c-ares.org/download/",
@@ -284,6 +291,7 @@
"repo": "libevent/libevent", "repo": "libevent/libevent",
"match": "libevent.+\\.tar\\.gz", "match": "libevent.+\\.tar\\.gz",
"prefer-stable": true, "prefer-stable": true,
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE" "path": "LICENSE"
@@ -312,6 +320,7 @@
"type": "filelist", "type": "filelist",
"url": "https://ftp.gnu.org/gnu/libiconv/", "url": "https://ftp.gnu.org/gnu/libiconv/",
"regex": "/href=\"(?<file>libiconv-(?<version>[^\"]+)\\.tar\\.gz)\"/", "regex": "/href=\"(?<file>libiconv-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "COPYING" "path": "COPYING"
@@ -321,6 +330,7 @@
"type": "git", "type": "git",
"rev": "master", "rev": "master",
"url": "https://github.com/static-php/libiconv-win.git", "url": "https://github.com/static-php/libiconv-win.git",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "source/COPYING" "path": "source/COPYING"
@@ -339,6 +349,7 @@
"repo": "lz4/lz4", "repo": "lz4/lz4",
"match": "lz4-.+\\.tar\\.gz", "match": "lz4-.+\\.tar\\.gz",
"prefer-stable": true, "prefer-stable": true,
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE" "path": "LICENSE"
@@ -357,6 +368,7 @@
"type": "git", "type": "git",
"url": "https://github.com/glennrp/libpng.git", "url": "https://github.com/glennrp/libpng.git",
"rev": "libpng16", "rev": "libpng16",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE" "path": "LICENSE"
@@ -376,6 +388,7 @@
"repo": "jedisct1/libsodium", "repo": "jedisct1/libsodium",
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz", "match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
"prefer-stable": true, "prefer-stable": true,
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE" "path": "LICENSE"
@@ -395,6 +408,7 @@
"type": "filelist", "type": "filelist",
"url": "https://download.osgeo.org/libtiff/", "url": "https://download.osgeo.org/libtiff/",
"regex": "/href=\"(?<file>tiff-(?<version>[^\"]+)\\.tar\\.xz)\"/", "regex": "/href=\"(?<file>tiff-(?<version>[^\"]+)\\.tar\\.xz)\"/",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE.md" "path": "LICENSE.md"
@@ -426,6 +440,7 @@
"libwebp": { "libwebp": {
"type": "url", "type": "url",
"url": "https://github.com/webmproject/libwebp/archive/refs/tags/v1.3.2.tar.gz", "url": "https://github.com/webmproject/libwebp/archive/refs/tags/v1.3.2.tar.gz",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "COPYING" "path": "COPYING"
@@ -453,6 +468,7 @@
"repo": "yaml/libyaml", "repo": "yaml/libyaml",
"match": "yaml-.+\\.tar\\.gz", "match": "yaml-.+\\.tar\\.gz",
"prefer-stable": true, "prefer-stable": true,
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "License" "path": "License"
@@ -503,6 +519,7 @@
"type": "filelist", "type": "filelist",
"url": "https://ftp.gnu.org/pub/gnu/ncurses/", "url": "https://ftp.gnu.org/pub/gnu/ncurses/",
"regex": "/href=\"(?<file>ncurses-(?<version>[^\"]+)\\.tar\\.gz)\"/", "regex": "/href=\"(?<file>ncurses-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "COPYING" "path": "COPYING"
@@ -523,6 +540,7 @@
"repo": "kkos/oniguruma", "repo": "kkos/oniguruma",
"match": "onig-.+\\.tar\\.gz", "match": "onig-.+\\.tar\\.gz",
"prefer-stable": true, "prefer-stable": true,
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "COPYING" "path": "COPYING"
@@ -532,6 +550,7 @@
"type": "filelist", "type": "filelist",
"url": "https://www.openssl.org/source/", "url": "https://www.openssl.org/source/",
"regex": "/href=\"(?<file>openssl-(?<version>[^\"]+)\\.tar\\.gz)\"/", "regex": "/href=\"(?<file>openssl-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "LICENSE.txt" "path": "LICENSE.txt"
@@ -560,6 +579,7 @@
"pkg-config": { "pkg-config": {
"type": "url", "type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/pkg-config/pkg-config-0.29.2.tar.gz", "url": "https://dl.static-php.dev/static-php-cli/deps/pkg-config/pkg-config-0.29.2.tar.gz",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "COPYING" "path": "COPYING"
@@ -615,6 +635,7 @@
"type": "filelist", "type": "filelist",
"url": "https://ftp.gnu.org/pub/gnu/readline/", "url": "https://ftp.gnu.org/pub/gnu/readline/",
"regex": "/href=\"(?<file>readline-(?<version>[^\"]+)\\.tar\\.gz)\"/", "regex": "/href=\"(?<file>readline-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "COPYING" "path": "COPYING"
@@ -653,6 +674,7 @@
"sqlite": { "sqlite": {
"type": "url", "type": "url",
"url": "https://www.sqlite.org/2023/sqlite-autoconf-3430200.tar.gz", "url": "https://www.sqlite.org/2023/sqlite-autoconf-3430200.tar.gz",
"provide-pre-built": true,
"license": { "license": {
"type": "text", "type": "text",
"text": "The author disclaims copyright to this source code. In place of\na legal notice, here is a blessing:\n\n * May you do good and not evil.\n * May you find forgiveness for yourself and forgive others.\n * May you share freely, never taking more than you give." "text": "The author disclaims copyright to this source code. In place of\na legal notice, here is a blessing:\n\n * May you do good and not evil.\n * May you find forgiveness for yourself and forgive others.\n * May you share freely, never taking more than you give."
@@ -701,6 +723,7 @@
"unixodbc": { "unixodbc": {
"type": "url", "type": "url",
"url": "https://www.unixodbc.org/unixODBC-2.3.12.tar.gz", "url": "https://www.unixodbc.org/unixODBC-2.3.12.tar.gz",
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "COPYING" "path": "COPYING"
@@ -731,6 +754,7 @@
"repo": "tukaani-project/xz", "repo": "tukaani-project/xz",
"match": "xz.+\\.tar\\.xz", "match": "xz.+\\.tar\\.xz",
"prefer-stable": true, "prefer-stable": true,
"provide-pre-built": true,
"license": { "license": {
"type": "file", "type": "file",
"path": "COPYING" "path": "COPYING"
@@ -761,6 +785,7 @@
"repo": "madler/zlib", "repo": "madler/zlib",
"match": "zlib.+\\.tar\\.gz", "match": "zlib.+\\.tar\\.gz",
"prefer-stable": true, "prefer-stable": true,
"provide-pre-built": true,
"license": { "license": {
"type": "text", "type": "text",
"text": "(C) 1995-2022 Jean-loup Gailly and Mark Adler\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must not\n claim that you wrote the original software. If you use this software\n in a product, an acknowledgment in the product documentation would be\n appreciated but is not required.\n2. Altered source versions must be plainly marked as such, and must not be\n misrepresented as being the original software.\n3. This notice may not be removed or altered from any source distribution.\n\nJean-loup Gailly Mark Adler\njloup@gzip.org madler@alumni.caltech.edu" "text": "(C) 1995-2022 Jean-loup Gailly and Mark Adler\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must not\n claim that you wrote the original software. If you use this software\n in a product, an acknowledgment in the product documentation would be\n appreciated but is not required.\n2. Altered source versions must be plainly marked as such, and must not be\n misrepresented as being the original software.\n3. This notice may not be removed or altered from any source distribution.\n\nJean-loup Gailly Mark Adler\njloup@gzip.org madler@alumni.caltech.edu"

View File

@@ -11,6 +11,7 @@ use SPC\command\dev\AllExtCommand;
use SPC\command\dev\ExtVerCommand; use SPC\command\dev\ExtVerCommand;
use SPC\command\dev\GenerateExtDocCommand; use SPC\command\dev\GenerateExtDocCommand;
use SPC\command\dev\LibVerCommand; use SPC\command\dev\LibVerCommand;
use SPC\command\dev\PackLibCommand;
use SPC\command\dev\PhpVerCommand; use SPC\command\dev\PhpVerCommand;
use SPC\command\dev\SortConfigCommand; use SPC\command\dev\SortConfigCommand;
use SPC\command\DoctorCommand; use SPC\command\DoctorCommand;
@@ -54,6 +55,7 @@ final class ConsoleApplication extends Application
new ExtVerCommand(), new ExtVerCommand(),
new SortConfigCommand(), new SortConfigCommand(),
new GenerateExtDocCommand(), new GenerateExtDocCommand(),
new PackLibCommand(),
] ]
); );
} }

View File

@@ -45,20 +45,22 @@ abstract class BuilderBase
abstract public function proveLibs(array $sorted_libraries); abstract public function proveLibs(array $sorted_libraries);
/** /**
* Build libraries * Set-Up libraries
* *
* @throws FileSystemException * @throws FileSystemException
* @throws RuntimeException * @throws RuntimeException
* @throws WrongUsageException * @throws WrongUsageException
*/ */
public function buildLibs(): void public function setupLibs(): void
{ {
// build all libs // build all libs
foreach ($this->libs as $lib) { foreach ($this->libs as $lib) {
match ($lib->tryBuild($this->getOption('rebuild', false))) { $starttime = microtime(true);
BUILD_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] build success'), match ($lib->setup($this->getOption('rebuild', false))) {
BUILD_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'), LIB_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] setup success, took ' . round(microtime(true) - $starttime, 2) . ' s'),
BUILD_STATUS_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'), 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'), default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
}; };
} }

View File

@@ -8,6 +8,7 @@ use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\store\Config; use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\SourceManager; use SPC\store\SourceManager;
abstract class LibraryBase abstract class LibraryBase
@@ -32,6 +33,32 @@ abstract class LibraryBase
$this->source_dir = $source_dir ?? (SOURCE_PATH . '/' . static::NAME); $this->source_dir = $source_dir ?? (SOURCE_PATH . '/' . static::NAME);
} }
/**
* Try to install or build this library.
* @param bool $force If true, force install or build
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function setup(bool $force = false): int
{
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
$source = Config::getLib(static::NAME, 'source');
// if source is locked as pre-built, we just tryInstall it
if (isset($lock[$source]) && ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
return $this->tryInstall($lock[$source]['filename'], $force);
}
return $this->tryBuild($force);
}
/**
* Get library name.
*/
public function getName(): string
{
return static::NAME;
}
/** /**
* Get current lib source root dir. * Get current lib source root dir.
*/ */
@@ -119,6 +146,45 @@ abstract class LibraryBase
return Config::getLib(static::NAME, 'headers', []); return Config::getLib(static::NAME, 'headers', []);
} }
/**
* @throws WrongUsageException
* @throws FileSystemException
*/
public function tryInstall(string $install_file, bool $force_install = false): int
{
if ($force_install) {
logger()->info('Installing required library [' . static::NAME . '] from pre-built binaries');
// Extract files
try {
FileSystem::extractPackage($install_file, DOWNLOAD_PATH . '/' . $install_file, BUILD_ROOT_PATH);
$this->install();
return LIB_STATUS_OK;
} catch (FileSystemException|RuntimeException $e) {
logger()->error('Failed to extract pre-built library [' . static::NAME . ']: ' . $e->getMessage());
return LIB_STATUS_INSTALL_FAILED;
}
}
foreach ($this->getStaticLibs() as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryInstall($install_file, true);
return LIB_STATUS_OK;
}
}
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryInstall($install_file, 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($install_file, true);
return LIB_STATUS_OK;
}
return LIB_STATUS_ALREADY;
}
/** /**
* Try to build this library, before build, we check first. * Try to build this library, before build, we check first.
* *
@@ -151,31 +217,32 @@ abstract class LibraryBase
} }
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build'); $this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build');
$this->build(); $this->build();
$this->installLicense();
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build'); $this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build');
return BUILD_STATUS_OK; return LIB_STATUS_OK;
} }
// check if these libraries exist, if not, invoke compilation and return the result status // check if these libraries exist, if not, invoke compilation and return the result status
foreach ($this->getStaticLibs() as $name) { foreach ($this->getStaticLibs() as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) { if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryBuild(true); $this->tryBuild(true);
return BUILD_STATUS_OK; return LIB_STATUS_OK;
} }
} }
// header files the same // header files the same
foreach ($this->getHeaders() as $name) { foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) { if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryBuild(true); $this->tryBuild(true);
return BUILD_STATUS_OK; return LIB_STATUS_OK;
} }
} }
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists // 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')) { if (static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryBuild(true); $this->tryBuild(true);
return BUILD_STATUS_OK; return LIB_STATUS_OK;
} }
// if all the files exist at this point, skip the compilation process // if all the files exist at this point, skip the compilation process
return BUILD_STATUS_ALREADY; return LIB_STATUS_ALREADY;
} }
/** /**
@@ -206,6 +273,11 @@ abstract class LibraryBase
*/ */
abstract public function getBuilder(): BuilderBase; abstract public function getBuilder(): BuilderBase;
public function beforePack(): void
{
// do something before pack, default do nothing. overwrite this method to do something (e.g. modify pkg-config file)
}
/** /**
* Build this library. * Build this library.
* *
@@ -213,6 +285,11 @@ abstract class LibraryBase
*/ */
abstract protected function build(); abstract protected function build();
protected function install(): void
{
// do something after extracting pre-built files, default do nothing. overwrite this method to do something
}
/** /**
* Add lib dependency * Add lib dependency
* *
@@ -235,4 +312,26 @@ abstract class LibraryBase
{ {
return str_replace('-', '_', static::NAME); return str_replace('-', '_', static::NAME);
} }
/**
* Install license files in buildroot directory
*/
protected function installLicense(): void
{
FileSystem::createDir(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName());
$source = Config::getLib($this->getName(), 'source');
$license_files = Config::getSource($source)['license'] ?? [];
if (is_assoc_array($license_files)) {
$license_files = [$license_files];
}
foreach ($license_files as $index => $license) {
if ($license['type'] === 'text') {
FileSystem::writeFile(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt", $license['text']);
continue;
}
if ($license['type'] === 'file') {
copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt");
}
}
}
} }

View File

@@ -6,6 +6,8 @@ namespace SPC\builder\linux\library;
class icu extends LinuxLibraryBase class icu extends LinuxLibraryBase
{ {
use \SPC\builder\unix\library\icu;
public const NAME = 'icu'; public const NAME = 'icu';
protected function build(): void protected function build(): void
@@ -21,10 +23,10 @@ class icu extends LinuxLibraryBase
'--disable-shared ' . '--disable-shared ' .
'--with-data-packaging=static ' . '--with-data-packaging=static ' .
'--enable-release=yes ' . '--enable-release=yes ' .
'--enable-extras=yes ' . '--enable-extras=no ' .
'--enable-icuio=yes ' . '--enable-icuio=yes ' .
'--enable-dyload=no ' . '--enable-dyload=no ' .
'--enable-tools=yes ' . '--enable-tools=no ' .
'--enable-tests=no ' . '--enable-tests=no ' .
'--enable-samples=no ' . '--enable-samples=no ' .
'--prefix=' . BUILD_ROOT_PATH '--prefix=' . BUILD_ROOT_PATH
@@ -32,5 +34,7 @@ class icu extends LinuxLibraryBase
->exec('make clean') ->exec('make clean')
->exec("make -j{$this->builder->concurrency}") ->exec("make -j{$this->builder->concurrency}")
->exec('make install'); ->exec('make install');
$this->patchPkgconfPrefix(['icu-i18n.pc', 'icu-io.pc', 'icu-uc.pc'], PKGCONF_PATCH_PREFIX);
} }
} }

View File

@@ -79,13 +79,15 @@ class openssl extends LinuxLibraryBase
$this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']); $this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']);
// patch for openssl 3.3.0+ // patch for openssl 3.3.0+
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
} }
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
} }
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=${pcfiledir}/../..' . "\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")');
} }
} }

View File

@@ -6,15 +6,19 @@ namespace SPC\builder\macos\library;
class icu extends MacOSLibraryBase class icu extends MacOSLibraryBase
{ {
use \SPC\builder\unix\library\icu;
public const NAME = 'icu'; public const NAME = 'icu';
protected function build(): void protected function build(): void
{ {
$root = BUILD_ROOT_PATH; $root = BUILD_ROOT_PATH;
shell()->cd($this->source_dir . '/source') shell()->cd($this->source_dir . '/source')
->exec("./runConfigureICU MacOSX --enable-static --disable-shared --prefix={$root}") ->exec("./runConfigureICU MacOSX --enable-static --disable-shared --disable-extras --disable-samples --disable-tests --disable-tools --prefix={$root}")
->exec('make clean') ->exec('make clean')
->exec("make -j{$this->builder->concurrency}") ->exec("make -j{$this->builder->concurrency}")
->exec('make install'); ->exec('make install');
$this->patchPkgconfPrefix(['icu-i18n.pc', 'icu-io.pc', 'icu-uc.pc'], PKGCONF_PATCH_PREFIX);
} }
} }

View File

@@ -62,13 +62,15 @@ class openssl extends MacOSLibraryBase
$this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']); $this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']);
// patch for openssl 3.3.0+ // patch for openssl 3.3.0+
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
} }
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
} }
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) { if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file); FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=${pcfiledir}/../..' . "\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")');
} }
} }

View File

@@ -75,10 +75,10 @@ trait UnixLibraryTrait
logger()->debug('Patching ' . $realpath); logger()->debug('Patching ' . $realpath);
// replace prefix // replace prefix
$file = FileSystem::readFile($realpath); $file = FileSystem::readFile($realpath);
$file = ($patch_option & PKGCONF_PATCH_PREFIX) === PKGCONF_PATCH_PREFIX ? preg_replace('/^prefix=.*$/m', 'prefix=' . BUILD_ROOT_PATH, $file) : $file; $file = ($patch_option & PKGCONF_PATCH_PREFIX) === PKGCONF_PATCH_PREFIX ? preg_replace('/^prefix\s*=.*$/m', 'prefix=${pcfiledir}/../..', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_EXEC_PREFIX) === PKGCONF_PATCH_EXEC_PREFIX ? preg_replace('/^exec_prefix=.*$/m', 'exec_prefix=${prefix}', $file) : $file; $file = ($patch_option & PKGCONF_PATCH_EXEC_PREFIX) === PKGCONF_PATCH_EXEC_PREFIX ? preg_replace('/^exec_prefix\s*=.*$/m', 'exec_prefix=${prefix}', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_LIBDIR) === PKGCONF_PATCH_LIBDIR ? preg_replace('/^libdir=.*$/m', 'libdir=${prefix}/lib', $file) : $file; $file = ($patch_option & PKGCONF_PATCH_LIBDIR) === PKGCONF_PATCH_LIBDIR ? preg_replace('/^libdir\s*=.*$/m', 'libdir=${prefix}/lib', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_INCLUDEDIR) === PKGCONF_PATCH_INCLUDEDIR ? preg_replace('/^includedir=.*$/m', 'includedir=${prefix}/include', $file) : $file; $file = ($patch_option & PKGCONF_PATCH_INCLUDEDIR) === PKGCONF_PATCH_INCLUDEDIR ? preg_replace('/^includedir\s*=.*$/m', 'includedir=${prefix}/include', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_CUSTOM) === PKGCONF_PATCH_CUSTOM && $custom_replace !== null ? preg_replace($custom_replace[0], $custom_replace[1], $file) : $file; $file = ($patch_option & PKGCONF_PATCH_CUSTOM) === PKGCONF_PATCH_CUSTOM && $custom_replace !== null ? preg_replace($custom_replace[0], $custom_replace[1], $file) : $file;
FileSystem::writeFile($realpath, $file); FileSystem::writeFile($realpath, $file);
} }

View File

@@ -11,7 +11,6 @@ use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\store\Config; use SPC\store\Config;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\store\SourceManager;
use SPC\util\DependencyUtil; use SPC\util\DependencyUtil;
abstract class UnixBuilderBase extends BuilderBase abstract class UnixBuilderBase extends BuilderBase
@@ -129,14 +128,6 @@ abstract class UnixBuilderBase extends BuilderBase
foreach ($this->libs as $lib) { foreach ($this->libs as $lib) {
$lib->calcDependency(); $lib->calcDependency();
} }
// patch point
$this->emitPatchPoint('before-libs-extract');
// extract sources
SourceManager::initSource(libs: $sorted_libraries);
$this->emitPatchPoint('after-libs-extract');
} }
/** /**

View File

@@ -34,5 +34,9 @@ trait brotli
unlink(BUILD_ROOT_PATH . '/lib/' . $filename); unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
} }
} }
if (file_exists(BUILD_BIN_PATH . '/brotli')) {
unlink(BUILD_BIN_PATH . '/brotli');
}
} }
} }

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
trait icu
{
public function beforePack(): void
{
// Replace buildroot/bin/icu-config default_prefix=* to placeholder default_prefix={BUILD_ROOT_PATH}
$icu_config = BUILD_ROOT_PATH . '/bin/icu-config';
FileSystem::replaceFileRegex($icu_config, '/default_prefix=.*/m', 'default_prefix="{BUILD_ROOT_PATH}"');
}
protected function install(): void
{
$icu_config = BUILD_ROOT_PATH . '/bin/icu-config';
FileSystem::replaceFileStr($icu_config, '{BUILD_ROOT_PATH}', BUILD_ROOT_PATH);
}
}

View File

@@ -23,5 +23,9 @@ trait libargon2
unlink(BUILD_ROOT_PATH . '/lib/' . $filename); unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
} }
} }
if (file_exists(BUILD_BIN_PATH . '/argon2')) {
unlink(BUILD_BIN_PATH . '/argon2');
}
} }
} }

View File

@@ -26,8 +26,10 @@ trait libcares
{ {
shell()->cd($this->source_dir) shell()->cd($this->source_dir)
->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()])
->execWithEnv('./configure --prefix=' . BUILD_ROOT_PATH . ' --enable-static --disable-shared --disable-tests') ->execWithEnv('./configure --prefix= --enable-static --disable-shared --disable-tests')
->execWithEnv("make -j {$this->builder->concurrency}") ->execWithEnv("make -j {$this->builder->concurrency}")
->exec('make install'); ->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['libcares.pc'], PKGCONF_PATCH_PREFIX);
} }
} }

View File

@@ -10,12 +10,36 @@ use SPC\store\FileSystem;
trait libevent trait libevent
{ {
public function beforePack(): void
{
if (file_exists(BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake')) {
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake',
'/set\(_IMPORT_PREFIX .*\)/m',
'set(_IMPORT_PREFIX "{BUILD_ROOT_PATH}")'
);
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake',
'/INTERFACE_INCLUDE_DIRECTORIES ".*"/m',
'INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"'
);
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake',
'/INTERFACE_LINK_LIBRARIES "libevent::core;.*"/m',
'INTERFACE_LINK_LIBRARIES "libevent::core;${_IMPORT_PREFIX}/lib/libssl.a;${_IMPORT_PREFIX}/lib/libcrypto.a"'
);
}
}
/** /**
* @throws RuntimeException * @throws RuntimeException
* @throws FileSystemException * @throws FileSystemException
*/ */
protected function build(): void protected function build(): void
{ {
[$lib, $include, $destdir] = SEPARATED_PATH;
// CMake needs a clean build directory // CMake needs a clean build directory
FileSystem::resetDir($this->source_dir . '/build'); FileSystem::resetDir($this->source_dir . '/build');
// Start build // Start build
@@ -36,5 +60,25 @@ trait libevent
) )
->execWithEnv("cmake --build . -j {$this->builder->concurrency}") ->execWithEnv("cmake --build . -j {$this->builder->concurrency}")
->exec('make install'); ->exec('make install');
$this->patchPkgconfPrefix(['libevent.pc', 'libevent_core.pc', 'libevent_extra.pc', 'libevent_openssl.pc']);
$this->patchPkgconfPrefix(
['libevent_openssl.pc'],
PKGCONF_PATCH_CUSTOM,
[
'/Libs.private:.*/m',
'Libs.private: -lssl -lcrypto',
]
);
}
protected function install(): void
{
FileSystem::replaceFileStr(
BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake',
'{BUILD_ROOT_PATH}',
BUILD_ROOT_PATH
);
} }
} }

View File

@@ -20,5 +20,9 @@ trait libiconv
->exec('make clean') ->exec('make clean')
->exec("make -j{$this->builder->concurrency}") ->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . $destdir); ->exec('make install DESTDIR=' . $destdir);
if (file_exists(BUILD_BIN_PATH . '/iconv')) {
unlink(BUILD_BIN_PATH . '/iconv');
}
} }
} }

View File

@@ -8,7 +8,14 @@ use SPC\store\FileSystem;
trait liblz4 trait liblz4
{ {
protected function build() public function patchBeforeBuild(): bool
{
// disable executables
FileSystem::replaceFileStr($this->source_dir . '/programs/Makefile', 'install: lz4', "install: lz4\n\ninstallewfwef: lz4");
return true;
}
protected function build(): void
{ {
shell()->cd($this->source_dir) shell()->cd($this->source_dir)
->exec("make PREFIX='' clean") ->exec("make PREFIX='' clean")

View File

@@ -8,11 +8,12 @@ trait libsodium
{ {
protected function build(): void protected function build(): void
{ {
$root = BUILD_ROOT_PATH;
shell()->cd($this->source_dir) shell()->cd($this->source_dir)
->exec("./configure --enable-static --disable-shared --prefix={$root}") ->exec('./configure --enable-static --disable-shared --prefix=')
->exec('make clean') ->exec('make clean')
->exec("make -j{$this->builder->concurrency}") ->exec("make -j{$this->builder->concurrency}")
->exec('make install'); ->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['libsodium.pc'], PKGCONF_PATCH_PREFIX);
} }
} }

View File

@@ -4,10 +4,13 @@ declare(strict_types=1);
namespace SPC\builder\unix\library; namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
trait ncurses trait ncurses
{ {
protected function build(): void protected function build(): void
{ {
$filelist = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true);
shell()->cd($this->source_dir) shell()->cd($this->source_dir)
->exec( ->exec(
'./configure ' . './configure ' .
@@ -32,5 +35,22 @@ trait ncurses
->exec('make clean') ->exec('make clean')
->exec("make -j{$this->builder->concurrency}") ->exec("make -j{$this->builder->concurrency}")
->exec('make install'); ->exec('make install');
$final = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true);
// Remove the new files
$new_files = array_diff($final, $filelist);
foreach ($new_files as $file) {
@unlink(BUILD_BIN_PATH . '/' . $file);
}
shell()->cd(BUILD_ROOT_PATH)->exec('rm -rf share/terminfo');
shell()->cd(BUILD_ROOT_PATH)->exec('rm -rf lib/terminfo');
$pkgconf_list = ['form.pc', 'menu.pc', 'ncurses++.pc', 'ncurses.pc', 'panel.pc', 'tic.pc'];
$this->patchPkgconfPrefix($pkgconf_list);
foreach ($pkgconf_list as $pkgconf) {
FileSystem::replaceFileStr(BUILD_LIB_PATH . '/pkgconfig/' . $pkgconf, '-L' . BUILD_LIB_PATH, '-L${libdir}');
}
} }
} }

View File

@@ -13,5 +13,6 @@ trait sqlite
->exec('make clean') ->exec('make clean')
->exec("make -j{$this->builder->concurrency}") ->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH); ->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['sqlite3.pc']);
} }
} }

View File

@@ -10,7 +10,6 @@ use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\store\Config; use SPC\store\Config;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\store\SourceManager;
use SPC\store\SourcePatcher; use SPC\store\SourcePatcher;
use SPC\util\DependencyUtil; use SPC\util\DependencyUtil;
use SPC\util\GlobalEnvManager; use SPC\util\GlobalEnvManager;
@@ -245,9 +244,6 @@ class WindowsBuilder extends BuilderBase
foreach ($this->libs as $lib) { foreach ($this->libs as $lib) {
$lib->calcDependency(); $lib->calcDependency();
} }
// extract sources
SourceManager::initSource(libs: $sorted_libraries);
} }
/** /**

View File

@@ -41,5 +41,12 @@ class libwebp extends WindowsLibraryBase
$this->builder->makeSimpleWrapper('cmake'), $this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}" "--build build --config Release --target install -j{$this->builder->concurrency}"
); );
// Actually we don't need pkgconf in windows, but for packing, we still need patching prefix.
// for libsharpyuv, libwebp, libwebpdecoder, libwebpdemux
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '\pkgconfig\libsharpyuv.pc', '/^prefix=.*/m', 'prefix=${pcfiledir}/../..');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '\pkgconfig\libwebp.pc', '/^prefix=.*/m', 'prefix=${pcfiledir}/../..');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '\pkgconfig\libwebpdecoder.pc', '/^prefix=.*/m', 'prefix=${pcfiledir}/../..');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '\pkgconfig\libwebpdemux.pc', '/^prefix=.*/m', 'prefix=${pcfiledir}/../..');
} }
} }

View File

@@ -41,5 +41,11 @@ class openssl extends WindowsLibraryBase
'CNF_LDFLAGS="/NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:msvcrt /NODEFAULTLIB:msvcrtd /DEFAULTLIB:libcmt /LIBPATH:' . BUILD_LIB_PATH . ' zlibstatic.lib"' 'CNF_LDFLAGS="/NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:msvcrt /NODEFAULTLIB:msvcrtd /DEFAULTLIB:libcmt /LIBPATH:' . BUILD_LIB_PATH . ' zlibstatic.lib"'
); );
copy($this->source_dir . '\ms\applink.c', BUILD_INCLUDE_PATH . '\openssl\applink.c'); copy($this->source_dir . '\ms\applink.c', BUILD_INCLUDE_PATH . '\openssl\applink.c');
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '\cmake\OpenSSL\OpenSSLConfig.cmake',
'/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m',
'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}" ws2_32.lib gdi32.lib advapi32.lib crypt32.lib user32.lib)'
);
} }
} }

View File

@@ -147,8 +147,8 @@ class BuildCliCommand extends BuildCommand
$builder->proveExts($extensions); $builder->proveExts($extensions);
// validate libs and exts // validate libs and exts
$builder->validateLibsAndExts(); $builder->validateLibsAndExts();
// build libraries // build or install libraries
$builder->buildLibs(); $builder->setupLibs();
if ($this->input->getOption('with-clean')) { if ($this->input->getOption('with-clean')) {
logger()->info('Cleaning source dir...'); logger()->info('Cleaning source dir...');

View File

@@ -65,7 +65,7 @@ class BuildLibsCommand extends BuildCommand
sleep(2); sleep(2);
$builder->proveLibs($libraries); $builder->proveLibs($libraries);
$builder->validateLibsAndExts(); $builder->validateLibsAndExts();
$builder->buildLibs(); $builder->setupLibs();
$time = round(microtime(true) - START_TIME, 3); $time = round(microtime(true) - START_TIME, 3);
logger()->info('Build libs complete, used ' . $time . ' s !'); logger()->info('Build libs complete, used ' . $time . ' s !');

View File

@@ -38,8 +38,9 @@ class DownloadCommand extends BaseCommand
$this->addOption('for-extensions', 'e', InputOption::VALUE_REQUIRED, 'Fetch by extensions, e.g "openssl,mbstring"'); $this->addOption('for-extensions', 'e', InputOption::VALUE_REQUIRED, 'Fetch by extensions, e.g "openssl,mbstring"');
$this->addOption('for-libs', 'l', InputOption::VALUE_REQUIRED, 'Fetch by libraries, e.g "libcares,openssl,onig"'); $this->addOption('for-libs', 'l', InputOption::VALUE_REQUIRED, 'Fetch by libraries, e.g "libcares,openssl,onig"');
$this->addOption('without-suggestions', null, null, 'Do not fetch suggested sources when using --for-extensions'); $this->addOption('without-suggestions', null, null, 'Do not fetch suggested sources when using --for-extensions');
$this->addOption('ignore-cache-sources', null, InputOption::VALUE_OPTIONAL, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', ''); $this->addOption('ignore-cache-sources', null, InputOption::VALUE_OPTIONAL, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', false);
$this->addOption('retry', 'R', InputOption::VALUE_REQUIRED, 'Set retry time when downloading failed (default: 0)', '0'); $this->addOption('retry', 'R', InputOption::VALUE_REQUIRED, 'Set retry time when downloading failed (default: 0)', '0');
$this->addOption('prefer-pre-built', 'P', null, 'Download pre-built libraries when available');
} }
/** /**
@@ -147,12 +148,22 @@ class DownloadCommand extends BaseCommand
} }
$chosen_sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources')))); $chosen_sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
$force_all = empty($this->getOption('ignore-cache-sources'));
if (!$force_all) { $sss = $this->getOption('ignore-cache-sources');
$force_list = array_map('trim', array_filter(explode(',', $this->getOption('ignore-cache-sources')))); if ($sss === false) {
} else { // false is no-any-ignores, that is, default.
$force_all = false;
$force_list = []; $force_list = [];
} elseif ($sss === null) {
// null means all sources will be ignored, equals to --force-all (but we don't want to add too many options)
$force_all = true;
$force_list = [];
} else {
// ignore some sources
$force_all = false;
$force_list = array_map('trim', array_filter(explode(',', $this->getOption('ignore-cache-sources'))));
} }
if ($this->getOption('all')) { if ($this->getOption('all')) {
logger()->notice('Downloading with --all option will take more times to download, we recommend you to download with --for-extensions option !'); logger()->notice('Downloading with --all option will take more times to download, we recommend you to download with --for-extensions option !');
} }
@@ -164,6 +175,17 @@ class DownloadCommand extends BaseCommand
$custom_urls[$source_name] = $url; $custom_urls[$source_name] = $url;
} }
// If passing --prefer-pre-built option, we need to load pre-built library list from pre-built.json targeted releases
if ($this->getOption('prefer-pre-built')) {
$repo = Config::getPreBuilt('repo');
$pre_built_libs = Downloader::getLatestGithubRelease($repo, [
'repo' => $repo,
'prefer-stable' => Config::getPreBuilt('prefer-stable'),
], false);
} else {
$pre_built_libs = [];
}
// Download them // Download them
f_mkdir(DOWNLOAD_PATH); f_mkdir(DOWNLOAD_PATH);
$cnt = count($chosen_sources); $cnt = count($chosen_sources);
@@ -185,8 +207,21 @@ class DownloadCommand extends BaseCommand
logger()->info("Fetching source {$source} from custom url [{$ni}/{$cnt}]"); logger()->info("Fetching source {$source} from custom url [{$ni}/{$cnt}]");
Downloader::downloadSource($source, $new_config, true); Downloader::downloadSource($source, $new_config, true);
} else { } else {
$config = Config::getSource($source);
// Prefer pre-built, we need to search pre-built library
if ($this->getOption('prefer-pre-built') && ($config['provide-pre-built'] ?? false) === true) {
// We need to replace pattern
$find = str_replace(['{name}', '{arch}', '{os}'], [$source, arch2gnu(php_uname('m')), strtolower(PHP_OS_FAMILY)], Config::getPreBuilt('match-pattern'));
// find filename in asset list
if (($url = $this->findPreBuilt($pre_built_libs, $find)) !== null) {
logger()->info("Fetching pre-built content {$source} [{$ni}/{$cnt}]");
Downloader::downloadSource($source, ['type' => 'url', 'url' => $url], $force_all || in_array($source, $force_list), SPC_LOCK_PRE_BUILT);
continue;
}
logger()->warning("Pre-built content not found for {$source}, fallback to source download");
}
logger()->info("Fetching source {$source} [{$ni}/{$cnt}]"); logger()->info("Fetching source {$source} [{$ni}/{$cnt}]");
Downloader::downloadSource($source, Config::getSource($source), $force_all || in_array($source, $force_list)); Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
} }
} }
$time = round(microtime(true) - START_TIME, 3); $time = round(microtime(true) - START_TIME, 3);
@@ -286,4 +321,19 @@ class DownloadCommand extends BaseCommand
} }
return array_values(array_unique($sources)); return array_values(array_unique($sources));
} }
/**
* @param array $assets Asset list from GitHub API
* @param string $filename Match file name, e.g. pkg-config-aarch64-darwin.txz
* @return null|string Return the download URL if found, otherwise null
*/
private function findPreBuilt(array $assets, string $filename): ?string
{
foreach ($assets as $asset) {
if ($asset['name'] === $filename) {
return $asset['browser_download_url'];
}
}
return null;
}
} }

View File

@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace SPC\command\dev;
use SPC\builder\BuilderProvider;
use SPC\command\BuildCommand;
use SPC\exception\ExceptionHandler;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\util\DependencyUtil;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
#[AsCommand('dev:pack-lib', 'Build and pack library as pre-built release')]
class PackLibCommand extends BuildCommand
{
public function configure(): void
{
$this->addArgument('library', InputArgument::REQUIRED, 'The library will be compiled');
}
public function handle(): int
{
try {
$lib_name = $this->getArgument('library');
$builder = BuilderProvider::makeBuilderByInput($this->input);
$builder->setLibsOnly();
$libraries = DependencyUtil::getLibs([$lib_name]);
logger()->info('Building libraries: ' . implode(',', $libraries));
sleep(2);
FileSystem::createDir(WORKING_DIR . '/dist');
$builder->proveLibs($libraries);
$builder->validateLibsAndExts();
foreach ($builder->getLibs() as $lib) {
if ($lib->getName() !== $lib_name) {
// other dependencies: install or build, both ok
$lib->setup();
} else {
// Get lock info
$lock = json_decode(file_get_contents(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
$source = Config::getLib($lib->getName(), 'source');
if (!isset($lock[$source]) || ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
logger()->critical("The library {$lib->getName()} is downloaded as pre-built, we need to build it instead of installing pre-built.");
return static::FAILURE;
}
// Before build: load buildroot/ directory
$before_buildroot = FileSystem::scanDirFiles(BUILD_ROOT_PATH, relative: true);
// build
$lib->tryBuild(true);
// do something like patching pkg-conf files.
$lib->beforePack();
// 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);
// every file mapped with BUILD_ROOT_PATH
// get BUILD_ROOT_PATH last dir part
$buildroot_part = basename(BUILD_ROOT_PATH);
$increase_files = array_map(fn ($file) => $buildroot_part . '/' . $file, $increase_files);
// write list to packlib_files.txt
FileSystem::writeFile(WORKING_DIR . '/packlib_files.txt', implode("\n", $increase_files));
// pack
$filename = WORKING_DIR . '/dist/' . $lib->getName() . '-' . arch2gnu(php_uname('m')) . '-' . strtolower(PHP_OS_FAMILY) . '.' . Config::getPreBuilt('suffix');
f_passthru('tar -czf ' . $filename . ' -T ' . WORKING_DIR . '/packlib_files.txt');
logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.');
}
}
$time = round(microtime(true) - START_TIME, 3);
logger()->info('Build libs complete, used ' . $time . ' s !');
return static::SUCCESS;
} catch (\Throwable $e) {
if ($this->getOption('debug')) {
ExceptionHandler::getInstance()->handle($e);
} else {
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
logger()->critical('Please check with --debug option to see more details.');
}
return static::FAILURE;
}
}
}

View File

@@ -71,7 +71,7 @@ class WindowsToolCheckList
if (($path = SystemUtil::findCommand('perl.exe')) === null) { if (($path = SystemUtil::findCommand('perl.exe')) === null) {
return CheckResult::fail('perl not found in path.', 'install-perl'); return CheckResult::fail('perl not found in path.', 'install-perl');
} }
if (!str_contains(implode('', cmd()->execWithResult(quote($path) . ' -v')[1]), 'MSWin32')) { if (!str_contains(implode('', cmd()->execWithResult(quote($path) . ' -v', false)[1]), 'MSWin32')) {
return CheckResult::fail($path . ' is not built for msvc.', 'install-perl'); return CheckResult::fail($path . ' is not built for msvc.', 'install-perl');
} }
return CheckResult::ok(); return CheckResult::ok();

View File

@@ -20,6 +20,16 @@ class Config
public static ?array $ext = null; public static ?array $ext = null;
public static ?array $pre_built = null;
public static function getPreBuilt(string $name): mixed
{
if (self::$pre_built === null) {
self::$pre_built = FileSystem::loadConfigArray('pre-built');
}
return self::$pre_built[$name] ?? null;
}
/** /**
* 从配置文件读取一个资源(source)的元信息 * 从配置文件读取一个资源(source)的元信息
* *

View File

@@ -100,14 +100,15 @@ class Downloader
/** /**
* Get latest version from GitHub release (uploaded archive) * Get latest version from GitHub release (uploaded archive)
* *
* @param string $name source name * @param string $name source name
* @param array $source source meta info: [repo, match] * @param array $source source meta info: [repo, match]
* @return array<int, string> [url, filename] * @param bool $match_result Whether to return matched result by `match` param (default: true)
* @return array<int, string> When $match_result = true, and we matched, [url, filename]. Otherwise, [{asset object}. ...]
* @throws DownloaderException * @throws DownloaderException
*/ */
public static function getLatestGithubRelease(string $name, array $source): array public static function getLatestGithubRelease(string $name, array $source, bool $match_result = true): array
{ {
logger()->debug("finding {$name} source from github releases assests"); logger()->debug("finding {$name} from github releases assests");
$data = json_decode(self::curlExec( $data = json_decode(self::curlExec(
url: "https://api.github.com/repos/{$source['repo']}/releases", url: "https://api.github.com/repos/{$source['repo']}/releases",
hooks: [[CurlHook::class, 'setupGithubToken']], hooks: [[CurlHook::class, 'setupGithubToken']],
@@ -118,6 +119,9 @@ class Downloader
if (($source['prefer-stable'] ?? false) === true && $release['prerelease'] === true) { if (($source['prefer-stable'] ?? false) === true && $release['prerelease'] === true) {
continue; continue;
} }
if (!$match_result) {
return $release['assets'];
}
foreach ($release['assets'] as $asset) { foreach ($release['assets'] as $asset) {
if (preg_match('|' . $source['match'] . '|', $asset['name'])) { if (preg_match('|' . $source['match'] . '|', $asset['name'])) {
$url = $asset['browser_download_url']; $url = $asset['browser_download_url'];
@@ -127,7 +131,7 @@ class Downloader
} }
if (!$url) { if (!$url) {
throw new DownloaderException("failed to find {$name} source"); throw new DownloaderException("failed to find {$name} release metadata");
} }
$filename = basename($url); $filename = basename($url);
@@ -176,11 +180,10 @@ class Downloader
/** /**
* Just download file using system curl command, and lock it * Just download file using system curl command, and lock it
* *
* @throws DownloaderException
* @throws RuntimeException
* @throws FileSystemException * @throws FileSystemException
* @throws RuntimeException
*/ */
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null): void public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $lock_as = SPC_LOCK_SOURCE): void
{ {
logger()->debug("Downloading {$url}"); logger()->debug("Downloading {$url}");
$cancel_func = function () use ($filename) { $cancel_func = function () use ($filename) {
@@ -193,7 +196,7 @@ class Downloader
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"), retry: intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0)); self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"), retry: intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0));
self::unregisterCancelEvent(); self::unregisterCancelEvent();
logger()->debug("Locking {$filename}"); logger()->debug("Locking {$filename}");
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path]); self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path, 'lock_as' => $lock_as]);
} }
/** /**
@@ -218,7 +221,7 @@ class Downloader
* @throws FileSystemException * @throws FileSystemException
* @throws RuntimeException * @throws RuntimeException
*/ */
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0): void public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_LOCK_SOURCE): void
{ {
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}"); $download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
if (file_exists($download_path)) { if (file_exists($download_path)) {
@@ -253,7 +256,7 @@ class Downloader
} }
// Lock // Lock
logger()->debug("Locking git source {$name}"); logger()->debug("Locking git source {$name}");
self::lockSource($name, ['source_type' => 'dir', 'dirname' => $name, 'move_path' => $move_path]); self::lockSource($name, ['source_type' => 'dir', 'dirname' => $name, 'move_path' => $move_path, 'lock_as' => $lock_as]);
/* /*
// 复制目录过去 // 复制目录过去
@@ -313,28 +316,28 @@ class Downloader
switch ($pkg['type']) { switch ($pkg['type']) {
case 'bitbuckettag': // BitBucket Tag case 'bitbuckettag': // BitBucket Tag
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg); [$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null); self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break; break;
case 'ghtar': // GitHub Release (tar) case 'ghtar': // GitHub Release (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $pkg); [$url, $filename] = self::getLatestGithubTarball($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null); self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break; break;
case 'ghtagtar': // GitHub Tag (tar) case 'ghtagtar': // GitHub Tag (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags'); [$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null); self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break; break;
case 'ghrel': // GitHub Release (uploaded) case 'ghrel': // GitHub Release (uploaded)
[$url, $filename] = self::getLatestGithubRelease($name, $pkg); [$url, $filename] = self::getLatestGithubRelease($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null); self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break; break;
case 'filelist': // Basic File List (regex based crawler) case 'filelist': // Basic File List (regex based crawler)
[$url, $filename] = self::getFromFileList($name, $pkg); [$url, $filename] = self::getFromFileList($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null); self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break; break;
case 'url': // Direct download URL case 'url': // Direct download URL
$url = $pkg['url']; $url = $pkg['url'];
$filename = $pkg['filename'] ?? basename($pkg['url']); $filename = $pkg['filename'] ?? basename($pkg['url']);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null); self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break; break;
case 'git': // Git repo case 'git': // Git repo
self::downloadGit( self::downloadGit(
@@ -342,7 +345,8 @@ class Downloader
$pkg['url'], $pkg['url'],
$pkg['rev'], $pkg['rev'],
$pkg['extract'] ?? null, $pkg['extract'] ?? null,
intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0) intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0),
SPC_LOCK_PRE_BUILT
); );
break; break;
case 'custom': // Custom download method, like API-based download or other case 'custom': // Custom download method, like API-based download or other
@@ -371,12 +375,14 @@ class Downloader
/** /**
* Download source by name and meta. * Download source by name and meta.
* *
* @param string $name source name * @param string $name source name
* @param null|array $source source meta info: [type, path, rev, url, filename, regex, license] * @param null|array $source source meta info: [type, path, rev, url, filename, regex, license]
* @param bool $force Whether to force download (default: false)
* @param int $lock_as Lock source type (default: SPC_LOCK_SOURCE)
* @throws DownloaderException * @throws DownloaderException
* @throws FileSystemException * @throws FileSystemException
*/ */
public static function downloadSource(string $name, ?array $source = null, bool $force = false): void public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $lock_as = SPC_LOCK_SOURCE): void
{ {
if ($source === null) { if ($source === null) {
$source = Config::getSource($name); $source = Config::getSource($name);
@@ -398,7 +404,7 @@ class Downloader
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? []; $lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
} }
// If lock file exists, skip downloading // If lock file exists, skip downloading
if (isset($lock[$name]) && !$force) { if (isset($lock[$name]) && !$force && ($lock[$name]['lock_as'] ?? SPC_LOCK_SOURCE) === $lock_as) {
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) { if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
logger()->notice("source [{$name}] already downloaded: " . $lock[$name]['filename']); logger()->notice("source [{$name}] already downloaded: " . $lock[$name]['filename']);
return; return;
@@ -413,28 +419,28 @@ class Downloader
switch ($source['type']) { switch ($source['type']) {
case 'bitbuckettag': // BitBucket Tag case 'bitbuckettag': // BitBucket Tag
[$url, $filename] = self::getLatestBitbucketTag($name, $source); [$url, $filename] = self::getLatestBitbucketTag($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null); self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break; break;
case 'ghtar': // GitHub Release (tar) case 'ghtar': // GitHub Release (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $source); [$url, $filename] = self::getLatestGithubTarball($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null); self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break; break;
case 'ghtagtar': // GitHub Tag (tar) case 'ghtagtar': // GitHub Tag (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags'); [$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
self::downloadFile($name, $url, $filename, $source['path'] ?? null); self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break; break;
case 'ghrel': // GitHub Release (uploaded) case 'ghrel': // GitHub Release (uploaded)
[$url, $filename] = self::getLatestGithubRelease($name, $source); [$url, $filename] = self::getLatestGithubRelease($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null); self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break; break;
case 'filelist': // Basic File List (regex based crawler) case 'filelist': // Basic File List (regex based crawler)
[$url, $filename] = self::getFromFileList($name, $source); [$url, $filename] = self::getFromFileList($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null); self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break; break;
case 'url': // Direct download URL case 'url': // Direct download URL
$url = $source['url']; $url = $source['url'];
$filename = $source['filename'] ?? basename($source['url']); $filename = $source['filename'] ?? basename($source['url']);
self::downloadFile($name, $url, $filename, $source['path'] ?? null); self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break; break;
case 'git': // Git repo case 'git': // Git repo
self::downloadGit( self::downloadGit(
@@ -442,14 +448,15 @@ class Downloader
$source['url'], $source['url'],
$source['rev'], $source['rev'],
$source['path'] ?? null, $source['path'] ?? null,
intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0) intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0),
$lock_as
); );
break; break;
case 'custom': // Custom download method, like API-based download or other case 'custom': // Custom download method, like API-based download or other
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source'); $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
foreach ($classes as $class) { foreach ($classes as $class) {
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) { if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
(new $class())->fetch($force); (new $class())->fetch($force, $source, $lock_as);
break; break;
} }
} }
@@ -551,7 +558,6 @@ class Downloader
try { try {
f_passthru($cmd); f_passthru($cmd);
} catch (RuntimeException $e) { } catch (RuntimeException $e) {
var_dump($e->getCode());
if ($e->getCode() === 2 || $e->getCode() === -1073741510) { if ($e->getCode() === 2 || $e->getCode() === -1073741510) {
throw new WrongUsageException('Keyboard interrupted, download failed !'); throw new WrongUsageException('Keyboard interrupted, download failed !');
} }

View File

@@ -16,7 +16,7 @@ class FileSystem
*/ */
public static function loadConfigArray(string $config, ?string $config_dir = null): array public static function loadConfigArray(string $config, ?string $config_dir = null): array
{ {
$whitelist = ['ext', 'lib', 'source', 'pkg']; $whitelist = ['ext', 'lib', 'source', 'pkg', 'pre-built'];
if (!in_array($config, $whitelist)) { if (!in_array($config, $whitelist)) {
throw new FileSystemException('Reading ' . $config . '.json is not allowed'); throw new FileSystemException('Reading ' . $config . '.json is not allowed');
} }

View File

@@ -8,5 +8,5 @@ abstract class CustomSourceBase
{ {
public const NAME = 'unknown'; public const NAME = 'unknown';
abstract public function fetch(bool $force = false); abstract public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void;
} }

View File

@@ -17,7 +17,7 @@ class PhpSource extends CustomSourceBase
* @throws DownloaderException * @throws DownloaderException
* @throws FileSystemException * @throws FileSystemException
*/ */
public function fetch(bool $force = false): void public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void
{ {
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.1'; $major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.1';
Downloader::downloadSource('php-src', self::getLatestPHPInfo($major), $force); Downloader::downloadSource('php-src', self::getLatestPHPInfo($major), $force);
@@ -45,7 +45,7 @@ class PhpSource extends CustomSourceBase
// 从官网直接下载 // 从官网直接下载
return [ return [
'type' => 'url', 'type' => 'url',
'url' => "https://www.php.net/distributions/php-{$version}.tar.gz", 'url' => "https://www.php.net/distributions/php-{$version}.tar.xz",
]; ];
} }
} }

View File

@@ -16,7 +16,7 @@ class PostgreSQLSource extends CustomSourceBase
* @throws DownloaderException * @throws DownloaderException
* @throws FileSystemException * @throws FileSystemException
*/ */
public function fetch(bool $force = false): void public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void
{ {
Downloader::downloadSource('postgresql', self::getLatestInfo(), $force); Downloader::downloadSource('postgresql', self::getLatestInfo(), $force);
} }

View File

@@ -107,9 +107,9 @@ class LicenseDumper
} }
foreach ($licenses as $index => $license) { foreach ($licenses as $index => $license) {
yield ($license['suffix'] ?? $index) => match ($license['type']) { yield $index => match ($license['type']) {
'text' => $license['text'], 'text' => $license['text'],
'file' => $this->loadSourceFile($source_name, $license['path'], Config::getSource($source_name)['path'] ?? null), 'file' => $this->loadSourceFile($source_name, $index, $license['path'], Config::getSource($source_name)['path'] ?? null),
default => throw new RuntimeException('source [' . $source_name . '] license type is not allowed'), default => throw new RuntimeException('source [' . $source_name . '] license type is not allowed'),
}; };
} }
@@ -118,15 +118,21 @@ class LicenseDumper
/** /**
* @throws RuntimeException * @throws RuntimeException
*/ */
private function loadSourceFile(string $source_name, ?string $in_path, ?string $custom_base_path = null): string private function loadSourceFile(string $source_name, int $index, ?string $in_path, ?string $custom_base_path = null): string
{ {
if (is_null($in_path)) { if (is_null($in_path)) {
throw new RuntimeException('source [' . $source_name . '] license file is not set, please check config/source.json'); throw new RuntimeException('source [' . $source_name . '] license file is not set, please check config/source.json');
} }
if (!file_exists(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path)) {
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] not exist'); if (file_exists(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path)) {
return file_get_contents(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path);
} }
return file_get_contents(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path); if (file_exists(BUILD_ROOT_PATH . '/source-licenses/' . $source_name . '/' . $index . '.txt')) {
logger()->debug('source [' . $source_name . '] license file [' . $index . ':' . $in_path . '] not exist, use installed version instead');
return file_get_contents(BUILD_ROOT_PATH . '/source-licenses/' . $source_name . '/' . $index . '.txt');
}
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] not exist');
} }
} }

View File

@@ -41,6 +41,7 @@ class UnixShell
{ {
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
logger()->info(ConsoleColor::yellow('[EXEC] ') . ConsoleColor::green($cmd)); logger()->info(ConsoleColor::yellow('[EXEC] ') . ConsoleColor::green($cmd));
logger()->debug('Executed at: ' . debug_backtrace()[0]['file'] . ':' . debug_backtrace()[0]['line']);
if ($this->cd !== null) { if ($this->cd !== null) {
$cmd = 'cd ' . escapeshellarg($this->cd) . ' && ' . $cmd; $cmd = 'cd ' . escapeshellarg($this->cd) . ' && ' . $cmd;
} }
@@ -57,8 +58,10 @@ class UnixShell
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
logger()->info(ConsoleColor::blue('[EXEC] ') . ConsoleColor::green($cmd)); logger()->info(ConsoleColor::blue('[EXEC] ') . ConsoleColor::green($cmd));
} else { } else {
logger()->debug('Running command with result: ' . $cmd); /* @phpstan-ignore-next-line */
logger()->debug(ConsoleColor::blue('[EXEC] ') . ConsoleColor::gray($cmd));
} }
logger()->debug('Executed at: ' . debug_backtrace()[0]['file'] . ':' . debug_backtrace()[0]['line']);
exec($cmd, $out, $code); exec($cmd, $out, $code);
return [$code, $out]; return [$code, $out];
} }

View File

@@ -56,15 +56,20 @@ const SPC_EXTENSION_ALIAS = [
'zendopcache' => 'opcache', 'zendopcache' => 'opcache',
]; ];
// spc lock type
const SPC_LOCK_SOURCE = 1; // lock source
const SPC_LOCK_PRE_BUILT = 2; // lock pre-built
// file replace strategy // file replace strategy
const REPLACE_FILE_STR = 1; const REPLACE_FILE_STR = 1;
const REPLACE_FILE_PREG = 2; const REPLACE_FILE_PREG = 2;
const REPLACE_FILE_USER = 3; const REPLACE_FILE_USER = 3;
// library build status // library build status
const BUILD_STATUS_OK = 0; const LIB_STATUS_OK = 0;
const BUILD_STATUS_ALREADY = 1; const LIB_STATUS_ALREADY = 1;
const BUILD_STATUS_FAILED = 2; const LIB_STATUS_BUILD_FAILED = 2;
const LIB_STATUS_INSTALL_FAILED = 3;
// build target type // build target type
const BUILD_TARGET_NONE = 0; // no target const BUILD_TARGET_NONE = 0; // no target

View File

@@ -26,7 +26,7 @@ LDFLAGS=/DEBUG /GUARD:CF /INCREMENTAL:NO
SQLITE3_STATIC_BASE=libsqlite3_a SQLITE3_STATIC_BASE=libsqlite3_a
SQLITE3_DLL_BASE=libsqlite3 SQLITE3_DLL_BASE=libsqlite3
SQLITE3_EXE_BASE=sqlite3 SQLITE3_EXE_BASE=sqlite3
CFLAGS=$(COMMON_CFLAGS) /Zi /MT /guard:cf /Zc:inline /Qspectre /Ox /W3 /GF /GL /Gw CFLAGS=$(COMMON_CFLAGS) /Zi /MT /guard:cf /Zc:inline /Qspectre /Ox /W3 /GF /Gw
LDFLAGS=/GUARD:CF /INCREMENTAL:NO /NXCOMPAT /DYNAMICBASE LDFLAGS=/GUARD:CF /INCREMENTAL:NO /NXCOMPAT /DYNAMICBASE
!ENDIF !ENDIF

View File

@@ -140,7 +140,7 @@ function f_passthru(string $cmd): ?bool
if ($danger) { if ($danger) {
logger()->notice('Running dangerous command: ' . $cmd); logger()->notice('Running dangerous command: ' . $cmd);
} else { } else {
logger()->debug('Running command with direct output: ' . $cmd); logger()->debug('[PASSTHRU] ' . $cmd);
} }
$ret = passthru($cmd, $code); $ret = passthru($cmd, $code);
if ($code !== 0) { if ($code !== 0) {

View File

@@ -19,8 +19,8 @@ $upx = true;
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
$extensions = match (PHP_OS_FAMILY) { $extensions = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'spx', 'Linux', 'Darwin' => 'openssl',
'Windows' => 'mbstring,pdo_sqlite,mbregex,bz2,sqlsrv,pdo_sqlsrv,yaml', 'Windows' => 'mbstring,pdo_sqlite,openssl',
}; };
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`). // If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).

View File

@@ -43,7 +43,6 @@ final class LicenseDumperTest extends TestCase
'license' => [ 'license' => [
'type' => 'text', 'type' => 'text',
'text' => 'license', 'text' => 'license',
'suffix' => 'zend',
], ],
], ],
]; ];
@@ -52,7 +51,7 @@ final class LicenseDumperTest extends TestCase
$dumper->addLibs(['fake_lib']); $dumper->addLibs(['fake_lib']);
$dumper->dump(self::DIRECTORY); $dumper->dump(self::DIRECTORY);
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt'); $this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
} }
public function testDumpWithMultipleLicenses(): void public function testDumpWithMultipleLicenses(): void
@@ -76,7 +75,6 @@ final class LicenseDumperTest extends TestCase
[ [
'type' => 'text', 'type' => 'text',
'text' => 'license', 'text' => 'license',
'suffix' => 'zend',
], ],
], ],
], ],
@@ -88,6 +86,6 @@ final class LicenseDumperTest extends TestCase
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt'); $this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_1.txt'); $this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_1.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt'); $this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_2.txt');
} }
} }