Skip to content

Commit 21bb371

Browse files
authored
fix: initialize arguments and executable path correctly, and dlopen with RTLD_GLOBAL (#8)
* fix: initialize arguments and executable path correctly. fixes numpy issue on darwin * chore: test importing numpy on ci * tests: log python version and executable * fix: workaround for dlopen with RTLD_GLOBAL * ci: only setup python3 on windows
1 parent c9e70c5 commit 21bb371

File tree

4 files changed

+51
-4
lines changed

4 files changed

+51
-4
lines changed

.github/workflows/checks.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,14 @@ jobs:
3939
with:
4040
deno-version: v1.x
4141

42-
- name: Setup python 3.8
42+
- name: Setup Python 3.9 (Windows)
4343
uses: actions/setup-python@v2
44+
if: ${{ matrix.os == 'windows-latest' }}
4445
with:
45-
python-version: '3.8'
46+
python-version: '3.9'
47+
48+
- name: Install NumPy
49+
run: python3 -m pip install numpy
4650

4751
- name: Run deno test
4852
run: deno test --allow-all --unstable

src/ffi.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { findLib } from "./util.ts";
1+
import { cstr, findLib } from "./util.ts";
22

33
const lib = Deno.env.get("DENO_PYTHON_PATH") ?? await findLib();
44

@@ -375,6 +375,30 @@ try {
375375
result: "pointer",
376376
},
377377
}).symbols;
378+
379+
// On Unix based systems, we need to supply dlopen with RTLD_GLOBAL
380+
// but Deno.dlopen does not support passing that flag. So we'll open
381+
// libc and use its dlopen to open with RTLD_LAZY | RTLD_GLOBAL to
382+
// allow subsequently loaded shared libraries to be able to use symbols
383+
// from Python C API.
384+
if (Deno.build.os === "linux") {
385+
// TODO: is it right to use this symbol?
386+
const libc = Deno.dlopen(`libc.so.6`, {
387+
__libc_dlopen_mode: {
388+
parameters: ["pointer", "i32"],
389+
result: "pointer",
390+
},
391+
});
392+
libc.symbols.__libc_dlopen_mode(cstr(lib), 0x00001 | 0x00100);
393+
} else if (Deno.build.os === "darwin") {
394+
const libc = Deno.dlopen(`libc.dylib`, {
395+
dlopen: {
396+
parameters: ["pointer", "i32"],
397+
result: "pointer",
398+
},
399+
});
400+
libc.symbols.dlopen(cstr(lib), 0x00001 | 0x00100);
401+
}
378402
} catch (e) {
379403
throw new Error(`Python library not found: ${(e as Error).message}`);
380404
}

src/python.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,18 @@ export class Python {
681681
this.bool = this.builtins.bool;
682682
this.set = this.builtins.set;
683683
this.tuple = this.builtins.tuple;
684+
685+
// Initialize arguments and executable path,
686+
// since some modules expect them to be set.
687+
688+
const sys = this.import("sys");
689+
const os = this.import("os");
690+
691+
sys.argv = [""];
692+
693+
if (Deno.build.os === "darwin") {
694+
sys.executable = os.path.join(sys.exec_prefix, "bin", "python3");
695+
}
684696
}
685697

686698
/**

test/test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { assert, assertEquals } from "./deps.ts";
22
import { NamedArgument, PyObject, python } from "../mod.ts";
33

4+
const { version, executable } = python.import("sys");
5+
console.log("Python version:", version);
6+
console.log("Executable:", executable);
7+
48
Deno.test("python version", () => {
5-
const { version } = python.import("sys");
69
assert(String(version).match(/^\d+\.\d+\.\d+/));
710
});
811

@@ -111,3 +114,7 @@ Deno.test("named argument", () => {
111114
"Hello, world!",
112115
);
113116
});
117+
118+
Deno.test("numpy", () => {
119+
const _np = python.import("numpy");
120+
});

0 commit comments

Comments
 (0)