Re: [cx-oracle-users] Wheels again
Brought to you by:
atuining
|
From: Kubo T. <ku...@ji...> - 2016-04-22 01:37:37
|
Hi,
I know a little about python and nothing about wheels.
However I have three ideas.
1. Distribute cx_Oracle compiled for Oracle 10g.
Oracle client library ABI keeps backward compatibility on Windows.
When a binary file is compiled for Oracle 10g, it works with Oracle
10g, 11g and 12c.
However it cannot use features depends on Oracle 11g and 12c clients.
2. Check Oracle client version at runtime.
This is ideal for pre-compiled packages but not practical because this needs
too many changes in cx_Oracle.
Add the following code to Module_Initialize() in cx_Oracle.c
HMODULE hMod = GetModuleHandle("OCI.DLL");
void (*func)(sword*, sword*, sword*, sword*, sword*) = (void
(*)(sword*, sword*, sword*, sword*, sword*))GetProcAddress(hMod,
"OCIClientVersion");
if (func == NULL) {
oracle_version_hex = ORACLE_VERSION(10, 1)
} else {
sword major, minor, update, patch, port;
(*func)(&major, &minor, &update, &patch, &port);
oracle_version_hex = ORACLE_VERSION(major, minor);
}
and rewrite code such as
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(11,1)
...
#endif
to
if (oracle_client_hex >= ORACLE_VERSION(11,1)) {
...
}
Use function pointers retrieved by GetProcAddress() for functions
added in Oracle 11g and 12c,
3. Add a bootstrap module if wheels can include more than one module.
Compile cx_Oracle for Oracle 10.1, 10.2, 11.1, 11.2 and 12.1 and rename them
to cx_Oracle.10.1.dll, cx_Oracle.10.2.dll, cx_Oracle.11.1.dll,
cx_Oracle.11.2.dll and cx_Oracle.12.1.dll respectively.
Compile the following code as cx_Oracle.dll.
// This is incomplete code. no error checks.
typedef int sword;
static void *get_init_func(const char *init_func_name)
{
HMODULE hMod;
void (*func)(sword*, sword*, sword*, sword*, sword*);
char dll_name[30];
char dll_full_path[MAX_PATH];
// Get the Oracle client version and fill dll_name.
hMod = LoadLibrary("OCI.DLL");
func = (void (*)(sword*, sword*, sword*, sword*,
sword*))GetProcAddress(hMod, "OCIClientVersion");
if (func == NULL) {
strcpy(dll_name, "cx_Oracle.10.1.dll");
} else {
sword major, minor, update, patch, port;
(*func)(&major, &minor, &update, &patch, &port);
sprintf(dll_name, "cx_Oracle.%d.%d.dll", major, minor);
}
FreeLibrary(hMod);
// get the current module handle.
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
&get_init_func, &hMod);
... fill dll_full_path with the directory name containing the
current module by using GetModuleFileName(hMod, ...).
... append dll_name to dll_full_path.
// Load the real cx_Oracle module and get the module initializer function.
hMod = LoadLibrary(dll_full_path);
return GetProcAddress(hMod, init_func_name);
}
#if PY_MAJOR_VERSION >= 3
PyMODINIT_FUNC PyInit_cx_Oracle(void)
{
PyObject *(*init)(void) =
(PyObject*(*)(void))get_init_func("PyInit_cx_Oracle");
return (*init)();
}
#else
void initcx_Oracle(void)
{
void (*init)(void) = (void(*)(void))get_init_func("initcx_Oracle");
(*init)();
}
#endif
Put cx_Oracle.dll, cx_Oracle.10.1.dll, cx_Oracle.10.2.dll,
cx_Oracle.11.1.dll, cx_Oracle.11.2.dll
and cx_Oracle.12.1.dll in a directory.
|