-
Notifications
You must be signed in to change notification settings - Fork 29
Expand file tree
/
Copy pathcopy-dependencies.php
More file actions
111 lines (102 loc) · 4.21 KB
/
copy-dependencies.php
File metadata and controls
111 lines (102 loc) · 4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?php declare(strict_types=1);
/********************************************************
*
* Copies the system dependencies used by a binary/extension.
*
* Usage:
* php copy-dependencies.php <file-to-analyze> <target-directory>
* It also works with directories:
* php copy-dependencies.php <directory-to-analyze> <target-directory>
*
* For example:
* php copy-dependencies.php /opt/bin/php /opt/lib
*
********************************************************/
if (! ($argv[1] ?? false)) {
echo 'Missing the first argument, check the file to see how to use it' . PHP_EOL;
exit(1);
}
if (! ($argv[2] ?? false)) {
echo 'Missing the second argument, check the file to see how to use it' . PHP_EOL;
exit(1);
}
[$_, $pathToCheck, $targetDirectory] = $argv;
// Create the target directory if it doesn't exist
if (! is_dir($targetDirectory)) {
mkdir($targetDirectory, 0777, true);
}
$arch = 'x86';
if (php_uname('m') !== 'x86_64') {
$arch = 'arm';
}
$librariesThatExistOnLambda = file(__DIR__ . "/libs-$arch.txt");
$librariesThatExistOnLambda = array_map('trim', $librariesThatExistOnLambda);
// For some reason some libraries are actually not in Lambda, despite being in the docker image 🤷
$librariesThatExistOnLambda = array_filter($librariesThatExistOnLambda, function ($library) {
return ! str_contains($library, 'libgcrypt.so')
&& ! str_contains($library, 'libassuan.so')
&& ! str_contains($library, 'libgobject-2.0.so')
&& ! str_contains($library, 'libgpg-error.so')
&& ! str_contains($library, 'libgpgme-pthread.so')
&& ! str_contains($library, 'libgpgme.so')
;
});
if (is_file($pathToCheck)) {
$requiredLibraries = listDependencies($pathToCheck);
} elseif (is_dir($pathToCheck)) {
$requiredLibraries = [];
foreach (glob($pathToCheck . '/*') as $file) {
if (is_file($file)) {
$requiredLibraries = array_merge($requiredLibraries, listDependencies($file));
}
}
} else {
throw new RuntimeException("The path to check is neither a file nor a directory: $pathToCheck");
}
// Exclude existing system libraries
$requiredLibraries = array_filter($requiredLibraries, function (string $lib) use ($librariesThatExistOnLambda) {
// Libraries that we compiled are in /opt/lib or /opt/lib64, we compiled them because they are more
// recent than the ones in Lambda so we definitely want to use them
$isALibraryWeCompiled = str_starts_with($lib, '/opt/lib');
$doesNotExistInLambda = !in_array(basename($lib), $librariesThatExistOnLambda, true);
$keep = $isALibraryWeCompiled || $doesNotExistInLambda;
if (! $keep) {
echo "Skipping $lib because it's already in Lambda" . PHP_EOL;
}
return $keep;
});
// Copy all the libraries
foreach ($requiredLibraries as $libraryPath) {
$targetPath = $targetDirectory . '/' . basename($libraryPath);
echo "Copying $libraryPath to $targetPath" . PHP_EOL;
$success = copy($libraryPath, $targetPath);
if (! $success) {
throw new RuntimeException("Could not copy $libraryPath to $targetPath");
}
}
function listDependencies(string $path): array
{
// ldd lists the dependencies of a binary or library/extension (.so file)
exec("ldd $path 2>&1", $lines);
if (str_contains(end($lines), 'exited with unknown exit code (139)')) {
// We can't use `ldd` on binaries (like /opt/bin/php) because it fails on cross-platform builds
// so we fall back to `LD_TRACE_LOADED_OBJECTS` (which doesn't work for .so files, that's why we also try `ldd`)
// See https://stackoverflow.com/a/35905007/245552
$output = shell_exec("LD_TRACE_LOADED_OBJECTS=1 $path 2>&1");
if (!$output) {
throw new RuntimeException("Could not list dependencies for $path");
}
$lines = explode(PHP_EOL, $output);
}
$dependencies = [];
foreach ($lines as $line) {
if (str_ends_with($line, ' => not found')) {
throw new RuntimeException("This library is a dependency for $path but cannot be found by 'ldd':\n$line\n");
}
$matches = [];
if (preg_match('/=> (.*) \(0x[0-9a-f]+\)/', $line, $matches)) {
$dependencies[] = $matches[1];
}
}
return $dependencies;
}