summaryrefslogtreecommitdiff
path: root/setup.py
diff options
context:
space:
mode:
authorFederico Di Gregorio <fog@initd.org>2007-04-11 04:16:00 +0000
committerFederico Di Gregorio <fog@initd.org>2007-04-11 04:16:00 +0000
commit2a6b523506b64d6949cd46d64a2a76014922de7f (patch)
treefd51b922c74183c0857f322260286069db77d808 /setup.py
parentd6f2aa27b7f760e745cc718773183641bd9915ed (diff)
downloadpsycopg2-2a6b523506b64d6949cd46d64a2a76014922de7f.tar.gz
Fixed crash and win32 patches.
Diffstat (limited to 'setup.py')
-rw-r--r--setup.py200
1 files changed, 160 insertions, 40 deletions
diff --git a/setup.py b/setup.py
index 664018f..8f91274 100644
--- a/setup.py
+++ b/setup.py
@@ -13,13 +13,13 @@
# for more details.
"""Python-PostgreSQL Database Adapter
-
+
psycopg is a PostgreSQL database adapter for the Python programming
language. This is version 2, a complete rewrite of the original code to
provide new-style classes for connection and cursor objects and other sweet
candies. Like the original, psycopg 2 was written with the aim of being
very small and fast, and stable as a rock.
-
+
psycopg is different from the other database adapter because it was
designed for heavily multi-threaded applications that create and destroy
lots of cursors and make a conspicuous number of concurrent INSERTs or
@@ -44,8 +44,10 @@ Operating System :: Unix
"""
import os
+import os.path
import sys
import popen2
+import ConfigParser
from distutils.core import setup, Extension
from distutils.errors import DistutilsFileError
from distutils.command.build_ext import build_ext
@@ -55,6 +57,8 @@ from distutils.ccompiler import get_default_compiler
PSYCOPG_VERSION = '2.0.6b1'
version_flags = []
+PLATFORM_IS_WINDOWS = sys.platform.lower().startswith('win')
+
# to work around older distutil limitations
if sys.version < '2.2.3':
from distutils.dist import DistributionMetadata
@@ -67,86 +71,127 @@ def get_pg_config(kind, pg_config="pg_config"):
if not r:
raise Warning(p[2].readline())
return r
-
+
class psycopg_build_ext(build_ext):
"""Conditionally complement the setup.cfg options file.
-
+
This class configures the include_dirs, libray_dirs, libraries
options as required by the system. Most of the configuration happens
in finalize_options() method.
-
+
If you want to set up the build step for a peculiar platform, add a
method finalize_PLAT(), where PLAT matches your sys.platform.
"""
user_options = build_ext.user_options[:]
user_options.extend([
('use-pydatetime', None,
- "Use Python datatime objects for date and time representation."),
+ "Use Python datatime objects for date and time representation."),
('pg-config=', None,
"The name of the pg_config binary and/or full path to find it"),
('use-decimal', None,
"Use Decimal type even on Python 2.3 if the module is provided."),
])
-
+
boolean_options = build_ext.boolean_options[:]
boolean_options.extend(('use-pydatetime', 'use-decimal'))
-
+
DEFAULT_PG_CONFIG = "pg_config"
-
+
def initialize_options(self):
build_ext.initialize_options(self)
self.use_pg_dll = 1
self.pgdir = None
- self.pg_config = self.DEFAULT_PG_CONFIG
self.mx_include_dir = None
-
+
+ self.pg_config = self.autodetect_pg_config_path()
+
def get_compiler(self):
- """Return the c compiler to compile extensions.
+ """Return the name of the C compiler used to compile extensions.
If a compiler was not explicitely set (on the command line, for
example), fall back on the default compiler.
"""
- return self.compiler or get_default_compiler()
+ if self.compiler:
+ # distutils doesn't keep the type of self.compiler uniform; we
+ # compensate:
+ if isinstance(self.compiler, str):
+ name = self.compiler
+ else:
+ name = self.compiler.compiler_type
+ else:
+ name = get_default_compiler()
+ return name
def get_pg_config(self, kind):
return get_pg_config(kind, self.pg_config)
- def build_extensions(self):
- # Linking against this library causes psycopg2 to crash
- # on Python >= 2.4. Maybe related to strdup calls, cfr.
- # http://mail.python.org/pipermail/distutils-sig/2005-April/004433.html
- if self.get_compiler().compiler_type == "mingw32" \
- and 'msvcr71' in self.compiler.dll_libraries:
- self.compiler.dll_libraries.remove('msvcr71')
-
- build_ext.build_extensions(self)
-
def finalize_win32(self):
"""Finalize build system configuration on win32 platform."""
+ import struct
+ sysVer = sys.version_info[:2]
+
+ # Add compiler-specific arguments:
+ extra_compiler_args = []
+
+ compiler_name = self.get_compiler().lower()
+ compiler_is_msvc = compiler_name.startswith('msvc')
+ compiler_is_mingw = compiler_name.startswith('mingw')
+ if compiler_is_msvc:
+ # If we're using MSVC 7.1 or later on a 32-bit platform, add the
+ # /Wp64 option to generate warnings about Win64 portability
+ # problems.
+ if sysVer >= (2,4) and struct.calcsize('P') == 4:
+ extra_compiler_args.append('/Wp64')
+ elif compiler_is_mingw:
+ # Default MinGW compilation of Python extensions on Windows uses
+ # only -O:
+ extra_compiler_args.append('-O3')
+
+ # GCC-compiled Python on non-Windows platforms is built with strict
+ # aliasing disabled, but that must be done explicitly on Windows to
+ # avoid large numbers of warnings for perfectly idiomatic Python C
+ # API code.
+ extra_compiler_args.append('-fno-strict-aliasing')
+
+ # Force correct C runtime library linkage:
+ if sysVer <= (2,3):
+ # Yes: 'msvcr60', rather than 'msvcrt', is the correct value
+ # on the line below:
+ self.libraries.append('msvcr60')
+ elif sysVer in ((2,4), (2,5)):
+ self.libraries.append('msvcr71')
+ # Beyond Python 2.5, we take our chances on the default C runtime
+ # library, because we don't know what compiler those future
+ # versions of Python will use.
+
+ for exten in ext: # ext is a global list of Extension objects
+ exten.extra_compile_args.extend(extra_compiler_args)
+ # End of add-compiler-specific arguments section.
+
self.libraries.append("ws2_32")
self.libraries.append("advapi32")
- if self.get_compiler() == "msvc":
+ if compiler_is_msvc:
# MSVC requires an explicit "libpq"
self.libraries.remove("pq")
self.libraries.append("libpq")
self.libraries.append("shfolder")
- for path in self.library_dirs:
- if os.path.isfile(os.path.join(path, "ms", "libpq.lib")):
- self.library_dirs.append(os.path.join(path, "ms"))
+ for path in self.library_dirs:
+ if os.path.isfile(os.path.join(path, "ms", "libpq.lib")):
+ self.library_dirs.append(os.path.join(path, "ms"))
break
-
+
def finalize_darwin(self):
"""Finalize build system configuration on darwin platform."""
self.libraries.append('ssl')
self.libraries.append('crypto')
-
+
def finalize_options(self):
"""Complete the build system configuation."""
build_ext.finalize_options(self)
- self.include_dirs.append(".")
+ self.include_dirs.append(".")
self.libraries.append("pq")
-
+
try:
self.library_dirs.append(self.get_pg_config("libdir"))
self.include_dirs.append(self.get_pg_config("includedir"))
@@ -168,10 +213,86 @@ class psycopg_build_ext(build_ext):
else:
sys.stderr.write("Error: %s" % str(w))
sys.exit(1)
-
+
if hasattr(self, "finalize_" + sys.platform):
getattr(self, "finalize_" + sys.platform)()
-
+
+ def autodetect_pg_config_path(self):
+ res = None
+
+ if PLATFORM_IS_WINDOWS:
+ res = self.autodetect_pg_config_path_windows()
+
+ return res or self.DEFAULT_PG_CONFIG
+
+ def autodetect_pg_config_path_windows(self):
+ # Find the first PostgreSQL installation listed in the registry and
+ # return the full path to its pg_config utility.
+ #
+ # This autodetection is performed *only* if the following conditions
+ # hold:
+ #
+ # 1) The pg_config utility is not already available on the PATH:
+ if os.popen('pg_config').close() is None: # .close()->None == success
+ return None
+ # 2) The user has not specified any of the following settings in
+ # setup.cfg:
+ # - pg_config
+ # - include_dirs
+ # - library_dirs
+ for settingName in ('pg_config', 'include_dirs', 'library_dirs'):
+ try:
+ val = parser.get('build_ext', settingName)
+ except ConfigParser.NoOptionError:
+ pass
+ else:
+ if val.strip() != '':
+ return None
+ # end of guard conditions
+
+ import _winreg
+
+ pg_inst_base_dir = None
+ pg_config_path = None
+
+ reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
+ pg_inst_list_key = _winreg.OpenKey(reg,
+ 'SOFTWARE\\PostgreSQL\\Installations'
+ )
+ try:
+ # Determine the name of the first subkey, if any:
+ try:
+ first_sub_key_name = _winreg.EnumKey(pg_inst_list_key, 0)
+ except EnvironmentError:
+ first_sub_key_name = None
+
+ if first_sub_key_name is not None:
+ pg_first_inst_key = _winreg.OpenKey(reg,
+ 'SOFTWARE\\PostgreSQL\\Installations\\'
+ + first_sub_key_name
+ )
+ try:
+ pg_inst_base_dir = _winreg.QueryValueEx(
+ pg_first_inst_key, 'Base Directory'
+ )[0]
+ finally:
+ _winreg.CloseKey(pg_first_inst_key)
+ finally:
+ _winreg.CloseKey(pg_inst_list_key)
+
+ if pg_inst_base_dir and os.path.exists(pg_inst_base_dir):
+ pg_config_path = os.path.join(pg_inst_base_dir, 'bin',
+ 'pg_config.exe'
+ )
+ # Support unicode paths, if this version of Python provides the
+ # necessary infrastructure:
+ if hasattr(sys, 'getfilesystemencoding'):
+ pg_config_path = pg_config_path.encode(
+ sys.getfilesystemencoding()
+ )
+
+ return pg_config_path
+
# let's start with macro definitions (the ones not already in setup.cfg)
define_macros = []
include_dirs = []
@@ -183,7 +304,7 @@ define_macros.append(('PY_MINOR_VERSION', str(sys.version_info[1])))
# some macros related to python versions and features
if sys.version_info[0] >= 2 and sys.version_info[1] >= 3:
define_macros.append(('HAVE_PYBOOL','1'))
-
+
# gather information to build the extension module
ext = [] ; data_files = []
@@ -191,13 +312,12 @@ ext = [] ; data_files = []
sources = [
'psycopgmodule.c', 'pqpath.c', 'typecast.c',
- 'microprotocols.c', 'microprotocols_proto.c',
+ 'microprotocols.c', 'microprotocols_proto.c',
'connection_type.c', 'connection_int.c', 'cursor_type.c', 'cursor_int.c',
'adapter_qstring.c', 'adapter_pboolean.c', 'adapter_binary.c',
'adapter_asis.c', 'adapter_list.c']
-from ConfigParser import ConfigParser
-parser = ConfigParser()
+parser = ConfigParser.ConfigParser()
parser.read('setup.cfg')
# Choose if to use Decimal type
@@ -230,7 +350,7 @@ if os.path.exists(os.path.join(get_python_inc(plat_specific=1),"datetime.h")):
sources.append('adapter_datetime.c')
have_pydatetime = True
version_flags.append('dt')
-
+
# now decide which package will be the default for date/time typecasts
if have_pydatetime and use_pydatetime \
or have_pydatetime and not have_mxdatetime:
@@ -258,8 +378,8 @@ if version_flags:
PSYCOPG_VERSION_EX = PSYCOPG_VERSION + " (%s)" % ' '.join(version_flags)
else:
PSYCOPG_VERSION_EX = PSYCOPG_VERSION
-
-if sys.platform != 'win32':
+
+if not PLATFORM_IS_WINDOWS:
define_macros.append(('PSYCOPG_VERSION', '"'+PSYCOPG_VERSION_EX+'"'))
else:
define_macros.append(('PSYCOPG_VERSION', '\\"'+PSYCOPG_VERSION_EX+'\\"'))