rework to separate out python module

Remove the magic from the magic _db* modules.
Combine as one 'devsup._dbapi'.

libpyDevSup exists only to bootstrap python
interpreter in IOCs.
This commit is contained in:
Michael Davidsaver
2018-11-03 13:33:36 -07:00
parent 662b518338
commit f428d2a4e4
15 changed files with 401 additions and 426 deletions

View File

@ -1,35 +1,31 @@
TOP=../..
include $(TOP)/configure/CONFIG
PYMODULE = NO
include $(TOP)/configure/CONFIG_PY
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#=============================
# Build the IOC application
INSTALL_SHRLIB = $(PY_INSTALL_DIR)/devsup
LIBRARY = pyDevSup$(PY_LD_VER)
LOADABLE_LIBRARY_HOST += _dbapi
SHRLIB_VERSION = 0
TARGETS += $(COMMON_DIR)/pyDevSupCommon.dbd
DBDDEPENDS_FILES += pyDevSupCommon.dbd$(DEP)
DBD += pyDevSup.dbd
pyDevSupCommon_DBD += base.dbd
pyDevSup$(PY_LD_VER)_SYS_LIBS += python$(PY_LD_VER)
dbapi_CPPFLAGS += -DXEPICS_ARCH=\"$(T_A)\"
dbapi_CPPFLAGS += -DXPYDEV_BASE=\"$(abspath $(INSTALL_LOCATION))\"
dbapi_CPPFLAGS += -DXEPICS_BASE=\"$(EPICS_BASE)\"
dbapi_CPPFLAGS += -DPYDIR=\"python$(PY_VER)\"
setup_CPPFLAGS += -DXEPICS_ARCH=\"$(T_A)\"
setup_CPPFLAGS += -DXPYDEV_BASE=\"$(abspath $(INSTALL_LOCATION))\"
setup_CPPFLAGS += -DXEPICS_BASE=\"$(EPICS_BASE)\"
setup_CPPFLAGS += -DPYDIR=\"python$(PY_VER)\"
_dbapi_SRCS += dbapi.c
_dbapi_SRCS += dbrec.c
_dbapi_SRCS += dbfield.c
_dbapi_SRCS += dbdset.c
pyDevSup$(PY_LD_VER)_SRCS += setup.c
pyDevSup$(PY_LD_VER)_SRCS += dbbase.c
pyDevSup$(PY_LD_VER)_SRCS += dbrec.c
pyDevSup$(PY_LD_VER)_SRCS += dbfield.c
pyDevSup$(PY_LD_VER)_SRCS += dbdset.c
pyDevSup$(PY_LD_VER)_LIBS += $(EPICS_BASE_IOC_LIBS)
_dbapi_SRCS += pyDevSupCommon_registerRecordDeviceDriver.cpp
PY += devsup/__init__.py
PY += devsup/_nullapi.py

View File

@ -1,6 +1,3 @@
/* Global interpreter setup
*/
/* python has its own ideas about which version to support */
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
@ -21,9 +18,13 @@
#include <epicsThread.h>
#include <epicsExit.h>
#include <alarm.h>
#include <iocsh.h>
#include <iocInit.h>
#include "pydevsup.h"
extern int pyDevSupCommon_registerRecordDeviceDriver(DBBASE *pbase);
typedef struct {
const initHookState state;
const char * const name;
@ -102,6 +103,20 @@ void pyfile(const char* file)
PyGILState_Release(state);
}
static const iocshArg argCode = {"python code", iocshArgString};
static const iocshArg argFile = {"file", iocshArgString};
static const iocshArg* const codeArgs[] = {&argCode};
static const iocshArg* const fileArgs[] = {&argFile};
static const iocshFuncDef codeDef = {"py", 1, codeArgs};
static const iocshFuncDef fileDef = {"pyfile", 1, fileArgs};
static void codeRun(const iocshArgBuf *args){py(args[0].sval);}
static void fileRun(const iocshArgBuf *args){pyfile(args[0].sval);}
initHookState pyInitLastState = (initHookState)-1;
static void pyhook(initHookState state)
@ -137,28 +152,127 @@ fail:
PyGILState_Release(gilstate);
}
static
PyObject *py_iocsh(PyObject *unused, PyObject *args, PyObject *kws)
{
int ret;
static char* names[] = {"script", "cmd", NULL};
char *script=NULL, *cmd=NULL;
if(!PyArg_ParseTupleAndKeywords(args, kws, "|ss", names, &script, &cmd))
return NULL;
if(!(!script ^ !cmd)) {
PyErr_SetString(PyExc_ValueError, "iocsh requires a script file name or command string");
return NULL;
}
Py_BEGIN_ALLOW_THREADS {
if(script)
ret = iocsh(script);
else
ret = iocshCmd(cmd);
} Py_END_ALLOW_THREADS
return PyInt_FromLong(ret);
}
static
PyObject *py_dbReadDatabase(PyObject *unused, PyObject *args, PyObject *kws)
{
long status;
static char* names[] = {"name", "fp", "path", "sub", NULL};
char *fname=NULL, *path=NULL, *sub=NULL;
int fd=-1;
if(!PyArg_ParseTupleAndKeywords(args, kws, "|siss", names, &fname, &fd, &path, &sub))
return NULL;
if(!((!fname) ^ (fd<0))) {
PyErr_SetString(PyExc_ValueError, "dbReadDatabase requires a file name or descriptor");
return NULL;
}
Py_BEGIN_ALLOW_THREADS {
if(fname)
status = dbReadDatabase(&pdbbase, fname, path, sub);
else {
FILE *ff = fdopen(fd, "r");
status = dbReadDatabaseFP(&pdbbase, ff, path, sub);
// dbReadDatabaseFP() has called fclose()
}
} Py_END_ALLOW_THREADS
if(status) {
char buf[30];
errSymLookup(status, buf, sizeof(buf));
PyErr_SetString(PyExc_RuntimeError, buf);
return NULL;
}
Py_RETURN_NONE;
}
static
PyObject *py_iocInit(PyObject *unused)
{
Py_BEGIN_ALLOW_THREADS {
iocInit();
} Py_END_ALLOW_THREADS
Py_RETURN_NONE;
}
static
PyObject *py_pyDevSupCommon(PyObject *unused)
{
Py_BEGIN_ALLOW_THREADS {
pyDevSupCommon_registerRecordDeviceDriver(pdbbase);
} Py_END_ALLOW_THREADS
Py_RETURN_NONE;
}
static struct PyMethodDef dbapimethod[] = {
{"iocsh", (PyCFunction)py_iocsh, METH_VARARGS|METH_KEYWORDS,
"Execute IOC shell script or command"},
{"dbReadDatabase", (PyCFunction)py_dbReadDatabase, METH_VARARGS|METH_KEYWORDS,
"Load EPICS database file"},
{"iocInit", (PyCFunction)py_iocInit, METH_NOARGS,
"Initialize IOC"},
{"_dbd_setup", (PyCFunction)pyDBD_setup, METH_NOARGS, ""},
{"_dbd_rrd_base", (PyCFunction)py_pyDevSupCommon, METH_NOARGS, ""},
{"_dbd_cleanup", (PyCFunction)pyDBD_cleanup, METH_NOARGS, ""},
{NULL}
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef dbapimodule = {
PyModuleDef_HEAD_INIT,
"_dbapi",
"devsup._dbapi",
NULL,
-1,
NULL
&dbapimethod
};
#endif
/* initialize "magic" builtin module */
PyMODINIT_FUNC init_dbapi(void)
{
PyObject *mod = NULL, *hookdict;
PyObject *mod = NULL, *hookdict, *vertup, *obj;
pystate *st;
pyDevReasonID = epicsThreadPrivateCreate();
iocshRegister(&codeDef, &codeRun);
iocshRegister(&fileDef, &fileRun);
initHookRegister(&pyhook);
import_array();
#if PY_MAJOR_VERSION >= 3
mod = PyModule_Create(&dbapimodule);
#else
mod = Py_InitModule("_dbapi", NULL);
mod = Py_InitModule("devsup._dbapi", dbapimethod);
#endif
if(!mod)
goto fail;
@ -178,43 +292,6 @@ PyMODINIT_FUNC init_dbapi(void)
}
}
if(pyField_prepare(mod))
goto fail;
if(pyRecord_prepare(mod))
goto fail;
MODINIT_RET(mod);
fail:
fprintf(stderr, "Failed to initialize builtin _dbapi module!\n");
Py_XDECREF(mod);
MODINIT_RET(NULL);
}
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef constantsmodule = {
PyModuleDef_HEAD_INIT,
"_dbconstants",
NULL,
-1,
NULL
};
#endif
/* initialize "magic" builtin module */
PyMODINIT_FUNC init_dbconstants(void)
{
PyObject *mod = NULL, *vertup;
#if PY_MAJOR_VERSION >= 3
mod = PyModule_Create(&constantsmodule);
#else
mod = Py_InitModule("_dbconstants", NULL);
#endif
if(!mod)
MODINIT_RET(NULL);
PyModule_AddIntMacro(mod, NO_ALARM);
PyModule_AddIntMacro(mod, MINOR_ALARM);
PyModule_AddIntMacro(mod, MAJOR_ALARM);
@ -277,150 +354,24 @@ PyMODINIT_FUNC init_dbconstants(void)
if(vertup)
PyModule_AddObject(mod, "pydevver", vertup);
#if PY_MAJOR_VERSION >= 3 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION>=7)
obj = PyCapsule_New(pdbbase, "pdbbase", NULL);
#else
obj = PyCObject_FromVoidPtrAndDesc(pdbbase, "pdbbase", NULL);
#endif
if(!obj)
goto fail;
PyModule_AddObject(mod, "pdbbase", obj);
if(pyField_prepare(mod))
goto fail;
if(pyRecord_prepare(mod))
goto fail;
MODINIT_RET(mod);
}
static void cleanupPy(void *junk)
{
PyThreadState *state = PyGILState_GetThisThreadState();
PyEval_RestoreThread(state);
/* special "fake" hook for shutdown */
pyhook((initHookState)9999);
pyDBD_cleanup();
pyField_cleanup();
Py_Finalize();
epicsThreadPrivateDelete(pyDevReasonID);
}
/* Initialize the interpreter environment
*/
static void setupPyInit(void)
{
PyImport_AppendInittab("_dbapi", init_dbapi);
PyImport_AppendInittab("_dbconstants", init_dbconstants);
PyImport_AppendInittab("_dbbase", init_dbbase);
Py_Initialize();
PyEval_InitThreads();
(void)PyEval_SaveThread();
epicsAtExit(&cleanupPy, NULL);
}
static void extendPath(PyObject *list,
const char *base,
const char *archdir)
{
PyObject *mod, *ret;
mod = PyImport_ImportModule("os.path");
if(!mod)
return;
ret = PyObject_CallMethod(mod, "join", "sss", base, PYDIR, archdir);
if(ret && !PySequence_Contains(list, ret)) {
PyList_Insert(list, 0, ret);
}
Py_XDECREF(ret);
Py_DECREF(mod);
if(PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
}
static void insertDefaultPath(PyObject *list)
{
const char *basedir, *pydevdir, *top, *arch;
basedir = getenv("EPICS_BASE");
if(!basedir)
basedir = XEPICS_BASE;
pydevdir = getenv("PYDEV_BASE");
if(!pydevdir)
pydevdir = XPYDEV_BASE;
top = getenv("TOP");
arch = getenv("ARCH");
if(!arch)
arch = XEPICS_ARCH;
assert(PyList_Check(list));
assert(PySequence_Check(list));
extendPath(list, basedir, arch);
extendPath(list, pydevdir, arch);
if(top)
extendPath(list, top, arch);
}
static void setupPyPath(void)
{
PyObject *mod, *path = NULL;
mod = PyImport_ImportModule("sys");
if(mod)
path = PyObject_GetAttrString(mod, "path");
fail:
fprintf(stderr, "Failed to initialize builtin _dbapi module!\n");
Py_XDECREF(mod);
if(path) {
PyObject *cur;
char cwd[PATH_MAX];
insertDefaultPath(path);
/* prepend current directory */
if(getcwd(cwd, sizeof(cwd)-1)) {
cwd[sizeof(cwd)-1] = '\0';
cur = PyString_FromString(cwd);
if(cur)
PyList_Insert(path, 0, cur);
Py_XDECREF(cur);
MODINIT_RET(NULL);
}
}
Py_XDECREF(path);
}
#include <iocsh.h>
static const iocshArg argCode = {"python code", iocshArgString};
static const iocshArg argFile = {"file", iocshArgString};
static const iocshArg* const codeArgs[] = {&argCode};
static const iocshArg* const fileArgs[] = {&argFile};
static const iocshFuncDef codeDef = {"py", 1, codeArgs};
static const iocshFuncDef fileDef = {"pyfile", 1, fileArgs};
static void codeRun(const iocshArgBuf *args){py(args[0].sval);}
static void fileRun(const iocshArgBuf *args){pyfile(args[0].sval);}
static void pySetupReg(void)
{
PyGILState_STATE state;
pyDevReasonID = epicsThreadPrivateCreate();
setupPyInit();
iocshRegister(&codeDef, &codeRun);
iocshRegister(&fileDef, &fileRun);
initHookRegister(&pyhook);
state = PyGILState_Ensure();
init_dbapi();
setupPyPath();
if(PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
PyGILState_Release(state);
}
#include <epicsExport.h>
epicsExportRegistrar(pySetupReg);

View File

@ -1,136 +0,0 @@
/* python has its own ideas about which version to support */
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#include <Python.h>
#include <epicsVersion.h>
#include <dbCommon.h>
#include <dbStaticLib.h>
#include <dbAccess.h>
#include <initHooks.h>
#include <iocsh.h>
#include <iocInit.h>
#include "pydevsup.h"
static
PyObject *py_iocsh(PyObject *unused, PyObject *args, PyObject *kws)
{
int ret;
static char* names[] = {"script", "cmd", NULL};
char *script=NULL, *cmd=NULL;
if(!PyArg_ParseTupleAndKeywords(args, kws, "|ss", names, &script, &cmd))
return NULL;
if(!(!script ^ !cmd)) {
PyErr_SetString(PyExc_ValueError, "iocsh requires a script file name or command string");
return NULL;
}
Py_BEGIN_ALLOW_THREADS {
if(script)
ret = iocsh(script);
else
ret = iocshCmd(cmd);
} Py_END_ALLOW_THREADS
return PyInt_FromLong(ret);
}
static
PyObject *py_dbReadDatabase(PyObject *unused, PyObject *args, PyObject *kws)
{
long status;
static char* names[] = {"name", "fp", "path", "sub", NULL};
char *fname=NULL, *path=NULL, *sub=NULL;
int fd=-1;
if(!PyArg_ParseTupleAndKeywords(args, kws, "|siss", names, &fname, &fd, &path, &sub))
return NULL;
if(!((!fname) ^ (fd<0))) {
PyErr_SetString(PyExc_ValueError, "dbReadDatabase requires a file name or descriptor");
return NULL;
}
Py_BEGIN_ALLOW_THREADS {
if(fname)
status = dbReadDatabase(&pdbbase, fname, path, sub);
else {
FILE *ff = fdopen(fd, "r");
status = dbReadDatabaseFP(&pdbbase, ff, path, sub);
fclose(ff);
}
} Py_END_ALLOW_THREADS
if(status) {
char buf[30];
errSymLookup(status, buf, sizeof(buf));
PyErr_SetString(PyExc_RuntimeError, buf);
return NULL;
}
Py_RETURN_NONE;
}
static
PyObject *py_iocInit(PyObject *unused)
{
Py_BEGIN_ALLOW_THREADS {
iocInit();
} Py_END_ALLOW_THREADS
Py_RETURN_NONE;
}
static struct PyMethodDef dbbasemethods[] = {
{"iocsh", (PyCFunction)py_iocsh, METH_VARARGS|METH_KEYWORDS,
"Execute IOC shell script or command"},
{"dbReadDatabase", (PyCFunction)py_dbReadDatabase, METH_VARARGS|METH_KEYWORDS,
"Load EPICS database file"},
{"iocInit", (PyCFunction)py_iocInit, METH_NOARGS,
"Initialize IOC"},
{NULL}
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef dbbasemodule = {
PyModuleDef_HEAD_INIT,
"_dbbase",
NULL,
-1,
&dbbasemethods
};
#endif
/* initialize "magic" builtin module */
PyMODINIT_FUNC init_dbbase(void)
{
PyObject *mod = NULL, *obj = NULL;
#if PY_MAJOR_VERSION >= 3
mod = PyModule_Create(&dbbasemodule);
#else
mod = Py_InitModule("_dbbase", dbbasemethods);
#endif
if(!mod)
goto fail;
#if PY_MAJOR_VERSION >= 3 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION>=7)
obj = PyCapsule_New(pdbbase, "pdbbase", NULL);
#else
obj = PyCObject_FromVoidPtrAndDesc(pdbbase, "pdbbase", NULL);
#endif
if(!obj)
goto fail;
PyModule_AddObject(mod, "pdbbase", obj);
MODINIT_RET(mod);
fail:
Py_XDECREF(obj);
Py_XDECREF(mod);
fprintf(stderr, "Failed to initialize builtin _dbbase module!\n");
MODINIT_RET(NULL);
}

View File

@ -19,6 +19,8 @@
#include <dbScan.h>
#include <cantProceed.h>
#include <registryFunction.h>
#include <iocshRegisterCommon.h>
#include <registryCommon.h>
#include <aSubRecord.h>
#include "pydevsup.h"
@ -471,8 +473,28 @@ int canIOScanRecord(dbCommon *prec)
return !!priv->scanobj;
}
static
const dset* pydsets[] = {
&pydevsupComSpec.com,
&pydevsupComIn.com,
&pydevsupComOut.com,
};
static const char* pydsetnames[] = {
"pydevsupComSpec",
"pydevsupComIn",
"pydevsupComOut",
};
PyObject* pyDBD_setup(PyObject *unused)
{
registerDevices(pdbbase, NELEMENTS(pydsets), pydsetnames, pydsets);
registryFunctionAdd("python_asub", (REGISTRYFUNCTION)&python_asub);
Py_RETURN_NONE;
}
/* Called with GIL locked */
void pyDBD_cleanup(void)
PyObject* pyDBD_cleanup(PyObject *unused)
{
ELLNODE *cur;
inshutdown = 1;
@ -497,12 +519,5 @@ void pyDBD_cleanup(void)
free(priv);
}
Py_RETURN_NONE;
}
#include <epicsExport.h>
epicsExportAddress(dset, pydevsupComSpec);
epicsExportAddress(dset, pydevsupComIn);
epicsExportAddress(dset, pydevsupComOut);
epicsRegisterFunction(python_asub);

View File

@ -569,12 +569,3 @@ int pyField_prepare(PyObject *module)
return 0;
}
void pyField_cleanup(void)
{
size_t i;
for(i=0; i<=DBF_MENU; i++) {
Py_XDECREF(dbf2np[i]);
dbf2np[i] = NULL;
}
}

View File

@ -1,28 +1,68 @@
try:
import _dbapi
HAVE_DBAPI = True
except ImportError:
import devsup._nullapi as _dbapi
HAVE_DBAPI = False
import os
import atexit
import tempfile
try:
from _dbconstants import *
except ImportError:
EPICS_VERSION_STRING = "EPICS 0.0.0.0-0"
EPICS_DEV_SNAPSHOT = ""
EPICS_SITE_VERSION = "0"
EPICS_VERSION = 0
EPICS_REVISION = 0
EPICS_MODIFICATION = 0
EPICS_PATCH_LEVEL = 0
from . import _dbapi
XEPICS_ARCH = "nullos-nullarch"
XPYDEV_BASE = "invaliddir"
XEPICS_BASE = "invaliddir"
epicsver = (0,0,0,0,"0","")
pydevver = (0,0)
INVALID_ALARM = UDF_ALARM = 0
from ._dbapi import (EPICS_VERSION_STRING,
EPICS_DEV_SNAPSHOT,
EPICS_SITE_VERSION,
EPICS_VERSION,
EPICS_REVISION,
EPICS_MODIFICATION,
EPICS_PATCH_LEVEL,
XEPICS_ARCH,
XPYDEV_BASE,
XEPICS_BASE,
epicsver,
pydevver,
INVALID_ALARM,
UDF_ALARM,
)
__all__ = []
_ready = [False]
def _init(iocMain=False):
if _ready[0]:
return
_ready[0] = True
if not iocMain:
# we haven't read/register base.dbd
_dbapi.dbReadDatabase(os.path.join(XEPICS_BASE, "dbd", "base.dbd"))
_dbapi._dbd_rrd_base()
with tempfile.NamedTemporaryFile() as F:
F.write("""
device(longin, INST_IO, pydevsupComIn, "Python Device")
device(longout, INST_IO, pydevsupComOut, "Python Device")
device(ai, INST_IO, pydevsupComIn, "Python Device")
device(ao, INST_IO, pydevsupComOut, "Python Device")
device(stringin, INST_IO, pydevsupComIn, "Python Device")
device(stringout, INST_IO, pydevsupComOut, "Python Device")
device(bi, INST_IO, pydevsupComIn, "Python Device")
device(bo, INST_IO, pydevsupComOut, "Python Device")
device(mbbi, INST_IO, pydevsupComIn, "Python Device")
device(mbbo, INST_IO, pydevsupComOut, "Python Device")
device(mbbiDirect, INST_IO, pydevsupComIn, "Python Device")
device(mbboDirect, INST_IO, pydevsupComOut, "Python Device")
device(waveform, INST_IO, pydevsupComIn, "Python Device")
device(aai, INST_IO, pydevsupComIn, "Python Device")
device(aao, INST_IO, pydevsupComOut, "Python Device")
""")
F.flush()
_dbapi.dbReadDatabase(F.name)
_dbapi._dbd_setup()
@atexit.register
def _fini():
print("ATEXIT")
_dbapi._dbd_cleanup()

View File

@ -3,10 +3,7 @@ import threading, sys, traceback, time
from devsup.util import Worker, importmod
try:
import _dbapi
except ImportError:
import _nullapi as _dbapi
from . import _dbapi
_rec_cache = {}
_no_such_field = object()

View File

@ -4,10 +4,7 @@ import traceback
from functools import wraps
from collections import defaultdict
try:
import _dbapi
except ImportError:
import devsup._nullapi as _dbapi
from . import _dbapi
__all__ = [
"hooknames",

View File

@ -7,8 +7,8 @@ import threading, inspect
_tables = {}
from devsup.db import IOScanListThread
from devsup import INVALID_ALARM, UDF_ALARM
from .db import IOScanListThread
from . import INVALID_ALARM, UDF_ALARM
__all__ = [
'Parameter',

View File

@ -1,26 +0,0 @@
registrar(pySetupReg)
device(longin, INST_IO, pydevsupComIn, "Python Device")
device(longout, INST_IO, pydevsupComOut, "Python Device")
device(ai, INST_IO, pydevsupComIn, "Python Device")
device(ao, INST_IO, pydevsupComOut, "Python Device")
device(stringin, INST_IO, pydevsupComIn, "Python Device")
device(stringout, INST_IO, pydevsupComOut, "Python Device")
device(bi, INST_IO, pydevsupComIn, "Python Device")
device(bo, INST_IO, pydevsupComOut, "Python Device")
device(mbbi, INST_IO, pydevsupComIn, "Python Device")
device(mbbo, INST_IO, pydevsupComOut, "Python Device")
device(mbbiDirect, INST_IO, pydevsupComIn, "Python Device")
device(mbboDirect, INST_IO, pydevsupComOut, "Python Device")
device(waveform, INST_IO, pydevsupComIn, "Python Device")
device(aai, INST_IO, pydevsupComIn, "Python Device")
device(aao, INST_IO, pydevsupComOut, "Python Device")
function(python_asub)

View File

@ -17,12 +17,10 @@
initHookState pyInitLastState;
PyMODINIT_FUNC init_dbbase(void);
void pyDBD_cleanup(void);
PyObject* pyDBD_setup(PyObject *unused);
PyObject* pyDBD_cleanup(PyObject *unused);
int pyField_prepare(PyObject *module);
void pyField_cleanup(void);
int pyRecord_prepare(PyObject *module);

View File

@ -10,6 +10,25 @@ include $(TOP)/configure/CONFIG_PY
#=============================
# Build the IOC application
USR_CPPFLAGS += -I$(TOP)/devsupApp/src
LIBRARY = pyDevSup$(PY_LD_VER)
SHRLIB_VERSION = 0
DBD += pyDevSup.dbd
pyDevSup$(PY_LD_VER)_SYS_LIBS += python$(PY_LD_VER)
pyDevSup$(PY_LD_VER)_LIBS += $(EPICS_BASE_IOC_LIBS)
setup_CPPFLAGS += -DXEPICS_ARCH=\"$(T_A)\"
setup_CPPFLAGS += -DXPYDEV_BASE=\"$(abspath $(INSTALL_LOCATION))\"
setup_CPPFLAGS += -DXEPICS_BASE=\"$(EPICS_BASE)\"
setup_CPPFLAGS += -DPYDIR=\"python$(PY_VER)\"
pyDevSup$(PY_LD_VER)_SRCS += setup.c
PROD_IOC = softIocPy$(PY_VER)
PRODNAME = $(addsuffix $(EXE),$(PROD))

1
pyIocApp/pyDevSup.dbd Normal file
View File

@ -0,0 +1 @@
registrar(pySetupReg)

133
pyIocApp/setup.c Normal file
View File

@ -0,0 +1,133 @@
/* Global interpreter setup
*/
/* python has its own ideas about which version to support */
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#include <Python.h>
#ifdef HAVE_NUMPY
#include <numpy/ndarrayobject.h>
#endif
#include <stdio.h>
#include <epicsVersion.h>
#include <dbCommon.h>
#include <dbAccess.h>
#include <dbStaticLib.h>
#include <dbScan.h>
#include <initHooks.h>
#include <epicsThread.h>
#include <epicsExit.h>
#include <alarm.h>
#include "pydevsup.h"
static void cleanupPy(void *junk)
{
PyThreadState *state = PyGILState_GetThisThreadState();
PyEval_RestoreThread(state);
/* special "fake" hook for shutdown */
//pyhook((initHookState)9999);
Py_Finalize(); // calls python atexit hooks
}
static void extendPath(PyObject *list,
const char *base,
const char *archdir)
{
PyObject *mod, *ret;
mod = PyImport_ImportModule("os.path");
if(!mod)
return;
ret = PyObject_CallMethod(mod, "join", "sss", base, PYDIR, archdir);
if(ret && !PySequence_Contains(list, ret)) {
PyList_Insert(list, 0, ret);
}
Py_XDECREF(ret);
Py_DECREF(mod);
if(PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
}
static void insertDefaultPath(PyObject *list)
{
const char *basedir, *pydevdir, *top, *arch;
basedir = getenv("EPICS_BASE");
if(!basedir)
basedir = XEPICS_BASE;
pydevdir = getenv("PYDEV_BASE");
if(!pydevdir)
pydevdir = XPYDEV_BASE;
top = getenv("TOP");
arch = getenv("ARCH");
if(!arch)
arch = XEPICS_ARCH;
assert(PyList_Check(list));
assert(PySequence_Check(list));
extendPath(list, basedir, arch);
extendPath(list, pydevdir, arch);
if(top)
extendPath(list, top, arch);
}
static void setupPyPath(void)
{
PyObject *mod, *path = NULL;
mod = PyImport_ImportModule("sys");
if(mod)
path = PyObject_GetAttrString(mod, "path");
Py_XDECREF(mod);
if(path) {
PyObject *cur;
char cwd[PATH_MAX];
insertDefaultPath(path);
/* prepend current directory */
if(getcwd(cwd, sizeof(cwd)-1)) {
cwd[sizeof(cwd)-1] = '\0';
cur = PyString_FromString(cwd);
if(cur)
PyList_Insert(path, 0, cur);
Py_XDECREF(cur);
}
}
Py_XDECREF(path);
}
static void pySetupReg(void)
{
PyGILState_STATE state;
Py_Initialize();
PyEval_InitThreads();
setupPyPath();
if(PyRun_SimpleString("import devsup\n"
"devsup._init(True)\n"
)) {
PyErr_Print();
PyErr_Clear();
}
(void)PyEval_SaveThread();
epicsAtExit(&cleanupPy, NULL);
}
#include <epicsExport.h>
epicsExportRegistrar(pySetupReg);

View File

@ -3,7 +3,6 @@
py "import logging"
py "logging.basicConfig(level=logging.DEBUG)"
py "import devsup; print devsup.HAVE_DBAPI"
py "import sys; sys.path.insert(0,'${PWD}/testApp')"
py "print sys.path"
@ -23,4 +22,4 @@ dbLoadRecords("db/test6.db","P=tst:,TNAME=tsum")
iocInit()
# Start Reference tracker
py "from devsup import disect; disect.periodic(10)"
#py "from devsup import disect; disect.periodic(10)"