"""
Module responsible for the creation of the json files containing the default configuration for each available compiler.
This module only needs to be imported once. Once the json files have been generated they can be used directly thus
avoiding the need for a large number of imports
"""
import glob
import os
import sys
import sysconfig
import subprocess
import shutil
from numpy import get_include as get_numpy_include
from pyccel import __version__ as pyccel_version
gfort_info = {'exec' : 'gfortran',
'mpi_exec' : 'mpif90',
'module_output_flag': '-J',
'debug_flags': ("-fcheck=bounds","-g","-O0"),
'release_flags': ("-O3","-funroll-loops",),
'general_flags' : ('-fPIC',),
'standard_flags' : ('-std=f2003',),
'mpi': {
},
'openmp': {
'flags' : ('-fopenmp',),
'libs' : ('gomp',),
},
'openacc': {
'flags' : ("-ta=multicore", "-Minfo=accel"),
},
}
if sys.platform == "win32":
gfort_info['mpi_exec'] = 'gfortran'
gfort_info['mpi']['flags'] = ('-D','USE_MPI_MODULE')
gfort_info['mpi']['libs'] = ('msmpi',)
gfort_info['mpi']['include'] = (os.environ["MSMPI_INC"].rstrip('\\'),)
gfort_info['mpi']['libdir'] = (os.environ["MSMPI_LIB64"].rstrip('\\'),)
#------------------------------------------------------------
ifort_info = {'exec' : 'ifx',
'mpi_exec' : 'mpiifx',
'module_output_flag': '-module',
'debug_flags': ("-check", "bounds","-g","-O0"),
'release_flags': ("-O3","-funroll-loops",),
'general_flags' : ('-fPIC',),
'standard_flags' : ('-std=f2003',),
'openmp': {
'flags' : ('-qopenmp','-nostandard-realloc-lhs'),
'libs' : ('iomp5',),
},
'openacc': {
'flags' : ("-ta=multicore", "-Minfo=accel"),
},
}
#------------------------------------------------------------
pgfortran_info = {'exec' : 'pgfortran',
'mpi_exec' : 'pgfortran',
'module_output_flag': '-module',
'debug_flags': ("-Mbounds","-g","-O0"),
'release_flags': ("-O3","-Munroll",),
'general_flags' : ('-fPIC',),
'standard_flags' : ('-Mstandard',),
'openmp': {
'flags' : ('-mp',),
},
'openacc': {
'flags' : ("-acc"),
},
}
#------------------------------------------------------------
nvfort_info = {'exec' : 'nvfort',
'mpi_exec' : 'mpifort',
'module_output_flag': '-module',
'debug_flags': ("-Mbounds","-g","-O0"),
'release_flags': ("-O3","-Munroll",),
'general_flags' : ('-fPIC',),
'standard_flags' : ('-Mstandard',),
'openmp': {
'flags' : ('-mp',),
},
'openacc': {
'flags' : ("-acc"),
},
}
#------------------------------------------------------------
gcc_info = {'exec' : 'gcc',
'mpi_exec' : 'mpicc',
'debug_flags': ("-g","-O0"),
'release_flags': ("-O3","-funroll-loops",),
'general_flags' : ('-fPIC',),
'standard_flags' : ('-std=c99',),
'mpi': {
},
'openmp': {
'flags' : ('-fopenmp',),
'libs' : ('gomp',),
},
'openacc': {
'flags' : ("-ta=multicore", "-Minfo=accel"),
},
}
#------------------------------------------------------------
clang_info = {'exec': 'clang',
'mpi_exec': 'mpicc',
'debug_flags': ("-g", "-O0",),
'release_flags': ("-O3", "-funroll-loops"),
'general_flags': ("-fPIC",),
'standard_flags': ("-std=c99",),
'mpi': {},
'openmp': {
'flags': ("-fopenmp",),
},
'openacc': {
'flags': ("-fopenacc",),
},
}
#------------------------------------------------------------
flang_info = {
'exec': 'flang',
'mpi_exec': 'mpif90',
'module_output_flag': '-J',
'debug_flags': ("-g", "-O0",),
'release_flags': ("-O3",),
'general_flags': ("-fPIC",),
'standard_flags': ("-std=f2003",),
'mpi': {},
'openmp': {
'flags': ("-fopenmp",),
},
'openacc': {
'flags': ("-fopenacc",),
},
}
if sys.platform == "darwin":
p = subprocess.run([shutil.which('brew'), '--prefix'], check=True, capture_output=True)
HOMEBREW_PREFIX = p.stdout.decode().strip()
OMP_PATH = os.path.join(HOMEBREW_PREFIX, 'opt/libomp')
gcc_info['openmp']['flags'] = ("-Xpreprocessor", '-fopenmp')
gcc_info['openmp']['libs'] = ('omp',)
gcc_info['openmp']['libdir'] = (os.path.join(OMP_PATH, 'lib'),)
gcc_info['openmp']['include'] = (os.path.join(OMP_PATH, 'include'),)
elif sys.platform == "win32":
gcc_info['mpi_exec'] = 'gcc'
gcc_info['mpi']['flags'] = ('-D','USE_MPI_MODULE')
gcc_info['mpi']['libs'] = ('msmpi',)
gcc_info['mpi']['include'] = (os.environ["MSMPI_INC"].rstrip('\\'),)
gcc_info['mpi']['libdir'] = (os.environ["MSMPI_LIB64"].rstrip('\\'),)
#------------------------------------------------------------
icc_info = {'exec' : 'icx',
'mpi_exec' : 'mpiicx',
'debug_flags': ("-g","-O0"),
'release_flags': ("-O3","-funroll-loops",),
'general_flags' : ('-fPIC',),
'standard_flags' : ('-std=c99',),
'openmp': {
'flags' : ('-qopenmp',),
},
'openacc': {
'flags' : ("-ta=multicore", "-Minfo=accel"),
},
}
#------------------------------------------------------------
pgcc_info = {'exec' : 'pgcc',
'mpi_exec' : 'pgcc',
'debug_flags': ("-g","-O0"),
'release_flags': ("-O3","-Munroll",),
'general_flags' : ('-fPIC',),
'standard_flags' : ('-std=c99',),
'openmp': {
'flags' : ('-mp',),
},
'openacc': {
'flags' : ("-acc"),
},
}
#------------------------------------------------------------
nvc_info = {'exec' : 'nvc',
'mpi_exec' : 'mpicc',
'debug_flags': ("-g","-O0"),
'release_flags': ("-O3","-Munroll",),
'general_flags' : ('-fPIC',),
'standard_flags' : ('-std=c99',),
'openmp': {
'flags' : ('-mp',),
},
'openacc': {
'flags' : ("-acc"),
},
}
#------------------------------------------------------------
[docs]
def change_to_lib_flag(lib):
"""
Convert a library to a library flag.
Take a library file and return the associated library
flag by stripping the library suffix. If the file does
not begin with the expected 'lib' prefix then it is returned
unchanged.
Parameters
----------
lib : str
The library file.
Returns
-------
str
The library flag.
"""
if lib.startswith('lib'):
end = len(lib)
if lib.endswith('.a'):
end = end-2
if lib.endswith('.so'):
end = end-3
if lib.endswith('.dylib'):
end = end-5
return '-l{}'.format(lib[3:end])
else:
return lib
config_vars = sysconfig.get_config_vars()
python_info = {
"libs" : config_vars.get("LIBM","").split(), # Strip -l from beginning
'python': {
'flags' : config_vars.get("CFLAGS","").split()\
+ config_vars.get("CC","").split()[1:],
'include' : [*config_vars.get("INCLUDEPY","").split(), get_numpy_include()],
"shared_suffix" : config_vars['EXT_SUFFIX'],
}
}
if sys.platform == "win32":
expected_dir = config_vars["prefix"]
version = config_vars["VERSION"]
python_libs = glob.glob(f"{expected_dir}/python{version}.dll")
if python_libs:
python_info['python']['dependencies'] = tuple(python_libs)
else:
python_info['python']['libs'] = (f'python{version}',)
python_info['python']['libdir'] = config_vars.get("installed_base","").split()
else:
# Collect library according to python config file
expected_dir = config_vars["LIBDIR"]
version = config_vars["VERSION"]
python_shared_libs = glob.glob(f"{expected_dir}/libpython{version}*")
# Collect a list of all possible libraries matching the name in the configs
# which can be found on the system
shared_ending = '.dylib' if sys.platform == "darwin" else '.so'
possible_shared_lib = [l for l in python_shared_libs if shared_ending in l]
possible_static_lib = [l for l in python_shared_libs if '.a' in l]
# Prefer saving the library as a dependency where possible to avoid
# unnecessary libdir which may lead to the wrong versions being linked
# for other libraries
# Prefer a shared library as it requires less memory
if possible_shared_lib:
if len(possible_shared_lib)>1:
preferred_lib = [l for l in possible_shared_lib if l.endswith(shared_ending)]
if preferred_lib:
possible_shared_lib = preferred_lib
python_info['python']['dependencies'] = (possible_shared_lib[0],)
python_info['python']['libdir'] = (os.path.dirname(possible_shared_lib[0]),)
elif possible_static_lib:
if len(possible_static_lib)>1:
preferred_lib = [l for l in possible_static_lib if l.endswith('.a')]
if preferred_lib:
possible_static_lib = preferred_lib
python_info['python']['dependencies'] = (possible_static_lib[0],)
else:
# If the proposed library does not exist use different config flags
# to specify the library
linker_flags = [change_to_lib_flag(l) for l in
config_vars.get("LDSHARED","").split() + \
config_vars.get("LIBRARY","").split()[1:]]
python_info['python']['libs'] = [l[2:] for l in linker_flags if l.startswith('-l')]
python_info['python']['libdir'] = [l[2:] for l in linker_flags if l.startswith('-L')] + \
config_vars.get("LIBPL","").split()+config_vars.get("LIBDIR","").split()
#------------------------------------------------------------
gcc_info.update(python_info)
gfort_info.update(python_info)
icc_info.update(python_info)
ifort_info.update(python_info)
pgcc_info.update(python_info)
pgfortran_info.update(python_info)
nvc_info.update(python_info)
nvfort_info.update(python_info)
clang_info.update(python_info)
flang_info.update(python_info)
available_compilers = {
'GNU': {
'c' : gcc_info,
'fortran' : gfort_info
},
'intel': {
'c' : icc_info,
'fortran' : ifort_info
},
'PGI': {
'c' : pgcc_info,
'fortran' : pgfortran_info
},
'nvidia': {
'c' : nvc_info,
'fortran' : nvfort_info
},
'LLVM': {
'c': clang_info,
'fortran': flang_info
},
}
vendors = ('GNU','intel','PGI','nvidia','LLVM')