/Python/scipy/_build_utils/_fortran.py

https://github.com/mantidproject/3rdpartylibs-mac
Python | 154 lines | 106 code | 19 blank | 29 comment | 17 complexity | 7849c07ce2c46ab55a5bcfc5b6c52ebe MD5 | raw file
  1. import re
  2. import sys
  3. import os
  4. import glob
  5. __all__ = ['needs_g77_abi_wrapper', 'split_fortran_files',
  6. 'get_g77_abi_wrappers']
  7. def _uses_veclib(info):
  8. r_accelerate = re.compile("Accelerate|vecLib")
  9. extra_link_args = info.get('extra_link_args', '')
  10. for arg in extra_link_args:
  11. if r_accelerate.search(arg):
  12. return True
  13. return False
  14. def uses_accelerate(info):
  15. return _uses_veclib(info)
  16. def uses_mkl(info):
  17. r_mkl = re.compile("mkl_core")
  18. libraries = info.get('libraries', '')
  19. for library in libraries:
  20. if r_mkl.search(library):
  21. return True
  22. return False
  23. def needs_g77_abi_wrapper(info):
  24. """Returns true if g77 ABI wrapper must be used."""
  25. if uses_accelerate(info):
  26. return True
  27. # XXX: is this really true only on Mac OS X ?
  28. elif uses_mkl(info) and sys.platform == "darwin":
  29. return True
  30. else:
  31. return False
  32. def get_g77_abi_wrappers(info):
  33. """
  34. Returns file names of source files containing Fortran ABI wrapper
  35. routines.
  36. """
  37. wrapper_sources = []
  38. path = os.path.abspath(os.path.dirname(__file__))
  39. if needs_g77_abi_wrapper(info):
  40. wrapper_sources += [
  41. os.path.join(path, 'src', 'wrap_g77_abi_f.f'),
  42. os.path.join(path, 'src', 'wrap_g77_abi_c.c'),
  43. ]
  44. if uses_accelerate(info):
  45. wrapper_sources += [
  46. os.path.join(path, 'src', 'wrap_accelerate_c.c'),
  47. os.path.join(path, 'src', 'wrap_accelerate_f.f'),
  48. ]
  49. elif uses_mkl(info):
  50. wrapper_sources += [
  51. os.path.join(path, 'src', 'wrap_dummy_accelerate.f'),
  52. ]
  53. else:
  54. raise NotImplementedError("Do not know how to handle LAPACK %s on mac os x" % (info,))
  55. else:
  56. wrapper_sources += [
  57. os.path.join(path, 'src', 'wrap_dummy_g77_abi.f'),
  58. os.path.join(path, 'src', 'wrap_dummy_accelerate.f'),
  59. ]
  60. return wrapper_sources
  61. def split_fortran_files(source_dir, subroutines=None):
  62. """Split each file in `source_dir` into separate files per subroutine.
  63. Parameters
  64. ----------
  65. source_dir : str
  66. Full path to directory in which sources to be split are located.
  67. subroutines : list of str, optional
  68. Subroutines to split. (Default: all)
  69. Returns
  70. -------
  71. fnames : list of str
  72. List of file names (not including any path) that were created
  73. in `source_dir`.
  74. Notes
  75. -----
  76. This function is useful for code that can't be compiled with g77 because of
  77. type casting errors which do work with gfortran.
  78. Created files are named: ``original_name + '_subr_i' + '.f'``, with ``i``
  79. starting at zero and ending at ``num_subroutines_in_file - 1``.
  80. """
  81. if subroutines is not None:
  82. subroutines = [x.lower() for x in subroutines]
  83. def split_file(fname):
  84. with open(fname, 'rb') as f:
  85. lines = f.readlines()
  86. subs = []
  87. need_split_next = True
  88. # find lines with SUBROUTINE statements
  89. for ix, line in enumerate(lines):
  90. m = re.match(b'^\\s+subroutine\\s+([a-z0-9_]+)\s*\\(', line, re.I)
  91. if m and line[0] not in b'Cc!*':
  92. if subroutines is not None:
  93. subr_name = m.group(1).decode('ascii').lower()
  94. subr_wanted = (subr_name in subroutines)
  95. else:
  96. subr_wanted = True
  97. if subr_wanted or need_split_next:
  98. need_split_next = subr_wanted
  99. subs.append(ix)
  100. # check if no split needed
  101. if len(subs) <= 1:
  102. return [fname]
  103. # write out one file per subroutine
  104. new_fnames = []
  105. num_files = len(subs)
  106. for nfile in range(num_files):
  107. new_fname = fname[:-2] + '_subr_' + str(nfile) + '.f'
  108. new_fnames.append(new_fname)
  109. with open(new_fname, 'wb') as fn:
  110. if nfile + 1 == num_files:
  111. fn.writelines(lines[subs[nfile]:])
  112. else:
  113. fn.writelines(lines[subs[nfile] : subs[nfile+1]])
  114. return new_fnames
  115. exclude_pattern = re.compile('_subr_[0-9]')
  116. source_fnames = [f for f in glob.glob(os.path.join(source_dir, '*.f'))
  117. if not exclude_pattern.search(os.path.basename(f))]
  118. fnames = []
  119. for source_fname in source_fnames:
  120. created_files = split_file(source_fname)
  121. if created_files is not None:
  122. for cfile in created_files:
  123. fnames.append(os.path.basename(cfile))
  124. return fnames