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

Last change on this file since 5008 was 4813, checked in by ole, 17 years ago

Cosmetics

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