| #! /usr/bin/env python |
| # encoding: utf-8 |
| # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file |
| |
| import re,shutil,os,sys,string,shlex |
| from waflib.Configure import conf |
| from waflib.TaskGen import feature,after_method,before_method |
| from waflib import Build,Utils |
| FC_FRAGMENT=' program main\n end program main\n' |
| FC_FRAGMENT2=' PROGRAM MAIN\n END\n' |
| def fc_flags(conf): |
| v=conf.env |
| v['FC_SRC_F']=[] |
| v['FC_TGT_F']=['-c','-o'] |
| v['FCINCPATH_ST']='-I%s' |
| v['FCDEFINES_ST']='-D%s' |
| if not v['LINK_FC']:v['LINK_FC']=v['FC'] |
| v['FCLNK_SRC_F']=[] |
| v['FCLNK_TGT_F']=['-o'] |
| v['FCFLAGS_fcshlib']=['-fpic'] |
| v['LINKFLAGS_fcshlib']=['-shared'] |
| v['fcshlib_PATTERN']='lib%s.so' |
| v['fcstlib_PATTERN']='lib%s.a' |
| v['FCLIB_ST']='-l%s' |
| v['FCLIBPATH_ST']='-L%s' |
| v['FCSTLIB_ST']='-l%s' |
| v['FCSTLIBPATH_ST']='-L%s' |
| v['FCSTLIB_MARKER']='-Wl,-Bstatic' |
| v['FCSHLIB_MARKER']='-Wl,-Bdynamic' |
| v['SONAME_ST']='-Wl,-h,%s' |
| def check_fortran(self,*k,**kw): |
| self.check_cc(fragment=FC_FRAGMENT,compile_filename='test.f',features='fc fcprogram',msg='Compiling a simple fortran app') |
| def check_fc(self,*k,**kw): |
| kw['compiler']='fc' |
| if not'compile_mode'in kw: |
| kw['compile_mode']='fc' |
| if not'type'in kw: |
| kw['type']='fcprogram' |
| if not'compile_filename'in kw: |
| kw['compile_filename']='test.f90' |
| if not'code'in kw: |
| kw['code']=FC_FRAGMENT |
| return self.check(*k,**kw) |
| def fortran_modifier_darwin(conf): |
| v=conf.env |
| v['FCFLAGS_fcshlib']=['-fPIC','-compatibility_version','1','-current_version','1'] |
| v['LINKFLAGS_fcshlib']=['-dynamiclib'] |
| v['fcshlib_PATTERN']='lib%s.dylib' |
| v['FRAMEWORKPATH_ST']='-F%s' |
| v['FRAMEWORK_ST']='-framework %s' |
| v['LINKFLAGS_fcstlib']=[] |
| v['FCSHLIB_MARKER']='' |
| v['FCSTLIB_MARKER']='' |
| v['SONAME_ST']='' |
| def fortran_modifier_win32(conf): |
| v=conf.env |
| v['fcprogram_PATTERN']=v['fcprogram_test_PATTERN']='%s.exe' |
| v['fcshlib_PATTERN']='%s.dll' |
| v['implib_PATTERN']='lib%s.dll.a' |
| v['IMPLIB_ST']='-Wl,--out-implib,%s' |
| v['FCFLAGS_fcshlib']=[] |
| v.append_value('FCFLAGS_fcshlib',['-DDLL_EXPORT']) |
| v.append_value('LINKFLAGS',['-Wl,--enable-auto-import']) |
| def fortran_modifier_cygwin(conf): |
| fortran_modifier_win32(conf) |
| v=conf.env |
| v['fcshlib_PATTERN']='cyg%s.dll' |
| v.append_value('LINKFLAGS_fcshlib',['-Wl,--enable-auto-image-base']) |
| v['FCFLAGS_fcshlib']=[] |
| def check_fortran_dummy_main(self,*k,**kw): |
| if not self.env.CC: |
| self.fatal('A c compiler is required for check_fortran_dummy_main') |
| lst=['MAIN__','__MAIN','_MAIN','MAIN_','MAIN'] |
| lst.extend([m.lower()for m in lst]) |
| lst.append('') |
| self.start_msg('Detecting whether we need a dummy main') |
| for main in lst: |
| kw['fortran_main']=main |
| try: |
| self.check_cc(fragment='int %s() { return 0; }\n'%(main or'test'),features='c fcprogram',mandatory=True) |
| if not main: |
| self.env.FC_MAIN=-1 |
| self.end_msg('no') |
| else: |
| self.env.FC_MAIN=main |
| self.end_msg('yes %s'%main) |
| break |
| except self.errors.ConfigurationError: |
| pass |
| else: |
| self.end_msg('not found') |
| self.fatal('could not detect whether fortran requires a dummy main, see the config.log') |
| GCC_DRIVER_LINE=re.compile('^Driving:') |
| POSIX_STATIC_EXT=re.compile('\S+\.a') |
| POSIX_LIB_FLAGS=re.compile('-l\S+') |
| def is_link_verbose(self,txt): |
| assert isinstance(txt,str) |
| for line in txt.splitlines(): |
| if not GCC_DRIVER_LINE.search(line): |
| if POSIX_STATIC_EXT.search(line)or POSIX_LIB_FLAGS.search(line): |
| return True |
| return False |
| def check_fortran_verbose_flag(self,*k,**kw): |
| self.start_msg('fortran link verbose flag') |
| for x in['-v','--verbose','-verbose','-V']: |
| try: |
| self.check_cc(features='fc fcprogram_test',fragment=FC_FRAGMENT2,compile_filename='test.f',linkflags=[x],mandatory=True) |
| except self.errors.ConfigurationError: |
| pass |
| else: |
| if self.is_link_verbose(self.test_bld.err)or self.is_link_verbose(self.test_bld.out): |
| self.end_msg(x) |
| break |
| else: |
| self.end_msg('failure') |
| self.fatal('Could not obtain the fortran link verbose flag (see config.log)') |
| self.env.FC_VERBOSE_FLAG=x |
| return x |
| LINKFLAGS_IGNORED=[r'-lang*',r'-lcrt[a-zA-Z0-9\.]*\.o',r'-lc$',r'-lSystem',r'-libmil',r'-LIST:*',r'-LNO:*'] |
| if os.name=='nt': |
| LINKFLAGS_IGNORED.extend([r'-lfrt*',r'-luser32',r'-lkernel32',r'-ladvapi32',r'-lmsvcrt',r'-lshell32',r'-lmingw',r'-lmoldname']) |
| else: |
| LINKFLAGS_IGNORED.append(r'-lgcc*') |
| RLINKFLAGS_IGNORED=[re.compile(f)for f in LINKFLAGS_IGNORED] |
| def _match_ignore(line): |
| for i in RLINKFLAGS_IGNORED: |
| if i.match(line): |
| return True |
| return False |
| def parse_fortran_link(lines): |
| final_flags=[] |
| for line in lines: |
| if not GCC_DRIVER_LINE.match(line): |
| _parse_flink_line(line,final_flags) |
| return final_flags |
| SPACE_OPTS=re.compile('^-[LRuYz]$') |
| NOSPACE_OPTS=re.compile('^-[RL]') |
| def _parse_flink_line(line,final_flags): |
| lexer=shlex.shlex(line,posix=True) |
| lexer.whitespace_split=True |
| t=lexer.get_token() |
| tmp_flags=[] |
| while t: |
| def parse(token): |
| if _match_ignore(token): |
| pass |
| elif token.startswith('-lkernel32')and sys.platform=='cygwin': |
| tmp_flags.append(token) |
| elif SPACE_OPTS.match(token): |
| t=lexer.get_token() |
| if t.startswith('P,'): |
| t=t[2:] |
| for opt in t.split(os.pathsep): |
| tmp_flags.append('-L%s'%opt) |
| elif NOSPACE_OPTS.match(token): |
| tmp_flags.append(token) |
| elif POSIX_LIB_FLAGS.match(token): |
| tmp_flags.append(token) |
| else: |
| pass |
| t=lexer.get_token() |
| return t |
| t=parse(t) |
| final_flags.extend(tmp_flags) |
| return final_flags |
| def check_fortran_clib(self,autoadd=True,*k,**kw): |
| if not self.env.FC_VERBOSE_FLAG: |
| self.fatal('env.FC_VERBOSE_FLAG is not set: execute check_fortran_verbose_flag?') |
| self.start_msg('Getting fortran runtime link flags') |
| try: |
| self.check_cc(fragment=FC_FRAGMENT2,compile_filename='test.f',features='fc fcprogram_test',linkflags=[self.env.FC_VERBOSE_FLAG]) |
| except: |
| self.end_msg(False) |
| if kw.get('mandatory',True): |
| conf.fatal('Could not find the c library flags') |
| else: |
| out=self.test_bld.err |
| flags=parse_fortran_link(out.splitlines()) |
| self.end_msg('ok (%s)'%' '.join(flags)) |
| self.env.LINKFLAGS_CLIB=flags |
| return flags |
| return[] |
| def getoutput(conf,cmd,stdin=False): |
| if stdin: |
| stdin=Utils.subprocess.PIPE |
| else: |
| stdin=None |
| env=conf.env.env or None |
| try: |
| p=Utils.subprocess.Popen(cmd,stdin=stdin,stdout=Utils.subprocess.PIPE,stderr=Utils.subprocess.PIPE,env=env) |
| if stdin: |
| p.stdin.write('\n') |
| stdout,stderr=p.communicate() |
| except: |
| conf.fatal('could not determine the compiler version %r'%cmd) |
| else: |
| if not isinstance(stdout,str): |
| stdout=stdout.decode(sys.stdout.encoding) |
| if not isinstance(stderr,str): |
| stderr=stderr.decode(sys.stdout.encoding) |
| return stdout,stderr |
| ROUTINES_CODE="""\ |
| subroutine foobar() |
| return |
| end |
| subroutine foo_bar() |
| return |
| end |
| """ |
| MAIN_CODE=""" |
| void %(dummy_func_nounder)s(void); |
| void %(dummy_func_under)s(void); |
| int %(main_func_name)s() { |
| %(dummy_func_nounder)s(); |
| %(dummy_func_under)s(); |
| return 0; |
| } |
| """ |
| def link_main_routines_tg_method(self): |
| def write_test_file(task): |
| task.outputs[0].write(task.generator.code) |
| bld=self.bld |
| bld(rule=write_test_file,target='main.c',code=MAIN_CODE%self.__dict__) |
| bld(rule=write_test_file,target='test.f',code=ROUTINES_CODE) |
| bld(features='fc fcstlib',source='test.f',target='test') |
| bld(features='c fcprogram',source='main.c',target='app',use='test') |
| def mangling_schemes(): |
| for u in['_','']: |
| for du in['','_']: |
| for c in["lower","upper"]: |
| yield(u,du,c) |
| def mangle_name(u,du,c,name): |
| return getattr(name,c)()+u+(name.find('_')!=-1 and du or'') |
| def check_fortran_mangling(self,*k,**kw): |
| if not self.env.CC: |
| self.fatal('A c compiler is required for link_main_routines') |
| if not self.env.FC: |
| self.fatal('A fortran compiler is required for link_main_routines') |
| if not self.env.FC_MAIN: |
| self.fatal('Checking for mangling requires self.env.FC_MAIN (execute "check_fortran_dummy_main" first?)') |
| self.start_msg('Getting fortran mangling scheme') |
| for(u,du,c)in mangling_schemes(): |
| try: |
| self.check_cc(compile_filename=[],features='link_main_routines_func',msg='nomsg',errmsg='nomsg',mandatory=True,dummy_func_nounder=mangle_name(u,du,c,"foobar"),dummy_func_under=mangle_name(u,du,c,"foo_bar"),main_func_name=self.env.FC_MAIN) |
| except self.errors.ConfigurationError: |
| pass |
| else: |
| self.end_msg("ok ('%s', '%s', '%s-case')"%(u,du,c)) |
| self.env.FORTRAN_MANGLING=(u,du,c) |
| break |
| else: |
| self.end_msg(False) |
| self.fatal('mangler not found') |
| return(u,du,c) |
| def set_lib_pat(self): |
| self.env['fcshlib_PATTERN']=self.env['pyext_PATTERN'] |
| def detect_openmp(self): |
| for x in['-fopenmp','-openmp','-mp','-xopenmp','-omp','-qsmp=omp']: |
| try: |
| self.check_fc(msg='Checking for OpenMP flag %s'%x,fragment='program main\n call omp_get_num_threads()\nend program main',fcflags=x,linkflags=x,uselib_store='OPENMP') |
| except self.errors.ConfigurationError: |
| pass |
| else: |
| break |
| else: |
| self.fatal('Could not find OpenMP') |
| |
| conf(fc_flags) |
| conf(check_fortran) |
| conf(check_fc) |
| conf(fortran_modifier_darwin) |
| conf(fortran_modifier_win32) |
| conf(fortran_modifier_cygwin) |
| conf(check_fortran_dummy_main) |
| conf(is_link_verbose) |
| conf(check_fortran_verbose_flag) |
| conf(check_fortran_clib) |
| feature('link_main_routines_func')(link_main_routines_tg_method) |
| before_method('process_source')(link_main_routines_tg_method) |
| conf(check_fortran_mangling) |
| feature('pyext')(set_lib_pat) |
| before_method('propagate_uselib_vars','apply_link')(set_lib_pat) |
| conf(detect_openmp) |