From 455d42d1628f63280be3206d3a48211a83715899 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 13:32:35 +0800 Subject: [PATCH] Separate package config --- README-en.md | 3 - config/artifact.yaml | 67 -------------------- config/pkg.lib.yaml | 48 -------------- config/pkg/lib/attr.yml | 14 ++++ config/pkg/lib/brotli.yml | 17 +++++ config/pkg/lib/bzip2.yml | 18 ++++++ config/pkg/lib/fastlz.yml | 14 ++++ config/pkg/lib/gmp.yml | 19 ++++++ config/pkg/lib/openssl.yml | 22 +++++++ config/pkg/lib/zlib.yml | 16 +++++ spc.registry.json | 7 +- src/Package/Artifact/openssl.php | 4 +- src/Package/Library/gmp.php | 25 ++++++++ src/StaticPHP/Config/ArtifactConfig.php | 15 +++++ src/StaticPHP/Config/ConfigValidator.php | 42 +++++++++++- src/StaticPHP/Config/PackageConfig.php | 31 ++++++++- src/StaticPHP/Doctor/Item/LinuxToolCheck.php | 5 +- src/StaticPHP/Package/Package.php | 17 ++++- src/StaticPHP/Registry/Registry.php | 48 ++++++++------ src/StaticPHP/Util/LicenseDumper.php | 18 ++++-- src/globals/licenses/gmp.txt | 1 + 21 files changed, 294 insertions(+), 157 deletions(-) delete mode 100755 README-en.md delete mode 100644 config/artifact.yaml delete mode 100644 config/pkg.lib.yaml create mode 100644 config/pkg/lib/attr.yml create mode 100644 config/pkg/lib/brotli.yml create mode 100644 config/pkg/lib/bzip2.yml create mode 100644 config/pkg/lib/fastlz.yml create mode 100644 config/pkg/lib/gmp.yml create mode 100644 config/pkg/lib/openssl.yml create mode 100644 config/pkg/lib/zlib.yml create mode 100644 src/Package/Library/gmp.php create mode 100644 src/globals/licenses/gmp.txt diff --git a/README-en.md b/README-en.md deleted file mode 100755 index 505fd70a..00000000 --- a/README-en.md +++ /dev/null @@ -1,3 +0,0 @@ -# static-php-cli - -English README has been moved to [README.md](README.md). diff --git a/config/artifact.yaml b/config/artifact.yaml deleted file mode 100644 index d01d6267..00000000 --- a/config/artifact.yaml +++ /dev/null @@ -1,67 +0,0 @@ -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 - -fastlz: - source: - type: git - url: 'https://github.com/ariya/FastLZ.git' - rev: master - metadata: - 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 - 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 deleted file mode 100644 index 7c4df000..00000000 --- a/config/pkg.lib.yaml +++ /dev/null @@ -1,48 +0,0 @@ -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 - -fastlz: - type: library - static-libs@unix: - - libfastlz.a - headers: - - 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: - - libz.a - headers: - - zlib.h - - zconf.h - artifact: zlib diff --git a/config/pkg/lib/attr.yml b/config/pkg/lib/attr.yml new file mode 100644 index 00000000..4e785851 --- /dev/null +++ b/config/pkg/lib/attr.yml @@ -0,0 +1,14 @@ +attr: + type: library + static-libs@unix: + - libattr.a + artifact: + 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 diff --git a/config/pkg/lib/brotli.yml b/config/pkg/lib/brotli.yml new file mode 100644 index 00000000..342359aa --- /dev/null +++ b/config/pkg/lib/brotli.yml @@ -0,0 +1,17 @@ +brotli: + type: library + pkg-configs: + - libbrotlicommon + - libbrotlidec + - libbrotlienc + headers: + - brotli + artifact: + source: + type: ghtagtar + repo: google/brotli + match: 'v1\.\d.*' + binary: hosted + metadata: + license-files: ['LICENSE'] + license: MIT diff --git a/config/pkg/lib/bzip2.yml b/config/pkg/lib/bzip2.yml new file mode 100644 index 00000000..6f7b483b --- /dev/null +++ b/config/pkg/lib/bzip2.yml @@ -0,0 +1,18 @@ +bzip2: + type: library + static-libs@unix: + - libbz2.a + headers: + - bzlib.h + artifact: + 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 \ No newline at end of file diff --git a/config/pkg/lib/fastlz.yml b/config/pkg/lib/fastlz.yml new file mode 100644 index 00000000..32f26d8a --- /dev/null +++ b/config/pkg/lib/fastlz.yml @@ -0,0 +1,14 @@ +fastlz: + type: library + static-libs@unix: + - libfastlz.a + headers: + - fastlz.h + artifact: + source: + type: git + url: 'https://github.com/ariya/FastLZ.git' + rev: master + metadata: + license-files: ['LICENSE.MIT'] + license: MIT \ No newline at end of file diff --git a/config/pkg/lib/gmp.yml b/config/pkg/lib/gmp.yml new file mode 100644 index 00000000..8a28069b --- /dev/null +++ b/config/pkg/lib/gmp.yml @@ -0,0 +1,19 @@ +gmp: + type: library + static-libs@unix: + - libgmp.a + headers: + - gmp.h + pkg-configs: + - gmp + artifact: + source: + type: filelist + url: 'https://gmplib.org/download/gmp/' + regex: '/href="(?gmp-(?[^"]+)\.tar\.xz)"/' + source-mirror: + type: url + url: 'https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz' + metadata: + license-files: ['@/gmp.txt'] + license: Custom diff --git a/config/pkg/lib/openssl.yml b/config/pkg/lib/openssl.yml new file mode 100644 index 00000000..ce83a4d4 --- /dev/null +++ b/config/pkg/lib/openssl.yml @@ -0,0 +1,22 @@ +openssl: + type: library + static-libs@unix: + - libssl.a + - libcrypto.a + headers: ['openssl'] + depends: + - zlib + artifact: + 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 diff --git a/config/pkg/lib/zlib.yml b/config/pkg/lib/zlib.yml new file mode 100644 index 00000000..0a7eec71 --- /dev/null +++ b/config/pkg/lib/zlib.yml @@ -0,0 +1,16 @@ +zlib: + type: library + static-libs@unix: + - libz.a + headers: + - zlib.h + - zconf.h + artifact: + 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 \ No newline at end of file diff --git a/spc.registry.json b/spc.registry.json index 3ced5656..e8be4b5d 100644 --- a/spc.registry.json +++ b/spc.registry.json @@ -1,5 +1,5 @@ { - "name": "internal", + "name": "core", "autoload": "vendor/autoload.php", "doctor": { "psr-4": { @@ -12,14 +12,11 @@ }, "config": [ "config/pkg.ext.json", - "config/pkg.lib.yaml", + "config/pkg/lib", "config/pkg.target.json" ] }, "artifact": { - "config": [ - "config/artifact.yaml" - ], "psr-4": { "Package\\Artifact": "src/Package/Artifact" } diff --git a/src/Package/Artifact/openssl.php b/src/Package/Artifact/openssl.php index 8809d9ce..325e6a09 100644 --- a/src/Package/Artifact/openssl.php +++ b/src/Package/Artifact/openssl.php @@ -27,9 +27,9 @@ class openssl spc_skip_if(!file_exists("{$target_path}/openssl/test/v3ext.c"), 'v3ext.c not found, skipping patch.'); FileSystem::replaceFileStr( - SOURCE_PATH . '/openssl/test/v3ext.c', + "{$target_path}/openssl/test/v3ext.c", '#include ', - '#include ' . PHP_EOL . '#include ' + "#include \n#include " ); } } diff --git a/src/Package/Library/gmp.php b/src/Package/Library/gmp.php new file mode 100644 index 00000000..f8eb5f8e --- /dev/null +++ b/src/Package/Library/gmp.php @@ -0,0 +1,25 @@ +appendEnv(['CFLAGS' => '-std=c17']) + ->configure('--enable-fat') + ->make(); + $lib->patchPkgconfPrefix(['gmp.pc']); + } +} diff --git a/src/StaticPHP/Config/ArtifactConfig.php b/src/StaticPHP/Config/ArtifactConfig.php index 0ae9e284..49bfec23 100644 --- a/src/StaticPHP/Config/ArtifactConfig.php +++ b/src/StaticPHP/Config/ArtifactConfig.php @@ -77,4 +77,19 @@ class ArtifactConfig { return self::$artifact_configs[$artifact_name] ?? null; } + + /** + * Register an inline artifact configuration. + * Used when artifact is defined inline within a package configuration. + * + * @param string $artifact_name Artifact name (usually same as package name) + * @param array $config Artifact configuration + * @param string $registry_name Registry name + * @param string $source_info Source info for debugging + */ + public static function registerInlineArtifact(string $artifact_name, array $config, string $registry_name, string $source_info = 'inline'): void + { + self::$artifact_configs[$artifact_name] = $config; + Registry::_bindArtifactConfigFile($artifact_name, $registry_name, $source_info); + } } diff --git a/src/StaticPHP/Config/ConfigValidator.php b/src/StaticPHP/Config/ConfigValidator.php index b32f4106..1f3d5b9d 100644 --- a/src/StaticPHP/Config/ConfigValidator.php +++ b/src/StaticPHP/Config/ConfigValidator.php @@ -18,7 +18,7 @@ class ConfigValidator 'type' => ConfigType::STRING, 'depends' => ConfigType::LIST_ARRAY, // @ 'suggests' => ConfigType::LIST_ARRAY, // @ - 'artifact' => ConfigType::STRING, + 'artifact' => [self::class, 'validateArtifactField'], // STRING or OBJECT 'license' => [ConfigType::class, 'validateLicenseField'], 'lang' => ConfigType::STRING, 'frameworks' => ConfigType::LIST_ARRAY, // @ @@ -102,7 +102,14 @@ class ConfigValidator if (!is_array($data)) { throw new ValidationException("{$config_file_name} is broken"); } + + // Define allowed artifact fields + $allowed_artifact_fields = ['source', 'source-mirror', 'binary', 'binary-mirror', 'metadata']; + foreach ($data as $name => $artifact) { + // First pass: validate unknown fields + self::validateNoInvalidFields('artifact', $name, $artifact, $allowed_artifact_fields); + foreach ($artifact as $k => $v) { // check source field if ($k === 'source' || $k === 'source-mirror') { @@ -202,6 +209,11 @@ class ConfigValidator throw new ValidationException("Package [{$name}] in {$config_file_name} of type '{$pkg['type']}' must have an 'artifact' field"); } + // validate and lint inline artifact object if present + if (isset($pkg['artifact']) && is_array($pkg['artifact'])) { + self::validateAndLintInlineArtifact($name, $data[$name]['artifact']); + } + // check if "php-extension" package has php-extension specific fields and validate inside if ($pkg['type'] === 'php-extension') { self::validatePhpExtensionFields($name, $pkg); @@ -234,6 +246,19 @@ class ConfigValidator } } + /** + * Validate artifact field - can be string (reference) or object (inline). + * + * @param mixed $value Field value + */ + public static function validateArtifactField(mixed $value): bool + { + if (!is_string($value) && !is_assoc_array($value)) { + return false; + } + return true; + } + /** * Validate an artifact download object field. * @@ -373,4 +398,19 @@ class ConfigValidator } } } + + /** + * Validate and lint inline artifact object structure. + * + * @param string $pkg_name Package name + * @param array $artifact Inline artifact configuration (passed by reference to apply linting) + */ + private static function validateAndLintInlineArtifact(string $pkg_name, array &$artifact): void + { + // Validate and lint as if it's a standalone artifact + $temp_data = [$pkg_name => $artifact]; + self::validateAndLintArtifacts("inline artifact in package '{$pkg_name}'", $temp_data); + // Write back the linted artifact configuration + $artifact = $temp_data[$pkg_name]; + } } diff --git a/src/StaticPHP/Config/PackageConfig.php b/src/StaticPHP/Config/PackageConfig.php index 92c01f70..bd9786c3 100644 --- a/src/StaticPHP/Config/PackageConfig.php +++ b/src/StaticPHP/Config/PackageConfig.php @@ -23,7 +23,7 @@ class PackageConfig throw new WrongUsageException("Directory {$dir} does not exist, cannot load pkg.json config."); } $loaded = []; - $files = glob("{$dir}/pkg.*.json"); + $files = glob("{$dir}/*"); if (is_array($files)) { foreach ($files as $file) { self::loadFromFile($file, $registry_name); @@ -58,10 +58,39 @@ class PackageConfig foreach ($data as $pkg_name => $config) { self::$package_configs[$pkg_name] = $config; Registry::_bindPackageConfigFile($pkg_name, $registry_name, $file); + + // Register inline artifact if present + if (isset($config['artifact']) && is_array($config['artifact'])) { + ArtifactConfig::registerInlineArtifact( + $pkg_name, + $config['artifact'], + $registry_name, + "inline in {$file}" + ); + } } return $file; } + public static function loadFromArray(array $data, string $registry_name): void + { + ConfigValidator::validateAndLintPackages('array_input', $data); + foreach ($data as $pkg_name => $config) { + self::$package_configs[$pkg_name] = $config; + Registry::_bindPackageConfigFile($pkg_name, $registry_name, 'array_input'); + + // Register inline artifact if present + if (isset($config['artifact']) && is_array($config['artifact'])) { + ArtifactConfig::registerInlineArtifact( + $pkg_name, + $config['artifact'], + $registry_name, + 'inline in array_input' + ); + } + } + } + /** * Check if a package configuration exists. */ diff --git a/src/StaticPHP/Doctor/Item/LinuxToolCheck.php b/src/StaticPHP/Doctor/Item/LinuxToolCheck.php index 09161c74..f4cdc311 100644 --- a/src/StaticPHP/Doctor/Item/LinuxToolCheck.php +++ b/src/StaticPHP/Doctor/Item/LinuxToolCheck.php @@ -19,7 +19,6 @@ class LinuxToolCheck 'bzip2', 'cmake', 'gcc', 'g++', 'patch', 'binutils-gold', 'libtoolize', 'which', - 'patchelf', ]; public const TOOLS_DEBIAN = [ @@ -28,7 +27,6 @@ class LinuxToolCheck 'tar', 'unzip', 'gzip', 'gcc', 'g++', 'bzip2', 'cmake', 'patch', 'xz', 'libtoolize', 'which', - 'patchelf', ]; public const TOOLS_RHEL = [ @@ -36,8 +34,7 @@ class LinuxToolCheck 'git', 'autoconf', 'automake', 'tar', 'unzip', 'gzip', 'gcc', 'g++', 'bzip2', 'cmake', 'patch', 'which', - 'xz', 'libtool', 'gettext-devel', - 'patchelf', 'file', + 'xz', 'libtool', 'gettext-devel', 'file', ]; public const TOOLS_ARCH = [ diff --git a/src/StaticPHP/Package/Package.php b/src/StaticPHP/Package/Package.php index 943d03b0..a0f415d1 100644 --- a/src/StaticPHP/Package/Package.php +++ b/src/StaticPHP/Package/Package.php @@ -175,8 +175,21 @@ abstract class Package public function getArtifact(): ?Artifact { // find config - $artifact_name = PackageConfig::get($this->name, 'artifact'); - return $artifact_name !== null ? ArtifactLoader::getArtifactInstance($artifact_name) : null; + $artifact_field = PackageConfig::get($this->name, 'artifact'); + + if ($artifact_field === null) { + return null; + } + + if (is_string($artifact_field)) { + return ArtifactLoader::getArtifactInstance($artifact_field); + } + + if (is_array($artifact_field)) { + return ArtifactLoader::getArtifactInstance($this->name); + } + + return null; } /** diff --git a/src/StaticPHP/Registry/Registry.php b/src/StaticPHP/Registry/Registry.php index e464ed47..68aa766d 100644 --- a/src/StaticPHP/Registry/Registry.php +++ b/src/StaticPHP/Registry/Registry.php @@ -13,6 +13,8 @@ use Symfony\Component\Yaml\Yaml; class Registry { + private static ?string $current_registry_name = null; + /** @var string[] List of loaded registries */ private static array $loaded_registries = []; @@ -35,7 +37,7 @@ class Registry public static function getRegistryConfig(?string $registry_name = null): array { if ($registry_name === null && spc_mode(SPC_MODE_SOURCE)) { - return self::$registry_configs['internal']; + return self::$registry_configs['core']; } if ($registry_name !== null && isset(self::$registry_configs[$registry_name])) { return self::$registry_configs[$registry_name]; @@ -83,6 +85,8 @@ class Registry logger()->debug("Loading registry '{$registry_name}' from file: {$registry_file}"); + self::$current_registry_name = $registry_name; + // Load composer autoload if specified (for external registries with their own dependencies) if (isset($data['autoload']) && is_string($data['autoload'])) { $autoload_path = FileSystem::fullpath($data['autoload'], dirname($registry_file)); @@ -94,24 +98,6 @@ class Registry } } - // load doctor items from PSR-4 directories - if (isset($data['doctor']['psr-4']) && is_assoc_array($data['doctor']['psr-4'])) { - foreach ($data['doctor']['psr-4'] as $namespace => $path) { - $path = FileSystem::fullpath($path, dirname($registry_file)); - DoctorLoader::loadFromPsr4Dir($path, $namespace, $auto_require); - } - } - - // load doctor items from specific classes - // Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"} - if (isset($data['doctor']['classes']) && is_array($data['doctor']['classes'])) { - foreach ($data['doctor']['classes'] as $key => $value) { - [$class, $file] = self::parseClassEntry($key, $value); - self::requireClassFile($class, $file, dirname($registry_file), $auto_require); - DoctorLoader::loadFromClass($class); - } - } - // load package configs if (isset($data['package']['config']) && is_array($data['package']['config'])) { foreach ($data['package']['config'] as $path) { @@ -136,6 +122,24 @@ class Registry } } + // load doctor items from PSR-4 directories + if (isset($data['doctor']['psr-4']) && is_assoc_array($data['doctor']['psr-4'])) { + foreach ($data['doctor']['psr-4'] as $namespace => $path) { + $path = FileSystem::fullpath($path, dirname($registry_file)); + DoctorLoader::loadFromPsr4Dir($path, $namespace, $auto_require); + } + } + + // load doctor items from specific classes + // Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"} + if (isset($data['doctor']['classes']) && is_array($data['doctor']['classes'])) { + foreach ($data['doctor']['classes'] as $key => $value) { + [$class, $file] = self::parseClassEntry($key, $value); + self::requireClassFile($class, $file, dirname($registry_file), $auto_require); + DoctorLoader::loadFromClass($class); + } + } + // load packages from PSR-4 directories if (isset($data['package']['psr-4']) && is_assoc_array($data['package']['psr-4'])) { foreach ($data['package']['psr-4'] as $namespace => $path) { @@ -193,6 +197,7 @@ class Registry } ConsoleApplication::_addAdditionalCommands($instances); } + self::$current_registry_name = null; } /** @@ -300,6 +305,11 @@ class Registry return self::$loaded_artifact_configs; } + public static function getCurrentRegistryName(): ?string + { + return self::$current_registry_name; + } + /** * Parse a class entry from the classes array. * Supports two formats: diff --git a/src/StaticPHP/Util/LicenseDumper.php b/src/StaticPHP/Util/LicenseDumper.php index 57fc3aec..54c6266b 100644 --- a/src/StaticPHP/Util/LicenseDumper.php +++ b/src/StaticPHP/Util/LicenseDumper.php @@ -163,18 +163,26 @@ class LicenseDumper { $artifact_name = $artifact->getName(); - // Try source directory first (if extracted) - if ($artifact->isSourceExtracted()) { - $source_dir = $artifact->getSourceDir(); - $full_path = "{$source_dir}/{$license_file_path}"; + // replace + if (str_starts_with($license_file_path, '@/')) { + $license_file_path = str_replace('@/', ROOT_DIR . '/src/globals/licenses/', $license_file_path); + } + $source_dir = $artifact->getSourceDir(); + if (FileSystem::isRelativePath($license_file_path)) { + $full_path = "{$source_dir}/{$license_file_path}"; + } else { + $full_path = $license_file_path; + } + // Try source directory first (if extracted) + if ($artifact->isSourceExtracted() || file_exists($full_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}"); + logger()->warning("Artifact source not extracted: {$artifact_name}"); } // Fallback: try SOURCE_PATH directly diff --git a/src/globals/licenses/gmp.txt b/src/globals/licenses/gmp.txt new file mode 100644 index 00000000..488f3b90 --- /dev/null +++ b/src/globals/licenses/gmp.txt @@ -0,0 +1 @@ +Since version 6, GMP is distributed under the dual licenses, GNU LGPL v3 and GNU GPL v2. These licenses make the library free to use, share, and improve, and allow you to pass on the result. The GNU licenses give freedoms, but also set firm restrictions on the use with non-free programs.