From 1865762f80e2d6c7ec13cf690c3d1edc4e34f3b0 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 22 Jan 2026 16:03:01 +0800 Subject: [PATCH 1/5] Fix config yaml support --- src/StaticPHP/Config/ArtifactConfig.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/StaticPHP/Config/ArtifactConfig.php b/src/StaticPHP/Config/ArtifactConfig.php index 49abae926..0ae9e2849 100644 --- a/src/StaticPHP/Config/ArtifactConfig.php +++ b/src/StaticPHP/Config/ArtifactConfig.php @@ -6,6 +6,7 @@ use StaticPHP\Exception\WrongUsageException; use StaticPHP\Registry\Registry; +use Symfony\Component\Yaml\Yaml; class ArtifactConfig { @@ -40,7 +41,11 @@ public static function loadFromFile(string $file, string $registry_name): string if ($content === false) { throw new WrongUsageException("Failed to read artifact config file: {$file}"); } - $data = json_decode($content, true); + $data = match (pathinfo($file, PATHINFO_EXTENSION)) { + 'json' => json_decode($content, true), + 'yml', 'yaml' => Yaml::parse($content), + default => throw new WrongUsageException("Unsupported artifact config file format: {$file}"), + }; if (!is_array($data)) { throw new WrongUsageException("Invalid JSON format in artifact config file: {$file}"); } From ae748757d1a9a420d55141b2cbe471d81c3c3682 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 22 Jan 2026 16:03:06 +0800 Subject: [PATCH 2/5] Fix config yaml support --- src/StaticPHP/Config/PackageConfig.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/StaticPHP/Config/PackageConfig.php b/src/StaticPHP/Config/PackageConfig.php index 56ef7ab1c..92c01f70f 100644 --- a/src/StaticPHP/Config/PackageConfig.php +++ b/src/StaticPHP/Config/PackageConfig.php @@ -7,6 +7,7 @@ use StaticPHP\Exception\WrongUsageException; use StaticPHP\Registry\Registry; use StaticPHP\Runtime\SystemTarget; +use Symfony\Component\Yaml\Yaml; class PackageConfig { @@ -47,10 +48,12 @@ public static function loadFromFile(string $file, string $registry_name): string if ($content === false) { throw new WrongUsageException("Failed to read package config file: {$file}"); } - $data = json_decode($content, true); - if (!is_array($data)) { - throw new WrongUsageException("Invalid JSON format in package config file: {$file}"); - } + // judge extension + $data = match (pathinfo($file, PATHINFO_EXTENSION)) { + 'json' => json_decode($content, true), + 'yml', 'yaml' => Yaml::parse($content), + default => throw new WrongUsageException("Unsupported package config file format: {$file}"), + }; ConfigValidator::validateAndLintPackages(basename($file), $data); foreach ($data as $pkg_name => $config) { self::$package_configs[$pkg_name] = $config; From 7b725bb4da0a605c8c63f0ebac50c58f5d07c21e Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 22 Jan 2026 16:04:48 +0800 Subject: [PATCH 3/5] Add LicenseDumper component --- src/StaticPHP/Command/DumpLicenseCommand.php | 147 +++++++++++ src/StaticPHP/ConsoleApplication.php | 2 + src/StaticPHP/Util/LicenseDumper.php | 262 +++++++++++++++++++ 3 files changed, 411 insertions(+) create mode 100644 src/StaticPHP/Command/DumpLicenseCommand.php create mode 100644 src/StaticPHP/Util/LicenseDumper.php diff --git a/src/StaticPHP/Command/DumpLicenseCommand.php b/src/StaticPHP/Command/DumpLicenseCommand.php new file mode 100644 index 000000000..d90ecbf95 --- /dev/null +++ b/src/StaticPHP/Command/DumpLicenseCommand.php @@ -0,0 +1,147 @@ +addArgument('artifacts', InputArgument::OPTIONAL, 'Specific artifacts to dump licenses, comma separated, e.g "php-src,openssl,curl"'); + + // v2 compatible options + $this->addOption('for-extensions', 'e', InputOption::VALUE_REQUIRED, 'Dump by extensions (automatically includes php-src), e.g "openssl,mbstring"'); + $this->addOption('for-libs', 'l', InputOption::VALUE_REQUIRED, 'Dump by libraries, e.g "openssl,zlib,curl"'); + + // v3 options + $this->addOption('for-packages', 'p', InputOption::VALUE_REQUIRED, 'Dump by packages, e.g "php,libssl,libcurl"'); + $this->addOption('dump-dir', 'd', InputOption::VALUE_REQUIRED, 'Target directory for dumped licenses', BUILD_ROOT_PATH . '/license'); + $this->addOption('without-suggests', null, null, 'Do not include suggested packages when using --for-extensions or --for-packages'); + } + + public function handle(): int + { + $dumper = new LicenseDumper(); + $dump_dir = $this->getOption('dump-dir'); + $artifacts_to_dump = []; + + // Handle direct artifact argument + if ($artifacts = $this->getArgument('artifacts')) { + $artifacts_to_dump = array_merge($artifacts_to_dump, parse_comma_list($artifacts)); + } + + // Handle --for-extensions option + if ($exts = $this->getOption('for-extensions')) { + $artifacts_to_dump = array_merge( + $artifacts_to_dump, + $this->resolveFromExtensions(parse_extension_list($exts)) + ); + } + + // Handle --for-libs option (v2 compat) + if ($libs = $this->getOption('for-libs')) { + $artifacts_to_dump = array_merge( + $artifacts_to_dump, + $this->resolveFromPackages(parse_comma_list($libs)) + ); + } + + // Handle --for-packages option + if ($packages = $this->getOption('for-packages')) { + $artifacts_to_dump = array_merge( + $artifacts_to_dump, + $this->resolveFromPackages(parse_comma_list($packages)) + ); + } + + // Check if any artifacts to dump + if (empty($artifacts_to_dump)) { + $this->output->writeln('No artifacts specified. Use one of:'); + $this->output->writeln(' - Direct argument: dump-license php-src,openssl,curl'); + $this->output->writeln(' - --for-extensions: dump-license --for-extensions=openssl,mbstring'); + $this->output->writeln(' - --for-libs: dump-license --for-libs=openssl,zlib'); + $this->output->writeln(' - --for-packages: dump-license --for-packages=php,libssl'); + return self::FAILURE; + } + + // Deduplicate artifacts + $artifacts_to_dump = array_values(array_unique($artifacts_to_dump)); + + logger()->info('Dumping licenses for ' . count($artifacts_to_dump) . ' artifact(s)'); + logger()->debug('Artifacts: ' . implode(', ', $artifacts_to_dump)); + + // Add artifacts to dumper + $dumper->addArtifacts($artifacts_to_dump); + + // Dump + $success = $dumper->dump($dump_dir); + + if ($success) { + InteractiveTerm::success('Licenses dumped successfully: ' . $dump_dir); + // $this->output->writeln("✓ Successfully dumped licenses to: {$dump_dir}"); + // $this->output->writeln(" Total artifacts: " . count($artifacts_to_dump) . ''); + return self::SUCCESS; + } + + $this->output->writeln('Failed to dump licenses'); + return self::FAILURE; + } + + /** + * Resolve artifacts from extension names. + * + * @param array $extensions Extension names + * @return array Artifact names + */ + private function resolveFromExtensions(array $extensions): array + { + // Convert extension names to package names + $packages = array_map(fn ($ext) => "ext-{$ext}", $extensions); + + // Automatically include php-related artifacts + array_unshift($packages, 'php'); + array_unshift($packages, 'php-micro'); + array_unshift($packages, 'php-embed'); + array_unshift($packages, 'php-fpm'); + + return $this->resolveFromPackages($packages); + } + + /** + * Resolve artifacts from package names. + * + * @param array $packages Package names + * @return array Artifact names + */ + private function resolveFromPackages(array $packages): array + { + $artifacts = []; + $include_suggests = !$this->getOption('without-suggests'); + + // Resolve package dependencies + $resolved_packages = DependencyResolver::resolve($packages, [], $include_suggests); + + foreach ($resolved_packages as $pkg_name) { + try { + $pkg = PackageLoader::getPackage($pkg_name); + if ($artifact = $pkg->getArtifact()) { + $artifacts[] = $artifact->getName(); + } + } catch (\Throwable $e) { + logger()->debug("Package {$pkg_name} has no artifact or failed to load: {$e->getMessage()}"); + } + } + + return array_unique($artifacts); + } +} diff --git a/src/StaticPHP/ConsoleApplication.php b/src/StaticPHP/ConsoleApplication.php index 9e37698c6..bd2e4eb19 100644 --- a/src/StaticPHP/ConsoleApplication.php +++ b/src/StaticPHP/ConsoleApplication.php @@ -12,6 +12,7 @@ use StaticPHP\Command\Dev\SortConfigCommand; use StaticPHP\Command\DoctorCommand; use StaticPHP\Command\DownloadCommand; +use StaticPHP\Command\DumpLicenseCommand; use StaticPHP\Command\ExtractCommand; use StaticPHP\Command\InstallPackageCommand; use StaticPHP\Command\SPCConfigCommand; @@ -55,6 +56,7 @@ public function __construct() new BuildLibsCommand(), new ExtractCommand(), new SPCConfigCommand(), + new DumpLicenseCommand(), // dev commands new ShellCommand(), diff --git a/src/StaticPHP/Util/LicenseDumper.php b/src/StaticPHP/Util/LicenseDumper.php new file mode 100644 index 000000000..57fc3aec4 --- /dev/null +++ b/src/StaticPHP/Util/LicenseDumper.php @@ -0,0 +1,262 @@ + Artifact names to dump */ + private array $artifacts = []; + + /** + * Add artifacts by name. + * + * @param array $artifacts Artifact names + */ + public function addArtifacts(array $artifacts): self + { + $this->artifacts = array_unique(array_merge($this->artifacts, $artifacts)); + return $this; + } + + /** + * Dump all collected artifact licenses to target directory. + * + * @param string $target_dir Target directory path + * @return bool True on success + */ + public function dump(string $target_dir): bool + { + // Create target directory if not exists (don't clean existing files) + if (!is_dir($target_dir)) { + FileSystem::createDir($target_dir); + } else { + logger()->debug("Target directory exists, will append/update licenses: {$target_dir}"); + } + + $license_summary = []; + $dumped_count = 0; + + foreach ($this->artifacts as $artifact_name) { + $artifact = ArtifactLoader::getArtifactInstance($artifact_name); + if ($artifact === null) { + logger()->warning("Artifact not found, skipping: {$artifact_name}"); + continue; + } + + try { + $result = $this->dumpArtifactLicense($artifact, $target_dir, $license_summary); + if ($result) { + ++$dumped_count; + } + } catch (\Throwable $e) { + logger()->warning("Failed to dump license for {$artifact_name}: {$e->getMessage()}"); + } + } + + // Generate LICENSE-SUMMARY.json (read-modify-write) + $this->generateSummary($target_dir, $license_summary); + + logger()->info("Successfully dumped {$dumped_count} license(s) to: {$target_dir}"); + return true; + } + + /** + * Dump license for a single artifact. + * + * @param Artifact $artifact Artifact instance + * @param string $target_dir Target directory + * @param array &$license_summary Summary data to populate + * @return bool True if dumped + * @throws SPCInternalException + */ + private function dumpArtifactLicense(Artifact $artifact, string $target_dir, array &$license_summary): bool + { + $artifact_name = $artifact->getName(); + + // Get metadata from ArtifactConfig + $artifact_config = ArtifactConfig::get($artifact_name); + $config = $artifact_config['metadata'] ?? null; + + if ($config === null) { + logger()->debug("No metadata for artifact: {$artifact_name}"); + return false; + } + + $license_type = $config['license'] ?? null; + $license_files = $config['license-files'] ?? []; + + // Ensure license_files is array + if (is_string($license_files)) { + $license_files = [$license_files]; + } + + if (empty($license_files)) { + logger()->debug("No license files specified for: {$artifact_name}"); + return false; + } + + // Record in summary + $summary_license = $license_type ?? 'Custom'; + if (!isset($license_summary[$summary_license])) { + $license_summary[$summary_license] = []; + } + $license_summary[$summary_license][] = $artifact_name; + + // Dump each license file + $file_count = count($license_files); + $dumped_any = false; + + foreach ($license_files as $index => $license_file_path) { + // Construct output filename + if ($file_count === 1) { + $output_filename = "{$artifact_name}_LICENSE.txt"; + } else { + $output_filename = "{$artifact_name}_LICENSE_{$index}.txt"; + } + + $output_path = "{$target_dir}/{$output_filename}"; + + // Skip if file already exists (avoid duplicate writes) + if (file_exists($output_path)) { + logger()->debug("License file already exists, skipping: {$output_filename}"); + $dumped_any = true; // Still count as dumped + continue; + } + + // Try to read license file from source directory + $license_content = $this->readLicenseFile($artifact, $license_file_path); + if ($license_content === null) { + logger()->warning("License file not found for {$artifact_name}: {$license_file_path}"); + continue; + } + + // Write to target + if (file_put_contents($output_path, $license_content) === false) { + throw new SPCInternalException("Failed to write license file: {$output_path}"); + } + + logger()->info("Dumped license: {$output_filename}"); + $dumped_any = true; + } + + return $dumped_any; + } + + /** + * Read license file content from artifact's source directory. + * + * @param Artifact $artifact Artifact instance + * @param string $license_file_path Relative path to license file + * @return null|string License content, or null if not found + */ + private function readLicenseFile(Artifact $artifact, string $license_file_path): ?string + { + $artifact_name = $artifact->getName(); + + // Try source directory first (if extracted) + if ($artifact->isSourceExtracted()) { + $source_dir = $artifact->getSourceDir(); + $full_path = "{$source_dir}/{$license_file_path}"; + + logger()->debug("Checking license file: {$full_path}"); + if (file_exists($full_path)) { + logger()->info("Reading license from source: {$full_path}"); + return file_get_contents($full_path); + } + } else { + logger()->debug("Artifact source not extracted: {$artifact_name}"); + } + + // Fallback: try SOURCE_PATH directly + $fallback_path = SOURCE_PATH . "/{$artifact_name}/{$license_file_path}"; + logger()->debug("Checking fallback path: {$fallback_path}"); + if (file_exists($fallback_path)) { + logger()->info("Reading license from fallback path: {$fallback_path}"); + return file_get_contents($fallback_path); + } + + logger()->debug("License file not found in any location for {$artifact_name}"); + return null; + } + + /** + * Generate LICENSE-SUMMARY.json file with read-modify-write support. + * + * @param string $target_dir Target directory + * @param array $license_summary License summary data (license_type => [artifacts]) + */ + private function generateSummary(string $target_dir, array $license_summary): void + { + if (empty($license_summary)) { + logger()->debug('No licenses to summarize'); + return; + } + + $summary_file = "{$target_dir}/LICENSE-SUMMARY.json"; + + // Read existing summary if exists + $existing_data = []; + if (file_exists($summary_file)) { + $content = file_get_contents($summary_file); + $existing_data = json_decode($content, true) ?? []; + logger()->debug('Loaded existing LICENSE-SUMMARY.json'); + } + + // Initialize structure + if (!isset($existing_data['artifacts'])) { + $existing_data['artifacts'] = []; + } + if (!isset($existing_data['summary'])) { + $existing_data['summary'] = ['license_types' => []]; + } + + // Merge new license information + foreach ($license_summary as $license_type => $artifacts) { + foreach ($artifacts as $artifact_name) { + // Add/update artifact info + $existing_data['artifacts'][$artifact_name] = [ + 'license' => $license_type, + 'dumped_at' => date('Y-m-d H:i:s'), + ]; + + // Update license_types summary + if (!isset($existing_data['summary']['license_types'][$license_type])) { + $existing_data['summary']['license_types'][$license_type] = []; + } + if (!in_array($artifact_name, $existing_data['summary']['license_types'][$license_type])) { + $existing_data['summary']['license_types'][$license_type][] = $artifact_name; + } + } + } + + // Sort license types and artifacts + ksort($existing_data['summary']['license_types']); + foreach ($existing_data['summary']['license_types'] as &$artifacts) { + sort($artifacts); + } + ksort($existing_data['artifacts']); + + // Update totals + $existing_data['summary']['total_artifacts'] = count($existing_data['artifacts']); + $existing_data['summary']['total_license_types'] = count($existing_data['summary']['license_types']); + $existing_data['summary']['last_updated'] = date('Y-m-d H:i:s'); + + // Write JSON file + file_put_contents( + $summary_file, + json_encode($existing_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) + ); + + logger()->info('Generated LICENSE-SUMMARY.json with ' . $existing_data['summary']['total_artifacts'] . ' artifact(s)'); + } +} From 22fc7030f69a6d42aff0a424c2ad1d5f31c38be5 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 22 Jan 2026 16:05:21 +0800 Subject: [PATCH 4/5] Implement attr, brotli, bzip2 build for unix --- config/artifact.yaml | 33 ++++++++++++++++++++ config/pkg.lib.yaml | 21 +++++++++++++ spc.registry.json | 4 +-- src/Package/Artifact/attr.php | 23 ++++++++++++++ src/Package/Artifact/bzip2.php | 24 +++++++++++++++ src/Package/Library/attr.php | 29 ++++++++++++++++++ src/Package/Library/brotli.php | 55 ++++++++++++++++++++++++++++++++++ src/Package/Library/bzip2.php | 25 ++++++++++++++++ src/globals/licenses/bzip2.txt | 14 +++++++++ 9 files changed, 226 insertions(+), 2 deletions(-) create mode 100644 config/artifact.yaml create mode 100644 config/pkg.lib.yaml create mode 100644 src/Package/Artifact/attr.php create mode 100644 src/Package/Artifact/bzip2.php create mode 100644 src/Package/Library/attr.php create mode 100644 src/Package/Library/brotli.php create mode 100644 src/Package/Library/bzip2.php create mode 100644 src/globals/licenses/bzip2.txt diff --git a/config/artifact.yaml b/config/artifact.yaml new file mode 100644 index 000000000..7ed407363 --- /dev/null +++ b/config/artifact.yaml @@ -0,0 +1,33 @@ +attr: + source: + type: url + url: 'https://download.savannah.nongnu.org/releases/attr/attr-2.5.2.tar.gz' + source-mirror: + type: url + url: 'https://mirror.souseiseki.middlendian.com/nongnu/attr/attr-2.5.2.tar.gz' + metadata: + license-files: ['doc/COPYING.LGPL'] + license: LGPL-2.1-or-later + +brotli: + source: + type: ghtagtar + repo: google/brotli + match: 'v1\.\d.*' + binary: hosted # 等价于v2的provide-pre-built: true + metadata: + license-files: ['LICENSE'] + license: MIT + +bzip2: + source: + type: url + url: 'https://dl.static-php.dev/static-php-cli/deps/bzip2/bzip2-1.0.8.tar.gz' + source-mirror: + type: filelist + url: 'https://sourceware.org/pub/bzip2/' + regex: '/href="(?bzip2-(?[^"]+)\.tar\.gz)"/' + binary: hosted + metadata: + license-files: ['{registry_root}/src/globals/licenses/bzip2.txt'] + license: bzip2-1.0.6 diff --git a/config/pkg.lib.yaml b/config/pkg.lib.yaml new file mode 100644 index 000000000..baf4ebc9d --- /dev/null +++ b/config/pkg.lib.yaml @@ -0,0 +1,21 @@ +attr: + type: library + static-libs@unix: + - libattr.a + artifact: attr +brotli: + type: library + pkg-configs: + - libbrotlicommon + - libbrotlidec + - libbrotlienc + headers: + - brotli + artifact: brotli +bzip2: + type: library + static-libs@unix: + - libbz2.a + headers: + - bzlib.h + artifact: bzip2 diff --git a/spc.registry.json b/spc.registry.json index 7c5a8ce7b..3ced56564 100644 --- a/spc.registry.json +++ b/spc.registry.json @@ -12,13 +12,13 @@ }, "config": [ "config/pkg.ext.json", - "config/pkg.lib.json", + "config/pkg.lib.yaml", "config/pkg.target.json" ] }, "artifact": { "config": [ - "config/artifact.json" + "config/artifact.yaml" ], "psr-4": { "Package\\Artifact": "src/Package/Artifact" diff --git a/src/Package/Artifact/attr.php b/src/Package/Artifact/attr.php new file mode 100644 index 000000000..e80c8c831 --- /dev/null +++ b/src/Package/Artifact/attr.php @@ -0,0 +1,23 @@ +getSourceDir()); + } + } +} diff --git a/src/Package/Artifact/bzip2.php b/src/Package/Artifact/bzip2.php new file mode 100644 index 000000000..a6a1e58e5 --- /dev/null +++ b/src/Package/Artifact/bzip2.php @@ -0,0 +1,24 @@ +getSourceDir() . '/Makefile', + 'CFLAGS=-Wall', + 'CFLAGS=-fPIC -Wall' + ); + } +} diff --git a/src/Package/Library/attr.php b/src/Package/Library/attr.php new file mode 100644 index 000000000..40637e80a --- /dev/null +++ b/src/Package/Library/attr.php @@ -0,0 +1,29 @@ +appendEnv([ + 'CFLAGS' => '-Wno-int-conversion -Wno-implicit-function-declaration', + ]) + ->exec('libtoolize --force --copy') + ->exec('./autogen.sh || autoreconf -if') + ->configure('--disable-nls') + ->make('install-attributes_h install-data install-libattr_h install-libLTLIBRARIES install-pkgincludeHEADERS install-pkgconfDATA', with_install: false); + $lib->patchPkgconfPrefix(['libattr.pc'], PKGCONF_PATCH_PREFIX); + } +} diff --git a/src/Package/Library/brotli.php b/src/Package/Library/brotli.php new file mode 100644 index 000000000..f22b9ef29 --- /dev/null +++ b/src/Package/Library/brotli.php @@ -0,0 +1,55 @@ +setBuildDir($lib->getSourceDir() . '/build-dir') + ->addConfigureArgs("-DSHARE_INSTALL_PREFIX={$lib->getBuildRootPath()}") + ->build(); + + // Patch pkg-config files + $lib->patchPkgconfPrefix(['libbrotlicommon.pc', 'libbrotlidec.pc', 'libbrotlienc.pc'], PKGCONF_PATCH_PREFIX); + + // Add -lbrotlicommon to libbrotlidec.pc and libbrotlienc.pc + FileSystem::replaceFileLineContainsString( + $lib->getLibDir() . '/pkgconfig/libbrotlidec.pc', + 'Libs: -L${libdir} -lbrotlidec', + 'Libs: -L${libdir} -lbrotlidec -lbrotlicommon' + ); + FileSystem::replaceFileLineContainsString( + $lib->getLibDir() . '/pkgconfig/libbrotlienc.pc', + 'Libs: -L${libdir} -lbrotlienc', + 'Libs: -L${libdir} -lbrotlienc -lbrotlicommon' + ); + + // Create symlink: libbrotli.a -> libbrotlicommon.a + shell()->cd($lib->getLibDir())->exec('ln -sf libbrotlicommon.a libbrotli.a'); + + // Remove dynamic libraries + foreach (FileSystem::scanDirFiles($lib->getLibDir(), false, true) as $filename) { + if (str_starts_with($filename, 'libbrotli') && (str_contains($filename, '.so') || str_ends_with($filename, '.dylib'))) { + unlink($lib->getLibDir() . '/' . $filename); + } + } + + // Remove brotli binary if exists + if (file_exists($lib->getBinDir() . '/brotli')) { + unlink($lib->getBinDir() . '/brotli'); + } + } +} diff --git a/src/Package/Library/bzip2.php b/src/Package/Library/bzip2.php new file mode 100644 index 000000000..7f554ab48 --- /dev/null +++ b/src/Package/Library/bzip2.php @@ -0,0 +1,25 @@ +cd($lib->getSourceDir())->initializeEnv($lib) + ->exec("make PREFIX='{$lib->getBuildRootPath()}' clean") + ->exec("make -j{$builder->concurrency} PREFIX='{$lib->getBuildRootPath()}' libbz2.a") + ->exec('cp libbz2.a ' . $lib->getLibDir()) + ->exec('cp bzlib.h ' . $lib->getIncludeDir()); + } +} diff --git a/src/globals/licenses/bzip2.txt b/src/globals/licenses/bzip2.txt new file mode 100644 index 000000000..2f2ed1cd0 --- /dev/null +++ b/src/globals/licenses/bzip2.txt @@ -0,0 +1,14 @@ +This program, "bzip2", the associated library "libbzip2", and all documentation, are copyright (C) 1996-2010 Julian R Seward. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + 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. + 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. + +THIS 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. + +Julian Seward, jseward@bzip.org bzip2/libbzip2 version 1.0.6 of 6 September 2010 + +PATENTS: 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. From c27ed8b0b4990848d4676bb45d48c500ec92bb4b Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 22 Jan 2026 16:50:31 +0800 Subject: [PATCH 5/5] Implement fastlz, zlib (unix) --- config/artifact.yaml | 19 ++++++++++++++++++ config/pkg.lib.yaml | 17 ++++++++++++++++ src/Package/Library/fastlz.php | 36 ++++++++++++++++++++++++++++++++++ src/Package/Library/zlib.php | 24 +++++++++++++++++++++++ src/globals/licenses/zlib.txt | 20 +++++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 src/Package/Library/fastlz.php create mode 100644 src/Package/Library/zlib.php create mode 100644 src/globals/licenses/zlib.txt diff --git a/config/artifact.yaml b/config/artifact.yaml index 7ed407363..cfbb832d0 100644 --- a/config/artifact.yaml +++ b/config/artifact.yaml @@ -31,3 +31,22 @@ bzip2: metadata: license-files: ['{registry_root}/src/globals/licenses/bzip2.txt'] license: bzip2-1.0.6 + +fastlz: + source: + type: git + url: 'https://github.com/ariya/FastLZ.git' + rev: master + metadata: + license-files: ['LICENSE.MIT'] + license: MIT + +zlib: + source: + type: ghrel + repo: madler/zlib + match: 'zlib.+\.tar\.gz' + binary: hosted + metadata: + license-files: ['{registry_root}/src/globals/licenses/zlib.txt'] + license: Zlib-Custom diff --git a/config/pkg.lib.yaml b/config/pkg.lib.yaml index baf4ebc9d..f38a5512d 100644 --- a/config/pkg.lib.yaml +++ b/config/pkg.lib.yaml @@ -19,3 +19,20 @@ bzip2: headers: - bzlib.h artifact: bzip2 + +fastlz: + type: library + static-libs@unix: + - libfastlz.a + headers: + - fastlz.h + artifact: fastlz + +zlib: + type: library + static-libs@unix: + - libz.a + headers: + - zlib.h + - zconf.h + artifact: zlib diff --git a/src/Package/Library/fastlz.php b/src/Package/Library/fastlz.php new file mode 100644 index 000000000..f9dd010dc --- /dev/null +++ b/src/Package/Library/fastlz.php @@ -0,0 +1,36 @@ +cd($lib->getSourceDir())->initializeEnv($lib) + ->exec("{$cc} -c -O3 -fPIC fastlz.c -o fastlz.o") + ->exec("{$ar} rcs libfastlz.a fastlz.o"); + + // Copy header file + if (!copy($lib->getSourceDir() . '/fastlz.h', $lib->getIncludeDir() . '/fastlz.h')) { + throw new BuildFailureException('Failed to copy fastlz.h'); + } + + // Copy static library + if (!copy($lib->getSourceDir() . '/libfastlz.a', $lib->getLibDir() . '/libfastlz.a')) { + throw new BuildFailureException('Failed to copy libfastlz.a'); + } + } +} diff --git a/src/Package/Library/zlib.php b/src/Package/Library/zlib.php new file mode 100644 index 000000000..8706dfe9b --- /dev/null +++ b/src/Package/Library/zlib.php @@ -0,0 +1,24 @@ +exec("./configure --static --prefix={$lib->getBuildRootPath()}")->make(); + + // Patch pkg-config file + $lib->patchPkgconfPrefix(['zlib.pc'], PKGCONF_PATCH_PREFIX); + } +} diff --git a/src/globals/licenses/zlib.txt b/src/globals/licenses/zlib.txt new file mode 100644 index 000000000..b698f3434 --- /dev/null +++ b/src/globals/licenses/zlib.txt @@ -0,0 +1,20 @@ +(C) 1995-2022 Jean-loup Gailly and Mark Adler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. 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. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu