add example code
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
foo.c
|
||||||
|
example_builtin
|
65
bash.h
Normal file
65
bash.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <bash/builtins.h>
|
||||||
|
#include <bash/builtins/bashgetopt.h>
|
||||||
|
#include <bash/shell.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
extern char **make_builtin_argv(WORD_LIST*, int*);
|
||||||
|
|
||||||
|
#define DEFINE_BUILTIN(name) \
|
||||||
|
struct builtin name##_struct = { \
|
||||||
|
#name, \
|
||||||
|
name##_builtin_func, \
|
||||||
|
BUILTIN_ENABLED, \
|
||||||
|
NULL, \
|
||||||
|
NULL, \
|
||||||
|
0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WRAP_FUNC_WITH_BUILTIN(name)\
|
||||||
|
int name##_builtin_func(WORD_LIST *list) { \
|
||||||
|
int argc, ret; \
|
||||||
|
char **argv; \
|
||||||
|
argv = make_builtin_argv(list, &argc); \
|
||||||
|
ret = name(argc, argv); \
|
||||||
|
free(argv); \
|
||||||
|
return ret;\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PY_FUNC(bash_name, modname, function) \
|
||||||
|
int bash_name(int argc, char **argv) { \
|
||||||
|
dlopen("libpython3.13.so", RTLD_NOW | RTLD_GLOBAL);\
|
||||||
|
if (!Py_IsInitialized()) { \
|
||||||
|
PyImport_AppendInittab(#modname, PyInit_##modname); \
|
||||||
|
Py_Initialize(); \
|
||||||
|
} \
|
||||||
|
int _##bash_name(int argc, char **argv) { \
|
||||||
|
int ret = 1; \
|
||||||
|
PyObject *mod = NULL, *func = NULL, *result; \
|
||||||
|
\
|
||||||
|
mod = PyImport_ImportModule(#modname); \
|
||||||
|
func = PyObject_GetAttrString(mod, #function); \
|
||||||
|
\
|
||||||
|
PyObject *py_argv = PyTuple_New(argc - 1); \
|
||||||
|
\
|
||||||
|
for (int i = 1; i < argc; i++) { \
|
||||||
|
PyObject *arg_as_str = PyUnicode_FromString(argv[i]); \
|
||||||
|
PyTuple_SetItem(py_argv, i-1, arg_as_str); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
result = PyObject_CallObject(func, py_argv); \
|
||||||
|
if (!result) { PyErr_Print(); goto finally; } \
|
||||||
|
ret = (int) PyFloat_AsDouble(result); \
|
||||||
|
\
|
||||||
|
finally: \
|
||||||
|
Py_XDECREF(result); \
|
||||||
|
Py_XDECREF(py_argv); \
|
||||||
|
Py_XDECREF(func); \
|
||||||
|
Py_XDECREF(mod); \
|
||||||
|
return ret; \
|
||||||
|
} \
|
||||||
|
return _##bash_name(argc, argv); \
|
||||||
|
} \
|
||||||
|
WRAP_FUNC_WITH_BUILTIN(bash_name); \
|
||||||
|
DEFINE_BUILTIN(bash_name);
|
39
build.sh
Executable file
39
build.sh
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# maybe uses non-posix regex and thus may be non-portable. oops.
|
||||||
|
# the bash regex implementation is actually platform dependent, lol.
|
||||||
|
|
||||||
|
shopt -s extglob
|
||||||
|
|
||||||
|
PY_VERSION=3.13
|
||||||
|
PYFLAGS="$(/usr/bin/python${PY_VERSION}-config --cflags --ldflags)"
|
||||||
|
BASH_INCLUDE_DIR="/usr/include/bash"
|
||||||
|
|
||||||
|
function translate_function_names() {
|
||||||
|
# cython generates garbled names like __pyx_pf_7py_test_2foo for a python function named foo
|
||||||
|
# this function generates a list of #defines that translate these names to what they are in python
|
||||||
|
|
||||||
|
file="${1}"
|
||||||
|
|
||||||
|
grep 'static PyObject \*__pyx_pf_' "${file}" | grep -v 'proto' | while read -r line; do
|
||||||
|
desired_name=$"${line#*$"${file/.c/}"_}"
|
||||||
|
desired_name="${desired_name/#+([0-9])/}"
|
||||||
|
real_name="${line#*\*}"
|
||||||
|
echo "#define ${desired_name%(*} ${real_name%(*}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
py2c() {
|
||||||
|
rm "${1/.py/.c}"
|
||||||
|
cython3 -3 "${1}" -o "${1/.py/.c}"
|
||||||
|
translate_function_names $(basename ${1/.py/.c}) >> "${1/.py/.c}"
|
||||||
|
}
|
||||||
|
|
||||||
|
compile() {
|
||||||
|
gcc -I$BASH_INCLUDE_DIR{/include,/builtins,}\
|
||||||
|
$PYFLAGS $1 -o ${1/.c/} -Wall\
|
||||||
|
-lpython3.13 \
|
||||||
|
-fPIC -shared -O3
|
||||||
|
}
|
||||||
|
|
||||||
|
py2c foo.py
|
||||||
|
compile example_builtin.c
|
6
example_builtin.c
Normal file
6
example_builtin.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "bash.h"
|
||||||
|
#include "foo.c"
|
||||||
|
|
||||||
|
PY_FUNC(foo, foo, _foo);
|
||||||
|
PY_FUNC(bar, foo, _bar);
|
||||||
|
PY_FUNC(graph, foo, _complicated_function);
|
22
foo.py
Normal file
22
foo.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
def _foo(*_):
|
||||||
|
print("foo.py")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _bar(*args):
|
||||||
|
for arg in args:
|
||||||
|
print(arg)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _complicated_function(*args):
|
||||||
|
mean, stdv, *_ = args
|
||||||
|
mean, stdv = int(mean), int(stdv)
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from scipy.stats import norm
|
||||||
|
x_min = norm.ppf(0.005, loc=mean, scale=stdv)
|
||||||
|
x_max = norm.ppf(0.995, loc=mean, scale=stdv)
|
||||||
|
x = np.linspace(x_min, x_max, 1000)
|
||||||
|
plt.plot(x, norm.pdf(x, mean, stdv))
|
||||||
|
plt.show()
|
||||||
|
return 0
|
Reference in New Issue
Block a user