#! /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)