diff --git a/bin/spc-gnu-docker b/bin/spc-gnu-docker new file mode 100755 index 00000000..362242b6 --- /dev/null +++ b/bin/spc-gnu-docker @@ -0,0 +1,104 @@ +#!/usr/bin/env bash + +# This file is using docker to run commands +set -e + +# Detect docker can run +if ! which docker >/dev/null; then + echo "Docker is not installed, please install docker first !" + exit 1 +fi +DOCKER_EXECUTABLE="docker" +# shellcheck disable=SC2046 +if [ $(id -u) -ne 0 ]; then + if ! docker info > /dev/null 2>&1; then + if [ "$SPC_USE_SUDO" != "yes" ]; then + echo "Docker command requires sudo" + # shellcheck disable=SC2039 + echo -n 'To use sudo to run docker, run "export SPC_USE_SUDO=yes" and run command again' + exit 1 + fi + DOCKER_EXECUTABLE="sudo docker" + fi +fi + + + +# to check if qemu-docker run +if [ "$SPC_USE_ARCH" = "" ]; then + SPC_USE_ARCH=current +fi +case $SPC_USE_ARCH in +current) + BASE_ARCH=$(uname -m) + if [ "$BASE_ARCH" = "arm64" ]; then + BASE_ARCH=aarch64 + fi + ;; +aarch64) + BASE_ARCH=aarch64 + # shellcheck disable=SC2039 + echo -e "\e[033m* Using different arch needs to setup qemu-static for docker !\e[0m" + $DOCKER_EXECUTABLE run --rm --privileged multiarch/qemu-user-static:register --reset > /dev/null + ;; +*) + echo "Current arch is not supported to run in docker: $SPC_USE_ARCH" + exit 1 + ;; +esac + +# Detect docker env is setup +if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-gnu-$SPC_USE_ARCH; then + echo "Docker container does not exist. Building docker image ..." + $DOCKER_EXECUTABLE build -t cwcc-spc-gnu-$SPC_USE_ARCH -f- . <options = $options; + SystemUtil::initLibcVar($this->options['libc'] ?? null); + + $this->libc = getenv('SPC_LIBC') ?: LIBC_MUSL_WRAPPER; // check musl-cross make installed if we use musl-cross-make $arch = arch2gnu(php_uname('m')); - // set library path, some libraries need it. (We cannot use `putenv` here, because cmake will be confused) - $this->setOptionIfNotExist('library_path', "LIBRARY_PATH=/usr/local/musl/{$arch}-linux-musl/lib"); - $this->setOptionIfNotExist('ld_library_path', "LD_LIBRARY_PATH=/usr/local/musl/{$arch}-linux-musl/lib"); + if ($this->libc !== LIBC_GLIBC) { + // set library path, some libraries need it. (We cannot use `putenv` here, because cmake will be confused) + $this->setOptionIfNotExist('library_path', "LIBRARY_PATH=/usr/local/musl/{$arch}-linux-musl/lib"); + $this->setOptionIfNotExist('ld_library_path', "LD_LIBRARY_PATH=/usr/local/musl/{$arch}-linux-musl/lib"); + } GlobalEnvManager::init($this); diff --git a/src/SPC/builder/linux/SystemUtil.php b/src/SPC/builder/linux/SystemUtil.php index c0ae6766..aef748b8 100644 --- a/src/SPC/builder/linux/SystemUtil.php +++ b/src/SPC/builder/linux/SystemUtil.php @@ -182,4 +182,12 @@ class SystemUtil 'arch', 'manjaro', ]; } + + public static function initLibcVar(?string $libc = null): void + { + if ($libc === null) { + $libc = self::isMuslDist() ? 'musl' : 'musl-wrapper'; + } + f_putenv('SPC_LIBC=' . $libc); + } } diff --git a/src/SPC/builder/linux/library/libpng.php b/src/SPC/builder/linux/library/libpng.php index 5049a647..abc039c0 100644 --- a/src/SPC/builder/linux/library/libpng.php +++ b/src/SPC/builder/linux/library/libpng.php @@ -44,7 +44,8 @@ class libpng extends LinuxLibraryBase shell()->cd($this->source_dir) ->exec('chmod +x ./configure') ->exec('chmod +x ./install-sh') - ->exec( + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $this->builder->arch_c_flags, 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv( 'LDFLAGS="-L' . BUILD_LIB_PATH . '" ' . './configure ' . '--disable-shared ' . @@ -54,9 +55,9 @@ class libpng extends LinuxLibraryBase $optimizations . '--prefix=' ) - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency} DEFAULT_INCLUDES='-I{$this->source_dir} -I" . BUILD_INCLUDE_PATH . "' LIBS= libpng16.la") - ->exec('make install-libLTLIBRARIES install-data-am DESTDIR=' . BUILD_ROOT_PATH); + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency} DEFAULT_INCLUDES='-I{$this->source_dir} -I" . BUILD_INCLUDE_PATH . "' LIBS= libpng16.la") + ->execWithEnv('make install-libLTLIBRARIES install-data-am DESTDIR=' . BUILD_ROOT_PATH); $this->patchPkgconfPrefix(['libpng16.pc'], PKGCONF_PATCH_PREFIX); $this->cleanLaFiles(); } diff --git a/src/SPC/builder/linux/library/openssl.php b/src/SPC/builder/linux/library/openssl.php index fb3ef045..4c83f2e7 100644 --- a/src/SPC/builder/linux/library/openssl.php +++ b/src/SPC/builder/linux/library/openssl.php @@ -43,7 +43,7 @@ class openssl extends LinuxLibraryBase $extra = ''; $ex_lib = '-ldl -pthread'; - $env = "CC='" . getenv('CC') . ' -static -idirafter ' . BUILD_INCLUDE_PATH . + $env = "CC='" . getenv('CC') . ' -idirafter ' . BUILD_INCLUDE_PATH . ' -idirafter /usr/include/ ' . ' -idirafter /usr/include/' . $this->builder->getOption('arch') . '-linux-gnu/ ' . "' "; @@ -70,7 +70,6 @@ class openssl extends LinuxLibraryBase '--prefix=/ ' . '--libdir=lib ' . '--openssldir=/etc/ssl ' . - '-static ' . "{$zlib_extra}" . 'no-legacy ' . "linux-{$this->builder->getOption('arch')}{$clang_postfix}" diff --git a/src/SPC/builder/traits/UnixSystemUtilTrait.php b/src/SPC/builder/traits/UnixSystemUtilTrait.php index 5aa325ab..22e18985 100644 --- a/src/SPC/builder/traits/UnixSystemUtilTrait.php +++ b/src/SPC/builder/traits/UnixSystemUtilTrait.php @@ -52,6 +52,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(CMAKE_EXE_LINKER_FLAGS "-ldl -lpthread -lm -lutil") CMAKE; // 有时候系统的 cmake 找不到 ar 命令,真奇怪 if (PHP_OS_FAMILY === 'Linux') { diff --git a/src/SPC/builder/unix/library/bzip2.php b/src/SPC/builder/unix/library/bzip2.php index 23428317..0241fb1b 100644 --- a/src/SPC/builder/unix/library/bzip2.php +++ b/src/SPC/builder/unix/library/bzip2.php @@ -4,8 +4,16 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\store\FileSystem; + trait bzip2 { + public function patchBeforeBuild(): bool + { + FileSystem::replaceFileStr($this->source_dir . '/Makefile', 'CFLAGS=-Wall', 'CFLAGS=-fPIC -Wall'); + return true; + } + protected function build(): void { shell()->cd($this->source_dir) diff --git a/src/SPC/builder/unix/library/curl.php b/src/SPC/builder/unix/library/curl.php index e01bec2c..3d63e5e7 100644 --- a/src/SPC/builder/unix/library/curl.php +++ b/src/SPC/builder/unix/library/curl.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\builder\linux\library\LinuxLibraryBase; +use SPC\builder\linux\LinuxBuilder; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\store\FileSystem; @@ -51,9 +53,11 @@ trait curl $extra .= $this->builder->getLib('libcares') ? '-DENABLE_ARES=ON ' : ''; FileSystem::resetDir($this->source_dir . '/build'); + + $cflags = $this instanceof LinuxLibraryBase && $this->builder->libc === 'glibc' ? '-fPIC' : ''; // compile! shell()->cd($this->source_dir . '/build') - ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $cflags, 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) ->exec('sed -i.save s@\${CMAKE_C_IMPLICIT_LINK_LIBRARIES}@@ ../CMakeLists.txt') ->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DBUILD_CURL_EXE=OFF -DBUILD_LIBCURL_DOCS=OFF {$extra} ..") ->execWithEnv("make -j{$this->builder->concurrency}") diff --git a/src/SPC/builder/unix/library/gmp.php b/src/SPC/builder/unix/library/gmp.php index 0748c870..49b207fb 100644 --- a/src/SPC/builder/unix/library/gmp.php +++ b/src/SPC/builder/unix/library/gmp.php @@ -16,7 +16,7 @@ trait gmp protected function build(): void { shell()->cd($this->source_dir) - ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $this->builder->arch_c_flags, 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) ->execWithEnv( './configure ' . '--enable-static --disable-shared ' . diff --git a/src/SPC/builder/unix/library/onig.php b/src/SPC/builder/unix/library/onig.php index b43d14b3..60ea84fa 100644 --- a/src/SPC/builder/unix/library/onig.php +++ b/src/SPC/builder/unix/library/onig.php @@ -18,9 +18,10 @@ trait onig [,,$destdir] = SEPARATED_PATH; shell()->cd($this->source_dir) - ->exec('./configure --enable-static --disable-shared --prefix=') - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency}") + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $this->builder->arch_c_flags, 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv('./configure --enable-static --disable-shared --prefix=') + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency}") ->exec("make install DESTDIR={$destdir}"); $this->patchPkgconfPrefix(['oniguruma.pc']); } diff --git a/src/SPC/builder/unix/library/pkgconfig.php b/src/SPC/builder/unix/library/pkgconfig.php index ca93fd25..1f2584ac 100644 --- a/src/SPC/builder/unix/library/pkgconfig.php +++ b/src/SPC/builder/unix/library/pkgconfig.php @@ -4,12 +4,14 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\builder\linux\library\LinuxLibraryBase; + trait pkgconfig { protected function build(): void { $cflags = PHP_OS_FAMILY !== 'Linux' ? "{$this->builder->arch_c_flags} -Wimplicit-function-declaration -Wno-int-conversion" : ''; - $ldflags = PHP_OS_FAMILY !== 'Linux' ? '' : '--static'; + $ldflags = !($this instanceof LinuxLibraryBase) || $this->builder->libc === 'glibc' ? '' : '--static'; shell()->cd($this->source_dir) ->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $cflags, 'LDFLAGS' => $this->getLibExtraLdFlags() ?: $ldflags, 'LIBS' => $this->getLibExtraLibs()]) diff --git a/src/SPC/command/BuildCliCommand.php b/src/SPC/command/BuildCliCommand.php index bc214760..3892877c 100644 --- a/src/SPC/command/BuildCliCommand.php +++ b/src/SPC/command/BuildCliCommand.php @@ -191,7 +191,7 @@ class BuildCliCommand extends BuildCommand $fixed = ''; if (!empty(getenv('SPC_FIX_DEPLOY_ROOT'))) { str_replace($cwd, '', $build_root_path); - $build_root_path = getenv('SPC_FIX_DEPLOY_ROOT') . $build_root_path; + $build_root_path = getenv('SPC_FIX_DEPLOY_ROOT') . '/' . basename($build_root_path); $fixed = ' (host system)'; } if (($rule & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) { diff --git a/src/SPC/command/BuildCommand.php b/src/SPC/command/BuildCommand.php index bea9c119..ad391840 100644 --- a/src/SPC/command/BuildCommand.php +++ b/src/SPC/command/BuildCommand.php @@ -19,6 +19,8 @@ abstract class BuildCommand extends BaseCommand $this->addOption('arch', null, InputOption::VALUE_REQUIRED, 'architecture, "x64" or "arm64"', 'x64'); break; case 'Linux': + $this->addOption('libc', null, InputOption::VALUE_REQUIRED, 'glibc, musl or musl-wrapper', 'musl-wrapper'); + // no break case 'Darwin': $this->addOption('cc', null, InputOption::VALUE_REQUIRED, 'C compiler'); $this->addOption('cxx', null, InputOption::VALUE_REQUIRED, 'C++ compiler'); diff --git a/src/SPC/doctor/item/LinuxToolCheckList.php b/src/SPC/doctor/item/LinuxToolCheckList.php index e605c73b..d75d0fe8 100644 --- a/src/SPC/doctor/item/LinuxToolCheckList.php +++ b/src/SPC/doctor/item/LinuxToolCheckList.php @@ -57,7 +57,8 @@ class LinuxToolCheckList $required = match ($distro['dist']) { 'alpine' => self::TOOLS_ALPINE, - 'redhat', 'centos' => self::TOOLS_RHEL, + 'redhat' => self::TOOLS_RHEL, + 'centos' => array_merge(self::TOOLS_RHEL, ['perl-IPC-Cmd']), 'arch' => self::TOOLS_ARCH, default => self::TOOLS_DEBIAN, }; diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index f6044927..5c7db38f 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -86,6 +86,9 @@ class SourcePatcher } // patch capstone FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/have_capstone="yes"/', 'have_capstone="no"'); + if ($builder instanceof LinuxBuilder && $builder->libc === 'glibc') { + FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Zend/zend_operators.h', '# define ZEND_USE_ASM_ARITHMETIC 1', '# define ZEND_USE_ASM_ARITHMETIC 0'); + } } /** diff --git a/src/SPC/util/GlobalEnvManager.php b/src/SPC/util/GlobalEnvManager.php index 6c6c9820..d3bebbd6 100644 --- a/src/SPC/util/GlobalEnvManager.php +++ b/src/SPC/util/GlobalEnvManager.php @@ -70,6 +70,10 @@ class GlobalEnvManager WORKING_DIR . '/config/env.ini', ROOT_DIR . '/config/env.ini', ]; + $ini_custom = [ + WORKING_DIR . '/config/env.custom.ini', + ROOT_DIR . '/config/env.custom.ini', + ]; $ini = null; foreach ($ini_files as $ini_file) { if (file_exists($ini_file)) { @@ -83,6 +87,23 @@ class GlobalEnvManager if ($ini === false || !isset($ini['global'])) { throw new WrongUsageException('Failed to parse ' . $ini_file); } + // apply custom env + foreach ($ini_custom as $ini_file) { + if (file_exists($ini_file)) { + $ini_custom = parse_ini_file($ini_file, true); + if ($ini_custom !== false) { + $ini['global'] = array_merge($ini['global'], $ini_custom['global'] ?? []); + match (PHP_OS_FAMILY) { + 'Windows' => $ini['windows'] = array_merge($ini['windows'], $ini_custom['windows'] ?? []), + 'Darwin' => $ini['macos'] = array_merge($ini['macos'], $ini_custom['macos'] ?? []), + 'Linux' => $ini['linux'] = array_merge($ini['linux'], $ini_custom['linux'] ?? []), + 'BSD' => $ini['freebsd'] = array_merge($ini['freebsd'], $ini_custom['freebsd'] ?? []), + default => null, + }; + } + break; + } + } self::applyConfig($ini['global']); match (PHP_OS_FAMILY) { 'Windows' => self::applyConfig($ini['windows']), diff --git a/src/globals/defines.php b/src/globals/defines.php index 956e5a9b..bbc2bd2f 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -83,4 +83,9 @@ const AUTOCONF_CPPFLAGS = 4; const AUTOCONF_LDFLAGS = 8; const AUTOCONF_ALL = 15; +const LIBC_MUSL_WRAPPER = 'musl-wrapper'; +const LIBC_MUSL = 'musl'; +const LIBC_GLIBC = 'glibc'; + ConsoleLogger::$date_format = 'H:i:s'; +ConsoleLogger::$format = '[%date%] [I] %body%'; diff --git a/src/globals/ext-tests/openssl.php b/src/globals/ext-tests/openssl.php index 8c42202d..3b3452b3 100644 --- a/src/globals/ext-tests/openssl.php +++ b/src/globals/ext-tests/openssl.php @@ -4,4 +4,6 @@ declare(strict_types=1); assert(function_exists('openssl_digest')); assert(openssl_digest('123456', 'md5') === 'e10adc3949ba59abbe56e057f20f883e'); -assert(file_get_contents('https://example.com/') !== false); +if (file_exists('/etc/ssl/openssl.cnf')) { + assert(file_get_contents('https://example.com/') !== false); +}