diff --git a/config/artifact.yaml b/config/artifact.yaml index cfbb832d..d01d6267 100644 --- a/config/artifact.yaml +++ b/config/artifact.yaml @@ -41,6 +41,21 @@ fastlz: license-files: ['LICENSE.MIT'] license: MIT +openssl: + source: + type: ghrel + repo: openssl/openssl + match: 'openssl.+\.tar\.gz' + prefer-stable: true + source-mirror: + type: filelist + url: 'https://www.openssl.org/source/' + regex: '/href="(?openssl-(?[^"]+)\.tar\.gz)"/' + binary: hosted + metadata: + license-files: ['LICENSE.txt'] + license: OpenSSL + zlib: source: type: ghrel diff --git a/config/pkg.lib.yaml b/config/pkg.lib.yaml index f38a5512..7c4df000 100644 --- a/config/pkg.lib.yaml +++ b/config/pkg.lib.yaml @@ -28,6 +28,16 @@ fastlz: - fastlz.h artifact: fastlz +openssl: + type: library + static-libs@unix: + - libssl.a + - libcrypto.a + headers: ['openssl'] + depends: + - zlib + artifact: openssl + zlib: type: library static-libs@unix: diff --git a/src/Package/Artifact/openssl.php b/src/Package/Artifact/openssl.php new file mode 100644 index 00000000..8809d9ce --- /dev/null +++ b/src/Package/Artifact/openssl.php @@ -0,0 +1,35 @@ +', + '#include ' . PHP_EOL . '#include ' + ); + } +} diff --git a/src/Package/Library/openssl.php b/src/Package/Library/openssl.php new file mode 100644 index 00000000..e0ee9edc --- /dev/null +++ b/src/Package/Library/openssl.php @@ -0,0 +1,89 @@ +getInstaller()->getLibraryPackage('zlib')->getStaticLibFiles(); + $arch = getenv('SPC_ARCH'); + + shell()->cd($pkg->getSourceDir())->initializeEnv($pkg) + ->exec( + './Configure no-shared zlib ' . + "--prefix={$pkg->getBuildRootPath()} " . + '--libdir=lib ' . + '--openssldir=/etc/ssl ' . + "darwin64-{$arch}-cc" + ) + ->exec('make clean') + ->exec("make -j{$pkg->getBuilder()->concurrency} CNF_EX_LIBS=\"{$zlib_libs}\"") + ->exec('make install_sw'); + $this->patchPkgConfig($pkg); + } + + #[BuildFor('Linux')] + public function build(LibraryPackage $lib): void + { + $arch = getenv('SPC_ARCH'); + + $env = "CC='" . getenv('CC') . ' -idirafter ' . BUILD_INCLUDE_PATH . + ' -idirafter /usr/include/ ' . + ' -idirafter /usr/include/' . getenv('SPC_ARCH') . '-linux-gnu/ ' . + "' "; + + $ex_lib = trim($lib->getInstaller()->getLibraryPackage('zlib')->getStaticLibFiles()) . ' -ldl -pthread'; + $zlib_extra = + '--with-zlib-include=' . BUILD_INCLUDE_PATH . ' ' . + '--with-zlib-lib=' . BUILD_LIB_PATH . ' '; + + $openssl_dir = getenv('OPENSSLDIR') ?: null; + // TODO: in v3 use the following: $openssl_dir ??= SystemUtil::getOSRelease()['dist'] === 'redhat' ? '/etc/pki/tls' : '/etc/ssl'; + $openssl_dir ??= '/etc/ssl'; + $ex_lib = trim($ex_lib); + + shell()->cd($lib->getSourceDir())->initializeEnv($lib) + ->exec( + "{$env} ./Configure no-shared zlib " . + "--prefix={$lib->getBuildRootPath()} " . + "--libdir={$lib->getLibDir()} " . + "--openssldir={$openssl_dir} " . + "{$zlib_extra}" . + 'enable-pie ' . + 'no-legacy ' . + 'no-tests ' . + "linux-{$arch}" + ) + ->exec('make clean') + ->exec("make -j{$lib->getBuilder()->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"") + ->exec('make install_sw'); + $this->patchPkgConfig($lib); + } + + private function patchPkgConfig(LibraryPackage $pkg): void + { + $pkg->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']); + // patch for openssl 3.3.0+ + if (!str_contains($file = FileSystem::readFile("{$pkg->getLibDir()}/pkgconfig/libssl.pc"), 'prefix=')) { + FileSystem::writeFile("{$pkg->getLibDir()}/pkgconfig/libssl.pc", "prefix={$pkg->getBuildRootPath()}\n{$file}"); + } + if (!str_contains($file = FileSystem::readFile("{$pkg->getLibDir()}/pkgconfig/openssl.pc"), 'prefix=')) { + FileSystem::writeFile("{$pkg->getLibDir()}/pkgconfig/openssl.pc", "prefix={$pkg->getBuildRootPath()}\n{$file}"); + } + if (!str_contains($file = FileSystem::readFile("{$pkg->getLibDir()}/pkgconfig/libcrypto.pc"), 'prefix=')) { + FileSystem::writeFile("{$pkg->getLibDir()}/pkgconfig/libcrypto.pc", "prefix={$pkg->getBuildRootPath()}\n{$file}"); + } + FileSystem::replaceFileRegex("{$pkg->getLibDir()}/pkgconfig/libcrypto.pc", '/Libs.private:.*/m', 'Requires.private: zlib'); + FileSystem::replaceFileRegex("{$pkg->getLibDir()}/cmake/OpenSSL/OpenSSLConfig.cmake", '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")'); + } +} diff --git a/src/StaticPHP/Package/LibraryPackage.php b/src/StaticPHP/Package/LibraryPackage.php index 97ec8007..1cdd229e 100644 --- a/src/StaticPHP/Package/LibraryPackage.php +++ b/src/StaticPHP/Package/LibraryPackage.php @@ -7,6 +7,7 @@ namespace StaticPHP\Package; use StaticPHP\Config\PackageConfig; use StaticPHP\Exception\PatchException; use StaticPHP\Util\FileSystem; +use StaticPHP\Util\SPCConfigUtil; /** * Represents a library package with platform-specific build functions. @@ -159,6 +160,16 @@ class LibraryPackage extends Package } } + /** + * Get static library files for current package and its dependencies. + */ + public function getStaticLibFiles(): string + { + $config = new SPCConfigUtil(['libs_only_deps' => true, 'absolute_libs' => true]); + $res = $config->config([$this->getName()]); + return $res['libs']; + } + /** * Get extra LIBS for current package. * You need to define the environment variable in the format of {LIBRARY_NAME}_LIBS diff --git a/src/StaticPHP/Package/Package.php b/src/StaticPHP/Package/Package.php index aa8ab6f0..943d03b0 100644 --- a/src/StaticPHP/Package/Package.php +++ b/src/StaticPHP/Package/Package.php @@ -135,6 +135,22 @@ abstract class Package return isset($this->build_functions[PHP_OS_FAMILY]); } + /** + * Get the PackageBuilder instance for this package. + */ + public function getBuilder(): PackageBuilder + { + return ApplicationContext::get(PackageBuilder::class); + } + + /** + * Get the PackageInstaller instance for this package. + */ + public function getInstaller(): PackageInstaller + { + return ApplicationContext::get(PackageInstaller::class); + } + /** * Get the name of the package. */ diff --git a/src/StaticPHP/Package/PackageInstaller.php b/src/StaticPHP/Package/PackageInstaller.php index ae3b7346..c4262d9a 100644 --- a/src/StaticPHP/Package/PackageInstaller.php +++ b/src/StaticPHP/Package/PackageInstaller.php @@ -402,11 +402,64 @@ class PackageInstaller return SPC_STATUS_INSTALLED; } + /** + * @internal internally calling only, for users, please use specific getter, such as 'getLibraryPackage', 'getTaretPackage', etc + * @param string $package_name Package name + */ public function getPackage(string $package_name): ?Package { return $this->packages[$package_name] ?? null; } + /** + * Get a library package by name. + * + * @param string $package_name Package name + * @return null|LibraryPackage The library package instance or null if not found + */ + public function getLibraryPackage(string $package_name): ?LibraryPackage + { + $pkg = $this->getPackage($package_name); + if ($pkg instanceof LibraryPackage) { + return $pkg; + } + return null; + } + + /** + * Get a target package by name. + * + * @param string $package_name Package name + * @return null|TargetPackage The target package instance or null if not found + */ + public function getTargetPackage(string $package_name): ?TargetPackage + { + $pkg = $this->getPackage($package_name); + if ($pkg instanceof TargetPackage) { + return $pkg; + } + return null; + } + + /** + * Get a PHP extension by name. + * + * @param string $package_or_ext_name Extension name + * @return null|PhpExtensionPackage The target package instance or null if not found + */ + public function getPhpExtensionPackage(string $package_or_ext_name): ?PhpExtensionPackage + { + $pkg = $this->getPackage($package_or_ext_name); + if ($pkg instanceof PhpExtensionPackage) { + return $pkg; + } + $pkg = $this->getPackage("ext-{$package_or_ext_name}"); + if ($pkg instanceof PhpExtensionPackage) { + return $pkg; + } + return null; + } + /** * Validate that a package has required artifacts. */ diff --git a/src/StaticPHP/Util/SPCConfigUtil.php b/src/StaticPHP/Util/SPCConfigUtil.php index c525f8c7..3a20e56f 100644 --- a/src/StaticPHP/Util/SPCConfigUtil.php +++ b/src/StaticPHP/Util/SPCConfigUtil.php @@ -209,18 +209,21 @@ class SPCConfigUtil $frameworks = []; foreach ($packages as $package) { - // add pkg-configs libs - $pkg_configs = PackageConfig::get($package, 'pkg-configs', []); - foreach ($pkg_configs as $pkg_config) { - if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$pkg_config}.pc")) { - throw new WrongUsageException("pkg-config file '{$pkg_config}.pc' for lib [{$package}] does not exist in '" . BUILD_LIB_PATH . "/pkgconfig'. Please build it first."); + // parse pkg-configs only for unix systems + if (SystemTarget::isUnix()) { + // add pkg-configs libs + $pkg_configs = PackageConfig::get($package, 'pkg-configs', []); + foreach ($pkg_configs as $pkg_config) { + if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$pkg_config}.pc")) { + throw new WrongUsageException("pkg-config file '{$pkg_config}.pc' for lib [{$package}] does not exist in '" . BUILD_LIB_PATH . "/pkgconfig'. Please build it first."); + } + } + $pkg_configs = implode(' ', $pkg_configs); + if ($pkg_configs !== '') { + // static libs with dependencies come in reverse order, so reverse this too + $pc_libs = array_reverse(PkgConfigUtil::getLibsArray($pkg_configs)); + $lib_names = [...$lib_names, ...$pc_libs]; } - } - $pkg_configs = implode(' ', $pkg_configs); - if ($pkg_configs !== '') { - // static libs with dependencies come in reverse order, so reverse this too - $pc_libs = array_reverse(PkgConfigUtil::getLibsArray($pkg_configs)); - $lib_names = [...$lib_names, ...$pc_libs]; } // convert all static-libs to short names $libs = array_reverse(PackageConfig::get($package, 'static-libs', []));