PSARC/2015/294 cx_Oracle for Solaris
15803329 SUNBT7183489 Include python module cx_Oracle in Solaris
This patch provides support for finding the Oracle Instant Client
libraries (and sdk) delivered via IPS. It also forces the specification
of an RPATH so that the cx_Oracle module links against the IPS-
delivered Instant Client packages.
This patch has not yet been integrated with upstream.
--- cx_Oracle-5.2/setup.py.orig Fri Apr 3 21:10:29 2015
+++ cx_Oracle-5.2/setup.py Fri Sep 11 17:23:39 2015
@@ -61,9 +61,17 @@
# define the list of files to be included as documentation for bdist_rpm
docFiles = "README.txt BUILD.txt samples test"
+# Globalize some variables
+subDirs = []
+versions = []
+if struct.calcsize("P") == 4:
+ bitness = 32
+else:
+ bitness = 64
+
# method for checking a potential Oracle home
def CheckOracleHome(directoryToCheck):
- global oracleHome, oracleVersion, oracleLibDir
+ global oracleHome, oracleVersion, oracleLibDir, subDirs, versions
import os
import struct
import sys
@@ -81,8 +89,19 @@
("11g", "libclntsh.dylib.11.1"),
("10g", "libclntsh.dylib.10.1")
]
+ elif sys.platform == "sunos5":
+ if bitness == 32:
+ # 32bit
+ subDirs = ["lib"]
+ else:
+ subDirs = ["lib/64", "lib"]
+ filesToCheck = [
+ ("12c", "libclntsh.so.12.1"),
+ ("11g", "libclntsh.so.11.1"),
+ ("10g", "libclntsh.so.10.1")
+ ]
else:
- if struct.calcsize("P") == 4:
+ if bitness == 32:
subDirs = ["lib", "lib32"]
else:
subDirs = ["lib", "lib64"]
@@ -124,7 +143,7 @@
# Older Instant Client dirs have the form:
# /usr/lib/oracle/10.2.0.5/client[64]/lib
def FindInstantClientRPMLib():
- versions = []
+ global versions
for path in glob.glob(os.path.join(rpmBaseLibDir, "[0-9.]*")):
versions.append(os.path.basename(path))
versions.sort(key = lambda x: [int(s) for s in x.split(".")])
@@ -147,26 +166,68 @@
# define Linux Instant Client RPM path components
# Assume 64 bit builds if the platform is 64 bit
rpmBaseLibDir = "/usr/lib/oracle"
-if struct.calcsize("P") == 4:
+if bitness == 32:
rpmClientDir = "client"
else:
rpmClientDir = "client64"
instantClientRPMLib = None
+#
+# Solaris 11.x and later make use of the Image Packaging System, IPS,
+# and can install Instant Client 12.1 (and later versions) using that
+# format. IPS-delivered versions exist under
+# /usr/oracle/instantclient/[version]
+# which allows us to bake an rpath into this module and remove the need
+# for setting LD_LIBRARY_PATH in a wrapper.
+def FindInstantClientIPSLib():
+ global versions
+ for path in glob.glob(os.path.join(ipsBaseLibDir, "[0-9.]*")):
+ versions.append(os.path.basename(path))
+ versions.sort(key = lambda x: [int(s) for s in x.split(".")])
+ versions.reverse()
+ for version in versions:
+ path = os.path.join(ipsBaseLibDir, version)
+ if os.path.exists(path) and CheckOracleHome(path):
+ return path
+
+# If the lib dir appears to be an Instant Client IPS dir, then look only
+# for matching SDK headers
+def FindInstantClientIPSInclude(libDir):
+ includeDir = os.path.join("/usr/include/oracle", versions[0])
+ if os.path.isfile(os.path.join(includeDir, "oci.h")):
+ return [includeDir]
+ raise DistutilsSetupError("cannot locate Oracle Instant Client " \
+ "SDK RPM header files")
+
+# Now we can define path components for the Solaris 11.x++ Instant Client
+# delivered via IPS.
+#
+# We build cx_Oracle as 32bit if we're running python2.7, and
+# 64bit if we're running python3.4 or later. That, however,
+# doesn't matter when finding the libraries since the IPS package
+# ships with both 32- and 64-bit libraries.
+ipsBaseLibDir = "/usr/oracle/instantclient"
+instantClientIPSLib = None
+
+
# try to determine the Oracle home
userOracleHome = os.environ.get("ORACLE_HOME")
if userOracleHome is not None:
if not CheckOracleHome(userOracleHome):
messageFormat = "Oracle home (%s) does not refer to an " \
- "10g, 11g or 12c installation."
+ "10g, 11g or 12c installation.\n"
raise DistutilsSetupError(messageFormat % userOracleHome)
else:
for path in os.environ["PATH"].split(os.pathsep):
if CheckOracleHome(path):
break
- if oracleHome is None and sys.platform.startswith("linux"):
- instantClientRPMLib = FindInstantClientRPMLib()
if oracleHome is None:
+ if sys.platform.startswith("linux"):
+ instantClientRPMLib = FindInstantClientRPMLib()
+ elif sys.platform.startswith("sunos5"):
+ instantClientIPSLib = FindInstantClientIPSLib()
+ else:
+ # oracleHome is None
raise DistutilsSetupError("cannot locate an Oracle software " \
"installation")
@@ -199,6 +260,8 @@
libs = ["clntsh"]
if instantClientRPMLib is not None:
includeDirs = FindInstantClientRPMInclude(instantClientRPMLib)
+ elif instantClientIPSLib is not None:
+ includeDirs = FindInstantClientIPSInclude(instantClientIPSLib)
else:
possibleIncludeDirs = ["rdbms/demo", "rdbms/public", "network/public",
"sdk/include"]
@@ -238,12 +301,19 @@
elif sys.platform == "darwin":
extraLinkArgs.append("-shared-libgcc")
-# force the inclusion of an RPATH linker directive if desired; this will
-# eliminate the need for setting LD_LIBRARY_PATH but it also means that this
-# location will be the only location searched for the Oracle client library
-if "FORCE_RPATH" in os.environ or instantClientRPMLib:
+# Eliminate the need for setting LD_LIBRARY_PATH in a wrapper script
+# by baking in a RUNPATH (aka RPATH)
+if sys.platform.startswith("sunos5"):
+ extraLinkArgs.append("-R%s" % oracleLibDir)
+else:
extraLinkArgs.append("-Wl,-rpath,%s" % oracleLibDir)
+# If we're running as a 64bit python interpreter, we need to ensure that
+# we get the compiler and linker to generate 64bit code too.
+if bitness == 64:
+ extraCompileArgs.append("-m64")
+ extraLinkArgs.append("-m64")
+
# tweak distribution full name to include the Oracle version
class Distribution(distutils.dist.Distribution):