4 # Thomas Nagy 2016-2018 (ita)
6 import os
, re
, traceback
7 from waflib
import Utils
, Logs
, Errors
8 from waflib
.Tools
import fc
, fc_config
, fc_scan
, ar
, ccroot
9 from waflib
.Configure
import conf
10 from waflib
.TaskGen
import after_method
, feature
14 fc
= conf
.find_program('ifort', var
='FC')
15 conf
.get_ifort_version(fc
)
16 conf
.env
.FC_NAME
= 'IFORT'
19 def ifort_modifier_win32(self
):
25 v
.FCLIB_ST
= v
.FCSTLIB_ST
= '%s.lib'
26 v
.FCLIBPATH_ST
= v
.STLIBPATH_ST
= '/LIBPATH:%s'
27 v
.FCINCPATH_ST
= '/I%s'
28 v
.FCDEFINES_ST
= '/D%s'
30 v
.fcprogram_PATTERN
= v
.fcprogram_test_PATTERN
= '%s.exe'
31 v
.fcshlib_PATTERN
= '%s.dll'
32 v
.fcstlib_PATTERN
= v
.implib_PATTERN
= '%s.lib'
34 v
.FCLNK_TGT_F
= '/out:'
35 v
.FC_TGT_F
= ['/c', '/o', '']
36 v
.FCFLAGS_fcshlib
= ''
37 v
.LINKFLAGS_fcshlib
= '/DLL'
39 v
.IMPLIB_ST
= '/IMPLIB:%s'
41 v
.append_value('LINKFLAGS', '/subsystem:console')
43 v
.append_value('LINKFLAGS', ['/MANIFEST'])
46 def ifort_modifier_darwin(conf
):
47 fc_config
.fortran_modifier_darwin(conf
)
50 def ifort_modifier_platform(conf
):
51 dest_os
= conf
.env
.DEST_OS
or Utils
.unversioned_sys_platform()
52 ifort_modifier_func
= getattr(conf
, 'ifort_modifier_' + dest_os
, None)
53 if ifort_modifier_func
:
57 def get_ifort_version(conf
, fc
):
59 Detects the compiler version and sets ``conf.env.FC_VERSION``
61 version_re
= re
.compile(r
"\bIntel\b.*\bVersion\s*(?P<major>\d*)\.(?P<minor>\d*)",re
.I
).search
67 out
, err
= fc_config
.getoutput(conf
, cmd
, stdin
=False)
68 match
= version_re(out
) or version_re(err
)
70 conf
.fatal('cannot determine ifort version.')
72 conf
.env
.FC_VERSION
= (k
['major'], k
['minor'])
76 Detects the Intel Fortran compilers
79 compiler
, version
, path
, includes
, libdirs
, arch
= conf
.detect_ifort()
85 v
.MSVC_COMPILER
= compiler
87 v
.MSVC_VERSION
= float(version
)
89 v
.MSVC_VERSION
= float(version
[:-3])
91 conf
.find_ifort_win32()
92 conf
.ifort_modifier_win32()
95 conf
.find_program('xiar', var
='AR')
99 conf
.ifort_modifier_platform()
102 all_ifort_platforms
= [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), ('Itanium', 'ia64')]
103 """List of icl platforms"""
106 def gather_ifort_versions(conf
, versions
):
108 List compiler versions by looking up registry keys
110 version_pattern
= re
.compile(r
'^...?.?\....?.?')
112 all_versions
= Utils
.winreg
.OpenKey(Utils
.winreg
.HKEY_LOCAL_MACHINE
, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\Fortran')
115 all_versions
= Utils
.winreg
.OpenKey(Utils
.winreg
.HKEY_LOCAL_MACHINE
, 'SOFTWARE\\Intel\\Compilers\\Fortran')
121 version
= Utils
.winreg
.EnumKey(all_versions
, index
)
125 if not version_pattern
.match(version
):
128 for target
,arch
in all_ifort_platforms
:
129 if target
=='intel64':
130 targetDir
='EM64T_NATIVE'
134 Utils
.winreg
.OpenKey(all_versions
,version
+'\\'+targetDir
)
135 icl_version
=Utils
.winreg
.OpenKey(all_versions
,version
)
136 path
,type=Utils
.winreg
.QueryValueEx(icl_version
,'ProductDir')
140 batch_file
=os
.path
.join(path
,'bin','ifortvars.bat')
141 if os
.path
.isfile(batch_file
):
142 targets
[target
] = target_compiler(conf
, 'intel', arch
, version
, target
, batch_file
)
144 for target
,arch
in all_ifort_platforms
:
146 icl_version
= Utils
.winreg
.OpenKey(all_versions
, version
+'\\'+target
)
147 path
,type = Utils
.winreg
.QueryValueEx(icl_version
,'ProductDir')
151 batch_file
=os
.path
.join(path
,'bin','ifortvars.bat')
152 if os
.path
.isfile(batch_file
):
153 targets
[target
] = target_compiler(conf
, 'intel', arch
, version
, target
, batch_file
)
155 versions
['intel ' + major
] = targets
158 def setup_ifort(conf
, versiondict
):
160 Checks installed compilers and targets and returns the first combination from the user's
161 options, env, or the global supported lists that checks.
163 :param versiondict: dict(platform -> dict(architecture -> configuration))
164 :type versiondict: dict(string -> dict(string -> target_compiler)
165 :return: the compiler, revision, path, include dirs, library paths and target architecture
166 :rtype: tuple of strings
168 platforms
= Utils
.to_list(conf
.env
.MSVC_TARGETS
) or [i
for i
,j
in all_ifort_platforms
]
169 desired_versions
= conf
.env
.MSVC_VERSIONS
or list(reversed(list(versiondict
.keys())))
170 for version
in desired_versions
:
172 targets
= versiondict
[version
]
175 for arch
in platforms
:
182 compiler
,revision
= version
.rsplit(' ', 1)
183 return compiler
,revision
,cfg
.bindirs
,cfg
.incdirs
,cfg
.libdirs
,cfg
.cpu
184 conf
.fatal('ifort: Impossible to find a valid architecture for building %r - %r' % (desired_versions
, list(versiondict
.keys())))
187 def get_ifort_version_win32(conf
, compiler
, version
, target
, vcvars
):
191 except AttributeError:
193 batfile
= conf
.bldnode
.make_node('waf-print-msvc-%d.bat' % conf
.msvc_cnt
)
194 batfile
.write("""@echo off
199 echo INCLUDE=%%INCLUDE%%
200 echo LIB=%%LIB%%;%%LIBPATH%%
201 """ % (vcvars
,target
))
202 sout
= conf
.cmd_and_log(['cmd.exe', '/E:on', '/V:on', '/C', batfile
.abspath()])
204 lines
= sout
.splitlines()
209 MSVC_PATH
= MSVC_INCDIR
= MSVC_LIBDIR
= None
211 if line
.startswith('PATH='):
213 MSVC_PATH
= path
.split(';')
214 elif line
.startswith('INCLUDE='):
215 MSVC_INCDIR
= [i
for i
in line
[8:].split(';') if i
]
216 elif line
.startswith('LIB='):
217 MSVC_LIBDIR
= [i
for i
in line
[4:].split(';') if i
]
218 if None in (MSVC_PATH
, MSVC_INCDIR
, MSVC_LIBDIR
):
219 conf
.fatal('ifort: Could not find a valid architecture for building (get_ifort_version_win32)')
221 # Check if the compiler is usable at all.
222 # The detection may return 64-bit versions even on 32-bit systems, and these would fail to run.
223 env
= dict(os
.environ
)
224 env
.update(PATH
= path
)
225 compiler_name
, linker_name
, lib_name
= _get_prog_names(conf
, compiler
)
226 fc
= conf
.find_program(compiler_name
, path_list
=MSVC_PATH
)
228 # delete CL if exists. because it could contain parameters which can change cl's behaviour rather catastrophically.
233 conf
.cmd_and_log(fc
+ ['/help'], env
=env
)
235 st
= traceback
.format_exc()
237 conf
.logger
.error(st
)
238 conf
.fatal('ifort: Unicode error - check the code page?')
239 except Exception as e
:
240 Logs
.debug('ifort: get_ifort_version: %r %r %r -> failure %s', compiler
, version
, target
, str(e
))
241 conf
.fatal('ifort: cannot run the compiler in get_ifort_version (run with -v to display errors)')
243 Logs
.debug('ifort: get_ifort_version: %r %r %r -> OK', compiler
, version
, target
)
245 conf
.env
[compiler_name
] = ''
247 return (MSVC_PATH
, MSVC_INCDIR
, MSVC_LIBDIR
)
249 class target_compiler(object):
251 Wraps a compiler configuration; call evaluate() to determine
252 whether the configuration is usable.
254 def __init__(self
, ctx
, compiler
, cpu
, version
, bat_target
, bat
, callback
=None):
256 :param ctx: configuration context to use to eventually get the version environment
257 :param compiler: compiler name
258 :param cpu: target cpu
259 :param version: compiler version number
261 :param bat: path to the batch file to run
262 :param callback: optional function to take the realized environment variables tup and map it (e.g. to combine other constant paths)
266 self
.is_valid
= False
269 self
.compiler
= compiler
271 self
.version
= version
272 self
.bat_target
= bat_target
274 self
.callback
= callback
281 vs
= self
.conf
.get_ifort_version_win32(self
.compiler
, self
.version
, self
.bat_target
, self
.bat
)
282 except Errors
.ConfigurationError
:
283 self
.is_valid
= False
286 vs
= self
.callback(self
, vs
)
288 (self
.bindirs
, self
.incdirs
, self
.libdirs
) = vs
291 return str((self
.bindirs
, self
.incdirs
, self
.libdirs
))
294 return repr((self
.bindirs
, self
.incdirs
, self
.libdirs
))
297 def detect_ifort(self
):
298 return self
.setup_ifort(self
.get_ifort_versions(False))
301 def get_ifort_versions(self
, eval_and_save
=True):
303 :return: platforms to compiler configurations
307 self
.gather_ifort_versions(dct
)
310 def _get_prog_names(self
, compiler
):
311 if compiler
=='intel':
312 compiler_name
= 'ifort'
313 linker_name
= 'XILINK'
320 return compiler_name
, linker_name
, lib_name
323 def find_ifort_win32(conf
):
324 # the autodetection is supposed to be performed before entering in this method
327 compiler
= v
.MSVC_COMPILER
328 version
= v
.MSVC_VERSION
330 compiler_name
, linker_name
, lib_name
= _get_prog_names(conf
, compiler
)
331 v
.IFORT_MANIFEST
= (compiler
== 'intel' and version
>= 11)
334 fc
= conf
.find_program(compiler_name
, var
='FC', path_list
=path
)
336 # before setting anything, check if the compiler is really intel fortran
337 env
= dict(conf
.environ
)
339 env
.update(PATH
= ';'.join(path
))
340 if not conf
.cmd_and_log(fc
+ ['/nologo', '/help'], env
=env
):
341 conf
.fatal('not intel fortran compiler could not be identified')
346 conf
.find_program(linker_name
, var
='LINK_FC', path_list
=path
, mandatory
=True)
349 conf
.find_program(lib_name
, path_list
=path
, var
='AR', mandatory
=True)
350 v
.ARFLAGS
= ['/nologo']
352 # manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later
354 conf
.find_program('MT', path_list
=path
, var
='MT')
355 v
.MTFLAGS
= ['/nologo']
359 except Errors
.WafError
:
360 Logs
.warn('Resource compiler not found. Compiling resource file is disabled')
362 #######################################################################################################
363 ##### conf above, build below
365 @after_method('apply_link')
367 def apply_flags_ifort(self
):
369 Adds additional flags implied by msvc, such as subsystems and pdb files::
372 bld.stlib(source='main.c', target='bar', subsystem='gruik')
374 if not self
.env
.IFORT_WIN32
or not getattr(self
, 'link_task', None):
377 is_static
= isinstance(self
.link_task
, ccroot
.stlink_task
)
379 subsystem
= getattr(self
, 'subsystem', '')
381 subsystem
= '/subsystem:%s' % subsystem
382 flags
= is_static
and 'ARFLAGS' or 'LINKFLAGS'
383 self
.env
.append_value(flags
, subsystem
)
386 for f
in self
.env
.LINKFLAGS
:
389 pdbnode
= self
.link_task
.outputs
[0].change_ext('.pdb')
390 self
.link_task
.outputs
.append(pdbnode
)
392 if getattr(self
, 'install_task', None):
393 self
.pdb_install_task
= self
.add_install_files(install_to
=self
.install_task
.install_to
, install_from
=pdbnode
)
397 @feature('fcprogram', 'fcshlib', 'fcprogram_test')
398 @after_method('apply_link')
399 def apply_manifest_ifort(self
):
401 Enables manifest embedding in Fortran DLLs when using ifort on Windows
402 See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx
404 if self
.env
.IFORT_WIN32
and getattr(self
, 'link_task', None):
405 # it seems ifort.exe cannot be called for linking
406 self
.link_task
.env
.FC
= self
.env
.LINK_FC
408 if self
.env
.IFORT_WIN32
and self
.env
.IFORT_MANIFEST
and getattr(self
, 'link_task', None):
409 out_node
= self
.link_task
.outputs
[0]
410 man_node
= out_node
.parent
.find_or_declare(out_node
.name
+ '.manifest')
411 self
.link_task
.outputs
.append(man_node
)
412 self
.env
.DO_MANIFEST
= True