execWithResult($cmd); if ($result[0] !== 0) { throw new ExecutionException($cmd, 'Failed to get defined symbols from ' . $lib_file); } // parse shell output and filter $defined = []; foreach ($result[1] as $line) { $line = trim($line); if ($line === '' || str_ends_with($line, '.o:') || str_ends_with($line, '.o]:')) { continue; } $name = strtok($line, " \t"); if (!$name) { continue; } $name = preg_replace('/@.*$/', '', $name); if ($name !== '' && $name !== false) { $defined[] = $name; } } $defined = array_unique($defined); sort($defined); // export if (SPCTarget::getTargetOS() === 'Linux') { file_put_contents("{$lib_file}.dynsym", "{\n" . implode("\n", array_map(fn ($x) => " {$x};", $defined)) . "};\n"); } else { file_put_contents("{$lib_file}.dynsym", implode("\n", $defined) . "\n"); } } /** * Get linker flag to export dynamic symbols from a static library. * * @param string $lib_file Static library file path (e.g. /path/to/libxxx.a) * @return null|string Linker flag to export dynamic symbols, null if no .dynsym file found */ public static function getDynamicExportedSymbols(string $lib_file): ?string { $symbol_file = "{$lib_file}.dynsym"; if (!is_file($symbol_file)) { return null; } // https://github.com/ziglang/zig/issues/24662 if (ToolchainManager::getToolchainClass() === ZigToolchain::class) { return '-Wl,--export-dynamic'; } // macOS if (SPCTarget::getTargetOS() !== 'Linux') { return "-Wl,-exported_symbols_list,{$symbol_file}"; } return "-Wl,--dynamic-list={$symbol_file}"; } /** * Find a command in given paths or system PATH. * If $name is an absolute path, check if it exists. * * @param string $name Command name or absolute path * @param array $paths Paths to search, if empty, use system PATH * @return null|string Absolute path of the command if found, null otherwise */ public static function findCommand(string $name, array $paths = []): ?string { if (!$paths) { $paths = explode(PATH_SEPARATOR, getenv('PATH')); } if (str_starts_with($name, '/')) { return file_exists($name) ? $name : null; } foreach ($paths as $path) { if (file_exists($path . DIRECTORY_SEPARATOR . $name)) { return $path . DIRECTORY_SEPARATOR . $name; } } return null; } /** * Make environment variable string for shell command. * * @param array $vars Variables, like: ["CFLAGS" => "-Ixxx"] * @return string like: CFLAGS="-Ixxx" */ public static function makeEnvVarString(array $vars): string { $str = ''; foreach ($vars as $key => $value) { if ($str !== '') { $str .= ' '; } $str .= $key . '=' . escapeshellarg($value); } return $str; } }