Skip to content

Commit 7402fbf

Browse files
authored
Use cmake to build librdkafka, add helper function for SPCConfigUtil (#955)
2 parents ae15d6c + 2c590e5 commit 7402fbf

File tree

11 files changed

+136
-90
lines changed

11 files changed

+136
-90
lines changed

config/lib.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -506,13 +506,16 @@
506506
},
507507
"librdkafka": {
508508
"source": "librdkafka",
509-
"static-libs-unix": [
510-
"librdkafka.a",
511-
"librdkafka++.a",
512-
"librdkafka-static.a"
509+
"pkg-configs": [
510+
"rdkafka++-static",
511+
"rdkafka-static"
513512
],
514513
"cpp-library": true,
515514
"lib-suggests": [
515+
"curl",
516+
"liblz4",
517+
"openssl",
518+
"zlib",
516519
"zstd"
517520
]
518521
},

src/SPC/builder/Extension.php

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ public function patchBeforeSharedConfigure(): bool
220220
*/
221221
public function patchBeforeSharedMake(): bool
222222
{
223-
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()], array_map(fn ($l) => $l->getName(), $this->builder->getLibs()));
223+
$config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this);
224224
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
225225
$lstdcpp = str_contains($sharedLibs, '-l:libstdc++.a') ? '-l:libstdc++.a' : null;
226226
$lstdcpp ??= str_contains($sharedLibs, '-lstdc++') ? '-lstdc++' : '';
@@ -486,18 +486,46 @@ public function isBuildStatic(): bool
486486
return $this->build_static;
487487
}
488488

489+
/**
490+
* Get the library dependencies that current extension depends on.
491+
*
492+
* @param bool $recursive Whether it includes dependencies recursively
493+
*/
494+
public function getLibraryDependencies(bool $recursive = false): array
495+
{
496+
$ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase);
497+
if (!$recursive) {
498+
return $ret;
499+
}
500+
501+
$deps = [];
502+
503+
$added = 1;
504+
while ($added !== 0) {
505+
$added = 0;
506+
foreach ($ret as $depName => $dep) {
507+
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
508+
if (!array_key_exists($depdepName, $deps)) {
509+
$deps[$depdepName] = $depdep;
510+
++$added;
511+
}
512+
}
513+
if (!array_key_exists($depName, $deps)) {
514+
$deps[$depName] = $dep;
515+
}
516+
}
517+
}
518+
519+
return $deps;
520+
}
521+
489522
/**
490523
* Returns the environment variables a shared extension needs to be built.
491524
* CFLAGS, CXXFLAGS, LDFLAGS and so on.
492525
*/
493526
protected function getSharedExtensionEnv(): array
494527
{
495-
$config = (new SPCConfigUtil($this->builder))->config(
496-
[$this->getName()],
497-
array_map(fn ($l) => $l->getName(), $this->getLibraryDependencies(recursive: true)),
498-
$this->builder->getOption('with-suggested-exts'),
499-
$this->builder->getOption('with-suggested-libs'),
500-
);
528+
$config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this);
501529
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
502530
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
503531
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
@@ -519,7 +547,7 @@ protected function addLibraryDependency(string $name, bool $optional = false): v
519547
}
520548
logger()->info("enabling {$this->name} without library {$name}");
521549
} else {
522-
$this->dependencies[] = $depLib;
550+
$this->dependencies[$name] = $depLib;
523551
}
524552
}
525553

@@ -532,7 +560,7 @@ protected function addExtensionDependency(string $name, bool $optional = false):
532560
}
533561
logger()->info("enabling {$this->name} without extension {$name}");
534562
} else {
535-
$this->dependencies[] = $depExt;
563+
$this->dependencies[$name] = $depExt;
536564
}
537565
}
538566

@@ -567,37 +595,4 @@ protected function splitLibsIntoStaticAndShared(string $allLibs): array
567595
}
568596
return [trim($staticLibString), trim($sharedLibString)];
569597
}
570-
571-
private function getLibraryDependencies(bool $recursive = false): array
572-
{
573-
$ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase);
574-
if (!$recursive) {
575-
return $ret;
576-
}
577-
578-
$deps = [];
579-
580-
$added = 1;
581-
while ($added !== 0) {
582-
$added = 0;
583-
foreach ($ret as $depName => $dep) {
584-
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
585-
if (!array_key_exists($depdepName, $deps)) {
586-
$deps[$depdepName] = $depdep;
587-
++$added;
588-
}
589-
}
590-
if (!array_key_exists($depName, $deps)) {
591-
$deps[$depName] = $dep;
592-
}
593-
}
594-
}
595-
596-
if (array_key_exists(0, $deps)) {
597-
$zero = [0 => $deps[0]];
598-
unset($deps[0]);
599-
return $zero + $deps;
600-
}
601-
return $deps;
602-
}
603598
}

src/SPC/builder/extension/grpc.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public function patchBeforeBuildconf(): bool
4343
public function patchBeforeConfigure(): bool
4444
{
4545
$util = new SPCConfigUtil($this->builder, ['libs_only_deps' => true]);
46-
$config = $util->config(['grpc']);
46+
$config = $util->getExtensionConfig($this);
4747
$libs = $config['libs'];
4848
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/configure', '-lgrpc', $libs);
4949
return true;

src/SPC/builder/extension/rdkafka.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use SPC\builder\Extension;
88
use SPC\store\FileSystem;
99
use SPC\util\CustomExt;
10+
use SPC\util\SPCConfigUtil;
1011

1112
#[CustomExt('rdkafka')]
1213
class rdkafka extends Extension
@@ -15,6 +16,7 @@ public function patchBeforeBuildconf(): bool
1516
{
1617
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\n", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm \$RDKAFKA_LIBS\n");
1718
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\"\n", '-L$RDKAFKA_DIR/$PHP_LIBDIR -lm $RDKAFKA_LIBS"');
19+
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", 'PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,', 'AC_CHECK_LIB([$LIBNAME], [$LIBSYMBOL],');
1820
return true;
1921
}
2022

@@ -37,8 +39,7 @@ public function patchBeforeMake(): bool
3739

3840
public function getUnixConfigureArg(bool $shared = false): string
3941
{
40-
$pkgconf_libs = shell()->execWithResult('pkg-config --libs --static rdkafka')[1];
41-
$pkgconf_libs = trim(implode('', $pkgconf_libs));
42-
return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . ' RDKAFKA_LIBS="' . $pkgconf_libs . '"';
42+
$pkgconf_libs = (new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]))->getExtensionConfig($this);
43+
return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . " RDKAFKA_LIBS=\"{$pkgconf_libs['libs']}\"";
4344
}
4445
}

src/SPC/builder/extension/swoole.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function getUnixConfigureArg(bool $shared = false): string
7070
$arg .= $this->builder->getExt('swoole-hook-mysql') ? ' --enable-mysqlnd' : ' --disable-mysqlnd';
7171
$arg .= $this->builder->getExt('swoole-hook-sqlite') ? ' --enable-swoole-sqlite' : ' --disable-swoole-sqlite';
7272
if ($this->builder->getExt('swoole-hook-odbc')) {
73-
$config = (new SPCConfigUtil($this->builder, ['libs_only_deps' => true]))->config([], ['unixodbc']);
73+
$config = (new SPCConfigUtil($this->builder))->getLibraryConfig($this->builder->getLib('unixodbc'));
7474
$arg .= ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH . ' SWOOLE_ODBC_LIBS="' . $config['libs'] . '"';
7575
}
7676

src/SPC/builder/unix/UnixBuilderBase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ protected function buildFrankenphp(): void
301301
}
302302

303303
$config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list);
304-
$cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS');
304+
$cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -DFRANKENPHP_VERSION=' . $frankenPhpVersion;
305305
$libs = $config['libs'];
306306
// Go's gcc driver doesn't automatically link against -lgcov or -lrt. Ugly, but necessary fix.
307307
if ((str_contains((string) getenv('SPC_DEFAULT_C_FLAGS'), '-fprofile') ||

src/SPC/builder/unix/library/librdkafka.php

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace SPC\builder\unix\library;
66

77
use SPC\store\FileSystem;
8-
use SPC\util\executor\UnixAutoconfExecutor;
8+
use SPC\util\executor\UnixCMakeExecutor;
99

1010
trait librdkafka
1111
{
@@ -26,34 +26,18 @@ public function patchBeforeBuild(): bool
2626

2727
protected function build(): void
2828
{
29-
UnixAutoconfExecutor::create($this)
30-
->appendEnv(['CFLAGS' => '-Wno-int-conversion -Wno-unused-but-set-variable -Wno-unused-variable'])
31-
->optionalLib(
32-
'zstd',
33-
function ($lib) {
34-
putenv("STATIC_LIB_libzstd={$lib->getLibDir()}/libzstd.a");
35-
return '';
36-
},
37-
'--disable-zstd'
29+
UnixCMakeExecutor::create($this)
30+
->optionalLib('zstd', ...cmake_boolean_args('WITH_ZSTD'))
31+
->optionalLib('curl', ...cmake_boolean_args('WITH_CURL'))
32+
->optionalLib('openssl', ...cmake_boolean_args('WITH_SSL'))
33+
->optionalLib('zlib', ...cmake_boolean_args('WITH_ZLIB'))
34+
->optionalLib('liblz4', ...cmake_boolean_args('ENABLE_LZ4_EXT'))
35+
->addConfigureArgs(
36+
'-DWITH_SASL=OFF',
37+
'-DRDKAFKA_BUILD_STATIC=ON',
38+
'-DRDKAFKA_BUILD_EXAMPLES=OFF',
39+
'-DRDKAFKA_BUILD_TESTS=OFF',
3840
)
39-
->removeConfigureArgs(
40-
'--with-pic',
41-
'--enable-pic',
42-
)
43-
->configure(
44-
'--disable-curl',
45-
'--disable-sasl',
46-
'--disable-valgrind',
47-
'--disable-zlib',
48-
'--disable-ssl',
49-
)
50-
->make();
51-
52-
$this->patchPkgconfPrefix(['rdkafka.pc', 'rdkafka-static.pc', 'rdkafka++.pc', 'rdkafka++-static.pc']);
53-
// remove dynamic libs
54-
shell()
55-
->exec("rm -rf {$this->getLibDir()}/*.so.*")
56-
->exec("rm -rf {$this->getLibDir()}/*.so")
57-
->exec("rm -rf {$this->getLibDir()}/*.dylib");
41+
->build();
5842
}
5943
}

src/SPC/builder/unix/library/postgresql.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protected function build(): void
4747
{
4848
$libs = array_map(fn ($x) => $x->getName(), $this->getDependencies(true));
4949
$spc = new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]);
50-
$config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs'));
50+
$config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs', false));
5151

5252
$env_vars = [
5353
'CFLAGS' => $config['cflags'],

src/SPC/exception/ExceptionHandler.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ public static function handleSPCException(SPCException $e): void
159159
public static function handleDefaultException(\Throwable $e): void
160160
{
161161
$class = get_class($e);
162-
self::logError("✗ Unhandled exception {$class}:\n\t{$e->getMessage()}\n");
162+
$file = $e->getFile();
163+
$line = $e->getLine();
164+
self::logError("✗ Unhandled exception {$class} on {$file} line {$line}:\n\t{$e->getMessage()}\n");
163165
self::logError('Stack trace:');
164166
self::logError(ConsoleColor::gray($e->getTraceAsString()) . PHP_EOL, 4);
165167
self::logError('⚠ Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues');

src/SPC/util/SPCConfigUtil.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use SPC\builder\BuilderBase;
88
use SPC\builder\BuilderProvider;
99
use SPC\builder\Extension;
10+
use SPC\builder\LibraryBase;
1011
use SPC\exception\WrongUsageException;
1112
use SPC\store\Config;
1213
use Symfony\Component\Console\Input\ArgvInput;
@@ -53,6 +54,9 @@ public function __construct(?BuilderBase $builder = null, array $options = [])
5354
*/
5455
public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
5556
{
57+
logger()->debug('config extensions: ' . implode(',', $extensions));
58+
logger()->debug('config libs: ' . implode(',', $libraries));
59+
logger()->debug('config suggest for [ext, lib]: ' . ($include_suggest_ext ? 'true' : 'false') . ',' . ($include_suggest_lib ? 'true' : 'false'));
5660
$extra_exts = [];
5761
foreach ($extensions as $ext) {
5862
$extra_exts = array_merge($extra_exts, Config::getExt($ext, 'ext-suggests', []));
@@ -124,6 +128,63 @@ public function config(array $extensions = [], array $libraries = [], bool $incl
124128
];
125129
}
126130

131+
/**
132+
* [Helper function]
133+
* Get configuration for a specific extension(s) dependencies.
134+
*
135+
* @param Extension|Extension[] $extension Extension instance or list
136+
* @param bool $include_suggest_ext Whether to include suggested extensions
137+
* @param bool $include_suggest_lib Whether to include suggested libraries
138+
* @return array{
139+
* cflags: string,
140+
* ldflags: string,
141+
* libs: string
142+
* }
143+
*/
144+
public function getExtensionConfig(array|Extension $extension, bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
145+
{
146+
if (!is_array($extension)) {
147+
$extension = [$extension];
148+
}
149+
$libs = array_map(fn ($y) => $y->getName(), array_merge(...array_map(fn ($x) => $x->getLibraryDependencies(true), $extension)));
150+
return $this->config(
151+
extensions: array_map(fn ($x) => $x->getName(), $extension),
152+
libraries: $libs,
153+
include_suggest_ext: $include_suggest_ext ?: $this->builder?->getOption('with-suggested-exts') ?? false,
154+
include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false,
155+
);
156+
}
157+
158+
/**
159+
* [Helper function]
160+
* Get configuration for a specific library(s) dependencies.
161+
*
162+
* @param LibraryBase|LibraryBase[] $lib Library instance or list
163+
* @param bool $include_suggest_lib Whether to include suggested libraries
164+
* @return array{
165+
* cflags: string,
166+
* ldflags: string,
167+
* libs: string
168+
* }
169+
*/
170+
public function getLibraryConfig(array|LibraryBase $lib, bool $include_suggest_lib = false): array
171+
{
172+
if (!is_array($lib)) {
173+
$lib = [$lib];
174+
}
175+
$save_no_php = $this->no_php;
176+
$this->no_php = true;
177+
$save_libs_only_deps = $this->libs_only_deps;
178+
$this->libs_only_deps = true;
179+
$ret = $this->config(
180+
libraries: array_map(fn ($x) => $x->getName(), $lib),
181+
include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false,
182+
);
183+
$this->no_php = $save_no_php;
184+
$this->libs_only_deps = $save_libs_only_deps;
185+
return $ret;
186+
}
187+
127188
private function hasCpp(array $extensions, array $libraries): bool
128189
{
129190
// judge cpp-extension

0 commit comments

Comments
 (0)