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

Last change on this file since 5917 was 5917, checked in by ole, 15 years ago

Included compile flag for Itanium 64 bit such as the ANU SF super computer.
Most tests pass except for CRC checksums and one other minor thing.

File size: 11.3 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] in ['x86_64', 'ia64']:
264      # Extra flags for 64 bit architectures.
265      #   AMD Opteron will give x86_64
266      #   Itanium will give ia64
267      #
268      # Second clause will always fail on Win32 because uname is UNIX specific
269      # but won't get past first clause
270
271      s += ' -fPIC' # Use position independent code for 64 bit archs
272      #s += ' -m64' # Used to be necessary for AMD Opteron
273     
274     
275    if verbose:
276      print s
277
278    # Doesn't work on Windows anyway 
279    #else:
280    #  s = s + ' 2> /dev/null' #Suppress errors
281   
282    try:
283      err = os.system(s)
284      if err != 0:
285          raise 'Attempting to compile %s failed - please try manually' %FN
286    except:
287      raise 'Could not compile %s - please try manually' %FN 
288
289 
290  # Make shared library (*.so or *.dll)
291  if libs is "":
292    s = '%s -%s %s -o %s.%s -lm' %(loader, sharedflag, object_files, root1, libext)
293  else:
294    s = '%s -%s %s -o %s.%s "%s" -lm' %(loader, sharedflag, object_files, root1, libext, libs)
295   
296  if verbose:
297    print s
298
299  # Doesn't work on Windows anyway     
300  #else:
301  #  s = s + ' 2> /dev/null' #Suppress warnings
302 
303  try: 
304    err=os.system(s)
305    if err != 0:       
306        raise 'Attempting to link %s failed - please try manually' %root1     
307  except:
308    raise 'Could not link %s - please try manually' %root1
309   
310
311def can_use_C_extension(filename):
312    """Determine whether specified C-extension
313    can and should be used.
314    """
315
316    from anuga.config import use_extensions
317
318    from os.path import splitext
319
320    root, ext = splitext(filename)
321   
322    C=False
323    if use_extensions:
324        try:
325            s = 'import %s' %root
326            #print s
327            exec(s)
328        except:
329            try:
330                open(filename)
331            except:
332                msg = 'C extension %s cannot be opened' %filename
333                print msg               
334            else:   
335                print '------- Trying to compile c-extension %s' %filename
336           
337                try:
338                    compile(filename)
339                except:
340                    print 'WARNING: Could not compile C-extension %s'\
341                          %filename
342                else:
343                    try:
344                        exec('import %s' %root)
345                    except:
346                        msg = 'C extension %s seems to compile OK, '
347                        msg += 'but it can still not be imported.'
348                        raise msg
349                    else:
350                        C=True
351        else:
352            C=True
353           
354    if not C:
355        pass
356        print 'NOTICE: C-extension %s not used' %filename
357
358    return C
359
360
361def set_python_dll_path():
362  """ On windows, find which of the two usual hiding places the python
363  dll is located.
364
365  If the file can't be found, return None.
366  """
367  import sys
368  from os import access, F_OK
369 
370  version = sys.version[:3]
371  v = version.replace('.','')
372  dllfilename = 'python%s.dll' %(v)
373  libs = os.path.join(sys.exec_prefix,dllfilename)
374
375  is_found = True   
376  if access(libs,F_OK) == 0 :
377    # Sometimes python dll is hidden in %WINDIR%/system32
378    libs = os.path.join(os.environ.get('WINDIR', 'C:\WINNT'), 'system32',
379                        dllfilename)
380    if access(libs,F_OK) == 0 :
381      # could not find the dll
382      libs = os.path.join(sys.exec_prefix,dllfilename)
383      is_found = False
384  return libs, is_found
385
386def check_python_dll():
387  libs, is_found = set_python_dll_path()
388  if not is_found:
389    print "%s not found.\nPlease install.\nIt is available on the web." \
390              %(libs)
391    import sys; sys.exit()
392   
393     
394if __name__ == '__main__':
395  from os.path import splitext
396 
397  if sys.platform == 'win32':
398    check_python_dll()
399  if len(sys.argv) > 1:
400      files = sys.argv[1:]
401      for filename in files:
402          root, ext = splitext(filename)
403
404          if ext <> '.c':
405              print 'WARNING (compile.py): Skipping %s. I only compile C-files.' %filename
406     
407  else: 
408      #path = os.path.split(sys.argv[0])[0] or os.getcwd()
409      path = '.'
410      files = os.listdir(path)
411     
412     
413
414  for filename in files:
415      root, ext = splitext(filename)
416
417      if ext == '.c':
418          for x in ['.dll', '.so']:
419              try:
420                  os.remove(root + x)
421              except:
422                  pass
423
424          print separation_line
425          print 'Trying to compile c-extension %s in %s'\
426                %(filename, os.getcwd())
427          try:
428            if filename == 'triang.c': 
429              compile(['triang.c','triangle.c'])
430            elif  filename == 'mesh_engine_c_layer.c': 
431              compile(['mesh_engine_c_layer.c','triangle.c'])
432            else:
433              compile(filename)
434          except Exception, e:
435              msg = 'Could not compile C extension %s\n' %filename
436              msg += str(e)
437              raise Exception, msg
438          else:
439              print 'C extension %s OK' %filename
440          print   
441       
442
Note: See TracBrowser for help on using the repository browser.