Skip to content

Commit 348a62d

Browse files
committed
Switch to using ldd to get the real full path of system libraries
1 parent 8ac0dbc commit 348a62d

File tree

2 files changed

+25
-46
lines changed

2 files changed

+25
-46
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ docker run --rm -it --entrypoint=bash bref/php-80
101101
>
102102
> `ldd` is a linux utility that will show libraries (`.so` files) used by a binary/library. For example: `ldd /opt/bin/php` or `ldd /opt/bref/extensions/curl.so`. That helps to make sure we include all the libraries needed by PHP extensions in the layers.
103103
>
104-
> However, `ldd` fails when running on another CPU architecture. So instead of `ldd`, we can use `objdump -p /usr/bin/bash | grep NEEDED` (that needs to be installed with `yum install binutils`).
104+
> However, `ldd` fails when running on another CPU architecture. So instead of `ldd`, we can use `LD_TRACE_LOADED_OBJECTS=1 /opt/bin/php` (see https://stackoverflow.com/a/35905007/245552).
105105
106106
### Supporting a new PHP version
107107

utils/lib-copy/copy-dependencies.php

+24-45
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,6 @@
2222
}
2323
[$_, $pathToCheck, $targetDirectory] = $argv;
2424

25-
// All the paths where shared libraries can be found
26-
const LIB_PATHS = [
27-
// System libraries
28-
'/lib64',
29-
'/usr/lib64',
30-
// Libraries we compiled from source are installed here
31-
'/tmp/bref/lib',
32-
'/tmp/bref/lib64',
33-
];
34-
3525
$arch = 'x86';
3626
if (php_uname('m') !== 'x86_64') {
3727
$arch = 'arm';
@@ -44,10 +34,12 @@
4434
return ! str_contains($library, 'libgcrypt.so') && ! str_contains($library, 'libgpg-error.so');
4535
});
4636

47-
$requiredLibraries = listAllDependenciesRecursively($pathToCheck);
37+
$requiredLibraries = listDependencies($pathToCheck);
4838
// Exclude existing system libraries
4939
$requiredLibraries = array_filter($requiredLibraries, function (string $lib) use ($librariesThatExistOnLambda) {
50-
$keep = ! in_array(basename($lib), $librariesThatExistOnLambda, true);
40+
$isALibraryWeCompiled = str_starts_with($lib, '/tmp/bref/lib');
41+
$doesNotExistInLambda = !in_array(basename($lib), $librariesThatExistOnLambda, true);
42+
$keep = $isALibraryWeCompiled || $doesNotExistInLambda;
5143
if (! $keep) {
5244
echo "Skipping $lib because it's already in Lambda" . PHP_EOL;
5345
}
@@ -58,46 +50,33 @@
5850
foreach ($requiredLibraries as $libraryPath) {
5951
$targetPath = $targetDirectory . '/' . basename($libraryPath);
6052
echo "Copying $libraryPath to $targetPath" . PHP_EOL;
61-
copy($libraryPath, $targetPath);
53+
$success = copy($libraryPath, $targetPath);
54+
if (! $success) {
55+
throw new RuntimeException("Could not copy $libraryPath to $targetPath");
56+
}
6257
}
6358

6459

6560
function listDependencies(string $path): array
6661
{
67-
static $cache = [];
68-
if (!isset($cache[$path])) {
69-
echo $path . PHP_EOL;
70-
$asString = shell_exec("objdump -p '$path' | grep NEEDED | awk '{ print $2 }'");
71-
if (!$asString) {
72-
$dependencies = [];
73-
} else {
74-
$dependencies = array_filter(explode(PHP_EOL, $asString));
62+
// ldd lists the dependencies of a binary or library/extension (.so file)
63+
exec("ldd $path 2>&1", $lines);
64+
if (str_contains(end($lines), 'exited with unknown exit code (139)')) {
65+
// We can't use `ldd` on binaries (like /opt/bin/php) because it fails on cross-platform builds
66+
// so we fall back to `LD_TRACE_LOADED_OBJECTS` (which doesn't work for .so files, that's why we also try `ldd`)
67+
// See https://stackoverflow.com/a/35905007/245552
68+
$output = shell_exec("LD_TRACE_LOADED_OBJECTS=1 $path 2>&1");
69+
if (!$output) {
70+
throw new RuntimeException("Could not list dependencies for $path");
7571
}
76-
$cache[$path] = array_map(fn(string $dependency) => findFullPath($dependency), $dependencies);
77-
}
78-
return $cache[$path];
79-
}
80-
81-
function findFullPath(string $lib): string {
82-
static $cache = [];
83-
if (isset($cache[$lib])) {
84-
return $cache[$lib];
72+
$lines = explode(PHP_EOL, $output);
8573
}
86-
foreach (LIB_PATHS as $libPath) {
87-
if (file_exists("$libPath/$lib")) {
88-
$cache[$lib] = "$libPath/$lib";
89-
return "$libPath/$lib";
74+
$dependencies = [];
75+
foreach ($lines as $line) {
76+
$matches = [];
77+
if (preg_match('/=> (.*) \(0x[0-9a-f]+\)/', $line, $matches)) {
78+
$dependencies[] = $matches[1];
9079
}
9180
}
92-
throw new RuntimeException("Dependency '$lib' not found");
93-
}
94-
95-
function listAllDependenciesRecursively(string $path): array
96-
{
97-
$dependencies = listDependencies($path);
98-
$allDependencies = [];
99-
foreach ($dependencies as $dependency) {
100-
$allDependencies = array_merge($allDependencies, listAllDependenciesRecursively($dependency));
101-
}
102-
return array_unique(array_merge($dependencies, $allDependencies));
81+
return $dependencies;
10382
}

0 commit comments

Comments
 (0)