1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# ==============================================================================
4# COPYRIGHT (C) 1991 - 2003  EDF R&D                  WWW.CODE-ASTER.ORG
5# THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6# IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7# THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8# (AT YOUR OPTION) ANY LATER VERSION.
9#
10# THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11# WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13# GENERAL PUBLIC LICENSE FOR MORE DETAILS.
14#
15# YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16# ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
18# ==============================================================================
19
20# ----- differ messages translation
21
22
23def _(mesg):
24    return mesg
25
26import sys
27# ----- check for Python version
28if sys.hexversion < 0x030500F0:
29    print(_('This script requires Python 3.5 or higher, sorry!'))
30    sys.exit(4)
31
32from glob import glob
33import os
34import os.path as osp
35import time
36import re
37import tempfile
38import traceback
39import shutil
40from types import ModuleType
41from optparse import OptionParser
42import distutils.sysconfig as SC
43
44from as_setup import (
45    SUMMARY,
46    SYSTEM,
47    DEPENDENCIES,
48    FIND_TOOLS,
49    check_pymodule,
50    should_continue,
51    should_continue_reg,
52    less_than_version,
53    get_install_message,
54    relative_symlink,
55    SetupError,
56)
57
58try:
59    from __pkginfo__ import dict_prod, dict_prod_param
60    short_version = '.'.join(dict_prod['aster'].split('.')[:2])
61    available_products = dict_prod_param['__to_install__']
62    numeric_version = tuple(map(int, dict_prod['aster'].split('.')[:2]))
63except (ImportError, KeyError) as msg:
64    print("File not found or invalid : '__pkginfo__.py'")
65    print("Error :")
66    print(msg)
67    sys.exit(4)
68
69import products
70import mprint
71
72python_version = '.'.join([str(n) for n in sys.version_info[:3]])
73pythonXY = 'python' + '.'.join([str(n) for n in sys.version_info[:2]])
74PY3 = sys.version_info.major >= 3
75
76log_file = 'setup.log'
77log = mprint.MPRINT(log_file, 'w')
78
79
80def product_alias(product):
81    return re.sub("[\-\+\.]+", "_", product)
82
83
84def main():
85    #-------------------------------------------------------------------------------
86    # 0. initialisation, configuration of the command-line parser
87    #-------------------------------------------------------------------------------
88    # 0.1. ----- list of products to install (could be skip through cfg)
89    t_ini = time.time()
90    to_install_ordered = ['hdf5', 'med',
91                          'scotch',
92                          'astk', 'metis', 'tfel',
93                          'mumps',
94                          'homard',
95                          'aster']
96    to_install = [
97        prod for prod in to_install_ordered if prod in available_products]
98
99    __aster_version__ = short_version
100
101    # 0.2. ----- version
102    import __pkginfo__
103
104    svers = os.linesep.join(['Code_Aster Setup version ' +
105                            __pkginfo__.version + '-' + __pkginfo__.release, __pkginfo__.copyright])
106
107    usage = "usage: python %prog [options] [install|test] [arg]\n" + \
108        _("""
109
110   Setup script for Code_Aster distribution.
111
112   NOTE : Code_Aster or eventually other products will be configured with
113          the Python you use to run this setup :
114            interpreter    : %(interp)s (version %(vers)s)
115            prefix         : %(prefix)s
116
117   arguments :
118     action : only 'install' or 'test'.
119
120     By default all products are installed, but you can install only one (if a
121     first attempt failed). Example : python setup.py install aster.
122
123     Available products (the order is important) :
124       %(prod)s.""") % {
125        'vers': python_version,
126        'prefix': os.path.abspath(sys.prefix),
127        'interp': sys.executable,
128        'prod': ', '.join(to_install),
129    }
130
131    _separ = '\n' + '-' * 80 + '\n'
132    _fmt_err = _(' *** Exception raised : %s')
133    _fmt_search = _('Checking for %s...   ')
134
135    log._print(_separ, svers, _separ)
136
137    scmd = """Command line :\n   %s""" % ' '.join([sys.executable] + sys.argv)
138    log._print(_separ, scmd, _separ)
139
140    # 0.3. ----- command line parser
141    parser = OptionParser(
142        usage=usage,
143          version='Code_Aster Setup version ' + __pkginfo__.version + '-' + __pkginfo__.release)
144    parser.add_option("--prefix", dest="prefix", action='store',
145                      help=_("define toplevel directory for Code_Aster (identical to --aster_root)"), metavar="DIR")
146    parser.add_option("--aster_root", dest="ASTER_ROOT", action='store',
147                      #       default='/opt/aster',    not here !
148                      help=_("define toplevel directory for Code_Aster (default '/opt/aster')"), metavar="DIR")
149    parser.add_option("--sourcedir", dest="SOURCEDIR", action='store',
150                      #       default='./SRC',         not here !
151                      help=_(
152                          "directory which contains archive files (default './SRC')"),
153                      metavar="DIR")
154    parser.add_option("--cfg", dest="fcfg", action='store', metavar="FILE",
155                      help=_("file which contains the installation parameters"),)
156    parser.add_option("--nocache", dest="cache", action='store_false',
157                      default=True,
158                      help=_("delete cache file before starting (it's default if you do not specify a product name)"),)
159    parser.add_option("--ignore_error", dest="ign_err", action='store_true',
160                      default=False,
161                      help=_("ignore error when checking prerequisites"),)  # same as the old --force option
162    parser.add_option("--reinstall", dest="reinstall", action='store',
163                      default='ask',
164                      help=_("tell what to do if a product is already installed: force, ignore, ask "
165                             "('force' reinstalls the product, 'ignore' keeps the current one, 'ask' prompts "
166                             "for each product)"),)
167    parser.add_option("-q", "--quiet", dest="verbose", action='store_false',
168                      default=True,
169                      help=_("turn off verbose mode"),)
170    parser.add_option("-g", "--debug", dest="debug", action='store_true',
171                      default=False,
172                      help=_("turn on debug mode"),)
173    parser.add_option("--noprompt", dest="noprompt", action='store_true',
174                      default=False,
175                      help=_("do not ask any questions"),)
176
177    opts, args = parser.parse_args()
178    fcfg = opts.fcfg
179    verbose = opts.verbose
180    debug = opts.debug
181    noprompt = opts.noprompt
182    should_continue_reg(noprompt)
183
184    main_script = sys.argv[0]
185    setup_maindir = os.path.normpath(
186        os.path.dirname(os.path.abspath(main_script)))
187
188    default_cfgfile = os.path.join(setup_maindir, 'setup.cfg')
189    cache_file = os.path.join(setup_maindir, 'setup.cache')
190
191    def_opts = {
192        'ASTER_ROOT': '/opt/aster',
193       'SOURCEDIR': os.path.normpath(os.path.join(setup_maindir, 'SRC')),
194    }
195    if opts.prefix is not None and opts.ASTER_ROOT is None:
196        opts.ASTER_ROOT = opts.prefix
197
198    # 0.4. ----- check for argument value
199    _install = True
200    _test = False
201    if len(args) > 0:
202        if args[0] == 'install':
203            pass
204        elif args[0] == 'test':
205            _test = True
206        elif args[0] == 'clean':
207            for fname in glob(log_file + '*') + glob('setup.dbg*') \
208                    + glob('*.pyc') + glob(cache_file):
209                print(_("remove %s") % fname)
210                os.remove(fname)
211            print(_("temporary files deleted!"))
212            return
213        else:
214            parser.error(_("unexpected argument %s") % repr(args[0]))
215    if opts.reinstall not in ('force', 'ignore', 'ask'):
216        parser.error(_("--reinstall must be one of 'force', 'ignore' or 'ask'. "
217                       "'%s' is not allowed") % opts.reinstall)
218
219    # 0.5. ----- adjust to_install list
220    to_install0 = to_install[:]
221    if len(args) > 1:
222        arg0 = args.pop(0)
223        for p in to_install[:]:
224            if not p in args:
225                to_install.remove(p)
226
227    # 0.6. ----- list of exceptions to handle during installation
228    if not debug:
229        safe_exceptions = (SetupError,)
230    else:
231        safe_exceptions = None
232
233    #-------------------------------------------------------------------------------
234    # 1. fill cfg reading setup.cfg + setup.cache files
235    #-------------------------------------------------------------------------
236    cfg = {}
237    cfg_init_keys = []
238    # 1.1.1. ----- read parameters from 'fcfg'
239    if fcfg == None and os.path.isfile(default_cfgfile):
240        fcfg = default_cfgfile
241    if fcfg != None:
242        fcfg = os.path.expanduser(fcfg)
243        if not os.path.isfile(fcfg):
244            log._print(_('file not found %s') % fcfg)
245            sys.exit(4)
246        else:
247            log._print(_separ, _('Reading config file %s...' % repr(fcfg)))
248            context = {}
249            try:
250                exec(compile(open(fcfg).read(), fcfg, 'exec'), context)
251            except:
252                traceback.print_exc()
253                log._print(_separ, term='')
254                raise SetupError(_("reading '%s' failed (probably syntax"
255                                   " error occured, see traceback above)") % fcfg)
256            for k, v in list(context.items()):
257                if re.search('^__', k) == None and not type(v) is ModuleType:
258                    cfg[k] = v
259                    cfg_init_keys.append(k)
260                    log._print(_(' %15s (from cfg) : %s') % (k, repr(v)))
261
262    # 1.1.2. ----- read cache file
263    # delete it if --nocache or to_install list is full.
264    if (not opts.cache or to_install == to_install0) and os.path.exists(cache_file):
265        log._print(_separ, _('Deleting cache file %s...' % repr(cache_file)))
266        os.remove(cache_file)
267    if os.path.exists(cache_file):
268        if fcfg != None and os.stat(fcfg).st_ctime > os.stat(cache_file).st_ctime:
269            log._print(_separ, _(""" WARNING : %(cfg)s is newer than %(cache)s.
270              The modifications you made in %(cfg)s might be overriden with
271              cached values. If errors occur delete %(cache)s and restart at
272              the beginning !""")
273                       % {'cfg': repr(fcfg), 'cache': repr(cache_file)}, _separ)
274            should_continue()
275        log._print(_separ, _('Reading cache file %s...' % repr(cache_file)))
276        context = {}
277        try:
278            exec(compile(open(cache_file).read(), cache_file, 'exec'), context)
279        except:
280            traceback.print_exc()
281            log._print(_separ, term='')
282            raise SetupError(
283                _("reading '%s' failed (probably syntax error occured)") % cache_file)
284        os.remove(cache_file)
285        lk = list(context.keys())
286        lk.sort()
287        for k in lk:
288            v = context[k]
289            if re.search('^__', k) == None and not type(v) is ModuleType:
290                cfg[k] = v
291                if not k in cfg_init_keys:
292                    cfg_init_keys.append(k)
293                log._print(_(' %15s (from cache) : %s') % (k, repr(v)))
294
295    # 1.1.3. ----- list of options to put in cfg
296    for o in ('ASTER_ROOT', 'SOURCEDIR',):
297        if getattr(opts, o) is not None:
298            cfg[o] = os.path.normpath(os.path.abspath(getattr(opts, o)))
299            log._print(_separ, _(' %15s (from arguments) : %s') % (o, cfg[o]))
300        elif o not in cfg:
301            cfg[o] = def_opts[o]
302        # if all options are not directories write a different loop
303        cfg[o] = os.path.abspath(os.path.expanduser(cfg[o]))
304
305    # 1.2. ----- start a wizard
306    # ... perhaps one day !
307    os.environ['ASTER_ROOT'] = cfg['ASTER_ROOT']
308
309    # 1.3.1. ----- configure standard directories
310    # {bin,lib,inc}dirs are used to search files
311    # Search first from ASTER_ROOT/public/{bin,lib,include}
312    # and ASTER_ROOT/public is added for recursive search.
313    bindirs = [os.path.join(cfg['ASTER_ROOT'], 'public', 'bin'),
314               os.path.join(cfg['ASTER_ROOT'], 'public'), ]
315    bindirs.extend(os.environ.get('PATH', '').strip(':').split(':'))
316    bindirs.extend(['/usr/local/bin', '/usr/bin', '/bin',
317                    '/usr/X11R6/bin', '/usr/bin/X11', '/usr/openwin/bin', ])
318
319    libdirs = [os.path.join(cfg['ASTER_ROOT'], 'public', 'lib'),
320               os.path.join(cfg['ASTER_ROOT'], 'public'), ]
321    libdirs.extend(os.environ.get('LD_LIBRARY_PATH', '').strip(':').split(':'))
322    libdirs.extend(['/usr/local/lib', '/usr/lib', '/lib',
323                    '/usr/lib/x86_64-linux-gnu',
324                    '/usr/X11R6/lib', '/usr/lib/X11', '/usr/openwin/lib', ])
325
326    incdirs = [os.path.join(cfg['ASTER_ROOT'], 'public', 'include'),
327               os.path.join(cfg['ASTER_ROOT'], 'public'), ]
328    incdirs.extend(os.environ.get('INCLUDE', '').split(':'))
329    incdirs.extend(['/usr/local/include', '/usr/include', '/include',
330                    '/usr/X11R6/include', '/usr/include/X11', '/usr/openwin/include', ])
331
332    # 1.3.2. ----- convert uname value to Code_Aster terminology...
333    sysname, nodename, release, version, machine = os.uname()
334    log._print('Architecture : os.uname = %s' % str(os.uname()), DBG=True)
335    plt = sys.platform
336    log._print('Architecture : sys.platform = %s    os.name = %s' %
337               (plt, os.name), DBG=True)
338
339    sident = ' '.join(os.uname())
340    if os.path.isfile('/etc/issue'):
341        sident = re.sub(r'\\.', '', open('/etc/issue', 'r').read()) + sident
342    log._print(_separ, """Installation on :\n%s""" % sident, _separ)
343
344    common_libs = ['pthread', 'z']
345    cfg['PLATFORM'] = plt
346    if plt.startswith('linux'):
347        plt = 'linux'
348    if plt == 'win32':
349        cfg['IFDEF'] = 'WIN32'
350    elif plt in ('linux', 'cygwin'):
351        cfg['ARCH'] = 'x86'
352        if machine.endswith('64'):
353            cfg['IFDEF'] = 'LINUX64'
354            if machine in ('x86_64', 'ia64', 'ppc64'):
355                cfg['ARCH'] = machine
356            else:  # force to x86_64
357                cfg['ARCH'] = 'x86_64'
358        else:
359            cfg['IFDEF'] = 'LINUX'
360    elif plt == 'darwin':
361        cfg['ARCH'] = 'x86'
362        if machine.endswith('64'):
363            cfg['IFDEF'] = 'DARWIN64'
364            if machine in ('x86_64', 'ia64', 'ppc64'):
365                cfg['ARCH'] = machine
366            else:  # force to x86_64
367                cfg['ARCH'] = 'x86_64'
368        else:
369            cfg['IFDEF'] = 'DARWIN'
370    elif plt.startswith('freebsd'):
371        common_libs = []
372        cfg['IFDEF'] = 'FREEBSD'
373        cfg['ARCH'] = 'x86'
374        if machine.endswith('64'):
375            if machine in ('x86_64', 'ia64', 'ppc64'):
376                cfg['ARCH'] = machine
377            else:  # force to x86_64
378                cfg['ARCH'] = 'x86_64'
379    elif plt.startswith('osf1'):
380        cfg['IFDEF'] = 'TRU64'
381    elif plt == 'sunos5':
382        cfg['IFDEF'] = 'SOLARIS'
383    # elif plt.startswith('irix64'):
384    #    cfg['IFDEF']='IRIX64'
385    elif plt.startswith('irix'):
386        cfg['IFDEF'] = 'IRIX'
387    else:
388        raise SetupError(_("Unsupported platform : sys.platform=%s, os.name=%s") %
389                         (sys.platform, os.name))
390    if cfg.get('_solaris64', False) and plt == 'sunos5':
391        cfg['IFDEF'] = 'SOLARIS64'
392    cfg['DEFINED'] = cfg['IFDEF']
393
394    # ----- insert 'lib64' at the beginning on 64 bits platforms
395    if cfg['IFDEF'].endswith('64'):
396        libdirs = [path.replace('lib', 'lib64') for path in libdirs
397                   if path.find('lib') > -1 and path.find('lib64') < 0] + libdirs
398    bindirs = cfg.get('BINDIR', []) + bindirs
399    libdirs = cfg.get('LIBDIR', []) + libdirs
400    incdirs = cfg.get('INCLUDEDIR', []) + incdirs
401
402    # 1.3.3. ----- variables with predefined value
403    cfg['ASTER_VERSION'] = cfg.get('ASTER_VERSION', __aster_version__)
404    cfg['ASTER_NUMVERS'] = numeric_version
405    cfg['ASTER_VERSLABEL'] = cfg.get('ASTER_VERSLABEL',
406                                     dict_prod_param['aster-verslabel'])
407
408    cfg['NODE'] = cfg.get('NODE', nodename.split('.')[0])
409
410    cfg['HOME_PYTHON'] = cfg.get('HOME_PYTHON', os.path.abspath(sys.prefix))
411    cfg['PYTHON_EXE'] = cfg.get('PYTHON_EXE', sys.executable)
412    cfg['PYTHON_XY'] = pythonXY.lstrip('python') # only major.minor
413    # these directories should respectively contain shared and static
414    # librairies
415    pylib = SC.get_python_lib(standard_lib=True)
416    # python modules location
417    cfg['PYTHONPATH'] = cfg.get('PYTHONPATH', '')
418    cfg['OPT_ENV'] = cfg.get('OPT_ENV', '')
419
420    #-------------------------------------------------------------------------------
421    # 1.4. ----- auto-configuration
422    #-------------------------------------------------------------------------
423    log._print(_separ, term='')
424
425    # 1.4.0. ----- checking for maximum command line length (as configure does)
426    log._print(_fmt_search % _('max command length'), term='')
427    system = SYSTEM({'verbose': verbose, 'debug': False},
428                    **{'maxcmdlen': 2 ** 31, 'log': log})
429    system.AddToEnv(cfg['OPT_ENV'], verbose=False)
430    default_value = 1024
431    lenmax = 0
432    i = 0
433    teststr = 'ABCD'
434    iret = 0
435    while iret == 0:
436        i += 1
437        cmd = 'echo ' + teststr
438        iret, out = system.local_shell(cmd, verbose=False)
439        out = out.replace('\n', '')
440        if len(out) != len(teststr) or len(teststr) > 2 ** 16:
441            lenmax = len(teststr) / 2
442            break
443        teststr = teststr * 2
444    # Add a significant safety factor because C++ compilers can tack on massive
445    # amounts of additional arguments before passing them to the linker.
446    # It appears as though 1/2 is a usable value.
447    system.MaxCmdLen = max(default_value, lenmax / 2)
448    log._print(system.MaxCmdLen)
449    cfg['MAXCMDLEN'] = system.MaxCmdLen
450    system.debug = debug
451
452    # ----- initialize DEPENDENCIES object
453    dep = DEPENDENCIES(
454        cfg=cfg,
455       cache=cache_file,
456       debug=debug,
457       system=system,
458       log=log)
459
460    # ----- initialize FIND_TOOLS object
461    ftools = FIND_TOOLS(log=log,
462                        maxdepth=cfg.get('MAXDEPTH', 5),
463                        use_locate=cfg.get('USE_LOCATE', False),
464                        prefshared=cfg.get('PREFER_SHARED_LIBS', False),
465                        debug=debug,
466                        system=system,
467                        arch=cfg.get('ARCH'),
468                        bindirs=bindirs,
469                        libdirs=libdirs,
470                        incdirs=incdirs,
471                        noerror=_test)
472
473    # 1.4.0a. ----- system info
474    ftools.check(
475        ' '.join([sysname, '/', os.name, '/', cfg['ARCH']]), 'architecture')
476    ftools.get_cpu_number()
477    ftools.check(cfg['IFDEF'], 'Code_Aster platform type')
478
479    # 1.4.1a. ----- checking for shell script interpreter
480    ftools.find_and_set(
481        cfg, 'SHELL_EXECUTION', ['bash', 'ksh', 'zsh'], err=False)
482    ftools.check(python_version, 'Python version')
483
484    pylibrary = ftools.findlib_and_set(cfg, 'PYTHON_LIBRARY',
485                                       [pythonXY, pythonXY + "m"],
486                                       paths=[pylib], prefshared=True, err=True)
487    cfg['PYTHON_LIBRARY'] = pylibrary
488    cfg['PYTHON_LIBRARY_DIR'] = osp.dirname(pylibrary)
489    pyinc = ftools.find_and_set(cfg, 'PYTHON_INCLUDE', "Python.h", typ='inc',
490                                paths=[osp.join(cfg['HOME_PYTHON'], 'include',
491                                                pythonXY)],
492                                err=True)
493    cfg['PYTHON_INCLUDE'] = osp.dirname(pyinc)
494    cfg['PYTHON_ALIAS'] = ''
495    if PY3:
496        py3tmpdir = tempfile.mkdtemp()
497        os.symlink(cfg['PYTHON_EXE'], osp.join(py3tmpdir, "python"))
498        cfg['PYTHON_ALIAS'] = "export PATH={0}:${{PATH}}".format(py3tmpdir)
499
500    resp = ftools.pymod_exists("numpy")
501    if resp:
502        import numpy
503        cfg['PYPATH_NUMPY'] = cfg.get('PYPATH_NUMPY',
504                                      osp.dirname(numpy.__path__[0]))
505    else:
506        log._print("'import numpy' failed. Please check your numpy installation.")
507
508    # 1.4.1b. ----- check for popen/threading bug :
509    response = sys.hexversion >= 0x020700F0
510    cfg['MULTITHREADING'] = response
511
512    # 1.4.1d. ----- check for mpirun command
513    # ftools.find_and_set(cfg, 'MPIRUN', ['mpirun', 'prun'], err=False)
514    cfg['MPIRUN'] = cfg.get('MPIRUN', 'mpiexec')
515
516    # 1.4.1e. ----- check for gcc libraries path
517    cc = cfg.get('CC')
518    if cc is None or not ftools.check_compiler_name(cc, 'GCC'):
519        cc = 'gcc'
520    ftools.find_and_set(cfg, 'gcc', cc)
521    if cfg.get('gcc'):   # for 'test' mode
522        ftools.GccPrintSearchDirs(cfg['gcc'])
523
524    # 1.4.1f. ----- check for system libraries
525    math_lib = cfg.get('MATH_LIST', [])
526    if not type(math_lib) in (list, tuple):
527        math_lib = [math_lib, ]
528    sys_lib = []
529    for glob_lib in common_libs:
530        cfg['__tmp__'] = ''
531        del cfg['__tmp__']
532        ftools.findlib_and_set(
533            cfg, '__tmp__', glob_lib, prefshared=True, err=False, silent=False)
534        if cfg.get('__tmp__'):
535            ftools.AddToCache('lib', glob_lib, cfg['__tmp__'])
536            sys_lib.append(glob_lib)
537
538    # 1.4.1g. ----- check for system dependent libraries (and only used by
539    # Code_Aster)
540    cfg['SYSLIB'] = cfg.get('SYSLIB', '')
541    aster_sys_lib = []
542    if cfg['IFDEF'] in ('LINUX', 'P_LINUX', 'LINUX64'):
543        cfg['SYSLIB'] += ' -Wl,--allow-multiple-definition -Wl,--export-dynamic'
544        aster_sys_lib.extend(['dl', 'util', 'm'])
545    elif cfg['IFDEF'] == 'TRU64':
546        aster_sys_lib.extend('/usr/lib/libots3.a /usr/lib/libpthread.a /usr/lib/libnuma.a '
547                             '/usr/lib/libpset.a  /usr/lib/libmach.a -lUfor -lfor -lFutil -lm '
548                             '-lots -lm_c32 -lmld /usr/ccs/lib/cmplrs/cc/libexc.a'.split())
549    elif cfg['IFDEF'] == 'SOLARIS':
550        aster_sys_lib.extend(
551            ['socket', 'nsl', 'm', '/usr/lib/libintl.so.1', 'dl', 'c'])
552    elif cfg['IFDEF'] == 'SOLARIS64':
553        aster_sys_lib.extend(['socket', 'nsl', 'm', 'dl', 'c', 'm'])
554    elif cfg['IFDEF'] == 'IRIX':
555        aster_sys_lib.extend(['fpe', 'm'])
556    else:
557        pass
558    list_lib = []
559    for glob_lib in aster_sys_lib:
560        cfg['__tmp__'] = ''
561        del cfg['__tmp__']
562        ftools.findlib_and_set(cfg, '__tmp__', glob_lib, prefshared=True,
563                               err=not opts.ign_err, silent=False)
564        if cfg.get('__tmp__'):
565            ftools.AddToCache('lib', glob_lib, cfg['__tmp__'])
566            list_lib.append(cfg['__tmp__'])
567    cfg['SYSLIB'] += ' ' + ' '.join(list_lib)
568    cfg['SYSLIB'] = cfg['SYSLIB'].strip()
569
570    # 1.4.2. ----- check for compilers
571    cfg_ini = cfg.copy()
572    dict_pref = dict([(k.replace('PREFER_COMPILER_', ''), v)
573                      for k, v in list(cfg.items()) if k.startswith('PREFER_COMPILER')])
574    if not dict_pref.get('PREFER_COMPILER'):
575        dict_pref['PREFER_COMPILER'] = 'GNU'
576
577    from check_compilers import COMPILER_MANAGER
578    compiler_manager = COMPILER_MANAGER(debug, print_func=log._print)
579    lkeys = list(dict_pref.keys())
580    lkeys.sort()
581    log._print('PREFER_COMPILER keys : %s' % lkeys, DBG=True)
582
583    # general compiler options
584    compiler_option = []
585    if cfg.get('USE_FPIC', True):
586        compiler_option.append('-fPIC')
587
588    for prod in lkeys:
589        prefcompiler = dict_pref[prod]
590        log._print(_separ, term='')
591        if prod == 'PREFER_COMPILER':
592            lprod = [p for p in list(dict_pref.keys()) if p != prod]
593            if len(lprod) > 0:
594                sprod = ' except %s' % ', '.join(lprod)
595            else:
596                sprod = ''
597            ftools.check(None, 'default compiler (for all products%s)' % sprod)
598            prod = '__main__'
599        else:
600            ftools.check(None, 'compiler for "%s"' % prod)
601        success = compiler_manager.check_compiler(name=prefcompiler,
602                                                  product=prod,
603                                                  system=system, ftools=ftools,
604                                                  necessary=(
605                                                  'CC', 'CXX', 'F90'),
606                                                  init=cfg_ini,
607                                                  platform=cfg['IFDEF'],
608                                                  arch=cfg.get('ARCH', ''),
609                                                  math_lib=math_lib,
610                                                  sys_lib=sys_lib,
611                                                  add_option=compiler_option)
612        if not success:
613            log._print(_separ, term='')
614            log._print(_('Unable to configure automatically %s compiler for "%s" product.') %
615                       (prefcompiler.upper(), prod))
616            return
617        else:
618            txt = compiler_manager.switch_in_dep(
619                dep, prod, system=system, verbose=True)
620            log._print(
621                os.linesep, 'Compiler variables (set as environment variables):', os.linesep)
622            log._print(txt)
623        if debug:
624            from pprint import pprint
625            pprint(compiler_manager.get_config(prod))
626
627    # activate main compiler
628    compiler_manager.switch_in_dep(
629        dep, product='__main__', system=system, verbose=False)
630
631    # 1.4.3. ----- check for ps commands :
632    #  PS_COMMAND_CPU returns (field 1) cputime and (field 2) command line
633    #  PS_COMMAND_PID returns (field 1) pid and (field 2) command line
634    log._print(_separ, term='')
635    ftools.find_and_set(cfg, 'PS_COMMAND', 'ps',  err=False)
636    ps_command = cfg.get('PS_COMMAND')
637    if ps_command != None:
638        if cfg['IFDEF'].find('SOLARIS') > -1:
639            cfg['PS_COMMAND_CPU'] = '%s -e -otime -oargs' % ps_command
640            cfg['PS_COMMAND_PID'] = '%s -e -opid -oargs' % ps_command
641        elif cfg['IFDEF'].find('IRIX') > -1 or cfg['IFDEF'] == 'TRU64':
642            cfg['PS_COMMAND_CPU'] = '%s -e -ocputime -ocommand' % ps_command
643            cfg['PS_COMMAND_PID'] = '%s -e -opid -ocommand' % ps_command
644        elif plt == 'darwin':
645            # per man page for Mac OS X (darwin) ps command
646            # if -w option is specified more than once, ps will use as many columns as necessary without
647            # regard for your window size.  When output is not to a terminal, an unlimited number of
648            # columns are always used.
649            cfg['PS_COMMAND_CPU'] = '%s -e -w -w -ocputime -ocommand' % ps_command
650            cfg['PS_COMMAND_PID'] = '%s -e -w -w -opid -ocommand' % ps_command
651        else:
652            cfg['PS_COMMAND_CPU'] = '%s -e --width=512 -ocputime -ocommand' % ps_command
653            cfg['PS_COMMAND_PID'] = '%s -e --width=512 -opid -ocommand' % ps_command
654
655    # 1.4.4. ----- check for a terminal
656    ListTerm = [
657        ['xterm', 'xterm -e @E', ],
658        ['gnome-terminal', 'gnome-terminal --command=@E', ],
659        ['konsole', 'konsole -e @E'], ]
660    for prg, cmd in ListTerm:
661        term = ftools.find_file(prg, typ='bin')
662        if term != None:
663            term = cmd.replace(prg, term)
664            break
665    # an empty string means no terminal for asrun
666    cfg['TERMINAL'] = cfg.get('TERMINAL', term) or ""
667
668    # 1.4.5. ----- check for a text editor
669    ListEdit = [
670        ['nedit', 'nedit', ],
671        ['geany', 'geany', ],
672        ['gvim', 'gvim', ],
673        ['gedit', 'gedit', ],
674        ['kwrite', 'kwrite', ],
675        ['xemacs', 'xemacs', ],
676        ['emacs', 'emacs', ],
677        ['xedit', 'xedit', ],
678        ['vi', cfg.get('TERMINAL', 'xterm') + ' -e vi', ], ]
679    for prg, cmd in ListEdit:
680        edit = ftools.find_file(prg, typ='bin')
681        if edit != None:
682            edit = cmd.replace(prg, edit)
683            break
684    cfg['EDITOR'] = cfg.get('EDITOR', edit) or 'gedit'
685
686    # 1.4.6. ----- check for debugger
687    #  DEBUGGER_COMMAND runs an interactive debugger
688    #  DEBUGGER_COMMAND_POST dumps a post-mortem traceback
689    #     @E will be remplaced by the name of the executable
690    #     @C will be remplaced by the name of the corefile
691    #     @D will be remplaced by the filename which contains "where+quit"
692    #     @d will be remplaced by the string 'where ; quit'
693    cfg['DEBUGGER_COMMAND'] = ''
694    cfg['DEBUGGER_COMMAND_POST'] = ''
695    ListDebbuger = [
696        ['gdb',     '%s -batch --command=@D @E @C', ],
697       ['dbx',     '%s -c @D @E @C', ],
698       ['ladebug', '%s -c @D @E @C', ], ]
699    for debugger, debugger_command_format in ListDebbuger:
700        debugger_command = ftools.find_file(debugger, typ='bin')
701        if debugger_command != None:
702            cfg['DEBUGGER_COMMAND_POST'] = debugger_command_format % debugger_command
703            break
704
705    if debugger_command != None:
706        ddd = ftools.find_file('ddd', typ='bin')
707        if ddd != None:
708            cfg['DEBUGGER_COMMAND'] = '%s --%s --debugger %s --command=@D @E @C' \
709                % (ddd, debugger, debugger_command)
710
711    # 1.4.7. ----- check for utilities (for scotch)
712    ftools.find_and_set(cfg, 'FLEX', 'flex', err=False)
713    ftools.find_and_set(cfg, 'RANLIB', 'ranlib', err=False)
714    ftools.find_and_set(cfg, 'YACC', 'bison', err=False)
715    if cfg.get('YACC') and cfg.get('YACC', '').find('-y') < 0:
716        cfg['YACC'] += ' -y'
717    if not opts.ign_err and 'scotch' in to_install \
718       and (not cfg.get('FLEX') or not cfg.get('RANLIB') or not cfg.get('YACC')):
719        to_install.remove('scotch')
720
721    # 1.4.8. ----- check for utilities (for tfel)
722    ftools.find_and_set(cfg, 'CMAKE', 'cmake', err=False)
723    if not opts.ign_err and 'tfel' in to_install and not cfg.get('CMAKE'):
724        log._print(
725            "\nWARNING: cmake is missing. You won't be able to install Mfront.")
726        to_install.remove('tfel')
727
728    #-------------------------------------------------------------------------------
729    # 1.5. ----- products configuration
730    #-------------------------------------------------------------------------
731    log._print(_separ, term='')
732
733    # 1.5.1. ----- check for hostname (for client part of astk)
734    log._print(_fmt_search % _('host name'), term='')
735    host = system.GetHostName()
736    # deduce domain name
737    tmp = host.split('.')
738    if len(tmp) > 1:
739        host = tmp[0]
740        domain = '.'.join(tmp[1:])
741    else:
742        domain = ''
743    cfg['SERVER_NAME'] = cfg.get('SERVER_NAME', host)
744    cfg['DOMAIN_NAME'] = cfg.get('DOMAIN_NAME', domain)
745    cfg['FULL_SERVER_NAME'] = cfg.get('FULL_SERVER_NAME', '.'.join(tmp))
746    domain = cfg['DOMAIN_NAME']
747    if domain == '':
748        domain = '(empty)'
749    log._print(cfg['SERVER_NAME'])
750    log._print(_fmt_search % _('network domain name'), domain)
751    log._print(_fmt_search %
752               _('full qualified network name'), cfg['FULL_SERVER_NAME'])
753
754    # 1.5.2. ----- check boost
755    if cfg['ASTER_NUMVERS'] >= (15, 2):
756        boostlib = ftools.findlib_and_set(
757            cfg, 'unused_boost',
758            cfg.get("LIBNAME_BOOST", ["boost_python3", "boost_python3-mt"]),
759            paths=cfg.get("HOME_BOOST", ""),
760            prefshared=True, err=True)
761        path, base = osp.split(boostlib)
762        home = re.sub("/lib(64)?$", "", path)
763        name = re.sub("^lib", "", re.sub("\.so.*", "", base))
764        cfg["HOME_BOOST"] = cfg.get("HOME_BOOST", home)
765        cfg["LIBNAME_BOOST"] = cfg.get("LIBNAME_BOOST", name)
766        cfg["LIBPATH_BOOST"] = cfg.get("LIBPATH_BOOST", path)
767    else:
768        cfg['HOME_BOOST'] = cfg.get('HOME_BOST', '')
769        cfg['LIBNAME_BOOST'] = cfg.get('LIBNAME_BOOST', '')
770        cfg["LIBPATH_BOOST"] = cfg.get("LIBPATH_BOOST", '')
771
772    #-------------------------------------------------------------------------------
773    # 1.6. ----- optional tools/libs
774    #-------------------------------------------------------------------------------
775    # 1.6.1. ----- check for F90 compiler : is now compulsory
776
777    # 1.6.2. ----- optional packages for aster
778    # hdf5
779    cfg['HOME_HDF'] = cfg.get('HOME_HDF', '')
780    # med
781    cfg['HOME_MED'] = cfg.get('HOME_MED', '')
782    # MUMPS
783    cfg['HOME_MUMPS'] = cfg.get('HOME_MUMPS', '')
784    # MFRONT
785    cfg['HOME_MFRONT'] = cfg.get('HOME_MFRONT', '')
786    # SCOTCH
787    cfg['HOME_SCOTCH'] = cfg.get('HOME_SCOTCH', '')
788    # MPI
789    cfg['HOME_MPI'] = cfg.get('HOME_MPI', '')
790
791    # 1.6.4. ----- mumps
792    cfg['INCLUDE_MUMPS'] = cfg.get('INCLUDE_MUMPS',
793                                   'include_mumps-%s' % dict_prod['mumps'])
794
795    # 1.6.5. ----- grace 5
796    grace_add_symlink = False
797    if not opts.ign_err and 'grace' in to_install:
798        ftools.find_and_set(cfg, 'XMGRACE', ['xmgrace', 'grace'], err=False)
799        if cfg.get('XMGRACE'):
800            # try to use grace instead of xmgrace that does not work without
801            # DISPLAY
802            ftools.find_and_set(
803                cfg, 'GRACEBAT', ['grace', 'gracebat'], err=False)
804            grace = cfg.get('GRACEBAT', cfg['XMGRACE'])
805            iret, out, outspl = ftools.get_product_version(grace, '-version')
806            vers = None
807            svers = '?'
808            mat = re.search('(Grace.*?)([0-9\.]+)', out, re.MULTILINE)
809            if mat is not None:
810                vers = mat.group(2).strip('.').split('.')
811                try:
812                    vers = [int(v) for v in vers]
813                    svers = '.'.join([str(i) for i in vers])
814                except:
815                    vers = None
816                log._print(
817                    'XMGRACE', ''.join(mat.groups()), ': version', vers, DBG=True)
818            if vers is not None and vers < [5, 90]:
819                res = 'version is %s : ok. Do not need compile grace from sources.' % svers
820                to_install.remove('grace')
821                grace_add_symlink = True
822            else:
823                res = 'version is %s. Trying to compile grace from sources.' % svers
824            ftools.check(res, 'Grace version < 5.99')
825
826    # 1.6.6. ----- OS X
827    if plt == 'darwin':
828        # gmsh and homard are x86 binaries
829        for prod in ('gmsh', 'homard'):
830            if prod in to_install:
831                to_install.remove(prod)
832
833    #-------------------------------------------------------------------------------
834    # 2. dependencies
835    #-------------------------------------------------------------------------------
836    # 2.1. ----- add in DEPENDENCIES instance values set by __main__...
837    dep.Add(product='__main__',
838            set=[k for k in list(cfg.keys()) if not k in cfg_init_keys],)
839
840    # 2.2. ----- ... and during configuration step
841    dep.Add(product='__cfg__',
842            set=cfg_init_keys)
843    dep.FillCache()
844
845    #-------------------------------------------------------------------------------
846    # 2.99. ----- stop here if 'test'
847    err = False
848    if not os.path.exists(cfg['ASTER_ROOT']):
849        try:
850            os.makedirs(cfg['ASTER_ROOT'])
851        except OSError:
852            err = True
853    if not os.path.exists(osp.join(cfg['ASTER_ROOT'], 'bin')):
854        try:
855            os.makedirs(osp.join(cfg['ASTER_ROOT'], 'bin'))
856        except OSError:
857            err = True
858    err = err or not os.access(cfg['ASTER_ROOT'], os.W_OK)
859    if err:
860        log._print(_separ, term='')
861        log._print(_('No write access to %s.\n'
862                     'Use --aster_root=XXX to change destination directory.') %
863                   cfg['ASTER_ROOT'])
864        return
865
866    t_ini = time.time() - t_ini
867    if _test:
868        print()
869        print('Stop here !')
870        print('Settings are saved in setup.cache. Remove it if you '
871              'change something.')
872        return
873    else:
874        print()
875        log._print(_separ, term='')
876        if cfg['F90'] == '':
877            log._print(
878                get_install_message('gfortran', 'a fortran 90 compiler'))
879            raise SetupError(_("Error: no fortran90 compiler found !"))
880
881        if noprompt:
882            log._print('Continue without prompting.')
883        else:
884            log._print(
885                _("Check if found values seem correct. If not you can change them using 'setup.cfg'."))
886            should_continue()
887
888    t_ini = time.time() - t_ini
889
890    #-------------------------------------------------------------------------------
891    # 4. products installation
892    #-------------------------------------------------------------------------
893
894    #-------------------------------------------------------------------------------
895    # product for which full installation is required
896    summary = SUMMARY(to_install, system=system, log=log, t_ini=t_ini)
897    summary.SetGlobal(cfg['ASTER_ROOT'], '')
898
899    for product in to_install:
900        alias = product_alias(product)
901        if cfg.get('_install_' + alias, product in to_install):
902            t0 = time.time()
903            setup = None
904            if hasattr(products, 'setup_%s' % alias):
905                txt = compiler_manager.switch_in_dep(dep,
906                                                     product=alias,
907                                                     system=system,
908                                                     verbose=True)
909                log._print(
910                    _separ, _('Compiler variables for %s (set as environment variables):') % product)
911                log._print(txt)
912                log._print()
913                # export environment
914                ftools.AddToPathVar(dep.cfg, 'PATH', None)
915                ftools.AddToPathVar(dep.cfg, 'LD_LIBRARY_PATH', None)
916                system.AddToEnv(dep.cfg['OPT_ENV'], verbose=False)
917                #
918                setup = getattr(products, 'setup_%s' % alias)(**{
919                                                              'dep': dep,
920                                                              'summary': summary,
921                                                              'verbose': verbose,
922                                                              'debug': debug,
923                                                              'system': system,
924                                                              'find_tools': ftools,
925                                                              'log': log,
926                                                              'reinstall': opts.reinstall,
927                                                              })
928            else:
929                raise SetupError(
930                    _('Setup script for %s not available.') % product)
931            try:
932                if not _test:
933                    setup.Go()
934                else:
935                    setup.PreCheck()
936            except safe_exceptions as msg:
937                log._print(_fmt_err % msg)
938            # how to continue if failed
939            if setup.exit_code != 0:
940                setup.IfFailed()
941            dt = time.time() - t0
942            summary.Set(product, setup, dt, sys.exc_info()[:2])
943
944    #-------------------------------------------------------------------------------
945    # 5. Summary
946    #-------------------------------------------------------------------------
947    summary.Print()
948
949    # 6. Clean up
950    ftools.clear_temporary_folder()
951    if PY3:
952        os.system('rm -rf %s' % py3tmpdir)
953
954
955def seedetails():
956    print('\n' * 2 +
957          _('Exception raised. See %s file for details.') % repr(log_file))
958
959
960#-------------------------------------------------------------------------
961if __name__ == '__main__':
962    try:
963        main()
964    except SystemExit as msg:
965        log._print(msg)
966        seedetails()
967        sys.exit(msg)
968    except:
969        traceback.print_exc()
970        seedetails()
971    log.close()
972