1"""numpy.distutils.fcompiler
2
3Contains FCompiler, an abstract base class that defines the interface
4for the numpy.distutils Fortran compiler abstraction model.
5
6Terminology:
7
8To be consistent, where the term 'executable' is used, it means the single
9file, like 'gcc', that is executed, and should be a string. In contrast,
10'command' means the entire command line, like ['gcc', '-c', 'file.c'], and
11should be a list.
12
13But note that FCompiler.executables is actually a dictionary of commands.
14
15"""
16__all__ = ['FCompiler', 'new_fcompiler', 'show_fcompilers',
17           'dummy_fortran_file']
18
19import os
20import sys
21import re
22
23from distutils.sysconfig import get_python_lib
24from distutils.fancy_getopt import FancyGetopt
25from distutils.errors import DistutilsModuleError, \
26     DistutilsExecError, CompileError, LinkError, DistutilsPlatformError
27from distutils.util import split_quoted, strtobool
28
29from numpy.distutils.ccompiler import CCompiler, gen_lib_options
30from numpy.distutils import log
31from numpy.distutils.misc_util import is_string, all_strings, is_sequence, \
32    make_temp_file, get_shared_lib_extension
33from numpy.distutils.exec_command import find_executable
34from numpy.distutils import _shell_utils
35
36from .environment import EnvironmentConfig
37
38__metaclass__ = type
39
40class CompilerNotFound(Exception):
41    pass
42
43def flaglist(s):
44    if is_string(s):
45        return split_quoted(s)
46    else:
47        return s
48
49def str2bool(s):
50    if is_string(s):
51        return strtobool(s)
52    return bool(s)
53
54def is_sequence_of_strings(seq):
55    return is_sequence(seq) and all_strings(seq)
56
57class FCompiler(CCompiler):
58    """Abstract base class to define the interface that must be implemented
59    by real Fortran compiler classes.
60
61    Methods that subclasses may redefine:
62
63        update_executables(), find_executables(), get_version()
64        get_flags(), get_flags_opt(), get_flags_arch(), get_flags_debug()
65        get_flags_f77(), get_flags_opt_f77(), get_flags_arch_f77(),
66        get_flags_debug_f77(), get_flags_f90(), get_flags_opt_f90(),
67        get_flags_arch_f90(), get_flags_debug_f90(),
68        get_flags_fix(), get_flags_linker_so()
69
70    DON'T call these methods (except get_version) after
71    constructing a compiler instance or inside any other method.
72    All methods, except update_executables() and find_executables(),
73    may call the get_version() method.
74
75    After constructing a compiler instance, always call customize(dist=None)
76    method that finalizes compiler construction and makes the following
77    attributes available:
78      compiler_f77
79      compiler_f90
80      compiler_fix
81      linker_so
82      archiver
83      ranlib
84      libraries
85      library_dirs
86    """
87
88    # These are the environment variables and distutils keys used.
89    # Each configuration description is
90    # (<hook name>, <environment variable>, <key in distutils.cfg>, <convert>, <append>)
91    # The hook names are handled by the self._environment_hook method.
92    #  - names starting with 'self.' call methods in this class
93    #  - names starting with 'exe.' return the key in the executables dict
94    #  - names like 'flags.YYY' return self.get_flag_YYY()
95    # convert is either None or a function to convert a string to the
96    # appropriate type used.
97
98    distutils_vars = EnvironmentConfig(
99        distutils_section='config_fc',
100        noopt = (None, None, 'noopt', str2bool, False),
101        noarch = (None, None, 'noarch', str2bool, False),
102        debug = (None, None, 'debug', str2bool, False),
103        verbose = (None, None, 'verbose', str2bool, False),
104    )
105
106    command_vars = EnvironmentConfig(
107        distutils_section='config_fc',
108        compiler_f77 = ('exe.compiler_f77', 'F77', 'f77exec', None, False),
109        compiler_f90 = ('exe.compiler_f90', 'F90', 'f90exec', None, False),
110        compiler_fix = ('exe.compiler_fix', 'F90', 'f90exec', None, False),
111        version_cmd = ('exe.version_cmd', None, None, None, False),
112        linker_so = ('exe.linker_so', 'LDSHARED', 'ldshared', None, False),
113        linker_exe = ('exe.linker_exe', 'LD', 'ld', None, False),
114        archiver = (None, 'AR', 'ar', None, False),
115        ranlib = (None, 'RANLIB', 'ranlib', None, False),
116    )
117
118    flag_vars = EnvironmentConfig(
119        distutils_section='config_fc',
120        f77 = ('flags.f77', 'F77FLAGS', 'f77flags', flaglist, True),
121        f90 = ('flags.f90', 'F90FLAGS', 'f90flags', flaglist, True),
122        free = ('flags.free', 'FREEFLAGS', 'freeflags', flaglist, True),
123        fix = ('flags.fix', None, None, flaglist, False),
124        opt = ('flags.opt', 'FOPT', 'opt', flaglist, True),
125        opt_f77 = ('flags.opt_f77', None, None, flaglist, False),
126        opt_f90 = ('flags.opt_f90', None, None, flaglist, False),
127        arch = ('flags.arch', 'FARCH', 'arch', flaglist, False),
128        arch_f77 = ('flags.arch_f77', None, None, flaglist, False),
129        arch_f90 = ('flags.arch_f90', None, None, flaglist, False),
130        debug = ('flags.debug', 'FDEBUG', 'fdebug', flaglist, True),
131        debug_f77 = ('flags.debug_f77', None, None, flaglist, False),
132        debug_f90 = ('flags.debug_f90', None, None, flaglist, False),
133        flags = ('self.get_flags', 'FFLAGS', 'fflags', flaglist, True),
134        linker_so = ('flags.linker_so', 'LDFLAGS', 'ldflags', flaglist, True),
135        linker_exe = ('flags.linker_exe', 'LDFLAGS', 'ldflags', flaglist, True),
136        ar = ('flags.ar', 'ARFLAGS', 'arflags', flaglist, True),
137    )
138
139    language_map = {'.f': 'f77',
140                    '.for': 'f77',
141                    '.F': 'f77',    # XXX: needs preprocessor
142                    '.ftn': 'f77',
143                    '.f77': 'f77',
144                    '.f90': 'f90',
145                    '.F90': 'f90',  # XXX: needs preprocessor
146                    '.f95': 'f90',
147                    }
148    language_order = ['f90', 'f77']
149
150
151    # These will be set by the subclass
152
153    compiler_type = None
154    compiler_aliases = ()
155    version_pattern = None
156
157    possible_executables = []
158    executables = {
159        'version_cmd': ["f77", "-v"],
160        'compiler_f77': ["f77"],
161        'compiler_f90': ["f90"],
162        'compiler_fix': ["f90", "-fixed"],
163        'linker_so': ["f90", "-shared"],
164        'linker_exe': ["f90"],
165        'archiver': ["ar", "-cr"],
166        'ranlib': None,
167        }
168
169    # If compiler does not support compiling Fortran 90 then it can
170    # suggest using another compiler. For example, gnu would suggest
171    # gnu95 compiler type when there are F90 sources.
172    suggested_f90_compiler = None
173
174    compile_switch = "-fPIC"
175    object_switch = "-o "   # Ending space matters! It will be stripped
176                            # but if it is missing then object_switch
177                            # will be prefixed to object file name by
178                            # string concatenation.
179    library_switch = "-o "  # Ditto!
180
181    # Switch to specify where module files are created and searched
182    # for USE statement.  Normally it is a string and also here ending
183    # space matters. See above.
184    module_dir_switch = None
185
186    # Switch to specify where module files are searched for USE statement.
187    module_include_switch = '-I'
188
189    pic_flags = []           # Flags to create position-independent code
190
191    src_extensions = ['.for', '.ftn', '.f77', '.f', '.f90', '.f95', '.F', '.F90', '.FOR']
192    obj_extension = ".o"
193
194    shared_lib_extension = get_shared_lib_extension()
195    static_lib_extension = ".a"  # or .lib
196    static_lib_format = "lib%s%s" # or %s%s
197    shared_lib_format = "%s%s"
198    exe_extension = ""
199
200    _exe_cache = {}
201
202    _executable_keys = ['version_cmd', 'compiler_f77', 'compiler_f90',
203                        'compiler_fix', 'linker_so', 'linker_exe', 'archiver',
204                        'ranlib']
205
206    # This will be set by new_fcompiler when called in
207    # command/{build_ext.py, build_clib.py, config.py} files.
208    c_compiler = None
209
210    # extra_{f77,f90}_compile_args are set by build_ext.build_extension method
211    extra_f77_compile_args = []
212    extra_f90_compile_args = []
213
214    def __init__(self, *args, **kw):
215        CCompiler.__init__(self, *args, **kw)
216        self.distutils_vars = self.distutils_vars.clone(self._environment_hook)
217        self.command_vars = self.command_vars.clone(self._environment_hook)
218        self.flag_vars = self.flag_vars.clone(self._environment_hook)
219        self.executables = self.executables.copy()
220        for e in self._executable_keys:
221            if e not in self.executables:
222                self.executables[e] = None
223
224        # Some methods depend on .customize() being called first, so
225        # this keeps track of whether that's happened yet.
226        self._is_customised = False
227
228    def __copy__(self):
229        obj = self.__new__(self.__class__)
230        obj.__dict__.update(self.__dict__)
231        obj.distutils_vars = obj.distutils_vars.clone(obj._environment_hook)
232        obj.command_vars = obj.command_vars.clone(obj._environment_hook)
233        obj.flag_vars = obj.flag_vars.clone(obj._environment_hook)
234        obj.executables = obj.executables.copy()
235        return obj
236
237    def copy(self):
238        return self.__copy__()
239
240    # Use properties for the attributes used by CCompiler. Setting them
241    # as attributes from the self.executables dictionary is error-prone,
242    # so we get them from there each time.
243    def _command_property(key):
244        def fget(self):
245            assert self._is_customised
246            return self.executables[key]
247        return property(fget=fget)
248    version_cmd = _command_property('version_cmd')
249    compiler_f77 = _command_property('compiler_f77')
250    compiler_f90 = _command_property('compiler_f90')
251    compiler_fix = _command_property('compiler_fix')
252    linker_so = _command_property('linker_so')
253    linker_exe = _command_property('linker_exe')
254    archiver = _command_property('archiver')
255    ranlib = _command_property('ranlib')
256
257    # Make our terminology consistent.
258    def set_executable(self, key, value):
259        self.set_command(key, value)
260
261    def set_commands(self, **kw):
262        for k, v in kw.items():
263            self.set_command(k, v)
264
265    def set_command(self, key, value):
266        if not key in self._executable_keys:
267            raise ValueError(
268                "unknown executable '%s' for class %s" %
269                (key, self.__class__.__name__))
270        if is_string(value):
271            value = split_quoted(value)
272        assert value is None or is_sequence_of_strings(value[1:]), (key, value)
273        self.executables[key] = value
274
275    ######################################################################
276    ## Methods that subclasses may redefine. But don't call these methods!
277    ## They are private to FCompiler class and may return unexpected
278    ## results if used elsewhere. So, you have been warned..
279
280    def find_executables(self):
281        """Go through the self.executables dictionary, and attempt to
282        find and assign appropriate executables.
283
284        Executable names are looked for in the environment (environment
285        variables, the distutils.cfg, and command line), the 0th-element of
286        the command list, and the self.possible_executables list.
287
288        Also, if the 0th element is "<F77>" or "<F90>", the Fortran 77
289        or the Fortran 90 compiler executable is used, unless overridden
290        by an environment setting.
291
292        Subclasses should call this if overridden.
293        """
294        assert self._is_customised
295        exe_cache = self._exe_cache
296        def cached_find_executable(exe):
297            if exe in exe_cache:
298                return exe_cache[exe]
299            fc_exe = find_executable(exe)
300            exe_cache[exe] = exe_cache[fc_exe] = fc_exe
301            return fc_exe
302        def verify_command_form(name, value):
303            if value is not None and not is_sequence_of_strings(value):
304                raise ValueError(
305                    "%s value %r is invalid in class %s" %
306                    (name, value, self.__class__.__name__))
307        def set_exe(exe_key, f77=None, f90=None):
308            cmd = self.executables.get(exe_key, None)
309            if not cmd:
310                return None
311            # Note that we get cmd[0] here if the environment doesn't
312            # have anything set
313            exe_from_environ = getattr(self.command_vars, exe_key)
314            if not exe_from_environ:
315                possibles = [f90, f77] + self.possible_executables
316            else:
317                possibles = [exe_from_environ] + self.possible_executables
318
319            seen = set()
320            unique_possibles = []
321            for e in possibles:
322                if e == '<F77>':
323                    e = f77
324                elif e == '<F90>':
325                    e = f90
326                if not e or e in seen:
327                    continue
328                seen.add(e)
329                unique_possibles.append(e)
330
331            for exe in unique_possibles:
332                fc_exe = cached_find_executable(exe)
333                if fc_exe:
334                    cmd[0] = fc_exe
335                    return fc_exe
336            self.set_command(exe_key, None)
337            return None
338
339        ctype = self.compiler_type
340        f90 = set_exe('compiler_f90')
341        if not f90:
342            f77 = set_exe('compiler_f77')
343            if f77:
344                log.warn('%s: no Fortran 90 compiler found' % ctype)
345            else:
346                raise CompilerNotFound('%s: f90 nor f77' % ctype)
347        else:
348            f77 = set_exe('compiler_f77', f90=f90)
349            if not f77:
350                log.warn('%s: no Fortran 77 compiler found' % ctype)
351            set_exe('compiler_fix', f90=f90)
352
353        set_exe('linker_so', f77=f77, f90=f90)
354        set_exe('linker_exe', f77=f77, f90=f90)
355        set_exe('version_cmd', f77=f77, f90=f90)
356        set_exe('archiver')
357        set_exe('ranlib')
358
359    def update_executables(self):
360        """Called at the beginning of customisation. Subclasses should
361        override this if they need to set up the executables dictionary.
362
363        Note that self.find_executables() is run afterwards, so the
364        self.executables dictionary values can contain <F77> or <F90> as
365        the command, which will be replaced by the found F77 or F90
366        compiler.
367        """
368        pass
369
370    def get_flags(self):
371        """List of flags common to all compiler types."""
372        return [] + self.pic_flags
373
374    def _get_command_flags(self, key):
375        cmd = self.executables.get(key, None)
376        if cmd is None:
377            return []
378        return cmd[1:]
379
380    def get_flags_f77(self):
381        """List of Fortran 77 specific flags."""
382        return self._get_command_flags('compiler_f77')
383    def get_flags_f90(self):
384        """List of Fortran 90 specific flags."""
385        return self._get_command_flags('compiler_f90')
386    def get_flags_free(self):
387        """List of Fortran 90 free format specific flags."""
388        return []
389    def get_flags_fix(self):
390        """List of Fortran 90 fixed format specific flags."""
391        return self._get_command_flags('compiler_fix')
392    def get_flags_linker_so(self):
393        """List of linker flags to build a shared library."""
394        return self._get_command_flags('linker_so')
395    def get_flags_linker_exe(self):
396        """List of linker flags to build an executable."""
397        return self._get_command_flags('linker_exe')
398    def get_flags_ar(self):
399        """List of archiver flags. """
400        return self._get_command_flags('archiver')
401    def get_flags_opt(self):
402        """List of architecture independent compiler flags."""
403        return []
404    def get_flags_arch(self):
405        """List of architecture dependent compiler flags."""
406        return []
407    def get_flags_debug(self):
408        """List of compiler flags to compile with debugging information."""
409        return []
410
411    get_flags_opt_f77 = get_flags_opt_f90 = get_flags_opt
412    get_flags_arch_f77 = get_flags_arch_f90 = get_flags_arch
413    get_flags_debug_f77 = get_flags_debug_f90 = get_flags_debug
414
415    def get_libraries(self):
416        """List of compiler libraries."""
417        return self.libraries[:]
418    def get_library_dirs(self):
419        """List of compiler library directories."""
420        return self.library_dirs[:]
421
422    def get_version(self, force=False, ok_status=[0]):
423        assert self._is_customised
424        version = CCompiler.get_version(self, force=force, ok_status=ok_status)
425        if version is None:
426            raise CompilerNotFound()
427        return version
428
429
430    ############################################################
431
432    ## Public methods:
433
434    def customize(self, dist = None):
435        """Customize Fortran compiler.
436
437        This method gets Fortran compiler specific information from
438        (i) class definition, (ii) environment, (iii) distutils config
439        files, and (iv) command line (later overrides earlier).
440
441        This method should be always called after constructing a
442        compiler instance. But not in __init__ because Distribution
443        instance is needed for (iii) and (iv).
444        """
445        log.info('customize %s' % (self.__class__.__name__))
446
447        self._is_customised = True
448
449        self.distutils_vars.use_distribution(dist)
450        self.command_vars.use_distribution(dist)
451        self.flag_vars.use_distribution(dist)
452
453        self.update_executables()
454
455        # find_executables takes care of setting the compiler commands,
456        # version_cmd, linker_so, linker_exe, ar, and ranlib
457        self.find_executables()
458
459        noopt = self.distutils_vars.get('noopt', False)
460        noarch = self.distutils_vars.get('noarch', noopt)
461        debug = self.distutils_vars.get('debug', False)
462
463        f77 = self.command_vars.compiler_f77
464        f90 = self.command_vars.compiler_f90
465
466        f77flags = []
467        f90flags = []
468        freeflags = []
469        fixflags = []
470
471        if f77:
472            f77 = _shell_utils.NativeParser.split(f77)
473            f77flags = self.flag_vars.f77
474        if f90:
475            f90 = _shell_utils.NativeParser.split(f90)
476            f90flags = self.flag_vars.f90
477            freeflags = self.flag_vars.free
478        # XXX Assuming that free format is default for f90 compiler.
479        fix = self.command_vars.compiler_fix
480        # NOTE: this and similar examples are probably just
481        # excluding --coverage flag when F90 = gfortran --coverage
482        # instead of putting that flag somewhere more appropriate
483        # this and similar examples where a Fortran compiler
484        # environment variable has been customized by CI or a user
485        # should perhaps eventually be more thoroughly tested and more
486        # robustly handled
487        if fix:
488            fix = _shell_utils.NativeParser.split(fix)
489            fixflags = self.flag_vars.fix + f90flags
490
491        oflags, aflags, dflags = [], [], []
492        # examine get_flags_<tag>_<compiler> for extra flags
493        # only add them if the method is different from get_flags_<tag>
494        def get_flags(tag, flags):
495            # note that self.flag_vars.<tag> calls self.get_flags_<tag>()
496            flags.extend(getattr(self.flag_vars, tag))
497            this_get = getattr(self, 'get_flags_' + tag)
498            for name, c, flagvar in [('f77', f77, f77flags),
499                                     ('f90', f90, f90flags),
500                                     ('f90', fix, fixflags)]:
501                t = '%s_%s' % (tag, name)
502                if c and this_get is not getattr(self, 'get_flags_' + t):
503                    flagvar.extend(getattr(self.flag_vars, t))
504        if not noopt:
505            get_flags('opt', oflags)
506            if not noarch:
507                get_flags('arch', aflags)
508        if debug:
509            get_flags('debug', dflags)
510
511        fflags = self.flag_vars.flags + dflags + oflags + aflags
512
513        if f77:
514            self.set_commands(compiler_f77=f77+f77flags+fflags)
515        if f90:
516            self.set_commands(compiler_f90=f90+freeflags+f90flags+fflags)
517        if fix:
518            self.set_commands(compiler_fix=fix+fixflags+fflags)
519
520
521        #XXX: Do we need LDSHARED->SOSHARED, LDFLAGS->SOFLAGS
522        linker_so = self.linker_so
523        if linker_so:
524            linker_so_flags = self.flag_vars.linker_so
525            if sys.platform.startswith('aix'):
526                python_lib = get_python_lib(standard_lib=1)
527                ld_so_aix = os.path.join(python_lib, 'config', 'ld_so_aix')
528                python_exp = os.path.join(python_lib, 'config', 'python.exp')
529                linker_so = [ld_so_aix] + linker_so + ['-bI:'+python_exp]
530            self.set_commands(linker_so=linker_so+linker_so_flags)
531
532        linker_exe = self.linker_exe
533        if linker_exe:
534            linker_exe_flags = self.flag_vars.linker_exe
535            self.set_commands(linker_exe=linker_exe+linker_exe_flags)
536
537        ar = self.command_vars.archiver
538        if ar:
539            arflags = self.flag_vars.ar
540            self.set_commands(archiver=[ar]+arflags)
541
542        self.set_library_dirs(self.get_library_dirs())
543        self.set_libraries(self.get_libraries())
544
545    def dump_properties(self):
546        """Print out the attributes of a compiler instance."""
547        props = []
548        for key in list(self.executables.keys()) + \
549                ['version', 'libraries', 'library_dirs',
550                 'object_switch', 'compile_switch']:
551            if hasattr(self, key):
552                v = getattr(self, key)
553                props.append((key, None, '= '+repr(v)))
554        props.sort()
555
556        pretty_printer = FancyGetopt(props)
557        for l in pretty_printer.generate_help("%s instance properties:" \
558                                              % (self.__class__.__name__)):
559            if l[:4]=='  --':
560                l = '  ' + l[4:]
561            print(l)
562
563    ###################
564
565    def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
566        """Compile 'src' to product 'obj'."""
567        src_flags = {}
568        if is_f_file(src) and not has_f90_header(src):
569            flavor = ':f77'
570            compiler = self.compiler_f77
571            src_flags = get_f77flags(src)
572            extra_compile_args = self.extra_f77_compile_args or []
573        elif is_free_format(src):
574            flavor = ':f90'
575            compiler = self.compiler_f90
576            if compiler is None:
577                raise DistutilsExecError('f90 not supported by %s needed for %s'\
578                      % (self.__class__.__name__, src))
579            extra_compile_args = self.extra_f90_compile_args or []
580        else:
581            flavor = ':fix'
582            compiler = self.compiler_fix
583            if compiler is None:
584                raise DistutilsExecError('f90 (fixed) not supported by %s needed for %s'\
585                      % (self.__class__.__name__, src))
586            extra_compile_args = self.extra_f90_compile_args or []
587        if self.object_switch[-1]==' ':
588            o_args = [self.object_switch.strip(), obj]
589        else:
590            o_args = [self.object_switch.strip()+obj]
591
592        assert self.compile_switch.strip()
593        s_args = [self.compile_switch, src]
594
595        if extra_compile_args:
596            log.info('extra %s options: %r' \
597                     % (flavor[1:], ' '.join(extra_compile_args)))
598
599        extra_flags = src_flags.get(self.compiler_type, [])
600        if extra_flags:
601            log.info('using compile options from source: %r' \
602                     % ' '.join(extra_flags))
603
604        command = compiler + cc_args + extra_flags + s_args + o_args \
605                  + extra_postargs + extra_compile_args
606
607        display = '%s: %s' % (os.path.basename(compiler[0]) + flavor,
608                              src)
609        try:
610            self.spawn(command, display=display)
611        except DistutilsExecError as e:
612            msg = str(e)
613            raise CompileError(msg)
614
615    def module_options(self, module_dirs, module_build_dir):
616        options = []
617        if self.module_dir_switch is not None:
618            if self.module_dir_switch[-1]==' ':
619                options.extend([self.module_dir_switch.strip(), module_build_dir])
620            else:
621                options.append(self.module_dir_switch.strip()+module_build_dir)
622        else:
623            print('XXX: module_build_dir=%r option ignored' % (module_build_dir))
624            print('XXX: Fix module_dir_switch for ', self.__class__.__name__)
625        if self.module_include_switch is not None:
626            for d in [module_build_dir]+module_dirs:
627                options.append('%s%s' % (self.module_include_switch, d))
628        else:
629            print('XXX: module_dirs=%r option ignored' % (module_dirs))
630            print('XXX: Fix module_include_switch for ', self.__class__.__name__)
631        return options
632
633    def library_option(self, lib):
634        return "-l" + lib
635    def library_dir_option(self, dir):
636        return "-L" + dir
637
638    def link(self, target_desc, objects,
639             output_filename, output_dir=None, libraries=None,
640             library_dirs=None, runtime_library_dirs=None,
641             export_symbols=None, debug=0, extra_preargs=None,
642             extra_postargs=None, build_temp=None, target_lang=None):
643        objects, output_dir = self._fix_object_args(objects, output_dir)
644        libraries, library_dirs, runtime_library_dirs = \
645            self._fix_lib_args(libraries, library_dirs, runtime_library_dirs)
646
647        lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs,
648                                   libraries)
649        if is_string(output_dir):
650            output_filename = os.path.join(output_dir, output_filename)
651        elif output_dir is not None:
652            raise TypeError("'output_dir' must be a string or None")
653
654        if self._need_link(objects, output_filename):
655            if self.library_switch[-1]==' ':
656                o_args = [self.library_switch.strip(), output_filename]
657            else:
658                o_args = [self.library_switch.strip()+output_filename]
659
660            if is_string(self.objects):
661                ld_args = objects + [self.objects]
662            else:
663                ld_args = objects + self.objects
664            ld_args = ld_args + lib_opts + o_args
665            if debug:
666                ld_args[:0] = ['-g']
667            if extra_preargs:
668                ld_args[:0] = extra_preargs
669            if extra_postargs:
670                ld_args.extend(extra_postargs)
671            self.mkpath(os.path.dirname(output_filename))
672            if target_desc == CCompiler.EXECUTABLE:
673                linker = self.linker_exe[:]
674            else:
675                linker = self.linker_so[:]
676            command = linker + ld_args
677            try:
678                self.spawn(command)
679            except DistutilsExecError as e:
680                msg = str(e)
681                raise LinkError(msg)
682        else:
683            log.debug("skipping %s (up-to-date)", output_filename)
684
685    def _environment_hook(self, name, hook_name):
686        if hook_name is None:
687            return None
688        if is_string(hook_name):
689            if hook_name.startswith('self.'):
690                hook_name = hook_name[5:]
691                hook = getattr(self, hook_name)
692                return hook()
693            elif hook_name.startswith('exe.'):
694                hook_name = hook_name[4:]
695                var = self.executables[hook_name]
696                if var:
697                    return var[0]
698                else:
699                    return None
700            elif hook_name.startswith('flags.'):
701                hook_name = hook_name[6:]
702                hook = getattr(self, 'get_flags_' + hook_name)
703                return hook()
704        else:
705            return hook_name()
706
707    def can_ccompiler_link(self, ccompiler):
708        """
709        Check if the given C compiler can link objects produced by
710        this compiler.
711        """
712        return True
713
714    def wrap_unlinkable_objects(self, objects, output_dir, extra_dll_dir):
715        """
716        Convert a set of object files that are not compatible with the default
717        linker, to a file that is compatible.
718
719        Parameters
720        ----------
721        objects : list
722            List of object files to include.
723        output_dir : str
724            Output directory to place generated object files.
725        extra_dll_dir : str
726            Output directory to place extra DLL files that need to be
727            included on Windows.
728
729        Returns
730        -------
731        converted_objects : list of str
732             List of converted object files.
733             Note that the number of output files is not necessarily
734             the same as inputs.
735
736        """
737        raise NotImplementedError()
738
739    ## class FCompiler
740
741_default_compilers = (
742    # sys.platform mappings
743    ('win32', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95',
744               'intelvem', 'intelem', 'flang')),
745    ('cygwin.*', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95')),
746    ('linux.*', ('gnu95', 'intel', 'lahey', 'pg', 'nv', 'absoft', 'nag', 'vast', 'compaq',
747                 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor', 'fujitsu')),
748    ('darwin.*', ('gnu95', 'nag', 'absoft', 'ibm', 'intel', 'gnu', 'g95', 'pg')),
749    ('sunos.*', ('sun', 'gnu', 'gnu95', 'g95')),
750    ('irix.*', ('mips', 'gnu', 'gnu95',)),
751    ('aix.*', ('ibm', 'gnu', 'gnu95',)),
752    # os.name mappings
753    ('posix', ('gnu', 'gnu95',)),
754    ('nt', ('gnu', 'gnu95',)),
755    ('mac', ('gnu95', 'gnu', 'pg')),
756    )
757
758fcompiler_class = None
759fcompiler_aliases = None
760
761def load_all_fcompiler_classes():
762    """Cache all the FCompiler classes found in modules in the
763    numpy.distutils.fcompiler package.
764    """
765    from glob import glob
766    global fcompiler_class, fcompiler_aliases
767    if fcompiler_class is not None:
768        return
769    pys = os.path.join(os.path.dirname(__file__), '*.py')
770    fcompiler_class = {}
771    fcompiler_aliases = {}
772    for fname in glob(pys):
773        module_name, ext = os.path.splitext(os.path.basename(fname))
774        module_name = 'numpy.distutils.fcompiler.' + module_name
775        __import__ (module_name)
776        module = sys.modules[module_name]
777        if hasattr(module, 'compilers'):
778            for cname in module.compilers:
779                klass = getattr(module, cname)
780                desc = (klass.compiler_type, klass, klass.description)
781                fcompiler_class[klass.compiler_type] = desc
782                for alias in klass.compiler_aliases:
783                    if alias in fcompiler_aliases:
784                        raise ValueError("alias %r defined for both %s and %s"
785                                         % (alias, klass.__name__,
786                                            fcompiler_aliases[alias][1].__name__))
787                    fcompiler_aliases[alias] = desc
788
789def _find_existing_fcompiler(compiler_types,
790                             osname=None, platform=None,
791                             requiref90=False,
792                             c_compiler=None):
793    from numpy.distutils.core import get_distribution
794    dist = get_distribution(always=True)
795    for compiler_type in compiler_types:
796        v = None
797        try:
798            c = new_fcompiler(plat=platform, compiler=compiler_type,
799                              c_compiler=c_compiler)
800            c.customize(dist)
801            v = c.get_version()
802            if requiref90 and c.compiler_f90 is None:
803                v = None
804                new_compiler = c.suggested_f90_compiler
805                if new_compiler:
806                    log.warn('Trying %r compiler as suggested by %r '
807                             'compiler for f90 support.' % (compiler_type,
808                                                            new_compiler))
809                    c = new_fcompiler(plat=platform, compiler=new_compiler,
810                                      c_compiler=c_compiler)
811                    c.customize(dist)
812                    v = c.get_version()
813                    if v is not None:
814                        compiler_type = new_compiler
815            if requiref90 and c.compiler_f90 is None:
816                raise ValueError('%s does not support compiling f90 codes, '
817                                 'skipping.' % (c.__class__.__name__))
818        except DistutilsModuleError:
819            log.debug("_find_existing_fcompiler: compiler_type='%s' raised DistutilsModuleError", compiler_type)
820        except CompilerNotFound:
821            log.debug("_find_existing_fcompiler: compiler_type='%s' not found", compiler_type)
822        if v is not None:
823            return compiler_type
824    return None
825
826def available_fcompilers_for_platform(osname=None, platform=None):
827    if osname is None:
828        osname = os.name
829    if platform is None:
830        platform = sys.platform
831    matching_compiler_types = []
832    for pattern, compiler_type in _default_compilers:
833        if re.match(pattern, platform) or re.match(pattern, osname):
834            for ct in compiler_type:
835                if ct not in matching_compiler_types:
836                    matching_compiler_types.append(ct)
837    if not matching_compiler_types:
838        matching_compiler_types.append('gnu')
839    return matching_compiler_types
840
841def get_default_fcompiler(osname=None, platform=None, requiref90=False,
842                          c_compiler=None):
843    """Determine the default Fortran compiler to use for the given
844    platform."""
845    matching_compiler_types = available_fcompilers_for_platform(osname,
846                                                                platform)
847    log.info("get_default_fcompiler: matching types: '%s'",
848             matching_compiler_types)
849    compiler_type =  _find_existing_fcompiler(matching_compiler_types,
850                                              osname=osname,
851                                              platform=platform,
852                                              requiref90=requiref90,
853                                              c_compiler=c_compiler)
854    return compiler_type
855
856# Flag to avoid rechecking for Fortran compiler every time
857failed_fcompilers = set()
858
859def new_fcompiler(plat=None,
860                  compiler=None,
861                  verbose=0,
862                  dry_run=0,
863                  force=0,
864                  requiref90=False,
865                  c_compiler = None):
866    """Generate an instance of some FCompiler subclass for the supplied
867    platform/compiler combination.
868    """
869    global failed_fcompilers
870    fcompiler_key = (plat, compiler)
871    if fcompiler_key in failed_fcompilers:
872        return None
873
874    load_all_fcompiler_classes()
875    if plat is None:
876        plat = os.name
877    if compiler is None:
878        compiler = get_default_fcompiler(plat, requiref90=requiref90,
879                                         c_compiler=c_compiler)
880    if compiler in fcompiler_class:
881        module_name, klass, long_description = fcompiler_class[compiler]
882    elif compiler in fcompiler_aliases:
883        module_name, klass, long_description = fcompiler_aliases[compiler]
884    else:
885        msg = "don't know how to compile Fortran code on platform '%s'" % plat
886        if compiler is not None:
887            msg = msg + " with '%s' compiler." % compiler
888            msg = msg + " Supported compilers are: %s)" \
889                  % (','.join(fcompiler_class.keys()))
890        log.warn(msg)
891        failed_fcompilers.add(fcompiler_key)
892        return None
893
894    compiler = klass(verbose=verbose, dry_run=dry_run, force=force)
895    compiler.c_compiler = c_compiler
896    return compiler
897
898def show_fcompilers(dist=None):
899    """Print list of available compilers (used by the "--help-fcompiler"
900    option to "config_fc").
901    """
902    if dist is None:
903        from distutils.dist import Distribution
904        from numpy.distutils.command.config_compiler import config_fc
905        dist = Distribution()
906        dist.script_name = os.path.basename(sys.argv[0])
907        dist.script_args = ['config_fc'] + sys.argv[1:]
908        try:
909            dist.script_args.remove('--help-fcompiler')
910        except ValueError:
911            pass
912        dist.cmdclass['config_fc'] = config_fc
913        dist.parse_config_files()
914        dist.parse_command_line()
915    compilers = []
916    compilers_na = []
917    compilers_ni = []
918    if not fcompiler_class:
919        load_all_fcompiler_classes()
920    platform_compilers = available_fcompilers_for_platform()
921    for compiler in platform_compilers:
922        v = None
923        log.set_verbosity(-2)
924        try:
925            c = new_fcompiler(compiler=compiler, verbose=dist.verbose)
926            c.customize(dist)
927            v = c.get_version()
928        except (DistutilsModuleError, CompilerNotFound) as e:
929            log.debug("show_fcompilers: %s not found" % (compiler,))
930            log.debug(repr(e))
931
932        if v is None:
933            compilers_na.append(("fcompiler="+compiler, None,
934                              fcompiler_class[compiler][2]))
935        else:
936            c.dump_properties()
937            compilers.append(("fcompiler="+compiler, None,
938                              fcompiler_class[compiler][2] + ' (%s)' % v))
939
940    compilers_ni = list(set(fcompiler_class.keys()) - set(platform_compilers))
941    compilers_ni = [("fcompiler="+fc, None, fcompiler_class[fc][2])
942                    for fc in compilers_ni]
943
944    compilers.sort()
945    compilers_na.sort()
946    compilers_ni.sort()
947    pretty_printer = FancyGetopt(compilers)
948    pretty_printer.print_help("Fortran compilers found:")
949    pretty_printer = FancyGetopt(compilers_na)
950    pretty_printer.print_help("Compilers available for this "
951                              "platform, but not found:")
952    if compilers_ni:
953        pretty_printer = FancyGetopt(compilers_ni)
954        pretty_printer.print_help("Compilers not available on this platform:")
955    print("For compiler details, run 'config_fc --verbose' setup command.")
956
957
958def dummy_fortran_file():
959    fo, name = make_temp_file(suffix='.f')
960    fo.write("      subroutine dummy()\n      end\n")
961    fo.close()
962    return name[:-2]
963
964
965is_f_file = re.compile(r'.*[.](for|ftn|f77|f)\Z', re.I).match
966_has_f_header = re.compile(r'-[*]-\s*fortran\s*-[*]-', re.I).search
967_has_f90_header = re.compile(r'-[*]-\s*f90\s*-[*]-', re.I).search
968_has_fix_header = re.compile(r'-[*]-\s*fix\s*-[*]-', re.I).search
969_free_f90_start = re.compile(r'[^c*!]\s*[^\s\d\t]', re.I).match
970
971def is_free_format(file):
972    """Check if file is in free format Fortran."""
973    # f90 allows both fixed and free format, assuming fixed unless
974    # signs of free format are detected.
975    result = 0
976    with open(file, encoding='latin1') as f:
977        line = f.readline()
978        n = 10000 # the number of non-comment lines to scan for hints
979        if _has_f_header(line) or _has_fix_header(line):
980            n = 0
981        elif _has_f90_header(line):
982            n = 0
983            result = 1
984        while n>0 and line:
985            line = line.rstrip()
986            if line and line[0]!='!':
987                n -= 1
988                if (line[0]!='\t' and _free_f90_start(line[:5])) or line[-1:]=='&':
989                    result = 1
990                    break
991            line = f.readline()
992    return result
993
994def has_f90_header(src):
995    with open(src, encoding='latin1') as f:
996        line = f.readline()
997    return _has_f90_header(line) or _has_fix_header(line)
998
999_f77flags_re = re.compile(r'(c|)f77flags\s*\(\s*(?P<fcname>\w+)\s*\)\s*=\s*(?P<fflags>.*)', re.I)
1000def get_f77flags(src):
1001    """
1002    Search the first 20 lines of fortran 77 code for line pattern
1003      `CF77FLAGS(<fcompiler type>)=<f77 flags>`
1004    Return a dictionary {<fcompiler type>:<f77 flags>}.
1005    """
1006    flags = {}
1007    with open(src, encoding='latin1') as f:
1008        i = 0
1009        for line in f:
1010            i += 1
1011            if i>20: break
1012            m = _f77flags_re.match(line)
1013            if not m: continue
1014            fcname = m.group('fcname').strip()
1015            fflags = m.group('fflags').strip()
1016            flags[fcname] = split_quoted(fflags)
1017    return flags
1018
1019# TODO: implement get_f90flags and use it in _compile similarly to get_f77flags
1020
1021if __name__ == '__main__':
1022    show_fcompilers()
1023