components/python/cx_oracle/patches/cx_Oracle-setup.patch
author jmcp <James.McPherson@oracle.com>
Fri, 18 Sep 2015 15:29:23 -0700
changeset 4886 5489d408f67a
permissions -rw-r--r--
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):