source: anuga_core/source/anuga/utilities/compile.py @ 4765

Last change on this file since 4765 was 4765, checked in by duncan, 16 years ago

bug fix

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