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

Last change on this file since 5133 was 5133, checked in by jack, 16 years ago

Removed some dead code. Fixed the search for python dll on windows platforms.

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