source: trunk/anuga_work/development/2010-projects/kv/compile.py @ 8051

Last change on this file since 8051 was 8051, checked in by steve, 13 years ago

Added in Lindon's code

File size: 11.8 KB
Line 
1"""compile.py - compile Python C-extension
2
3   Commandline usage:
4     python compile.py <filename>
5
6   Usage from within Python:
7     import compile
8     compile.compile(<filename>,..)
9
10   Ole Nielsen, Duncan Gray Oct 2001     
11"""     
12
13#NumPy ------------------------------------
14# Something like these lines recommended in "Converting from NUMARRAY to NUMPY"
15import numpy
16I_dirs = '-I"%s" ' % numpy.get_include()
17#NumPy ------------------------------------
18
19# FIXME (Ole): Although this script says it works with a range of compilers,
20# it has only really been used with gcc.
21
22import os, string, sys, types
23
24separation_line = '---------------------------------------'     
25 
26def compile(FNs=None, CC=None, LD = None, SFLAG = None, verbose = 1):
27  """compile(FNs=None, CC=None, LD = None, SFLAG = None):
28 
29     Compile FN(s) using compiler CC (e.g. mpicc),
30     Loader LD and shared flag SFLAG.
31     If CC is absent use default compiler dependent on platform
32     if LD is absent CC is used.
33     if SFLAG is absent platform default is used
34     FNs can be either one filename or a list of filenames
35     In the latter case, the first will be used to name so file.
36  """
37 
38  # Input check
39  #
40  assert not FNs is None, 'No filename provided'
41
42  if not type(FNs) == types.ListType:
43    FNs = [FNs]
44
45
46  libext = 'so' #Default extension (Unix)
47  libs = ''
48  version = sys.version[:3]
49 
50  # Determine platform and compiler
51  #
52  if sys.platform == 'sunos5':  #Solaris
53    if CC:
54      compiler = CC
55    else: 
56      compiler = 'gcc'
57    if LD:
58      loader = LD
59    else: 
60      loader = compiler
61    if SFLAG:
62      sharedflag = SFLAG
63    else: 
64      sharedflag = 'G'
65     
66  elif sys.platform == 'osf1V5':  #Compaq AlphaServer
67    if CC:
68      compiler = CC
69    else: 
70      compiler = 'cc'
71    if LD:
72      loader = LD
73    else: 
74      loader = compiler
75    if SFLAG:
76      sharedflag = SFLAG
77    else: 
78      sharedflag = 'shared'   
79     
80  elif sys.platform == 'linux2':  #Linux
81    if CC:
82      compiler = CC
83    else: 
84      compiler = 'gcc'
85    if LD:
86      loader = LD
87    else: 
88      loader = compiler
89    if SFLAG:
90      sharedflag = SFLAG
91    else: 
92      sharedflag = 'shared'   
93     
94  elif sys.platform == 'darwin':  #Mac OS X:
95    if CC:
96      compiler = CC
97    else: 
98      compiler = 'cc'
99    if LD:
100      loader = LD
101    else: 
102      loader = compiler
103    if SFLAG:
104      sharedflag = SFLAG
105    else: 
106      sharedflag = 'bundle -flat_namespace -undefined suppress'
107
108  elif sys.platform == 'cygwin':  #Cygwin (compilation same as linux)
109    if CC:
110      compiler = CC
111    else: 
112      compiler = 'gcc'
113    if LD:
114      loader = LD
115    else: 
116      loader = compiler
117    if SFLAG:
118      sharedflag = SFLAG
119    else: 
120      sharedflag = 'shared'
121    libext = 'dll'
122    libs = '/lib/python%s/config/libpython%s.dll.a' %(version,version)
123     
124  elif sys.platform == 'win32':  #Windows
125    if CC:
126      compiler = CC
127    else: 
128      compiler = 'gcc.exe' #Some systems require this (a security measure?)
129    if LD:
130      loader = LD
131    else: 
132      loader = compiler
133    if SFLAG:
134      sharedflag = SFLAG
135    else: 
136      sharedflag = 'shared'
137     
138    # As of python2.5, .pyd is the extension for python extension
139    # modules.
140    if sys.version_info[0:2] >= (2, 5):
141      libext = 'pyd'
142    else:
143      libext = 'dll'
144
145    libs, is_found = set_python_dll_path()
146     
147  else:
148    if verbose: print "Unrecognised platform %s - revert to default"\
149                %sys.platform
150   
151    if CC:
152      compiler = CC
153    else: 
154      compiler = 'cc'
155    if LD:
156      loader = LD
157    else: 
158      loader = 'ld'
159    if SFLAG:
160      sharedflag = SFLAG
161    else: 
162      sharedflag = 'G'
163
164
165  # Verify that compiler can be executed
166  print 'Compiler: %s, version ' %compiler,
167  sys.stdout.flush()
168  s = '%s -dumpversion' %(compiler)
169  err = os.system(s)
170  print
171 
172  if err != 0:
173      msg = 'Unable to execute compiler: %s. ' %compiler
174      msg += 'Make sure it is available on the system path.\n'
175      msg += 'One way to check this is to run %s on ' %compiler
176      msg += 'the commandline.'
177      raise Exception, msg   
178
179 
180  # Find location of include files
181  #
182  if sys.platform == 'win32':  #Windows
183    python_include = os.path.join(sys.exec_prefix, 'include')   
184  else: 
185    python_include = os.path.join(os.path.join(sys.exec_prefix, 'include'),
186                                  'python' + version)
187
188  # Check existence of Python.h
189  #
190  headerfile = python_include + os.sep + 'Python.h'
191  try:
192    open(headerfile, 'r')
193  except:
194    raise """Did not find Python header file %s.
195    Make sure files for Python C-extensions are installed.
196    In debian linux, for example, you need to install a
197    package called something like python2.3-dev""" %headerfile
198
199
200
201  # Add Python path + utilities to includelist (see ticket:31)
202  # Assume there is only one 'utilities' dir under path dirs
203 
204  utilities_include_dir = None
205  for pathdir in sys.path:
206
207    utilities_include_dir = pathdir + os.sep + 'utilities'
208    #print pathdir
209    #print utilities_include_dir
210    try:
211      os.stat(utilities_include_dir)
212    except OSError:
213      pass
214    else:
215      #print 'Found %s to be used as include dir' %utilities_include_dir
216      break
217
218  # This is hacky since it
219  # assumes the location of the compile_all that determines buildroot
220  try:
221    utilities_include_dir = buildroot + os.sep + "source" + os.sep + "anuga" \
222                            + os.sep + 'utilities'
223  except:
224    # This will make compile work locally
225    utilities_include_dir = '.'
226    utilities_include_dir = '../utilities'
227
228
229   
230  try:
231    os.stat(utilities_include_dir)
232  except OSError: 
233    utilities_include_dir = buildroot + os.sep + 'utilities'
234 
235 
236 
237  # Check filename(s)
238  #
239  object_files = ''
240  for FN in FNs:       
241    root, ext = os.path.splitext(FN)
242    if ext == '':
243      FN = FN + '.c'
244    elif ext.lower() != '.c':
245      raise Exception, "Unrecognised extension: " + FN
246   
247    try:
248      open(FN, 'r')
249    except:
250      raise Exception, "Could not open: " + FN
251
252    if not object_files: root1 = root  #Remember first filename       
253    object_files += root + '.o ' 
254 
255 
256    # Compile
257    #
258    if utilities_include_dir is None:   
259      s = '%s -c %s -I"%s" -o "%s.o" -Wall -O3'\
260          %(compiler, FN, python_include, root)
261    else:
262      if FN == "triangle.c" or FN == "mesh_engine_c_layer.c":
263        s = '%s -c %s %s -I"%s" -I"%s" -o "%s.o" -O3 -DTRILIBRARY=1 -DNO_TIMER=1'\
264            % (compiler, FN, I_dirs, python_include, utilities_include_dir, root)
265      elif FN == "polygon_ext.c":
266        # gcc 4.3.x is problematic with this file if '-O3' is used
267        s = '%s -c %s %s -I"%s" -I"%s" -o "%s.o" -Wall'\
268            %(compiler, FN, I_dirs, python_include, utilities_include_dir, root)
269      else:
270        s = '%s -c %s %s -I"%s" -I"%s" -o "%s.o" -Wall -O3'\
271            %(compiler, FN, I_dirs, python_include, utilities_include_dir, root)
272
273    if os.name == 'posix' and os.uname()[4] in ['x86_64', 'ia64']:
274      # Extra flags for 64 bit architectures.
275      #   AMD Opteron will give x86_64
276      #   Itanium will give ia64
277      #
278      # Second clause will always fail on Win32 because uname is UNIX specific
279      # but won't get past first clause
280
281      s += ' -fPIC' # Use position independent code for 64 bit archs
282      #s += ' -m64' # Used to be necessary for AMD Opteron
283     
284     
285    if verbose:
286      print s
287
288    # Doesn't work on Windows anyway 
289    #else:
290    #  s = s + ' 2> /dev/null' #Suppress errors
291   
292    try:
293      err = os.system(s)
294      if err != 0:
295          raise 'Attempting to compile %s failed - please try manually' %FN
296    except:
297      raise 'Could not compile %s - please try manually' %FN 
298
299 
300  # Make shared library (*.so or *.dll)
301  if libs is "":
302    s = '%s -%s %s -o %s.%s -lm' %(loader, sharedflag, object_files, root1, libext)
303  else:
304    s = '%s -%s %s -o %s.%s "%s" -lm' %(loader, sharedflag, object_files, root1, libext, libs)
305   
306  if verbose:
307    print s
308
309  # Doesn't work on Windows anyway     
310  #else:
311  #  s = s + ' 2> /dev/null' #Suppress warnings
312 
313  try: 
314    err=os.system(s)
315    if err != 0:       
316        raise 'Attempting to link %s failed - please try manually' %root1     
317  except:
318    raise 'Could not link %s - please try manually' %root1
319   
320
321def can_use_C_extension(filename):
322    """Determine whether specified C-extension
323    can and should be used.
324    """
325
326    from anuga.config import use_extensions
327
328    from os.path import splitext
329
330    root, ext = splitext(filename)
331   
332    C=False
333    if use_extensions:
334        try:
335            s = 'import %s' %root
336            #print s
337            exec(s)
338        except:
339            try:
340                open(filename)
341            except:
342                msg = 'C extension %s cannot be opened' %filename
343                print msg               
344            else:   
345                print '------- Trying to compile c-extension %s' %filename
346           
347                try:
348                    compile(filename)
349                except:
350                    print 'WARNING: Could not compile C-extension %s'\
351                          %filename
352                else:
353                    try:
354                        exec('import %s' %root)
355                    except:
356                        msg = 'C extension %s seems to compile OK, '
357                        msg += 'but it can still not be imported.'
358                        raise msg
359                    else:
360                        C=True
361        else:
362            C=True
363           
364    if not C:
365        pass
366        print 'NOTICE: C-extension %s not used' %filename
367
368    return C
369
370
371def set_python_dll_path():
372  """ On windows, find which of the two usual hiding places the python
373  dll is located.
374
375  If the file can't be found, return None.
376  """
377  import sys
378  from os import access, F_OK
379 
380  version = sys.version[:3]
381  v = version.replace('.','')
382  dllfilename = 'python%s.dll' %(v)
383  libs = os.path.join(sys.exec_prefix,dllfilename)
384
385  is_found = True   
386  if access(libs,F_OK) == 0 :
387    # Sometimes python dll is hidden in %WINDIR%/system32
388    libs = os.path.join(os.environ.get('WINDIR', 'C:\WINNT'), 'system32',
389                        dllfilename)
390    if access(libs,F_OK) == 0 :
391      # could not find the dll
392      libs = os.path.join(sys.exec_prefix,dllfilename)
393      is_found = False
394  return libs, is_found
395
396def check_python_dll():
397  libs, is_found = set_python_dll_path()
398  if not is_found:
399    print "%s not found.\nPlease install.\nIt is available on the web." \
400              %(libs)
401    import sys; sys.exit()
402   
403     
404if __name__ == '__main__':
405  from os.path import splitext
406 
407  if sys.platform == 'win32':
408    check_python_dll()
409  if len(sys.argv) > 1:
410      files = sys.argv[1:]
411      for filename in files:
412          root, ext = splitext(filename)
413
414          if ext <> '.c':
415              print 'WARNING (compile.py): Skipping %s. I only compile C-files.' %filename
416     
417  else: 
418      #path = os.path.split(sys.argv[0])[0] or os.getcwd()
419      path = '.'
420      files = os.listdir(path)
421     
422     
423
424  for filename in files:
425      root, ext = splitext(filename)
426
427      if ext == '.c':
428          for x in ['.dll', '.so']:
429              try:
430                  os.remove(root + x)
431              except:
432                  pass
433
434          print separation_line
435          print 'Trying to compile c-extension %s in %s'\
436                %(filename, os.getcwd())
437          try:
438            if filename == 'triang.c': 
439              compile(['triang.c','triangle.c'])
440            elif  filename == 'mesh_engine_c_layer.c': 
441              compile(['mesh_engine_c_layer.c','triangle.c'])
442            else:
443              compile(filename)
444          except Exception, e:
445              msg = 'Could not compile C extension %s\n' %filename
446              msg += str(e)
447              raise Exception, msg
448          else:
449              print 'C extension %s OK' %filename
450          print   
451       
452
Note: See TracBrowser for help on using the repository browser.