source: anuga_work/development/anuga_1d/compile.py @ 7818

Last change on this file since 7818 was 6453, checked in by steve, 15 years ago

Added Padarn's (2008/2009 summer student) files

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