1import config.base
2
3import os
4
5class Configure(config.base.Configure):
6  def __init__(self, framework):
7    config.base.Configure.__init__(self, framework)
8    self.headerPrefix = ''
9    self.substPrefix  = ''
10    self.include      = None
11    self.lib          = None
12    self.isShared     = False
13    return
14
15  def __str__(self):
16    return ''
17
18  def setupDependencies(self, framework):
19    config.base.Configure.setupDependencies(self, framework)
20    self.compilers = framework.require('config.compilers', self)
21    self.headers   = framework.require('config.headers', self)
22    self.libraries = framework.require('config.libraries', self)
23    return
24
25  def configureDisutils(self):
26    '''Check that disutils.sysconfig is functional, and can return the required config vars'''
27    try:
28      try:
29        import distutils.sysconfig
30      except ImportError as e:
31        self.logPrint('Error importing distutils.sysconfig: '+str(e))
32        raise RuntimeError('Python is not fully installed. Perhaps python-devel package missing? Please consult your packing system.')
33
34      try:
35        distutils.sysconfig.get_python_inc()
36        distutils.sysconfig.get_python_inc(1)
37      except distutils.sysconfig.DistutilsPlatformError as e:
38        self.logPrint('Error finding Python include directories: '+str(e))
39        raise RuntimeError('Python is not fully installed. Perhaps python-devel package missing? Please consult your packing system.')
40
41      try:
42        distutils.sysconfig.get_config_var('LDFLAGS')
43        distutils.sysconfig.get_config_var('LIBS')
44        distutils.sysconfig.get_config_var('SYSLIBS')
45      except distutils.sysconfig.DistutilsPlatformError as e:
46        self.logPrint('Error finding Python libraries: '+str(e))
47        raise RuntimeError('Python is not fully installed. Perhaps python-devel package missing? Please consult your packing system.')
48
49      try:
50        distutils.sysconfig.get_config_var('LIBDIR')
51        distutils.sysconfig.get_config_var('LIBPL')
52        distutils.sysconfig.get_config_var('LDLIBRARY')
53        distutils.sysconfig.get_config_var('SO')
54      except distutils.sysconfig.DistutilsPlatformError as e:
55        self.logPrint('Error finding Python shared library: '+str(e))
56        raise RuntimeError('Python is not fully installed. Perhaps python-devel package missing? Please consult your packing system.')
57
58      try:
59        distutils.sysconfig.get_config_var('BINDIR')
60        distutils.sysconfig.get_config_var('PYTHON')
61      except distutils.sysconfig.DistutilsPlatformError as e:
62        self.logPrint('Error finding Python executable: '+str(e))
63        raise RuntimeError('Python is not fully installed. Perhaps python-devel package missing? Please consult your packing system.')
64    except Exception as e:
65      self.logPrint('I do not know what went wrong: '+str(e))
66      raise RuntimeError('Python is not fully installed. Perhaps python-devel package missing? Please consult your packing system.')
67    return
68
69  def checkInclude(self, includeDir):
70    '''Check that Python.h is present'''
71    oldFlags = self.compilers.CPPFLAGS
72    self.compilers.CPPFLAGS += ' '+' '.join([self.headers.getIncludeArgument(inc) for inc in includeDir])
73    found = self.checkPreprocess('#include <Python.h>\n')
74    self.compilers.CPPFLAGS = oldFlags
75    return found
76
77  def checkPythonLink(self, includes, body, cleanup = 1, codeBegin = None, codeEnd = None, shared = 0):
78    '''Analogous to checkLink(), but the Python includes and libraries are automatically provided'''
79    success  = 0
80    oldFlags = self.compilers.CPPFLAGS
81    oldLibs  = self.compilers.LIBS
82    self.compilers.CPPFLAGS += ' '+' '.join([self.headers.getIncludeArgument(inc) for inc in self.include])
83    self.compilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.lib])+' '+self.compilers.LIBS
84    if self.checkLink(includes, body, cleanup, codeBegin, codeEnd, shared):
85      success = 1
86    self.compilers.CPPFLAGS = oldFlags
87    self.compilers.LIBS = oldLibs
88    return success
89
90  def configurePythonLibraries(self):
91    import distutils.sysconfig
92
93    # Check for Python headers
94    inc = [distutils.sysconfig.get_python_inc(), distutils.sysconfig.get_python_inc(1)]
95    if not self.checkInclude(inc):
96      raise RuntimeError('Unable to locate Python headers')
97    self.include = inc
98    # Check for Python dynamic library
99    dylib = distutils.sysconfig.get_config_var('LDLIBRARY')
100    if not dylib:
101      raise RuntimeError('LDLIBRARY variable is missing from disutils database');
102    libDirs = [distutils.sysconfig.get_config_var('LIBDIR'),
103               distutils.sysconfig.get_config_var('LIBPL'),
104               os.path.join('/System', 'Library', 'Frameworks'),
105               os.path.join('/Library', 'Frameworks')]
106    lib = None
107    for libDir in libDirs:
108      if not libDir: continue
109      lib = os.path.join(libDir, dylib)
110      if os.path.isfile(lib):
111        break
112    if lib is None:
113      raise RuntimeError("Cannot locate Python dynamic libraries");
114    # Remove any version numbers from the library name
115    if distutils.sysconfig.get_config_var('SO'):
116      ext = distutils.sysconfig.get_config_var('SO')
117      if os.path.isfile(lib.split(ext)[0]+ext):
118        lib = lib.split(ext)[0]+ext
119    # Add any additional libraries needed for the link
120    self.lib = [lib]
121    if distutils.sysconfig.get_config_var('LIBS'):
122      flags = distutils.sysconfig.get_config_var('LIBS')
123      if distutils.sysconfig.get_config_var('LDFLAGS'):
124        flags = distutils.sysconfig.get_config_var('LDFLAGS')+' '+flags
125      self.lib.extend(self.splitLibs(flags))
126    if distutils.sysconfig.get_config_var('SYSLIBS'):
127      self.lib.extend(self.splitLibs(distutils.sysconfig.get_config_var('SYSLIBS')))
128    # Verify that the Python library is a shared library
129    try:
130      self.isShared = self.libraries.checkShared('#include <Python.h>\n', 'Py_Initialize', 'Py_IsInitialized', 'Py_Finalize', checkLink = self.checkPythonLink, libraries = self.lib, initArgs = '', noCheckArg = 1)
131    except RuntimeError as e:
132      raise RuntimeError('Python shared library check failed, probably due to inability to link Python libraries or a bad interaction with the shared linker.\nSuggest running with --with-python=0 if you do not need Python. Otherwise send configure.log to petsc-maint@mcs.anl.gov')
133    return
134
135  def setOutput(self):
136    '''Add defines and substitutions
137       - PYTHON_INCLUDE and PYTHON_LIB are command line arguments for the compile and link
138       - PYTHON_INCLUDE_DIR is the directory containing mpi.h
139       - PYTHON_LIBRARY is the list of Python libraries'''
140    if self.include:
141      self.addMakeMacro('PYTHON_INCLUDE',     ' '.join(['-I'+inc for inc in self.include]))
142      self.addSubstitution('PYTHON_INCLUDE',     ' '.join(['-I'+inc for inc in self.include]))
143      self.addSubstitution('PYTHON_INCLUDE_DIR', self.include[0])
144    else:
145      self.addSubstitution('PYTHON_INCLUDE',     '')
146      self.addSubstitution('PYTHON_INCLUDE_DIR', '')
147    if self.lib:
148      self.addMakeMacro('PYTHON_LIB',     ' '.join(map(self.libraries.getLibArgument, self.lib)))
149      self.addSubstitution('PYTHON_LIB',     ' '.join(map(self.libraries.getLibArgument, self.lib)))
150      self.addSubstitution('PYTHON_LIBRARY', self.lib)
151    else:
152      self.addSubstitution('PYTHON_LIB',     '')
153      self.addSubstitution('PYTHON_LIBRARY', '')
154    return
155
156  def configure(self):
157    self.executeTest(self.configureDisutils)
158    self.executeTest(self.configurePythonLibraries)
159    self.setOutput()
160    return
161