-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfix-python-soname.js
More file actions
executable file
·127 lines (109 loc) · 3.83 KB
/
fix-python-soname.js
File metadata and controls
executable file
·127 lines (109 loc) · 3.83 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env node
/**
* Post-install script to fix Python library soname on Linux
*
* This script automatically detects the system-installed Python version
* and updates the .node binary to link against the correct libpython.so.
*
* Only runs on Linux - other platforms don't need soname fixing.
* Uses a WASM version of the arwen ELF patcher for cross-platform compatibility.
*/
const { WASI } = require('wasi')
const fs = require('fs')
const path = require('path')
const os = require('os')
const platform = os.platform()
const arch = os.arch()
// Function to detect if this is a development install vs dependency install
function isDevInstall() {
const env = process.env
// Method 1: Check if INIT_CWD and PWD are the same (local dev install)
if (env.INIT_CWD && env.PWD) {
if (env.INIT_CWD === env.PWD || env.INIT_CWD.indexOf(env.PWD) === 0) {
return true
}
}
// Method 2: Check for .git folder existence (dev environment)
if (fs.existsSync(path.join(__dirname, '.git'))) {
return true
}
// Method 3: Check if we're in production mode
if (env.NODE_ENV === 'production' || env.npm_config_production) {
return false
}
return false
}
// Only patch on Linux and macOS
if (platform !== 'linux' && platform !== 'darwin') {
console.log(`No need to fix soname on platform: ${platform}`)
process.exit(0)
}
// Get the node file path based on platform
const nodeFilePath = platform === 'linux'
? path.join(__dirname, `python-node.linux-${arch}-gnu.node`)
: path.join(__dirname, `python-node.darwin-${arch}.node`)
if (!fs.existsSync(nodeFilePath)) {
if (isDevInstall()) {
// No .node file found during dev install - this is expected, skip silently
console.log(`${nodeFilePath} not found during development install, skipping binary patching`)
process.exit(0)
} else {
// No .node file found when installed as dependency - this is an error
console.error(`Error: Could not find "${nodeFilePath}" to patch binary`)
process.exit(1)
}
}
// Check if WASM file exists
const wasmPath = path.join(__dirname, 'fix-python-soname.wasm')
if (!fs.existsSync(wasmPath)) {
if (isDevInstall()) {
// WASM file not found during dev install - this is expected, skip with warning
console.log('WASM file not found during development install, skipping binary patching')
process.exit(0)
} else {
// WASM file not found when installed as dependency - this is an error
console.error('Error: fix-python-soname.wasm not found')
process.exit(1)
}
}
console.log(`Running binary patch on ${nodeFilePath}`)
// Create a WASI instance
const wasi = new WASI({
version: 'preview1',
args: ['fix-python-soname', nodeFilePath],
env: process.env,
preopens: {
'/': '/',
}
})
async function runSonameFixer() {
try {
const wasm = fs.readFileSync(wasmPath);
const { instance } = await WebAssembly.instantiate(wasm, {
wasi_snapshot_preview1: wasi.wasiImport
});
// Run the WASI module
const exitCode = wasi.start(instance)
if (exitCode !== 0) {
console.error(`Error: soname fixer exited with code ${exitCode}`)
process.exit(exitCode)
}
// On macOS, re-sign the binary after patching
if (platform === 'darwin') {
console.log('Re-signing binary after patching...')
const { execSync } = require('child_process')
try {
execSync(`codesign --force --sign - "${nodeFilePath}"`, { stdio: 'inherit' })
console.log('Binary re-signed successfully')
} catch (error) {
console.error('Warning: Failed to re-sign binary:', error.message)
// Don't fail the install if codesign fails - the binary might still work
}
}
process.exit(0)
} catch (error) {
console.error('Error: Failed to run soname fixer:', error.message)
process.exit(1) // Fail hard when installed as dependency
}
}
runSonameFixer()