source: anuga_core/source_numpy_conversion/anuga/utilities/compile.py @ 5902

Last change on this file since 5902 was 5902, checked in by rwilson, 16 years ago

NumPy? conversion.

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