diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index bd4bee44..519475d3 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -15,6 +15,7 @@ use SPC\store\Config; use SPC\store\CurlHook; use SPC\store\Downloader; use SPC\store\FileSystem; +use SPC\store\pkg\GoXcaddy; use SPC\util\DependencyUtil; use SPC\util\SPCConfigUtil; @@ -301,18 +302,6 @@ abstract class UnixBuilderBase extends BuilderBase */ protected function buildFrankenphp(): void { - $os = match (PHP_OS_FAMILY) { - 'Linux' => 'linux', - 'Windows' => 'win', - 'Darwin' => 'macos', - 'BSD' => 'freebsd', - default => throw new RuntimeException('Unsupported OS: ' . PHP_OS_FAMILY), - }; - $arch = arch2gnu(php_uname('m')); - - // define executables for go and xcaddy - $xcaddy_exec = PKG_ROOT_PATH . "/go-xcaddy-{$arch}-{$os}/bin/xcaddy"; - $nobrotli = $this->getLib('brotli') === null ? ',nobrotli' : ''; $nowatcher = $this->getLib('watcher') === null ? ',nowatcher' : ''; $xcaddyModules = getenv('SPC_CMD_VAR_FRANKENPHP_XCADDY_MODULES'); @@ -344,11 +333,7 @@ abstract class UnixBuilderBase extends BuilderBase $config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list, with_dependencies: true); - $env = [ - 'PATH' => PKG_ROOT_PATH . "/go-xcaddy-{$arch}-{$os}/bin:" . getenv('PATH'), - 'GOROOT' => PKG_ROOT_PATH . "/go-xcaddy-{$arch}-{$os}", - 'GOBIN' => PKG_ROOT_PATH . "/go-xcaddy-{$arch}-{$os}/bin", - 'GOPATH' => PKG_ROOT_PATH . '/go', + $env = [...GoXcaddy::getEnvironment(), ...[ 'CGO_ENABLED' => '1', 'CGO_CFLAGS' => $config['cflags'], 'CGO_LDFLAGS' => "{$config['ldflags']} {$config['libs']} {$lrt}", @@ -358,9 +343,9 @@ abstract class UnixBuilderBase extends BuilderBase "{$frankenPhpVersion} PHP {$libphpVersion} Caddy'\\\" " . "-tags={$muslTags}nobadger,nomysql,nopgx{$nobrotli}{$nowatcher}", 'LD_LIBRARY_PATH' => BUILD_LIB_PATH, - ]; + ]]; shell()->cd(BUILD_BIN_PATH) ->setEnv($env) - ->exec("{$xcaddy_exec} build --output frankenphp {$xcaddyModules}"); + ->exec("xcaddy build --output frankenphp {$xcaddyModules}"); } } diff --git a/src/SPC/store/pkg/CustomPackage.php b/src/SPC/store/pkg/CustomPackage.php index 89edb17e..bc6f6e46 100644 --- a/src/SPC/store/pkg/CustomPackage.php +++ b/src/SPC/store/pkg/CustomPackage.php @@ -10,8 +10,7 @@ abstract class CustomPackage abstract public function fetch(string $name, bool $force = false, ?array $config = null): void; - public function extract(string $name): void - { - throw new \RuntimeException("Extract method not implemented for package: {$name}"); - } + abstract public function extract(string $name): void; + + abstract public static function getEnvironment(): array; } diff --git a/src/SPC/store/pkg/GoXcaddy.php b/src/SPC/store/pkg/GoXcaddy.php index e0c7c5b9..5c089fc9 100644 --- a/src/SPC/store/pkg/GoXcaddy.php +++ b/src/SPC/store/pkg/GoXcaddy.php @@ -73,4 +73,26 @@ class GoXcaddy extends CustomPackage ]) ->exec("{$go_exec} install github.com/caddyserver/xcaddy/cmd/xcaddy@latest"); } + + public static function getEnvironment(): array + { + $arch = arch2gnu(php_uname('m')); + $os = match (PHP_OS_FAMILY) { + 'Windows' => 'win', + 'Darwin' => 'macos', + 'BSD' => 'freebsd', + default => 'linux', + }; + + $packageName = "go-xcaddy-{$arch}-{$os}"; + $pkgroot = PKG_ROOT_PATH; + + return [ + 'PATH' => "{$pkgroot}/{$packageName}/bin", + 'GOROOT' => "{$pkgroot}/{$packageName}", + 'GOBIN' => "{$pkgroot}/{$packageName}/bin", + 'GOPATH' => "{$pkgroot}/go", + ]; + } + } diff --git a/src/SPC/store/pkg/Zig.php b/src/SPC/store/pkg/Zig.php index 38020579..6784361c 100644 --- a/src/SPC/store/pkg/Zig.php +++ b/src/SPC/store/pkg/Zig.php @@ -112,12 +112,65 @@ class Zig extends CustomPackage private function createZigCcScript(string $bin_dir): void { - $zig_cc_path = "{$bin_dir}/zig-cc"; $script_content = <<<'EOF' #!/usr/bin/env bash -SPC_TARGET="${SPC_TARGET:-native-native}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BUILDROOT_ABS="$(realpath "$SCRIPT_DIR/../../buildroot/include" 2>/dev/null || echo "")" +PARSED_ARGS=() + +while [[ $# -gt 0 ]]; do + case "$1" in + -isystem) + shift + ARG="$1" + [[ -n "$ARG" ]] && shift || break + ARG_ABS="$(realpath "$ARG" 2>/dev/null || echo "")" + if [[ -n "$ARG_ABS" && "$ARG_ABS" == "$BUILDROOT_ABS" ]]; then + PARSED_ARGS+=("-I$ARG") + else + PARSED_ARGS+=("-isystem" "$ARG") + fi + ;; + -isystem*) + ARG="${1#-isystem}" + shift + ARG_ABS="$(realpath "$ARG" 2>/dev/null || echo "")" + if [[ -n "$ARG_ABS" && "$ARG_ABS" == "$BUILDROOT_ABS" ]]; then + PARSED_ARGS+=("-I$ARG") + else + PARSED_ARGS+=("-isystem$ARG") + fi + ;; + *) + PARSED_ARGS+=("$1") + shift + ;; + esac +done + +SPC_TARGET_WAS_SET=1 +if [ -z "${SPC_TARGET+x}" ]; then + SPC_TARGET_WAS_SET=0 +fi + +UNAME_M="$(uname -m)" +UNAME_S="$(uname -s)" + +case "$UNAME_M" in + x86_64) ARCH="x86_64" ;; + aarch64|arm64) ARCH="aarch64" ;; + *) echo "Unsupported architecture: $UNAME_M" >&2; exit 1 ;; +esac + +case "$UNAME_S" in + Linux) OS="linux" ;; + Darwin) OS="macos" ;; + *) echo "Unsupported OS: $UNAME_S" >&2; exit 1 ;; +esac + +SPC_TARGET="${SPC_TARGET:-$ARCH-$OS}" SPC_LIBC="${SPC_LIBC}" SPC_LIBC_VERSION="${SPC_LIBC_VERSION}" @@ -125,24 +178,47 @@ if [ "$SPC_LIBC" = "glibc" ]; then SPC_LIBC="gnu" fi -if [ "$SPC_TARGET" = "native-native" ] && [ -z "$SPC_LIBC" ] && [ -z "$SPC_LIBC_VERSION" ]; then - exec zig cc "$@" +if [ "$SPC_TARGET_WAS_SET" -eq 0 ] && [ -z "$SPC_LIBC" ] && [ -z "$SPC_LIBC_VERSION" ]; then + exec zig cc "${PARSED_ARGS[@]}" elif [ -z "$SPC_LIBC" ] && [ -z "$SPC_LIBC_VERSION" ]; then - exec zig cc -target ${SPC_TARGET} "$@" + exec zig cc -target ${SPC_TARGET} "${PARSED_ARGS[@]}" elif [ -z "$SPC_LIBC_VERSION" ]; then - exec zig cc -target ${SPC_TARGET}-${SPC_LIBC} -L/usr/lib64 -lstdc++ "$@" + exec zig cc -target ${SPC_TARGET}-${SPC_LIBC} -L/usr/lib64 -lstdc++ "${PARSED_ARGS[@]}" else - error_output=$(zig cc -target ${SPC_TARGET}-${SPC_LIBC}.${SPC_LIBC_VERSION} "$@" 2>&1 >/dev/null) + error_output=$(zig cc -target ${SPC_TARGET}-${SPC_LIBC}.${SPC_LIBC_VERSION} "${PARSED_ARGS[@]}" 2>&1 >/dev/null) if echo "$error_output" | grep -q "zig: error: version '.*' in target triple '${SPC_TARGET}-${SPC_LIBC}\..*' is invalid"; then - exec zig cc -target ${SPC_TARGET}-${SPC_LIBC} -L/usr/lib64 -lstdc++ "$@" + exec zig cc -target ${SPC_TARGET}-${SPC_LIBC} -L/usr/lib64 -lstdc++ "${PARSED_ARGS[@]}" else - exec zig cc -target ${SPC_TARGET}-${SPC_LIBC}.${SPC_LIBC_VERSION} -L/usr/lib64 -lstdc++ "$@" + exec zig cc -target ${SPC_TARGET}-${SPC_LIBC}.${SPC_LIBC_VERSION} -L/usr/lib64 -lstdc++ "${PARSED_ARGS[@]}" fi fi EOF; - file_put_contents($zig_cc_path, $script_content); - chmod($zig_cc_path, 0755); + file_put_contents("{$bin_dir}/zig-cc", $script_content); + chmod("{$bin_dir}/zig-cc", 0755); + + $script_content = str_replace('zig cc', 'zig c++', $script_content); + file_put_contents("{$bin_dir}/zig-c++", $script_content); + chmod("{$bin_dir}/zig-c++", 0755); + } + + public static function getEnvironment(): array + { + $arch = arch2gnu(php_uname('m')); + $os = match (PHP_OS_FAMILY) { + 'Linux' => 'linux', + 'Windows' => 'win', + 'Darwin' => 'macos', + 'BSD' => 'freebsd', + default => 'linux', + }; + + $packageName = "zig-{$arch}-{$os}"; + $path = PKG_ROOT_PATH . "/{$packageName}"; + + return [ + 'PATH' => $path + ]; } } diff --git a/src/SPC/util/GlobalEnvManager.php b/src/SPC/util/GlobalEnvManager.php index fa5c9cf5..8f916716 100644 --- a/src/SPC/util/GlobalEnvManager.php +++ b/src/SPC/util/GlobalEnvManager.php @@ -7,6 +7,7 @@ namespace SPC\util; use SPC\builder\linux\SystemUtil; use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; +use SPC\store\pkg\Zig; /** * Environment variable manager @@ -100,6 +101,14 @@ class GlobalEnvManager self::putenv("{$k}={$v}"); } } + if (str_contains(getenv('CC'), 'zig') || str_contains(getenv('CXX'), 'zig')) { + $zigEnv = Zig::getEnvironment(); + foreach ($zigEnv as $key => $value) { + if ($key === 'PATH') { + self::addPathIfNotExists($value); + } + } + } } public static function putenv(string $val): void