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

Last change on this file since 4811 was 4811, checked in by ole, 16 years ago

Added error message in case compiler can't be found.

File size: 10.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
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  # Verify that compiler can be executed
153  s = '%s --version' %compiler
154  s = s + ' > /dev/null' # Suppress output
155  err = os.system(s)
156  if err != 0:
157      msg = 'Unable to execute compiler: %s.' %compiler
158      msg += 'Make sure it is available on the system path.'
159      msg += 'One way is to try to check that %s runs on ' %compiler
160      msg += 'the commandline.'
161      raise Exception, msg
162     
163       
164  # Find location of include files
165  #
166  if sys.platform == 'win32':  #Windows
167    python_include = os.path.join(sys.exec_prefix, 'include')   
168  else: 
169    python_include = os.path.join(os.path.join(sys.exec_prefix, 'include'),
170                                  'python' + version)
171
172  # Check existence of Python.h
173  #
174  headerfile = python_include + os.sep + 'Python.h'
175  try:
176    open(headerfile, 'r')
177  except:
178    raise """Did not find Python header file %s.
179    Make sure files for Python C-extensions are installed.
180    In debian linux, for example, you need to install a
181    package called something like python2.3-dev""" %headerfile
182
183
184
185  #Add Python path + utilities to includelist (see ticket:31)
186  #Assume there is only one 'utilities' dir under path dirs
187 
188  utilities_include_dir = None
189  for pathdir in sys.path:
190
191    utilities_include_dir = pathdir + os.sep + 'utilities'
192    #print pathdir
193    #print utilities_include_dir
194    try:
195      os.stat(utilities_include_dir)
196    except OSError:
197      pass
198    else:
199      #print 'Found %s to be used as include dir' %utilities_include_dir
200      break
201
202  # This is hacky since it
203  # assumes the location of the compile_all that determines buildroot
204  try:
205    utilities_include_dir = buildroot + os.sep + "source" + os.sep + "anuga" \
206                            + os.sep + 'utilities'
207  except:
208    # This will make compile work locally
209    utilities_include_dir = '.'
210    utilities_include_dir = '../utilities'
211
212
213   
214  try:
215    os.stat(utilities_include_dir)
216  except OSError: 
217    utilities_include_dir = buildroot + os.sep + 'utilities'
218 
219 
220 
221  # Check filename(s)
222  #
223  object_files = ''
224  for FN in FNs:       
225    root, ext = os.path.splitext(FN)
226    if ext == '':
227      FN = FN + '.c'
228    elif ext.lower() != '.c':
229      raise Exception, "Unrecognised extension: " + FN
230   
231    try:
232      open(FN, 'r')
233    except:
234      raise Exception, "Could not open: " + FN
235
236    if not object_files: root1 = root  #Remember first filename       
237    object_files += root + '.o ' 
238 
239 
240    # Compile
241    #
242    if utilities_include_dir is None:   
243      s = '%s -c %s -I"%s" -o "%s.o" -Wall -O3'\
244          %(compiler, FN, python_include, root)
245    else:
246      if FN == "triangle.c" or FN == "mesh_engine_c_layer.c":
247        s = '%s -c %s -I"%s" -I"%s" -o "%s.o" -O3 -DTRILIBRARY=1 -DNO_TIMER=1'\
248            %(compiler, FN, python_include, utilities_include_dir, root)
249      else:
250        s = '%s -c %s -I"%s" -I"%s" -o "%s.o" -Wall -O3'\
251            %(compiler, FN, python_include, utilities_include_dir, root)
252
253    if os.name == 'posix' and os.uname()[4] == 'x86_64':
254      #Extra flags for 64 bit architectures
255      #Second clause will always fail on Win32 because uname is UNIX specific
256      #but won't get past first clause
257
258      #FIXME: Which one?
259      #s += ' -fPIC'
260      s += ' -fPIC -m64' 
261     
262     
263    if verbose:
264      print s
265    else:
266      s = s + ' 2> /dev/null' #Suppress errors
267 
268    try:
269      err = os.system(s)
270      if err != 0:
271          raise 'Attempting to compile %s failed - please try manually' %FN
272    except:
273      raise 'Could not compile %s - please try manually' %FN 
274
275 
276  # Make shared library (*.so or *.dll)
277  if libs is "":
278    s = '%s -%s %s -o %s.%s -lm' %(loader, sharedflag, object_files, root1, libext)
279  else:
280    s = '%s -%s %s -o %s.%s "%s" -lm' %(loader, sharedflag, object_files, root1, libext, libs)
281  if verbose:
282    print s
283  else:
284    s = s + ' 2> /dev/null' #Suppress warnings
285 
286  try: 
287    err=os.system(s)
288    if err != 0:       
289        raise 'Atempting to link %s failed - please try manually' %root1     
290  except:
291    raise 'Could not link %s - please try manually' %root1
292   
293
294def can_use_C_extension(filename):
295    """Determine whether specified C-extension
296    can and should be used.
297    """
298
299    from anuga.config import use_extensions
300
301    from os.path import splitext
302
303    root, ext = splitext(filename)
304   
305    C=False
306    if use_extensions:
307        try:
308            s = 'import %s' %root
309            #print s
310            exec(s)
311        except:
312            try:
313                open(filename)
314            except:
315                msg = 'C extension %s cannot be opened' %filename
316                print msg               
317            else:   
318                print '------- Trying to compile c-extension %s' %filename
319           
320                try:
321                    compile(filename)
322                except:
323                    print 'WARNING: Could not compile C-extension %s'\
324                          %filename
325                else:
326                    try:
327                        exec('import %s' %root)
328                    except:
329                        msg = 'C extension %s seems to compile OK, '
330                        msg += 'but it can still not be imported.'
331                        raise msg
332                    else:
333                        C=True
334        else:
335            C=True
336           
337    if not C:
338        pass
339        print 'NOTICE: C-extension %s not used' %filename
340
341    return C
342
343
344def set_python_dll_path():
345  """ Find which of the two usual hiding places the python dll is located.
346
347  If the file can't be found, return None.
348  """
349  import sys
350  from os import access, F_OK
351 
352  version = sys.version[:3]
353  v = version.replace('.','')
354  dllfilename = 'python%s.dll' %(v)
355  libs = os.path.join(sys.exec_prefix,dllfilename)
356
357  is_found = True   
358  if access(libs,F_OK) == 0 :
359    # Hacky - fix if you want
360    libs = os.path.join('c:'+os.sep+'WINNT'+os.sep+'system32',dllfilename)
361    if access(libs,F_OK) == 0 :
362      # could not find the dll
363      libs = os.path.join(sys.exec_prefix,dllfilename)
364      is_found = False
365  return libs, is_found
366
367def check_python_dll():
368  libs, is_found = set_python_dll_path()
369  if not is_found:
370    print "%s not found.\nPlease install.\nIt is available on the web." \
371              %(libs)
372    import sys; sys.exit()
373   
374     
375if __name__ == '__main__':
376  from os.path import splitext
377 
378  if sys.platform == 'win32':
379    check_python_dll()
380  if len(sys.argv) > 1:
381      files = sys.argv[1:]
382      for filename in files:
383          root, ext = splitext(filename)
384
385          if ext <> '.c':
386              print 'WARNING (compile.py): Skipping %s. I only compile C-files.' %filename
387     
388  else: 
389      #path = os.path.split(sys.argv[0])[0] or os.getcwd()
390      path = '.'
391      files = os.listdir(path)
392     
393     
394
395  for filename in files:
396      root, ext = splitext(filename)
397
398      if ext == '.c':
399          for x in ['.dll', '.so']:
400              try:
401                  os.remove(root + x)
402              except:
403                  pass
404
405          print '---------------------------------------'     
406          print 'Trying to compile c-extension %s in %s'\
407                %(filename, os.getcwd())
408          try:
409            if filename == 'triang.c': 
410              compile(['triang.c','triangle.c'])
411            elif  filename == 'mesh_engine_c_layer.c': 
412              compile(['mesh_engine_c_layer.c','triangle.c'])
413            else:
414              compile(filename)
415          except Exception, e:
416              print 'Could not compile C extension %s' %filename
417          else:
418              print 'C extension %s OK' %filename
419          print   
420       
421
Note: See TracBrowser for help on using the repository browser.