Skip to content

Commit d45dafe

Browse files
committed
add a real module with a preliminary API
1 parent 6b3a6b0 commit d45dafe

File tree

6 files changed

+123
-2
lines changed

6 files changed

+123
-2
lines changed

.gitignore

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,15 @@ builds/
44
*.pyc
55
*.swp
66
test.exe
7-
local/
87
dist/
8+
build/
9+
libs/
10+
# These are artifacts when using editable builds
11+
local/lib
12+
local/include
13+
local/openblas.egg-info
14+
local/openblas/lib
15+
local/openblas/include
16+
local/openblas/*.so
17+
local/openblas/*.pyd
18+
local/openblas/*.dylib

local/openblas/__init__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import os
2+
from . import _init_openblas
3+
4+
# Use importlib.metadata to single-source the version
5+
6+
try:
7+
# importlib.metadata is present in Python 3.8 and later
8+
import importlib.metadata as importlib_metadata
9+
except ImportError:
10+
# use the shim package importlib-metadata pre-3.8
11+
import importlib_metadata as importlib_metadata
12+
13+
try:
14+
# __package__ allows for the case where __name__ is "__main__"
15+
__version__ = importlib_metadata.version(__package__ or __name__)
16+
except importlib_metadata.PackageNotFoundError:
17+
__version__ = "0.0.0"
18+
19+
openblas_config = _init_openblas.get_config()
20+
21+
path_to_so = os.path.join(os.path.dirname(__file__), 'lib', 'libopenblas64_.so')
22+
23+
24+
def open_so():
25+
_init_openblas.open_so(path_to_so)
26+
27+

local/openblas/__main__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import openblas
2+
3+
if __name__ == "__main__":
4+
print(f"OpenBLAS using '{openblas.openblas_config}'")

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ upstream = "https://github.com/xianyi/OpenBLAS"
3131
namespaces = true
3232
where = ["local"]
3333

34+
[options]
35+
install_requires = "importlib-metadata ~= 1.0 ; python_version < '3.8'"
36+
3437
[tool.setuptools.package-data]
3538
openblas = ["lib/*", "include/*", "lib/pkgconfig/*", "lib/cmake/openblas/*"]
3639

setup.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,23 @@
1-
from setuptools import setup, find_packages
1+
import os
2+
from setuptools import setup, Extension
3+
4+
mydir = os.path.abspath(os.path.dirname(__file__))
5+
6+
# TODO: determine if we are building 64- or 32- bit interfaces
7+
use_64=True
8+
if use_64:
9+
libraries = ["openblas64_",]
10+
macros = [("SUFFIX", "64_")]
11+
else:
12+
libraries = ["openblas",]
13+
macros = []
214

315
setup(
16+
ext_modules=[Extension(
17+
"openblas._init_openblas", ["src/_init_openblas.c"],
18+
libraries=libraries,
19+
library_dirs=[os.path.join(mydir, 'local', 'openblas', 'lib'),],
20+
extra_link_args=["-Wl,-rpath,$ORIGIN/lib"],
21+
define_macros=macros,
22+
)],
423
)

src/_init_openblas.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include "Python.h"
2+
#include <dlfcn.h>
3+
#include <stdio.h>
4+
5+
#ifdef SUFFIX
6+
#define openblas_get_config openblas_get_config64_
7+
#endif
8+
9+
extern const char * openblas_get_config();
10+
11+
PyObject *
12+
get_config(PyObject *self, PyObject *args) {
13+
const char * config = openblas_get_config();
14+
return PyUnicode_FromString(config);
15+
}
16+
17+
PyObject*
18+
open_so(PyObject *self, PyObject *args) {
19+
const char *utf8 = PyUnicode_AsUTF8(args);
20+
if (utf8 == NULL) {
21+
return NULL;
22+
}
23+
void *handle = dlopen(utf8, RTLD_GLOBAL | RTLD_NOW);
24+
if (handle == NULL) {
25+
PyErr_SetString(PyExc_ValueError, "Could not open SO");
26+
return NULL;
27+
}
28+
Py_RETURN_TRUE;
29+
}
30+
31+
static PyMethodDef InitMethods[] = {
32+
{"get_config", get_config, METH_NOARGS,
33+
"Return openblas_get_config(), see https://github.com/xianyi/OpenBLAS/wiki/OpenBLAS-Extensions"},
34+
{"open_so", open_so, METH_O,
35+
"Use dlopen to load the shared object, which must exist"},
36+
{NULL, NULL, 0, NULL} /* Sentinel */
37+
};
38+
39+
static struct PyModuleDef initmodule = {
40+
PyModuleDef_HEAD_INIT,
41+
"_init_openblas", /* name of module */
42+
NULL, /* module documentation, may be NULL */
43+
-1, /* size of per-interpreter state of the module,
44+
or -1 if the module keeps state in global variables. */
45+
InitMethods
46+
};
47+
48+
PyMODINIT_FUNC
49+
PyInit__init_openblas(void)
50+
{
51+
PyObject *m;
52+
53+
m = PyModule_Create(&initmodule);
54+
if (m == NULL)
55+
return NULL;
56+
57+
return m;
58+
}

0 commit comments

Comments
 (0)