setup.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. """Distutils script for cx_Oracle.
  2. Windows platforms:
  3. python setup.py build --compiler=mingw32 install
  4. Unix platforms
  5. python setup.py build install
  6. """
  7. import distutils.command
  8. try:
  9. import distutils.command.bdist_msi
  10. except ImportError:
  11. distutils.command.bdist_msi = None
  12. try:
  13. import distutils.command.bdist_wininst
  14. except ImportError:
  15. distutils.command.bdist_wininst = None
  16. import distutils.command.bdist_rpm
  17. import distutils.command.build
  18. import distutils.core
  19. import distutils.dist
  20. import distutils.util
  21. import os
  22. import re
  23. import struct
  24. import sys
  25. from distutils.errors import DistutilsSetupError
  26. # if setuptools is detected, use it to add support for eggs
  27. try:
  28. from setuptools import setup, Extension
  29. except:
  30. from distutils.core import setup
  31. from distutils.extension import Extension
  32. # define build constants
  33. BUILD_VERSION = "5.1.2"
  34. # define the list of files to be included as documentation for Windows
  35. dataFiles = None
  36. if sys.platform in ("win32", "cygwin"):
  37. baseName = "cx_Oracle-doc"
  38. dataFiles = [ (baseName,
  39. [ "BUILD.txt", "LICENSE.TXT", "README.TXT", "HISTORY.txt"]) ]
  40. for dir in ("html", "html/_static", "samples", "test"):
  41. files = []
  42. fullDirName = "%s/%s" % (baseName, dir)
  43. for name in os.listdir(dir):
  44. if name.startswith("."):
  45. continue
  46. if os.path.isdir(os.path.join(dir, name)):
  47. continue
  48. fullName = "%s/%s" % (dir, name)
  49. files.append(fullName)
  50. dataFiles.append((fullDirName, files))
  51. # define the list of files to be included as documentation for bdist_rpm
  52. docFiles = "LICENSE.txt README.txt BUILD.txt HISTORY.txt html samples test"
  53. # method for checking a potential Oracle home
  54. def CheckOracleHome(directoryToCheck):
  55. global oracleHome, oracleVersion, oracleLibDir
  56. import os
  57. import struct
  58. import sys
  59. if sys.platform in ("win32", "cygwin"):
  60. subDirs = ["bin"]
  61. filesToCheck = [
  62. ("11g", "oraocci11.dll"),
  63. ("10g", "oraocci10.dll"),
  64. ("9i", "oraclient9.dll")
  65. ]
  66. elif sys.platform == "darwin":
  67. subDirs = ["lib"]
  68. filesToCheck = [
  69. ("11g", "libclntsh.dylib.11.1"),
  70. ("10g", "libclntsh.dylib.10.1"),
  71. ("9i", "libclntsh.dylib.9.0")
  72. ]
  73. else:
  74. if struct.calcsize("P") == 4:
  75. subDirs = ["lib", "lib32"]
  76. else:
  77. subDirs = ["lib", "lib64"]
  78. filesToCheck = [
  79. ("11g", "libclntsh.so.11.1"),
  80. ("10g", "libclntsh.so.10.1"),
  81. ("9i", "libclntsh.so.9.0")
  82. ]
  83. for version, baseFileName in filesToCheck:
  84. fileName = os.path.join(directoryToCheck, baseFileName)
  85. if os.path.exists(fileName):
  86. if os.path.basename(directoryToCheck).lower() == "bin":
  87. oracleHome = os.path.dirname(directoryToCheck)
  88. else:
  89. oracleHome = directoryToCheck
  90. oracleLibDir = directoryToCheck
  91. oracleVersion = version
  92. return True
  93. for subDir in subDirs:
  94. fileName = os.path.join(directoryToCheck, subDir, baseFileName)
  95. if os.path.exists(fileName):
  96. oracleHome = directoryToCheck
  97. oracleLibDir = os.path.join(directoryToCheck, subDir)
  98. oracleVersion = version
  99. return True
  100. dirName = os.path.dirname(directoryToCheck)
  101. fileName = os.path.join(dirName, subDir, baseFileName)
  102. if os.path.exists(fileName):
  103. oracleHome = dirName
  104. oracleLibDir = os.path.join(dirName, subDir)
  105. oracleVersion = version
  106. return True
  107. oracleHome = oracleVersion = oracleLibDir = None
  108. return False
  109. # try to determine the Oracle home
  110. userOracleHome = os.environ.get("ORACLE_HOME", os.environ.get("ORACLE_INSTANTCLIENT_HOME"))
  111. if userOracleHome is not None:
  112. if not CheckOracleHome(userOracleHome):
  113. messageFormat = "Oracle home (%s) does not refer to an " \
  114. "9i, 10g or 11g installation."
  115. raise DistutilsSetupError(messageFormat % userOracleHome)
  116. else:
  117. for path in os.environ["PATH"].split(os.pathsep):
  118. if CheckOracleHome(path):
  119. break
  120. if oracleHome is None:
  121. print >>sys.stderr, "cannot locate an Oracle software installation. skipping"
  122. sys.exit(0)
  123. # define some variables
  124. if sys.platform == "win32":
  125. libDirs = [os.path.join(oracleHome, "bin"), oracleHome,
  126. os.path.join(oracleHome, "oci", "lib", "msvc"),
  127. os.path.join(oracleHome, "sdk", "lib", "msvc")]
  128. possibleIncludeDirs = ["oci/include", "rdbms/demo", "sdk/include"]
  129. includeDirs = []
  130. for dir in possibleIncludeDirs:
  131. path = os.path.normpath(os.path.join(oracleHome, dir))
  132. if os.path.isdir(path):
  133. includeDirs.append(path)
  134. if not includeDirs:
  135. message = "cannot locate Oracle include files in %s" % oracleHome
  136. raise DistutilsSetupError(message)
  137. libs = ["oci"]
  138. elif sys.platform == "cygwin":
  139. includeDirs = ["/usr/include", "rdbms/demo", "rdbms/public", \
  140. "network/public", "oci/include"]
  141. libDirs = ["bin", "lib"]
  142. for i in range(len(includeDirs)):
  143. includeDirs[i] = os.path.join(oracleHome, includeDirs[i])
  144. for i in range(len(libDirs)):
  145. libDirs[i] = os.path.join(oracleHome, libDirs[i])
  146. libs = ["oci"]
  147. else:
  148. libDirs = [oracleLibDir]
  149. libs = ["clntsh"]
  150. possibleIncludeDirs = ["rdbms/demo", "rdbms/public", "network/public",
  151. "sdk/include"]
  152. if sys.platform == "darwin":
  153. possibleIncludeDirs.append("plsql/public")
  154. includeDirs = []
  155. for dir in possibleIncludeDirs:
  156. path = os.path.join(oracleHome, dir)
  157. if os.path.isdir(path):
  158. includeDirs.append(path)
  159. if not includeDirs:
  160. path = os.path.join(oracleLibDir, "include")
  161. if os.path.isdir(path):
  162. includeDirs.append(path)
  163. if not includeDirs:
  164. path = re.sub("lib(64)?", "include", oracleHome)
  165. if os.path.isdir(path):
  166. includeDirs.append(path)
  167. if not includeDirs:
  168. raise DistutilsSetupError("cannot locate Oracle include files")
  169. # NOTE: on HP-UX Itanium with Oracle 10g you need to add the library "ttsh10"
  170. # to the list of libraries along with "clntsh"; since I am unable to test, I'll
  171. # leave this as a comment until someone can verify when this is required
  172. # without making other cases where sys.platform == "hp-ux11" stop working
  173. # setup extra link and compile args
  174. extraCompileArgs = ["-DBUILD_VERSION=%s" % BUILD_VERSION]
  175. extraLinkArgs = []
  176. if sys.platform == "aix4":
  177. extraCompileArgs.append("-qcpluscmt")
  178. elif sys.platform == "aix5":
  179. extraCompileArgs.append("-DAIX5")
  180. elif sys.platform == "cygwin":
  181. extraCompileArgs.append("-mno-cygwin")
  182. extraLinkArgs.append("-Wl,--enable-runtime-pseudo-reloc")
  183. elif sys.platform == "darwin":
  184. extraLinkArgs.append("-shared-libgcc")
  185. # force the inclusion of an RPATH linker directive if desired; this will
  186. # eliminate the need for setting LD_LIBRARY_PATH but it also means that this
  187. # location will be the only location searched for the Oracle client library
  188. if "FORCE_RPATH" in os.environ:
  189. extraLinkArgs.append("-Wl,-rpath,%s" % oracleLibDir)
  190. # tweak distribution full name to include the Oracle version
  191. class Distribution(distutils.dist.Distribution):
  192. def get_fullname_with_oracle_version(self):
  193. name = self.metadata.get_fullname()
  194. return "%s-%s" % (name, oracleVersion)
  195. # tweak the RPM build command to include the Python and Oracle version
  196. class bdist_rpm(distutils.command.bdist_rpm.bdist_rpm):
  197. def run(self):
  198. distutils.command.bdist_rpm.bdist_rpm.run(self)
  199. specFile = os.path.join(self.rpm_base, "SPECS",
  200. "%s.spec" % self.distribution.get_name())
  201. queryFormat = "%{name}-%{version}-%{release}.%{arch}.rpm"
  202. command = "rpm -q --qf '%s' --specfile %s" % (queryFormat, specFile)
  203. origFileName = os.popen(command).read()
  204. parts = origFileName.split("-")
  205. parts.insert(2, oracleVersion)
  206. parts.insert(3, "py%s%s" % sys.version_info[:2])
  207. newFileName = "-".join(parts)
  208. self.move_file(os.path.join("dist", origFileName),
  209. os.path.join("dist", newFileName))
  210. # tweak the build directories to include the Oracle version
  211. class build(distutils.command.build.build):
  212. def finalize_options(self):
  213. import distutils.util
  214. import os
  215. import sys
  216. platSpecifier = ".%s-%s-%s" % \
  217. (distutils.util.get_platform(), sys.version[0:3],
  218. oracleVersion)
  219. if self.build_platlib is None:
  220. self.build_platlib = os.path.join(self.build_base,
  221. "lib%s" % platSpecifier)
  222. if self.build_temp is None:
  223. self.build_temp = os.path.join(self.build_base,
  224. "temp%s" % platSpecifier)
  225. distutils.command.build.build.finalize_options(self)
  226. class test(distutils.core.Command):
  227. description = "run the test suite for the extension"
  228. user_options = []
  229. def finalize_options(self):
  230. pass
  231. def initialize_options(self):
  232. pass
  233. def run(self):
  234. self.run_command("build")
  235. buildCommand = self.distribution.get_command_obj("build")
  236. sys.path.insert(0, os.path.abspath("test"))
  237. sys.path.insert(0, os.path.abspath(buildCommand.build_lib))
  238. if sys.version_info[0] < 3:
  239. execfile(os.path.join("test", "test.py"))
  240. else:
  241. fileName = os.path.join("test", "test3k.py")
  242. exec(open(fileName).read())
  243. commandClasses = dict(build = build, bdist_rpm = bdist_rpm, test = test)
  244. # tweak the Windows installer names to include the Oracle version
  245. if distutils.command.bdist_msi is not None:
  246. class bdist_msi(distutils.command.bdist_msi.bdist_msi):
  247. def run(self):
  248. origMethod = self.distribution.get_fullname
  249. self.distribution.get_fullname = \
  250. self.distribution.get_fullname_with_oracle_version
  251. distutils.command.bdist_msi.bdist_msi.run(self)
  252. self.distribution.get_fullname = origMethod
  253. commandClasses["bdist_msi"] = bdist_msi
  254. if distutils.command.bdist_wininst is not None:
  255. class bdist_wininst(distutils.command.bdist_wininst.bdist_wininst):
  256. def run(self):
  257. origMethod = self.distribution.get_fullname
  258. self.distribution.get_fullname = \
  259. self.distribution.get_fullname_with_oracle_version
  260. distutils.command.bdist_wininst.bdist_wininst.run(self)
  261. self.distribution.get_fullname = origMethod
  262. commandClasses["bdist_wininst"] = bdist_wininst
  263. # define classifiers for the package index
  264. classifiers = [
  265. "Development Status :: 6 - Mature",
  266. "Intended Audience :: Developers",
  267. "License :: OSI Approved :: Python Software Foundation License",
  268. "Natural Language :: English",
  269. "Operating System :: OS Independent",
  270. "Programming Language :: C",
  271. "Programming Language :: Python",
  272. "Programming Language :: Python :: 2",
  273. "Programming Language :: Python :: 3",
  274. "Topic :: Database"
  275. ]
  276. # setup the extension
  277. extension = Extension(
  278. name = "cx_Oracle",
  279. include_dirs = includeDirs,
  280. libraries = libs,
  281. library_dirs = libDirs,
  282. extra_compile_args = extraCompileArgs,
  283. extra_link_args = extraLinkArgs,
  284. sources = ["cx_Oracle.c"],
  285. depends = ["Buffer.c", "Callback.c", "Connection.c", "Cursor.c",
  286. "CursorVar.c", "DateTimeVar.c", "Environment.c", "Error.c",
  287. "ExternalLobVar.c", "ExternalObjectVar.c", "IntervalVar.c",
  288. "LobVar.c", "LongVar.c", "NumberVar.c", "ObjectType.c",
  289. "ObjectVar.c", "SessionPool.c", "StringVar.c",
  290. "Subscription.c", "TimestampVar.c", "Transforms.c",
  291. "Variable.c"])
  292. # perform the setup
  293. setup(
  294. name = "cx_Oracle",
  295. version = BUILD_VERSION,
  296. distclass = Distribution,
  297. description = "Python interface to Oracle",
  298. data_files = dataFiles,
  299. cmdclass = commandClasses,
  300. options = dict(bdist_rpm = dict(doc_files = docFiles)),
  301. long_description = \
  302. "Python interface to Oracle conforming to the Python DB API 2.0 "
  303. "specification.\n"
  304. "See http://www.python.org/topics/database/DatabaseAPI-2.0.html.",
  305. author = "Anthony Tuininga",
  306. author_email = "anthony.tuininga@gmail.com",
  307. url = "http://cx-oracle.sourceforge.net",
  308. ext_modules = [extension],
  309. keywords = "Oracle",
  310. license = "Python Software Foundation License",
  311. classifiers = classifiers)